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