suricata
flow-hash.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2024 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 * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
23 *
24 * Flow Hashing functions.
25 */
26
27#include "suricata-common.h"
28#include "threads.h"
29
30#include "decode.h"
31#include "detect-engine-state.h"
32
33#include "flow.h"
34#include "flow-hash.h"
35#include "flow-util.h"
36#include "flow-private.h"
37#include "flow-manager.h"
38#include "flow-storage.h"
39#include "flow-timeout.h"
40#include "flow-spare-pool.h"
41#include "flow-callbacks.h"
42#include "app-layer-parser.h"
43
44#include "util-time.h"
45#include "util-debug.h"
46#include "util-device-private.h"
47
48#include "util-hash-lookup3.h"
49
50#include "conf.h"
51#include "output.h"
52#include "output-flow.h"
53#include "stream-tcp.h"
55
57
58
59FlowBucket *flow_hash;
60SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx);
61SC_ATOMIC_EXTERN(unsigned int, flow_flags);
62
63static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv, const SCTime_t ts);
64
65/** \brief compare two raw ipv6 addrs
66 *
67 * \note we don't care about the real ipv6 ip's, this is just
68 * to consistently fill the FlowHashKey6 struct, without all
69 * the SCNtohl calls.
70 *
71 * \warning do not use elsewhere unless you know what you're doing.
72 * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely
73 * what you are looking for.
74 */
75static inline int FlowHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b)
76{
77 for (uint8_t i = 0; i < 4; i++) {
78 if (a[i] > b[i])
79 return 1;
80 if (a[i] < b[i])
81 break;
82 }
83
84 return 0;
85}
86
87typedef struct FlowHashKey4_ {
88 union {
89 struct {
90 uint32_t addrs[2];
91 uint16_t ports[2];
92 uint8_t proto; /**< u8 so proto and recur and livedev add up to u32 */
93 uint8_t recur;
94 uint16_t livedev;
96 uint16_t pad[1];
97 };
98 const uint32_t u32[6];
99 };
101
102typedef struct FlowHashKey6_ {
103 union {
104 struct {
105 uint32_t src[4], dst[4];
106 uint16_t ports[2];
107 uint8_t proto; /**< u8 so proto and recur and livedev add up to u32 */
108 uint8_t recur;
109 uint16_t livedev;
111 uint16_t pad[1];
112 };
113 const uint32_t u32[12];
114 };
116
118{
119 uint32_t hash = 0;
120 if (PacketIsIPv4(p)) {
121 FlowHashKey4 fhk = {
122 .pad[0] = 0,
123 };
124
125 int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]);
126 fhk.addrs[1 - ai] = p->src.addr_data32[0];
127 fhk.addrs[ai] = p->dst.addr_data32[0];
128
129 fhk.ports[0] = 0xfedc;
130 fhk.ports[1] = 0xba98;
131
132 fhk.proto = (uint8_t)p->proto;
133 /* g_recurlvl_mask sets the recursion_level to 0 if
134 * decoder.recursion-level.use-for-tracking is disabled.
135 */
136 fhk.recur = (uint8_t)p->recursion_level & g_recurlvl_mask;
137 /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking
138 * is disabled. */
139 fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
140 fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
141 fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
142
143 hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand);
144 } else if (PacketIsIPv6(p)) {
145 FlowHashKey6 fhk = {
146 .pad[0] = 0,
147 };
148 if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
149 fhk.src[0] = p->src.addr_data32[0];
150 fhk.src[1] = p->src.addr_data32[1];
151 fhk.src[2] = p->src.addr_data32[2];
152 fhk.src[3] = p->src.addr_data32[3];
153 fhk.dst[0] = p->dst.addr_data32[0];
154 fhk.dst[1] = p->dst.addr_data32[1];
155 fhk.dst[2] = p->dst.addr_data32[2];
156 fhk.dst[3] = p->dst.addr_data32[3];
157 } else {
158 fhk.src[0] = p->dst.addr_data32[0];
159 fhk.src[1] = p->dst.addr_data32[1];
160 fhk.src[2] = p->dst.addr_data32[2];
161 fhk.src[3] = p->dst.addr_data32[3];
162 fhk.dst[0] = p->src.addr_data32[0];
163 fhk.dst[1] = p->src.addr_data32[1];
164 fhk.dst[2] = p->src.addr_data32[2];
165 fhk.dst[3] = p->src.addr_data32[3];
166 }
167
168 fhk.ports[0] = 0xfedc;
169 fhk.ports[1] = 0xba98;
170 fhk.proto = (uint8_t)p->proto;
171 fhk.recur = (uint8_t)p->recursion_level & g_recurlvl_mask;
172 fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
173 fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
174 fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
175
176 hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand);
177 }
178 return hash;
179}
180
181/* calculate the hash key for this packet
182 *
183 * we're using:
184 * hash_rand -- set at init time
185 * source port
186 * destination port
187 * source address
188 * destination address
189 * recursion level -- for tunnels, make sure different tunnel layers can
190 * never get mixed up.
191 *
192 * For ICMP we only consider UNREACHABLE errors atm.
193 */
194static inline uint32_t FlowGetHash(const Packet *p)
195{
196 uint32_t hash = 0;
197
198 if (PacketIsIPv4(p)) {
199 if (PacketIsTCP(p) || PacketIsUDP(p)) {
200 FlowHashKey4 fhk = { .pad[0] = 0 };
201
202 int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]);
203 fhk.addrs[1-ai] = p->src.addr_data32[0];
204 fhk.addrs[ai] = p->dst.addr_data32[0];
205
206 const int pi = (p->sp > p->dp);
207 fhk.ports[1-pi] = p->sp;
208 fhk.ports[pi] = p->dp;
209
210 fhk.proto = p->proto;
211 /* g_recurlvl_mask sets the recursion_level to 0 if
212 * decoder.recursion-level.use-for-tracking is disabled.
213 */
215 /* g_livedev_mask sets the livedev ids to 0 if livedev.use-for-tracking
216 * is disabled. */
217 uint16_t devid = p->livedev ? p->livedev->id : 0;
218 fhk.livedev = devid & g_livedev_mask;
219 /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking
220 * is disabled. */
221 fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
222 fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
223 fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
224
225 hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand);
226
227 } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) {
228 uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(PacketGetICMPv4EmbIPv4(p));
229 uint32_t pdst = IPV4_GET_RAW_IPDST_U32(PacketGetICMPv4EmbIPv4(p));
230 FlowHashKey4 fhk = { .pad[0] = 0 };
231
232 const int ai = (psrc > pdst);
233 fhk.addrs[1-ai] = psrc;
234 fhk.addrs[ai] = pdst;
235
236 const int pi = (p->l4.vars.icmpv4.emb_sport > p->l4.vars.icmpv4.emb_dport);
237 fhk.ports[1 - pi] = p->l4.vars.icmpv4.emb_sport;
238 fhk.ports[pi] = p->l4.vars.icmpv4.emb_dport;
239
242 uint16_t devid = p->livedev ? p->livedev->id : 0;
243 fhk.livedev = devid & g_livedev_mask;
244 fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
245 fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
246 fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
247
248 hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand);
249
250 } else {
251 FlowHashKey4 fhk = { .pad[0] = 0 };
252 const int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]);
253 fhk.addrs[1-ai] = p->src.addr_data32[0];
254 fhk.addrs[ai] = p->dst.addr_data32[0];
255 fhk.ports[0] = 0xfeed;
256 fhk.ports[1] = 0xbeef;
257 fhk.proto = p->proto;
259 uint16_t devid = p->livedev ? p->livedev->id : 0;
260 fhk.livedev = devid & g_livedev_mask;
261 fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
262 fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
263 fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
264
265 hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand);
266 }
267 } else if (PacketIsIPv6(p)) {
268 FlowHashKey6 fhk = { .pad[0] = 0 };
269 if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
270 fhk.src[0] = p->src.addr_data32[0];
271 fhk.src[1] = p->src.addr_data32[1];
272 fhk.src[2] = p->src.addr_data32[2];
273 fhk.src[3] = p->src.addr_data32[3];
274 fhk.dst[0] = p->dst.addr_data32[0];
275 fhk.dst[1] = p->dst.addr_data32[1];
276 fhk.dst[2] = p->dst.addr_data32[2];
277 fhk.dst[3] = p->dst.addr_data32[3];
278 } else {
279 fhk.src[0] = p->dst.addr_data32[0];
280 fhk.src[1] = p->dst.addr_data32[1];
281 fhk.src[2] = p->dst.addr_data32[2];
282 fhk.src[3] = p->dst.addr_data32[3];
283 fhk.dst[0] = p->src.addr_data32[0];
284 fhk.dst[1] = p->src.addr_data32[1];
285 fhk.dst[2] = p->src.addr_data32[2];
286 fhk.dst[3] = p->src.addr_data32[3];
287 }
288
289 const int pi = (p->sp > p->dp);
290 fhk.ports[1-pi] = p->sp;
291 fhk.ports[pi] = p->dp;
292 fhk.proto = p->proto;
294 uint16_t devid = p->livedev ? p->livedev->id : 0;
295 fhk.livedev = devid & g_livedev_mask;
296 fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
297 fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
298 fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
299
300 hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand);
301 }
302
303 return hash;
304}
305
306/**
307 * Basic hashing function for FlowKey
308 *
309 * \note Function only used for bypass and TCP or UDP flows
310 *
311 * \note this is only used at start to create Flow from pinned maps
312 * so fairness is not an issue
313 */
315{
316 uint32_t hash = 0;
317
318 if (fk->src.family == AF_INET) {
319 FlowHashKey4 fhk = {
320 .pad[0] = 0,
321 };
322 int ai = (fk->src.address.address_un_data32[0] > fk->dst.address.address_un_data32[0]);
323 fhk.addrs[1-ai] = fk->src.address.address_un_data32[0];
324 fhk.addrs[ai] = fk->dst.address.address_un_data32[0];
325
326 const int pi = (fk->sp > fk->dp);
327 fhk.ports[1-pi] = fk->sp;
328 fhk.ports[pi] = fk->dp;
329
330 fhk.proto = fk->proto;
333 fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask;
334 fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask;
335 fhk.vlan_id[2] = fk->vlan_id[2] & g_vlan_mask;
336
337 hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand);
338 } else {
339 FlowHashKey6 fhk = {
340 .pad[0] = 0,
341 };
342 if (FlowHashRawAddressIPv6GtU32(fk->src.address.address_un_data32,
344 fhk.src[0] = fk->src.address.address_un_data32[0];
345 fhk.src[1] = fk->src.address.address_un_data32[1];
346 fhk.src[2] = fk->src.address.address_un_data32[2];
347 fhk.src[3] = fk->src.address.address_un_data32[3];
348 fhk.dst[0] = fk->dst.address.address_un_data32[0];
349 fhk.dst[1] = fk->dst.address.address_un_data32[1];
350 fhk.dst[2] = fk->dst.address.address_un_data32[2];
351 fhk.dst[3] = fk->dst.address.address_un_data32[3];
352 } else {
353 fhk.src[0] = fk->dst.address.address_un_data32[0];
354 fhk.src[1] = fk->dst.address.address_un_data32[1];
355 fhk.src[2] = fk->dst.address.address_un_data32[2];
356 fhk.src[3] = fk->dst.address.address_un_data32[3];
357 fhk.dst[0] = fk->src.address.address_un_data32[0];
358 fhk.dst[1] = fk->src.address.address_un_data32[1];
359 fhk.dst[2] = fk->src.address.address_un_data32[2];
360 fhk.dst[3] = fk->src.address.address_un_data32[3];
361 }
362
363 const int pi = (fk->sp > fk->dp);
364 fhk.ports[1-pi] = fk->sp;
365 fhk.ports[pi] = fk->dp;
366 fhk.proto = fk->proto;
369 fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask;
370 fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask;
371 fhk.vlan_id[2] = fk->vlan_id[2] & g_vlan_mask;
372
373 hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand);
374 }
375 return hash;
376}
377
378static inline bool CmpAddrs(const uint32_t addr1[4], const uint32_t addr2[4])
379{
380 return addr1[0] == addr2[0] && addr1[1] == addr2[1] &&
381 addr1[2] == addr2[2] && addr1[3] == addr2[3];
382}
383
384static inline bool CmpAddrsAndPorts(const uint32_t src1[4],
385 const uint32_t dst1[4], Port src_port1, Port dst_port1,
386 const uint32_t src2[4], const uint32_t dst2[4], Port src_port2,
387 Port dst_port2)
388{
389 /* Compare the source and destination addresses. If they are not equal,
390 * compare the first source address with the second destination address,
391 * and vice versa. Likewise for ports. */
392 return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) &&
393 src_port1 == src_port2 && dst_port1 == dst_port2) ||
394 (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) &&
395 src_port1 == dst_port2 && dst_port1 == src_port2);
396}
397
398static inline bool CmpVlanIds(
399 const uint16_t vlan_id1[VLAN_MAX_LAYERS], const uint16_t vlan_id2[VLAN_MAX_LAYERS])
400{
401 return ((vlan_id1[0] ^ vlan_id2[0]) & g_vlan_mask) == 0 &&
402 ((vlan_id1[1] ^ vlan_id2[1]) & g_vlan_mask) == 0 &&
403 ((vlan_id1[2] ^ vlan_id2[2]) & g_vlan_mask) == 0;
404}
405
406static inline bool CmpLiveDevIds(const LiveDevice *livedev, const uint16_t id)
407{
408 uint16_t devid = livedev ? livedev->id : 0;
409 return (((devid ^ id) & g_livedev_mask) == 0);
410}
411
412/* Since two or more flows can have the same hash key, we need to compare
413 * the flow with the current packet or flow key. */
414static inline bool CmpFlowPacket(const Flow *f, const Packet *p)
415{
416 const uint32_t *f_src = f->src.address.address_un_data32;
417 const uint32_t *f_dst = f->dst.address.address_un_data32;
418 const uint32_t *p_src = p->src.address.address_un_data32;
419 const uint32_t *p_dst = p->dst.address.address_un_data32;
420 return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, p_src, p_dst, p->sp, p->dp) &&
421 f->proto == p->proto &&
423 CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0);
424}
425
426static inline bool CmpFlowKey(const Flow *f, const FlowKey *k)
427{
428 const uint32_t *f_src = f->src.address.address_un_data32;
429 const uint32_t *f_dst = f->dst.address.address_un_data32;
430 const uint32_t *k_src = k->src.address.address_un_data32;
431 const uint32_t *k_dst = k->dst.address.address_un_data32;
432 return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, k_src, k_dst, k->sp, k->dp) &&
433 f->proto == k->proto &&
435 CmpVlanIds(f->vlan_id, k->vlan_id) && CmpLiveDevIds(f->livedev, k->livedev_id);
436}
437
438static inline bool CmpAddrsAndICMPTypes(const uint32_t src1[4],
439 const uint32_t dst1[4], uint8_t icmp_s_type1, uint8_t icmp_d_type1,
440 const uint32_t src2[4], const uint32_t dst2[4], uint8_t icmp_s_type2,
441 uint8_t icmp_d_type2)
442{
443 /* Compare the source and destination addresses. If they are not equal,
444 * compare the first source address with the second destination address,
445 * and vice versa. Likewise for icmp types. */
446 return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) &&
447 icmp_s_type1 == icmp_s_type2 && icmp_d_type1 == icmp_d_type2) ||
448 (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) &&
449 icmp_s_type1 == icmp_d_type2 && icmp_d_type1 == icmp_s_type2);
450}
451
452static inline bool CmpFlowICMPPacket(const Flow *f, const Packet *p)
453{
454 const uint32_t *f_src = f->src.address.address_un_data32;
455 const uint32_t *f_dst = f->dst.address.address_un_data32;
456 const uint32_t *p_src = p->src.address.address_un_data32;
457 const uint32_t *p_dst = p->dst.address.address_un_data32;
458 return CmpAddrsAndICMPTypes(f_src, f_dst, f->icmp_s.type, f->icmp_d.type, p_src, p_dst,
459 p->icmp_s.type, p->icmp_d.type) &&
460 f->proto == p->proto &&
462 CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0);
463}
464
465/**
466 * \brief See if a ICMP packet belongs to a flow by comparing the embedded
467 * packet in the ICMP error packet to the flow.
468 *
469 * \param f flow
470 * \param p ICMP packet
471 *
472 * \retval 1 match
473 * \retval 0 no match
474 */
475static inline int FlowCompareICMPv4(Flow *f, const Packet *p)
476{
478 /* first check the direction of the flow, in other words, the client ->
479 * server direction as it's most likely the ICMP error will be a
480 * response to the clients traffic */
481 if ((f->src.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32(PacketGetICMPv4EmbIPv4(p))) &&
482 (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(PacketGetICMPv4EmbIPv4(p))) &&
483 f->sp == p->l4.vars.icmpv4.emb_sport && f->dp == p->l4.vars.icmpv4.emb_dport &&
484 f->proto == ICMPV4_GET_EMB_PROTO(p) &&
486 CmpVlanIds(f->vlan_id, p->vlan_id) &&
487 (f->livedev == p->livedev || g_livedev_mask == 0)) {
488 return 1;
489
490 /* check the less likely case where the ICMP error was a response to
491 * a packet from the server. */
492 } else if ((f->dst.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32(PacketGetICMPv4EmbIPv4(p))) &&
493 (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(PacketGetICMPv4EmbIPv4(p))) &&
494 f->dp == p->l4.vars.icmpv4.emb_sport && f->sp == p->l4.vars.icmpv4.emb_dport &&
495 f->proto == ICMPV4_GET_EMB_PROTO(p) &&
497 CmpVlanIds(f->vlan_id, p->vlan_id) &&
498 (f->livedev == p->livedev || g_livedev_mask == 0)) {
499 return 1;
500 }
501
502 /* no match, fall through */
503 } else {
504 /* just treat ICMP as a normal proto for now */
505 return CmpFlowICMPPacket(f, p);
506 }
507
508 return 0;
509}
510
511/**
512 * \brief See if a IP-ESP packet belongs to a flow by comparing the SPI
513 *
514 * \param f flow
515 * \param p ESP packet
516 *
517 * \retval 1 match
518 * \retval 0 no match
519 */
520static inline int FlowCompareESP(Flow *f, const Packet *p)
521{
522 const uint32_t *f_src = f->src.address.address_un_data32;
523 const uint32_t *f_dst = f->dst.address.address_un_data32;
524 const uint32_t *p_src = p->src.address.address_un_data32;
525 const uint32_t *p_dst = p->dst.address.address_un_data32;
526
527 return CmpAddrs(f_src, p_src) && CmpAddrs(f_dst, p_dst) && f->proto == p->proto &&
529 CmpVlanIds(f->vlan_id, p->vlan_id) && f->esp.spi == ESP_GET_SPI(PacketGetESP(p)) &&
530 (f->livedev == p->livedev || g_livedev_mask == 0);
531}
532
534{
535 p->flags |= PKT_WANTS_FLOW;
536 p->flow_hash = FlowGetHash(p);
537}
538
539static inline int FlowCompare(Flow *f, const Packet *p)
540{
541 if (p->proto == IPPROTO_ICMP) {
542 return FlowCompareICMPv4(f, p);
543 } else if (PacketIsESP(p)) {
544 return FlowCompareESP(f, p);
545 }
546 return CmpFlowPacket(f, p);
547}
548
549/**
550 * \brief Check if we should create a flow based on a packet
551 *
552 * We use this check to filter out flow creation based on:
553 * - ICMP error messages
554 * - TCP flags (emergency mode only)
555 *
556 * \param p packet
557 * \retval true
558 * \retval false
559 */
560static inline bool FlowCreateCheck(const Packet *p, const bool emerg)
561{
562 /* if we're in emergency mode, don't try to create a flow for a TCP
563 * that is not a TCP SYN packet. */
564 if (emerg) {
565 if (PacketIsTCP(p)) {
566 const TCPHdr *tcph = PacketGetTCP(p);
567 if (((tcph->th_flags & (TH_SYN | TH_ACK | TH_RST | TH_FIN)) == TH_SYN) ||
569 ;
570 } else {
571 return false;
572 }
573 }
574 }
575
576 if (PacketIsICMPv4(p)) {
578 return false;
579 }
580 }
581
582 return true;
583}
584
585static inline void FlowUpdateCounter(ThreadVars *tv, DecodeThreadVars *dtv,
586 uint8_t proto)
587{
588#ifdef UNITTESTS
589 if (tv && dtv) {
590#endif
593 switch (proto){
594 case IPPROTO_UDP:
596 break;
597 case IPPROTO_TCP:
599 break;
600 case IPPROTO_ICMP:
602 break;
603 case IPPROTO_ICMPV6:
605 break;
606 }
607#ifdef UNITTESTS
608 }
609#endif
610}
611
612/** \internal
613 * \brief try to fetch a new set of flows from the master flow pool.
614 *
615 * If in emergency mode, do this only once a second at max to avoid trying
616 * to synchronise per packet in the worse case. */
617static inline Flow *FlowSpareSync(ThreadVars *tv, FlowLookupStruct *fls,
618 const Packet *p, const bool emerg)
619{
620 Flow *f = NULL;
621 bool spare_sync = false;
622 if (emerg) {
623 if ((uint32_t)SCTIME_SECS(p->ts) > fls->emerg_spare_sync_stamp) {
624 fls->spare_queue = FlowSpareGetFromPool(); /* local empty, (re)populate and try again */
625 spare_sync = true;
627 if (f == NULL) {
628 /* wait till next full sec before retrying */
629 fls->emerg_spare_sync_stamp = (uint32_t)SCTIME_SECS(p->ts);
630 }
631 }
632 } else {
633 fls->spare_queue = FlowSpareGetFromPool(); /* local empty, (re)populate and try again */
635 spare_sync = true;
636 }
637#ifdef UNITTESTS
638 if (tv && fls->dtv) {
639#endif
640 if (spare_sync) {
641 if (f != NULL) {
643 if (fls->spare_queue.len < 99) {
645 }
646 } else if (fls->spare_queue.len == 0) {
648 }
650 }
651#ifdef UNITTESTS
652 }
653#endif
654 return f;
655}
656
657static void FlowExceptionPolicyStatsIncr(
658 ThreadVars *tv, FlowLookupStruct *fls, enum ExceptionPolicy policy)
659{
660#ifdef UNITTESTS
661 if (tv == NULL || fls->dtv == NULL) {
662 return;
663 }
664#endif
665 uint16_t id = fls->dtv->counter_flow_memcap_eps.eps_id[policy];
666 if (likely(id > 0)) {
667 StatsIncr(tv, id);
668 }
669}
670
671static inline void NoFlowHandleIPS(ThreadVars *tv, FlowLookupStruct *fls, Packet *p)
672{
674 FlowExceptionPolicyStatsIncr(tv, fls, flow_config.memcap_policy);
675}
676
677/**
678 * \brief Get a new flow
679 *
680 * Get a new flow. We're checking memcap first and will try to make room
681 * if the memcap is reached.
682 *
683 * \param tv thread vars
684 * \param fls lookup support vars
685 *
686 * \retval f *LOCKED* flow on success, NULL on error or if we should not create
687 * a new flow.
688 */
689static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, Packet *p)
690{
691 const bool emerg = ((SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) != 0);
692#ifdef DEBUG
693 if (g_eps_flow_memcap != UINT64_MAX && g_eps_flow_memcap == p->pcap_cnt) {
694 NoFlowHandleIPS(tv, fls, p);
696 return NULL;
697 }
698#endif
699 if (!FlowCreateCheck(p, emerg)) {
700 return NULL;
701 }
702
703 /* get a flow from the spare queue */
705 if (f == NULL) {
706 f = FlowSpareSync(tv, fls, p, emerg);
707 }
708 if (f == NULL) {
709 /* If we reached the max memcap, we get a used flow */
710 if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) {
711 /* declare state of emergency */
712 if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) {
713 SC_ATOMIC_OR(flow_flags, FLOW_EMERGENCY);
716 }
717
718 f = FlowGetUsedFlow(tv, fls->dtv, p->ts);
719 if (f == NULL) {
720 NoFlowHandleIPS(tv, fls, p);
721#ifdef UNITTESTS
722 if (tv != NULL && fls->dtv != NULL) {
723#endif
725#ifdef UNITTESTS
726 }
727#endif
728 return NULL;
729 }
730#ifdef UNITTESTS
731 if (tv != NULL && fls->dtv != NULL) {
732#endif
734#ifdef UNITTESTS
735 }
736#endif
737 /* flow is still locked from FlowGetUsedFlow() */
738 FlowUpdateCounter(tv, fls->dtv, p->proto);
739 return f;
740 }
741
742 /* now see if we can alloc a new flow */
743 f = FlowAlloc();
744 if (f == NULL) {
745#ifdef UNITTESTS
746 if (tv != NULL && fls->dtv != NULL) {
747#endif
749#ifdef UNITTESTS
750 }
751#endif
752 NoFlowHandleIPS(tv, fls, p);
753 return NULL;
754 }
755
756 /* flow is initialized but *unlocked* */
757 } else {
758 /* flow has been recycled before it went into the spare queue */
759
760 /* flow is initialized (recycled) but *unlocked* */
761 }
762
764 FlowUpdateCounter(tv, fls->dtv, p->proto);
765 return f;
766}
767
768static Flow *TcpReuseReplace(ThreadVars *tv, FlowLookupStruct *fls, FlowBucket *fb, Flow *old_f,
769 const uint32_t hash, Packet *p)
770{
771#ifdef UNITTESTS
772 if (tv != NULL && fls->dtv != NULL) {
773#endif
775#ifdef UNITTESTS
776 }
777#endif
778 /* get some settings that we move over to the new flow */
779 FlowThreadId thread_id[2] = { old_f->thread_id[0], old_f->thread_id[1] };
781
782 /* flow is unlocked by caller */
783
784 /* Get a new flow. It will be either a locked flow or NULL */
785 Flow *f = FlowGetNew(tv, fls, p);
786 if (f == NULL) {
787 return NULL;
788 }
789
790 /* put at the start of the list */
791 f->next = fb->head;
792 fb->head = f;
793
794 /* initialize and return */
795 FlowInit(tv, f, p);
796 f->flow_hash = hash;
797 f->fb = fb;
799
800 f->thread_id[0] = thread_id[0];
801 f->thread_id[1] = thread_id[1];
802
804 return f;
805}
806
807static inline bool FlowBelongsToUs(const ThreadVars *tv, const Flow *f)
808{
809#ifdef UNITTESTS
810 if (RunmodeIsUnittests()) {
811 return true;
812 }
813#endif
814 return f->thread_id[0] == tv->id;
815}
816
817static inline void MoveToWorkQueue(ThreadVars *tv, FlowLookupStruct *fls,
818 FlowBucket *fb, Flow *f, Flow *prev_f)
819{
821
822 /* remove from hash... */
823 if (prev_f) {
824 prev_f->next = f->next;
825 }
826 if (f == fb->head) {
827 fb->head = f->next;
828 }
829
830 if (f->proto != IPPROTO_TCP || FlowBelongsToUs(tv, f)) { // TODO thread_id[] direction
831 f->fb = NULL;
832 f->next = NULL;
834 } else {
835 /* implied: TCP but our thread does not own it. So set it
836 * aside for the Flow Manager to pick it up. */
837 f->next = fb->evicted;
838 fb->evicted = f;
839 if (SC_ATOMIC_GET(f->fb->next_ts) != 0) {
840 SC_ATOMIC_SET(f->fb->next_ts, 0);
841 }
842 }
843}
844
845static inline bool FlowIsTimedOut(
846 const FlowThreadId ftid, const Flow *f, const SCTime_t pktts, const bool emerg)
847{
848 SCTime_t timesout_at;
849 if (emerg) {
851 timesout_at = SCTIME_ADD_SECS(f->lastts,
852 FlowGetFlowTimeoutDirect(flow_timeouts_emerg, f->flow_state, f->protomap));
853 } else {
854 timesout_at = SCTIME_ADD_SECS(f->lastts, f->timeout_policy);
855 }
856 /* if time is live, we just use the pktts */
857 if (TimeModeIsLive() || ftid == f->thread_id[0] || f->thread_id[0] == 0) {
858 if (SCTIME_CMP_LT(pktts, timesout_at)) {
859 return false;
860 }
861 } else {
863 /* do the timeout check */
864 if (SCTIME_CMP_LT(checkts, timesout_at)) {
865 return false;
866 }
867 }
868 return true;
869}
870
871static inline uint16_t GetTvId(const ThreadVars *tv)
872{
873 uint16_t tv_id;
874#ifdef UNITTESTS
875 if (RunmodeIsUnittests()) {
876 tv_id = 0;
877 } else {
878 tv_id = (uint16_t)tv->id;
879 }
880#else
881 tv_id = (uint16_t)tv->id;
882#endif
883 return tv_id;
884}
885
886/** \brief Get Flow for packet
887 *
888 * Hash retrieval function for flows. Looks up the hash bucket containing the
889 * flow pointer. Then compares the packet with the found flow to see if it is
890 * the flow we need. If it isn't, walk the list until the right flow is found.
891 *
892 * If the flow is not found or the bucket was empty, a new flow is taken from
893 * the spare pool. The pool will alloc new flows as long as we stay within our
894 * memcap limit.
895 *
896 * The p->flow pointer is updated to point to the flow.
897 *
898 * \param tv thread vars
899 * \param dtv decode thread vars (for flow log api thread data)
900 *
901 * \retval f *LOCKED* flow or NULL
902 */
904{
905 Flow *f = NULL;
906
907 /* get our hash bucket and lock it */
908 const uint32_t hash = p->flow_hash;
909 FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
910 FBLOCK_LOCK(fb);
911
912 SCLogDebug("fb %p fb->head %p", fb, fb->head);
913
914 /* see if the bucket already has a flow */
915 if (fb->head == NULL) {
916 f = FlowGetNew(tv, fls, p);
917 if (f == NULL) {
918 FBLOCK_UNLOCK(fb);
919 return NULL;
920 }
921
922 /* flow is locked */
923 fb->head = f;
924
925 /* got one, now lock, initialize and return */
926 FlowInit(tv, f, p);
927 f->flow_hash = hash;
928 f->fb = fb;
930
931 FlowReference(dest, f);
932
933 FBLOCK_UNLOCK(fb);
934 return f;
935 }
936
937 const uint16_t tv_id = GetTvId(tv);
938 const bool emerg = (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) != 0;
939 const uint32_t fb_nextts = !emerg ? SC_ATOMIC_GET(fb->next_ts) : 0;
940 const bool timeout_check = (fb_nextts <= (uint32_t)SCTIME_SECS(p->ts));
941 /* ok, we have a flow in the bucket. Let's find out if it is our flow */
942 Flow *prev_f = NULL; /* previous flow */
943 f = fb->head;
944 do {
945 Flow *next_f = NULL;
946 const bool our_flow = FlowCompare(f, p) != 0;
947 if (our_flow || timeout_check) {
949 const bool timedout = (timeout_check && FlowIsTimedOut(tv_id, f, p->ts, emerg));
950 if (timedout) {
951 next_f = f->next;
952 MoveToWorkQueue(tv, fls, fb, f, prev_f);
954 goto flow_removed;
955 } else if (our_flow) {
956 /* found a matching flow that is not timed out */
958 Flow *new_f = TcpReuseReplace(tv, fls, fb, f, hash, p);
959 if (prev_f == NULL) /* if we have no prev it means new_f is now our prev */
960 prev_f = new_f;
961 MoveToWorkQueue(tv, fls, fb, f, prev_f); /* evict old flow */
962 FLOWLOCK_UNLOCK(f); /* unlock old replaced flow */
963
964 if (new_f == NULL) {
965 FBLOCK_UNLOCK(fb);
966 return NULL;
967 }
968 f = new_f;
969 }
970 FlowReference(dest, f);
971 FBLOCK_UNLOCK(fb);
972 return f; /* return w/o releasing flow lock */
973 } else {
975 }
976 }
977 /* unless we removed 'f', prev_f needs to point to
978 * current 'f' when adding a new flow below. */
979 prev_f = f;
980 next_f = f->next;
981
982flow_removed:
983 if (next_f == NULL) {
984 f = FlowGetNew(tv, fls, p);
985 if (f == NULL) {
986 FBLOCK_UNLOCK(fb);
987 return NULL;
988 }
989
990 /* flow is locked */
991
992 f->next = fb->head;
993 fb->head = f;
994
995 /* initialize and return */
996 FlowInit(tv, f, p);
997 f->flow_hash = hash;
998 f->fb = fb;
1000 FlowReference(dest, f);
1001 FBLOCK_UNLOCK(fb);
1002 return f;
1003 }
1004 f = next_f;
1005 } while (f != NULL);
1006
1007 /* should be unreachable */
1008 BUG_ON(1);
1009 return NULL;
1010}
1011
1012/** \internal
1013 * \retval true if flow matches key
1014 * \retval false if flow does not match key, or unsupported protocol
1015 * \note only supports TCP & UDP
1016 */
1017static inline bool FlowCompareKey(Flow *f, FlowKey *key)
1018{
1019 if ((f->proto != IPPROTO_TCP) && (f->proto != IPPROTO_UDP))
1020 return false;
1021 return CmpFlowKey(f, key);
1022}
1023
1024/** \brief Look for existing Flow using a flow id value
1025 *
1026 * Hash retrieval function for flows. Looks up the hash bucket containing the
1027 * flow pointer. Then compares the flow_id with the found flow's flow_id to see
1028 * if it is the flow we need.
1029 *
1030 * \param flow_id Flow ID of the flow to look for
1031 * \retval f *LOCKED* flow or NULL
1032 */
1034{
1035 uint32_t hash = flow_id & 0x0000FFFF;
1036 FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
1037 FBLOCK_LOCK(fb);
1038 SCLogDebug("fb %p fb->head %p", fb, fb->head);
1039
1040 for (Flow *f = fb->head; f != NULL; f = f->next) {
1041 if (FlowGetId(f) == flow_id) {
1042 /* found our flow, lock & return */
1043 FLOWLOCK_WRLOCK(f);
1044 FBLOCK_UNLOCK(fb);
1045 return f;
1046 }
1047 }
1048 FBLOCK_UNLOCK(fb);
1049 return NULL;
1050}
1051
1052/** \brief Look for existing Flow using a FlowKey
1053 *
1054 * Hash retrieval function for flows. Looks up the hash bucket containing the
1055 * flow pointer. Then compares the key with the found flow to see if it is
1056 * the flow we need. If it isn't, walk the list until the right flow is found.
1057 *
1058 * \param key Pointer to FlowKey build using flow to look for
1059 * \param hash Value of the flow hash
1060 * \retval f *LOCKED* flow or NULL
1061 */
1062static Flow *FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash)
1063{
1064 /* get our hash bucket and lock it */
1065 FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
1066 FBLOCK_LOCK(fb);
1067 SCLogDebug("fb %p fb->head %p", fb, fb->head);
1068
1069 for (Flow *f = fb->head; f != NULL; f = f->next) {
1070 /* see if this is the flow we are looking for */
1071 if (FlowCompareKey(f, key)) {
1072 /* found our flow, lock & return */
1073 FLOWLOCK_WRLOCK(f);
1074 FBLOCK_UNLOCK(fb);
1075 return f;
1076 }
1077 }
1078
1079 FBLOCK_UNLOCK(fb);
1080 return NULL;
1081}
1082
1083/** \brief Get or create a Flow using a FlowKey
1084 *
1085 * Hash retrieval function for flows. Looks up the hash bucket containing the
1086 * flow pointer. Then compares the packet with the found flow to see if it is
1087 * the flow we need. If it isn't, walk the list until the right flow is found.
1088 * Return a new Flow if ever no Flow was found.
1089 *
1090 *
1091 * \param key Pointer to FlowKey build using flow to look for
1092 * \param ttime time to use for flow creation
1093 * \param hash Value of the flow hash
1094 * \retval f *LOCKED* flow or NULL
1095 */
1096
1097Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash)
1098{
1099 Flow *f = FlowGetExistingFlowFromHash(key, hash);
1100
1101 if (f != NULL) {
1102 return f;
1103 }
1104 /* TODO use spare pool */
1105 /* now see if we can alloc a new flow */
1106 f = FlowAlloc();
1107 if (f == NULL) {
1108 SCLogDebug("Can't get a spare flow at start");
1109 return NULL;
1110 }
1111 f->proto = key->proto;
1112 memcpy(&f->vlan_id[0], &key->vlan_id[0], sizeof(f->vlan_id));
1113 ;
1114 f->src.addr_data32[0] = key->src.addr_data32[0];
1115 f->src.addr_data32[1] = key->src.addr_data32[1];
1116 f->src.addr_data32[2] = key->src.addr_data32[2];
1117 f->src.addr_data32[3] = key->src.addr_data32[3];
1118 f->dst.addr_data32[0] = key->dst.addr_data32[0];
1119 f->dst.addr_data32[1] = key->dst.addr_data32[1];
1120 f->dst.addr_data32[2] = key->dst.addr_data32[2];
1121 f->dst.addr_data32[3] = key->dst.addr_data32[3];
1122 f->sp = key->sp;
1123 f->dp = key->dp;
1124 f->recursion_level = 0;
1125 // f->livedev is set by caller EBPFCreateFlowForKey
1126 f->flow_hash = hash;
1127 if (key->src.family == AF_INET) {
1128 f->flags |= FLOW_IPV4;
1129 } else if (key->src.family == AF_INET6) {
1130 f->flags |= FLOW_IPV6;
1131 }
1132
1134 /* set timestamp to now */
1135 f->startts = SCTIME_FROM_TIMESPEC(ttime);
1136 f->lastts = f->startts;
1137
1138 FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
1139 FBLOCK_LOCK(fb);
1140 f->fb = fb;
1141 f->next = fb->head;
1142 fb->head = f;
1143 FLOWLOCK_WRLOCK(f);
1144 FBLOCK_UNLOCK(fb);
1145 return f;
1146}
1147
1148#define FLOW_GET_NEW_TRIES 5
1149
1150/* inline locking wrappers to make profiling easier */
1151
1152static inline int GetUsedTryLockBucket(FlowBucket *fb)
1153{
1154 int r = FBLOCK_TRYLOCK(fb);
1155 return r;
1156}
1157static inline int GetUsedTryLockFlow(Flow *f)
1158{
1159 int r = FLOWLOCK_TRYWRLOCK(f);
1160 return r;
1161}
1162static inline uint32_t GetUsedAtomicUpdate(const uint32_t val)
1163{
1164 uint32_t r = SC_ATOMIC_ADD(flow_prune_idx, val);
1165 return r;
1166}
1167
1168/** \internal
1169 * \brief check if flow has just seen an update.
1170 */
1171static inline bool StillAlive(const Flow *f, const SCTime_t ts)
1172{
1173 switch (f->flow_state) {
1174 case FLOW_STATE_NEW:
1175 if (SCTIME_SECS(ts) - SCTIME_SECS(f->lastts) <= 1) {
1176 return true;
1177 }
1178 break;
1180 if (SCTIME_SECS(ts) - SCTIME_SECS(f->lastts) <= 5) {
1181 return true;
1182 }
1183 break;
1184 case FLOW_STATE_CLOSED:
1185 if (SCTIME_SECS(ts) - SCTIME_SECS(f->lastts) <= 3) {
1186 return true;
1187 }
1188 break;
1189 default:
1190 if (SCTIME_SECS(ts) - SCTIME_SECS(f->lastts) < 30) {
1191 return true;
1192 }
1193 break;
1194 }
1195 return false;
1196}
1197
1198#ifdef UNITTESTS
1199 #define STATSADDUI64(cnt, value) \
1200 if (tv && dtv) { \
1201 StatsAddUI64(tv, dtv->cnt, (value)); \
1202 }
1203#else
1204 #define STATSADDUI64(cnt, value) \
1205 StatsAddUI64(tv, dtv->cnt, (value));
1206#endif
1207
1208/** \internal
1209 * \brief Get a flow from the hash directly.
1210 *
1211 * Called in conditions where the spare queue is empty and memcap is reached.
1212 *
1213 * Walks the hash until a flow can be freed. Timeouts are disregarded.
1214 * "flow_prune_idx" atomic int makes sure we don't start at the
1215 * top each time since that would clear the top of the hash leading to longer
1216 * and longer search times under high pressure (observed).
1217 *
1218 * \param tv thread vars
1219 * \param dtv decode thread vars (for flow log api thread data)
1220 *
1221 * \retval f flow or NULL
1222 */
1223static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv, const SCTime_t ts)
1224{
1225 uint32_t idx = GetUsedAtomicUpdate(FLOW_GET_NEW_TRIES) % flow_config.hash_size;
1226 uint32_t tried = 0;
1227
1228 while (1) {
1229 if (tried++ > FLOW_GET_NEW_TRIES) {
1230 STATSADDUI64(counter_flow_get_used_eval, tried);
1231 break;
1232 }
1233 if (++idx >= flow_config.hash_size)
1234 idx = 0;
1235
1236 FlowBucket *fb = &flow_hash[idx];
1237
1238 if (SC_ATOMIC_GET(fb->next_ts) == UINT_MAX)
1239 continue;
1240
1241 if (GetUsedTryLockBucket(fb) != 0) {
1242 STATSADDUI64(counter_flow_get_used_eval_busy, 1);
1243 continue;
1244 }
1245
1246 Flow *f = fb->head;
1247 if (f == NULL) {
1248 FBLOCK_UNLOCK(fb);
1249 continue;
1250 }
1251
1252 if (GetUsedTryLockFlow(f) != 0) {
1253 STATSADDUI64(counter_flow_get_used_eval_busy, 1);
1254 FBLOCK_UNLOCK(fb);
1255 continue;
1256 }
1257
1258 if (StillAlive(f, ts)) {
1259 STATSADDUI64(counter_flow_get_used_eval_reject, 1);
1260 FBLOCK_UNLOCK(fb);
1261 FLOWLOCK_UNLOCK(f);
1262 continue;
1263 }
1264
1265 /* remove from the hash */
1266 fb->head = f->next;
1267 f->next = NULL;
1268 f->fb = NULL;
1269 FBLOCK_UNLOCK(fb);
1270
1271 /* rest of the flags is updated on-demand in output */
1273 if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)
1275
1276 /* invoke flow log api */
1277#ifdef UNITTESTS
1278 if (dtv) {
1279#endif
1282 }
1283#ifdef UNITTESTS
1284 }
1285#endif
1286
1289
1290 /* leave locked */
1291
1292 STATSADDUI64(counter_flow_get_used_eval, tried);
1293 return f;
1294 }
1295
1296 STATSADDUI64(counter_flow_get_used_failed, 1);
1297 return NULL;
1298}
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition counters.c:166
void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Adds a value of type uint64_t to the local counter.
Definition counters.c:146
#define ESP_GET_SPI(esph)
Get the spi field off a packet.
Definition decode-esp.h:29
#define ICMPV4_GET_EMB_PROTO(p)
#define ICMPV4_DEST_UNREACH_IS_VALID(p)
#define ICMPV4_IS_ERROR_MSG(type)
#define IPV4_GET_RAW_IPSRC_U32(ip4h)
#define IPV4_GET_RAW_IPDST_U32(ip4h)
#define TH_FIN
Definition decode-tcp.h:34
#define TH_ACK
Definition decode-tcp.h:38
#define TH_RST
Definition decode-tcp.h:36
#define TH_SYN
Definition decode-tcp.h:35
uint8_t proto
#define VLAN_MAX_LAYERS
Definition decode-vlan.h:51
@ PKT_DROP_REASON_FLOW_MEMCAP
Definition decode.h:385
#define PKT_WANTS_FLOW
Definition decode.h:1296
uint16_t Port
Definition decode.h:218
Data structures and function prototypes for keeping state for the detection engine.
void SCFlowRunFinishCallbacks(ThreadVars *tv, Flow *f)
#define FLOW_GET_NEW_TRIES
Definition flow-hash.c:1148
FlowBucket * flow_hash
Definition flow-hash.c:59
void FlowSetupPacket(Packet *p)
prepare packet for a life with flow Set PKT_WANTS_FLOW flag to indicate workers should do a flow look...
Definition flow-hash.c:533
Flow * FlowGetExistingFlowFromFlowId(uint64_t flow_id)
Look for existing Flow using a flow id value.
Definition flow-hash.c:1033
Flow * FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash)
Get or create a Flow using a FlowKey.
Definition flow-hash.c:1097
struct FlowHashKey4_ FlowHashKey4
uint32_t FlowKeyGetHash(FlowKey *fk)
Definition flow-hash.c:314
uint32_t FlowGetIpPairProtoHash(const Packet *p)
Definition flow-hash.c:117
TcpStreamCnf stream_config
Definition stream-tcp.c:219
struct FlowHashKey6_ FlowHashKey6
#define STATSADDUI64(cnt, value)
Definition flow-hash.c:1199
Flow * FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *fls, Packet *p, Flow **dest)
Get Flow for packet.
Definition flow-hash.c:903
#define FBLOCK_TRYLOCK(fb)
Definition flow-hash.h:74
#define FBLOCK_LOCK(fb)
Definition flow-hash.h:73
#define FBLOCK_UNLOCK(fb)
Definition flow-hash.h:75
void FlowTimeoutsEmergency(void)
void FlowWakeupFlowManagerThread(void)
@ FLOW_PROTO_MAX
#define FLOW_EMERGENCY
FlowConfig flow_config
Definition flow.c:93
FlowProtoTimeout flow_timeouts_emerg[FLOW_PROTO_MAX]
Definition flow.c:89
void FlowQueuePrivateAppendFlow(FlowQueuePrivate *fqc, Flow *f)
Definition flow-queue.c:65
Flow * FlowQueuePrivateGetFromTop(FlowQueuePrivate *fqc)
Definition flow-queue.c:151
FlowQueuePrivate FlowSpareGetFromPool(void)
unsigned int FlowStorageSize(void)
Flow * FlowAlloc(void)
allocate a flow
Definition flow-util.c:56
uint8_t FlowGetProtoMapping(uint8_t proto)
Function to map the protocol to the defined FLOW_PROTO_* enumeration.
Definition flow-util.c:99
void FlowInit(ThreadVars *tv, Flow *f, const Packet *p)
Definition flow-util.c:147
#define FLOW_CHECK_MEMCAP(size)
check if a memory alloc would fit in the memcap
Definition flow-util.h:134
void FlowUpdateState(Flow *f, const enum FlowState s)
Definition flow.c:1162
int FlowClearMemory(Flow *f, uint8_t proto_map)
Function clear the flow memory before queueing it to spare flow queue.
Definition flow.c:1097
#define FLOWLOCK_TRYWRLOCK(fb)
Definition flow.h:272
@ FLOW_STATE_NEW
Definition flow.h:504
@ FLOW_STATE_CLOSED
Definition flow.h:506
@ FLOW_STATE_ESTABLISHED
Definition flow.h:505
#define FLOW_END_FLAG_FORCED
Definition flow.h:244
#define FLOW_END_FLAG_TIMEOUT
Definition flow.h:243
#define FLOW_END_FLAG_TCPREUSE
Definition flow.h:246
uint16_t FlowThreadId
Definition flow.h:333
#define FLOW_IPV6
Definition flow.h:102
#define FLOW_END_FLAG_EMERGENCY
Definition flow.h:242
#define FLOW_IPV4
Definition flow.h:100
#define FLOWLOCK_UNLOCK(fb)
Definition flow.h:273
#define FLOWLOCK_WRLOCK(fb)
Definition flow.h:270
DecodeThreadVars * dtv
ThreadVars * tv
TmEcode OutputFlowLog(ThreadVars *tv, void *thread_data, Flow *f)
Run flow logger(s)
Definition output-flow.c:87
uint64_t ts
#define STREAM_PKT_FLAG_SET(p, f)
#define STREAM_PKT_FLAG_TCP_SESSION_REUSE
bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
uint32_t address_un_data32[4]
Definition decode.h:115
union Address_::@30 address
char family
Definition decode.h:113
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
uint16_t counter_flow_icmp4
Definition decode.h:1037
uint16_t counter_flow_active
Definition decode.h:1034
uint16_t counter_flow_get_used
Definition decode.h:1041
uint16_t counter_flow_tcp_reuse
Definition decode.h:1039
void * output_flow_thread_data
Definition decode.h:1056
uint16_t counter_flow_spare_sync_incomplete
Definition decode.h:1049
uint16_t counter_flow_spare_sync
Definition decode.h:1047
uint16_t counter_flow_total
Definition decode.h:1033
uint16_t counter_flow_udp
Definition decode.h:1036
uint16_t counter_flow_spare_sync_avg
Definition decode.h:1050
uint16_t counter_flow_memcap
Definition decode.h:1029
uint16_t counter_flow_tcp
Definition decode.h:1035
uint16_t counter_flow_icmp6
Definition decode.h:1038
ExceptionPolicyCounters counter_flow_memcap_eps
Definition decode.h:1030
uint16_t counter_flow_spare_sync_empty
Definition decode.h:1048
uint16_t eps_id[EXCEPTION_POLICY_MAX]
uint32_t address_un_data32[4]
Definition flow.h:320
union FlowAddress_::@128 address
enum ExceptionPolicy memcap_policy
Definition flow.h:302
uint32_t hash_rand
Definition flow.h:293
uint32_t hash_size
Definition flow.h:294
uint16_t livedev
Definition flow-hash.c:94
const uint32_t u32[6]
Definition flow-hash.c:98
uint16_t pad[1]
Definition flow-hash.c:96
uint32_t addrs[2]
Definition flow-hash.c:90
uint8_t recur
Definition flow-hash.c:93
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition flow-hash.c:95
uint8_t proto
Definition flow-hash.c:92
uint16_t ports[2]
Definition flow-hash.c:91
uint8_t recur
Definition flow-hash.c:108
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition flow-hash.c:110
uint16_t livedev
Definition flow-hash.c:109
uint16_t ports[2]
Definition flow-hash.c:106
uint8_t proto
Definition flow-hash.c:107
const uint32_t u32[12]
Definition flow-hash.c:113
uint32_t dst[4]
Definition flow-hash.c:105
uint16_t pad[1]
Definition flow-hash.c:111
uint32_t src[4]
Definition flow-hash.c:105
Port sp
Definition flow.h:311
uint8_t recursion_level
Definition flow.h:313
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition flow.h:315
Address dst
Definition flow.h:310
Port dp
Definition flow.h:311
uint16_t livedev_id
Definition flow.h:314
uint8_t proto
Definition flow.h:312
Address src
Definition flow.h:310
FlowQueuePrivate spare_queue
Definition flow.h:544
DecodeThreadVars * dtv
Definition flow.h:545
FlowQueuePrivate work_queue
Definition flow.h:546
uint32_t emerg_spare_sync_stamp
Definition flow.h:547
Flow data structure.
Definition flow.h:356
struct Flow_::@129::@135 icmp_s
Port dp
Definition flow.h:372
uint8_t proto
Definition flow.h:378
uint32_t flow_hash
Definition flow.h:401
uint32_t flags
Definition flow.h:421
uint8_t flow_end_flags
Definition flow.h:447
FlowStateType flow_state
Definition flow.h:412
uint32_t timeout_policy
Definition flow.h:405
void * protoctx
Definition flow.h:441
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition flow.h:380
SCTime_t lastts
Definition flow.h:410
struct LiveDevice_ * livedev
Definition flow.h:398
uint8_t protomap
Definition flow.h:445
struct Flow_::@131::@137 icmp_d
struct Flow_::@129::@136 esp
struct FlowBucket_ * fb
Definition flow.h:491
FlowThreadId thread_id[2]
Definition flow.h:394
uint32_t spi
Definition flow.h:368
FlowAddress src
Definition flow.h:359
struct Flow_ * next
Definition flow.h:396
Port sp
Definition flow.h:361
uint8_t recursion_level
Definition flow.h:379
FlowAddress dst
Definition flow.h:359
uint8_t type
Definition flow.h:363
SCTime_t startts
Definition flow.h:493
uint16_t emb_dport
uint16_t emb_sport
union PacketL4::L4Vars vars
struct Packet_::@33::@40 icmp_s
struct PacketL4 l4
Definition decode.h:601
uint64_t pcap_cnt
Definition decode.h:626
SCTime_t ts
Definition decode.h:555
Address src
Definition decode.h:505
Port sp
Definition decode.h:508
uint8_t recursion_level
Definition decode.h:526
uint8_t type
Definition decode.h:511
struct Packet_::@35::@41 icmp_d
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition decode.h:528
uint32_t flow_hash
Definition decode.h:550
struct LiveDevice_ * livedev
Definition decode.h:618
uint32_t flags
Definition decode.h:544
Address dst
Definition decode.h:506
uint8_t proto
Definition decode.h:523
Port dp
Definition decode.h:516
uint8_t th_flags
Definition decode-tcp.h:155
Per thread variable structure.
Definition threadvars.h:58
#define BUG_ON(x)
#define ARRAY_SIZE(arr)
uint16_t g_livedev_mask
Definition suricata.c:206
uint8_t g_recurlvl_mask
Definition suricata.c:210
uint16_t g_vlan_mask
Definition suricata.c:202
int RunmodeIsUnittests(void)
Definition suricata.c:270
SCTime_t TmThreadsGetThreadTime(const int idx)
ICMPV4Vars icmpv4
Definition decode.h:479
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define SC_ATOMIC_OR(name, val)
Bitwise OR a value to our atomic variable.
#define SC_ATOMIC_EXTERN(type, name)
wrapper for referencing an atomic variable declared on another file.
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
#define SCLogDebug(...)
Definition util-debug.h:275
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval)
#define likely(expr)
#define unlikely(expr)
bool TimeModeIsLive(void)
Definition util-time.c:111
#define SCTIME_FROM_TIMESPEC(ts)
Definition util-time.h:91
#define SCTIME_SECS(t)
Definition util-time.h:57
#define SCTIME_CMP_LT(a, b)
Definition util-time.h:105
#define SCTIME_ADD_SECS(ts, s)
Definition util-time.h:64