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