1 /* Copyright (C) 2007-2013 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Flow utility functions
24  */
25 
26 #include "suricata-common.h"
27 #include "threads.h"
28 
29 #include "flow.h"
30 #include "flow-private.h"
31 #include "flow-util.h"
32 #include "flow-var.h"
33 #include "app-layer.h"
34 
35 #include "util-var.h"
36 #include "util-debug.h"
37 #include "flow-storage.h"
38 
39 #include "detect.h"
40 #include "detect-engine-state.h"
41 
42 #include "decode-icmpv4.h"
43 
44 /** \brief allocate a flow
45  *
46  *  We check against the memuse counter. If it passes that check we increment
47  *  the counter first, then we try to alloc.
48  *
49  *  \retval f the flow or NULL on out of memory
50  */
FlowAlloc(void)51 Flow *FlowAlloc(void)
52 {
53     Flow *f;
54     size_t size = sizeof(Flow) + FlowStorageSize();
55 
56     if (!(FLOW_CHECK_MEMCAP(size))) {
57         return NULL;
58     }
59 
60     (void) SC_ATOMIC_ADD(flow_memuse, size);
61 
62     f = SCMalloc(size);
63     if (unlikely(f == NULL)) {
64         (void)SC_ATOMIC_SUB(flow_memuse, size);
65         return NULL;
66     }
67     memset(f, 0, size);
68 
69     /* coverity[missing_lock] */
70     FLOW_INITIALIZE(f);
71     return f;
72 }
73 
74 
75 /**
76  *  \brief cleanup & free the memory of a flow
77  *
78  *  \param f flow to clear & destroy
79  */
FlowFree(Flow * f)80 void FlowFree(Flow *f)
81 {
82     FLOW_DESTROY(f);
83     SCFree(f);
84 
85     size_t size = sizeof(Flow) + FlowStorageSize();
86     (void) SC_ATOMIC_SUB(flow_memuse, size);
87 }
88 
89 /**
90  *  \brief   Function to map the protocol to the defined FLOW_PROTO_* enumeration.
91  *
92  *  \param   proto  protocol which is needed to be mapped
93  */
94 
FlowGetProtoMapping(uint8_t proto)95 uint8_t FlowGetProtoMapping(uint8_t proto)
96 {
97     switch (proto) {
98         case IPPROTO_TCP:
99             return FLOW_PROTO_TCP;
100         case IPPROTO_UDP:
101             return FLOW_PROTO_UDP;
102         case IPPROTO_ICMP:
103             return FLOW_PROTO_ICMP;
104         default:
105             return FLOW_PROTO_DEFAULT;
106     }
107 }
108 
FlowGetReverseProtoMapping(uint8_t rproto)109 uint8_t FlowGetReverseProtoMapping(uint8_t rproto)
110 {
111     switch (rproto) {
112         case FLOW_PROTO_TCP:
113             return IPPROTO_TCP;
114         case FLOW_PROTO_UDP:
115             return IPPROTO_UDP;
116         case FLOW_PROTO_ICMP:
117             return IPPROTO_ICMP;
118         default:
119             exit(EXIT_FAILURE);
120     }
121 }
122 
FlowSetICMPv4CounterPart(Flow * f)123 static inline void FlowSetICMPv4CounterPart(Flow *f)
124 {
125     int ctype = ICMPv4GetCounterpart(f->icmp_s.type);
126     if (ctype == -1)
127         return;
128 
129     f->icmp_d.type = (uint8_t)ctype;
130 }
131 
FlowSetICMPv6CounterPart(Flow * f)132 static inline void FlowSetICMPv6CounterPart(Flow *f)
133 {
134     int ctype = ICMPv6GetCounterpart(f->icmp_s.type);
135     if (ctype == -1)
136         return;
137 
138     f->icmp_d.type = (uint8_t)ctype;
139 }
140 
141 /* initialize the flow from the first packet
142  * we see from it. */
FlowInit(Flow * f,const Packet * p)143 void FlowInit(Flow *f, const Packet *p)
144 {
145     SCEnter();
146     SCLogDebug("flow %p", f);
147 
148     f->proto = p->proto;
149     f->recursion_level = p->recursion_level;
150     f->vlan_id[0] = p->vlan_id[0];
151     f->vlan_id[1] = p->vlan_id[1];
152     f->vlan_idx = p->vlan_idx;
153     f->livedev = p->livedev;
154 
155     if (PKT_IS_IPV4(p)) {
156         FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, &f->src);
157         FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, &f->dst);
158         f->min_ttl_toserver = f->max_ttl_toserver = IPV4_GET_IPTTL((p));
159         f->flags |= FLOW_IPV4;
160     } else if (PKT_IS_IPV6(p)) {
161         FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, &f->src);
162         FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, &f->dst);
163         f->min_ttl_toserver = f->max_ttl_toserver = IPV6_GET_HLIM((p));
164         f->flags |= FLOW_IPV6;
165     }
166 #ifdef DEBUG
167     /* XXX handle default */
168     else {
169         printf("FIXME: %s:%s:%" PRId32 "\n", __FILE__, __FUNCTION__, __LINE__);
170     }
171 #endif
172 
173     if (p->tcph != NULL) { /* XXX MACRO */
174         SET_TCP_SRC_PORT(p,&f->sp);
175         SET_TCP_DST_PORT(p,&f->dp);
176     } else if (p->udph != NULL) { /* XXX MACRO */
177         SET_UDP_SRC_PORT(p,&f->sp);
178         SET_UDP_DST_PORT(p,&f->dp);
179     } else if (p->icmpv4h != NULL) {
180         f->icmp_s.type = p->icmp_s.type;
181         f->icmp_s.code = p->icmp_s.code;
182         FlowSetICMPv4CounterPart(f);
183     } else if (p->icmpv6h != NULL) {
184         f->icmp_s.type = p->icmp_s.type;
185         f->icmp_s.code = p->icmp_s.code;
186         FlowSetICMPv6CounterPart(f);
187     } else if (p->sctph != NULL) { /* XXX MACRO */
188         SET_SCTP_SRC_PORT(p,&f->sp);
189         SET_SCTP_DST_PORT(p,&f->dp);
190     } /* XXX handle default */
191 #ifdef DEBUG
192     else {
193         printf("FIXME: %s:%s:%" PRId32 "\n", __FILE__, __FUNCTION__, __LINE__);
194     }
195 #endif
196     COPY_TIMESTAMP(&p->ts, &f->startts);
197 
198     f->protomap = FlowGetProtoMapping(f->proto);
199     f->timeout_policy = FlowGetTimeoutPolicy(f);
200     const uint32_t timeout_at = (uint32_t)f->startts.tv_sec + f->timeout_policy;
201     f->timeout_at = timeout_at;
202 
203     if (MacSetFlowStorageEnabled()) {
204         MacSet *ms = FlowGetStorageById(f, MacSetGetFlowStorageID());
205         if (ms != NULL) {
206             MacSetReset(ms);
207         } else {
208             ms = MacSetInit(10);
209             FlowSetStorageById(f, MacSetGetFlowStorageID(), ms);
210         }
211     }
212 
213     SCReturn;
214 }
215 
216 int g_bypass_info_id = -1;
217 
GetFlowBypassInfoID(void)218 int GetFlowBypassInfoID(void)
219 {
220     return g_bypass_info_id;
221 }
222 
FlowBypassFree(void * x)223 static void FlowBypassFree(void *x)
224 {
225     FlowBypassInfo *fb = (FlowBypassInfo *) x;
226 
227     if (fb == NULL)
228         return;
229 
230     if (fb->bypass_data && fb->BypassFree) {
231         fb->BypassFree(fb->bypass_data);
232     }
233     SCFree(fb);
234 }
235 
RegisterFlowBypassInfo(void)236 void RegisterFlowBypassInfo(void)
237 {
238     g_bypass_info_id = FlowStorageRegister("bypass_counters", sizeof(void *),
239                                               NULL, FlowBypassFree);
240 }
241