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