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