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