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