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