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