suricata
stream-tcp.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 Gurvinder Singh <gurvindersinghdahiya@gmail.com>
23  *
24  * TCP stream tracking and reassembly engine.
25  *
26  * \todo - 4WHS: what if after the 2nd SYN we turn out to be normal 3WHS anyway?
27  */
28 
29 #include "suricata-common.h"
30 #include "suricata.h"
31 #include "packet.h"
32 #include "decode.h"
33 #include "detect.h"
34 
35 #include "flow.h"
36 #include "flow-util.h"
37 
38 #include "conf.h"
39 #include "conf-yaml-loader.h"
40 
41 #include "threads.h"
42 #include "threadvars.h"
43 #include "tm-threads.h"
44 
45 #include "util-pool.h"
46 #include "util-pool-thread.h"
47 #include "util-checksum.h"
48 #include "util-unittest.h"
49 #include "util-print.h"
50 #include "util-debug.h"
51 #include "util-device.h"
52 
53 #include "stream-tcp-private.h"
54 #include "stream-tcp.h"
55 #include "stream-tcp-cache.h"
56 #include "stream-tcp-inline.h"
57 #include "stream-tcp-reassemble.h"
58 #include "stream-tcp-sack.h"
59 #include "stream-tcp-util.h"
60 #include "stream.h"
61 
62 #include "pkt-var.h"
63 #include "host.h"
64 
65 #include "app-layer.h"
66 #include "app-layer-parser.h"
67 #include "app-layer-protos.h"
68 #include "app-layer-htp-mem.h"
69 
70 #include "util-host-os-info.h"
71 #include "util-privs.h"
72 #include "util-profiling.h"
73 #include "util-misc.h"
74 #include "util-validate.h"
75 #include "util-runmodes.h"
76 #include "util-random.h"
77 #include "util-exception-policy.h"
78 #include "util-time.h"
79 
80 #include "source-pcap-file.h"
81 #include "action-globals.h"
82 
83 //#define DEBUG
84 
85 #define STREAMTCP_DEFAULT_PREALLOC 2048
86 #define STREAMTCP_DEFAULT_MEMCAP (64 * 1024 * 1024) /* 64mb */
87 #define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP (256 * 1024 * 1024) /* 256mb */
88 #define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE 2560
89 #define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE 2560
90 #define STREAMTCP_DEFAULT_MAX_SYN_QUEUED 10
91 #define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED 5
92 
93 /* Settings order as in the enum */
94 // clang-format off
97  /* EXCEPTION_POLICY_NOT_SET */ false,
98  /* EXCEPTION_POLICY_AUTO */ false,
99  /* EXCEPTION_POLICY_PASS_PACKET */ true,
100  /* EXCEPTION_POLICY_PASS_FLOW */ true,
101  /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
102  /* EXCEPTION_POLICY_DROP_PACKET */ false,
103  /* EXCEPTION_POLICY_DROP_FLOW */ false,
104  /* EXCEPTION_POLICY_REJECT */ true,
105  },
106  .valid_settings_ips = {
107  /* EXCEPTION_POLICY_NOT_SET */ false,
108  /* EXCEPTION_POLICY_AUTO */ false,
109  /* EXCEPTION_POLICY_PASS_PACKET */ true,
110  /* EXCEPTION_POLICY_PASS_FLOW */ true,
111  /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
112  /* EXCEPTION_POLICY_DROP_PACKET */ true,
113  /* EXCEPTION_POLICY_DROP_FLOW */ true,
114  /* EXCEPTION_POLICY_REJECT */ true,
115  },
116 };
117 // clang-format on
118 
119 /* Settings order as in the enum */
120 // clang-format off
122  .valid_settings_ids = {
123  /* EXCEPTION_POLICY_NOT_SET */ false,
124  /* EXCEPTION_POLICY_AUTO */ false,
125  /* EXCEPTION_POLICY_PASS_PACKET */ true,
126  /* EXCEPTION_POLICY_PASS_FLOW */ true,
127  /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
128  /* EXCEPTION_POLICY_DROP_PACKET */ false,
129  /* EXCEPTION_POLICY_DROP_FLOW */ false,
130  /* EXCEPTION_POLICY_REJECT */ true,
131  },
132  .valid_settings_ips = {
133  /* EXCEPTION_POLICY_NOT_SET */ false,
134  /* EXCEPTION_POLICY_AUTO */ false,
135  /* EXCEPTION_POLICY_PASS_PACKET */ true,
136  /* EXCEPTION_POLICY_PASS_FLOW */ true,
137  /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
138  /* EXCEPTION_POLICY_DROP_PACKET */ true,
139  /* EXCEPTION_POLICY_DROP_FLOW */ true,
140  /* EXCEPTION_POLICY_REJECT */ true,
141  },
142 };
143 // clang-format on
144 
145 /* Settings order as in the enum */
146 // clang-format off
148  .valid_settings_ids = {
149  /* EXCEPTION_POLICY_NOT_SET */ false,
150  /* EXCEPTION_POLICY_AUTO */ false,
151  /* EXCEPTION_POLICY_PASS_PACKET */ false,
152  /* EXCEPTION_POLICY_PASS_FLOW */ true,
153  /* EXCEPTION_POLICY_BYPASS_FLOW */ false,
154  /* EXCEPTION_POLICY_DROP_PACKET */ false,
155  /* EXCEPTION_POLICY_DROP_FLOW */ false,
156  /* EXCEPTION_POLICY_REJECT */ false,
157  },
158  .valid_settings_ips = {
159  /* EXCEPTION_POLICY_NOT_SET */ false,
160  /* EXCEPTION_POLICY_AUTO */ false,
161  /* EXCEPTION_POLICY_PASS_PACKET */ false,
162  /* EXCEPTION_POLICY_PASS_FLOW */ true,
163  /* EXCEPTION_POLICY_BYPASS_FLOW */ false,
164  /* EXCEPTION_POLICY_DROP_PACKET */ false,
165  /* EXCEPTION_POLICY_DROP_FLOW */ false,
166  /* EXCEPTION_POLICY_REJECT */ false,
167  },
168 };
169 // clang-format on
170 
171 /* Settings order as in the enum */
172 // clang-format off
174  .valid_settings_ids = {
175  /* EXCEPTION_POLICY_NOT_SET */ false,
176  /* EXCEPTION_POLICY_AUTO */ false,
177  /* EXCEPTION_POLICY_PASS_PACKET */ false,
178  /* EXCEPTION_POLICY_PASS_FLOW */ true,
179  /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
180  /* EXCEPTION_POLICY_DROP_PACKET */ false,
181  /* EXCEPTION_POLICY_DROP_FLOW */ false,
182  /* EXCEPTION_POLICY_REJECT */ true,
183  },
184  .valid_settings_ips = {
185  /* EXCEPTION_POLICY_NOT_SET */ false,
186  /* EXCEPTION_POLICY_AUTO */ false,
187  /* EXCEPTION_POLICY_PASS_PACKET */ false,
188  /* EXCEPTION_POLICY_PASS_FLOW */ true,
189  /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
190  /* EXCEPTION_POLICY_DROP_PACKET */ false,
191  /* EXCEPTION_POLICY_DROP_FLOW */ true,
192  /* EXCEPTION_POLICY_REJECT */ true,
193  },
194 };
195 // clang-format on
196 
197 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *);
199 void StreamTcpInitConfig(bool);
202 
203 static int StreamTcpValidateTimestamp(TcpSession * , Packet *);
204 static int StreamTcpHandleTimestamp(TcpSession * , Packet *);
205 static int StreamTcpValidateRst(TcpSession * , Packet *);
206 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *, Packet *);
207 static int StreamTcpStateDispatch(
208  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state);
209 
210 extern thread_local uint64_t t_pcapcnt;
211 extern int g_detect_disabled;
212 
214 static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect initializing and growing pool */
215 #ifdef DEBUG
216 static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */
217 #endif
218 
221 SC_ATOMIC_DECLARE(uint64_t, st_memuse);
222 
224 {
225  SC_ATOMIC_INIT(st_memuse);
226 }
227 
228 void StreamTcpIncrMemuse(uint64_t size)
229 {
230  (void) SC_ATOMIC_ADD(st_memuse, size);
231  SCLogDebug("STREAM %" PRIu64 ", incr %" PRIu64, StreamTcpMemuseCounter(), size);
232 }
233 
234 void StreamTcpDecrMemuse(uint64_t size)
235 {
236 #if defined(DEBUG_VALIDATION) && defined(UNITTESTS)
237  uint64_t presize = SC_ATOMIC_GET(st_memuse);
238  if (RunmodeIsUnittests()) {
239  BUG_ON(presize > UINT_MAX);
240  }
241 #endif
242 
243  (void) SC_ATOMIC_SUB(st_memuse, size);
244 
245 #if defined(DEBUG_VALIDATION) && defined(UNITTESTS)
246  if (RunmodeIsUnittests()) {
247  uint64_t postsize = SC_ATOMIC_GET(st_memuse);
248  BUG_ON(postsize > presize);
249  }
250 #endif
251  SCLogDebug("STREAM %" PRIu64 ", decr %" PRIu64, StreamTcpMemuseCounter(), size);
252 }
253 
255 {
256  uint64_t memusecopy = SC_ATOMIC_GET(st_memuse);
257  return memusecopy;
258 }
259 
260 /**
261  * \brief Check if alloc'ing "size" would mean we're over memcap
262  *
263  * \retval 1 if in bounds
264  * \retval 0 if not in bounds
265  */
266 int StreamTcpCheckMemcap(uint64_t size)
267 {
268  uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.memcap);
269  if (memcapcopy == 0 || size + SC_ATOMIC_GET(st_memuse) <= memcapcopy)
270  return 1;
271  return 0;
272 }
273 
274 /**
275  * \brief Update memcap value
276  *
277  * \param size new memcap value
278  */
279 int StreamTcpSetMemcap(uint64_t size)
280 {
281  if (size == 0 || (uint64_t)SC_ATOMIC_GET(st_memuse) < size) {
282  SC_ATOMIC_SET(stream_config.memcap, size);
283  return 1;
284  }
285 
286  return 0;
287 }
288 
289 /**
290  * \brief Return memcap value
291  *
292  * \param memcap memcap value
293  */
294 uint64_t StreamTcpGetMemcap(void)
295 {
296  uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.memcap);
297  return memcapcopy;
298 }
299 
301 {
302  if (stream != NULL) {
303  StreamTcpSackFreeList(stream);
306  }
307 }
308 
309 static void StreamTcp3wsFreeQueue(TcpSession *ssn)
310 {
311  TcpStateQueue *q, *q_next;
312  q = ssn->queue;
313  while (q != NULL) {
314  q_next = q->next;
315  SCFree(q);
316  q = q_next;
317  StreamTcpDecrMemuse((uint64_t)sizeof(TcpStateQueue));
318  }
319  ssn->queue = NULL;
320  ssn->queue_len = 0;
321 }
322 
323 /**
324  * \brief Session cleanup function. Does not free the ssn.
325  * \param ssn tcp session
326  */
328 {
329  SCEnter();
330 
331  if (ssn == NULL)
332  return;
333 
336  StreamTcp3wsFreeQueue(ssn);
337 
338  SCReturn;
339 }
340 
341 /**
342  * \brief Function to return the stream back to the pool. It returns the
343  * segments in the stream to the segment pool.
344  *
345  * This function is called when the flow is destroyed, so it should free
346  * *everything* related to the tcp session. So including the app layer
347  * data.
348  *
349  * \param ssn Void ptr to the ssn.
350  */
351 void StreamTcpSessionClear(void *ssnptr)
352 {
353  SCEnter();
354  TcpSession *ssn = (TcpSession *)ssnptr;
355  if (ssn == NULL)
356  return;
357 
359 
360  /* HACK: don't loose track of thread id */
362  memset(ssn, 0, sizeof(TcpSession));
363  ssn->pool_id = pool_id;
364 
366 #ifdef DEBUG
367  SCMutexLock(&ssn_pool_mutex);
368  ssn_pool_cnt--;
369  SCMutexUnlock(&ssn_pool_mutex);
370 #endif
371 
372  SCReturn;
373 }
374 
375 /**
376  * \brief Function to return the stream segments back to the pool.
377  *
378  * \param p Packet used to identify the stream.
379  */
381 {
382  SCEnter();
383 
384  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
385  if (ssn == NULL)
386  SCReturn;
387 
390 
391  SCReturn;
392 }
393 
394 /** \brief Stream alloc function for the Pool
395  * \retval ptr void ptr to TcpSession structure with all vars set to 0/NULL
396  */
397 static void *StreamTcpSessionPoolAlloc(void)
398 {
399  void *ptr = NULL;
400 
401  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpSession)) == 0)
402  return NULL;
403 
404  ptr = SCMalloc(sizeof(TcpSession));
405  if (unlikely(ptr == NULL))
406  return NULL;
407 
408  return ptr;
409 }
410 
411 static int StreamTcpSessionPoolInit(void *data, void* initdata)
412 {
413  memset(data, 0, sizeof(TcpSession));
414  StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession));
415 
416  return 1;
417 }
418 
419 /** \brief Pool cleanup function
420  * \param s Void ptr to TcpSession memory */
421 static void StreamTcpSessionPoolCleanup(void *s)
422 {
423  if (s != NULL) {
425  /** \todo not very clean, as the memory is not freed here */
426  StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession));
427  }
428 }
429 
430 /** \internal
431  * \brief See if stream engine is dropping invalid packet in inline mode
432  * \retval false no
433  * \retval true yes
434  */
435 static inline bool StreamTcpInlineDropInvalid(void)
436 {
439 }
440 
441 /** \internal
442  * \brief See if stream engine is dropping URG packets in inline mode
443  * \retval false no
444  * \retval true yes
445  */
446 static inline bool StreamTcpInlineDropUrg(void)
447 {
450 }
451 
452 /* hack: stream random range code expects random values in range of 0-RAND_MAX,
453  * but we can get both <0 and >RAND_MAX values from RandomGet
454  */
455 static int RandomGetWrap(void)
456 {
457  unsigned long r;
458 
459  do {
460  r = RandomGet();
461  } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
462 
463  return r % RAND_MAX;
464 }
465 
466 static const char *UrgentPolicyToString(enum TcpStreamUrgentHandling pol)
467 {
468  switch (pol) {
470  return "oob";
472  return "inline";
474  return "drop";
476  return "gap";
477  }
478  return NULL;
479 }
480 
481 
482 /** \brief To initialize the stream global configuration data
483  *
484  * \param quiet It tells the mode of operation, if it is true nothing will
485  * be get printed.
486  */
487 
488 void StreamTcpInitConfig(bool quiet)
489 {
490  intmax_t value = 0;
491  uint16_t rdrange = 10;
492 
493  SCLogDebug("Initializing Stream");
494 
495  memset(&stream_config, 0, sizeof(stream_config));
496 
498  SC_ATOMIC_INIT(stream_config.reassembly_memcap);
499 
500  if ((ConfGetInt("stream.max-sessions", &value)) == 1) {
501  SCLogWarning("max-sessions is obsolete. "
502  "Number of concurrent sessions is now only limited by Flow and "
503  "TCP stream engine memcaps.");
504  }
505 
506  if ((ConfGetInt("stream.prealloc-sessions", &value)) == 1) {
507  stream_config.prealloc_sessions = (uint32_t)value;
508  } else {
509  if (RunmodeIsUnittests()) {
511  } else {
513  if (ConfGetNode("stream.prealloc-sessions") != NULL) {
514  WarnInvalidConfEntry("stream.prealloc_sessions",
515  "%"PRIu32,
517  }
518  }
519  }
520  if (!quiet) {
521  SCLogConfig("stream \"prealloc-sessions\": %"PRIu32" (per thread)",
523  }
524 
525  const char *temp_stream_memcap_str;
526  if (ConfGet("stream.memcap", &temp_stream_memcap_str) == 1) {
527  uint64_t stream_memcap_copy;
528  if (ParseSizeStringU64(temp_stream_memcap_str, &stream_memcap_copy) < 0) {
529  SCLogError("Error parsing stream.memcap "
530  "from conf file - %s. Killing engine",
531  temp_stream_memcap_str);
532  exit(EXIT_FAILURE);
533  } else {
534  SC_ATOMIC_SET(stream_config.memcap, stream_memcap_copy);
535  }
536  } else {
538  }
539 
540  if (!quiet) {
541  SCLogConfig("stream \"memcap\": %"PRIu64, SC_ATOMIC_GET(stream_config.memcap));
542  }
543 
544  int imidstream;
545  (void)ConfGetBool("stream.midstream", &imidstream);
546  stream_config.midstream = imidstream != 0;
547 
548  if (!quiet) {
549  SCLogConfig("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled");
550  }
551 
552  int async_oneside;
553  (void)ConfGetBool("stream.async-oneside", &async_oneside);
554  stream_config.async_oneside = async_oneside != 0;
555 
556  if (!quiet) {
557  SCLogConfig("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled");
558  }
559 
560  int csum = 0;
561 
562  if ((ConfGetBool("stream.checksum-validation", &csum)) == 1) {
563  if (csum == 1) {
565  }
566  /* Default is that we validate the checksum of all the packets */
567  } else {
569  }
570 
571  if (!quiet) {
572  SCLogConfig("stream \"checksum-validation\": %s",
574  "enabled" : "disabled");
575  }
576 
577  const char *temp_stream_inline_str;
578  if (ConfGet("stream.inline", &temp_stream_inline_str) == 1) {
579  int inl = 0;
580 
581  /* checking for "auto" and falling back to boolean to provide
582  * backward compatibility */
583  if (strcmp(temp_stream_inline_str, "auto") == 0) {
584  if (EngineModeIsIPS()) {
586  }
587  } else if (ConfGetBool("stream.inline", &inl) == 1) {
588  if (inl) {
590  }
591  }
592  } else {
593  /* default to 'auto' */
594  if (EngineModeIsIPS()) {
596  }
597  }
598  stream_config.ssn_memcap_policy = ExceptionPolicyParse("stream.memcap-policy", true);
600  ExceptionPolicyParse("stream.reassembly.memcap-policy", true);
602 
603  if (!quiet) {
604  SCLogConfig("stream.\"inline\": %s",
606  ? "enabled" : "disabled");
607  }
608 
609  int bypass = 0;
610  if ((ConfGetBool("stream.bypass", &bypass)) == 1) {
611  if (bypass == 1) {
613  }
614  }
615 
616  if (!quiet) {
617  SCLogConfig("stream \"bypass\": %s",
619  ? "enabled" : "disabled");
620  }
621 
622  int drop_invalid = 0;
623  if ((ConfGetBool("stream.drop-invalid", &drop_invalid)) == 1) {
624  if (drop_invalid == 1) {
626  }
627  } else {
629  }
630 
631  const char *temp_urgpol = NULL;
632  if (ConfGet("stream.reassembly.urgent.policy", &temp_urgpol) == 1 && temp_urgpol != NULL) {
633  if (strcmp(temp_urgpol, "inline") == 0) {
635  } else if (strcmp(temp_urgpol, "drop") == 0) {
637  } else if (strcmp(temp_urgpol, "oob") == 0) {
639  } else if (strcmp(temp_urgpol, "gap") == 0) {
641  } else {
642  FatalError("stream.reassembly.urgent.policy: invalid value '%s'", temp_urgpol);
643  }
644  } else {
646  }
647  if (!quiet) {
648  SCLogConfig("stream.reassembly.urgent.policy\": %s", UrgentPolicyToString(stream_config.urgent_policy));
649  }
651  const char *temp_urgoobpol = NULL;
652  if (ConfGet("stream.reassembly.urgent.oob-limit-policy", &temp_urgoobpol) == 1 &&
653  temp_urgoobpol != NULL) {
654  if (strcmp(temp_urgoobpol, "inline") == 0) {
656  } else if (strcmp(temp_urgoobpol, "drop") == 0) {
658  } else if (strcmp(temp_urgoobpol, "gap") == 0) {
660  } else {
661  FatalError("stream.reassembly.urgent.oob-limit-policy: invalid value '%s'", temp_urgoobpol);
662  }
663  } else {
665  }
666  if (!quiet) {
667  SCLogConfig("stream.reassembly.urgent.oob-limit-policy\": %s", UrgentPolicyToString(stream_config.urgent_oob_limit_policy));
668  }
669  }
670 
671  if ((ConfGetInt("stream.max-syn-queued", &value)) == 1) {
672  if (value >= 0 && value <= 255) {
673  stream_config.max_syn_queued = (uint8_t)value;
674  } else {
676  }
677  } else {
679  }
680  if (!quiet) {
681  SCLogConfig("stream \"max-syn-queued\": %" PRIu8, stream_config.max_syn_queued);
682  }
683 
684  if ((ConfGetInt("stream.max-synack-queued", &value)) == 1) {
685  if (value >= 0 && value <= 255) {
686  stream_config.max_synack_queued = (uint8_t)value;
687  } else {
689  }
690  } else {
692  }
693  if (!quiet) {
694  SCLogConfig("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued);
695  }
696 
697  const char *temp_stream_reassembly_memcap_str;
698  if (ConfGet("stream.reassembly.memcap", &temp_stream_reassembly_memcap_str) == 1) {
699  uint64_t stream_reassembly_memcap_copy;
700  if (ParseSizeStringU64(temp_stream_reassembly_memcap_str,
701  &stream_reassembly_memcap_copy) < 0) {
702  SCLogError("Error parsing "
703  "stream.reassembly.memcap "
704  "from conf file - %s. Killing engine",
705  temp_stream_reassembly_memcap_str);
706  exit(EXIT_FAILURE);
707  } else {
708  SC_ATOMIC_SET(stream_config.reassembly_memcap, stream_reassembly_memcap_copy);
709  }
710  } else {
712  }
713 
714  if (!quiet) {
715  SCLogConfig("stream.reassembly \"memcap\": %"PRIu64"",
716  SC_ATOMIC_GET(stream_config.reassembly_memcap));
717  }
718 
719  const char *temp_stream_reassembly_depth_str;
720  if (ConfGet("stream.reassembly.depth", &temp_stream_reassembly_depth_str) == 1) {
721  if (ParseSizeStringU32(temp_stream_reassembly_depth_str,
723  SCLogError("Error parsing "
724  "stream.reassembly.depth "
725  "from conf file - %s. Killing engine",
726  temp_stream_reassembly_depth_str);
727  exit(EXIT_FAILURE);
728  }
729  } else {
731  }
732 
733  if (!quiet) {
734  SCLogConfig("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth);
735  }
736 
737  int randomize = 0;
738  if ((ConfGetBool("stream.reassembly.randomize-chunk-size", &randomize)) == 0) {
739  /* randomize by default if value not set
740  * In ut mode we disable, to get predictable test results */
741  if (!(RunmodeIsUnittests()))
742  randomize = 1;
743  }
744 
745  if (randomize) {
746  const char *temp_rdrange;
747  if (ConfGet("stream.reassembly.randomize-chunk-range", &temp_rdrange) == 1) {
748  if (ParseSizeStringU16(temp_rdrange, &rdrange) < 0) {
749  SCLogError("Error parsing "
750  "stream.reassembly.randomize-chunk-range "
751  "from conf file - %s. Killing engine",
752  temp_rdrange);
753  exit(EXIT_FAILURE);
754  } else if (rdrange >= 100) {
755  FatalError("stream.reassembly.randomize-chunk-range "
756  "must be lower than 100");
757  }
758  }
759  }
760 
761  const char *temp_stream_reassembly_toserver_chunk_size_str;
762  if (ConfGet("stream.reassembly.toserver-chunk-size",
763  &temp_stream_reassembly_toserver_chunk_size_str) == 1) {
764  if (ParseSizeStringU16(temp_stream_reassembly_toserver_chunk_size_str,
766  SCLogError("Error parsing "
767  "stream.reassembly.toserver-chunk-size "
768  "from conf file - %s. Killing engine",
769  temp_stream_reassembly_toserver_chunk_size_str);
770  exit(EXIT_FAILURE);
771  }
772  } else {
775  }
776 
777  if (randomize) {
778  long int r = RandomGetWrap();
780  (int)(stream_config.reassembly_toserver_chunk_size * ((double)r / RAND_MAX - 0.5) *
781  rdrange / 100);
782  }
783  const char *temp_stream_reassembly_toclient_chunk_size_str;
784  if (ConfGet("stream.reassembly.toclient-chunk-size",
785  &temp_stream_reassembly_toclient_chunk_size_str) == 1) {
786  if (ParseSizeStringU16(temp_stream_reassembly_toclient_chunk_size_str,
788  SCLogError("Error parsing "
789  "stream.reassembly.toclient-chunk-size "
790  "from conf file - %s. Killing engine",
791  temp_stream_reassembly_toclient_chunk_size_str);
792  exit(EXIT_FAILURE);
793  }
794  } else {
797  }
798 
799  if (randomize) {
800  long int r = RandomGetWrap();
802  (int)(stream_config.reassembly_toclient_chunk_size * ((double)r / RAND_MAX - 0.5) *
803  rdrange / 100);
804  }
805  if (!quiet) {
806  SCLogConfig("stream.reassembly \"toserver-chunk-size\": %"PRIu16,
808  SCLogConfig("stream.reassembly \"toclient-chunk-size\": %"PRIu16,
810  }
811 
812  int enable_raw = 1;
813  if (ConfGetBool("stream.reassembly.raw", &enable_raw) == 1) {
814  if (!enable_raw) {
816  }
817  } else {
818  enable_raw = 1;
819  }
820  if (!quiet)
821  SCLogConfig("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled");
822 
823  /* default to true. Not many ppl (correctly) set up host-os policies, so be permissive. */
825  int liberal_timestamps = 0;
826  if (ConfGetBool("stream.liberal-timestamps", &liberal_timestamps) == 1) {
827  stream_config.liberal_timestamps = liberal_timestamps;
828  }
829  if (!quiet)
830  SCLogConfig("stream.liberal-timestamps: %s", liberal_timestamps ? "enabled" : "disabled");
831 
832  /* init the memcap/use tracking */
835 
837 
838  /* set the default free function and flow state function
839  * values. */
841 
842 #ifdef UNITTESTS
843  if (RunmodeIsUnittests()) {
844  SCMutexLock(&ssn_pool_mutex);
845  if (ssn_pool == NULL) {
846  ssn_pool = PoolThreadInit(1, /* thread */
847  0, /* unlimited */
849  sizeof(TcpSession),
850  StreamTcpSessionPoolAlloc,
851  StreamTcpSessionPoolInit, NULL,
852  StreamTcpSessionPoolCleanup, NULL);
853  }
854  SCMutexUnlock(&ssn_pool_mutex);
855  }
856 #endif
857 }
858 
859 void StreamTcpFreeConfig(bool quiet)
860 {
862 
863  SCMutexLock(&ssn_pool_mutex);
864  if (ssn_pool != NULL) {
866  ssn_pool = NULL;
867  }
868  SCMutexUnlock(&ssn_pool_mutex);
869  SCMutexDestroy(&ssn_pool_mutex);
870 
871  SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt);
872 }
873 
874 static bool IsReassemblyMemcapExceptionPolicyStatsValid(enum ExceptionPolicy exception_policy)
875 {
876  if (EngineModeIsIPS()) {
878  }
880 }
881 
882 static bool IsStreamTcpSessionMemcapExceptionPolicyStatsValid(enum ExceptionPolicy policy)
883 {
884  if (EngineModeIsIPS()) {
886  }
888 }
889 
890 static void StreamTcpSsnMemcapExceptionPolicyStatsIncr(
891  ThreadVars *tv, StreamTcpThread *stt, enum ExceptionPolicy policy)
892 {
893  const uint16_t id = stt->counter_tcp_ssn_memcap_eps.eps_id[policy];
894  if (likely(tv && id > 0)) {
895  StatsIncr(tv, id);
896  }
897 }
898 
899 /** \internal
900  * \brief The function is used to fetch a TCP session from the
901  * ssn_pool, when a TCP SYN is received.
902  *
903  * \param p packet starting the new TCP session.
904  * \param id thread pool id
905  *
906  * \retval ssn new TCP session.
907  */
908 static TcpSession *StreamTcpNewSession(ThreadVars *tv, StreamTcpThread *stt, Packet *p, int id)
909 {
910  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
911 
912  if (ssn == NULL) {
913  DEBUG_VALIDATE_BUG_ON(id < 0 || id > UINT16_MAX);
915  if (p->flow->protoctx != NULL) {
916 #ifdef UNITTESTS
917  if (tv)
918 #endif
920  } else {
921  p->flow->protoctx = PoolThreadGetById(ssn_pool, (uint16_t)id);
922  if (p->flow->protoctx != NULL)
923 #ifdef UNITTESTS
924  if (tv)
925 #endif
927  }
928 #ifdef DEBUG
929  SCMutexLock(&ssn_pool_mutex);
930  if (p->flow->protoctx != NULL)
931  ssn_pool_cnt++;
932  SCMutexUnlock(&ssn_pool_mutex);
933 
934  if (unlikely((g_eps_stream_ssn_memcap != UINT64_MAX &&
935  g_eps_stream_ssn_memcap == t_pcapcnt))) {
936  SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt);
938  StreamTcpSsnMemcapExceptionPolicyStatsIncr(tv, stt, stream_config.ssn_memcap_policy);
939  return NULL;
940  }
941 #endif
942  ssn = (TcpSession *)p->flow->protoctx;
943  if (ssn == NULL) {
944  SCLogDebug("ssn_pool is empty");
946  StreamTcpSsnMemcapExceptionPolicyStatsIncr(tv, stt, stream_config.ssn_memcap_policy);
947  return NULL;
948  }
949 
950  const TCPHdr *tcph = PacketGetTCP(p);
951  ssn->state = TCP_NONE;
953  ssn->tcp_packet_flags = tcph->th_flags;
956 
958  ssn->client.sb = x;
959  ssn->server.sb = x;
960 
961  if (PKT_IS_TOSERVER(p)) {
962  ssn->client.tcp_flags = tcph->th_flags;
963  ssn->server.tcp_flags = 0;
964  } else if (PKT_IS_TOCLIENT(p)) {
965  ssn->server.tcp_flags = tcph->th_flags;
966  ssn->client.tcp_flags = 0;
967  }
968  }
969 
970  return ssn;
971 }
972 
973 static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn,
974  uint8_t state)
975 {
976  if (state == ssn->state || PKT_IS_PSEUDOPKT(p))
977  return;
978 
979  ssn->pstate = ssn->state;
980  ssn->state = state;
982 
983  /* update the flow state */
984  switch(ssn->state) {
985  case TCP_ESTABLISHED:
986  case TCP_FIN_WAIT1:
987  case TCP_FIN_WAIT2:
988  case TCP_CLOSING:
989  case TCP_CLOSE_WAIT:
991  break;
992  case TCP_LAST_ACK:
993  case TCP_TIME_WAIT:
994  case TCP_CLOSED:
996  break;
997  }
998 }
999 
1000 /**
1001  * \brief Function to set the OS policy for the given stream based on the
1002  * destination of the received packet.
1003  *
1004  * \param stream TcpStream of which os_policy needs to set
1005  * \param p Packet which is used to set the os policy
1006  */
1008 {
1009  if (PacketIsIPv4(p)) {
1010  /* Get the OS policy based on destination IP address, as destination
1011  OS will decide how to react on the anomalies of newly received
1012  packets */
1013  int ret = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
1014  if (ret > 0)
1015  stream->os_policy = (uint8_t)ret;
1016  else
1017  stream->os_policy = OS_POLICY_DEFAULT;
1018 
1019  } else if (PacketIsIPv6(p)) {
1020  /* Get the OS policy based on destination IP address, as destination
1021  OS will decide how to react on the anomalies of newly received
1022  packets */
1023  int ret = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
1024  if (ret > 0)
1025  stream->os_policy = (uint8_t)ret;
1026  else
1027  stream->os_policy = OS_POLICY_DEFAULT;
1028  }
1029 
1030  if (stream->os_policy == OS_POLICY_BSD_RIGHT)
1031  stream->os_policy = OS_POLICY_BSD;
1032  else if (stream->os_policy == OS_POLICY_OLD_SOLARIS)
1033  stream->os_policy = OS_POLICY_SOLARIS;
1034 
1035  SCLogDebug("Policy is %" PRIu8 "", stream->os_policy);
1036 }
1037 
1038 /**
1039  * \brief macro to update last_ack only if the new value is higher
1040  *
1041  * \param ssn session
1042  * \param stream stream to update
1043  * \param ack ACK value to test and set
1044  */
1045 #define StreamTcpUpdateLastAck(ssn, stream, ack) { \
1046  if (SEQ_GT((ack), (stream)->last_ack)) \
1047  { \
1048  SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \
1049  if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \
1050  SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \
1051  } else { \
1052  SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \
1053  }\
1054  (stream)->last_ack = (ack); \
1055  StreamTcpSackPruneList((stream)); \
1056  } else { \
1057  SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \
1058  (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \
1059  }\
1060 }
1061 
1062 #define StreamTcpAsyncLastAckUpdate(ssn, stream) { \
1063  if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \
1064  if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \
1065  uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \
1066  (stream)->last_ack += ack_diff; \
1067  SCLogDebug("ssn %p: ASYNC last_ack set to %"PRIu32", moved %u forward", \
1068  (ssn), (stream)->next_seq, ack_diff); \
1069  } \
1070  } \
1071 }
1072 
1073 #define StreamTcpUpdateNextSeq(ssn, stream, seq) { \
1074  (stream)->next_seq = seq; \
1075  SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \
1076  StreamTcpAsyncLastAckUpdate((ssn), (stream)); \
1077 }
1078 
1079 /**
1080  * \brief macro to update next_win only if the new value is higher
1081  *
1082  * \param ssn session
1083  * \param stream stream to update
1084  * \param win window value to test and set
1085  */
1086 #define StreamTcpUpdateNextWin(ssn, stream, win) { \
1087  uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \
1088  if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \
1089  (stream)->next_win = ((win) + sacked_size__); \
1090  SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \
1091  } \
1092 }
1093 
1094 static inline void StreamTcpCloseSsnWithReset(Packet *p, TcpSession *ssn)
1095 {
1097  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1098  SCLogDebug("ssn %p: (state: %s) Reset received and state changed to "
1099  "TCP_CLOSED", ssn, StreamTcpStateAsString(ssn->state));
1100 }
1101 
1102 static bool IsMidstreamExceptionPolicyStatsValid(enum ExceptionPolicy policy)
1103 {
1104  if (EngineModeIsIPS()) {
1105  if (stream_config.midstream) {
1107  }
1109  }
1110  if (stream_config.midstream) {
1112  }
1114 }
1115 
1116 static void StreamTcpMidstreamExceptionPolicyStatsIncr(
1117  ThreadVars *tv, StreamTcpThread *stt, enum ExceptionPolicy policy)
1118 {
1119  const uint16_t id = stt->counter_tcp_midstream_eps.eps_id[policy];
1120  if (likely(tv && id > 0)) {
1121  StatsIncr(tv, id);
1122  }
1123 }
1124 
1125 static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p)
1126 {
1127  if (p->payload_len == 0)
1128  SCReturnInt(0);
1129 
1130  const TCPHdr *tcph = PacketGetTCP(p);
1131  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
1132  /* retransmission of already partially ack'd data */
1133  if (SEQ_LT(seq, stream->last_ack) && SEQ_GT((seq + p->payload_len), stream->last_ack)) {
1135  SCReturnInt(1);
1136  }
1137 
1138  /* retransmission of already ack'd data */
1139  if (SEQ_LEQ((seq + p->payload_len), stream->last_ack)) {
1141  SCReturnInt(1);
1142  }
1143 
1144  /* retransmission of in flight data */
1145  if (SEQ_LEQ((seq + p->payload_len), stream->next_seq)) {
1147  SCReturnInt(2);
1148  }
1149 
1150  SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", seq, p->payload_len,
1151  (seq + p->payload_len), stream->last_ack, stream->next_seq);
1152  SCReturnInt(0);
1153 }
1154 
1155 /**
1156  * \internal
1157  * \brief Function to handle the TCP_CLOSED or NONE state. The function handles
1158  * packets while the session state is None which means a newly
1159  * initialized structure, or a fully closed session.
1160  *
1161  * \param tv Thread Variable containing input/output queue, cpu affinity
1162  * \param p Packet which has to be handled in this TCP state.
1163  * \param stt Stream Thread module registered to handle the stream handling
1164  *
1165  * \retval 0 ok
1166  * \retval -1 error
1167  */
1168 static int StreamTcpPacketStateNone(
1169  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
1170 {
1171  const TCPHdr *tcph = PacketGetTCP(p);
1172  if (tcph->th_flags & TH_RST) {
1174  SCLogDebug("RST packet received, no session setup");
1175  return -1;
1176 
1177  } else if (tcph->th_flags & TH_FIN) {
1178  /* Drop reason will only be used if midstream policy is set to fail closed */
1180  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1181 
1182  if (!stream_config.midstream || p->payload_len == 0) {
1184  SCLogDebug("FIN packet received, no session setup");
1185  return -1;
1186  }
1190  SCLogDebug("FIN packet received, no session setup");
1191  return -1;
1192  }
1193  SCLogDebug("midstream picked up");
1194 
1195  if (ssn == NULL) {
1196  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1197  if (ssn == NULL) {
1199  return -1;
1200  }
1204  }
1205  /* set the state */
1206  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
1207  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1208  "TCP_FIN_WAIT1",
1209  ssn);
1210 
1214  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1215  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1216  }
1217 
1218  /** window scaling for midstream pickups, we can't do much other
1219  * than assume that it's set to the max value: 14 */
1220  ssn->client.wscale = TCP_WSCALE_MAX;
1221  ssn->server.wscale = TCP_WSCALE_MAX;
1222 
1223  /* set the sequence numbers and window */
1224  ssn->client.isn = TCP_GET_RAW_SEQ(tcph) - 1;
1226  ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len + 1;
1227  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
1228  ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
1229  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1230  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", ssn, ssn->client.isn,
1231  ssn->client.next_seq);
1232 
1233  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
1235  ssn->server.next_seq = ssn->server.isn + 1;
1236  ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
1237  ssn->server.next_win = ssn->server.last_ack;
1238 
1239  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
1240  "ssn->server.next_win %" PRIu32 "",
1241  ssn, ssn->client.next_win, ssn->server.next_win);
1242  SCLogDebug("ssn %p: ssn->client.last_ack %" PRIu32 ", "
1243  "ssn->server.last_ack %" PRIu32 "",
1244  ssn, ssn->client.last_ack, ssn->server.last_ack);
1245 
1246  /* Set the timestamp value for both streams, if packet has timestamp
1247  * option enabled.*/
1248  if (TCP_HAS_TS(p)) {
1249  ssn->client.last_ts = TCP_GET_TSVAL(p);
1250  ssn->server.last_ts = TCP_GET_TSECR(p);
1251  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " "
1252  "ssn->client.last_ts %" PRIu32 "",
1253  ssn, ssn->server.last_ts, ssn->client.last_ts);
1254 
1256 
1257  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1258  if (ssn->server.last_ts == 0)
1260  if (ssn->client.last_ts == 0)
1262 
1263  } else {
1264  ssn->server.last_ts = 0;
1265  ssn->client.last_ts = 0;
1266  }
1267 
1268  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1269 
1270  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1271  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1272 
1273  /* SYN/ACK */
1274  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
1275  /* Drop reason will only be used if midstream policy is set to fail closed */
1277  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1278 
1280  SCLogDebug("Midstream not enabled, so won't pick up a session");
1281  return 0;
1282  }
1285  SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1286  return 0;
1287  }
1288  SCLogDebug("midstream picked up");
1289 
1290  if (ssn == NULL) {
1291  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1292  if (ssn == NULL) {
1294  return -1;
1295  }
1299  }
1300 
1301  /* reverse packet and flow */
1302  SCLogDebug("reversing flow and packet");
1303  PacketSwap(p);
1304  FlowSwap(p->flow);
1305 
1306  /* set the state */
1307  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1308  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1309  "TCP_SYN_RECV", ssn);
1311  /* Flag used to change the direct in the later stage in the session */
1314  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1315  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1316  }
1317 
1318  /* sequence number & window */
1319  ssn->server.isn = TCP_GET_RAW_SEQ(tcph);
1321  ssn->server.next_seq = ssn->server.isn + 1;
1322  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
1323  SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
1324 
1325  ssn->client.isn = TCP_GET_RAW_ACK(tcph) - 1;
1327  ssn->client.next_seq = ssn->client.isn + 1;
1328 
1329  ssn->client.last_ack = TCP_GET_RAW_ACK(tcph);
1330  ssn->server.last_ack = TCP_GET_RAW_SEQ(tcph);
1331 
1332  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1333 
1334  /** If the client has a wscale option the server had it too,
1335  * so set the wscale for the server to max. Otherwise none
1336  * will have the wscale opt just like it should. */
1337  if (TCP_HAS_WSCALE(p)) {
1338  ssn->client.wscale = TCP_GET_WSCALE(p);
1339  ssn->server.wscale = TCP_WSCALE_MAX;
1340  SCLogDebug("ssn %p: wscale enabled. client %u server %u",
1341  ssn, ssn->client.wscale, ssn->server.wscale);
1342  }
1343 
1344  SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
1345  " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
1346  ssn->client.isn, ssn->client.next_seq,
1347  ssn->client.last_ack);
1348  SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
1349  " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
1350  ssn->server.isn, ssn->server.next_seq,
1351  ssn->server.last_ack);
1352 
1353  /* Set the timestamp value for both streams, if packet has timestamp
1354  * option enabled.*/
1355  if (TCP_HAS_TS(p)) {
1356  ssn->server.last_ts = TCP_GET_TSVAL(p);
1357  ssn->client.last_ts = TCP_GET_TSECR(p);
1358  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1359  "ssn->client.last_ts %" PRIu32"", ssn,
1360  ssn->server.last_ts, ssn->client.last_ts);
1361 
1363 
1364  ssn->server.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1365  if (ssn->server.last_ts == 0)
1367  if (ssn->client.last_ts == 0)
1369 
1370  } else {
1371  ssn->server.last_ts = 0;
1372  ssn->client.last_ts = 0;
1373  }
1374 
1375  if (TCP_GET_SACKOK(p)) {
1376  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1377  SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
1378  "SACK permitted for both sides", ssn);
1379  }
1380  return 0;
1381 
1382  } else if (tcph->th_flags & TH_SYN) {
1383  if (ssn == NULL) {
1384  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1385  if (ssn == NULL) {
1387  return -1;
1388  }
1389 
1392  }
1393 
1394  /* set the state */
1395  StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
1396  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
1397 
1399  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1400  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1401  }
1402 
1403  /* set the sequence numbers and window */
1404  ssn->client.isn = TCP_GET_RAW_SEQ(tcph);
1406  ssn->client.next_seq = ssn->client.isn + 1;
1407 
1408  /* Set the stream timestamp value, if packet has timestamp option
1409  * enabled. */
1410  if (TCP_HAS_TS(p)) {
1411  ssn->client.last_ts = TCP_GET_TSVAL(p);
1412  SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
1413 
1414  if (ssn->client.last_ts == 0)
1416 
1417  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1419  }
1420 
1421  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
1422  if (TCP_HAS_WSCALE(p)) {
1424  ssn->server.wscale = TCP_GET_WSCALE(p);
1425  }
1426 
1427  if (TCP_GET_SACKOK(p)) {
1429  SCLogDebug("ssn %p: SACK permitted on SYN packet", ssn);
1430  }
1431 
1432  if (TCP_HAS_TFO(p)) {
1434  if (p->payload_len) {
1435  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
1436  SCLogDebug("ssn: %p (TFO) isn %u base_seq %u next_seq %u payload len %u", ssn,
1437  ssn->client.isn, ssn->client.base_seq, ssn->client.next_seq,
1438  p->payload_len);
1439  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1440  }
1441  }
1442 
1443  SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
1444  "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
1445  "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
1446  ssn->client.last_ack);
1447 
1448  } else if (tcph->th_flags & TH_ACK) {
1449  /* Drop reason will only be used if midstream policy is set to fail closed */
1451  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1452 
1453  if (!stream_config.midstream) {
1454  SCLogDebug("Midstream not enabled, so won't pick up a session");
1455  return 0;
1456  }
1459  SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1460  return 0;
1461  }
1462  SCLogDebug("midstream picked up");
1463 
1464  if (ssn == NULL) {
1465  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1466  if (ssn == NULL) {
1468  return -1;
1469  }
1473  }
1474  /* set the state */
1475  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1476  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1477  "TCP_ESTABLISHED", ssn);
1478 
1482  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1483  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1484  }
1485 
1486  /** window scaling for midstream pickups, we can't do much other
1487  * than assume that it's set to the max value: 14 */
1488  ssn->client.wscale = TCP_WSCALE_MAX;
1489  ssn->server.wscale = TCP_WSCALE_MAX;
1490 
1491  /* set the sequence numbers and window */
1492  ssn->client.isn = TCP_GET_RAW_SEQ(tcph) - 1;
1494  ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
1495  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
1496  ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
1497  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1498  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
1499  ssn, ssn->client.isn, ssn->client.next_seq);
1500 
1501  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
1503  ssn->server.next_seq = ssn->server.isn + 1;
1504  ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
1505  ssn->server.next_win = ssn->server.last_ack;
1506 
1507  SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
1508  "ssn->server.next_win %"PRIu32"", ssn,
1509  ssn->client.next_win, ssn->server.next_win);
1510  SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
1511  "ssn->server.last_ack %"PRIu32"", ssn,
1512  ssn->client.last_ack, ssn->server.last_ack);
1513 
1514  /* Set the timestamp value for both streams, if packet has timestamp
1515  * option enabled.*/
1516  if (TCP_HAS_TS(p)) {
1517  ssn->client.last_ts = TCP_GET_TSVAL(p);
1518  ssn->server.last_ts = TCP_GET_TSECR(p);
1519  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1520  "ssn->client.last_ts %" PRIu32"", ssn,
1521  ssn->server.last_ts, ssn->client.last_ts);
1522 
1524 
1525  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1526  if (ssn->server.last_ts == 0)
1528  if (ssn->client.last_ts == 0)
1530 
1531  } else {
1532  ssn->server.last_ts = 0;
1533  ssn->client.last_ts = 0;
1534  }
1535 
1536  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1537 
1538  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1539  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1540 
1541  } else {
1542  SCLogDebug("default case");
1543  }
1544 
1545  return 0;
1546 }
1547 
1548 /** \internal
1549  * \brief Setup TcpStateQueue based on SYN/ACK packet
1550  */
1551 static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
1552 {
1553  const TCPHdr *tcph = PacketGetTCP(p);
1554  q->flags = 0;
1555  q->wscale = 0;
1556  q->ts = 0;
1557  q->win = TCP_GET_RAW_WINDOW(tcph);
1558  q->seq = TCP_GET_RAW_SEQ(tcph);
1559  q->ack = TCP_GET_RAW_ACK(tcph);
1560  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1561 
1562  if (TCP_GET_SACKOK(p))
1564 
1565  if (TCP_HAS_WSCALE(p)) {
1567  q->wscale = TCP_GET_WSCALE(p);
1568  }
1569  if (TCP_HAS_TS(p)) {
1571  q->ts = TCP_GET_TSVAL(p);
1572  }
1573 }
1574 
1575 /** \internal
1576  * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
1577  * \retval q or NULL */
1578 static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
1579 {
1580  TcpStateQueue *q = ssn->queue;
1581  TcpStateQueue search;
1582 
1583  StreamTcp3whsSynAckToStateQueue(p, &search);
1584 
1585  while (q != NULL) {
1586  if (search.flags == q->flags &&
1587  search.wscale == q->wscale &&
1588  search.win == q->win &&
1589  search.seq == q->seq &&
1590  search.ack == q->ack &&
1591  search.ts == q->ts) {
1592  return q;
1593  }
1594 
1595  q = q->next;
1596  }
1597 
1598  return q;
1599 }
1600 
1601 static int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
1602 {
1603  /* first see if this is already in our list */
1604  if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
1605  return 0;
1606 
1608  SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
1610  return -1;
1611  }
1612 
1613  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1614  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
1615  return -1;
1616  }
1617 
1618  TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1619  if (unlikely(q == NULL)) {
1620  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
1621  return -1;
1622  }
1623  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1624 
1625  StreamTcp3whsSynAckToStateQueue(p, q);
1626 
1627  /* put in list */
1628  q->next = ssn->queue;
1629  ssn->queue = q;
1630  ssn->queue_len++;
1631  return 0;
1632 }
1633 
1634 /** \internal
1635  * \brief Find the Queued SYN/ACK that goes with this ACK
1636  * \retval q or NULL */
1637 static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
1638 {
1639  const TCPHdr *tcph = PacketGetTCP(p);
1640  const uint32_t ack = TCP_GET_RAW_SEQ(tcph);
1641  const uint32_t seq = TCP_GET_RAW_ACK(tcph) - 1;
1642  TcpStateQueue *q = ssn->queue;
1643 
1644  while (q != NULL) {
1645  if (seq == q->seq &&
1646  ack == q->ack) {
1647  return q;
1648  }
1649 
1650  q = q->next;
1651  }
1652 
1653  return NULL;
1654 }
1655 
1656 /** \internal
1657  * \brief Update SSN after receiving a valid SYN/ACK
1658  *
1659  * Normally we update the SSN from the SYN/ACK packet. But in case
1660  * of queued SYN/ACKs, we can use one of those.
1661  *
1662  * \param ssn TCP session
1663  * \param p Packet
1664  * \param q queued state if used, NULL otherwise
1665  *
1666  * To make sure all SYN/ACK based state updates are in one place,
1667  * this function can updated based on Packet or TcpStateQueue, where
1668  * the latter takes precedence.
1669  */
1670 static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
1671 {
1672  TcpStateQueue update;
1673  if (likely(q == NULL)) {
1674  StreamTcp3whsSynAckToStateQueue(p, &update);
1675  q = &update;
1676  }
1677 
1678  if (ssn->state != TCP_SYN_RECV) {
1679  /* update state */
1680  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1681  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
1682  }
1683  /* sequence number & window */
1684  ssn->server.isn = q->seq;
1686  ssn->server.next_seq = ssn->server.isn + 1;
1687 
1688  ssn->client.window = q->win;
1689  SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
1690 
1691  /* Set the timestamp values used to validate the timestamp of
1692  * received packets.*/
1693  if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
1695  {
1696  ssn->server.last_ts = q->ts;
1697  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1698  "ssn->client.last_ts %" PRIu32"", ssn,
1699  ssn->server.last_ts, ssn->client.last_ts);
1701  ssn->server.last_pkt_ts = q->pkt_ts;
1702  if (ssn->server.last_ts == 0)
1704  } else {
1705  ssn->client.last_ts = 0;
1706  ssn->server.last_ts = 0;
1708  }
1709 
1710  ssn->client.last_ack = q->ack;
1711  ssn->server.last_ack = ssn->server.isn + 1;
1712 
1713  /** check for the presence of the ws ptr to determine if we
1714  * support wscale at all */
1715  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1717  {
1718  ssn->client.wscale = q->wscale;
1719  } else {
1720  ssn->client.wscale = 0;
1721  }
1722 
1723  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1725  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1726  SCLogDebug("ssn %p: SACK permitted for session", ssn);
1727  } else {
1728  ssn->flags &= ~STREAMTCP_FLAG_SACKOK;
1729  }
1730 
1731  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1732  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1733  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
1734  ssn->server.next_win);
1735  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
1736  ssn->client.next_win);
1737  SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
1738  "ssn->server.next_seq %" PRIu32 ", "
1739  "ssn->server.last_ack %" PRIu32 " "
1740  "(ssn->client.last_ack %" PRIu32 ")", ssn,
1741  ssn->server.isn, ssn->server.next_seq,
1742  ssn->server.last_ack, ssn->client.last_ack);
1743 
1744  /* unset the 4WHS flag as we received this SYN/ACK as part of a
1745  * (so far) valid 3WHS */
1746  if (ssn->flags & STREAMTCP_FLAG_4WHS)
1747  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
1748  " so considering 3WHS", ssn);
1749 
1750  ssn->flags &=~ STREAMTCP_FLAG_4WHS;
1751 }
1752 
1753 /** \internal
1754  * \brief detect timestamp anomalies when processing responses to the
1755  * SYN packet.
1756  * \retval true packet is ok
1757  * \retval false packet is bad
1758  */
1759 static inline bool StateSynSentValidateTimestamp(TcpSession *ssn, Packet *p)
1760 {
1761  /* we only care about evil server here, so skip TS packets */
1762  if (PKT_IS_TOSERVER(p) || !(TCP_HAS_TS(p))) {
1763  return true;
1764  }
1765 
1766  TcpStream *receiver_stream = &ssn->client;
1767  const uint32_t ts_echo = TCP_GET_TSECR(p);
1768  if ((receiver_stream->flags & STREAMTCP_STREAM_FLAG_TIMESTAMP) != 0) {
1769  if (receiver_stream->last_ts != 0 && ts_echo != 0 &&
1770  ts_echo != receiver_stream->last_ts)
1771  {
1772  SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn,
1773  ts_echo, receiver_stream->last_ts);
1774  return false;
1775  }
1776  } else {
1777  if (receiver_stream->last_ts == 0 && ts_echo != 0) {
1778  SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn,
1779  ts_echo, receiver_stream->last_ts);
1780  return false;
1781  }
1782  }
1783  return true;
1784 }
1785 
1786 static void TcpStateQueueInitFromSsnSyn(const TcpSession *ssn, TcpStateQueue *q)
1787 {
1788  BUG_ON(ssn->state != TCP_SYN_SENT); // TODO
1789  memset(q, 0, sizeof(*q));
1790 
1791  /* SYN won't use wscale yet. So window should be limited to 16 bits. */
1792  DEBUG_VALIDATE_BUG_ON(ssn->server.window > UINT16_MAX);
1793  q->win = (uint16_t)ssn->server.window;
1794 
1795  q->pkt_ts = ssn->client.last_pkt_ts;
1796 
1797  if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
1799  }
1800  if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
1802  q->wscale = ssn->server.wscale;
1803  }
1806  q->ts = ssn->client.last_ts;
1807  }
1808 
1809  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1811 }
1812 
1813 static void TcpStateQueueInitFromPktSyn(const Packet *p, TcpStateQueue *q)
1814 {
1815 #if defined(DEBUG_VALIDATION) || defined(DEBUG)
1816  const TcpSession *ssn = p->flow->protoctx;
1817  BUG_ON(ssn->state != TCP_SYN_SENT);
1818 #endif
1819  memset(q, 0, sizeof(*q));
1820  const TCPHdr *tcph = PacketGetTCP(p);
1821 
1822  q->win = TCP_GET_RAW_WINDOW(tcph);
1823  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1824 
1825  if (TCP_GET_SACKOK(p)) {
1827  }
1828  if (TCP_HAS_WSCALE(p)) {
1830  q->wscale = TCP_GET_WSCALE(p);
1831  }
1832  if (TCP_HAS_TS(p)) {
1834  q->ts = TCP_GET_TSVAL(p);
1835  }
1836 
1837 #if defined(DEBUG)
1838  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1840 #endif
1841 }
1842 
1843 static void TcpStateQueueInitFromPktSynAck(const Packet *p, TcpStateQueue *q)
1844 {
1845 #if defined(DEBUG_VALIDATION) || defined(DEBUG)
1846  const TcpSession *ssn = p->flow->protoctx;
1847  if ((ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) == 0)
1848  BUG_ON(ssn->state != TCP_SYN_SENT);
1849  else
1850  BUG_ON(ssn->state != TCP_ESTABLISHED);
1851 #endif
1852  memset(q, 0, sizeof(*q));
1853 
1854  const TCPHdr *tcph = PacketGetTCP(p);
1855  q->win = TCP_GET_RAW_WINDOW(tcph);
1856  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1857 
1858  if (TCP_GET_SACKOK(p)) {
1860  }
1861  if (TCP_HAS_WSCALE(p)) {
1863  q->wscale = TCP_GET_WSCALE(p);
1864  }
1865  if (TCP_HAS_TS(p)) {
1867  q->ts = TCP_GET_TSECR(p);
1868  }
1869 
1870 #if defined(DEBUG)
1871  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1873 #endif
1874 }
1875 
1876 /** \internal
1877  * \brief Find the Queued SYN that is the same as this SYN/ACK
1878  * \retval q or NULL */
1879 static const TcpStateQueue *StreamTcp3whsFindSyn(const TcpSession *ssn, TcpStateQueue *s)
1880 {
1881  SCLogDebug("ssn %p: search state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, s, s->seq, s->win,
1883 
1884  for (const TcpStateQueue *q = ssn->queue; q != NULL; q = q->next) {
1885  SCLogDebug("ssn %p: queue state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq,
1886  q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS), q->ts);
1888  s->ts == q->ts) {
1889  return q;
1890  }
1891  }
1892  return NULL;
1893 }
1894 
1895 /** \note the SEQ values *must* be the same */
1896 static int StreamTcp3whsStoreSyn(TcpSession *ssn, Packet *p)
1897 {
1898  TcpStateQueue search;
1899  TcpStateQueueInitFromSsnSyn(ssn, &search);
1900 
1901  /* first see if this is already in our list */
1902  if (ssn->queue != NULL && StreamTcp3whsFindSyn(ssn, &search) != NULL)
1903  return 0;
1904 
1905  if (ssn->queue_len == stream_config.max_syn_queued) {
1906  SCLogDebug("ssn %p: =~ SYN queue limit reached", ssn);
1908  return -1;
1909  }
1910 
1911  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1912  SCLogDebug("ssn %p: =~ SYN queue failed: stream memcap reached", ssn);
1913  return -1;
1914  }
1915 
1916  TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1917  if (unlikely(q == NULL)) {
1918  SCLogDebug("ssn %p: =~ SYN queue failed: alloc failed", ssn);
1919  return -1;
1920  }
1921  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1922 
1923  *q = search;
1924  /* put in list */
1925  q->next = ssn->queue;
1926  ssn->queue = q;
1927  ssn->queue_len++;
1928  return 0;
1929 }
1930 
1931 static inline void StreamTcp3whsStoreSynApplyToSsn(TcpSession *ssn, const TcpStateQueue *q)
1932 {
1933  if (q->flags & STREAMTCP_QUEUE_FLAG_TS) {
1934  ssn->client.last_pkt_ts = q->pkt_ts;
1935  ssn->client.last_ts = q->ts;
1937  SCLogDebug("ssn: %p client.last_ts updated to %u", ssn, ssn->client.last_ts);
1938  }
1939  if (q->flags & STREAMTCP_QUEUE_FLAG_WS) {
1941  ssn->server.wscale = q->wscale;
1942  } else {
1944  ssn->server.wscale = 0;
1945  }
1946  ssn->server.window = q->win;
1947 
1948  if (q->flags & STREAMTCP_QUEUE_FLAG_SACK) {
1950  } else {
1952  }
1953 }
1954 
1955 /**
1956  * \brief Function to handle the TCP_SYN_SENT state. The function handles
1957  * SYN, SYN/ACK, RST packets and correspondingly changes the connection
1958  * state.
1959  *
1960  * \param tv Thread Variable containing input/output queue, cpu affinity
1961  * \param p Packet which has to be handled in this TCP state.
1962  * \param stt Stream Thread module registered to handle the stream handling
1963  */
1964 
1965 static int StreamTcpPacketStateSynSent(
1966  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
1967 {
1968  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
1969  const TCPHdr *tcph = PacketGetTCP(p);
1970 
1971  SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ? "toclient" : "toserver");
1972 
1973  /* common case: SYN/ACK from server to client */
1974  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOCLIENT(p)) {
1975  SCLogDebug("ssn %p: SYN/ACK on SYN_SENT state for packet %" PRIu64, ssn, p->pcap_cnt);
1976 
1977  if (!(TCP_HAS_TFO(p) || (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN))) {
1978  /* Check if the SYN/ACK packet ack's the earlier
1979  * received SYN packet. */
1980  if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1))) {
1982  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1983  "%" PRIu32 " from stream",
1984  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
1985  return -1;
1986  }
1987  } else {
1988  if (SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.next_seq)) {
1989  SCLogDebug("ssn %p: (TFO) ACK matches next_seq, packet ACK %" PRIu32 " == "
1990  "%" PRIu32 " from stream",
1991  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
1992  } else if (SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1)) {
1993  SCLogDebug("ssn %p: (TFO) ACK matches ISN+1, packet ACK %" PRIu32 " == "
1994  "%" PRIu32 " from stream",
1995  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
1996  ssn->client.next_seq = ssn->client.isn; // reset to ISN
1997  SCLogDebug("ssn %p: (TFO) next_seq reset to isn (%u)", ssn, ssn->client.next_seq);
2000  } else {
2002  SCLogDebug("ssn %p: (TFO) ACK mismatch, packet ACK %" PRIu32 " != "
2003  "%" PRIu32 " from stream",
2004  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
2005  return -1;
2006  }
2008  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2009  }
2010 
2011  const bool ts_mismatch = !StateSynSentValidateTimestamp(ssn, p);
2012  if (ts_mismatch) {
2013  SCLogDebug("ssn %p: ts_mismatch:%s", ssn, BOOL2STR(ts_mismatch));
2014  if (ssn->queue) {
2015  TcpStateQueue search;
2016  TcpStateQueueInitFromPktSynAck(p, &search);
2017 
2018  const TcpStateQueue *q = StreamTcp3whsFindSyn(ssn, &search);
2019  if (q == NULL) {
2020  SCLogDebug("not found: mismatch");
2022  return -1;
2023  }
2024  SCLogDebug("ssn %p: found queued SYN state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u",
2025  ssn, q, q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS),
2026  q->ts);
2027 
2028  StreamTcp3whsStoreSynApplyToSsn(ssn, q);
2029 
2030  } else {
2031  SCLogDebug("not found: no queue");
2033  return -1;
2034  }
2035  }
2036 
2037  /* clear ssn->queue on state change: TcpSession can be reused by SYN/ACK */
2038  StreamTcp3wsFreeQueue(ssn);
2039 
2040  StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
2041  return 0;
2042 
2043  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOSERVER(p)) {
2044 
2045  if (!(ssn->flags & STREAMTCP_FLAG_4WHS)) {
2047  SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
2048  return -1;
2049  }
2050 
2051  SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
2052 
2053  /* Check if the SYN/ACK packet ack's the earlier
2054  * received SYN packet. */
2055  if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.isn + 1))) {
2057 
2058  SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %" PRIu32 ""
2059  " != %" PRIu32 " from stream",
2060  ssn, TCP_GET_RAW_ACK(tcph), ssn->server.isn + 1);
2061  return -1;
2062  }
2063 
2064  /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
2065  * packet. */
2066  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn))) {
2068 
2069  SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %" PRIu32 ""
2070  " != %" PRIu32 " from *first* SYN pkt",
2071  ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.isn);
2072  return -1;
2073  }
2074 
2075  /* update state */
2076  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
2077  SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
2078 
2079  /* sequence number & window */
2080  ssn->client.isn = TCP_GET_RAW_SEQ(tcph);
2082  ssn->client.next_seq = ssn->client.isn + 1;
2083 
2084  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2085  SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn, ssn->client.window);
2086 
2087  /* Set the timestamp values used to validate the timestamp of
2088  * received packets. */
2089  if ((TCP_HAS_TS(p)) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) {
2090  ssn->client.last_ts = TCP_GET_TSVAL(p);
2091  SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32 " "
2092  "ssn->server.last_ts %" PRIu32 "",
2093  ssn, ssn->client.last_ts, ssn->server.last_ts);
2095  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2096  if (ssn->client.last_ts == 0)
2098  } else {
2099  ssn->server.last_ts = 0;
2100  ssn->client.last_ts = 0;
2102  }
2103 
2104  ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
2105  ssn->client.last_ack = ssn->client.isn + 1;
2106 
2107  /** check for the presense of the ws ptr to determine if we
2108  * support wscale at all */
2109  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && (TCP_HAS_WSCALE(p))) {
2110  ssn->server.wscale = TCP_GET_WSCALE(p);
2111  } else {
2112  ssn->server.wscale = 0;
2113  }
2114 
2115  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) && TCP_GET_SACKOK(p)) {
2116  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2117  SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
2118  }
2119 
2120  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2121  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2122  SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win);
2123  SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win);
2124  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2125  "ssn->client.next_seq %" PRIu32 ", "
2126  "ssn->client.last_ack %" PRIu32 " "
2127  "(ssn->server.last_ack %" PRIu32 ")",
2128  ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack,
2129  ssn->server.last_ack);
2130 
2131  /* done here */
2132  return 0;
2133  }
2134 
2135  /* check for bad responses */
2136  if (!StateSynSentValidateTimestamp(ssn, p)) {
2138  return -1;
2139  }
2140 
2141  /* RST */
2142  if (tcph->th_flags & TH_RST) {
2143 
2144  if (!StreamTcpValidateRst(ssn, p))
2145  return -1;
2146 
2147  if (PKT_IS_TOSERVER(p)) {
2148  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn) &&
2149  SEQ_EQ(TCP_GET_RAW_WINDOW(tcph), 0) &&
2150  SEQ_EQ(TCP_GET_RAW_ACK(tcph), (ssn->client.isn + 1))) {
2151  SCLogDebug("ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
2153  StreamTcpCloseSsnWithReset(p, ssn);
2154  StreamTcp3wsFreeQueue(ssn);
2155  }
2156  } else {
2158  SCLogDebug("ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
2159  StreamTcpCloseSsnWithReset(p, ssn);
2160  StreamTcp3wsFreeQueue(ssn);
2161  }
2162 
2163  /* FIN */
2164  } else if (tcph->th_flags & TH_FIN) {
2165  /** \todo */
2166 
2167  } else if (tcph->th_flags & TH_SYN) {
2168  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
2169  if (ssn->flags & STREAMTCP_FLAG_4WHS) {
2170  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
2171  "4WHS SYN", ssn);
2172  }
2173 
2174  if (PKT_IS_TOCLIENT(p)) {
2175  /** a SYN only packet in the opposite direction could be:
2176  * http://www.breakingpointsystems.com/community/blog/tcp-
2177  * portals-the-three-way-handshake-is-a-lie
2178  *
2179  * \todo improve resetting the session */
2180 
2181  /* indicate that we're dealing with 4WHS here */
2182  ssn->flags |= STREAMTCP_FLAG_4WHS;
2183  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
2184 
2185  /* set the sequence numbers and window for server
2186  * We leave the ssn->client.isn in place as we will
2187  * check the SYN/ACK pkt with that.
2188  */
2189  ssn->server.isn = TCP_GET_RAW_SEQ(tcph);
2191  ssn->server.next_seq = ssn->server.isn + 1;
2192 
2193  /* Set the stream timestamp value, if packet has timestamp
2194  * option enabled. */
2195  if (TCP_HAS_TS(p)) {
2196  ssn->server.last_ts = TCP_GET_TSVAL(p);
2197  SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
2198 
2199  if (ssn->server.last_ts == 0)
2201  ssn->server.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2203  }
2204 
2205  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2206  if (TCP_HAS_WSCALE(p)) {
2208  ssn->server.wscale = TCP_GET_WSCALE(p);
2209  } else {
2211  ssn->server.wscale = 0;
2212  }
2213 
2214  if (TCP_GET_SACKOK(p)) {
2216  } else {
2218  }
2219 
2220  SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
2221  "ssn->server.next_seq %" PRIu32 ", "
2222  "ssn->server.last_ack %"PRIu32"", ssn,
2223  ssn->server.isn, ssn->server.next_seq,
2224  ssn->server.last_ack);
2225  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2226  "ssn->client.next_seq %" PRIu32 ", "
2227  "ssn->client.last_ack %"PRIu32"", ssn,
2228  ssn->client.isn, ssn->client.next_seq,
2229  ssn->client.last_ack);
2230  } else if (PKT_IS_TOSERVER(p)) {
2231  /* on a SYN resend we queue up the SYN's until a SYN/ACK moves the state
2232  * to SYN_RECV. We update the ssn to the most recent, as it is most likely
2233  * to be correct. */
2234 
2235  TcpStateQueue syn_pkt, syn_ssn;
2236  TcpStateQueueInitFromPktSyn(p, &syn_pkt);
2237  TcpStateQueueInitFromSsnSyn(ssn, &syn_ssn);
2238 
2239  if (memcmp(&syn_pkt, &syn_ssn, sizeof(TcpStateQueue)) != 0) {
2240  /* store the old session settings */
2241  StreamTcp3whsStoreSyn(ssn, p);
2242  SCLogDebug("ssn %p: Retransmitted SYN. Updating ssn from packet %" PRIu64
2243  ". Stored previous state",
2244  ssn, p->pcap_cnt);
2245  }
2246  StreamTcp3whsStoreSynApplyToSsn(ssn, &syn_pkt);
2247  }
2248  } else if (tcph->th_flags & TH_ACK) {
2249  /* Handle the asynchronous stream, when we receive a SYN packet
2250  and now instead of receiving a SYN/ACK we receive a ACK from the
2251  same host, which sent the SYN, this suggests the ASYNC streams.*/
2253  return 0;
2254 
2255  /* we are in ASYNC (one side) mode now. */
2256 
2257  /* one side async means we won't see a SYN/ACK, so we can
2258  * only check the SYN. */
2259  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq))) {
2261 
2262  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2263  "%" PRIu32 " from stream",
2264  ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq);
2265  return -1;
2266  }
2267 
2268  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2269  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2270  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2271  StreamTcp3wsFreeQueue(ssn);
2272 
2273  ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2274  ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
2275  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2276 
2277  /* Set the server side parameters */
2278  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
2280  ssn->server.next_seq = ssn->server.isn + 1;
2281  ssn->server.last_ack = ssn->server.next_seq;
2282  ssn->server.next_win = ssn->server.last_ack;
2283 
2284  SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
2285  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2286  "ssn->client.next_seq %" PRIu32 "",
2287  ssn, TCP_GET_RAW_SEQ(tcph), p->payload_len, TCP_GET_RAW_SEQ(tcph) + p->payload_len,
2288  ssn->client.next_seq);
2289 
2290  /* if SYN had wscale, assume it to be supported. Otherwise
2291  * we know it not to be supported. */
2292  if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
2293  ssn->client.wscale = TCP_WSCALE_MAX;
2294  }
2295 
2296  /* Set the timestamp values used to validate the timestamp of
2297  * received packets.*/
2298  if (TCP_HAS_TS(p) &&
2300  {
2303  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2304  } else {
2305  ssn->client.last_ts = 0;
2307  }
2308 
2309  if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
2310  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2311  }
2312 
2313  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2314 
2315  } else {
2316  SCLogDebug("ssn %p: default case", ssn);
2317  }
2318 
2319  return 0;
2320 }
2321 
2322 /**
2323  * \brief Function to handle the TCP_SYN_RECV state. The function handles
2324  * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
2325  * the connection state.
2326  *
2327  * \param tv Thread Variable containing input/output queue, cpu affinity
2328  * \param p Packet which has to be handled in this TCP state.
2329  * \param stt Stream Thread module registered to handle the stream handling
2330  *
2331  * \retval 0 ok
2332  * \retval -1 error
2333  */
2334 
2335 static int StreamTcpPacketStateSynRecv(
2336  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
2337 {
2338  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
2339  const TCPHdr *tcph = PacketGetTCP(p);
2340 
2341  if (tcph->th_flags & TH_RST) {
2342  if (!StreamTcpValidateRst(ssn, p))
2343  return -1;
2344 
2345  bool reset = true;
2346  /* After receiving the RST in SYN_RECV state and if detection
2347  evasion flags has been set, then the following operating
2348  systems will not closed the connection. As they consider the
2349  packet as stray packet and not belonging to the current
2350  session, for more information check
2351  http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
2353  if (PKT_IS_TOSERVER(p)) {
2354  if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
2355  (ssn->server.os_policy == OS_POLICY_OLD_LINUX) ||
2357  {
2358  reset = false;
2359  SCLogDebug("Detection evasion has been attempted, so"
2360  " not resetting the connection !!");
2361  }
2362  } else {
2363  if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
2364  (ssn->client.os_policy == OS_POLICY_OLD_LINUX) ||
2366  {
2367  reset = false;
2368  SCLogDebug("Detection evasion has been attempted, so"
2369  " not resetting the connection !!");
2370  }
2371  }
2372  }
2373 
2374  if (reset) {
2375  StreamTcpCloseSsnWithReset(p, ssn);
2376 
2377  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2378  StreamTcpHandleTimestamp(ssn, p);
2379  }
2380  }
2381 
2382  } else if (tcph->th_flags & TH_FIN) {
2383  /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
2384  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2385  if (!StreamTcpValidateTimestamp(ssn, p))
2386  return -1;
2387  }
2388 
2389  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
2390  return -1;
2391 
2392  /* SYN/ACK */
2393  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
2394  SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
2395 
2396  if (PKT_IS_TOSERVER(p)) {
2397  SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
2398 
2400  return -1;
2401  }
2402 
2403  /* Check if the SYN/ACK packets ACK matches the earlier
2404  * received SYN/ACK packet. */
2405  if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack))) {
2406  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
2407  "%" PRIu32 " from stream",
2408  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2409 
2411  return -1;
2412  }
2413 
2414  /* Check if the SYN/ACK packet SEQ the earlier
2415  * received SYN/ACK packet, server resend with different ISN. */
2416  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.isn))) {
2417  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2418  "%" PRIu32 " from stream",
2419  ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.isn);
2420 
2421  if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
2422  return -1;
2423  SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
2424  }
2425 
2426  } else if (tcph->th_flags & TH_SYN) {
2427  SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
2428 
2429  if (PKT_IS_TOCLIENT(p)) {
2430  SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
2431 
2433  return -1;
2434  }
2435 
2436  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn))) {
2437  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
2438 
2440  return -1;
2441  }
2442 
2443  } else if (tcph->th_flags & TH_ACK) {
2444  if (ssn->queue_len) {
2445  SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
2446  TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
2447  if (q != NULL) {
2448  SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
2449  StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
2450  } else {
2451  SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
2452  }
2453  }
2454 
2455 
2456  /* If the timestamp option is enabled for both the streams, then
2457  * validate the received packet timestamp value against the
2458  * stream->last_ts. If the timestamp is valid then process the
2459  * packet normally otherwise the drop the packet (RFC 1323)*/
2460  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2461  if (!(StreamTcpValidateTimestamp(ssn, p))) {
2462  return -1;
2463  }
2464  }
2465 
2466  if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) {
2467  SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
2468 
2469  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2470  SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
2472  return -1;
2473  }
2474 
2475  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2476  SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
2478  return -1;
2479  }
2480 
2481  SCLogDebug("4WHS normal pkt");
2482  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2483  "%" PRIu32 ", ACK %" PRIu32 "",
2484  ssn, p->payload_len, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph));
2485 
2486  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2487  StreamTcpHandleTimestamp(ssn, p);
2488  }
2489 
2490  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_RAW_ACK(tcph));
2491  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2492  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2493  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2494 
2495  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2496  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2497 
2498  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2499 
2500  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
2501  "ssn->client.last_ack %"PRIu32"", ssn,
2502  ssn->client.next_win, ssn->client.last_ack);
2503  return 0;
2504  }
2505 
2506  bool ack_indicates_missed_3whs_ack_packet = false;
2507  /* Check if the ACK received is in right direction. But when we have
2508  * picked up a mid stream session after missing the initial SYN pkt,
2509  * in this case the ACK packet can arrive from either client (normal
2510  * case) or from server itself (asynchronous streams). Therefore
2511  * the check has been avoided in this case */
2512  if (PKT_IS_TOCLIENT(p)) {
2513  /* special case, handle 4WHS, so SYN/ACK in the opposite
2514  * direction */
2516  SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
2517  "pickup session",ssn);
2518  /* fall through */
2519  } else if (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) {
2520  SCLogDebug("ssn %p: ACK received on TFO session",ssn);
2521  /* fall through */
2522 
2523  } else {
2524  /* if we missed traffic between the S/SA and the current
2525  * 'wrong direction' ACK, we could end up here. In IPS
2526  * reject it. But in IDS mode we continue.
2527  *
2528  * IPS rejects as it should see all packets, so pktloss
2529  * should lead to retransmissions. As this can also be
2530  * pattern for MOTS/MITM injection attacks, we need to be
2531  * careful.
2532  */
2533  if (StreamTcpInlineMode()) {
2534  if (p->payload_len > 0 && SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack) &&
2535  SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq)) {
2536  /* packet loss is possible but unlikely here */
2537  SCLogDebug("ssn %p: possible data injection", ssn);
2539  return -1;
2540  }
2541 
2542  SCLogDebug("ssn %p: ACK received in the wrong direction",
2543  ssn);
2545  return -1;
2546  }
2547  ack_indicates_missed_3whs_ack_packet = true;
2548  }
2549  }
2550 
2551  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
2552  ", ACK %" PRIu32 "",
2553  ssn, p->payload_len, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph));
2554 
2555  /* Check both seq and ack number before accepting the packet and
2556  changing to ESTABLISHED state */
2557  if ((SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) &&
2558  SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.next_seq)) {
2559  SCLogDebug("normal pkt");
2560 
2561  /* process the packet normal, No Async streams :) */
2562 
2563  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2564  StreamTcpHandleTimestamp(ssn, p);
2565  }
2566 
2567  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_RAW_ACK(tcph));
2568  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2569  ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2570 
2571  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2572 
2573  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2574  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2575  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2576  ssn->server.next_win = ssn->server.last_ack +
2577  ssn->server.window;
2578  if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
2579  /* window scaling for midstream pickups, we can't do much
2580  * other than assume that it's set to the max value: 14 */
2581  ssn->server.wscale = TCP_WSCALE_MAX;
2582  ssn->client.wscale = TCP_WSCALE_MAX;
2583  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2584  }
2585  }
2586 
2587  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2588  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2589 
2590  /* special case: normally the packet following the 3whs is
2591  * considered flow established, but with data we need it to
2592  * be established now. This can happen if the original ACK was
2593  * lost. */
2594  if (p->payload_len) {
2596  }
2597 
2598  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2599 
2600  /* If asynchronous stream handling is allowed then set the session,
2601  if packet's seq number is equal the expected seq no.*/
2602  } else if (stream_config.async_oneside &&
2603  (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2604  /*set the ASYNC flag used to indicate the session as async stream
2605  and helps in relaxing the windows checks.*/
2606  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2607  ssn->server.next_seq += p->payload_len;
2608  ssn->server.last_ack = TCP_GET_RAW_SEQ(tcph);
2609 
2610  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2611  ssn->client.last_ack = TCP_GET_RAW_ACK(tcph);
2612 
2613  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2614  StreamTcpHandleTimestamp(ssn, p);
2615  }
2616 
2617  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2618  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2619  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2620  /* window scaling for midstream pickups, we can't do much
2621  * other than assume that it's set to the max value: 14 */
2622  ssn->server.wscale = TCP_WSCALE_MAX;
2623  ssn->client.wscale = TCP_WSCALE_MAX;
2624  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2625  }
2626 
2627  SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
2628  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2629  "ssn->server.next_seq %" PRIu32,
2630  ssn, TCP_GET_RAW_SEQ(tcph), p->payload_len,
2631  TCP_GET_RAW_SEQ(tcph) + p->payload_len, ssn->server.next_seq);
2632 
2633  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2634  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2635 
2636  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2637  /* Upon receiving the packet with correct seq number and wrong
2638  ACK number, it causes the other end to send RST. But some target
2639  system (Linux & solaris) does not RST the connection, so it is
2640  likely to avoid the detection */
2641  } else if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) {
2643  SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
2644  ssn);
2645 
2647  return -1;
2648 
2649  /* SYN/ACK followed by more TOCLIENT suggesting packet loss */
2650  } else if (PKT_IS_TOCLIENT(p) && !StreamTcpInlineMode() &&
2651  SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2652  SEQ_GT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
2653  SCLogDebug("ssn %p: ACK for missing data", ssn);
2654 
2655  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2656  StreamTcpHandleTimestamp(ssn, p);
2657  }
2658 
2659  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_RAW_ACK(tcph));
2660 
2661  ssn->server.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
2662  SCLogDebug("ssn %p: ACK for missing data: ssn->server.next_seq %u", ssn,
2663  ssn->server.next_seq);
2664  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2665 
2666  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2667 
2668  ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2669  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2670 
2671  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2672  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2673 
2674  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2675 
2676  /* if we get a packet with a proper ack, but a seq that is beyond
2677  * next_seq but in-window, we probably missed some packets */
2678  } else if (SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2679  SEQ_LEQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_win) &&
2680  SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.next_seq)) {
2681  SCLogDebug("ssn %p: ACK for missing data", ssn);
2682 
2683  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2684  StreamTcpHandleTimestamp(ssn, p);
2685  }
2686 
2687  ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
2688  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_RAW_ACK(tcph));
2689 
2690  SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
2691  ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2692  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2693 
2694  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2695  ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2696  ssn->server.next_win = ssn->server.last_ack +
2697  ssn->server.window;
2698  /* window scaling for midstream pickups, we can't do much
2699  * other than assume that it's set to the max value: 14 */
2700  ssn->server.wscale = TCP_WSCALE_MAX;
2701  ssn->client.wscale = TCP_WSCALE_MAX;
2702  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2703  }
2704 
2705  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2706  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2707 
2708  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2709 
2710  /* toclient packet: after having missed the 3whs's final ACK */
2711  } else if ((ack_indicates_missed_3whs_ack_packet ||
2712  (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN)) &&
2713  SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack) &&
2714  SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq)) {
2715  if (ack_indicates_missed_3whs_ack_packet) {
2716  SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2717  } else {
2718  SCLogDebug("ssn %p: (TFO) expected packet fits perfectly after SYN/ACK", ssn);
2719  }
2720 
2721  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_RAW_SEQ(tcph) + p->payload_len));
2722 
2723  ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2724  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2725 
2726  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2727  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2728 
2729  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2730 
2731  } else {
2732  SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2733 
2735  return -1;
2736  }
2737 
2738  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2739  "ssn->server.last_ack %"PRIu32"", ssn,
2740  ssn->server.next_win, ssn->server.last_ack);
2741  } else {
2742  SCLogDebug("ssn %p: default case", ssn);
2743  }
2744 
2745  return 0;
2746 }
2747 
2748 /**
2749  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2750  * sent by the client to server. The function handles
2751  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2752  * the reassembly.
2753  *
2754  * Timestamp has already been checked at this point.
2755  *
2756  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2757  * \param ssn Pointer to the current TCP session
2758  * \param p Packet which has to be handled in this TCP state.
2759  * \param stt Stream Thread module registered to handle the stream handling
2760  */
2761 static int HandleEstablishedPacketToServer(
2762  ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt)
2763 {
2764  const TCPHdr *tcph = PacketGetTCP(p);
2765  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
2766  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
2767  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
2768 
2769  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2770  "ACK %" PRIu32 ", WIN %" PRIu16 "",
2771  ssn, p->payload_len, seq, ack, window);
2772 
2773  const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
2774  if (has_ack) {
2775  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TC) && ack == ssn->server.next_seq + 1) {
2776  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2778 
2779  } else if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2780  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2782  return -1;
2783  }
2784  }
2785 
2786  /* check for Keep Alive */
2787  if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->client.next_seq - 1))) {
2788  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2789 
2790  /* normal pkt */
2791  } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->client.last_ack))) {
2792  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2793  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2794  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2795  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2796  "%" PRIu32 "(%" PRIu32 ")",
2797  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2798  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2799 
2800  /* update the last_ack to current seq number as the session is
2801  * async and other stream is not updating it anymore :( */
2802  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2803 
2804  } else if (SEQ_EQ(ssn->client.next_seq, seq) && stream_config.async_oneside &&
2805  (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2806  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2807  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2808  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2809  "%" PRIu32 "(%" PRIu32 ")",
2810  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2811  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2812 
2813  /* it seems we missed SYN and SYN/ACK packets of this session.
2814  * Update the last_ack to current seq number as the session
2815  * is async and other stream is not updating it anymore :( */
2816  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2817  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2818 
2819  } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2821  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2822  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2823  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2824  "%" PRIu32 "(%" PRIu32 ")",
2825  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2826  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2827 
2828  /* it seems we missed SYN and SYN/ACK packets of this session.
2829  * Update the last_ack to current seq number as the session
2830  * is async and other stream is not updating it anymore :(*/
2831  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2832  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2833 
2834  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2835  * In this case we do accept the data before last_ack if it is (partly)
2836  * beyond next seq */
2837  } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
2838  SEQ_GT((seq + p->payload_len), ssn->client.next_seq)) {
2839  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2840  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
2841  " acked data that we haven't seen before",
2842  ssn, seq, p->payload_len, ssn->client.last_ack, ssn->client.next_seq);
2843  } else {
2844  SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
2845  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2846  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2847  "%" PRIu32 "(%" PRIu32 ")",
2848  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2849  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2850 
2851  SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
2853  return -1;
2854  }
2855  }
2856 
2857  int zerowindowprobe = 0;
2858  /* zero window probe */
2859  if (p->payload_len == 1 && seq == ssn->client.next_seq && ssn->client.window == 0) {
2860  SCLogDebug("ssn %p: zero window probe", ssn);
2861  zerowindowprobe = 1;
2863  ssn->flags |= STREAMTCP_FLAG_ZWP_TS;
2864  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2865 
2866  } else if (SEQ_GEQ(seq + p->payload_len, ssn->client.next_seq)) {
2867  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
2868  }
2869 
2870  /* in window check */
2871  if (zerowindowprobe) {
2872  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2873  } else if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
2875  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
2876  "%" PRIu32 "",
2877  ssn, seq, ssn->client.next_win);
2878 
2879  ssn->server.window = window << ssn->server.wscale;
2880  SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
2881  ssn->server.window);
2882 
2883  /* Check if the ACK value is sane and inside the window limit */
2884  if (tcph->th_flags & TH_ACK) {
2885  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
2886  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
2887  SEQ_GT(ssn->server.last_ack, ssn->server.next_seq)) {
2890  }
2891  }
2892 
2893  SCLogDebug(
2894  "ack %u last_ack %u next_seq %u", ack, ssn->server.last_ack, ssn->server.next_seq);
2895 
2896  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2897  StreamTcpHandleTimestamp(ssn, p);
2898  }
2899 
2901 
2902  /* update next_win */
2903  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
2904 
2905  /* handle data (if any) */
2906  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2907 
2908  } else {
2909  SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
2910  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2911  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2912  "%" PRIu32 "(%" PRIu32 ")",
2913  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2914  ssn->client.next_win, (seq + p->payload_len) - ssn->client.next_win);
2915  SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
2916  StreamTcpSackedSize(&ssn->client));
2918  return -1;
2919  }
2920  return 0;
2921 }
2922 
2923 /**
2924  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2925  * sent by the server to client. The function handles
2926  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2927  * the reassembly
2928  *
2929  * Timestamp has already been checked at this point.
2930  *
2931  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2932  * \param ssn Pointer to the current TCP session
2933  * \param p Packet which has to be handled in this TCP state.
2934  * \param stt Stream Thread module registered to handle the stream handling
2935  */
2936 static int HandleEstablishedPacketToClient(
2937  ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt)
2938 {
2939  const TCPHdr *tcph = PacketGetTCP(p);
2940  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
2941  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
2942  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
2943 
2944  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
2945  " ACK %" PRIu32 ", WIN %" PRIu16 "",
2946  ssn, p->payload_len, seq, ack, window);
2947 
2948  const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
2949  if (has_ack) {
2950  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TS) && ack == ssn->client.next_seq + 1) {
2951  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2953 
2954  } else if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2955  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2957  return -1;
2958  }
2959  }
2960 
2961  /* To get the server window value from the servers packet, when connection
2962  is picked up as midstream */
2963  if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
2965  {
2966  ssn->server.window = window << ssn->server.wscale;
2967  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2969  SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
2970  "%" PRIu32 "", ssn, ssn->server.next_win);
2971  }
2972 
2973  /* check for Keep Alive */
2974  if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->server.next_seq - 1))) {
2975  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2976 
2977  /* normal pkt */
2978  } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->server.last_ack))) {
2979  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2980 
2981  SCLogDebug("ssn %p: client => Asynchronous stream, packet SEQ"
2982  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2983  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2984  " %" PRIu32 "(%" PRIu32 ")",
2985  ssn, seq, p->payload_len, seq + p->payload_len, ssn->server.last_ack,
2986  ssn->server.next_win, seq + p->payload_len - ssn->server.next_win);
2987 
2988  ssn->server.last_ack = seq;
2989 
2990  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2991  * In this case we do accept the data before last_ack if it is (partly)
2992  * beyond next seq */
2993  } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
2994  SEQ_GT((seq + p->payload_len), ssn->server.next_seq)) {
2995  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2996  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
2997  " acked data that we haven't seen before",
2998  ssn, seq, p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2999  } else {
3000  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
3001  " before last_ack %" PRIu32 ". next_seq %" PRIu32,
3002  ssn, seq, p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
3004  return -1;
3005  }
3006  }
3007 
3008  int zerowindowprobe = 0;
3009  /* zero window probe */
3010  if (p->payload_len == 1 && seq == ssn->server.next_seq && ssn->server.window == 0) {
3011  SCLogDebug("ssn %p: zero window probe", ssn);
3012  zerowindowprobe = 1;
3014  ssn->flags |= STREAMTCP_FLAG_ZWP_TC;
3015 
3016  /* accept the segment */
3017  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3018 
3019  } else if (SEQ_GEQ(seq + p->payload_len, ssn->server.next_seq)) {
3020  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3021  }
3022 
3023  if (zerowindowprobe) {
3024  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
3025  } else if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
3027  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
3028  "%" PRIu32 "",
3029  ssn, seq, ssn->server.next_win);
3030  ssn->client.window = window << ssn->client.wscale;
3031  SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
3032  ssn->client.window);
3033 
3034  if (tcph->th_flags & TH_ACK) {
3035  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3036  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
3037  SEQ_GT(ssn->client.last_ack, ssn->client.next_seq)) {
3040  }
3041  }
3042 
3043  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3044  StreamTcpHandleTimestamp(ssn, p);
3045  }
3046 
3048 
3049  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3050 
3051  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3052  } else {
3053  SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
3054  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
3055  " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
3056  "%" PRIu32 "(%" PRIu32 ")",
3057  ssn, seq, p->payload_len, seq + p->payload_len, ssn->server.last_ack,
3058  ssn->server.next_win, seq + p->payload_len - ssn->server.next_win);
3060  return -1;
3061  }
3062  return 0;
3063 }
3064 
3065 static bool StreamTcpPacketIsZeroWindowProbeAck(const TcpSession *ssn, const Packet *p)
3066 {
3067  const TCPHdr *tcph = PacketGetTCP(p);
3068  if (ssn->state < TCP_ESTABLISHED)
3069  return false;
3070  if (p->payload_len != 0)
3071  return false;
3072  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3073  return false;
3074 
3075  const TcpStream *snd, *rcv;
3076  if (PKT_IS_TOCLIENT(p)) {
3077  snd = &ssn->server;
3078  rcv = &ssn->client;
3079  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TS))
3080  return false;
3081  } else {
3082  snd = &ssn->client;
3083  rcv = &ssn->server;
3084  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TC))
3085  return false;
3086  }
3087 
3088  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3089  if (pkt_win != 0)
3090  return false;
3091  if (pkt_win != rcv->window)
3092  return false;
3093 
3094  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3095  return false;
3096  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3097  return false;
3098  SCLogDebug("ssn %p: packet %" PRIu64 " is a Zero Window Probe ACK", ssn, p->pcap_cnt);
3099  return true;
3100 }
3101 
3102 /** \internal
3103  * \brief check if an ACK packet is a dup-ACK
3104  */
3105 static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p)
3106 {
3107  const TCPHdr *tcph = PacketGetTCP(p);
3108  if (ssn->state < TCP_ESTABLISHED)
3109  return false;
3110  if (p->payload_len != 0)
3111  return false;
3112  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3113  return false;
3114 
3115  const TcpStream *snd, *rcv;
3116  if (PKT_IS_TOCLIENT(p)) {
3117  snd = &ssn->server;
3118  rcv = &ssn->client;
3119  } else {
3120  snd = &ssn->client;
3121  rcv = &ssn->server;
3122  }
3123 
3124  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3125  if (pkt_win == 0 || rcv->window == 0)
3126  return false;
3127  if (pkt_win != rcv->window)
3128  return false;
3129 
3130  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3131  return false;
3132  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3133  return false;
3134 
3135  SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn,
3136  p->pcap_cnt, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph), pkt_win, snd->next_seq,
3137  snd->last_ack, rcv->window, snd->next_seq, rcv->last_ack, rcv->window);
3138  return true;
3139 }
3140 
3141 /** \internal
3142  * \brief check if a ACK packet is outdated so processing can be fast tracked
3143  *
3144  * Consider a packet outdated ack if:
3145  * - state is >= ESTABLISHED
3146  * - ACK < last_ACK
3147  * - SACK acks nothing new
3148  * - packet has no data
3149  * - SEQ == next_SEQ
3150  * - flags has ACK set but don't contain SYN/FIN/RST
3151  *
3152  * \todo the most likely explanation for this packet is that we already
3153  * accepted a "newer" ACK. We will not consider an outdated timestamp
3154  * option an issue for this packet, but we should probably still
3155  * check if the ts isn't too far off.
3156  */
3157 static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p)
3158 {
3159  const TCPHdr *tcph = PacketGetTCP(p);
3160  if (ssn->state < TCP_ESTABLISHED)
3161  return false;
3162  if (p->payload_len != 0)
3163  return false;
3164  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3165  return false;
3166 
3167  /* lets see if this is a packet that is entirely eclipsed by earlier ACKs */
3168  if (PKT_IS_TOSERVER(p)) {
3169  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
3170  SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->server.last_ack)) {
3171  if (!TCP_HAS_SACK(p)) {
3172  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3173  ssn->client.next_seq);
3174  return true;
3175  }
3176 
3177  if (StreamTcpSackPacketIsOutdated(&ssn->server, p)) {
3178  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3179  ssn->client.next_seq);
3180  return true;
3181  }
3182  }
3183  } else {
3184  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq) &&
3185  SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
3186  if (!TCP_HAS_SACK(p)) {
3187  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3188  ssn->client.next_seq);
3189  return true;
3190  }
3191 
3192  if (StreamTcpSackPacketIsOutdated(&ssn->client, p)) {
3193  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3194  ssn->client.next_seq);
3195  return true;
3196  }
3197  }
3198  }
3199  return false;
3200 }
3201 
3202 /** \internal
3203  * \brief check if packet is before ack'd windows
3204  * If packet is before last ack, we will not accept it
3205  *
3206  * \retval 0 not spurious retransmission
3207  * \retval 1 before last_ack, after base_seq
3208  * \retval 2 before last_ack and base_seq
3209  */
3210 static int StreamTcpPacketIsSpuriousRetransmission(const TcpSession *ssn, Packet *p)
3211 {
3212  const TcpStream *stream;
3213  if (PKT_IS_TOCLIENT(p)) {
3214  stream = &ssn->server;
3215  } else {
3216  stream = &ssn->client;
3217  }
3218  if (p->payload_len == 0)
3219  return 0;
3220 
3221  const TCPHdr *tcph = PacketGetTCP(p);
3222  /* take base_seq into account to avoid edge cases where last_ack might be
3223  * too far ahead during heavy packet loss */
3224  if (!(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3225  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->base_seq))) {
3226  SCLogDebug(
3227  "ssn %p: spurious retransmission; packet entirely before base_seq: SEQ %u(%u) "
3228  "last_ack %u base_seq %u",
3229  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3230  stream->last_ack, stream->base_seq);
3232  return 2;
3233  }
3234  }
3235 
3236  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack))) {
3237  SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) "
3238  "last_ack %u",
3239  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3240  stream->last_ack);
3242  return 1;
3243  }
3244 
3245  SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ "
3246  "%u(%u) last_ack %u, base_seq %u",
3247  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack,
3248  stream->base_seq);
3249  return 0;
3250 }
3251 
3252 /**
3253  * \brief Function to handle the TCP_ESTABLISHED state. The function handles
3254  * ACK, FIN, RST packets and correspondingly changes the connection
3255  * state. The function handles the data inside packets and call
3256  * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
3257  *
3258  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3259  * \param p Packet which has to be handled in this TCP state.
3260  * \param stt Stream Thread module registered to handle the stream handling
3261  */
3262 
3263 static int StreamTcpPacketStateEstablished(
3264  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3265 {
3266  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3267  const TCPHdr *tcph = PacketGetTCP(p);
3268  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3269  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3270  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3271 
3272  if (tcph->th_flags & TH_RST) {
3273  if (!StreamTcpValidateRst(ssn, p))
3274  return -1;
3275 
3276  if (PKT_IS_TOSERVER(p)) {
3277  StreamTcpCloseSsnWithReset(p, ssn);
3278 
3279  ssn->server.next_seq = ack;
3280  ssn->client.next_seq = seq + p->payload_len;
3281  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3282  ssn->server.next_seq);
3283  ssn->client.window = window << ssn->client.wscale;
3284 
3285  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3286  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3287 
3288  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
3289 
3290  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3291  StreamTcpHandleTimestamp(ssn, p);
3292  }
3293 
3294  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3295  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3296  "%" PRIu32 "", ssn, ssn->client.next_seq,
3297  ssn->server.last_ack);
3298 
3299  /* don't return packets to pools here just yet, the pseudo
3300  * packet will take care, otherwise the normal session
3301  * cleanup. */
3302  } else {
3303  StreamTcpCloseSsnWithReset(p, ssn);
3304 
3305  ssn->server.next_seq = seq + p->payload_len + 1;
3306  ssn->client.next_seq = ack;
3307 
3308  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3309  ssn->server.next_seq);
3310  ssn->server.window = window << ssn->server.wscale;
3311 
3312  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3313  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3314 
3315  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
3316 
3317  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3318  StreamTcpHandleTimestamp(ssn, p);
3319  }
3320 
3321  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3322  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3323  "%" PRIu32 "", ssn, ssn->server.next_seq,
3324  ssn->client.last_ack);
3325 
3326  /* don't return packets to pools here just yet, the pseudo
3327  * packet will take care, otherwise the normal session
3328  * cleanup. */
3329  }
3330 
3331  } else if (tcph->th_flags & TH_FIN) {
3332  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3333  if (!StreamTcpValidateTimestamp(ssn, p))
3334  return -1;
3335  }
3336 
3337  SCLogDebug("ssn (%p: FIN received SEQ"
3338  " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
3339  " win %" PRIu32 "", ssn, ssn->server.next_seq,
3340  ssn->client.last_ack, ssn->server.next_win,
3341  ssn->server.window);
3342 
3343  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
3344  return -1;
3345 
3346  /* SYN/ACK */
3347  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
3348  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
3349  ssn);
3350 
3351  if (PKT_IS_TOSERVER(p)) {
3352  SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
3353 
3355  return -1;
3356  }
3357 
3358  /* Check if the SYN/ACK packets ACK matches the earlier
3359  * received SYN/ACK packet. */
3360  if (!(SEQ_EQ(ack, ssn->client.last_ack))) {
3361  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
3362  "%" PRIu32 " from stream",
3363  ssn, ack, ssn->client.isn + 1);
3364 
3366  return -1;
3367  }
3368 
3369  /* Check if the SYN/ACK packet SEQ the earlier
3370  * received SYN packet. */
3371  if (!(SEQ_EQ(seq, ssn->server.isn))) {
3372  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
3373  "%" PRIu32 " from stream",
3374  ssn, ack, ssn->client.isn + 1);
3375 
3377  return -1;
3378  }
3379 
3380  if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
3381  /* a resend of a SYN while we are established already -- fishy */
3383  return -1;
3384  }
3385 
3386  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
3387  "Likely due server not receiving final ACK in 3whs", ssn);
3388  return 0;
3389 
3390  } else if (tcph->th_flags & TH_SYN) {
3391  SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
3392  if (PKT_IS_TOCLIENT(p)) {
3393  SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
3394 
3396  return -1;
3397  }
3398 
3399  if (!(SEQ_EQ(ack, ssn->client.isn))) {
3400  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
3401 
3403  return -1;
3404  }
3405 
3406  /* a resend of a SYN while we are established already -- fishy */
3408  return -1;
3409 
3410  } else if (tcph->th_flags & TH_ACK) {
3411  /* Urgent pointer size can be more than the payload size, as it tells
3412  * the future coming data from the sender will be handled urgently
3413  * until data of size equal to urgent offset has been processed
3414  * (RFC 2147) */
3415 
3416  /* If the timestamp option is enabled for both the streams, then
3417  * validate the received packet timestamp value against the
3418  * stream->last_ts. If the timestamp is valid then process the
3419  * packet normally otherwise the drop the packet (RFC 1323) */
3420  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3421  if (!StreamTcpValidateTimestamp(ssn, p))
3422  return -1;
3423  }
3424 
3425  if (PKT_IS_TOSERVER(p)) {
3426  /* Process the received packet to server */
3427  HandleEstablishedPacketToServer(tv, ssn, p, stt);
3428 
3429  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3430  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3431  ssn->client.next_seq, ssn->server.last_ack
3432  ,ssn->client.next_win, ssn->client.window);
3433 
3434  } else { /* implied to client */
3435  if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
3437  SCLogDebug("3whs is now confirmed by server");
3438  }
3439 
3440  /* Process the received packet to client */
3441  HandleEstablishedPacketToClient(tv, ssn, p, stt);
3442 
3443  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3444  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3445  ssn->server.next_seq, ssn->client.last_ack,
3446  ssn->server.next_win, ssn->server.window);
3447  }
3448  } else {
3449  SCLogDebug("ssn %p: default case", ssn);
3450  }
3451 
3452  return 0;
3453 }
3454 
3455 /**
3456  * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
3457  * TCP_ESTABLISHED and changes to another TCP state as required.
3458  *
3459  * \param tv Thread Variable containing input/output queue, cpu affinity
3460  * \param p Packet which has to be handled in this TCP state.
3461  * \param stt Stream Thread module registered to handle the stream handling
3462  *
3463  * \retval 0 success
3464  * \retval -1 something wrong with the packet
3465  */
3466 
3467 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession *ssn, Packet *p)
3468 {
3469  const TCPHdr *tcph = PacketGetTCP(p);
3470  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3471  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3472  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3473 
3474  if (PKT_IS_TOSERVER(p)) {
3475  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
3476  " ACK %" PRIu32 "",
3477  ssn, p->payload_len, seq, ack);
3478 
3479  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3480  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3482  return -1;
3483  }
3484 
3485  const uint32_t pkt_re = seq + p->payload_len;
3486  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3487  ssn->client.last_ack, ssn->client.next_win);
3488  if (SEQ_GEQ(seq, ssn->client.last_ack) && SEQ_LEQ(pkt_re, ssn->client.next_win)) {
3489  // within expectations
3490  } else {
3491  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3492  "%" PRIu32 " from stream",
3493  ssn, seq, ssn->client.next_seq);
3494 
3496  return -1;
3497  }
3498 
3499  if (tcph->th_flags & TH_SYN) {
3500  SCLogDebug("ssn %p: FIN+SYN", ssn);
3502  return -1;
3503  }
3504  StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
3505  SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
3506 
3507  /* if we accept the FIN, next_seq needs to reflect the FIN */
3508  ssn->client.next_seq = seq + p->payload_len;
3509 
3510  SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
3511  ssn->client.next_seq);
3512  ssn->server.window = window << ssn->server.wscale;
3513 
3514  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3515  StreamTcpHandleTimestamp(ssn, p);
3516  }
3517 
3518  /* Update the next_seq, in case if we have missed the client packet
3519  and server has already received and acked it */
3520  if (SEQ_LT(ssn->server.next_seq, ack))
3521  ssn->server.next_seq = ack;
3522 
3523  if (tcph->th_flags & TH_ACK)
3524  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3525 
3526  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3527 
3528  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3529  ssn, ssn->client.next_seq, ssn->server.last_ack);
3530  } else { /* implied to client */
3531  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
3532  "ACK %" PRIu32 "",
3533  ssn, p->payload_len, seq, ack);
3534 
3535  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3536  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3538  return -1;
3539  }
3540 
3541  const uint32_t pkt_re = seq + p->payload_len;
3542  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3543  ssn->server.last_ack, ssn->server.next_win);
3544  if (SEQ_GEQ(seq, ssn->server.last_ack) && SEQ_LEQ(pkt_re, ssn->server.next_win)) {
3545  // within expectations
3546  } else {
3547  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3548  "%" PRIu32 " from stream (last_ack %u win %u = %u)",
3549  ssn, seq, ssn->server.next_seq, ssn->server.last_ack, ssn->server.window,
3550  (ssn->server.last_ack + ssn->server.window));
3551 
3553  return -1;
3554  }
3555 
3556  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
3557  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
3558 
3559  /* if we accept the FIN, next_seq needs to reflect the FIN */
3560  ssn->server.next_seq = seq + p->payload_len + 1;
3561  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 " updated", ssn, ssn->server.next_seq);
3562 
3563  ssn->client.window = window << ssn->client.wscale;
3564 
3565  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3566  StreamTcpHandleTimestamp(ssn, p);
3567  }
3568 
3569  /* Update the next_seq, in case if we have missed the client packet
3570  and server has already received and acked it */
3571  if (SEQ_LT(ssn->client.next_seq, ack))
3572  ssn->client.next_seq = ack;
3573 
3574  if (tcph->th_flags & TH_ACK)
3575  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3576 
3577  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3578 
3579  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3580  ssn, ssn->server.next_seq, ssn->client.last_ack);
3581  }
3582 
3583  return 0;
3584 }
3585 
3586 /**
3587  * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
3588  * ACK, FIN, RST packets and correspondingly changes the connection
3589  * state.
3590  *
3591  * \param tv Thread Variable containing input/output queue, cpu affinity
3592  * \param p Packet which has to be handled in this TCP state.
3593  * \param stt Stream Thread module registered to handle the stream handling
3594  *
3595  * \retval 0 success
3596  * \retval -1 something wrong with the packet
3597  */
3598 
3599 static int StreamTcpPacketStateFinWait1(
3600  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3601 {
3602  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3603  const TCPHdr *tcph = PacketGetTCP(p);
3604  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3605  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3606  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3607 
3608  if (tcph->th_flags & TH_RST) {
3609  if (!StreamTcpValidateRst(ssn, p))
3610  return -1;
3611 
3612  StreamTcpCloseSsnWithReset(p, ssn);
3613 
3614  if (PKT_IS_TOSERVER(p)) {
3615  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3616  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3617 
3618  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
3619 
3620  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3621  StreamTcpHandleTimestamp(ssn, p);
3622  }
3623 
3624  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3625  } else {
3626  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3627  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3628 
3629  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
3630 
3631  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3632  StreamTcpHandleTimestamp(ssn, p);
3633  }
3634 
3635  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3636  }
3637 
3638  } else if ((tcph->th_flags & (TH_FIN | TH_ACK)) == (TH_FIN | TH_ACK)) {
3639  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3640  if (!StreamTcpValidateTimestamp(ssn, p))
3641  return -1;
3642  }
3643 
3644  if (PKT_IS_TOSERVER(p)) {
3645  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3646  "%" PRIu32 ", ACK %" PRIu32 "",
3647  ssn, p->payload_len, seq, ack);
3648  int retransmission = 0;
3649 
3650  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3651  SCLogDebug("ssn %p: packet is retransmission", ssn);
3652  retransmission = 1;
3654 
3655  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3656  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3657  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3658  " != %" PRIu32 " from stream",
3659  ssn, seq, ssn->client.next_seq);
3661  return -1;
3662  }
3663 
3664  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3665  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3667  return -1;
3668  }
3669 
3670  if (!retransmission) {
3671  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3672  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3673 
3674  ssn->server.window = window << ssn->server.wscale;
3675  }
3676 
3677  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3678  StreamTcpHandleTimestamp(ssn, p);
3679  }
3680 
3681  /* Update the next_seq, in case if we have missed the client
3682  packet and server has already received and acked it */
3683  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3684  ssn->server.next_seq = ack;
3685 
3686  if (SEQ_EQ(ssn->client.next_seq, seq)) {
3687  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3688  }
3689 
3690  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3691 
3692  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3693 
3694  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3695  "%" PRIu32 "", ssn, ssn->client.next_seq,
3696  ssn->server.last_ack);
3697  } else { /* implied to client */
3698  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3699  "%" PRIu32 ", ACK %" PRIu32 "",
3700  ssn, p->payload_len, seq, ack);
3701  int retransmission = 0;
3702 
3703  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3704  SCLogDebug("ssn %p: packet is retransmission", ssn);
3705  retransmission = 1;
3707 
3708  } else if (SEQ_EQ(ssn->server.next_seq - 1, seq) && SEQ_EQ(ssn->client.last_ack, ack)) {
3709  SCLogDebug("ssn %p: packet is retransmission", ssn);
3710  retransmission = 1;
3712 
3713  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3714  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3715  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3716  " != %" PRIu32 " from stream",
3717  ssn, seq, ssn->server.next_seq);
3719  return -1;
3720  }
3721 
3722  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3723  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3725  return -1;
3726  }
3727 
3728  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3729  StreamTcpHandleTimestamp(ssn, p);
3730  }
3731 
3732  if (!retransmission) {
3733  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3734  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3735 
3736  ssn->client.window = window << ssn->client.wscale;
3737 
3738  /* Update the next_seq, in case if we have missed the client
3739  packet and server has already received and acked it */
3740  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3741  ssn->client.next_seq = ack;
3742 
3743  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3744  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3745  }
3746 
3747  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3748  }
3749 
3750  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3751 
3752  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3753  "%" PRIu32 "", ssn, ssn->server.next_seq,
3754  ssn->client.last_ack);
3755  }
3756 
3757  } else if (tcph->th_flags & TH_FIN) {
3758  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3759  if (!StreamTcpValidateTimestamp(ssn, p))
3760  return -1;
3761  }
3762 
3763  if (PKT_IS_TOSERVER(p)) {
3764  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3765  "%" PRIu32 ", ACK %" PRIu32 "",
3766  ssn, p->payload_len, seq, ack);
3767  int retransmission = 0;
3768 
3769  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3770  SCLogDebug("ssn %p: packet is retransmission", ssn);
3771  retransmission = 1;
3773 
3774  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3775  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3776  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3777  " != %" PRIu32 " from stream",
3778  ssn, seq, ssn->client.next_seq);
3780  return -1;
3781  }
3782 
3783  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3784  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3786  return -1;
3787  }
3788 
3789  if (!retransmission) {
3790  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3791  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3792 
3793  ssn->server.window = window << ssn->server.wscale;
3794  }
3795 
3796  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3797  StreamTcpHandleTimestamp(ssn, p);
3798  }
3799 
3800  /* Update the next_seq, in case if we have missed the client
3801  packet and server has already received and acked it */
3802  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3803  ssn->server.next_seq = ack;
3804 
3805  if (SEQ_EQ(ssn->client.next_seq - 1, seq)) {
3806  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3807  }
3808 
3809  if (tcph->th_flags & TH_ACK)
3810  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3811 
3812  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3813 
3814  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3815  "%" PRIu32 "", ssn, ssn->client.next_seq,
3816  ssn->server.last_ack);
3817  } else { /* implied to client */
3818  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3819  "%" PRIu32 ", ACK %" PRIu32 "",
3820  ssn, p->payload_len, seq, ack);
3821 
3822  int retransmission = 0;
3823 
3824  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3825  SCLogDebug("ssn %p: packet is retransmission", ssn);
3826  retransmission = 1;
3828 
3829  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3830  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3831  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3832  " != %" PRIu32 " from stream",
3833  ssn, seq, ssn->server.next_seq);
3835  return -1;
3836  }
3837 
3838  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3839  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3841  return -1;
3842  }
3843 
3844  if (!retransmission) {
3845  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3846  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3847 
3848  ssn->client.window = window << ssn->client.wscale;
3849  }
3850 
3851  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3852  StreamTcpHandleTimestamp(ssn, p);
3853  }
3854 
3855  /* Update the next_seq, in case if we have missed the client
3856  packet and server has already received and acked it */
3857  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3858  ssn->client.next_seq = ack;
3859 
3860  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3861  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3862  }
3863 
3864  if (tcph->th_flags & TH_ACK)
3865  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3866 
3867  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3868 
3869  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3870  "%" PRIu32 "", ssn, ssn->server.next_seq,
3871  ssn->client.last_ack);
3872  }
3873  } else if (tcph->th_flags & TH_SYN) {
3874  SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
3876  return -1;
3877 
3878  } else if (tcph->th_flags & TH_ACK) {
3879  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3880  if (!StreamTcpValidateTimestamp(ssn, p))
3881  return -1;
3882  }
3883 
3884  if (PKT_IS_TOSERVER(p)) {
3885  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3886  "%" PRIu32 ", ACK %" PRIu32 "",
3887  ssn, p->payload_len, seq, ack);
3888  int retransmission = 0;
3889 
3890  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3891  SCLogDebug("ssn %p: packet is retransmission", ssn);
3892  retransmission = 1;
3894  }
3895 
3896  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3897  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3899  return -1;
3900  }
3901 
3902  if (SEQ_LT(ack, ssn->server.next_seq)) {
3903  SCLogDebug(
3904  "ssn %p: ACK's older segment as %u < %u", ssn, ack, ssn->server.next_seq);
3905  } else if (!retransmission) {
3906  if (SEQ_EQ(ack, ssn->server.next_seq)) {
3907  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
3909  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
3910  "%" PRIu32 "",
3911  ssn, seq, ssn->client.next_win);
3912  SCLogDebug("seq %u client.next_seq %u", seq, ssn->client.next_seq);
3913  if (seq == ssn->client.next_seq) {
3914  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3915  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3916  }
3917  } else {
3918  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3919  " != %" PRIu32 " from stream",
3920  ssn, seq, ssn->client.next_seq);
3921 
3923  return -1;
3924  }
3925 
3926  ssn->server.window = window << ssn->server.wscale;
3927  }
3928  }
3929 
3930  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3931  StreamTcpHandleTimestamp(ssn, p);
3932  }
3933 
3934  /* Update the next_seq, in case if we have missed the client
3935  packet and server has already received and acked it */
3936  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3937  ssn->server.next_seq = ack;
3938 
3939  if (SEQ_EQ(ssn->client.next_seq, seq)) {
3940  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3941  }
3942 
3943  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3944 
3946 
3947  /* update next_win */
3948  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3949 
3950  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3951 
3952  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3953  "%" PRIu32 "", ssn, ssn->client.next_seq,
3954  ssn->server.last_ack);
3955 
3956  } else { /* implied to client */
3957 
3958  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3959  "%" PRIu32 ", ACK %" PRIu32 "",
3960  ssn, p->payload_len, seq, ack);
3961 
3962  int retransmission = 0;
3963 
3964  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3965  SCLogDebug("ssn %p: packet is retransmission", ssn);
3966  retransmission = 1;
3968  }
3969 
3970  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3971  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3973  return -1;
3974  }
3975 
3976  if (!retransmission) {
3977  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
3979  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
3980  "%" PRIu32 "",
3981  ssn, seq, ssn->server.next_win);
3982 
3983  if (seq == ssn->server.next_seq - 1) {
3984  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3985  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3986  }
3987  } else {
3988  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3989  " != %" PRIu32 " from stream",
3990  ssn, seq, ssn->server.next_seq);
3992  return -1;
3993  }
3994 
3995  ssn->client.window = window << ssn->client.wscale;
3996  }
3997 
3998  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3999  StreamTcpHandleTimestamp(ssn, p);
4000  }
4001 
4002  /* Update the next_seq, in case if we have missed the client
4003  packet and server has already received and acked it */
4004  if (SEQ_LT(ssn->client.next_seq - 1, ack))
4005  ssn->client.next_seq = ack;
4006 
4007  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
4008  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
4009  }
4010 
4011  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4012 
4014 
4015  /* update next_win */
4016  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4017 
4018  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4019 
4020  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4021  "%" PRIu32 "", ssn, ssn->server.next_seq,
4022  ssn->client.last_ack);
4023  }
4024  } else {
4025  SCLogDebug("ssn (%p): default case", ssn);
4026  }
4027 
4028  return 0;
4029 }
4030 
4031 /**
4032  * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
4033  * ACK, RST, FIN packets and correspondingly changes the connection
4034  * state.
4035  *
4036  * \param tv Thread Variable containing input/output queue, cpu affinity
4037  * \param p Packet which has to be handled in this TCP state.
4038  * \param stt Stream Thread module registered to handle the stream handling
4039  */
4040 
4041 static int StreamTcpPacketStateFinWait2(
4042  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4043 {
4044  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4045  const TCPHdr *tcph = PacketGetTCP(p);
4046  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4047  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4048  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4049 
4050  if (tcph->th_flags & TH_RST) {
4051  if (!StreamTcpValidateRst(ssn, p))
4052  return -1;
4053 
4054  StreamTcpCloseSsnWithReset(p, ssn);
4055 
4056  if (PKT_IS_TOSERVER(p)) {
4057  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4058  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4059 
4060  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4061 
4062  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4063  StreamTcpHandleTimestamp(ssn, p);
4064  }
4065 
4066  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4067  } else {
4068  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4069  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4070 
4071  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4072 
4073  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4074  StreamTcpHandleTimestamp(ssn, p);
4075  }
4076 
4077  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4078  }
4079 
4080  } else if (tcph->th_flags & TH_FIN) {
4081  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4082  if (!StreamTcpValidateTimestamp(ssn, p))
4083  return -1;
4084  }
4085 
4086  if (PKT_IS_TOSERVER(p)) {
4087  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4088  "%" PRIu32 ", ACK %" PRIu32 "",
4089  ssn, p->payload_len, seq, ack);
4090  int retransmission = 0;
4091 
4092  if (SEQ_EQ(seq, ssn->client.next_seq - 1) && SEQ_EQ(ack, ssn->server.last_ack)) {
4093  SCLogDebug("ssn %p: retransmission", ssn);
4094  retransmission = 1;
4096  } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4097  SCLogDebug("ssn %p: packet is retransmission", ssn);
4098  retransmission = 1;
4100 
4101  } else if (SEQ_LT(seq, ssn->client.next_seq) ||
4102  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4103  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4104  "%" PRIu32 " != %" PRIu32 " from stream",
4105  ssn, seq, ssn->client.next_seq);
4107  return -1;
4108  }
4109 
4110  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4111  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4113  return -1;
4114  }
4115 
4116  if (!retransmission) {
4117  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4118  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4119 
4120  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4122  ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4123  }
4124  ssn->server.window = window << ssn->server.wscale;
4125  }
4126 
4127  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4128  StreamTcpHandleTimestamp(ssn, p);
4129  }
4130 
4131  /* Update the next_seq, in case if we have missed the client
4132  packet and server has already received and acked it */
4133  if (SEQ_LT(ssn->server.next_seq, ack))
4134  ssn->server.next_seq = ack;
4135 
4136  if (tcph->th_flags & TH_ACK)
4137  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4138 
4139  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4140 
4141  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4142  "%" PRIu32 "", ssn, ssn->client.next_seq,
4143  ssn->server.last_ack);
4144  } else { /* implied to client */
4145  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4146  "%" PRIu32 ", ACK %" PRIu32 "",
4147  ssn, p->payload_len, seq, ack);
4148  int retransmission = 0;
4149 
4150  if (SEQ_EQ(seq, ssn->server.next_seq - 1) && SEQ_EQ(ack, ssn->client.last_ack)) {
4151  SCLogDebug("ssn %p: retransmission", ssn);
4152  retransmission = 1;
4154  } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4155  SCLogDebug("ssn %p: packet is retransmission", ssn);
4156  retransmission = 1;
4158 
4159  } else if (SEQ_LT(seq, ssn->server.next_seq) ||
4160  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4161  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4162  "%" PRIu32 " != %" PRIu32 " from stream",
4163  ssn, seq, ssn->server.next_seq);
4165  return -1;
4166  }
4167 
4168  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4169  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4171  return -1;
4172  }
4173 
4174  if (!retransmission) {
4175  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4176  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4177 
4178  ssn->client.window = window << ssn->client.wscale;
4179  }
4180 
4181  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4182  StreamTcpHandleTimestamp(ssn, p);
4183  }
4184 
4185  /* Update the next_seq, in case if we have missed the client
4186  packet and server has already received and acked it */
4187  if (SEQ_LT(ssn->client.next_seq, ack))
4188  ssn->client.next_seq = ack;
4189 
4190  if (tcph->th_flags & TH_ACK)
4191  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4192 
4193  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4194  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4195  "%" PRIu32 "", ssn, ssn->server.next_seq,
4196  ssn->client.last_ack);
4197  }
4198 
4199  } else if (tcph->th_flags & TH_SYN) {
4200  SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
4202  return -1;
4203 
4204  } else if (tcph->th_flags & TH_ACK) {
4205  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4206  if (!StreamTcpValidateTimestamp(ssn, p))
4207  return -1;
4208  }
4209 
4210  if (PKT_IS_TOSERVER(p)) {
4211  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4212  "%" PRIu32 ", ACK %" PRIu32 "",
4213  ssn, p->payload_len, seq, ack);
4214  int retransmission = 0;
4215 
4216  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4217  SCLogDebug("ssn %p: packet is retransmission", ssn);
4218  retransmission = 1;
4220  }
4221 
4222  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4223  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4225  return -1;
4226  }
4227 
4228  if (!retransmission) {
4229  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
4231  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
4232  "%" PRIu32 "",
4233  ssn, seq, ssn->client.next_win);
4234 
4235  } else {
4236  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4237  " != %" PRIu32 " from stream",
4238  ssn, seq, ssn->client.next_seq);
4240  return -1;
4241  }
4242 
4243  ssn->server.window = window << ssn->server.wscale;
4244  }
4245 
4246  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4247  StreamTcpHandleTimestamp(ssn, p);
4248  }
4249 
4250  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4251  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4252  }
4253 
4254  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4255 
4257 
4258  /* update next_win */
4259  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
4260 
4261  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4262 
4263  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4264  "%" PRIu32 "", ssn, ssn->client.next_seq,
4265  ssn->server.last_ack);
4266  } else { /* implied to client */
4267  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4268  "%" PRIu32 ", ACK %" PRIu32 "",
4269  ssn, p->payload_len, seq, ack);
4270  int retransmission = 0;
4271 
4272  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4273  SCLogDebug("ssn %p: packet is retransmission", ssn);
4274  retransmission = 1;
4276  }
4277 
4278  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4279  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4281  return -1;
4282  }
4283 
4284  if (!retransmission) {
4285  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4287  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4288  "%" PRIu32 "",
4289  ssn, seq, ssn->server.next_win);
4290  } else {
4291  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4292  " != %" PRIu32 " from stream",
4293  ssn, seq, ssn->server.next_seq);
4295  return -1;
4296  }
4297 
4298  ssn->client.window = window << ssn->client.wscale;
4299  }
4300 
4301  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4302  StreamTcpHandleTimestamp(ssn, p);
4303  }
4304 
4305  if (SEQ_EQ(ssn->server.next_seq, seq)) {
4306  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4307  }
4308 
4309  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4310 
4312 
4313  /* update next_win */
4314  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4315 
4316  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4317 
4318  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4319  "%" PRIu32 "", ssn, ssn->server.next_seq,
4320  ssn->client.last_ack);
4321  }
4322  } else {
4323  SCLogDebug("ssn %p: default case", ssn);
4324  }
4325 
4326  return 0;
4327 }
4328 
4329 /**
4330  * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
4331  * the connection goes to TCP_TIME_WAIT state. The state has been
4332  * reached as both end application has been closed.
4333  *
4334  * \param tv Thread Variable containing input/output queue, cpu affinity
4335  * \param p Packet which has to be handled in this TCP state.
4336  * \param stt Stream Thread module registered to handle the stream handling
4337  */
4338 
4339 static int StreamTcpPacketStateClosing(
4340  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4341 {
4342  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4343  const TCPHdr *tcph = PacketGetTCP(p);
4344  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4345  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4346  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4347 
4348  if (tcph->th_flags & TH_RST) {
4349  if (!StreamTcpValidateRst(ssn, p))
4350  return -1;
4351 
4352  StreamTcpCloseSsnWithReset(p, ssn);
4353 
4354  if (PKT_IS_TOSERVER(p)) {
4355  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4356  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4357 
4358  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4359 
4360  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4361  StreamTcpHandleTimestamp(ssn, p);
4362  }
4363 
4364  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4365  } else {
4366  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4367  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4368 
4369  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4370 
4371  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4372  StreamTcpHandleTimestamp(ssn, p);
4373  }
4374 
4375  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4376  }
4377 
4378  } else if (tcph->th_flags & TH_SYN) {
4379  SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
4381  return -1;
4382 
4383  } else if (tcph->th_flags & TH_ACK) {
4384  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4385  if (!StreamTcpValidateTimestamp(ssn, p))
4386  return -1;
4387  }
4388 
4389  if (PKT_IS_TOSERVER(p)) {
4390  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4391  "%" PRIu32 ", ACK %" PRIu32 "",
4392  ssn, p->payload_len, seq, ack);
4393  int retransmission = 0;
4394  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4395  SCLogDebug("ssn %p: packet is retransmission", ssn);
4396  retransmission = 1;
4398  }
4399 
4400  if (seq != ssn->client.next_seq) {
4401  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4402  " != %" PRIu32 " from stream",
4403  ssn, seq, ssn->client.next_seq);
4405  return -1;
4406  }
4407 
4408  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4409  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4411  return -1;
4412  }
4413 
4414  if (!retransmission) {
4415  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4416  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4417 
4418  ssn->client.window = window << ssn->client.wscale;
4419  }
4420 
4421  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4422  StreamTcpHandleTimestamp(ssn, p);
4423  }
4424  /* Update the next_seq, in case if we have missed the client
4425  packet and server has already received and acked it */
4426  if (SEQ_LT(ssn->server.next_seq, ack))
4427  ssn->server.next_seq = ack;
4428 
4429  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4430 
4431  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4432  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4433  "%" PRIu32 "", ssn, ssn->client.next_seq,
4434  ssn->server.last_ack);
4435  } else { /* implied to client */
4436  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4437  "%" PRIu32 ", ACK %" PRIu32 "",
4438  ssn, p->payload_len, seq, ack);
4439  int retransmission = 0;
4440  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4441  SCLogDebug("ssn %p: packet is retransmission", ssn);
4442  retransmission = 1;
4444  }
4445 
4446  if (seq != ssn->server.next_seq) {
4447  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4448  " != %" PRIu32 " from stream",
4449  ssn, seq, ssn->server.next_seq);
4451  return -1;
4452  }
4453 
4454  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4455  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4457  return -1;
4458  }
4459 
4460  if (!retransmission) {
4461  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4462  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4463 
4464  ssn->client.window = window << ssn->client.wscale;
4465  }
4466 
4467  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4468  StreamTcpHandleTimestamp(ssn, p);
4469  }
4470 
4471  /* Update the next_seq, in case if we have missed the client
4472  packet and server has already received and acked it */
4473  if (SEQ_LT(ssn->client.next_seq, ack))
4474  ssn->client.next_seq = ack;
4475 
4476  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4477 
4478  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4479  SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
4480  "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
4481  ssn->server.next_seq, ssn->client.last_ack);
4482  }
4483  } else {
4484  SCLogDebug("ssn %p: default case", ssn);
4485  }
4486 
4487  return 0;
4488 }
4489 
4490 /**
4491  * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
4492  * packet from server the connection goes to TCP_LAST_ACK state.
4493  * The state is possible only for server host.
4494  *
4495  * \param tv Thread Variable containing input/output queue, cpu affinity
4496  * \param p Packet which has to be handled in this TCP state.
4497  * \param stt Stream Thread module registered to handle the stream handling
4498  */
4499 
4500 static int StreamTcpPacketStateCloseWait(
4501  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4502 {
4503  SCEnter();
4504  const TCPHdr *tcph = PacketGetTCP(p);
4505  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4506  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4507  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4508 
4509  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4510 
4511  if (PKT_IS_TOCLIENT(p)) {
4512  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4513  "%" PRIu32 ", ACK %" PRIu32 "",
4514  ssn, p->payload_len, seq, ack);
4515  } else {
4516  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4517  "%" PRIu32 ", ACK %" PRIu32 "",
4518  ssn, p->payload_len, seq, ack);
4519  }
4520 
4521  if (tcph->th_flags & TH_RST) {
4522  if (!StreamTcpValidateRst(ssn, p))
4523  return -1;
4524 
4525  StreamTcpCloseSsnWithReset(p, ssn);
4526 
4527  if (PKT_IS_TOSERVER(p)) {
4528  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4529  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4530 
4531  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4532 
4533  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4534  StreamTcpHandleTimestamp(ssn, p);
4535  }
4536 
4537  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4538  } else {
4539  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4540  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4541 
4542  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4543 
4544  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4545  StreamTcpHandleTimestamp(ssn, p);
4546  }
4547 
4548  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4549  }
4550 
4551  } else if (tcph->th_flags & TH_FIN) {
4552  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4553  if (!StreamTcpValidateTimestamp(ssn, p))
4554  SCReturnInt(-1);
4555  }
4556 
4557  if (PKT_IS_TOSERVER(p)) {
4558  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4559  "%" PRIu32 ", ACK %" PRIu32 "",
4560  ssn, p->payload_len, seq, ack);
4561 
4562  int retransmission = 0;
4563  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4564  SCLogDebug("ssn %p: packet is retransmission", ssn);
4565  retransmission = 1;
4567  }
4568 
4569  if (!retransmission) {
4570  if (SEQ_LT(seq, ssn->client.next_seq) ||
4571  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4572  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4573  " != %" PRIu32 " from stream",
4574  ssn, seq, ssn->client.next_seq);
4576  SCReturnInt(-1);
4577  }
4578  }
4579 
4580  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4581  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4583  SCReturnInt(-1);
4584  }
4585 
4586  /* don't update to LAST_ACK here as we want a toclient FIN for that */
4587 
4588  if (!retransmission)
4589  ssn->server.window = window << ssn->server.wscale;
4590 
4591  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4592  StreamTcpHandleTimestamp(ssn, p);
4593  }
4594 
4595  /* Update the next_seq, in case if we have missed the client
4596  packet and server has already received and acked it */
4597  if (SEQ_LT(ssn->server.next_seq, ack))
4598  ssn->server.next_seq = ack;
4599 
4600  if (tcph->th_flags & TH_ACK)
4601  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4602 
4603  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4604  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4605  "%" PRIu32 "", ssn, ssn->client.next_seq,
4606  ssn->server.last_ack);
4607  } else {
4608  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4609  "%" PRIu32 ", ACK %" PRIu32 "",
4610  ssn, p->payload_len, seq, ack);
4611 
4612  int retransmission = 0;
4613  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4614  SCLogDebug("ssn %p: packet is retransmission", ssn);
4615  retransmission = 1;
4617  }
4618 
4619  if (!retransmission) {
4620  if (SEQ_LT(seq, ssn->server.next_seq) ||
4621  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4622  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4623  " != %" PRIu32 " from stream",
4624  ssn, seq, ssn->server.next_seq);
4626  SCReturnInt(-1);
4627  }
4628  }
4629 
4630  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4631  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4633  SCReturnInt(-1);
4634  }
4635 
4636  if (!retransmission) {
4637  StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
4638  SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
4639 
4640  ssn->client.window = window << ssn->client.wscale;
4641  }
4642 
4643  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4644  StreamTcpHandleTimestamp(ssn, p);
4645  }
4646 
4647  /* Update the next_seq, in case if we have missed the client
4648  packet and server has already received and acked it */
4649  if (SEQ_LT(ssn->client.next_seq, ack))
4650  ssn->client.next_seq = ack;
4651 
4652  if (tcph->th_flags & TH_ACK)
4653  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4654 
4655  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4656  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4657  "%" PRIu32 "", ssn, ssn->server.next_seq,
4658  ssn->client.last_ack);
4659  }
4660 
4661  } else if (tcph->th_flags & TH_SYN) {
4662  SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
4664  SCReturnInt(-1);
4665 
4666  } else if (tcph->th_flags & TH_ACK) {
4667  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4668  if (!StreamTcpValidateTimestamp(ssn, p))
4669  SCReturnInt(-1);
4670  }
4671 
4672  if (PKT_IS_TOSERVER(p)) {
4673  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4674  "%" PRIu32 ", ACK %" PRIu32 "",
4675  ssn, p->payload_len, seq, ack);
4676 
4677  int retransmission = 0;
4678  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4679  SCLogDebug("ssn %p: packet is retransmission", ssn);
4680  retransmission = 1;
4682  }
4683 
4684  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->client.last_ack))) {
4685  SCLogDebug("ssn %p: -> retransmission", ssn);
4687  SCReturnInt(-1);
4688 
4689  } else if (SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4690  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4691  " != %" PRIu32 " from stream",
4692  ssn, seq, ssn->client.next_seq);
4694  SCReturnInt(-1);
4695  }
4696 
4697  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4698  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4700  SCReturnInt(-1);
4701  }
4702 
4703  if (!retransmission) {
4704  ssn->server.window = window << ssn->server.wscale;
4705  }
4706 
4707  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4708  StreamTcpHandleTimestamp(ssn, p);
4709  }
4710 
4711  /* Update the next_seq, in case if we have missed the client
4712  packet and server has already received and acked it */
4713  if (SEQ_LT(ssn->server.next_seq, ack))
4714  ssn->server.next_seq = ack;
4715 
4716  if (SEQ_EQ(seq, ssn->client.next_seq))
4717  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4718 
4719  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4720 
4721  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4722  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4723  "%" PRIu32 "", ssn, ssn->client.next_seq,
4724  ssn->server.last_ack);
4725  } else {
4726  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4727  "%" PRIu32 ", ACK %" PRIu32 "",
4728  ssn, p->payload_len, seq, ack);
4729  int retransmission = 0;
4730  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4731  SCLogDebug("ssn %p: packet is retransmission", ssn);
4732  retransmission = 1;
4734  }
4735 
4736  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->server.last_ack))) {
4737  SCLogDebug("ssn %p: -> retransmission", ssn);
4739  SCReturnInt(-1);
4740 
4741  } else if (SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4742  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4743  " != %" PRIu32 " from stream",
4744  ssn, seq, ssn->server.next_seq);
4746  SCReturnInt(-1);
4747  }
4748 
4749  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4750  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4752  SCReturnInt(-1);
4753  }
4754 
4755  if (!retransmission) {
4756  ssn->client.window = window << ssn->client.wscale;
4757  }
4758 
4759  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4760  StreamTcpHandleTimestamp(ssn, p);
4761  }
4762 
4763  /* Update the next_seq, in case if we have missed the client
4764  packet and server has already received and acked it */
4765  if (SEQ_LT(ssn->client.next_seq, ack))
4766  ssn->client.next_seq = ack;
4767 
4768  if (SEQ_EQ(seq, ssn->server.next_seq))
4769  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4770 
4771  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4772 
4773  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4774  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4775  "%" PRIu32 "", ssn, ssn->server.next_seq,
4776  ssn->client.last_ack);
4777  }
4778 
4779  } else {
4780  SCLogDebug("ssn %p: default case", ssn);
4781  }
4782  SCReturnInt(0);
4783 }
4784 
4785 /**
4786  * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
4787  * the connection goes to TCP_CLOSED state and stream memory is
4788  * returned back to pool. The state is possible only for server host.
4789  *
4790  * \param tv Thread Variable containing input/output queue, cpu affinity
4791  * \param p Packet which has to be handled in this TCP state.
4792  * \param stt Stream Thread module registered to handle the stream handling
4793  */
4794 
4795 static int StreamTcpPacketStateLastAck(
4796  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4797 {
4798  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4799  const TCPHdr *tcph = PacketGetTCP(p);
4800  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4801  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4802  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4803 
4804  if (tcph->th_flags & TH_RST) {
4805  if (!StreamTcpValidateRst(ssn, p))
4806  return -1;
4807 
4808  StreamTcpCloseSsnWithReset(p, ssn);
4809 
4810  if (PKT_IS_TOSERVER(p)) {
4811  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4812  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4813 
4814  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4815 
4816  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4817  StreamTcpHandleTimestamp(ssn, p);
4818  }
4819 
4820  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4821  } else {
4822  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4823  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4824 
4825  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4826 
4827  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4828  StreamTcpHandleTimestamp(ssn, p);
4829  }
4830 
4831  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4832  }
4833 
4834  } else if (tcph->th_flags & TH_FIN) {
4835  /** \todo */
4836  SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
4837 
4838  } else if (tcph->th_flags & TH_SYN) {
4839  SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
4841  return -1;
4842 
4843  } else if (tcph->th_flags & TH_ACK) {
4844  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4845  if (!StreamTcpValidateTimestamp(ssn, p))
4846  return -1;
4847  }
4848 
4849  if (PKT_IS_TOSERVER(p)) {
4850  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4851  "%" PRIu32 ", ACK %" PRIu32 "",
4852  ssn, p->payload_len, seq, ack);
4853 
4854  int retransmission = 0;
4855  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4856  SCLogDebug("ssn %p: packet is retransmission", ssn);
4857  retransmission = 1;
4859  }
4860 
4861  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4862  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4864  SCReturnInt(-1);
4865  }
4866 
4867  if (!retransmission) {
4868  if (SEQ_LT(seq, ssn->client.next_seq)) {
4869  SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
4870  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
4871  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4872  " != %" PRIu32 " from stream",
4873  ssn, seq, ssn->client.next_seq);
4875  return -1;
4876  } else {
4877  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4878  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4879  }
4880  ssn->server.window = window << ssn->server.wscale;
4881  }
4882 
4883  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4884  StreamTcpHandleTimestamp(ssn, p);
4885  }
4886 
4887  /* Update the next_seq, in case if we have missed the client
4888  packet and server has already received and acked it */
4889  if (SEQ_LT(ssn->server.next_seq, ack))
4890  ssn->server.next_seq = ack;
4891 
4892  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4893 
4894  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4895  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4896  "%" PRIu32 "", ssn, ssn->client.next_seq,
4897  ssn->server.last_ack);
4898  }
4899  } else {
4900  SCLogDebug("ssn %p: default case", ssn);
4901  }
4902 
4903  return 0;
4904 }
4905 
4906 /**
4907  * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
4908  * the connection goes to TCP_CLOSED state and stream memory is
4909  * returned back to pool.
4910  *
4911  * \param tv Thread Variable containing input/output queue, cpu affinity
4912  * \param p Packet which has to be handled in this TCP state.
4913  * \param stt Stream Thread module registered to handle the stream handling
4914  */
4915 
4916 static int StreamTcpPacketStateTimeWait(
4917  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4918 {
4919  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4920  const TCPHdr *tcph = PacketGetTCP(p);
4921  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4922  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4923  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4924 
4925  if (tcph->th_flags & TH_RST) {
4926  if (!StreamTcpValidateRst(ssn, p))
4927  return -1;
4928 
4929  StreamTcpCloseSsnWithReset(p, ssn);
4930 
4931  if (PKT_IS_TOSERVER(p)) {
4932  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4933  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4934 
4935  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4936 
4937  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4938  StreamTcpHandleTimestamp(ssn, p);
4939  }
4940 
4941  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4942  } else {
4943  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4944  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4945 
4946  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4947 
4948  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4949  StreamTcpHandleTimestamp(ssn, p);
4950  }
4951 
4952  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4953  }
4954 
4955  } else if (tcph->th_flags & TH_FIN) {
4956  /** \todo */
4957 
4958  } else if (tcph->th_flags & TH_SYN) {
4959  SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
4961  return -1;
4962 
4963  } else if (tcph->th_flags & TH_ACK) {
4964  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4965  if (!StreamTcpValidateTimestamp(ssn, p))
4966  return -1;
4967  }
4968 
4969  if (PKT_IS_TOSERVER(p)) {
4970  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4971  "%" PRIu32 ", ACK %" PRIu32 "",
4972  ssn, p->payload_len, seq, ack);
4973  int retransmission = 0;
4974  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4975  SCLogDebug("ssn %p: packet is retransmission", ssn);
4976  retransmission = 1;
4978 
4979  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
4980  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4981  " != %" PRIu32 " from stream",
4982  ssn, seq, ssn->client.next_seq);
4984  return -1;
4985  }
4986 
4987  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4988  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4990  SCReturnInt(-1);
4991  }
4992 
4993  if (!retransmission) {
4994  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4995  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4996 
4997  ssn->server.window = window << ssn->server.wscale;
4998  }
4999 
5000  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5001  StreamTcpHandleTimestamp(ssn, p);
5002  }
5003 
5004  /* Update the next_seq, in case if we have missed the client
5005  packet and server has already received and acked it */
5006  if (SEQ_LT(ssn->server.next_seq, ack))
5007  ssn->server.next_seq = ack;
5008 
5009  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
5010 
5011  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5012  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5013  "%" PRIu32 "", ssn, ssn->client.next_seq,
5014  ssn->server.last_ack);
5015  } else {
5016  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
5017  "%" PRIu32 ", ACK %" PRIu32 "",
5018  ssn, p->payload_len, seq, ack);
5019  int retransmission = 0;
5020  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
5021  SCLogDebug("ssn %p: packet is retransmission", ssn);
5022  retransmission = 1;
5024  } else if (seq != ssn->server.next_seq - 1 && seq != ssn->server.next_seq) {
5025  if (p->payload_len > 0 && seq == ssn->server.last_ack) {
5026  SCLogDebug("ssn %p: -> retransmission", ssn);
5027  SCReturnInt(0);
5028  } else {
5029  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5030  " != %" PRIu32 " from stream",
5031  ssn, seq, ssn->server.next_seq);
5033  return -1;
5034  }
5035  }
5036 
5037  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
5038  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5040  SCReturnInt(-1);
5041  }
5042 
5043  if (!retransmission) {
5044  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5045  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5046 
5047  ssn->client.window = window << ssn->client.wscale;
5048  }
5049 
5050  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5051  StreamTcpHandleTimestamp(ssn, p);
5052  }
5053 
5054  /* Update the next_seq, in case if we have missed the client
5055  packet and server has already received and acked it */
5056  if (SEQ_LT(ssn->client.next_seq, ack))
5057  ssn->client.next_seq = ack;
5058 
5059  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
5060 
5061  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5062  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5063  "%" PRIu32 "", ssn, ssn->server.next_seq,
5064  ssn->client.last_ack);
5065  }
5066 
5067  } else {
5068  SCLogDebug("ssn %p: default case", ssn);
5069  }
5070 
5071  return 0;
5072 }
5073 
5074 static int StreamTcpPacketStateClosed(
5075  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
5076 {
5077  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5078 
5079  const TCPHdr *tcph = PacketGetTCP(p);
5080  if (tcph->th_flags & TH_RST) {
5081  SCLogDebug("RST on closed state");
5082  return 0;
5083  }
5084 
5085  TcpStream *stream = NULL, *ostream = NULL;
5086  if (PKT_IS_TOSERVER(p)) {
5087  stream = &ssn->client;
5088  ostream = &ssn->server;
5089  } else {
5090  stream = &ssn->server;
5091  ostream = &ssn->client;
5092  }
5093 
5094  SCLogDebug("stream %s ostream %s",
5095  stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
5096  ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
5097 
5098  /* if we've seen a RST on our direction, but not on the other
5099  * see if we perhaps need to continue processing anyway. */
5100  if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
5101  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5102  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->pstate) < 0)
5103  return -1;
5104  /* if state is still "closed", it wasn't updated by our dispatch. */
5105  if (ssn->state == TCP_CLOSED)
5106  ssn->state = ssn->pstate;
5107  }
5108  }
5109  return 0;
5110 }
5111 
5112 static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
5113 {
5114  if (p->flags & PKT_PSEUDO_STREAM_END) {
5115  return;
5116  }
5117  const TCPHdr *tcph = PacketGetTCP(p);
5118  /* more RSTs are not unusual */
5119  if ((tcph->th_flags & (TH_RST)) != 0) {
5120  return;
5121  }
5122 
5123  TcpStream *ostream = NULL;
5124  if (PKT_IS_TOSERVER(p)) {
5125  ostream = &ssn->server;
5126  } else {
5127  ostream = &ssn->client;
5128  }
5129 
5130  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5131  SCLogDebug("regular packet %"PRIu64" from same sender as "
5132  "the previous RST. Looks like it injected!", p->pcap_cnt);
5136  return;
5137  }
5138 }
5139 
5140 /**
5141  * \retval 1 packet is a keep alive pkt
5142  * \retval 0 packet is not a keep alive pkt
5143  */
5144 static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
5145 {
5146  if (p->flags & PKT_PSEUDO_STREAM_END)
5147  return 0;
5148 
5149  /* rfc 1122:
5150  An implementation SHOULD send a keep-alive segment with no
5151  data; however, it MAY be configurable to send a keep-alive
5152  segment containing one garbage octet, for compatibility with
5153  erroneous TCP implementations.
5154  */
5155  if (p->payload_len > 1)
5156  return 0;
5157 
5158  const TCPHdr *tcph = PacketGetTCP(p);
5159  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) {
5160  return 0;
5161  }
5162 
5163  TcpStream *stream = NULL, *ostream = NULL;
5164  if (PKT_IS_TOSERVER(p)) {
5165  stream = &ssn->client;
5166  ostream = &ssn->server;
5167  } else {
5168  stream = &ssn->server;
5169  ostream = &ssn->client;
5170  }
5171 
5172  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
5173  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
5174  if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
5175  SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
5178  return 1;
5179  }
5180  SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
5181  return 0;
5182 }
5183 
5184 /**
5185  * \retval 1 packet is a keep alive ACK pkt
5186  * \retval 0 packet is not a keep alive ACK pkt
5187  */
5188 static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
5189 {
5190  TcpStream *stream = NULL, *ostream = NULL;
5191  uint32_t seq;
5192  uint32_t ack;
5193  uint32_t pkt_win;
5194 
5195  if (p->flags & PKT_PSEUDO_STREAM_END)
5196  return 0;
5197  /* should get a normal ACK to a Keep Alive */
5198  if (p->payload_len > 0)
5199  return 0;
5200 
5201  const TCPHdr *tcph = PacketGetTCP(p);
5202  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5203  return 0;
5204 
5205  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5206  return 0;
5207 
5208  if (PKT_IS_TOSERVER(p)) {
5209  stream = &ssn->client;
5210  ostream = &ssn->server;
5211  } else {
5212  stream = &ssn->server;
5213  ostream = &ssn->client;
5214  }
5215 
5216  seq = TCP_GET_RAW_SEQ(tcph);
5217  ack = TCP_GET_RAW_ACK(tcph);
5218 
5219  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5220  if (pkt_win != ostream->window)
5221  return 0;
5222 
5223  if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
5224  SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
5225  ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
5227  return 1;
5228  }
5229  SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
5230  ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
5231  return 0;
5232 }
5233 
5234 static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
5235 {
5236  TcpStream *stream = NULL;
5237 
5238  if (p->flags & PKT_PSEUDO_STREAM_END)
5239  return;
5240 
5241  if (PKT_IS_TOSERVER(p)) {
5242  stream = &ssn->client;
5243  } else {
5244  stream = &ssn->server;
5245  }
5246 
5247  if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
5249  SCLogDebug("FLAG_KEEPALIVE cleared");
5250  }
5251 }
5252 
5253 /**
5254  * \retval 1 packet is a window update pkt
5255  * \retval 0 packet is not a window update pkt
5256  */
5257 static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
5258 {
5259  TcpStream *stream = NULL, *ostream = NULL;
5260  uint32_t seq;
5261  uint32_t ack;
5262  uint32_t pkt_win;
5263 
5264  if (p->flags & PKT_PSEUDO_STREAM_END)
5265  return 0;
5266 
5267  if (ssn->state < TCP_ESTABLISHED)
5268  return 0;
5269 
5270  if (p->payload_len > 0)
5271  return 0;
5272 
5273  const TCPHdr *tcph = PacketGetTCP(p);
5274  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5275  return 0;
5276 
5277  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5278  return 0;
5279 
5280  if (PKT_IS_TOSERVER(p)) {
5281  stream = &ssn->client;
5282  ostream = &ssn->server;
5283  } else {
5284  stream = &ssn->server;
5285  ostream = &ssn->client;
5286  }
5287 
5288  seq = TCP_GET_RAW_SEQ(tcph);
5289  ack = TCP_GET_RAW_ACK(tcph);
5290 
5291  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5292  if (pkt_win == ostream->window)
5293  return 0;
5294 
5295  if (ack == ostream->last_ack && seq == stream->next_seq) {
5296  SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
5298  return 1;
5299  }
5300  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5301  return 0;
5302 }
5303 
5304 /**
5305  * Try to detect whether a packet is a valid FIN 4whs final ack.
5306  *
5307  */
5308 static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
5309 {
5310  TcpStream *stream = NULL, *ostream = NULL;
5311  uint32_t seq;
5312  uint32_t ack;
5313 
5314  if (p->flags & PKT_PSEUDO_STREAM_END)
5315  return 0;
5316  if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
5317  return 0;
5318  const TCPHdr *tcph = PacketGetTCP(p);
5319  if (tcph->th_flags != TH_ACK)
5320  return 0;
5321  if (p->payload_len != 0)
5322  return 0;
5323 
5324  if (PKT_IS_TOSERVER(p)) {
5325  stream = &ssn->client;
5326  ostream = &ssn->server;
5327  } else {
5328  stream = &ssn->server;
5329  ostream = &ssn->client;
5330  }
5331 
5332  seq = TCP_GET_RAW_SEQ(tcph);
5333  ack = TCP_GET_RAW_ACK(tcph);
5334 
5335  SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
5336  p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
5337 
5338  if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
5339  return 1;
5340  }
5341  return 0;
5342 }
5343 
5344 /**
5345  * Try to detect packets doing bad window updates
5346  *
5347  * See bug 1238.
5348  *
5349  * Find packets that are unexpected, and shrink the window to the point
5350  * where the packets we do expect are rejected for being out of window.
5351  *
5352  * The logic we use here is:
5353  * - packet seq > next_seq
5354  * - packet ack > next_seq (packet acks unseen data)
5355  * - packet shrinks window more than it's own data size
5356  * - packet shrinks window more than the diff between it's ack and the
5357  * last_ack value
5358  *
5359  * Packets coming in after packet loss can look quite a bit like this.
5360  */
5361 static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
5362 {
5363  TcpStream *stream = NULL, *ostream = NULL;
5364  uint32_t seq;
5365  uint32_t ack;
5366  uint32_t pkt_win;
5367 
5368  if (p->flags & PKT_PSEUDO_STREAM_END)
5369  return 0;
5370 
5371  if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
5372  return 0;
5373 
5374  const TCPHdr *tcph = PacketGetTCP(p);
5375  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5376  return 0;
5377 
5378  if (PKT_IS_TOSERVER(p)) {
5379  stream = &ssn->client;
5380  ostream = &ssn->server;
5381  } else {
5382  stream = &ssn->server;
5383  ostream = &ssn->client;
5384  }
5385 
5386  seq = TCP_GET_RAW_SEQ(tcph);
5387  ack = TCP_GET_RAW_ACK(tcph);
5388  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5389 
5390  if (pkt_win < ostream->window) {
5391  uint32_t diff = ostream->window - pkt_win;
5392  if (diff > p->payload_len &&
5393  SEQ_GT(ack, ostream->next_seq) &&
5394  SEQ_GT(seq, stream->next_seq))
5395  {
5396  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
5397  p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
5398  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
5399  p->pcap_cnt, pkt_win, ostream->window);
5400  SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
5401  p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
5402  ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
5403 
5404  /* get the expected window shrinking from looking at ack vs last_ack.
5405  * Observed a lot of just a little overrunning that value. So added some
5406  * margin that is still ok. To make sure this isn't a loophole to still
5407  * close the window, this is limited to windows above 1024. Both values
5408  * are rather arbitrary. */
5409  uint32_t adiff = ack - ostream->last_ack;
5410  if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
5411  ((pkt_win <= 1024) && (diff > adiff)))
5412  {
5413  SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
5414  "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
5415  SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
5417  return 1;
5418  }
5419  }
5420 
5421  }
5422  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5423  return 0;
5424 }
5425 
5426 /** \internal
5427  * \brief call packet handling function for 'state'
5428  * \param state current TCP state
5429  */
5430 static inline int StreamTcpStateDispatch(
5431  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state)
5432 {
5433  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5434 
5435  SCLogDebug("ssn: %p", ssn);
5436  switch (state) {
5437  case TCP_SYN_SENT:
5438  SCLogDebug("packet received on TCP_SYN_SENT state");
5439  if (StreamTcpPacketStateSynSent(tv, p, stt, ssn)) {
5440  return -1;
5441  }
5442  break;
5443  case TCP_SYN_RECV:
5444  SCLogDebug("packet received on TCP_SYN_RECV state");
5445  if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn)) {
5446  return -1;
5447  }
5448  break;
5449  case TCP_ESTABLISHED:
5450  SCLogDebug("packet received on TCP_ESTABLISHED state");
5451  if (StreamTcpPacketStateEstablished(tv, p, stt, ssn)) {
5452  return -1;
5453  }
5454  break;
5455  case TCP_FIN_WAIT1:
5456  SCLogDebug("packet received on TCP_FIN_WAIT1 state");
5457  if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn)) {
5458  return -1;
5459  }
5460  break;
5461  case TCP_FIN_WAIT2:
5462  SCLogDebug("packet received on TCP_FIN_WAIT2 state");
5463  if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn)) {
5464  return -1;
5465  }
5466  break;
5467  case TCP_CLOSING:
5468  SCLogDebug("packet received on TCP_CLOSING state");
5469  if (StreamTcpPacketStateClosing(tv, p, stt, ssn)) {
5470  return -1;
5471  }
5472  break;
5473  case TCP_CLOSE_WAIT:
5474  SCLogDebug("packet received on TCP_CLOSE_WAIT state");
5475  if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn)) {
5476  return -1;
5477  }
5478  break;
5479  case TCP_LAST_ACK:
5480  SCLogDebug("packet received on TCP_LAST_ACK state");
5481  if (StreamTcpPacketStateLastAck(tv, p, stt, ssn)) {
5482  return -1;
5483  }
5484  break;
5485  case TCP_TIME_WAIT:
5486  SCLogDebug("packet received on TCP_TIME_WAIT state");
5487  if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn)) {
5488  return -1;
5489  }
5490  break;
5491  case TCP_CLOSED:
5492  /* TCP session memory is not returned to pool until timeout. */
5493  SCLogDebug("packet received on closed state");
5494 
5495  if (StreamTcpPacketStateClosed(tv, p, stt, ssn)) {
5496  return -1;
5497  }
5498 
5499  break;
5500  default:
5501  SCLogDebug("packet received on default state");
5502  break;
5503  }
5504  return 0;
5505 }
5506 
5507 static inline void HandleThreadId(ThreadVars *tv, Packet *p, StreamTcpThread *stt)
5508 {
5509  const int idx = (!(PKT_IS_TOSERVER(p)));
5510 
5511  /* assign the thread id to the flow */
5512  if (unlikely(p->flow->thread_id[idx] == 0)) {
5513  p->flow->thread_id[idx] = (FlowThreadId)tv->id;
5514  } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id[idx])) {
5515  SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id[idx], tv->id);
5516  if (p->pkt_src == PKT_SRC_WIRE) {
5518  if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
5519  p->flow->flags |= FLOW_WRONG_THREAD;
5521  }
5522  }
5523  }
5524 }
5525 
5526 /* flow is and stays locked */
5528  PacketQueueNoLock *pq)
5529 {
5530  SCEnter();
5531 
5533 
5534  SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
5535 
5536  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
5537  const TCPHdr *tcph = PacketGetTCP(p);
5538 
5539  /* track TCP flags */
5540  if (ssn != NULL) {
5541  ssn->tcp_packet_flags |= tcph->th_flags;
5542  if (PKT_IS_TOSERVER(p))
5543  ssn->client.tcp_flags |= tcph->th_flags;
5544  else if (PKT_IS_TOCLIENT(p))
5545  ssn->server.tcp_flags |= tcph->th_flags;
5546 
5547  /* check if we need to unset the ASYNC flag */
5548  if (ssn->flags & STREAMTCP_FLAG_ASYNC &&
5549  ssn->client.tcp_flags != 0 &&
5550  ssn->server.tcp_flags != 0)
5551  {
5552  SCLogDebug("ssn %p: removing ASYNC flag as we have packets on both sides", ssn);
5553  ssn->flags &= ~STREAMTCP_FLAG_ASYNC;
5554  }
5555  }
5556 
5557  /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */
5558  if (!(tcph->th_flags & TH_ACK) && TCP_GET_RAW_ACK(tcph) != 0) {
5560  }
5561 
5562  if ((tcph->th_flags & TH_URG) && StreamTcpInlineDropUrg()) {
5564  SCLogDebug("dropping urgent packet");
5565  SCReturnInt(0);
5566  }
5567 
5568  /* If we are on IPS mode, and got a drop action triggered from
5569  * the IP only module, or from a reassembled msg and/or from an
5570  * applayer detection, then drop the rest of the packets of the
5571  * same stream and avoid inspecting it any further */
5572  if (StreamTcpCheckFlowDrops(p) == 1) {
5574  SCLogDebug("flow triggered a drop rule");
5576  /* return the segments to the pool */
5578  SCReturnInt(0);
5579  }
5580 
5581  if (ssn == NULL || ssn->state == TCP_NONE) {
5582  if (StreamTcpPacketStateNone(tv, p, stt, ssn) == -1) {
5583  goto error;
5584  }
5585 
5586  if (ssn != NULL)
5587  SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto);
5588  } else {
5589  /* special case for PKT_PSEUDO_STREAM_END packets:
5590  * bypass the state handling and various packet checks,
5591  * we care about reassembly here. */
5592  if (p->flags & PKT_PSEUDO_STREAM_END) {
5593  if (PKT_IS_TOCLIENT(p)) {
5594  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5595  } else {
5596  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5597  }
5598  /* straight to 'skip' as we already handled reassembly */
5599  goto skip;
5600  }
5601 
5602  if (p->flow->flags & FLOW_WRONG_THREAD) {
5603  /* Stream and/or session in known bad condition. Block events
5604  * from being set. */
5606  }
5607 
5608  if (StreamTcpPacketIsKeepAlive(ssn, p) == 1) {
5609  goto skip;
5610  }
5611  if (StreamTcpPacketIsKeepAliveACK(ssn, p) == 1) {
5612  StreamTcpClearKeepAliveFlag(ssn, p);
5613  goto skip;
5614  }
5615  StreamTcpClearKeepAliveFlag(ssn, p);
5616 
5617  const bool is_zwp_ack = StreamTcpPacketIsZeroWindowProbeAck(ssn, p);
5618  if (PKT_IS_TOCLIENT(p)) {
5619  ssn->flags &= ~STREAMTCP_FLAG_ZWP_TS;
5620  } else {
5621  ssn->flags &= ~STREAMTCP_FLAG_ZWP_TC;
5622  }
5623  if (is_zwp_ack) {
5625  goto skip;
5626  }
5627 
5628  if (StreamTcpPacketIsDupAck(ssn, p)) {
5630  // TODO see if we can skip work on these
5631  }
5632 
5633  /* if packet is not a valid window update, check if it is perhaps
5634  * a bad window update that we should ignore (and alert on) */
5635  if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) {
5636  if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0) {
5637  if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
5638  goto skip;
5639  if (StreamTcpPacketIsOutdatedAck(ssn, p))
5640  goto skip;
5641  }
5642  }
5643 
5644  int ret = StreamTcpPacketIsSpuriousRetransmission(ssn, p);
5645  if (ret > 0) {
5647  /* skip packet if fully before base_seq */
5648  if (ret == 2)
5649  goto skip;
5650  }
5651 
5652  /* handle the per 'state' logic */
5653  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->state) < 0)
5654  goto error;
5655 
5656  skip:
5657  StreamTcpPacketCheckPostRst(ssn, p);
5658 
5659  if (ssn->state >= TCP_ESTABLISHED) {
5660  p->flags |= PKT_STREAM_EST;
5661  }
5662  }
5663 
5664  if (ssn != NULL) {
5665  /* recalc the csum on the packet if it was modified */
5666  if (p->flags & PKT_STREAM_MODIFIED) {
5668  }
5669  /* check for conditions that may make us not want to log this packet */
5670 
5671  /* streams that hit depth */
5674  {
5675  /* we can call bypass callback, if enabled */
5676  if (StreamTcpBypassEnabled()) {
5678  }
5679  }
5680 
5683  {
5685  }
5686 
5687  /* encrypted packets */
5690  {
5692  }
5693 
5694  if (ssn->flags & STREAMTCP_FLAG_BYPASS) {
5695  /* we can call bypass callback, if enabled */
5696  if (StreamTcpBypassEnabled()) {
5698  }
5699 
5700  /* if stream is dead and we have no detect engine at all, bypass. */
5701  } else if (g_detect_disabled &&
5705  {
5706  SCLogDebug("bypass as stream is dead and we have no rules");
5708  }
5709  }
5710 
5711  SCReturnInt(0);
5712 
5713 error:
5714  /* recalc the csum on the packet if it was modified */
5715  if (p->flags & PKT_STREAM_MODIFIED) {
5717  }
5718 
5719  if (StreamTcpInlineDropInvalid()) {
5720  /* disable payload inspection as we're dropping this packet
5721  * anyway. Doesn't disable all detection, so we can still
5722  * match on the stream event that was set. */
5723  DecodeSetNoPayloadInspectionFlag(p);
5725  }
5726  SCReturnInt(-1);
5727 }
5728 
5729 /**
5730  * \brief Function to validate the checksum of the received packet. If the
5731  * checksum is invalid, packet will be dropped, as the end system will
5732  * also drop the packet.
5733  *
5734  * \param p Packet of which checksum has to be validated
5735  * \retval 1 if the checksum is valid, otherwise 0
5736  */
5737 static inline int StreamTcpValidateChecksum(Packet *p)
5738 {
5739  int ret = 1;
5740 
5741  if (p->flags & PKT_IGNORE_CHECKSUM)
5742  return ret;
5743 
5744  if (!p->l4.csum_set) {
5745  const TCPHdr *tcph = PacketGetTCP(p);
5746  if (PacketIsIPv4(p)) {
5747  const IPV4Hdr *ip4h = PacketGetIPv4(p);
5748  p->l4.csum = TCPChecksum(ip4h->s_ip_addrs, (uint16_t *)tcph,
5749  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5750  p->l4.csum_set = true;
5751  } else if (PacketIsIPv6(p)) {
5752  const IPV6Hdr *ip6h = PacketGetIPv6(p);
5753  p->l4.csum = TCPV6Checksum(ip6h->s_ip6_addrs, (uint16_t *)tcph,
5754  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5755  p->l4.csum_set = true;
5756  }
5757  }
5758 
5759  if (p->l4.csum != 0) {
5760  ret = 0;
5761  if (p->livedev) {
5762  (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1);
5763  } else if (p->pcap_cnt) {
5765  }
5766  }
5767 
5768  return ret;
5769 }
5770 
5771 /** \internal
5772  * \brief check if a packet is a valid stream started
5773  * \retval bool true/false */
5774 static int TcpSessionPacketIsStreamStarter(const Packet *p)
5775 {
5776  const TCPHdr *tcph = PacketGetTCP(p);
5777  if (tcph->th_flags & (TH_RST | TH_FIN)) {
5778  return 0;
5779  }
5780 
5781  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5782  SCLogDebug("packet %" PRIu64 " is a stream starter: %02x", p->pcap_cnt, tcph->th_flags);
5783  return 1;
5784  }
5785 
5787  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5788  SCLogDebug("packet %" PRIu64 " is a midstream stream starter: %02x", p->pcap_cnt,
5789  tcph->th_flags);
5790  return 1;
5791  }
5792  }
5793  return 0;
5794 }
5795 
5796 /** \internal
5797  * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused
5798  * \retval bool true yes reuse, false no keep tracking old ssn */
5799 static bool TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn)
5800 {
5801  const TCPHdr *tcph = PacketGetTCP(p);
5802  if (FlowGetPacketDirection(f, p) == TOSERVER) {
5803  if (ssn == NULL) {
5804  /* most likely a flow that was picked up after the 3whs, or a flow that
5805  * does not have a session due to memcap issues. */
5806  SCLogDebug("steam starter packet %" PRIu64 ", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5807  return true;
5808  }
5810  SCLogDebug("steam starter packet %" PRIu64
5811  ", ssn %p. STREAMTCP_FLAG_TFO_DATA_IGNORED set. Reuse.",
5812  p->pcap_cnt, ssn);
5813  return true;
5814  }
5815  if (SEQ_EQ(ssn->client.isn, TCP_GET_RAW_SEQ(tcph))) {
5816  SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5817  return false;
5818  }
5819  if (ssn->state >= TCP_LAST_ACK) {
5820  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5821  return true;
5822  } else if (ssn->state == TCP_NONE) {
5823  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5824  return true;
5825  } else { // < TCP_LAST_ACK
5826  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5827  return false;
5828  }
5829 
5830  } else {
5831  if (ssn == NULL) {
5832  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5833  return true;
5834  }
5835  if (ssn->state >= TCP_LAST_ACK) {
5836  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5837  return true;
5838  } else if (ssn->state == TCP_NONE) {
5839  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5840  return true;
5841  } else { // < TCP_LAST_ACK
5842  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5843  return false;
5844  }
5845  }
5846 
5847  SCLogDebug("default: how did we get here?");
5848  return false;
5849 }
5850 
5851 /** \internal
5852  * \brief check if ssn is done enough for reuse by syn/ack
5853  * \note should only be called if midstream is enabled
5854  */
5855 static bool TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn)
5856 {
5857  const TCPHdr *tcph = PacketGetTCP(p);
5858  if (FlowGetPacketDirection(f, p) == TOCLIENT) {
5859  if (ssn == NULL) {
5860  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
5861  return false;
5862  }
5863  if (SEQ_EQ(ssn->server.isn, TCP_GET_RAW_SEQ(tcph))) {
5864  SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5865  return false;
5866  }
5867  if (ssn->state >= TCP_LAST_ACK) {
5868  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5869  return true;
5870  } else if (ssn->state == TCP_NONE) {
5871  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5872  return true;
5873  } else { // < TCP_LAST_ACK
5874  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5875  return false;
5876  }
5877 
5878  } else {
5879  if (ssn == NULL) {
5880  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5881  return true;
5882  }
5883  if (ssn->state >= TCP_LAST_ACK) {
5884  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5885  return true;
5886  } else if (ssn->state == TCP_NONE) {
5887  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5888  return true;
5889  } else { // < TCP_LAST_ACK
5890  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5891  return false;
5892  }
5893  }
5894 
5895  SCLogDebug("default: how did we get here?");
5896  return false;
5897 }
5898 
5899 /** \brief Check if SSN is done enough for reuse
5900  *
5901  * Reuse means a new TCP session reuses the tuple (flow in suri)
5902  *
5903  * \retval bool true if ssn can be reused, false if not */
5904 static bool TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn)
5905 {
5906  const TCPHdr *tcph = PacketGetTCP(p);
5907  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5908  return TcpSessionReuseDoneEnoughSyn(p, f, ssn);
5909  }
5910 
5912  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5913  return TcpSessionReuseDoneEnoughSynAck(p, f, ssn);
5914  }
5915  }
5916 
5917  return false;
5918 }
5919 
5920 bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
5921 {
5922  if (p->proto == IPPROTO_TCP && PacketIsTCP(p)) {
5923  if (TcpSessionPacketIsStreamStarter(p) == 1) {
5924  if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) {
5925  return true;
5926  }
5927  }
5928  }
5929  return false;
5930 }
5931 
5933 {
5934  DEBUG_VALIDATE_BUG_ON(p->flow == NULL);
5935  if (unlikely(p->flow == NULL)) {
5936  return TM_ECODE_OK;
5937  }
5938 
5939  StreamTcpThread *stt = (StreamTcpThread *)data;
5940 
5941  SCLogDebug("p->pcap_cnt %" PRIu64 " direction %s pkt_src %s", p->pcap_cnt,
5942  p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
5943  : "noflow",
5944  PktSrcToString(p->pkt_src));
5945  t_pcapcnt = p->pcap_cnt;
5946 
5947  if (!(PacketIsTCP(p))) {
5948  return TM_ECODE_OK;
5949  }
5950 
5951  HandleThreadId(tv, p, stt);
5952 
5953  /* only TCP packets with a flow from here */
5954 
5955  if (!(p->flags & PKT_PSEUDO_STREAM_END)) {
5957  if (StreamTcpValidateChecksum(p) == 0) {
5959  return TM_ECODE_OK;
5960  }
5961  }
5962  }
5964 
5965  (void)StreamTcpPacket(tv, p, stt, pq);
5966 
5967  return TM_ECODE_OK;
5968 }
5969 
5970 TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
5971 {
5972  SCEnter();
5973  StreamTcpThread *stt = SCCalloc(1, sizeof(StreamTcpThread));
5974  if (unlikely(stt == NULL))
5976  stt->ssn_pool_id = -1;
5978 
5979  *data = (void *)stt;
5980 
5981  stt->counter_tcp_active_sessions = StatsRegisterCounter("tcp.active_sessions", tv);
5982  stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv);
5983  stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv);
5984  stt->counter_tcp_ssn_from_cache = StatsRegisterCounter("tcp.ssn_from_cache", tv);
5985  stt->counter_tcp_ssn_from_pool = StatsRegisterCounter("tcp.ssn_from_pool", tv);
5987  stream_config.ssn_memcap_policy, "tcp.ssn_memcap_exception_policy.",
5988  IsStreamTcpSessionMemcapExceptionPolicyStatsValid);
5989 
5990  stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv);
5991  stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv);
5992  stt->counter_tcp_midstream_pickups = StatsRegisterCounter("tcp.midstream_pickups", tv);
5993  if (stream_config.midstream) {
5996  "tcp.midstream_exception_policy.", IsMidstreamExceptionPolicyStatsValid);
5997  } else {
6000  "tcp.midstream_exception_policy.", IsMidstreamExceptionPolicyStatsValid);
6001  }
6002 
6003  stt->counter_tcp_wrong_thread = StatsRegisterCounter("tcp.pkt_on_wrong_thread", tv);
6004  stt->counter_tcp_ack_unseen_data = StatsRegisterCounter("tcp.ack_unseen_data", tv);
6005 
6006  /* init reassembly ctx */
6008  if (stt->ra_ctx == NULL)
6010 
6011  stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv);
6012 
6015  "tcp.reassembly_exception_policy.", IsReassemblyMemcapExceptionPolicyStatsValid);
6016 
6018  StatsRegisterCounter("tcp.segment_from_cache", tv);
6019  stt->ra_ctx->counter_tcp_segment_from_pool = StatsRegisterCounter("tcp.segment_from_pool", tv);
6020  stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv);
6021  stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv);
6022  stt->ra_ctx->counter_tcp_reass_overlap = StatsRegisterCounter("tcp.overlap", tv);
6023  stt->ra_ctx->counter_tcp_reass_overlap_diff_data = StatsRegisterCounter("tcp.overlap_diff_data", tv);
6024 
6025  stt->ra_ctx->counter_tcp_reass_data_normal_fail = StatsRegisterCounter("tcp.insert_data_normal_fail", tv);
6026  stt->ra_ctx->counter_tcp_reass_data_overlap_fail = StatsRegisterCounter("tcp.insert_data_overlap_fail", tv);
6027  stt->ra_ctx->counter_tcp_urgent_oob = StatsRegisterCounter("tcp.urgent_oob_data", tv);
6028 
6029  SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p",
6030  stt, stt->ra_ctx);
6031 
6032  SCMutexLock(&ssn_pool_mutex);
6033  if (ssn_pool == NULL) {
6034  ssn_pool = PoolThreadInit(1, /* thread */
6035  0, /* unlimited */
6037  sizeof(TcpSession),
6038  StreamTcpSessionPoolAlloc,
6039  StreamTcpSessionPoolInit, NULL,
6040  StreamTcpSessionPoolCleanup, NULL);
6041  stt->ssn_pool_id = 0;
6042  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6043  } else {
6044  /* grow ssn_pool until we have a element for our thread id */
6046  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6047  }
6048  SCMutexUnlock(&ssn_pool_mutex);
6049  if (stt->ssn_pool_id < 0 || ssn_pool == NULL) {
6050  SCLogError("failed to setup/expand stream session pool. Expand stream.memcap?");
6052  }
6053 
6055 }
6056 
6058 {
6059  SCEnter();
6060  StreamTcpThread *stt = (StreamTcpThread *)data;
6061  if (stt == NULL) {
6062  return TM_ECODE_OK;
6063  }
6064 
6065  /* XXX */
6066 
6067  /* free reassembly ctx */
6069 
6070  /* clear memory */
6071  memset(stt, 0, sizeof(StreamTcpThread));
6072 
6073  SCFree(stt);
6075 }
6076 
6077 /**
6078  * \brief Function to check the validity of the RST packets based on the
6079  * target OS of the given packet.
6080  *
6081  * \param ssn TCP session to which the given packet belongs
6082  * \param p Packet which has to be checked for its validity
6083  *
6084  * \retval 0 unacceptable RST
6085  * \retval 1 acceptable RST
6086  *
6087  * WebSense sends RST packets that are:
6088  * - RST flag, win 0, ack 0, seq = nextseq
6089  *
6090  */
6091 
6092 static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
6093 {
6094  uint8_t os_policy;
6095  const TCPHdr *tcph = PacketGetTCP(p);
6096  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6097 
6099  SCReturnInt(1);
6100  }
6101 
6102  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
6103  if (!StreamTcpValidateTimestamp(ssn, p)) {
6104  SCReturnInt(0);
6105  }
6106  }
6107 
6108  /* RST with data, it's complicated:
6109 
6110  4.2.2.12 RST Segment: RFC-793 Section 3.4
6111 
6112  A TCP SHOULD allow a received RST segment to include data.
6113 
6114  DISCUSSION
6115  It has been suggested that a RST segment could contain
6116  ASCII text that encoded and explained the cause of the
6117  RST. No standard has yet been established for such
6118  data.
6119  */
6120  if (p->payload_len)
6122 
6123  /* Set up the os_policy to be used in validating the RST packets based on
6124  target system */
6125  if (PKT_IS_TOSERVER(p)) {
6126  if (ssn->server.os_policy == 0)
6127  StreamTcpSetOSPolicy(&ssn->server, p);
6128 
6129  os_policy = ssn->server.os_policy;
6130 
6131  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6132  StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
6133  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6135  SCReturnInt(0);
6136  }
6137 
6138  } else {
6139  if (ssn->client.os_policy == 0)
6140  StreamTcpSetOSPolicy(&ssn->client, p);
6141 
6142  os_policy = ssn->client.os_policy;
6143 
6144  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6145  StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
6146  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6148  SCReturnInt(0);
6149  }
6150  }
6151 
6152  /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
6153  * validate these (requires key that is set/transferred out of band), we can't know
6154  * if the RST will be accepted or rejected by the end host. We accept it, but keep
6155  * tracking if the sender of it ignores it, which would be a sign of injection. */
6157  TcpStream *receiver_stream;
6158  if (PKT_IS_TOSERVER(p)) {
6159  receiver_stream = &ssn->server;
6160  } else {
6161  receiver_stream = &ssn->client;
6162  }
6163  SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
6164  receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
6165  }
6166 
6167  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
6168  if (PKT_IS_TOSERVER(p)) {
6169  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6170  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6171  return 1;
6172  }
6173  } else {
6174  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6175  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6176  return 1;
6177  }
6178  }
6179  SCLogDebug("ssn %p: ASYNC reject RST", ssn);
6180  return 0;
6181  }
6182 
6183  switch (os_policy) {
6184  case OS_POLICY_HPUX11:
6185  if(PKT_IS_TOSERVER(p)){
6186  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6187  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6188  return 1;
6189  } else {
6190  SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " "
6191  "and server SEQ: %" PRIu32 "",
6192  seq, ssn->client.next_seq);
6193  return 0;
6194  }
6195  } else { /* implied to client */
6196  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6197  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6198  return 1;
6199  } else {
6200  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6201  "and client SEQ: %" PRIu32 "",
6202  seq, ssn->server.next_seq);
6203  return 0;
6204  }
6205  }
6206  break;
6207  case OS_POLICY_OLD_LINUX:
6208  case OS_POLICY_LINUX:
6209  case OS_POLICY_SOLARIS:
6210  if(PKT_IS_TOSERVER(p)){
6211  if (SEQ_GEQ((seq + p->payload_len),
6212  ssn->client.last_ack)) { /*window base is needed !!*/
6213  if (SEQ_LT(seq, (ssn->client.next_seq + ssn->client.window))) {
6214  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6215  return 1;
6216  }
6217  } else {
6218  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6219  " server SEQ: %" PRIu32 "",
6220  seq, ssn->client.next_seq);
6221  return 0;
6222  }
6223  } else { /* implied to client */
6224  if (SEQ_GEQ((seq + p->payload_len),
6225  ssn->server.last_ack)) { /*window base is needed !!*/
6226  if (SEQ_LT(seq, (ssn->server.next_seq + ssn->server.window))) {
6227  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6228  return 1;
6229  }
6230  } else {
6231  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6232  " client SEQ: %" PRIu32 "",
6233  seq, ssn->server.next_seq);
6234  return 0;
6235  }
6236  }
6237  break;
6238  default:
6239  case OS_POLICY_BSD:
6240  case OS_POLICY_FIRST:
6241  case OS_POLICY_HPUX10:
6242  case OS_POLICY_IRIX:
6243  case OS_POLICY_MACOS:
6244  case OS_POLICY_LAST:
6245  case OS_POLICY_WINDOWS:
6246  case OS_POLICY_WINDOWS2K3:
6247  case OS_POLICY_VISTA:
6248  if(PKT_IS_TOSERVER(p)) {
6249  if (SEQ_EQ(seq, ssn->client.next_seq)) {
6250  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6251  return 1;
6252  } else {
6253  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6254  "and server SEQ: %" PRIu32 "",
6255  seq, ssn->client.next_seq);
6256  return 0;
6257  }
6258  } else { /* implied to client */
6259  if (SEQ_EQ(seq, ssn->server.next_seq)) {
6260  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u", seq,
6261  ssn->server.next_seq);
6262  return 1;
6263  } else {
6264  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6265  " client SEQ: %" PRIu32 "",
6266  seq, ssn->server.next_seq);
6267  return 0;
6268  }
6269  }
6270  break;
6271  }
6272  return 0;
6273 }
6274 
6275 /**
6276  * \brief Function to check the validity of the received timestamp based on
6277  * the target OS of the given stream.
6278  *
6279  * It's passive except for:
6280  * 1. it sets the os policy on the stream if necessary
6281  * 2. it sets an event in the packet if necessary
6282  *
6283  * \param ssn TCP session to which the given packet belongs
6284  * \param p Packet which has to be checked for its validity
6285  *
6286  * \retval 1 if the timestamp is valid
6287  * \retval 0 if the timestamp is invalid
6288  */
6289 static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p)
6290 {
6291  SCEnter();
6292 
6293  TcpStream *sender_stream;
6294  TcpStream *receiver_stream;
6295  uint8_t ret = 1;
6296  uint8_t check_ts = 1;
6297  const TCPHdr *tcph = PacketGetTCP(p);
6298  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6299 
6300  if (PKT_IS_TOSERVER(p)) {
6301  sender_stream = &ssn->client;
6302  receiver_stream = &ssn->server;
6303  } else {
6304  sender_stream = &ssn->server;
6305  receiver_stream = &ssn->client;
6306  }
6307 
6308  /* Set up the os_policy to be used in validating the timestamps based on
6309  the target system */
6310  if (receiver_stream->os_policy == 0) {
6311  StreamTcpSetOSPolicy(receiver_stream, p);
6312  }
6313 
6314  if (TCP_HAS_TS(p)) {
6315  uint32_t ts = TCP_GET_TSVAL(p);
6316  uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
6317  uint32_t last_ts = sender_stream->last_ts;
6318 
6319  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6320  /* The 3whs used the timestamp with 0 value. */
6321  switch (receiver_stream->os_policy) {
6322  case OS_POLICY_LINUX:
6323  case OS_POLICY_WINDOWS2K3:
6324  /* Linux and windows 2003 does not allow the use of 0 as
6325  * timestamp in the 3whs. */
6326  check_ts = 0;
6327  break;
6328 
6329  case OS_POLICY_OLD_LINUX:
6330  case OS_POLICY_WINDOWS:
6331  case OS_POLICY_VISTA:
6332  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6333  last_ts = ts;
6334  check_ts = 0; /*next packet will be checked for validity
6335  and stream TS has been updated with this
6336  one.*/
6337  }
6338  break;
6339  }
6340  }
6341 
6342  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6343  /* HPUX11 ignores the timestamp of out of order packets */
6344  if (!SEQ_EQ(sender_stream->next_seq, seq))
6345  check_ts = 0;
6346  }
6347 
6348  if (ts == 0) {
6349  switch (receiver_stream->os_policy) {
6350  case OS_POLICY_OLD_LINUX:
6351  case OS_POLICY_WINDOWS:
6352  case OS_POLICY_WINDOWS2K3:
6353  case OS_POLICY_VISTA:
6354  case OS_POLICY_SOLARIS:
6355  /* Old Linux and windows allowed packet with 0 timestamp. */
6356  break;
6357  default:
6358  /* other OS simply drop the packet with 0 timestamp, when
6359  * 3whs has valid timestamp*/
6360  goto invalid;
6361  }
6362  }
6363 
6364  if (check_ts) {
6365  int32_t result = 0;
6366 
6367  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts);
6368 
6369  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6370  /* Linux accepts TS which are off by one.*/
6371  result = (int32_t) ((ts - last_ts) + 1);
6372  } else {
6373  result = (int32_t) (ts - last_ts);
6374  }
6375 
6376  SCLogDebug("result %" PRIi32 ", p->ts(secs) %" PRIuMAX "", result,
6377  (uintmax_t)SCTIME_SECS(p->ts));
6378 
6379  if (last_pkt_ts == 0 &&
6381  {
6382  last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6383  }
6384 
6385  if (result < 0) {
6386  SCLogDebug("timestamp is not valid last_ts "
6387  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6388  "%" PRId32 "", last_ts, ts, result);
6389  /* candidate for rejection */
6390  ret = 0;
6391  } else if ((sender_stream->last_ts != 0) &&
6392  (((uint32_t)SCTIME_SECS(p->ts)) > last_pkt_ts + PAWS_24DAYS)) {
6393  SCLogDebug("packet is not valid last_pkt_ts "
6394  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6395  last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6396  /* candidate for rejection */
6397  ret = 0;
6398  }
6399 
6400  if (ret == 0) {
6401  /* if the timestamp of packet is not valid then, check if the
6402  * current stream timestamp is not so old. if so then we need to
6403  * accept the packet and update the stream->last_ts (RFC 1323)*/
6404  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6405  (((uint32_t)SCTIME_SECS(p->ts) > (last_pkt_ts + PAWS_24DAYS)))) {
6406  SCLogDebug("timestamp considered valid anyway");
6407  } else {
6408  goto invalid;
6409  }
6410  }
6411  }
6412  }
6413 
6414  SCReturnInt(1);
6415 
6416 invalid:
6418  SCReturnInt(0);
6419 }
6420 
6421 /**
6422  * \brief Function to check the validity of the received timestamp based on
6423  * the target OS of the given stream and update the session.
6424  *
6425  * \param ssn TCP session to which the given packet belongs
6426  * \param p Packet which has to be checked for its validity
6427  *
6428  * \retval 1 if the timestamp is valid
6429  * \retval 0 if the timestamp is invalid
6430  */
6431 static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p)
6432 {
6433  SCEnter();
6434 
6435  TcpStream *sender_stream;
6436  TcpStream *receiver_stream;
6437  uint8_t ret = 1;
6438  uint8_t check_ts = 1;
6439  const TCPHdr *tcph = PacketGetTCP(p);
6440  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6441 
6442  if (PKT_IS_TOSERVER(p)) {
6443  sender_stream = &ssn->client;
6444  receiver_stream = &ssn->server;
6445  } else {
6446  sender_stream = &ssn->server;
6447  receiver_stream = &ssn->client;
6448  }
6449 
6450  /* Set up the os_policy to be used in validating the timestamps based on
6451  the target system */
6452  if (receiver_stream->os_policy == 0) {
6453  StreamTcpSetOSPolicy(receiver_stream, p);
6454  }
6455 
6456  if (TCP_HAS_TS(p)) {
6457  uint32_t ts = TCP_GET_TSVAL(p);
6458 
6459  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6460  /* The 3whs used the timestamp with 0 value. */
6461  switch (receiver_stream->os_policy) {
6462  case OS_POLICY_LINUX:
6463  case OS_POLICY_WINDOWS2K3:
6464  /* Linux and windows 2003 does not allow the use of 0 as
6465  * timestamp in the 3whs. */
6467  check_ts = 0;
6468  break;
6469 
6470  case OS_POLICY_OLD_LINUX:
6471  case OS_POLICY_WINDOWS:
6472  case OS_POLICY_VISTA:
6473  sender_stream->flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
6474  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6475  sender_stream->last_ts = ts;
6476  check_ts = 0; /*next packet will be checked for validity
6477  and stream TS has been updated with this
6478  one.*/
6479  }
6480  break;
6481  default:
6482  break;
6483  }
6484  }
6485 
6486  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6487  /*HPUX11 ignores the timestamp of out of order packets*/
6488  if (!SEQ_EQ(sender_stream->next_seq, seq))
6489  check_ts = 0;
6490  }
6491 
6492  if (ts == 0) {
6493  switch (receiver_stream->os_policy) {
6494  case OS_POLICY_OLD_LINUX:
6495  case OS_POLICY_WINDOWS:
6496  case OS_POLICY_WINDOWS2K3:
6497  case OS_POLICY_VISTA:
6498  case OS_POLICY_SOLARIS:
6499  /* Old Linux and windows allowed packet with 0 timestamp. */
6500  break;
6501  default:
6502  /* other OS simply drop the packet with 0 timestamp, when
6503  * 3whs has valid timestamp*/
6504  goto invalid;
6505  }
6506  }
6507 
6508  if (check_ts) {
6509  int32_t result = 0;
6510 
6511  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts);
6512 
6513  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6514  /* Linux accepts TS which are off by one.*/
6515  result = (int32_t) ((ts - sender_stream->last_ts) + 1);
6516  } else {
6517  result = (int32_t) (ts - sender_stream->last_ts);
6518  }
6519 
6520  SCLogDebug("result %" PRIi32 ", p->ts(sec) %" PRIuMAX "", result,
6521  (uintmax_t)SCTIME_SECS(p->ts));
6522 
6523  if (sender_stream->last_pkt_ts == 0 &&
6525  {
6526  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6527  }
6528 
6529  if (result < 0) {
6530  SCLogDebug("timestamp is not valid sender_stream->last_ts "
6531  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6532  "%" PRId32 "", sender_stream->last_ts, ts, result);
6533  /* candidate for rejection */
6534  ret = 0;
6535  } else if ((sender_stream->last_ts != 0) &&
6536  (((uint32_t)SCTIME_SECS(p->ts)) >
6537  sender_stream->last_pkt_ts + PAWS_24DAYS)) {
6538  SCLogDebug("packet is not valid sender_stream->last_pkt_ts "
6539  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6540  sender_stream->last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6541  /* candidate for rejection */
6542  ret = 0;
6543  }
6544 
6545  if (ret == 1) {
6546  /* Update the timestamp and last seen packet time for this
6547  * stream */
6548  if (SEQ_EQ(sender_stream->next_seq, seq))
6549  sender_stream->last_ts = ts;
6550 
6551  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6552 
6553  } else if (ret == 0) {
6554  /* if the timestamp of packet is not valid then, check if the
6555  * current stream timestamp is not so old. if so then we need to
6556  * accept the packet and update the stream->last_ts (RFC 1323)*/
6557  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6558  (((uint32_t)SCTIME_SECS(p->ts) >
6559  (sender_stream->last_pkt_ts + PAWS_24DAYS)))) {
6560  sender_stream->last_ts = ts;
6561  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6562 
6563  SCLogDebug("timestamp considered valid anyway");
6564  } else {
6565  goto invalid;
6566  }
6567  }
6568  }
6569  } else {
6570  /* Solaris stops using timestamps if a packet is received
6571  without a timestamp and timestamps were used on that stream. */
6572  if (receiver_stream->os_policy == OS_POLICY_SOLARIS)
6574  }
6575 
6576  SCReturnInt(1);
6577 
6578 invalid:
6580  SCReturnInt(0);
6581 }
6582 
6583 /**
6584  * \brief Function to test the received ACK values against the stream window
6585  * and previous ack value. ACK values should be higher than previous
6586  * ACK value and less than the next_win value.
6587  *
6588  * \param ssn TcpSession for state access
6589  * \param stream TcpStream of which last_ack needs to be tested
6590  * \param p Packet which is used to test the last_ack
6591  *
6592  * \retval 0 ACK is valid, last_ack is updated if ACK was higher
6593  * \retval -1 ACK is invalid
6594  */
6595 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p)
6596 {
6597  SCEnter();
6598 
6599  const TCPHdr *tcph = PacketGetTCP(p);
6600  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
6601 
6602  if (!(tcph->th_flags & TH_ACK))
6603  SCReturnInt(0);
6604 
6605  /* fast track */
6606  if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win))
6607  {
6608  SCLogDebug("ssn %p: ACK %u in bounds > %u <= %u", ssn, ack, stream->last_ack,
6609  stream->next_win);
6610  SCReturnInt(0);
6611  }
6612  /* fast track */
6613  else if (SEQ_EQ(ack, stream->last_ack)) {
6614  SCLogDebug("ssn %p: pkt ACK %" PRIu32 " == stream last ACK %" PRIu32, ssn, ack,
6615  stream->last_ack);
6616  SCReturnInt(0);
6617  }
6618 
6619  /* exception handling */
6620  if (SEQ_LT(ack, stream->last_ack)) {
6621  SCLogDebug("pkt ACK %" PRIu32 " < stream last ACK %" PRIu32, ack, stream->last_ack);
6622 
6623  /* This is an attempt to get a 'left edge' value that we can check against.
6624  * It doesn't work when the window is 0, need to think of a better way. */
6625 
6626  if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) {
6627  SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window "
6628  "%"PRIu32" = %"PRIu32, ack, stream->last_ack,
6629  stream->window, stream->last_ack - stream->window);
6630  goto invalid;
6631  }
6632 
6633  SCReturnInt(0);
6634  }
6635 
6636  /* no further checks possible for ASYNC */
6637  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
6638  SCReturnInt(0);
6639  }
6640 
6641  if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) {
6642  SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win);
6643  goto invalid;
6644  /* a toclient RST as a response to SYN, next_win is 0, ack will be isn+1, just like
6645  * the syn ack */
6646  } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && tcph->th_flags & TH_RST &&
6647  SEQ_EQ(ack, stream->isn + 1)) {
6648  SCReturnInt(0);
6649  }
6650 
6651  SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32
6652  " next_win %"PRIu32, ack, stream->last_ack, stream->next_win);
6653 invalid:
6655  SCReturnInt(-1);
6656 }
6657 
6658 /** \brief update reassembly progress
6659 
6660  * \param ssn TCP Session
6661  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6662  */
6664  const uint32_t progress)
6665 {
6666  if (direction) {
6667  ssn->server.app_progress_rel += progress;
6668  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->server));
6669  } else {
6670  ssn->client.app_progress_rel += progress;
6671  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->client));
6672  }
6673 }
6674 
6675 /** \brief disable reassembly
6676 
6677  * Disable app layer and set raw inspect to no longer accept new data.
6678  * Stream engine will then fully disable raw after last inspection.
6679  *
6680  * \param ssn TCP Session to set the flag in
6681  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6682  */
6684 {
6686  if (direction) {
6688  } else {
6690  }
6691 }
6692 
6693 /** \brief Set the No reassembly flag for the given direction in given TCP
6694  * session.
6695  *
6696  * \param ssn TCP Session to set the flag in
6697  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6698  */
6700 {
6701  direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) :
6703 }
6704 
6705 /** \brief enable bypass
6706  *
6707  * \param ssn TCP Session to set the flag in
6708  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6709  */
6711 {
6712  ssn->flags |= STREAMTCP_FLAG_BYPASS;
6713 }
6714 
6715 /** \brief Create a pseudo packet injected into the engine to signal the
6716  * opposing direction of this stream trigger detection/logging.
6717  *
6718  * \param parent real packet
6719  * \param pq packet queue to store the new pseudo packet in
6720  * \param dir 0 ts 1 tc
6721  */
6722 static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv,
6723  StreamTcpThread *stt, Packet *parent,
6724  TcpSession *ssn, PacketQueueNoLock *pq, int dir)
6725 {
6726  SCEnter();
6727  Flow *f = parent->flow;
6728  TCPHdr *tcph = NULL;
6729 
6730  if (parent->flags & PKT_PSEUDO_DETECTLOG_FLUSH) {
6731  SCReturn;
6732  }
6733  if ((f->flags & (FLOW_IPV4 | FLOW_IPV6)) == 0) {
6734  SCReturn;
6735  }
6736 
6737  Packet *np = PacketPoolGetPacket();
6738  if (np == NULL) {
6739  SCReturn;
6740  }
6742 
6743  np->tenant_id = f->tenant_id;
6744  np->datalink = DLT_RAW;
6745  np->proto = IPPROTO_TCP;
6746  FlowReference(&np->flow, f);
6747  np->flags |= PKT_STREAM_EST;
6748  np->flags |= PKT_HAS_FLOW;
6749  np->flags |= PKT_IGNORE_CHECKSUM;
6751  memcpy(&np->vlan_id[0], &f->vlan_id[0], sizeof(np->vlan_id));
6752  np->vlan_idx = f->vlan_idx;
6753  np->livedev = (struct LiveDevice_ *)f->livedev;
6754 
6755  if (parent->flags & PKT_NOPACKET_INSPECTION) {
6756  DecodeSetNoPacketInspectionFlag(np);
6757  }
6758  if (parent->flags & PKT_NOPAYLOAD_INSPECTION) {
6759  DecodeSetNoPayloadInspectionFlag(np);
6760  }
6761 
6762  if (dir == 0) {
6763  SCLogDebug("pseudo is to_server");
6765  } else {
6766  SCLogDebug("pseudo is to_client");
6768  }
6770  np->payload = NULL;
6771  np->payload_len = 0;
6772 
6773  if (FLOW_IS_IPV4(f)) {
6774  if (dir == 0) {
6777  np->sp = f->sp;
6778  np->dp = f->dp;
6779  } else {
6782  np->sp = f->dp;
6783  np->dp = f->sp;
6784  }
6785 
6786  /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
6787  * Force an allocation if it is not the case.
6788  */
6789  if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) {
6790  if (PacketCallocExtPkt(np, 40) == -1) {
6791  goto error;
6792  }
6793  }
6794  /* set the ip header */
6795  IPV4Hdr *ip4h = PacketSetIPV4(np, GET_PKT_DATA(np));
6796  /* version 4 and length 20 bytes for the tcp header */
6797  ip4h->ip_verhl = 0x45;
6798  ip4h->ip_tos = 0;
6799  ip4h->ip_len = htons(40);
6800  ip4h->ip_id = 0;
6801  ip4h->ip_off = 0;
6802  ip4h->ip_ttl = 64;
6803  ip4h->ip_proto = IPPROTO_TCP;
6804  if (dir == 0) {
6805  ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
6806  ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
6807  } else {
6808  ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
6809  ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
6810  }
6811 
6812  /* set the tcp header */
6813  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 20);
6814 
6815  SET_PKT_LEN(np, 40); /* ipv4 hdr + tcp hdr */
6816  } else {
6817  /* implied IPv6 */
6818 
6819  if (dir == 0) {
6822  np->sp = f->sp;
6823  np->dp = f->dp;
6824  } else {
6827  np->sp = f->dp;
6828  np->dp = f->sp;
6829  }
6830 
6831  /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
6832  * Force an allocation if it is not the case.
6833  */
6834  if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) {
6835  if (PacketCallocExtPkt(np, 60) == -1) {
6836  goto error;
6837  }
6838  }
6839  /* set the ip header */
6840  IPV6Hdr *ip6h = PacketSetIPV6(np, GET_PKT_DATA(np));
6841  /* version 6 */
6842  ip6h->s_ip6_vfc = 0x60;
6843  ip6h->s_ip6_flow = 0;
6844  ip6h->s_ip6_nxt = IPPROTO_TCP;
6845  ip6h->s_ip6_plen = htons(20);
6846  ip6h->s_ip6_hlim = 64;
6847  if (dir == 0) {
6848  ip6h->s_ip6_src[0] = f->src.addr_data32[0];
6849  ip6h->s_ip6_src[1] = f->src.addr_data32[1];
6850  ip6h->s_ip6_src[2] = f->src.addr_data32[2];
6851  ip6h->s_ip6_src[3] = f->src.addr_data32[3];
6852  ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
6853  ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
6854  ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
6855  ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
6856  } else {
6857  ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
6858  ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
6859  ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
6860  ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
6861  ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
6862  ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
6863  ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
6864  ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
6865  }
6866 
6867  /* set the tcp header */
6868  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 40);
6869 
6870  SET_PKT_LEN(np, 60); /* ipv6 hdr + tcp hdr */
6871  }
6872 
6873  tcph->th_offx2 = 0x50;
6874  tcph->th_flags |= TH_ACK;
6875  tcph->th_win = 10;
6876  tcph->th_urp = 0;
6877 
6878  /* to server */
6879  if (dir == 0) {
6880  tcph->th_sport = htons(f->sp);
6881  tcph->th_dport = htons(f->dp);
6882 
6883  tcph->th_seq = htonl(ssn->client.next_seq);
6884  tcph->th_ack = htonl(ssn->server.last_ack);
6885 
6886  /* to client */
6887  } else {
6888  tcph->th_sport = htons(f->dp);
6889  tcph->th_dport = htons(f->sp);
6890 
6891  tcph->th_seq = htonl(ssn->server.next_seq);
6892  tcph->th_ack = htonl(ssn->client.last_ack);
6893  }
6894 
6895  /* use parent time stamp */
6896  np->ts = parent->ts;
6897 
6898  SCLogDebug("np %p", np);
6899  PacketEnqueueNoLock(pq, np);
6900 
6902  SCReturn;
6903 error:
6904  FlowDeReference(&np->flow);
6905  SCReturn;
6906 }
6907 
6908 /** \brief create packets in both directions to flush out logging
6909  * and detection before switching protocols.
6910  * In IDS mode, create first in packet dir, 2nd in opposing
6911  * In IPS mode, do the reverse.
6912  * Flag TCP engine that data needs to be inspected regardless
6913  * of how far we are wrt inspect limits.
6914  */
6916  PacketQueueNoLock *pq)
6917 {
6918  TcpSession *ssn = f->protoctx;
6921  bool ts = PKT_IS_TOSERVER(p) ? true : false;
6922  ts ^= StreamTcpInlineMode();
6923  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^0);
6924  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^1);
6925 }
6926 
6927 /**
6928  * \brief Run callback function on each TCP segment in a single direction.
6929  *
6930  * \note when stream engine is running in inline mode all segments are used,
6931  * in IDS/non-inline mode only ack'd segments are iterated.
6932  *
6933  * \note Must be called under flow lock.
6934  * \var flag determines the direction to run callback on (either to server or to client).
6935  *
6936  * \return -1 in case of error, the number of segment in case of success
6937  *
6938  */
6939 int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
6940 {
6941  TcpStream *stream = NULL;
6942  int cnt = 0;
6943 
6944  if (p->flow == NULL)
6945  return 0;
6946 
6947  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
6948  if (ssn == NULL) {
6949  return 0;
6950  }
6951 
6952  if (flag & STREAM_DUMP_TOSERVER) {
6953  stream = &(ssn->server);
6954  } else {
6955  stream = &(ssn->client);
6956  }
6957 
6958  /* for IDS, return ack'd segments. For IPS all. */
6959  TcpSegment *seg;
6960  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
6962  if (PKT_IS_PSEUDOPKT(p)) {
6963  /* use un-ACK'd data as well */
6964  } else {
6965  /* in IDS mode, use ACK'd data */
6966  if (SEQ_GEQ(seg->seq, stream->last_ack)) {
6967  break;
6968  }
6969  }
6970  }
6971 
6972  const uint8_t *seg_data;
6973  uint32_t seg_datalen;
6974  StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
6975 
6976  int ret = CallbackFunc(p, seg, data, seg_data, seg_datalen);
6977  if (ret != 1) {
6978  SCLogDebug("Callback function has failed");
6979  return -1;
6980  }
6981 
6982  cnt++;
6983  }
6984  return cnt;
6985 }
6986 
6987 /**
6988  * \brief Run callback function on each TCP segment in both directions of a session.
6989  *
6990  * \note when stream engine is running in inline mode all segments are used,
6991  * in IDS/non-inline mode only ack'd segments are iterated.
6992  *
6993  * \note Must be called under flow lock.
6994  *
6995  * \return -1 in case of error, the number of segment in case of success
6996  *
6997  */
6999  const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
7000 {
7001  int ret = 0;
7002  int cnt = 0;
7003 
7004  if (p->flow == NULL)
7005  return 0;
7006 
7007  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
7008 
7009  if (ssn == NULL) {
7010  return -1;
7011  }
7012 
7013  TcpStream *server_stream = &(ssn->server);
7014  TcpStream *client_stream = &(ssn->client);
7015 
7016  TcpSegment *server_node = RB_MIN(TCPSEG, &server_stream->seg_tree);
7017  TcpSegment *client_node = RB_MIN(TCPSEG, &client_stream->seg_tree);
7018  if (server_node == NULL && client_node == NULL) {
7019  return cnt;
7020  }
7021 
7022  while (server_node != NULL || client_node != NULL) {
7023  const uint8_t *seg_data;
7024  uint32_t seg_datalen;
7025  if (server_node == NULL) {
7026  /*
7027  * This means the server side RB Tree has been completely searched,
7028  * thus all that remains is to dump the TcpSegments on the client
7029  * side.
7030  */
7032  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7033  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7034  if (ret != 1) {
7035  SCLogDebug("Callback function has failed");
7036  return -1;
7037  }
7038  client_node = TCPSEG_RB_NEXT(client_node);
7039  } else if (client_node == NULL) {
7040  /*
7041  * This means the client side RB Tree has been completely searched,
7042  * thus all that remains is to dump the TcpSegments on the server
7043  * side.
7044  */
7046  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7047  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7048  if (ret != 1) {
7049  SCLogDebug("Callback function has failed");
7050  return -1;
7051  }
7052  server_node = TCPSEG_RB_NEXT(server_node);
7053  } else {
7054  if (SCTIME_CMP_LT(
7055  client_node->pcap_hdr_storage->ts, server_node->pcap_hdr_storage->ts)) {
7057  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7058  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7059  if (ret != 1) {
7060  SCLogDebug("Callback function has failed");
7061  return -1;
7062  }
7063  client_node = TCPSEG_RB_NEXT(client_node);
7064  } else {
7066  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7067  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7068  if (ret != 1) {
7069  SCLogDebug("Callback function has failed");
7070  return -1;
7071  }
7072  server_node = TCPSEG_RB_NEXT(server_node);
7073  }
7074  }
7075 
7076  cnt++;
7077  }
7078  return cnt;
7079 }
7080 
7082 {
7084 }
7085 
7086 /**
7087  * \brief See if stream engine is operating in inline mode
7088  *
7089  * \retval 0 no
7090  * \retval 1 yes
7091  */
7093 {
7095 }
7096 
7097 
7098 void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
7099 {
7100  if (size > ssn->reassembly_depth || size == 0) {
7101  ssn->reassembly_depth = size;
7102  }
7103 }
7104 
7105 const char *StreamTcpStateAsString(const enum TcpState state)
7106 {
7107  const char *tcp_state = NULL;
7108  switch (state) {
7109  case TCP_NONE:
7110  tcp_state = "none";
7111  break;
7112  case TCP_SYN_SENT:
7113  tcp_state = "syn_sent";
7114  break;
7115  case TCP_SYN_RECV:
7116  tcp_state = "syn_recv";
7117  break;
7118  case TCP_ESTABLISHED:
7119  tcp_state = "established";
7120  break;
7121  case TCP_FIN_WAIT1:
7122  tcp_state = "fin_wait1";
7123  break;
7124  case TCP_FIN_WAIT2:
7125  tcp_state = "fin_wait2";
7126  break;
7127  case TCP_TIME_WAIT:
7128  tcp_state = "time_wait";
7129  break;
7130  case TCP_LAST_ACK:
7131  tcp_state = "last_ack";
7132  break;
7133  case TCP_CLOSE_WAIT:
7134  tcp_state = "close_wait";
7135  break;
7136  case TCP_CLOSING:
7137  tcp_state = "closing";
7138  break;
7139  case TCP_CLOSED:
7140  tcp_state = "closed";
7141  break;
7142  }
7143  return tcp_state;
7144 }
7145 
7146 const char *StreamTcpSsnStateAsString(const TcpSession *ssn)
7147 {
7148  if (ssn == NULL)
7149  return NULL;
7150  return StreamTcpStateAsString(ssn->state);
7151 }
7152 
7153 #ifdef UNITTESTS
7154 #include "tests/stream-tcp.c"
7155 #endif
PKT_IS_TOCLIENT
#define PKT_IS_TOCLIENT(p)
Definition: decode.h:235
PacketL4::csum_set
bool csum_set
Definition: decode.h:441
StreamTcpSetEvent
#define StreamTcpSetEvent(p, e)
Definition: stream-tcp-private.h:270
StreamTcpThread_::counter_tcp_midstream_pickups
uint16_t counter_tcp_midstream_pickups
Definition: stream-tcp.h:108
TCP_GET_RAW_SEQ
#define TCP_GET_RAW_SEQ(tcph)
Definition: decode-tcp.h:80
PoolThreadInit
PoolThread * PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int(*Init)(void *, void *), void *InitData, void(*Cleanup)(void *), void(*Free)(void *))
per thread Pool, initialization function
Definition: util-pool-thread.c:43
STREAM_3WHS_ACK_IN_WRONG_DIR
@ STREAM_3WHS_ACK_IN_WRONG_DIR
Definition: decode-events.h:228
PacketCheckAction
bool PacketCheckAction(const Packet *p, const uint8_t a)
Definition: packet.c:49
StreamTcpIncrMemuse
void StreamTcpIncrMemuse(uint64_t size)
Definition: stream-tcp.c:228
STREAM_CLOSING_INVALID_ACK
@ STREAM_CLOSING_INVALID_ACK
Definition: decode-events.h:252
STREAMTCP_QUEUE_FLAG_WS
#define STREAMTCP_QUEUE_FLAG_WS
Definition: stream-tcp-private.h:31
TcpStateQueue_::next
struct TcpStateQueue_ * next
Definition: stream-tcp-private.h:43
host.h
StreamSegmentCallback
int(* StreamSegmentCallback)(const Packet *, TcpSegment *, void *, const uint8_t *, uint32_t)
Definition: stream.h:36
tm-threads.h
TCP_SYN_RECV
@ TCP_SYN_RECV
Definition: stream-tcp-private.h:154
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:399
TCPVars_::ao_option_present
uint8_t ao_option_present
Definition: decode-tcp.h:165
Packet_::proto
uint8_t proto
Definition: decode.h:498
TcpStream_
Definition: stream-tcp-private.h:106
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
TCPHdr_::th_dport
uint16_t th_dport
Definition: decode-tcp.h:151
TcpSession_::pstate
uint8_t pstate
Definition: stream-tcp-private.h:286
STREAMTCP_FLAG_CLIENT_SACKOK
#define STREAMTCP_FLAG_CLIENT_SACKOK
Definition: stream-tcp-private.h:190
StreamTcpSessionPktFree
void StreamTcpSessionPktFree(Packet *p)
Function to return the stream segments back to the pool.
Definition: stream-tcp.c:380
TcpStream_::isn
uint32_t isn
Definition: stream-tcp-private.h:113
EXCEPTION_POLICY_PASS_FLOW
@ EXCEPTION_POLICY_PASS_FLOW
Definition: util-exception-policy-types.h:29
TcpReassemblyThreadCtx_::counter_tcp_reas_eps
ExceptionPolicyCounters counter_tcp_reas_eps
Definition: stream-tcp-reassemble.h:69
TCP_STREAM_URGENT_DEFAULT
#define TCP_STREAM_URGENT_DEFAULT
Definition: stream-tcp.h:47
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:166
PoolThreadExpand
int PoolThreadExpand(PoolThread *pt)
expand pool by one for a new thread
Definition: util-pool-thread.c:97
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1266
STREAM_TIMEWAIT_INVALID_ACK
@ STREAM_TIMEWAIT_INVALID_ACK
Definition: decode-events.h:278
STREAM_3WHS_SYNACK_WITH_WRONG_ACK
@ STREAM_3WHS_SYNACK_WITH_WRONG_ACK
Definition: decode-events.h:235
TCP_HAS_TFO
#define TCP_HAS_TFO(p)
Definition: decode-tcp.h:97
stream-tcp-inline.h
IPV4Hdr_::ip_ttl
uint8_t ip_ttl
Definition: decode-ipv4.h:78
STREAM_DUMP_TOSERVER
#define STREAM_DUMP_TOSERVER
Definition: stream.h:33
StreamTcpUpdateNextSeq
#define StreamTcpUpdateNextSeq(ssn, stream, seq)
Definition: stream-tcp.c:1073
FlowGetPacketDirection
int FlowGetPacketDirection(const Flow *f, const Packet *p)
determine the direction of the packet compared to the flow
Definition: flow.c:277
FLOW_STATE_ESTABLISHED
@ FLOW_STATE_ESTABLISHED
Definition: flow.h:500
TCP_SYN_SENT
@ TCP_SYN_SENT
Definition: stream-tcp-private.h:153
flow-util.h
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
TCP_STREAM_URGENT_OOB
@ TCP_STREAM_URGENT_OOB
Definition: stream-tcp.h:49
STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT
#define STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT
Definition: stream-tcp-private.h:188
source-pcap-file.h
STREAMTCP_FLAG_SACKOK
#define STREAMTCP_FLAG_SACKOK
Definition: stream-tcp-private.h:192
PacketBypassCallback
void PacketBypassCallback(Packet *p)
Definition: decode.c:504
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1321
TcpSessionPacketSsnReuse
bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
Definition: stream-tcp.c:5920
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition: conf.c:482
ParseSizeStringU16
int ParseSizeStringU16(const char *size, uint16_t *res)
Definition: util-misc.c:156
stream-tcp.h
StreamTcpInlineMode
bool StreamTcpInlineMode(void)
See if stream engine is operating in inline mode.
Definition: stream-tcp.c:7092
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:49
StreamTcpThreadCacheGetSession
TcpSession * StreamTcpThreadCacheGetSession(void)
Definition: stream-tcp-cache.c:190
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
PKT_DROP_REASON_STREAM_MEMCAP
@ PKT_DROP_REASON_STREAM_MEMCAP
Definition: decode.h:371
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
STREAM_3WHS_ACK_DATA_INJECT
@ STREAM_3WHS_ACK_DATA_INJECT
Definition: decode-events.h:242
PKT_STREAM_MODIFIED
#define PKT_STREAM_MODIFIED
Definition: decode.h:1271
TcpStream_::seg_tree
struct TCPSEG seg_tree
Definition: stream-tcp-private.h:136
STREAM_4WHS_SYNACK_WITH_WRONG_SYN
@ STREAM_4WHS_SYNACK_WITH_WRONG_SYN
Definition: decode-events.h:244
PacketL4::csum
uint16_t csum
Definition: decode.h:442
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:595
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:190
STREAM_FIN1_ACK_WRONG_SEQ
@ STREAM_FIN1_ACK_WRONG_SEQ
Definition: decode-events.h:265
util-pool-thread.h
seq
uint32_t seq
Definition: stream-tcp-private.h:2
StatsRegisterGlobalCounter
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
Definition: counters.c:1009
StreamTcpThread_
Definition: stream-tcp.h:92
StreamTcpSetSessionNoReassemblyFlag
void StreamTcpSetSessionNoReassemblyFlag(TcpSession *ssn, char direction)
disable reassembly
Definition: stream-tcp.c:6683
StreamTcpThreadCacheReturnSession
void StreamTcpThreadCacheReturnSession(TcpSession *ssn)
Definition: stream-tcp-cache.c:93
StreamTcpSackFreeList
void StreamTcpSackFreeList(TcpStream *stream)
Free SACK tree from a stream.
Definition: stream-tcp-sack.c:438
TCP_FIN_WAIT2
@ TCP_FIN_WAIT2
Definition: stream-tcp-private.h:157
STREAM_PKT_INVALID_ACK
@ STREAM_PKT_INVALID_ACK
Definition: decode-events.h:281
StreamTcpGetFlowState
int StreamTcpGetFlowState(void *)
STREAM_PKT_RETRANSMISSION
@ STREAM_PKT_RETRANSMISSION
Definition: decode-events.h:285
STREAM_PKT_FLAG_DUP_ACK
#define STREAM_PKT_FLAG_DUP_ACK
Definition: stream-tcp-private.h:319
Packet_::payload
uint8_t * payload
Definition: decode.h:574
util-checksum.h
action-globals.h
TcpReassemblyThreadCtx_::app_tctx
void * app_tctx
Definition: stream-tcp-reassemble.h:62
Packet_::flags
uint32_t flags
Definition: decode.h:513
STREAM_FIN2_INVALID_ACK
@ STREAM_FIN2_INVALID_ACK
Definition: decode-events.h:270
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:181
STREAM_PKT_FLAG_KEEPALIVEACK
#define STREAM_PKT_FLAG_KEEPALIVEACK
Definition: stream-tcp-private.h:316
threads.h
TcpStreamCnf_::async_oneside
bool async_oneside
Definition: stream-tcp.h:71
StreamTcpSetOSPolicy
void StreamTcpSetOSPolicy(TcpStream *, Packet *)
Function to set the OS policy for the given stream based on the destination of the received packet.
Definition: stream-tcp.c:1007
StreamTcpInitMemuse
void StreamTcpInitMemuse(void)
Definition: stream-tcp.c:223
TH_RST
#define TH_RST
Definition: decode-tcp.h:36
TcpStream_::os_policy
uint8_t os_policy
Definition: stream-tcp-private.h:110
STREAMTCP_DEFAULT_MAX_SYN_QUEUED
#define STREAMTCP_DEFAULT_MAX_SYN_QUEUED
Definition: stream-tcp.c:90
TcpStreamCnf_::reassembly_depth
uint32_t reassembly_depth
Definition: stream-tcp.h:75
Packet_::vlan_idx
uint8_t vlan_idx
Definition: decode.h:504
Flow_
Flow data structure.
Definition: flow.h:354
TcpSegment::sbseg
StreamingBufferSegment sbseg
Definition: stream-tcp-private.h:77
TcpStreamCnf_::flags
uint8_t flags
Definition: stream-tcp.h:65
StreamTcpThread_::counter_tcp_ssn_from_cache
uint16_t counter_tcp_ssn_from_cache
Definition: stream-tcp.h:99
TcpReassemblyThreadCtx_::counter_tcp_stream_depth
uint16_t counter_tcp_stream_depth
Definition: stream-tcp-reassemble.h:75
STREAMTCP_FLAG_ZWP_TC
#define STREAMTCP_FLAG_ZWP_TC
Definition: stream-tcp-private.h:210
TCP_WSCALE_MAX
#define TCP_WSCALE_MAX
Definition: decode-tcp.h:69
TH_FIN
#define TH_FIN
Definition: decode-tcp.h:34
TCPHdr_::th_win
uint16_t th_win
Definition: decode-tcp.h:156
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
ExceptionPolicyStatsSetts_
Definition: util-exception-policy-types.h:48
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:51
StreamTcpThread_::counter_tcp_sessions
uint16_t counter_tcp_sessions
Definition: stream-tcp.h:96
STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK
@ STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK
Definition: decode-events.h:249
TCP_FIN_WAIT1
@ TCP_FIN_WAIT1
Definition: stream-tcp-private.h:156
TCP_LAST_ACK
@ TCP_LAST_ACK
Definition: stream-tcp-private.h:159
TcpStreamCnf_::sbcnf
StreamingBufferConfig sbcnf
Definition: stream-tcp.h:89
util-runmodes.h
STREAM_EST_PACKET_OUT_OF_WINDOW
@ STREAM_EST_PACKET_OUT_OF_WINDOW
Definition: decode-events.h:253
TcpStateQueue_::win
uint16_t win
Definition: stream-tcp-private.h:38
TCP_GET_RAW_HLEN
#define TCP_GET_RAW_HLEN(tcph)
Definition: decode-tcp.h:72
IPV4Hdr_::ip_id
uint16_t ip_id
Definition: decode-ipv4.h:76
STREAM_PKT_FLAG_RETRANSMISSION
#define STREAM_PKT_FLAG_RETRANSMISSION
Definition: stream-tcp-private.h:312
pool_id
PoolThreadId pool_id
Definition: stream-tcp-private.h:0
StreamTcpThreadInit
TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
Definition: stream-tcp.c:5970
STREAM_4WHS_INVALID_ACK
@ STREAM_4WHS_INVALID_ACK
Definition: decode-events.h:246
STREAM_RST_INVALID_ACK
@ STREAM_RST_INVALID_ACK
Definition: decode-events.h:283
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint64_t, st_memuse)
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:231
RB_MIN
#define RB_MIN(name, x)
Definition: tree.h:778
TCP_ESTABLISHED
@ TCP_ESTABLISHED
Definition: stream-tcp-private.h:155
IPV4Hdr_::ip_tos
uint8_t ip_tos
Definition: decode-ipv4.h:74
TcpReassemblyThreadCtx_::counter_tcp_reass_overlap
uint16_t counter_tcp_reass_overlap
Definition: stream-tcp-reassemble.h:80
StreamTcpUpdateAppLayerProgress
void StreamTcpUpdateAppLayerProgress(TcpSession *ssn, char direction, const uint32_t progress)
update reassembly progress
Definition: stream-tcp.c:6663
TcpStreamCnf_::max_syn_queued
uint8_t max_syn_queued
Definition: stream-tcp.h:73
STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED
#define STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED
Definition: stream-tcp-private.h:172
util-privs.h
stream-tcp-reassemble.h
TcpSegment::seq
uint32_t seq
Definition: stream-tcp-private.h:75
STREAM_FIN1_FIN_WRONG_SEQ
@ STREAM_FIN1_FIN_WRONG_SEQ
Definition: decode-events.h:266
TcpStream_::flags
uint16_t flags
Definition: stream-tcp-private.h:107
TcpStreamCnf_
Definition: stream-tcp.h:54
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
STREAMTCP_STREAM_FLAG_KEEPALIVE
#define STREAMTCP_STREAM_FLAG_KEEPALIVE
Definition: stream-tcp-private.h:221
TcpStateQueue_::flags
uint8_t flags
Definition: stream-tcp-private.h:36
StreamTcpStreamCleanup
void StreamTcpStreamCleanup(TcpStream *stream)
Definition: stream-tcp.c:300
RandomGet
long int RandomGet(void)
Definition: util-random.c:130
PoolThreadFree
void PoolThreadFree(PoolThread *pt)
destroy the thread pool
Definition: util-pool-thread.c:155
TcpReassemblyThreadCtx_::counter_tcp_reass_overlap_diff_data
uint16_t counter_tcp_reass_overlap_diff_data
Definition: stream-tcp-reassemble.h:82
TCP_STREAM_URGENT_GAP
@ TCP_STREAM_URGENT_GAP
Definition: stream-tcp.h:50
PKT_STREAM_NO_EVENTS
#define PKT_STREAM_NO_EVENTS
Definition: decode.h:1312
STREAM_4WHS_SYNACK_WITH_WRONG_ACK
@ STREAM_4WHS_SYNACK_WITH_WRONG_ACK
Definition: decode-events.h:243
PKT_NOPAYLOAD_INSPECTION
#define PKT_NOPAYLOAD_INSPECTION
Definition: decode.h:1255
Flow_::dp
Port dp
Definition: flow.h:370
TCP_GET_SACKOK
#define TCP_GET_SACKOK(p)
Definition: decode-tcp.h:102
TcpStreamCnf_::midstream_policy
enum ExceptionPolicy midstream_policy
Definition: stream-tcp.h:82
STREAM_PKT_BAD_WINDOW_UPDATE
@ STREAM_PKT_BAD_WINDOW_UPDATE
Definition: decode-events.h:287
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:507
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
STREAM_3WHS_SYNACK_TFO_DATA_IGNORED
@ STREAM_3WHS_SYNACK_TFO_DATA_IGNORED
Definition: decode-events.h:237
Flow_::protoctx
void * protoctx
Definition: flow.h:439
STREAMTCP_INIT_FLAG_DROP_INVALID
#define STREAMTCP_INIT_FLAG_DROP_INVALID
Definition: stream-tcp.h:39
TCP_GET_RAW_WINDOW
#define TCP_GET_RAW_WINDOW(tcph)
Definition: decode-tcp.h:83
EXCEPTION_POLICY_NOT_SET
@ EXCEPTION_POLICY_NOT_SET
Definition: util-exception-policy-types.h:26
ExceptionPolicyParse
enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow)
Definition: util-exception-policy.c:232
TcpStateQueue_
Definition: stream-tcp-private.h:35
GET_PKT_DIRECT_MAX_SIZE
#define GET_PKT_DIRECT_MAX_SIZE(p)
Definition: decode.h:207
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:98
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:575
PacketQueueNoLock_
simple fifo queue for packets
Definition: packet-queue.h:34
STREAMTCP_STREAM_FLAG_DEPTH_REACHED
#define STREAMTCP_STREAM_FLAG_DEPTH_REACHED
Definition: stream-tcp-private.h:223
GET_IPV6_DST_ADDR
#define GET_IPV6_DST_ADDR(p)
Definition: decode.h:200
util-unittest.h
STREAM_PKT_INVALID_TIMESTAMP
@ STREAM_PKT_INVALID_TIMESTAMP
Definition: decode-events.h:280
STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW
@ STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW
Definition: decode-events.h:247
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:80
STREAMTCP_FLAG_TFO_DATA_IGNORED
#define STREAMTCP_FLAG_TFO_DATA_IGNORED
Definition: stream-tcp-private.h:207
TCP_GET_WSCALE
#define TCP_GET_WSCALE(p)
Definition: decode-tcp.h:100
FLOW_COPY_IPV6_ADDR_TO_PACKET
#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa)
Definition: flow.h:183
StreamTcpReassembleInit
int StreamTcpReassembleInit(bool quiet)
Definition: stream-tcp-reassemble.c:524
PKT_DROP_REASON_STREAM_URG
@ PKT_DROP_REASON_STREAM_URG
Definition: decode.h:374
TcpState
TcpState
Definition: stream-tcp-private.h:150
STREAMTCP_FLAG_MIDSTREAM
#define STREAMTCP_FLAG_MIDSTREAM
Definition: stream-tcp-private.h:170
STREAMTCP_FLAG_LOSSY_BE_LIBERAL
#define STREAMTCP_FLAG_LOSSY_BE_LIBERAL
Definition: stream-tcp-private.h:194
StreamTcpUpdateLastAck
#define StreamTcpUpdateLastAck(ssn, stream, ack)
macro to update last_ack only if the new value is higher
Definition: stream-tcp.c:1045
TCPHdr_::th_ack
uint32_t th_ack
Definition: decode-tcp.h:153
TcpSession_::flags
uint32_t flags
Definition: stream-tcp-private.h:294
TcpSession_::queue
TcpStateQueue * queue
Definition: stream-tcp-private.h:298
Packet_::datalink
int datalink
Definition: decode.h:608
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1325
DLT_RAW
#define DLT_RAW
Definition: decode.h:1222
StreamTcpThread_::counter_tcp_ssn_memcap
uint16_t counter_tcp_ssn_memcap
Definition: stream-tcp.h:98
TcpReassemblyThreadCtx_::counter_tcp_reass_data_normal_fail
uint16_t counter_tcp_reass_data_normal_fail
Definition: stream-tcp-reassemble.h:84
TcpStream_::last_ack
uint32_t last_ack
Definition: stream-tcp-private.h:115
IPV4Hdr_::ip_len
uint16_t ip_len
Definition: decode-ipv4.h:75
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:335
Flow_::dst
FlowAddress dst
Definition: flow.h:357
SET_PKT_LEN
#define SET_PKT_LEN(p, len)
Definition: decode.h:209
StreamTcpReassembleInitThreadCtx
TcpReassemblyThreadCtx * StreamTcpReassembleInitThreadCtx(ThreadVars *tv)
Definition: stream-tcp-reassemble.c:558
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:488
TCPHdr_::th_sport
uint16_t th_sport
Definition: decode-tcp.h:150
TCP_NONE
@ TCP_NONE
Definition: stream-tcp-private.h:151
TcpSession_::reassembly_depth
uint32_t reassembly_depth
Definition: stream-tcp-private.h:295
TCP_CLOSE_WAIT
@ TCP_CLOSE_WAIT
Definition: stream-tcp-private.h:160
TCP_GET_TSVAL
#define TCP_GET_TSVAL(p)
Definition: decode-tcp.h:88
TcpStream_::last_ts
uint32_t last_ts
Definition: stream-tcp-private.h:119
TCPHdr_::th_flags
uint8_t th_flags
Definition: decode-tcp.h:155
decode.h
TcpStreamCnf_::ssn_memcap_policy
enum ExceptionPolicy ssn_memcap_policy
Definition: stream-tcp.h:80
util-device.h
util-debug.h
PKT_SRC_WIRE
@ PKT_SRC_WIRE
Definition: decode.h:51
SCHInfoGetIPv6HostOSFlavour
int SCHInfoGetIPv6HostOSFlavour(uint8_t *addr)
Retrieves the host os flavour, given an ipv6 address in the raw address format.
Definition: util-host-os-info.c:261
TOSERVER
#define TOSERVER
Definition: flow.h:45
STREAM_3WHS_SYNACK_FLOOD
@ STREAM_3WHS_SYNACK_FLOOD
Definition: decode-events.h:236
StreamTcpCheckMemcap
int StreamTcpCheckMemcap(uint64_t size)
Check if alloc'ing "size" would mean we're over memcap.
Definition: stream-tcp.c:266
GET_IPV4_DST_ADDR_PTR
#define GET_IPV4_DST_ADDR_PTR(p)
Definition: decode.h:195
STREAM_CLOSEWAIT_INVALID_ACK
@ STREAM_CLOSEWAIT_INVALID_ACK
Definition: decode-events.h:250
TcpStateQueue_::seq
uint32_t seq
Definition: stream-tcp-private.h:39
PKT_IS_TOSERVER
#define PKT_IS_TOSERVER(p)
Definition: decode.h:234
STREAM_FIN_SYN
@ STREAM_FIN_SYN
Definition: decode-events.h:273
STREAMTCP_FLAG_ASYNC
#define STREAMTCP_FLAG_ASYNC
Definition: stream-tcp-private.h:182
TCPHdr_::th_seq
uint32_t th_seq
Definition: decode-tcp.h:152
STREAM_3WHS_WRONG_SEQ_WRONG_ACK
@ STREAM_3WHS_WRONG_SEQ_WRONG_ACK
Definition: decode-events.h:241
STREAMTCP_FLAG_BYPASS
#define STREAMTCP_FLAG_BYPASS
Definition: stream-tcp-private.h:203
Packet_::ts
SCTime_t ts
Definition: decode.h:524
TcpStreamCnf_::urgent_policy
enum TcpStreamUrgentHandling urgent_policy
Definition: stream-tcp.h:83
STREAM_EST_SYN_TOCLIENT
@ STREAM_EST_SYN_TOCLIENT
Definition: decode-events.h:261
StreamTcpSegmentForSession
int StreamTcpSegmentForSession(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
Run callback function on each TCP segment in both directions of a session.
Definition: stream-tcp.c:6998
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
TCPHdr_::th_offx2
uint8_t th_offx2
Definition: decode-tcp.h:154
TcpSegmentPcapHdrStorage_::ts
SCTime_t ts
Definition: stream-tcp-private.h:66
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1268
PacketSwap
void PacketSwap(Packet *p)
switch direction of a packet
Definition: decode.c:551
STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK
@ STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK
Definition: decode-events.h:232
util-exception-policy.h
OS_POLICY_VISTA
@ OS_POLICY_VISTA
Definition: stream-tcp-reassemble.h:48
STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW
@ STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW
Definition: decode-events.h:248
BOOL2STR
#define BOOL2STR(b)
Definition: util-debug.h:527
TcpSession_::pool_id
PoolThreadId pool_id
Definition: stream-tcp-private.h:284
STREAMTCP_STREAM_FLAG_RST_RECV
#define STREAMTCP_STREAM_FLAG_RST_RECV
Definition: stream-tcp-private.h:240
ExceptionPolicyCounters_::eps_id
uint16_t eps_id[EXCEPTION_POLICY_MAX]
Definition: util-exception-policy-types.h:45
util-print.h
STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE
#define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE
Definition: stream-tcp.c:89
OS_POLICY_IRIX
@ OS_POLICY_IRIX
Definition: stream-tcp-reassemble.h:45
StreamTcpThread_::counter_tcp_wrong_thread
uint16_t counter_tcp_wrong_thread
Definition: stream-tcp.h:112
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:205
ExceptionPolicySetStatsCounters
void ExceptionPolicySetStatsCounters(ThreadVars *tv, ExceptionPolicyCounters *counter, ExceptionPolicyStatsSetts *setting, enum ExceptionPolicy conf_policy, const char *default_str, bool(*isExceptionPolicyValid)(enum ExceptionPolicy))
Definition: util-exception-policy.c:298
detect.h
StreamTcpThread_::counter_tcp_invalid_checksum
uint16_t counter_tcp_invalid_checksum
Definition: stream-tcp.h:106
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
StreamTcp
TmEcode StreamTcp(ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq)
Definition: stream-tcp.c:5932
stream_memcap_eps_stats
ExceptionPolicyStatsSetts stream_memcap_eps_stats
Definition: stream-tcp.c:95
StreamingBufferClear
void StreamingBufferClear(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
Definition: util-streaming-buffer.c:271
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:40
pkt-var.h
PacketL4::L4Vars::tcp
TCPVars tcp
Definition: decode.h:453
StreamTcpPacket
int StreamTcpPacket(ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueueNoLock *pq)
Definition: stream-tcp.c:5527
Packet_::sp
Port sp
Definition: decode.h:483
TCP_GET_TSECR
#define TCP_GET_TSECR(p)
Definition: decode-tcp.h:91
STREAM_EST_ACK_ZWP_DATA
@ STREAM_EST_ACK_ZWP_DATA
Definition: decode-events.h:263
TcpSession_::state
uint8_t state
Definition: stream-tcp-private.h:285
FLOW_WRONG_THREAD
#define FLOW_WRONG_THREAD
Definition: flow.h:108
PAWS_24DAYS
#define PAWS_24DAYS
Definition: stream-tcp-private.h:247
PktSrcToString
const char * PktSrcToString(enum PktSrcEnum pkt_src)
Definition: decode.c:825
ExceptionPolicyStatsSetts_::valid_settings_ids
bool valid_settings_ids[EXCEPTION_POLICY_MAX]
Definition: util-exception-policy-types.h:50
TCPHdr_::th_urp
uint16_t th_urp
Definition: decode-tcp.h:158
TH_ACK
#define TH_ACK
Definition: decode-tcp.h:38
util-time.h
STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE_ACK
#define STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE_ACK
Definition: stream-tcp-private.h:324
TcpSession_::tcp_packet_flags
uint8_t tcp_packet_flags
Definition: stream-tcp-private.h:290
StreamTcpSegmentForEach
int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
Definition: stream-tcp.c:6939
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
STREAM_RST_BUT_NO_SESSION
@ STREAM_RST_BUT_NO_SESSION
Definition: decode-events.h:276
STREAM_PKT_FLAG_STATE_UPDATE
#define STREAM_PKT_FLAG_STATE_UPDATE
Definition: stream-tcp-private.h:314
app-layer-parser.h
STREAMTCP_STREAM_FLAG_TIMESTAMP
#define STREAMTCP_STREAM_FLAG_TIMESTAMP
Definition: stream-tcp-private.h:228
ThreadVars_::id
int id
Definition: threadvars.h:87
STREAM_SUSPECTED_RST_INJECT
@ STREAM_SUSPECTED_RST_INJECT
Definition: decode-events.h:289
TcpStream_::next_win
uint32_t next_win
Definition: stream-tcp-private.h:116
stream_config
TcpStreamCnf stream_config
Definition: stream-tcp.c:219
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:309
FLOW_IS_IPV4
#define FLOW_IS_IPV4(f)
Definition: flow.h:168
RB_FOREACH
#define RB_FOREACH(x, name, head)
Definition: tree.h:781
TcpStreamCnf_::liberal_timestamps
bool liberal_timestamps
Definition: stream-tcp.h:87
ExceptionPolicyMidstreamParse
enum ExceptionPolicy ExceptionPolicyMidstreamParse(bool midstream_enabled)
Definition: util-exception-policy.c:257
util-profiling.h
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:341
PacketCallocExtPkt
int PacketCallocExtPkt(Packet *p, int datalen)
Definition: decode.c:283
StreamTcpSessionClear
void StreamTcpSessionClear(void *ssnptr)
Function to return the stream back to the pool. It returns the segments in the stream to the segment ...
Definition: stream-tcp.c:351
FlowThreadId
uint16_t FlowThreadId
Definition: flow.h:331
SCReturn
#define SCReturn
Definition: util-debug.h:273
PKT_SRC_STREAM_TCP_DETECTLOG_FLUSH
@ PKT_SRC_STREAM_TCP_DETECTLOG_FLUSH
Definition: decode.h:58
STREAMTCP_QUEUE_FLAG_SACK
#define STREAMTCP_QUEUE_FLAG_SACK
Definition: stream-tcp-private.h:32
stream.h
t_pcapcnt
thread_local uint64_t t_pcapcnt
Definition: stream-tcp-reassemble.c:80
STREAM_EST_SYNACK_TOSERVER
@ STREAM_EST_SYNACK_TOSERVER
Definition: decode-events.h:258
TcpStreamCnf_::max_synack_queued
uint8_t max_synack_queued
Definition: stream-tcp.h:66
TcpSegment
Definition: stream-tcp-private.h:72
IPV6Hdr_
Definition: decode-ipv6.h:32
Packet_
Definition: decode.h:476
conf-yaml-loader.h
StreamTcpSackUpdatePacket
int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p)
Update stream with SACK records from a TCP packet.
Definition: stream-tcp-sack.c:249
stream-tcp-sack.h
stream-tcp-private.h
TcpReassemblyThreadCtx_::counter_tcp_urgent_oob
uint16_t counter_tcp_urgent_oob
Definition: stream-tcp-reassemble.h:88
conf.h
Packet_::l4
struct PacketL4 l4
Definition: decode.h:570
DEBUG_ASSERT_FLOW_LOCKED
#define DEBUG_ASSERT_FLOW_LOCKED(f)
Definition: util-validate.h:99
STREAM_EST_INVALID_ACK
@ STREAM_EST_INVALID_ACK
Definition: decode-events.h:262
TCP_HAS_SACK
#define TCP_HAS_SACK(p)
Definition: decode-tcp.h:94
STREAM_PKT_SPURIOUS_RETRANSMISSION
@ STREAM_PKT_SPURIOUS_RETRANSMISSION
Definition: decode-events.h:286
PKT_DROP_REASON_STREAM_ERROR
@ PKT_DROP_REASON_STREAM_ERROR
Definition: decode.h:370
TcpStream_::window
uint32_t window
Definition: stream-tcp-private.h:117
PKT_IGNORE_CHECKSUM
#define PKT_IGNORE_CHECKSUM
Definition: decode.h:1282
TCP_HAS_TS
#define TCP_HAS_TS(p)
Definition: decode-tcp.h:95
Packet_::livedev
struct LiveDevice_ * livedev
Definition: decode.h:587
StreamTcpReassembleFreeThreadCtx
void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx)
Definition: stream-tcp-reassemble.c:597
TmEcode
TmEcode
Definition: tm-threads-common.h:79
Flow_::vlan_idx
uint8_t vlan_idx
Definition: flow.h:380
PcapIncreaseInvalidChecksum
void PcapIncreaseInvalidChecksum(void)
Definition: source-pcap-file.c:481
STREAM_PKT_FLAG_KEEPALIVE
#define STREAM_PKT_FLAG_KEEPALIVE
Definition: stream-tcp-private.h:315
StreamTcpThread_::counter_tcp_ssn_from_pool
uint16_t counter_tcp_ssn_from_pool
Definition: stream-tcp.h:100
STREAMTCP_DEFAULT_MEMCAP
#define STREAMTCP_DEFAULT_MEMCAP
Definition: stream-tcp.c:86
STREAM_FIN_INVALID_ACK
@ STREAM_FIN_INVALID_ACK
Definition: decode-events.h:264
FLOW_PKT_TOCLIENT
#define FLOW_PKT_TOCLIENT
Definition: flow.h:232
TcpStreamCnf_::reassembly_memcap_policy
enum ExceptionPolicy reassembly_memcap_policy
Definition: stream-tcp.h:81
STREAM_FIN_OUT_OF_WINDOW
@ STREAM_FIN_OUT_OF_WINDOW
Definition: decode-events.h:272
OS_POLICY_SOLARIS
@ OS_POLICY_SOLARIS
Definition: stream-tcp-reassemble.h:42
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:255
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:37
STREAMING_BUFFER_INITIALIZER
#define STREAMING_BUFFER_INITIALIZER
Definition: util-streaming-buffer.h:137
StreamTcpReassembleFree
void StreamTcpReassembleFree(bool quiet)
Definition: stream-tcp-reassemble.c:540
TH_URG
#define TH_URG
Definition: decode-tcp.h:39
TcpReassemblyThreadCtx_::counter_tcp_reass_gap
uint16_t counter_tcp_reass_gap
Definition: stream-tcp-reassemble.h:77
WarnInvalidConfEntry
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition: util-misc.h:35
FlowUpdateState
void FlowUpdateState(Flow *f, const enum FlowState s)
Definition: flow.c:1146
Flow_::src
FlowAddress src
Definition: flow.h:357
util-host-os-info.h
OS_POLICY_BSD_RIGHT
@ OS_POLICY_BSD_RIGHT
Definition: stream-tcp-reassemble.h:38
ReCalculateChecksum
int ReCalculateChecksum(Packet *p)
Definition: util-checksum.c:29
StreamingBuffer_
Definition: util-streaming-buffer.h:108
STREAM_TIMEWAIT_ACK_WRONG_SEQ
@ STREAM_TIMEWAIT_ACK_WRONG_SEQ
Definition: decode-events.h:277
IPV4Hdr_
Definition: decode-ipv4.h:72
STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV
@ STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV
Definition: decode-events.h:234
SCTIME_CMP_LT
#define SCTIME_CMP_LT(a, b)
Definition: util-time.h:105
TCP_CLOSED
@ TCP_CLOSED
Definition: stream-tcp-private.h:162
TcpStateQueue_::wscale
uint8_t wscale
Definition: stream-tcp-private.h:37
stream_midstream_disabled_eps_stats
ExceptionPolicyStatsSetts stream_midstream_disabled_eps_stats
Definition: stream-tcp.c:173
STREAM_EST_PKT_BEFORE_LAST_ACK
@ STREAM_EST_PKT_BEFORE_LAST_ACK
Definition: decode-events.h:254
PacketEnqueueNoLock
void PacketEnqueueNoLock(PacketQueueNoLock *qnl, Packet *p)
Definition: packet-queue.c:168
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
StreamTcpSetMemcap
int StreamTcpSetMemcap(uint64_t size)
Update memcap value.
Definition: stream-tcp.c:279
STREAMTCP_FLAG_CLOSED_BY_RST
#define STREAMTCP_FLAG_CLOSED_BY_RST
Definition: stream-tcp-private.h:180
Packet_::tenant_id
uint32_t tenant_id
Definition: decode.h:634
Packet_::flow
struct Flow_ * flow
Definition: decode.h:515
STREAMTCP_FLAG_TIMESTAMP
#define STREAMTCP_FLAG_TIMESTAMP
Definition: stream-tcp-private.h:176
FlowSetProtoFreeFunc
int FlowSetProtoFreeFunc(uint8_t, void(*Free)(void *))
Function to set the function to get protocol specific flow state.
Definition: flow.c:1109
SEQ_GEQ
#define SEQ_GEQ(a, b)
Definition: stream-tcp-private.h:260
stream-tcp.c
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:859
TH_SYN
#define TH_SYN
Definition: decode-tcp.h:35
StreamTcpSackPacketIsOutdated
bool StreamTcpSackPacketIsOutdated(TcpStream *stream, Packet *p)
Definition: stream-tcp-sack.c:357
STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE
#define STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE
Definition: stream-tcp-private.h:323
STREAMTCP_SET_RA_BASE_SEQ
#define STREAMTCP_SET_RA_BASE_SEQ(stream, seq)
Definition: stream-tcp-private.h:264
StreamTcpDisableAppLayer
void StreamTcpDisableAppLayer(Flow *f)
Definition: stream-tcp-reassemble.c:448
suricata-common.h
SEQ_GT
#define SEQ_GT(a, b)
Definition: stream-tcp-private.h:259
FLOW_IPV6
#define FLOW_IPV6
Definition: flow.h:100
TcpStream_::base_seq
uint32_t base_seq
Definition: stream-tcp-private.h:124
STREAM_PKT_BROKEN_ACK
@ STREAM_PKT_BROKEN_ACK
Definition: decode-events.h:282
packet.h
TcpStreamCnf_::urgent_oob_limit_policy
enum TcpStreamUrgentHandling urgent_oob_limit_policy
Definition: stream-tcp.h:84
PKT_STREAM_NOPCAPLOG
#define PKT_STREAM_NOPCAPLOG
Definition: decode.h:1277
TcpStream_::sb
StreamingBuffer sb
Definition: stream-tcp-private.h:135
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
StreamTcpThread_::counter_tcp_active_sessions
uint16_t counter_tcp_active_sessions
Definition: stream-tcp.h:95
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP
#define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP
Definition: stream-tcp.c:87
STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK
@ STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK
Definition: decode-events.h:256
STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ
@ STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ
Definition: decode-events.h:257
TcpStreamCnf_::prealloc_sessions
uint32_t prealloc_sessions
Definition: stream-tcp.h:68
STREAM_EST_SYNACK_RESEND
@ STREAM_EST_SYNACK_RESEND
Definition: decode-events.h:255
STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION
@ STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION
Definition: decode-events.h:230
STREAM_LASTACK_ACK_WRONG_SEQ
@ STREAM_LASTACK_ACK_WRONG_SEQ
Definition: decode-events.h:274
FatalError
#define FatalError(...)
Definition: util-debug.h:502
STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
Definition: stream-tcp-private.h:236
TCPVars_::md5_option_present
uint8_t md5_option_present
Definition: decode-tcp.h:164
STREAMTCP_FLAG_MIDSTREAM_SYNACK
#define STREAMTCP_FLAG_MIDSTREAM_SYNACK
Definition: stream-tcp-private.h:174
STREAM_LASTACK_INVALID_ACK
@ STREAM_LASTACK_INVALID_ACK
Definition: decode-events.h:275
TcpSession_::client
TcpStream client
Definition: stream-tcp-private.h:297
StreamTcpReassembleHandleSegment
int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
Definition: stream-tcp-reassemble.c:2000
TCP_CLOSING
@ TCP_CLOSING
Definition: stream-tcp-private.h:161
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
ParseSizeStringU32
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:173
Flow_::livedev
struct LiveDevice_ * livedev
Definition: flow.h:396
TCP_STREAM_URGENT_DROP
@ TCP_STREAM_URGENT_DROP
Definition: stream-tcp.h:48
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:44
STREAM_WRONG_THREAD
@ STREAM_WRONG_THREAD
Definition: decode-events.h:290
TcpStreamCnf_::midstream
bool midstream
Definition: stream-tcp.h:70
TcpStreamCnf_::reassembly_toclient_chunk_size
uint16_t reassembly_toclient_chunk_size
Definition: stream-tcp.h:78
TcpStream_::next_seq
uint32_t next_seq
Definition: stream-tcp-private.h:114
threadvars.h
util-validate.h
FlowSwap
void FlowSwap(Flow *f)
swap the flow's direction
Definition: flow.c:244
OS_POLICY_OLD_SOLARIS
@ OS_POLICY_OLD_SOLARIS
Definition: stream-tcp-reassemble.h:41
StreamTcpDetectLogFlush
void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p, PacketQueueNoLock *pq)
create packets in both directions to flush out logging and detection before switching protocols....
Definition: stream-tcp.c:6915
STREAM_RST_WITH_DATA
@ STREAM_RST_WITH_DATA
Definition: decode-events.h:284
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
TcpSession_::server
TcpStream server
Definition: stream-tcp-private.h:296
FLOW_STATE_CLOSED
@ FLOW_STATE_CLOSED
Definition: flow.h:501
stream_midstream_enabled_eps_stats
ExceptionPolicyStatsSetts stream_midstream_enabled_eps_stats
Definition: stream-tcp.c:147
STREAM_PKT_FLAG_ACK_UNSEEN_DATA
#define STREAM_PKT_FLAG_ACK_UNSEEN_DATA
Definition: stream-tcp-private.h:321
PKT_PSEUDO_DETECTLOG_FLUSH
#define PKT_PSEUDO_DETECTLOG_FLUSH
Definition: decode.h:1308
OS_POLICY_MACOS
@ OS_POLICY_MACOS
Definition: stream-tcp-reassemble.h:46
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
STREAMTCP_QUEUE_FLAG_TS
#define STREAMTCP_QUEUE_FLAG_TS
Definition: stream-tcp-private.h:30
STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED
#define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED
Definition: stream-tcp.c:91
TcpSegment::pcap_hdr_storage
TcpSegmentPcapHdrStorage * pcap_hdr_storage
Definition: stream-tcp-private.h:78
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Packet_::pkt_src
uint8_t pkt_src
Definition: decode.h:580
ExceptionPolicyStatsSetts_::valid_settings_ips
bool valid_settings_ips[EXCEPTION_POLICY_MAX]
Definition: util-exception-policy-types.h:51
TcpSessionSetReassemblyDepth
void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
Definition: stream-tcp.c:7098
STREAM_PKT_FLAG_SPURIOUS_RETRANSMISSION
#define STREAM_PKT_FLAG_SPURIOUS_RETRANSMISSION
Definition: stream-tcp-private.h:313
SEQ_LT
#define SEQ_LT(a, b)
Definition: stream-tcp-private.h:257
Flow_::flags
uint32_t flags
Definition: flow.h:419
TcpStream_::app_progress_rel
uint32_t app_progress_rel
Definition: stream-tcp-private.h:127
StreamTcpSessionCleanup
void StreamTcpSessionCleanup(TcpSession *ssn)
Session cleanup function. Does not free the ssn.
Definition: stream-tcp.c:327
TcpReassemblyThreadCtx_::counter_tcp_reass_data_overlap_fail
uint16_t counter_tcp_reass_data_overlap_fail
Definition: stream-tcp-reassemble.h:85
TcpStateQueue_::ts
uint32_t ts
Definition: stream-tcp-private.h:41
stream_reassembly_memcap_eps_stats
ExceptionPolicyStatsSetts stream_reassembly_memcap_eps_stats
Definition: stream-tcp.c:121
StreamTcpMemuseCounter
uint64_t StreamTcpMemuseCounter(void)
Definition: stream-tcp.c:254
StreamTcpUpdateNextWin
#define StreamTcpUpdateNextWin(ssn, stream, win)
macro to update next_win only if the new value is higher
Definition: stream-tcp.c:1086
PoolThread_
Definition: util-pool-thread.h:53
TcpStateQueue_::pkt_ts
uint32_t pkt_ts
Definition: stream-tcp-private.h:42
STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION
@ STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION
Definition: decode-events.h:231
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:47
stream-tcp-cache.h
OS_POLICY_FIRST
@ OS_POLICY_FIRST
Definition: stream-tcp-reassemble.h:50
TcpStream_::last_pkt_ts
uint32_t last_pkt_ts
Definition: stream-tcp-private.h:120
stream-tcp-util.h
TCP_TIME_WAIT
@ TCP_TIME_WAIT
Definition: stream-tcp-private.h:158
PacketPoolGetPacket
Packet * PacketPoolGetPacket(void)
Get a new packet from the packet pool.
Definition: tmqh-packetpool.c:127
SEQ_EQ
#define SEQ_EQ(a, b)
Definition: stream-tcp-private.h:256
STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV
@ STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV
Definition: decode-events.h:238
util-random.h
StreamTcpThread_::counter_tcp_pseudo
uint16_t counter_tcp_pseudo
Definition: stream-tcp.h:104
StreamTcpThreadCacheEnable
void StreamTcpThreadCacheEnable(void)
enable segment cache. Should only be done for worker threads
Definition: stream-tcp-cache.c:48
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:233
SCHInfoGetIPv4HostOSFlavour
int SCHInfoGetIPv4HostOSFlavour(uint8_t *addr)
Retrieves the host os flavour, given an ipv4 address in the raw address format.
Definition: util-host-os-info.c:244
StreamTcpGetMemcap
uint64_t StreamTcpGetMemcap(void)
Return memcap value.
Definition: stream-tcp.c:294
StreamTcpThread_::ra_ctx
TcpReassemblyThreadCtx * ra_ctx
Definition: stream-tcp.h:117
TcpStreamCnf_::stream_init_flags
uint16_t stream_init_flags
Definition: stream-tcp.h:62
StreamTcpReturnStreamSegments
void StreamTcpReturnStreamSegments(TcpStream *)
return all segments in this stream into the pool(s)
Definition: stream-tcp-reassemble.c:398
PoolThreadId
uint16_t PoolThreadId
Definition: util-pool-thread.h:60
STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP
#define STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP
Definition: stream-tcp-private.h:230
TcpSession_::queue_len
uint8_t queue_len
Definition: stream-tcp-private.h:287
app-layer-protos.h
PacketDrop
void PacketDrop(Packet *p, const uint8_t action, enum PacketDropReason r)
issue drop action
Definition: packet.c:33
PoolThreadGetById
void * PoolThreadGetById(PoolThread *pt, uint16_t id)
get data from thread pool by thread id
Definition: util-pool-thread.c:173
StreamTcpThread_::counter_tcp_ssn_memcap_eps
ExceptionPolicyCounters counter_tcp_ssn_memcap_eps
Definition: stream-tcp.h:102
AppLayerProfilingReset
#define AppLayerProfilingReset(app_tctx)
Definition: app-layer.h:127
app-layer-htp-mem.h
EngineModeIsIPS
int EngineModeIsIPS(void)
Definition: suricata.c:232
g_detect_disabled
int g_detect_disabled
Definition: suricata.c:183
STREAM_PKT_FLAG_SET
#define STREAM_PKT_FLAG_SET(p, f)
Definition: stream-tcp-private.h:326
STREAMTCP_FLAG_APP_LAYER_DISABLED
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
Definition: stream-tcp-private.h:201
STREAMTCP_STREAM_FLAG_NOREASSEMBLY
#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY
Definition: stream-tcp-private.h:219
suricata.h
Packet_::dst
Address dst
Definition: decode.h:481
STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE
#define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE
Definition: stream-tcp.c:88
StreamTcpStateAsString
const char * StreamTcpStateAsString(const enum TcpState state)
Definition: stream-tcp.c:7105
Flow_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: flow.h:378
STREAMTCP_FLAG_3WHS_CONFIRMED
#define STREAMTCP_FLAG_3WHS_CONFIRMED
Definition: stream-tcp-private.h:199
STREAM_FIN2_ACK_WRONG_SEQ
@ STREAM_FIN2_ACK_WRONG_SEQ
Definition: decode-events.h:268
STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION
#define STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION
Definition: stream-tcp.h:38
SEQ_LEQ
#define SEQ_LEQ(a, b)
Definition: stream-tcp-private.h:258
STREAM_SHUTDOWN_SYN_RESEND
@ STREAM_SHUTDOWN_SYN_RESEND
Definition: decode-events.h:279
PKT_NOPACKET_INSPECTION
#define PKT_NOPACKET_INSPECTION
Definition: decode.h:1250
TCP_HAS_WSCALE
#define TCP_HAS_WSCALE(p)
Definition: decode-tcp.h:93
TcpReassemblyThreadCtx_::counter_tcp_segment_from_pool
uint16_t counter_tcp_segment_from_pool
Definition: stream-tcp-reassemble.h:72
STREAMTCP_STREAM_FLAG_DISABLE_RAW
#define STREAMTCP_STREAM_FLAG_DISABLE_RAW
Definition: stream-tcp-private.h:238
Packet_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: decode.h:503
TCP_STREAM_URGENT_INLINE
@ TCP_STREAM_URGENT_INLINE
Definition: stream-tcp.h:46
likely
#define likely(expr)
Definition: util-optimize.h:32
TcpStreamUrgentHandling
TcpStreamUrgentHandling
Definition: stream-tcp.h:45
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:39
STREAM_APP_PROGRESS
#define STREAM_APP_PROGRESS(stream)
Definition: stream-tcp-private.h:145
STREAMTCP_FLAG_ZWP_TS
#define STREAMTCP_FLAG_ZWP_TS
Definition: stream-tcp-private.h:209
OS_POLICY_DEFAULT
#define OS_POLICY_DEFAULT
Definition: stream-tcp-reassemble.h:91
IPV4Hdr_::ip_off
uint16_t ip_off
Definition: decode-ipv4.h:77
Flow_::sp
Port sp
Definition: flow.h:359
STREAMTCP_FLAG_4WHS
#define STREAMTCP_FLAG_4WHS
Definition: stream-tcp-private.h:185
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
STREAM_EST_SYN_RESEND
@ STREAM_EST_SYN_RESEND
Definition: decode-events.h:259
TcpSession_
Definition: stream-tcp-private.h:283
StreamTcpSsnStateAsString
const char * StreamTcpSsnStateAsString(const TcpSession *ssn)
Definition: stream-tcp.c:7146
StreamTcpThread_::ssn_pool_id
int ssn_pool_id
Definition: stream-tcp.h:93
util-misc.h
STREAM_3WHS_SYN_FLOOD
@ STREAM_3WHS_SYN_FLOOD
Definition: decode-events.h:240
STREAM_FIN2_FIN_WRONG_SEQ
@ STREAM_FIN2_FIN_WRONG_SEQ
Definition: decode-events.h:269
flow.h
PKT_DROP_REASON_STREAM_MIDSTREAM
@ PKT_DROP_REASON_STREAM_MIDSTREAM
Definition: decode.h:372
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:237
StreamingBufferSegmentGetData
void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, const uint8_t **data, uint32_t *data_len)
Definition: util-streaming-buffer.c:1766
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:448
Packet_::dp
Port dp
Definition: decode.h:491
ExceptionPolicy
ExceptionPolicy
Definition: util-exception-policy-types.h:25
StatsRegisterCounter
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:951
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:43
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
ssn_pool
PoolThread * ssn_pool
Definition: stream-tcp.c:213
STREAMTCP_STREAM_FLAG_TRIGGER_RAW
#define STREAMTCP_STREAM_FLAG_TRIGGER_RAW
Definition: stream-tcp-private.h:225
IPV4Hdr_::ip_proto
uint8_t ip_proto
Definition: decode-ipv4.h:79
PoolThreadSize
int PoolThreadSize(PoolThread *pt)
get size of PoolThread (number of 'threads', so array elements)
Definition: util-pool-thread.c:148
TCP_GET_RAW_ACK
#define TCP_GET_RAW_ACK(tcph)
Definition: decode-tcp.h:81
util-pool.h
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:120
STREAM_FIN1_INVALID_ACK
@ STREAM_FIN1_INVALID_ACK
Definition: decode-events.h:267
StreamTcpDecrMemuse
void StreamTcpDecrMemuse(uint64_t size)
Definition: stream-tcp.c:234
STREAM_3WHS_ASYNC_WRONG_SEQ
@ STREAM_3WHS_ASYNC_WRONG_SEQ
Definition: decode-events.h:229
TOCLIENT
#define TOCLIENT
Definition: flow.h:46
StreamTcpThread_::counter_tcp_ack_unseen_data
uint16_t counter_tcp_ack_unseen_data
Definition: stream-tcp.h:114
STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV
@ STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV
Definition: decode-events.h:239
TcpStream_::tcp_flags
uint8_t tcp_flags
Definition: stream-tcp-private.h:111
IPV4Hdr_::ip_verhl
uint8_t ip_verhl
Definition: decode-ipv4.h:73
StreamTcpReassembleMemuseGlobalCounter
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
Definition: stream-tcp-reassemble.c:150
TcpReassemblyThreadCtx_::counter_tcp_segment_memcap
uint16_t counter_tcp_segment_memcap
Definition: stream-tcp-reassemble.h:67
STREAMTCP_INIT_FLAG_BYPASS
#define STREAMTCP_INIT_FLAG_BYPASS
Definition: stream-tcp.h:40
StreamTcpThread_::counter_tcp_midstream_eps
ExceptionPolicyCounters counter_tcp_midstream_eps
Definition: stream-tcp.h:110
SCMutex
#define SCMutex
Definition: threads-debug.h:114
TcpStreamCnf_::reassembly_toserver_chunk_size
uint16_t reassembly_toserver_chunk_size
Definition: stream-tcp.h:77
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
STREAM_EST_SYN_RESEND_DIFF_SEQ
@ STREAM_EST_SYN_RESEND_DIFF_SEQ
Definition: decode-events.h:260
STREAM_FIN_BUT_NO_SESSION
@ STREAM_FIN_BUT_NO_SESSION
Definition: decode-events.h:271
STREAM_PKT_FLAG_WINDOWUPDATE
#define STREAM_PKT_FLAG_WINDOWUPDATE
Definition: stream-tcp-private.h:317
TCPHdr_
Definition: decode-tcp.h:149
Packet_::src
Address src
Definition: decode.h:480
Flow_::tenant_id
uint32_t tenant_id
Definition: flow.h:414
STREAM_4WHS_WRONG_SEQ
@ STREAM_4WHS_WRONG_SEQ
Definition: decode-events.h:245
TcpReassemblyThreadCtx_::counter_tcp_segment_from_cache
uint16_t counter_tcp_segment_from_cache
Definition: stream-tcp-reassemble.h:71
PacketL4::vars
union PacketL4::L4Vars vars
STREAMTCP_FLAG_TCP_FAST_OPEN
#define STREAMTCP_FLAG_TCP_FAST_OPEN
Definition: stream-tcp-private.h:205
TcpStream_::wscale
uint16_t wscale
Definition: stream-tcp-private.h:109
STREAMTCP_INIT_FLAG_INLINE
#define STREAMTCP_INIT_FLAG_INLINE
Definition: stream-tcp.h:41
StreamTcpThreadDeinit
TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data)
Definition: stream-tcp.c:6057
STREAMTCP_DEFAULT_PREALLOC
#define STREAMTCP_DEFAULT_PREALLOC
Definition: stream-tcp.c:85
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1263
Flow_::thread_id
FlowThreadId thread_id[2]
Definition: flow.h:392
TcpStateQueue_::ack
uint32_t ack
Definition: stream-tcp-private.h:40
app-layer.h
STREAMTCP_FLAG_SERVER_WSCALE
#define STREAMTCP_FLAG_SERVER_WSCALE
Definition: stream-tcp-private.h:178
FLOW_COPY_IPV4_ADDR_TO_PACKET
#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa)
Definition: flow.h:178
StreamTcpSetDisableRawReassemblyFlag
void StreamTcpSetDisableRawReassemblyFlag(TcpSession *ssn, char direction)
Set the No reassembly flag for the given direction in given TCP session.
Definition: stream-tcp.c:6699
STREAM_CLOSING_ACK_WRONG_SEQ
@ STREAM_CLOSING_ACK_WRONG_SEQ
Definition: decode-events.h:251
StreamTcpSetSessionBypassFlag
void StreamTcpSetSessionBypassFlag(TcpSession *ssn)
enable bypass
Definition: stream-tcp.c:6710
StreamTcpBypassEnabled
int StreamTcpBypassEnabled(void)
Definition: stream-tcp.c:7081