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