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