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 /**
3066  * \internal
3067  *
3068  * \brief Find the highest sequence number needed to consider all segments as ACK'd
3069  *
3070  * Used to treat all segments as ACK'd upon receiving a valid RST.
3071  *
3072  * \param stream stream to inspect the segments from
3073  * \param seq sequence number to check against
3074  *
3075  * \retval ack highest ack we need to set
3076  */
3077 static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
3078 {
3079  uint32_t ack = seq;
3080 
3081  if (STREAM_HAS_SEEN_DATA(stream)) {
3082  const uint32_t tail_seq = STREAM_SEQ_RIGHT_EDGE(stream);
3083  if (SEQ_GT(tail_seq, ack)) {
3084  ack = tail_seq;
3085  }
3086  }
3087 
3088  SCReturnUInt(ack);
3089 }
3090 
3091 static bool StreamTcpPacketIsZeroWindowProbeAck(const TcpSession *ssn, const Packet *p)
3092 {
3093  const TCPHdr *tcph = PacketGetTCP(p);
3094  if (ssn->state < TCP_ESTABLISHED)
3095  return false;
3096  if (p->payload_len != 0)
3097  return false;
3098  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3099  return false;
3100 
3101  const TcpStream *snd, *rcv;
3102  if (PKT_IS_TOCLIENT(p)) {
3103  snd = &ssn->server;
3104  rcv = &ssn->client;
3105  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TS))
3106  return false;
3107  } else {
3108  snd = &ssn->client;
3109  rcv = &ssn->server;
3110  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TC))
3111  return false;
3112  }
3113 
3114  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3115  if (pkt_win != 0)
3116  return false;
3117  if (pkt_win != rcv->window)
3118  return false;
3119 
3120  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3121  return false;
3122  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3123  return false;
3124  SCLogDebug("ssn %p: packet %" PRIu64 " is a Zero Window Probe ACK", ssn, p->pcap_cnt);
3125  return true;
3126 }
3127 
3128 /** \internal
3129  * \brief check if an ACK packet is a dup-ACK
3130  */
3131 static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p)
3132 {
3133  const TCPHdr *tcph = PacketGetTCP(p);
3134  if (ssn->state < TCP_ESTABLISHED)
3135  return false;
3136  if (p->payload_len != 0)
3137  return false;
3138  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3139  return false;
3140 
3141  const TcpStream *snd, *rcv;
3142  if (PKT_IS_TOCLIENT(p)) {
3143  snd = &ssn->server;
3144  rcv = &ssn->client;
3145  } else {
3146  snd = &ssn->client;
3147  rcv = &ssn->server;
3148  }
3149 
3150  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3151  if (pkt_win == 0 || rcv->window == 0)
3152  return false;
3153  if (pkt_win != rcv->window)
3154  return false;
3155 
3156  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3157  return false;
3158  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3159  return false;
3160 
3161  SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn,
3162  p->pcap_cnt, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph), pkt_win, snd->next_seq,
3163  snd->last_ack, rcv->window, snd->next_seq, rcv->last_ack, rcv->window);
3164  return true;
3165 }
3166 
3167 /** \internal
3168  * \brief check if a ACK packet is outdated so processing can be fast tracked
3169  *
3170  * Consider a packet outdated ack if:
3171  * - state is >= ESTABLISHED
3172  * - ACK < last_ACK
3173  * - SACK acks nothing new
3174  * - packet has no data
3175  * - SEQ == next_SEQ
3176  * - flags has ACK set but don't contain SYN/FIN/RST
3177  *
3178  * \todo the most likely explanation for this packet is that we already
3179  * accepted a "newer" ACK. We will not consider an outdated timestamp
3180  * option an issue for this packet, but we should probably still
3181  * check if the ts isn't too far off.
3182  */
3183 static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p)
3184 {
3185  const TCPHdr *tcph = PacketGetTCP(p);
3186  if (ssn->state < TCP_ESTABLISHED)
3187  return false;
3188  if (p->payload_len != 0)
3189  return false;
3190  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3191  return false;
3192 
3193  /* lets see if this is a packet that is entirely eclipsed by earlier ACKs */
3194  if (PKT_IS_TOSERVER(p)) {
3195  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
3196  SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->server.last_ack)) {
3197  if (!TCP_HAS_SACK(p)) {
3198  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3199  ssn->client.next_seq);
3200  return true;
3201  }
3202 
3203  if (StreamTcpSackPacketIsOutdated(&ssn->server, p)) {
3204  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3205  ssn->client.next_seq);
3206  return true;
3207  }
3208  }
3209  } else {
3210  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq) &&
3211  SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
3212  if (!TCP_HAS_SACK(p)) {
3213  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3214  ssn->client.next_seq);
3215  return true;
3216  }
3217 
3218  if (StreamTcpSackPacketIsOutdated(&ssn->client, p)) {
3219  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3220  ssn->client.next_seq);
3221  return true;
3222  }
3223  }
3224  }
3225  return false;
3226 }
3227 
3228 /** \internal
3229  * \brief check if packet is before ack'd windows
3230  * If packet is before last ack, we will not accept it
3231  *
3232  * \retval 0 not spurious retransmission
3233  * \retval 1 before last_ack, after base_seq
3234  * \retval 2 before last_ack and base_seq
3235  */
3236 static int StreamTcpPacketIsSpuriousRetransmission(const TcpSession *ssn, Packet *p)
3237 {
3238  const TcpStream *stream;
3239  if (PKT_IS_TOCLIENT(p)) {
3240  stream = &ssn->server;
3241  } else {
3242  stream = &ssn->client;
3243  }
3244  if (p->payload_len == 0)
3245  return 0;
3246 
3247  const TCPHdr *tcph = PacketGetTCP(p);
3248  /* take base_seq into account to avoid edge cases where last_ack might be
3249  * too far ahead during heavy packet loss */
3250  if (!(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3251  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->base_seq))) {
3252  SCLogDebug(
3253  "ssn %p: spurious retransmission; packet entirely before base_seq: SEQ %u(%u) "
3254  "last_ack %u base_seq %u",
3255  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3256  stream->last_ack, stream->base_seq);
3258  return 2;
3259  }
3260  }
3261 
3262  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack))) {
3263  SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) "
3264  "last_ack %u",
3265  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3266  stream->last_ack);
3268  return 1;
3269  }
3270 
3271  SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ "
3272  "%u(%u) last_ack %u, base_seq %u",
3273  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack,
3274  stream->base_seq);
3275  return 0;
3276 }
3277 
3278 /**
3279  * \brief Function to handle the TCP_ESTABLISHED state. The function handles
3280  * ACK, FIN, RST packets and correspondingly changes the connection
3281  * state. The function handles the data inside packets and call
3282  * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
3283  *
3284  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3285  * \param p Packet which has to be handled in this TCP state.
3286  * \param stt Stream Thread module registered to handle the stream handling
3287  */
3288 
3289 static int StreamTcpPacketStateEstablished(
3290  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3291 {
3292  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3293  const TCPHdr *tcph = PacketGetTCP(p);
3294  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3295  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3296  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3297 
3298  if (tcph->th_flags & TH_RST) {
3299  if (!StreamTcpValidateRst(ssn, p))
3300  return -1;
3301 
3302  if (PKT_IS_TOSERVER(p)) {
3303  StreamTcpCloseSsnWithReset(p, ssn);
3304 
3305  ssn->server.next_seq = ack;
3306  ssn->client.next_seq = seq + p->payload_len;
3307  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3308  ssn->server.next_seq);
3309  ssn->client.window = window << ssn->client.wscale;
3310 
3311  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3313  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, window));
3314 
3315  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
3316 
3317  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3318  StreamTcpHandleTimestamp(ssn, p);
3319  }
3320 
3321  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3322  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3323  "%" PRIu32 "", ssn, ssn->client.next_seq,
3324  ssn->server.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  } else {
3330  StreamTcpCloseSsnWithReset(p, ssn);
3331 
3332  ssn->server.next_seq = seq + p->payload_len + 1;
3333  ssn->client.next_seq = ack;
3334 
3335  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3336  ssn->server.next_seq);
3337  ssn->server.window = window << ssn->server.wscale;
3338 
3339  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3341  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
3342 
3343  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
3344 
3345  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3346  StreamTcpHandleTimestamp(ssn, p);
3347  }
3348 
3349  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3350  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3351  "%" PRIu32 "", ssn, ssn->server.next_seq,
3352  ssn->client.last_ack);
3353 
3354  /* don't return packets to pools here just yet, the pseudo
3355  * packet will take care, otherwise the normal session
3356  * cleanup. */
3357  }
3358 
3359  } else if (tcph->th_flags & TH_FIN) {
3360  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3361  if (!StreamTcpValidateTimestamp(ssn, p))
3362  return -1;
3363  }
3364 
3365  SCLogDebug("ssn (%p: FIN received SEQ"
3366  " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
3367  " win %" PRIu32 "", ssn, ssn->server.next_seq,
3368  ssn->client.last_ack, ssn->server.next_win,
3369  ssn->server.window);
3370 
3371  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
3372  return -1;
3373 
3374  /* SYN/ACK */
3375  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
3376  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
3377  ssn);
3378 
3379  if (PKT_IS_TOSERVER(p)) {
3380  SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
3381 
3383  return -1;
3384  }
3385 
3386  /* Check if the SYN/ACK packets ACK matches the earlier
3387  * received SYN/ACK packet. */
3388  if (!(SEQ_EQ(ack, ssn->client.last_ack))) {
3389  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
3390  "%" PRIu32 " from stream",
3391  ssn, ack, ssn->client.isn + 1);
3392 
3394  return -1;
3395  }
3396 
3397  /* Check if the SYN/ACK packet SEQ the earlier
3398  * received SYN packet. */
3399  if (!(SEQ_EQ(seq, ssn->server.isn))) {
3400  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
3401  "%" PRIu32 " from stream",
3402  ssn, ack, ssn->client.isn + 1);
3403 
3405  return -1;
3406  }
3407 
3408  if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
3409  /* a resend of a SYN while we are established already -- fishy */
3411  return -1;
3412  }
3413 
3414  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
3415  "Likely due server not receiving final ACK in 3whs", ssn);
3416  return 0;
3417 
3418  } else if (tcph->th_flags & TH_SYN) {
3419  SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
3420  if (PKT_IS_TOCLIENT(p)) {
3421  SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
3422 
3424  return -1;
3425  }
3426 
3427  if (!(SEQ_EQ(ack, ssn->client.isn))) {
3428  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
3429 
3431  return -1;
3432  }
3433 
3434  /* a resend of a SYN while we are established already -- fishy */
3436  return -1;
3437 
3438  } else if (tcph->th_flags & TH_ACK) {
3439  /* Urgent pointer size can be more than the payload size, as it tells
3440  * the future coming data from the sender will be handled urgently
3441  * until data of size equal to urgent offset has been processed
3442  * (RFC 2147) */
3443 
3444  /* If the timestamp option is enabled for both the streams, then
3445  * validate the received packet timestamp value against the
3446  * stream->last_ts. If the timestamp is valid then process the
3447  * packet normally otherwise the drop the packet (RFC 1323) */
3448  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3449  if (!StreamTcpValidateTimestamp(ssn, p))
3450  return -1;
3451  }
3452 
3453  if (PKT_IS_TOSERVER(p)) {
3454  /* Process the received packet to server */
3455  HandleEstablishedPacketToServer(tv, ssn, p, stt);
3456 
3457  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3458  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3459  ssn->client.next_seq, ssn->server.last_ack
3460  ,ssn->client.next_win, ssn->client.window);
3461 
3462  } else { /* implied to client */
3463  if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
3465  SCLogDebug("3whs is now confirmed by server");
3466  }
3467 
3468  /* Process the received packet to client */
3469  HandleEstablishedPacketToClient(tv, ssn, p, stt);
3470 
3471  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3472  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3473  ssn->server.next_seq, ssn->client.last_ack,
3474  ssn->server.next_win, ssn->server.window);
3475  }
3476  } else {
3477  SCLogDebug("ssn %p: default case", ssn);
3478  }
3479 
3480  return 0;
3481 }
3482 
3483 /**
3484  * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
3485  * TCP_ESTABLISHED and changes to another TCP state as required.
3486  *
3487  * \param tv Thread Variable containing input/output queue, cpu affinity
3488  * \param p Packet which has to be handled in this TCP state.
3489  * \param stt Stream Thread module registered to handle the stream handling
3490  *
3491  * \retval 0 success
3492  * \retval -1 something wrong with the packet
3493  */
3494 
3495 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession *ssn, Packet *p)
3496 {
3497  const TCPHdr *tcph = PacketGetTCP(p);
3498  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3499  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3500  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3501 
3502  if (PKT_IS_TOSERVER(p)) {
3503  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
3504  " ACK %" PRIu32 "",
3505  ssn, p->payload_len, seq, ack);
3506 
3507  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3508  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3510  return -1;
3511  }
3512 
3513  const uint32_t pkt_re = seq + p->payload_len;
3514  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3515  ssn->client.last_ack, ssn->client.next_win);
3516  if (SEQ_GEQ(seq, ssn->client.last_ack) && SEQ_LEQ(pkt_re, ssn->client.next_win)) {
3517  // within expectations
3518  } else {
3519  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3520  "%" PRIu32 " from stream",
3521  ssn, seq, ssn->client.next_seq);
3522 
3524  return -1;
3525  }
3526 
3527  if (tcph->th_flags & TH_SYN) {
3528  SCLogDebug("ssn %p: FIN+SYN", ssn);
3530  return -1;
3531  }
3532  StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
3533  SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
3534 
3535  /* if we accept the FIN, next_seq needs to reflect the FIN */
3536  ssn->client.next_seq = seq + p->payload_len;
3537 
3538  SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
3539  ssn->client.next_seq);
3540  ssn->server.window = window << ssn->server.wscale;
3541 
3542  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3543  StreamTcpHandleTimestamp(ssn, p);
3544  }
3545 
3546  /* Update the next_seq, in case if we have missed the client packet
3547  and server has already received and acked it */
3548  if (SEQ_LT(ssn->server.next_seq, ack))
3549  ssn->server.next_seq = ack;
3550 
3551  if (tcph->th_flags & TH_ACK)
3552  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3553 
3554  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3555 
3556  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3557  ssn, ssn->client.next_seq, ssn->server.last_ack);
3558  } else { /* implied to client */
3559  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
3560  "ACK %" PRIu32 "",
3561  ssn, p->payload_len, seq, ack);
3562 
3563  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3564  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3566  return -1;
3567  }
3568 
3569  const uint32_t pkt_re = seq + p->payload_len;
3570  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3571  ssn->server.last_ack, ssn->server.next_win);
3572  if (SEQ_GEQ(seq, ssn->server.last_ack) && SEQ_LEQ(pkt_re, ssn->server.next_win)) {
3573  // within expectations
3574  } else {
3575  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3576  "%" PRIu32 " from stream (last_ack %u win %u = %u)",
3577  ssn, seq, ssn->server.next_seq, ssn->server.last_ack, ssn->server.window,
3578  (ssn->server.last_ack + ssn->server.window));
3579 
3581  return -1;
3582  }
3583 
3584  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
3585  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
3586 
3587  /* if we accept the FIN, next_seq needs to reflect the FIN */
3588  ssn->server.next_seq = seq + p->payload_len + 1;
3589  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 " updated", ssn, ssn->server.next_seq);
3590 
3591  ssn->client.window = window << ssn->client.wscale;
3592 
3593  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3594  StreamTcpHandleTimestamp(ssn, p);
3595  }
3596 
3597  /* Update the next_seq, in case if we have missed the client packet
3598  and server has already received and acked it */
3599  if (SEQ_LT(ssn->client.next_seq, ack))
3600  ssn->client.next_seq = ack;
3601 
3602  if (tcph->th_flags & TH_ACK)
3603  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3604 
3605  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3606 
3607  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3608  ssn, ssn->server.next_seq, ssn->client.last_ack);
3609  }
3610 
3611  return 0;
3612 }
3613 
3614 /**
3615  * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
3616  * ACK, FIN, RST packets and correspondingly changes the connection
3617  * state.
3618  *
3619  * \param tv Thread Variable containing input/output queue, cpu affinity
3620  * \param p Packet which has to be handled in this TCP state.
3621  * \param stt Stream Thread module registered to handle the stream handling
3622  *
3623  * \retval 0 success
3624  * \retval -1 something wrong with the packet
3625  */
3626 
3627 static int StreamTcpPacketStateFinWait1(
3628  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3629 {
3630  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3631  const TCPHdr *tcph = PacketGetTCP(p);
3632  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3633  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3634  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3635 
3636  if (tcph->th_flags & TH_RST) {
3637  if (!StreamTcpValidateRst(ssn, p))
3638  return -1;
3639 
3640  StreamTcpCloseSsnWithReset(p, ssn);
3641 
3642  if (PKT_IS_TOSERVER(p)) {
3643  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3645  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
3646 
3647  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
3648 
3649  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3650  StreamTcpHandleTimestamp(ssn, p);
3651  }
3652 
3653  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3654  } else {
3655  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3657  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
3658 
3659  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
3660 
3661  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3662  StreamTcpHandleTimestamp(ssn, p);
3663  }
3664 
3665  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3666  }
3667 
3668  } else if ((tcph->th_flags & (TH_FIN | TH_ACK)) == (TH_FIN | TH_ACK)) {
3669  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3670  if (!StreamTcpValidateTimestamp(ssn, p))
3671  return -1;
3672  }
3673 
3674  if (PKT_IS_TOSERVER(p)) {
3675  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3676  "%" PRIu32 ", ACK %" PRIu32 "",
3677  ssn, p->payload_len, seq, ack);
3678  int retransmission = 0;
3679 
3680  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3681  SCLogDebug("ssn %p: packet is retransmission", ssn);
3682  retransmission = 1;
3684 
3685  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3686  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3687  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3688  " != %" PRIu32 " from stream",
3689  ssn, seq, ssn->client.next_seq);
3691  return -1;
3692  }
3693 
3694  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3695  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3697  return -1;
3698  }
3699 
3700  if (!retransmission) {
3701  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3702  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3703 
3704  ssn->server.window = window << ssn->server.wscale;
3705  }
3706 
3707  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3708  StreamTcpHandleTimestamp(ssn, p);
3709  }
3710 
3711  /* Update the next_seq, in case if we have missed the client
3712  packet and server has already received and acked it */
3713  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3714  ssn->server.next_seq = ack;
3715 
3716  if (SEQ_EQ(ssn->client.next_seq, seq)) {
3717  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3718  }
3719 
3720  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3721 
3722  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3723 
3724  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3725  "%" PRIu32 "", ssn, ssn->client.next_seq,
3726  ssn->server.last_ack);
3727  } else { /* implied to client */
3728  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3729  "%" PRIu32 ", ACK %" PRIu32 "",
3730  ssn, p->payload_len, seq, ack);
3731  int retransmission = 0;
3732 
3733  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3734  SCLogDebug("ssn %p: packet is retransmission", ssn);
3735  retransmission = 1;
3737 
3738  } else if (SEQ_EQ(ssn->server.next_seq - 1, seq) && SEQ_EQ(ssn->client.last_ack, ack)) {
3739  SCLogDebug("ssn %p: packet is retransmission", ssn);
3740  retransmission = 1;
3742 
3743  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3744  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3745  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3746  " != %" PRIu32 " from stream",
3747  ssn, seq, ssn->server.next_seq);
3749  return -1;
3750  }
3751 
3752  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3753  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3755  return -1;
3756  }
3757 
3758  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3759  StreamTcpHandleTimestamp(ssn, p);
3760  }
3761 
3762  if (!retransmission) {
3763  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3764  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3765 
3766  ssn->client.window = window << ssn->client.wscale;
3767 
3768  /* Update the next_seq, in case if we have missed the client
3769  packet and server has already received and acked it */
3770  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3771  ssn->client.next_seq = ack;
3772 
3773  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3774  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3775  }
3776 
3777  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3778  }
3779 
3780  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3781 
3782  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3783  "%" PRIu32 "", ssn, ssn->server.next_seq,
3784  ssn->client.last_ack);
3785  }
3786 
3787  } else if (tcph->th_flags & TH_FIN) {
3788  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3789  if (!StreamTcpValidateTimestamp(ssn, p))
3790  return -1;
3791  }
3792 
3793  if (PKT_IS_TOSERVER(p)) {
3794  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3795  "%" PRIu32 ", ACK %" PRIu32 "",
3796  ssn, p->payload_len, seq, ack);
3797  int retransmission = 0;
3798 
3799  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3800  SCLogDebug("ssn %p: packet is retransmission", ssn);
3801  retransmission = 1;
3803 
3804  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3805  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3806  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3807  " != %" PRIu32 " from stream",
3808  ssn, seq, ssn->client.next_seq);
3810  return -1;
3811  }
3812 
3813  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3814  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3816  return -1;
3817  }
3818 
3819  if (!retransmission) {
3820  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3821  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3822 
3823  ssn->server.window = window << ssn->server.wscale;
3824  }
3825 
3826  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3827  StreamTcpHandleTimestamp(ssn, p);
3828  }
3829 
3830  /* Update the next_seq, in case if we have missed the client
3831  packet and server has already received and acked it */
3832  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3833  ssn->server.next_seq = ack;
3834 
3835  if (SEQ_EQ(ssn->client.next_seq - 1, seq)) {
3836  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3837  }
3838 
3839  if (tcph->th_flags & TH_ACK)
3840  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3841 
3842  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3843 
3844  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3845  "%" PRIu32 "", ssn, ssn->client.next_seq,
3846  ssn->server.last_ack);
3847  } else { /* implied to client */
3848  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3849  "%" PRIu32 ", ACK %" PRIu32 "",
3850  ssn, p->payload_len, seq, ack);
3851 
3852  int retransmission = 0;
3853 
3854  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3855  SCLogDebug("ssn %p: packet is retransmission", ssn);
3856  retransmission = 1;
3858 
3859  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3860  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3861  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3862  " != %" PRIu32 " from stream",
3863  ssn, seq, ssn->server.next_seq);
3865  return -1;
3866  }
3867 
3868  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3869  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3871  return -1;
3872  }
3873 
3874  if (!retransmission) {
3875  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3876  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3877 
3878  ssn->client.window = window << ssn->client.wscale;
3879  }
3880 
3881  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3882  StreamTcpHandleTimestamp(ssn, p);
3883  }
3884 
3885  /* Update the next_seq, in case if we have missed the client
3886  packet and server has already received and acked it */
3887  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3888  ssn->client.next_seq = ack;
3889 
3890  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3891  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3892  }
3893 
3894  if (tcph->th_flags & TH_ACK)
3895  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3896 
3897  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3898 
3899  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3900  "%" PRIu32 "", ssn, ssn->server.next_seq,
3901  ssn->client.last_ack);
3902  }
3903  } else if (tcph->th_flags & TH_SYN) {
3904  SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
3906  return -1;
3907 
3908  } else if (tcph->th_flags & TH_ACK) {
3909  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3910  if (!StreamTcpValidateTimestamp(ssn, p))
3911  return -1;
3912  }
3913 
3914  if (PKT_IS_TOSERVER(p)) {
3915  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3916  "%" PRIu32 ", ACK %" PRIu32 "",
3917  ssn, p->payload_len, seq, ack);
3918  int retransmission = 0;
3919 
3920  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3921  SCLogDebug("ssn %p: packet is retransmission", ssn);
3922  retransmission = 1;
3924  }
3925 
3926  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3927  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3929  return -1;
3930  }
3931 
3932  if (SEQ_LT(ack, ssn->server.next_seq)) {
3933  SCLogDebug(
3934  "ssn %p: ACK's older segment as %u < %u", ssn, ack, ssn->server.next_seq);
3935  } else if (!retransmission) {
3936  if (SEQ_EQ(ack, ssn->server.next_seq)) {
3937  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
3939  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
3940  "%" PRIu32 "",
3941  ssn, seq, ssn->client.next_win);
3942  SCLogDebug("seq %u client.next_seq %u", seq, ssn->client.next_seq);
3943  if (seq == ssn->client.next_seq) {
3944  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3945  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3946  }
3947  } else {
3948  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3949  " != %" PRIu32 " from stream",
3950  ssn, seq, ssn->client.next_seq);
3951 
3953  return -1;
3954  }
3955 
3956  ssn->server.window = window << ssn->server.wscale;
3957  }
3958  }
3959 
3960  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3961  StreamTcpHandleTimestamp(ssn, p);
3962  }
3963 
3964  /* Update the next_seq, in case if we have missed the client
3965  packet and server has already received and acked it */
3966  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3967  ssn->server.next_seq = ack;
3968 
3969  if (SEQ_EQ(ssn->client.next_seq, seq)) {
3970  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3971  }
3972 
3973  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3974 
3976 
3977  /* update next_win */
3978  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3979 
3980  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3981 
3982  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3983  "%" PRIu32 "", ssn, ssn->client.next_seq,
3984  ssn->server.last_ack);
3985 
3986  } else { /* implied to client */
3987 
3988  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3989  "%" PRIu32 ", ACK %" PRIu32 "",
3990  ssn, p->payload_len, seq, ack);
3991 
3992  int retransmission = 0;
3993 
3994  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3995  SCLogDebug("ssn %p: packet is retransmission", ssn);
3996  retransmission = 1;
3998  }
3999 
4000  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4001  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4003  return -1;
4004  }
4005 
4006  if (!retransmission) {
4007  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4009  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4010  "%" PRIu32 "",
4011  ssn, seq, ssn->server.next_win);
4012 
4013  if (seq == ssn->server.next_seq - 1) {
4014  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
4015  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
4016  }
4017  } else {
4018  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4019  " != %" PRIu32 " from stream",
4020  ssn, seq, ssn->server.next_seq);
4022  return -1;
4023  }
4024 
4025  ssn->client.window = window << ssn->client.wscale;
4026  }
4027 
4028  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4029  StreamTcpHandleTimestamp(ssn, p);
4030  }
4031 
4032  /* Update the next_seq, in case if we have missed the client
4033  packet and server has already received and acked it */
4034  if (SEQ_LT(ssn->client.next_seq - 1, ack))
4035  ssn->client.next_seq = ack;
4036 
4037  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
4038  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
4039  }
4040 
4041  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4042 
4044 
4045  /* update next_win */
4046  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4047 
4048  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4049 
4050  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4051  "%" PRIu32 "", ssn, ssn->server.next_seq,
4052  ssn->client.last_ack);
4053  }
4054  } else {
4055  SCLogDebug("ssn (%p): default case", ssn);
4056  }
4057 
4058  return 0;
4059 }
4060 
4061 /**
4062  * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
4063  * ACK, RST, FIN packets and correspondingly changes the connection
4064  * state.
4065  *
4066  * \param tv Thread Variable containing input/output queue, cpu affinity
4067  * \param p Packet which has to be handled in this TCP state.
4068  * \param stt Stream Thread module registered to handle the stream handling
4069  */
4070 
4071 static int StreamTcpPacketStateFinWait2(
4072  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4073 {
4074  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4075  const TCPHdr *tcph = PacketGetTCP(p);
4076  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4077  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4078  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4079 
4080  if (tcph->th_flags & TH_RST) {
4081  if (!StreamTcpValidateRst(ssn, p))
4082  return -1;
4083 
4084  StreamTcpCloseSsnWithReset(p, ssn);
4085 
4086  if (PKT_IS_TOSERVER(p)) {
4087  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4089  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4090 
4091  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4092 
4093  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4094  StreamTcpHandleTimestamp(ssn, p);
4095  }
4096 
4097  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4098  } else {
4099  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4101  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4102 
4103  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4104 
4105  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4106  StreamTcpHandleTimestamp(ssn, p);
4107  }
4108 
4109  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4110  }
4111 
4112  } else if (tcph->th_flags & TH_FIN) {
4113  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4114  if (!StreamTcpValidateTimestamp(ssn, p))
4115  return -1;
4116  }
4117 
4118  if (PKT_IS_TOSERVER(p)) {
4119  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4120  "%" PRIu32 ", ACK %" PRIu32 "",
4121  ssn, p->payload_len, seq, ack);
4122  int retransmission = 0;
4123 
4124  if (SEQ_EQ(seq, ssn->client.next_seq - 1) && SEQ_EQ(ack, ssn->server.last_ack)) {
4125  SCLogDebug("ssn %p: retransmission", ssn);
4126  retransmission = 1;
4128  } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4129  SCLogDebug("ssn %p: packet is retransmission", ssn);
4130  retransmission = 1;
4132 
4133  } else if (SEQ_LT(seq, ssn->client.next_seq) ||
4134  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4135  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4136  "%" PRIu32 " != %" PRIu32 " from stream",
4137  ssn, seq, ssn->client.next_seq);
4139  return -1;
4140  }
4141 
4142  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4143  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4145  return -1;
4146  }
4147 
4148  if (!retransmission) {
4149  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4150  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4151 
4152  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4154  ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4155  }
4156  ssn->server.window = window << ssn->server.wscale;
4157  }
4158 
4159  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4160  StreamTcpHandleTimestamp(ssn, p);
4161  }
4162 
4163  /* Update the next_seq, in case if we have missed the client
4164  packet and server has already received and acked it */
4165  if (SEQ_LT(ssn->server.next_seq, ack))
4166  ssn->server.next_seq = ack;
4167 
4168  if (tcph->th_flags & TH_ACK)
4169  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4170 
4171  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4172 
4173  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4174  "%" PRIu32 "", ssn, ssn->client.next_seq,
4175  ssn->server.last_ack);
4176  } else { /* implied to client */
4177  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4178  "%" PRIu32 ", ACK %" PRIu32 "",
4179  ssn, p->payload_len, seq, ack);
4180  int retransmission = 0;
4181 
4182  if (SEQ_EQ(seq, ssn->server.next_seq - 1) && SEQ_EQ(ack, ssn->client.last_ack)) {
4183  SCLogDebug("ssn %p: retransmission", ssn);
4184  retransmission = 1;
4186  } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4187  SCLogDebug("ssn %p: packet is retransmission", ssn);
4188  retransmission = 1;
4190 
4191  } else if (SEQ_LT(seq, ssn->server.next_seq) ||
4192  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4193  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4194  "%" PRIu32 " != %" PRIu32 " from stream",
4195  ssn, seq, ssn->server.next_seq);
4197  return -1;
4198  }
4199 
4200  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4201  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4203  return -1;
4204  }
4205 
4206  if (!retransmission) {
4207  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4208  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4209 
4210  ssn->client.window = window << ssn->client.wscale;
4211  }
4212 
4213  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4214  StreamTcpHandleTimestamp(ssn, p);
4215  }
4216 
4217  /* Update the next_seq, in case if we have missed the client
4218  packet and server has already received and acked it */
4219  if (SEQ_LT(ssn->client.next_seq, ack))
4220  ssn->client.next_seq = ack;
4221 
4222  if (tcph->th_flags & TH_ACK)
4223  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4224 
4225  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4226  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4227  "%" PRIu32 "", ssn, ssn->server.next_seq,
4228  ssn->client.last_ack);
4229  }
4230 
4231  } else if (tcph->th_flags & TH_SYN) {
4232  SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
4234  return -1;
4235 
4236  } else if (tcph->th_flags & TH_ACK) {
4237  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4238  if (!StreamTcpValidateTimestamp(ssn, p))
4239  return -1;
4240  }
4241 
4242  if (PKT_IS_TOSERVER(p)) {
4243  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4244  "%" PRIu32 ", ACK %" PRIu32 "",
4245  ssn, p->payload_len, seq, ack);
4246  int retransmission = 0;
4247 
4248  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4249  SCLogDebug("ssn %p: packet is retransmission", ssn);
4250  retransmission = 1;
4252  }
4253 
4254  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4255  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4257  return -1;
4258  }
4259 
4260  if (!retransmission) {
4261  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
4263  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
4264  "%" PRIu32 "",
4265  ssn, seq, ssn->client.next_win);
4266 
4267  } else {
4268  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4269  " != %" PRIu32 " from stream",
4270  ssn, seq, ssn->client.next_seq);
4272  return -1;
4273  }
4274 
4275  ssn->server.window = window << ssn->server.wscale;
4276  }
4277 
4278  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4279  StreamTcpHandleTimestamp(ssn, p);
4280  }
4281 
4282  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4283  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4284  }
4285 
4286  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4287 
4289 
4290  /* update next_win */
4291  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
4292 
4293  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4294 
4295  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4296  "%" PRIu32 "", ssn, ssn->client.next_seq,
4297  ssn->server.last_ack);
4298  } else { /* implied to client */
4299  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4300  "%" PRIu32 ", ACK %" PRIu32 "",
4301  ssn, p->payload_len, seq, ack);
4302  int retransmission = 0;
4303 
4304  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4305  SCLogDebug("ssn %p: packet is retransmission", ssn);
4306  retransmission = 1;
4308  }
4309 
4310  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4311  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4313  return -1;
4314  }
4315 
4316  if (!retransmission) {
4317  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4319  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4320  "%" PRIu32 "",
4321  ssn, seq, ssn->server.next_win);
4322  } else {
4323  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4324  " != %" PRIu32 " from stream",
4325  ssn, seq, ssn->server.next_seq);
4327  return -1;
4328  }
4329 
4330  ssn->client.window = window << ssn->client.wscale;
4331  }
4332 
4333  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4334  StreamTcpHandleTimestamp(ssn, p);
4335  }
4336 
4337  if (SEQ_EQ(ssn->server.next_seq, seq)) {
4338  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4339  }
4340 
4341  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4342 
4344 
4345  /* update next_win */
4346  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4347 
4348  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4349 
4350  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4351  "%" PRIu32 "", ssn, ssn->server.next_seq,
4352  ssn->client.last_ack);
4353  }
4354  } else {
4355  SCLogDebug("ssn %p: default case", ssn);
4356  }
4357 
4358  return 0;
4359 }
4360 
4361 /**
4362  * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
4363  * the connection goes to TCP_TIME_WAIT state. The state has been
4364  * reached as both end application has been closed.
4365  *
4366  * \param tv Thread Variable containing input/output queue, cpu affinity
4367  * \param p Packet which has to be handled in this TCP state.
4368  * \param stt Stream Thread module registered to handle the stream handling
4369  */
4370 
4371 static int StreamTcpPacketStateClosing(
4372  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4373 {
4374  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4375  const TCPHdr *tcph = PacketGetTCP(p);
4376  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4377  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4378  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4379 
4380  if (tcph->th_flags & TH_RST) {
4381  if (!StreamTcpValidateRst(ssn, p))
4382  return -1;
4383 
4384  StreamTcpCloseSsnWithReset(p, ssn);
4385 
4386  if (PKT_IS_TOSERVER(p)) {
4387  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4389  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4390 
4391  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4392 
4393  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4394  StreamTcpHandleTimestamp(ssn, p);
4395  }
4396 
4397  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4398  } else {
4399  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4401  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4402 
4403  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4404 
4405  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4406  StreamTcpHandleTimestamp(ssn, p);
4407  }
4408 
4409  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4410  }
4411 
4412  } else if (tcph->th_flags & TH_SYN) {
4413  SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
4415  return -1;
4416 
4417  } else if (tcph->th_flags & TH_ACK) {
4418  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4419  if (!StreamTcpValidateTimestamp(ssn, p))
4420  return -1;
4421  }
4422 
4423  if (PKT_IS_TOSERVER(p)) {
4424  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4425  "%" PRIu32 ", ACK %" PRIu32 "",
4426  ssn, p->payload_len, seq, ack);
4427  int retransmission = 0;
4428  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4429  SCLogDebug("ssn %p: packet is retransmission", ssn);
4430  retransmission = 1;
4432  }
4433 
4434  if (seq != ssn->client.next_seq) {
4435  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4436  " != %" PRIu32 " from stream",
4437  ssn, seq, ssn->client.next_seq);
4439  return -1;
4440  }
4441 
4442  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4443  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4445  return -1;
4446  }
4447 
4448  if (!retransmission) {
4449  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4450  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4451 
4452  ssn->client.window = window << ssn->client.wscale;
4453  }
4454 
4455  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4456  StreamTcpHandleTimestamp(ssn, p);
4457  }
4458  /* Update the next_seq, in case if we have missed the client
4459  packet and server has already received and acked it */
4460  if (SEQ_LT(ssn->server.next_seq, ack))
4461  ssn->server.next_seq = ack;
4462 
4463  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4464 
4465  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4466  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4467  "%" PRIu32 "", ssn, ssn->client.next_seq,
4468  ssn->server.last_ack);
4469  } else { /* implied to client */
4470  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4471  "%" PRIu32 ", ACK %" PRIu32 "",
4472  ssn, p->payload_len, seq, ack);
4473  int retransmission = 0;
4474  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4475  SCLogDebug("ssn %p: packet is retransmission", ssn);
4476  retransmission = 1;
4478  }
4479 
4480  if (seq != ssn->server.next_seq) {
4481  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4482  " != %" PRIu32 " from stream",
4483  ssn, seq, ssn->server.next_seq);
4485  return -1;
4486  }
4487 
4488  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4489  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4491  return -1;
4492  }
4493 
4494  if (!retransmission) {
4495  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4496  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4497 
4498  ssn->client.window = window << ssn->client.wscale;
4499  }
4500 
4501  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4502  StreamTcpHandleTimestamp(ssn, p);
4503  }
4504 
4505  /* Update the next_seq, in case if we have missed the client
4506  packet and server has already received and acked it */
4507  if (SEQ_LT(ssn->client.next_seq, ack))
4508  ssn->client.next_seq = ack;
4509 
4510  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4511 
4512  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4513  SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
4514  "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
4515  ssn->server.next_seq, ssn->client.last_ack);
4516  }
4517  } else {
4518  SCLogDebug("ssn %p: default case", ssn);
4519  }
4520 
4521  return 0;
4522 }
4523 
4524 /**
4525  * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
4526  * packet from server the connection goes to TCP_LAST_ACK state.
4527  * The state is possible only for server host.
4528  *
4529  * \param tv Thread Variable containing input/output queue, cpu affinity
4530  * \param p Packet which has to be handled in this TCP state.
4531  * \param stt Stream Thread module registered to handle the stream handling
4532  */
4533 
4534 static int StreamTcpPacketStateCloseWait(
4535  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4536 {
4537  SCEnter();
4538  const TCPHdr *tcph = PacketGetTCP(p);
4539  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4540  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4541  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4542 
4543  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4544 
4545  if (PKT_IS_TOCLIENT(p)) {
4546  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4547  "%" PRIu32 ", ACK %" PRIu32 "",
4548  ssn, p->payload_len, seq, ack);
4549  } else {
4550  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4551  "%" PRIu32 ", ACK %" PRIu32 "",
4552  ssn, p->payload_len, seq, ack);
4553  }
4554 
4555  if (tcph->th_flags & TH_RST) {
4556  if (!StreamTcpValidateRst(ssn, p))
4557  return -1;
4558 
4559  StreamTcpCloseSsnWithReset(p, ssn);
4560 
4561  if (PKT_IS_TOSERVER(p)) {
4562  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4564  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4565 
4566  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4567 
4568  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4569  StreamTcpHandleTimestamp(ssn, p);
4570  }
4571 
4572  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4573  } else {
4574  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4576  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4577 
4578  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4579 
4580  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4581  StreamTcpHandleTimestamp(ssn, p);
4582  }
4583 
4584  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4585  }
4586 
4587  } else if (tcph->th_flags & TH_FIN) {
4588  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4589  if (!StreamTcpValidateTimestamp(ssn, p))
4590  SCReturnInt(-1);
4591  }
4592 
4593  if (PKT_IS_TOSERVER(p)) {
4594  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4595  "%" PRIu32 ", ACK %" PRIu32 "",
4596  ssn, p->payload_len, seq, ack);
4597 
4598  int retransmission = 0;
4599  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4600  SCLogDebug("ssn %p: packet is retransmission", ssn);
4601  retransmission = 1;
4603  }
4604 
4605  if (!retransmission) {
4606  if (SEQ_LT(seq, ssn->client.next_seq) ||
4607  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4608  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4609  " != %" PRIu32 " from stream",
4610  ssn, seq, ssn->client.next_seq);
4612  SCReturnInt(-1);
4613  }
4614  }
4615 
4616  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4617  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4619  SCReturnInt(-1);
4620  }
4621 
4622  /* don't update to LAST_ACK here as we want a toclient FIN for that */
4623 
4624  if (!retransmission)
4625  ssn->server.window = window << ssn->server.wscale;
4626 
4627  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4628  StreamTcpHandleTimestamp(ssn, p);
4629  }
4630 
4631  /* Update the next_seq, in case if we have missed the client
4632  packet and server has already received and acked it */
4633  if (SEQ_LT(ssn->server.next_seq, ack))
4634  ssn->server.next_seq = ack;
4635 
4636  if (tcph->th_flags & TH_ACK)
4637  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4638 
4639  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4640  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4641  "%" PRIu32 "", ssn, ssn->client.next_seq,
4642  ssn->server.last_ack);
4643  } else {
4644  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4645  "%" PRIu32 ", ACK %" PRIu32 "",
4646  ssn, p->payload_len, seq, ack);
4647 
4648  int retransmission = 0;
4649  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4650  SCLogDebug("ssn %p: packet is retransmission", ssn);
4651  retransmission = 1;
4653  }
4654 
4655  if (!retransmission) {
4656  if (SEQ_LT(seq, ssn->server.next_seq) ||
4657  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4658  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4659  " != %" PRIu32 " from stream",
4660  ssn, seq, ssn->server.next_seq);
4662  SCReturnInt(-1);
4663  }
4664  }
4665 
4666  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4667  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4669  SCReturnInt(-1);
4670  }
4671 
4672  if (!retransmission) {
4673  StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
4674  SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
4675 
4676  ssn->client.window = window << ssn->client.wscale;
4677  }
4678 
4679  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4680  StreamTcpHandleTimestamp(ssn, p);
4681  }
4682 
4683  /* Update the next_seq, in case if we have missed the client
4684  packet and server has already received and acked it */
4685  if (SEQ_LT(ssn->client.next_seq, ack))
4686  ssn->client.next_seq = ack;
4687 
4688  if (tcph->th_flags & TH_ACK)
4689  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4690 
4691  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4692  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4693  "%" PRIu32 "", ssn, ssn->server.next_seq,
4694  ssn->client.last_ack);
4695  }
4696 
4697  } else if (tcph->th_flags & TH_SYN) {
4698  SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
4700  SCReturnInt(-1);
4701 
4702  } else if (tcph->th_flags & TH_ACK) {
4703  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4704  if (!StreamTcpValidateTimestamp(ssn, p))
4705  SCReturnInt(-1);
4706  }
4707 
4708  if (PKT_IS_TOSERVER(p)) {
4709  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4710  "%" PRIu32 ", ACK %" PRIu32 "",
4711  ssn, p->payload_len, seq, ack);
4712 
4713  int retransmission = 0;
4714  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4715  SCLogDebug("ssn %p: packet is retransmission", ssn);
4716  retransmission = 1;
4718  }
4719 
4720  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->client.last_ack))) {
4721  SCLogDebug("ssn %p: -> retransmission", ssn);
4723  SCReturnInt(-1);
4724 
4725  } else if (SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4726  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4727  " != %" PRIu32 " from stream",
4728  ssn, seq, ssn->client.next_seq);
4730  SCReturnInt(-1);
4731  }
4732 
4733  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4734  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4736  SCReturnInt(-1);
4737  }
4738 
4739  if (!retransmission) {
4740  ssn->server.window = window << ssn->server.wscale;
4741  }
4742 
4743  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4744  StreamTcpHandleTimestamp(ssn, p);
4745  }
4746 
4747  /* Update the next_seq, in case if we have missed the client
4748  packet and server has already received and acked it */
4749  if (SEQ_LT(ssn->server.next_seq, ack))
4750  ssn->server.next_seq = ack;
4751 
4752  if (SEQ_EQ(seq, ssn->client.next_seq))
4753  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4754 
4755  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4756 
4757  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4758  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4759  "%" PRIu32 "", ssn, ssn->client.next_seq,
4760  ssn->server.last_ack);
4761  } else {
4762  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4763  "%" PRIu32 ", ACK %" PRIu32 "",
4764  ssn, p->payload_len, seq, ack);
4765  int retransmission = 0;
4766  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4767  SCLogDebug("ssn %p: packet is retransmission", ssn);
4768  retransmission = 1;
4770  }
4771 
4772  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->server.last_ack))) {
4773  SCLogDebug("ssn %p: -> retransmission", ssn);
4775  SCReturnInt(-1);
4776 
4777  } else if (SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4778  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4779  " != %" PRIu32 " from stream",
4780  ssn, seq, ssn->server.next_seq);
4782  SCReturnInt(-1);
4783  }
4784 
4785  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4786  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4788  SCReturnInt(-1);
4789  }
4790 
4791  if (!retransmission) {
4792  ssn->client.window = window << ssn->client.wscale;
4793  }
4794 
4795  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4796  StreamTcpHandleTimestamp(ssn, p);
4797  }
4798 
4799  /* Update the next_seq, in case if we have missed the client
4800  packet and server has already received and acked it */
4801  if (SEQ_LT(ssn->client.next_seq, ack))
4802  ssn->client.next_seq = ack;
4803 
4804  if (SEQ_EQ(seq, ssn->server.next_seq))
4805  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4806 
4807  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4808 
4809  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4810  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4811  "%" PRIu32 "", ssn, ssn->server.next_seq,
4812  ssn->client.last_ack);
4813  }
4814 
4815  } else {
4816  SCLogDebug("ssn %p: default case", ssn);
4817  }
4818  SCReturnInt(0);
4819 }
4820 
4821 /**
4822  * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
4823  * the connection goes to TCP_CLOSED state and stream memory is
4824  * returned back to pool. The state is possible only for server host.
4825  *
4826  * \param tv Thread Variable containing input/output queue, cpu affinity
4827  * \param p Packet which has to be handled in this TCP state.
4828  * \param stt Stream Thread module registered to handle the stream handling
4829  */
4830 
4831 static int StreamTcpPacketStateLastAck(
4832  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4833 {
4834  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4835  const TCPHdr *tcph = PacketGetTCP(p);
4836  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4837  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4838  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4839 
4840  if (tcph->th_flags & TH_RST) {
4841  if (!StreamTcpValidateRst(ssn, p))
4842  return -1;
4843 
4844  StreamTcpCloseSsnWithReset(p, ssn);
4845 
4846  if (PKT_IS_TOSERVER(p)) {
4847  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4849  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4850 
4851  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4852 
4853  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4854  StreamTcpHandleTimestamp(ssn, p);
4855  }
4856 
4857  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4858  } else {
4859  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4861  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4862 
4863  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4864 
4865  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4866  StreamTcpHandleTimestamp(ssn, p);
4867  }
4868 
4869  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4870  }
4871 
4872  } else if (tcph->th_flags & TH_FIN) {
4873  /** \todo */
4874  SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
4875 
4876  } else if (tcph->th_flags & TH_SYN) {
4877  SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
4879  return -1;
4880 
4881  } else if (tcph->th_flags & TH_ACK) {
4882  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4883  if (!StreamTcpValidateTimestamp(ssn, p))
4884  return -1;
4885  }
4886 
4887  if (PKT_IS_TOSERVER(p)) {
4888  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4889  "%" PRIu32 ", ACK %" PRIu32 "",
4890  ssn, p->payload_len, seq, ack);
4891 
4892  int retransmission = 0;
4893  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4894  SCLogDebug("ssn %p: packet is retransmission", ssn);
4895  retransmission = 1;
4897  }
4898 
4899  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4900  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4902  SCReturnInt(-1);
4903  }
4904 
4905  if (!retransmission) {
4906  if (SEQ_LT(seq, ssn->client.next_seq)) {
4907  SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
4908  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
4909  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4910  " != %" PRIu32 " from stream",
4911  ssn, seq, ssn->client.next_seq);
4913  return -1;
4914  } else {
4915  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4916  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4917  }
4918  ssn->server.window = window << ssn->server.wscale;
4919  }
4920 
4921  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4922  StreamTcpHandleTimestamp(ssn, p);
4923  }
4924 
4925  /* Update the next_seq, in case if we have missed the client
4926  packet and server has already received and acked it */
4927  if (SEQ_LT(ssn->server.next_seq, ack))
4928  ssn->server.next_seq = ack;
4929 
4930  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4931 
4932  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4933  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4934  "%" PRIu32 "", ssn, ssn->client.next_seq,
4935  ssn->server.last_ack);
4936  }
4937  } else {
4938  SCLogDebug("ssn %p: default case", ssn);
4939  }
4940 
4941  return 0;
4942 }
4943 
4944 /**
4945  * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
4946  * the connection goes to TCP_CLOSED state and stream memory is
4947  * returned back to pool.
4948  *
4949  * \param tv Thread Variable containing input/output queue, cpu affinity
4950  * \param p Packet which has to be handled in this TCP state.
4951  * \param stt Stream Thread module registered to handle the stream handling
4952  */
4953 
4954 static int StreamTcpPacketStateTimeWait(
4955  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4956 {
4957  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4958  const TCPHdr *tcph = PacketGetTCP(p);
4959  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4960  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4961  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4962 
4963  if (tcph->th_flags & TH_RST) {
4964  if (!StreamTcpValidateRst(ssn, p))
4965  return -1;
4966 
4967  StreamTcpCloseSsnWithReset(p, ssn);
4968 
4969  if (PKT_IS_TOSERVER(p)) {
4970  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4972  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4973 
4974  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4975 
4976  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4977  StreamTcpHandleTimestamp(ssn, p);
4978  }
4979 
4980  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4981  } else {
4982  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4984  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4985 
4986  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4987 
4988  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4989  StreamTcpHandleTimestamp(ssn, p);
4990  }
4991 
4992  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4993  }
4994 
4995  } else if (tcph->th_flags & TH_FIN) {
4996  /** \todo */
4997 
4998  } else if (tcph->th_flags & TH_SYN) {
4999  SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
5001  return -1;
5002 
5003  } else if (tcph->th_flags & TH_ACK) {
5004  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5005  if (!StreamTcpValidateTimestamp(ssn, p))
5006  return -1;
5007  }
5008 
5009  if (PKT_IS_TOSERVER(p)) {
5010  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
5011  "%" PRIu32 ", ACK %" PRIu32 "",
5012  ssn, p->payload_len, seq, ack);
5013  int retransmission = 0;
5014  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
5015  SCLogDebug("ssn %p: packet is retransmission", ssn);
5016  retransmission = 1;
5018 
5019  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
5020  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5021  " != %" PRIu32 " from stream",
5022  ssn, seq, ssn->client.next_seq);
5024  return -1;
5025  }
5026 
5027  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
5028  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5030  SCReturnInt(-1);
5031  }
5032 
5033  if (!retransmission) {
5034  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5035  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5036 
5037  ssn->server.window = window << ssn->server.wscale;
5038  }
5039 
5040  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5041  StreamTcpHandleTimestamp(ssn, p);
5042  }
5043 
5044  /* Update the next_seq, in case if we have missed the client
5045  packet and server has already received and acked it */
5046  if (SEQ_LT(ssn->server.next_seq, ack))
5047  ssn->server.next_seq = ack;
5048 
5049  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
5050 
5051  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5052  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5053  "%" PRIu32 "", ssn, ssn->client.next_seq,
5054  ssn->server.last_ack);
5055  } else {
5056  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
5057  "%" PRIu32 ", ACK %" PRIu32 "",
5058  ssn, p->payload_len, seq, ack);
5059  int retransmission = 0;
5060  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
5061  SCLogDebug("ssn %p: packet is retransmission", ssn);
5062  retransmission = 1;
5064  } else if (seq != ssn->server.next_seq - 1 && seq != ssn->server.next_seq) {
5065  if (p->payload_len > 0 && seq == ssn->server.last_ack) {
5066  SCLogDebug("ssn %p: -> retransmission", ssn);
5067  SCReturnInt(0);
5068  } else {
5069  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5070  " != %" PRIu32 " from stream",
5071  ssn, seq, ssn->server.next_seq);
5073  return -1;
5074  }
5075  }
5076 
5077  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
5078  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5080  SCReturnInt(-1);
5081  }
5082 
5083  if (!retransmission) {
5084  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5085  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5086 
5087  ssn->client.window = window << ssn->client.wscale;
5088  }
5089 
5090  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5091  StreamTcpHandleTimestamp(ssn, p);
5092  }
5093 
5094  /* Update the next_seq, in case if we have missed the client
5095  packet and server has already received and acked it */
5096  if (SEQ_LT(ssn->client.next_seq, ack))
5097  ssn->client.next_seq = ack;
5098 
5099  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
5100 
5101  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5102  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5103  "%" PRIu32 "", ssn, ssn->server.next_seq,
5104  ssn->client.last_ack);
5105  }
5106 
5107  } else {
5108  SCLogDebug("ssn %p: default case", ssn);
5109  }
5110 
5111  return 0;
5112 }
5113 
5114 static int StreamTcpPacketStateClosed(
5115  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
5116 {
5117  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5118 
5119  const TCPHdr *tcph = PacketGetTCP(p);
5120  if (tcph->th_flags & TH_RST) {
5121  SCLogDebug("RST on closed state");
5122  return 0;
5123  }
5124 
5125  TcpStream *stream = NULL, *ostream = NULL;
5126  if (PKT_IS_TOSERVER(p)) {
5127  stream = &ssn->client;
5128  ostream = &ssn->server;
5129  } else {
5130  stream = &ssn->server;
5131  ostream = &ssn->client;
5132  }
5133 
5134  SCLogDebug("stream %s ostream %s",
5135  stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
5136  ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
5137 
5138  /* if we've seen a RST on our direction, but not on the other
5139  * see if we perhaps need to continue processing anyway. */
5140  if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
5141  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5142  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->pstate) < 0)
5143  return -1;
5144  /* if state is still "closed", it wasn't updated by our dispatch. */
5145  if (ssn->state == TCP_CLOSED)
5146  ssn->state = ssn->pstate;
5147  }
5148  }
5149  return 0;
5150 }
5151 
5152 static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
5153 {
5154  if (p->flags & PKT_PSEUDO_STREAM_END) {
5155  return;
5156  }
5157  const TCPHdr *tcph = PacketGetTCP(p);
5158  /* more RSTs are not unusual */
5159  if ((tcph->th_flags & (TH_RST)) != 0) {
5160  return;
5161  }
5162 
5163  TcpStream *ostream = NULL;
5164  if (PKT_IS_TOSERVER(p)) {
5165  ostream = &ssn->server;
5166  } else {
5167  ostream = &ssn->client;
5168  }
5169 
5170  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5171  SCLogDebug("regular packet %"PRIu64" from same sender as "
5172  "the previous RST. Looks like it injected!", p->pcap_cnt);
5176  return;
5177  }
5178 }
5179 
5180 /**
5181  * \retval 1 packet is a keep alive pkt
5182  * \retval 0 packet is not a keep alive pkt
5183  */
5184 static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
5185 {
5186  if (p->flags & PKT_PSEUDO_STREAM_END)
5187  return 0;
5188 
5189  /* rfc 1122:
5190  An implementation SHOULD send a keep-alive segment with no
5191  data; however, it MAY be configurable to send a keep-alive
5192  segment containing one garbage octet, for compatibility with
5193  erroneous TCP implementations.
5194  */
5195  if (p->payload_len > 1)
5196  return 0;
5197 
5198  const TCPHdr *tcph = PacketGetTCP(p);
5199  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) {
5200  return 0;
5201  }
5202 
5203  TcpStream *stream = NULL, *ostream = NULL;
5204  if (PKT_IS_TOSERVER(p)) {
5205  stream = &ssn->client;
5206  ostream = &ssn->server;
5207  } else {
5208  stream = &ssn->server;
5209  ostream = &ssn->client;
5210  }
5211 
5212  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
5213  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
5214  if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
5215  SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
5218  return 1;
5219  }
5220  SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
5221  return 0;
5222 }
5223 
5224 /**
5225  * \retval 1 packet is a keep alive ACK pkt
5226  * \retval 0 packet is not a keep alive ACK pkt
5227  */
5228 static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
5229 {
5230  TcpStream *stream = NULL, *ostream = NULL;
5231  uint32_t seq;
5232  uint32_t ack;
5233  uint32_t pkt_win;
5234 
5235  if (p->flags & PKT_PSEUDO_STREAM_END)
5236  return 0;
5237  /* should get a normal ACK to a Keep Alive */
5238  if (p->payload_len > 0)
5239  return 0;
5240 
5241  const TCPHdr *tcph = PacketGetTCP(p);
5242  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5243  return 0;
5244 
5245  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5246  return 0;
5247 
5248  if (PKT_IS_TOSERVER(p)) {
5249  stream = &ssn->client;
5250  ostream = &ssn->server;
5251  } else {
5252  stream = &ssn->server;
5253  ostream = &ssn->client;
5254  }
5255 
5256  seq = TCP_GET_RAW_SEQ(tcph);
5257  ack = TCP_GET_RAW_ACK(tcph);
5258 
5259  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5260  if (pkt_win != ostream->window)
5261  return 0;
5262 
5263  if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
5264  SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
5265  ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
5267  return 1;
5268  }
5269  SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
5270  ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
5271  return 0;
5272 }
5273 
5274 static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
5275 {
5276  TcpStream *stream = NULL;
5277 
5278  if (p->flags & PKT_PSEUDO_STREAM_END)
5279  return;
5280 
5281  if (PKT_IS_TOSERVER(p)) {
5282  stream = &ssn->client;
5283  } else {
5284  stream = &ssn->server;
5285  }
5286 
5287  if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
5289  SCLogDebug("FLAG_KEEPALIVE cleared");
5290  }
5291 }
5292 
5293 /**
5294  * \retval 1 packet is a window update pkt
5295  * \retval 0 packet is not a window update pkt
5296  */
5297 static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
5298 {
5299  TcpStream *stream = NULL, *ostream = NULL;
5300  uint32_t seq;
5301  uint32_t ack;
5302  uint32_t pkt_win;
5303 
5304  if (p->flags & PKT_PSEUDO_STREAM_END)
5305  return 0;
5306 
5307  if (ssn->state < TCP_ESTABLISHED)
5308  return 0;
5309 
5310  if (p->payload_len > 0)
5311  return 0;
5312 
5313  const TCPHdr *tcph = PacketGetTCP(p);
5314  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5315  return 0;
5316 
5317  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5318  return 0;
5319 
5320  if (PKT_IS_TOSERVER(p)) {
5321  stream = &ssn->client;
5322  ostream = &ssn->server;
5323  } else {
5324  stream = &ssn->server;
5325  ostream = &ssn->client;
5326  }
5327 
5328  seq = TCP_GET_RAW_SEQ(tcph);
5329  ack = TCP_GET_RAW_ACK(tcph);
5330 
5331  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5332  if (pkt_win == ostream->window)
5333  return 0;
5334 
5335  if (ack == ostream->last_ack && seq == stream->next_seq) {
5336  SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
5338  return 1;
5339  }
5340  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5341  return 0;
5342 }
5343 
5344 /**
5345  * Try to detect whether a packet is a valid FIN 4whs final ack.
5346  *
5347  */
5348 static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
5349 {
5350  TcpStream *stream = NULL, *ostream = NULL;
5351  uint32_t seq;
5352  uint32_t ack;
5353 
5354  if (p->flags & PKT_PSEUDO_STREAM_END)
5355  return 0;
5356  if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
5357  return 0;
5358  const TCPHdr *tcph = PacketGetTCP(p);
5359  if (tcph->th_flags != TH_ACK)
5360  return 0;
5361  if (p->payload_len != 0)
5362  return 0;
5363 
5364  if (PKT_IS_TOSERVER(p)) {
5365  stream = &ssn->client;
5366  ostream = &ssn->server;
5367  } else {
5368  stream = &ssn->server;
5369  ostream = &ssn->client;
5370  }
5371 
5372  seq = TCP_GET_RAW_SEQ(tcph);
5373  ack = TCP_GET_RAW_ACK(tcph);
5374 
5375  SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
5376  p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
5377 
5378  if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
5379  return 1;
5380  }
5381  return 0;
5382 }
5383 
5384 /**
5385  * Try to detect packets doing bad window updates
5386  *
5387  * See bug 1238.
5388  *
5389  * Find packets that are unexpected, and shrink the window to the point
5390  * where the packets we do expect are rejected for being out of window.
5391  *
5392  * The logic we use here is:
5393  * - packet seq > next_seq
5394  * - packet ack > next_seq (packet acks unseen data)
5395  * - packet shrinks window more than it's own data size
5396  * - packet shrinks window more than the diff between it's ack and the
5397  * last_ack value
5398  *
5399  * Packets coming in after packet loss can look quite a bit like this.
5400  */
5401 static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
5402 {
5403  TcpStream *stream = NULL, *ostream = NULL;
5404  uint32_t seq;
5405  uint32_t ack;
5406  uint32_t pkt_win;
5407 
5408  if (p->flags & PKT_PSEUDO_STREAM_END)
5409  return 0;
5410 
5411  if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
5412  return 0;
5413 
5414  const TCPHdr *tcph = PacketGetTCP(p);
5415  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5416  return 0;
5417 
5418  if (PKT_IS_TOSERVER(p)) {
5419  stream = &ssn->client;
5420  ostream = &ssn->server;
5421  } else {
5422  stream = &ssn->server;
5423  ostream = &ssn->client;
5424  }
5425 
5426  seq = TCP_GET_RAW_SEQ(tcph);
5427  ack = TCP_GET_RAW_ACK(tcph);
5428  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5429 
5430  if (pkt_win < ostream->window) {
5431  uint32_t diff = ostream->window - pkt_win;
5432  if (diff > p->payload_len &&
5433  SEQ_GT(ack, ostream->next_seq) &&
5434  SEQ_GT(seq, stream->next_seq))
5435  {
5436  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
5437  p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
5438  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
5439  p->pcap_cnt, pkt_win, ostream->window);
5440  SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
5441  p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
5442  ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
5443 
5444  /* get the expected window shrinking from looking at ack vs last_ack.
5445  * Observed a lot of just a little overrunning that value. So added some
5446  * margin that is still ok. To make sure this isn't a loophole to still
5447  * close the window, this is limited to windows above 1024. Both values
5448  * are rather arbitrary. */
5449  uint32_t adiff = ack - ostream->last_ack;
5450  if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
5451  ((pkt_win <= 1024) && (diff > adiff)))
5452  {
5453  SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
5454  "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
5455  SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
5457  return 1;
5458  }
5459  }
5460 
5461  }
5462  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5463  return 0;
5464 }
5465 
5466 /** \internal
5467  * \brief call packet handling function for 'state'
5468  * \param state current TCP state
5469  */
5470 static inline int StreamTcpStateDispatch(
5471  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state)
5472 {
5473  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5474 
5475  SCLogDebug("ssn: %p", ssn);
5476  switch (state) {
5477  case TCP_SYN_SENT:
5478  SCLogDebug("packet received on TCP_SYN_SENT state");
5479  if (StreamTcpPacketStateSynSent(tv, p, stt, ssn)) {
5480  return -1;
5481  }
5482  break;
5483  case TCP_SYN_RECV:
5484  SCLogDebug("packet received on TCP_SYN_RECV state");
5485  if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn)) {
5486  return -1;
5487  }
5488  break;
5489  case TCP_ESTABLISHED:
5490  SCLogDebug("packet received on TCP_ESTABLISHED state");
5491  if (StreamTcpPacketStateEstablished(tv, p, stt, ssn)) {
5492  return -1;
5493  }
5494  break;
5495  case TCP_FIN_WAIT1:
5496  SCLogDebug("packet received on TCP_FIN_WAIT1 state");
5497  if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn)) {
5498  return -1;
5499  }
5500  break;
5501  case TCP_FIN_WAIT2:
5502  SCLogDebug("packet received on TCP_FIN_WAIT2 state");
5503  if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn)) {
5504  return -1;
5505  }
5506  break;
5507  case TCP_CLOSING:
5508  SCLogDebug("packet received on TCP_CLOSING state");
5509  if (StreamTcpPacketStateClosing(tv, p, stt, ssn)) {
5510  return -1;
5511  }
5512  break;
5513  case TCP_CLOSE_WAIT:
5514  SCLogDebug("packet received on TCP_CLOSE_WAIT state");
5515  if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn)) {
5516  return -1;
5517  }
5518  break;
5519  case TCP_LAST_ACK:
5520  SCLogDebug("packet received on TCP_LAST_ACK state");
5521  if (StreamTcpPacketStateLastAck(tv, p, stt, ssn)) {
5522  return -1;
5523  }
5524  break;
5525  case TCP_TIME_WAIT:
5526  SCLogDebug("packet received on TCP_TIME_WAIT state");
5527  if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn)) {
5528  return -1;
5529  }
5530  break;
5531  case TCP_CLOSED:
5532  /* TCP session memory is not returned to pool until timeout. */
5533  SCLogDebug("packet received on closed state");
5534 
5535  if (StreamTcpPacketStateClosed(tv, p, stt, ssn)) {
5536  return -1;
5537  }
5538 
5539  break;
5540  default:
5541  SCLogDebug("packet received on default state");
5542  break;
5543  }
5544  return 0;
5545 }
5546 
5547 static inline void HandleThreadId(ThreadVars *tv, Packet *p, StreamTcpThread *stt)
5548 {
5549  const int idx = (!(PKT_IS_TOSERVER(p)));
5550 
5551  /* assign the thread id to the flow */
5552  if (unlikely(p->flow->thread_id[idx] == 0)) {
5553  p->flow->thread_id[idx] = (FlowThreadId)tv->id;
5554  } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id[idx])) {
5555  SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id[idx], tv->id);
5556  if (p->pkt_src == PKT_SRC_WIRE) {
5558  if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
5559  p->flow->flags |= FLOW_WRONG_THREAD;
5561  }
5562  }
5563  }
5564 }
5565 
5566 /* flow is and stays locked */
5568  PacketQueueNoLock *pq)
5569 {
5570  SCEnter();
5571 
5573 
5574  SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
5575 
5576  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
5577  const TCPHdr *tcph = PacketGetTCP(p);
5578 
5579  /* track TCP flags */
5580  if (ssn != NULL) {
5581  ssn->tcp_packet_flags |= tcph->th_flags;
5582  if (PKT_IS_TOSERVER(p))
5583  ssn->client.tcp_flags |= tcph->th_flags;
5584  else if (PKT_IS_TOCLIENT(p))
5585  ssn->server.tcp_flags |= tcph->th_flags;
5586 
5587  /* check if we need to unset the ASYNC flag */
5588  if (ssn->flags & STREAMTCP_FLAG_ASYNC &&
5589  ssn->client.tcp_flags != 0 &&
5590  ssn->server.tcp_flags != 0)
5591  {
5592  SCLogDebug("ssn %p: removing ASYNC flag as we have packets on both sides", ssn);
5593  ssn->flags &= ~STREAMTCP_FLAG_ASYNC;
5594  }
5595  }
5596 
5597  /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */
5598  if (!(tcph->th_flags & TH_ACK) && TCP_GET_RAW_ACK(tcph) != 0) {
5600  }
5601 
5602  if ((tcph->th_flags & TH_URG) && StreamTcpInlineDropUrg()) {
5604  SCLogDebug("dropping urgent packet");
5605  SCReturnInt(0);
5606  }
5607 
5608  /* If we are on IPS mode, and got a drop action triggered from
5609  * the IP only module, or from a reassembled msg and/or from an
5610  * applayer detection, then drop the rest of the packets of the
5611  * same stream and avoid inspecting it any further */
5612  if (StreamTcpCheckFlowDrops(p) == 1) {
5614  SCLogDebug("flow triggered a drop rule");
5616  /* return the segments to the pool */
5618  SCReturnInt(0);
5619  }
5620 
5621  if (ssn == NULL || ssn->state == TCP_NONE) {
5622  if (StreamTcpPacketStateNone(tv, p, stt, ssn) == -1) {
5623  goto error;
5624  }
5625 
5626  if (ssn != NULL)
5627  SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto);
5628  } else {
5629  /* special case for PKT_PSEUDO_STREAM_END packets:
5630  * bypass the state handling and various packet checks,
5631  * we care about reassembly here. */
5632  if (p->flags & PKT_PSEUDO_STREAM_END) {
5633  if (PKT_IS_TOCLIENT(p)) {
5634  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5635  } else {
5636  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5637  }
5638  /* straight to 'skip' as we already handled reassembly */
5639  goto skip;
5640  }
5641 
5642  if (p->flow->flags & FLOW_WRONG_THREAD) {
5643  /* Stream and/or session in known bad condition. Block events
5644  * from being set. */
5646  }
5647 
5648  if (StreamTcpPacketIsKeepAlive(ssn, p) == 1) {
5649  goto skip;
5650  }
5651  if (StreamTcpPacketIsKeepAliveACK(ssn, p) == 1) {
5652  StreamTcpClearKeepAliveFlag(ssn, p);
5653  goto skip;
5654  }
5655  StreamTcpClearKeepAliveFlag(ssn, p);
5656 
5657  const bool is_zwp_ack = StreamTcpPacketIsZeroWindowProbeAck(ssn, p);
5658  if (PKT_IS_TOCLIENT(p)) {
5659  ssn->flags &= ~STREAMTCP_FLAG_ZWP_TS;
5660  } else {
5661  ssn->flags &= ~STREAMTCP_FLAG_ZWP_TC;
5662  }
5663  if (is_zwp_ack) {
5665  goto skip;
5666  }
5667 
5668  if (StreamTcpPacketIsDupAck(ssn, p) == true) {
5670  // TODO see if we can skip work on these
5671  }
5672 
5673  /* if packet is not a valid window update, check if it is perhaps
5674  * a bad window update that we should ignore (and alert on) */
5675  if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) {
5676  if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0) {
5677  if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
5678  goto skip;
5679  if (StreamTcpPacketIsOutdatedAck(ssn, p))
5680  goto skip;
5681  }
5682  }
5683 
5684  int ret = StreamTcpPacketIsSpuriousRetransmission(ssn, p);
5685  if (ret > 0) {
5687  /* skip packet if fully before base_seq */
5688  if (ret == 2)
5689  goto skip;
5690  }
5691 
5692  /* handle the per 'state' logic */
5693  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->state) < 0)
5694  goto error;
5695 
5696  skip:
5697  StreamTcpPacketCheckPostRst(ssn, p);
5698 
5699  if (ssn->state >= TCP_ESTABLISHED) {
5700  p->flags |= PKT_STREAM_EST;
5701  }
5702  }
5703 
5704  if (ssn != NULL) {
5705  /* recalc the csum on the packet if it was modified */
5706  if (p->flags & PKT_STREAM_MODIFIED) {
5708  }
5709  /* check for conditions that may make us not want to log this packet */
5710 
5711  /* streams that hit depth */
5714  {
5715  /* we can call bypass callback, if enabled */
5716  if (StreamTcpBypassEnabled()) {
5718  }
5719  }
5720 
5723  {
5725  }
5726 
5727  /* encrypted packets */
5730  {
5732  }
5733 
5734  if (ssn->flags & STREAMTCP_FLAG_BYPASS) {
5735  /* we can call bypass callback, if enabled */
5736  if (StreamTcpBypassEnabled()) {
5738  }
5739 
5740  /* if stream is dead and we have no detect engine at all, bypass. */
5741  } else if (g_detect_disabled &&
5745  {
5746  SCLogDebug("bypass as stream is dead and we have no rules");
5748  }
5749  }
5750 
5751  SCReturnInt(0);
5752 
5753 error:
5754  /* recalc the csum on the packet if it was modified */
5755  if (p->flags & PKT_STREAM_MODIFIED) {
5757  }
5758 
5759  if (StreamTcpInlineDropInvalid()) {
5760  /* disable payload inspection as we're dropping this packet
5761  * anyway. Doesn't disable all detection, so we can still
5762  * match on the stream event that was set. */
5763  DecodeSetNoPayloadInspectionFlag(p);
5765  }
5766  SCReturnInt(-1);
5767 }
5768 
5769 /**
5770  * \brief Function to validate the checksum of the received packet. If the
5771  * checksum is invalid, packet will be dropped, as the end system will
5772  * also drop the packet.
5773  *
5774  * \param p Packet of which checksum has to be validated
5775  * \retval 1 if the checksum is valid, otherwise 0
5776  */
5777 static inline int StreamTcpValidateChecksum(Packet *p)
5778 {
5779  int ret = 1;
5780 
5781  if (p->flags & PKT_IGNORE_CHECKSUM)
5782  return ret;
5783 
5784  if (!p->l4.csum_set) {
5785  const TCPHdr *tcph = PacketGetTCP(p);
5786  if (PacketIsIPv4(p)) {
5787  const IPV4Hdr *ip4h = PacketGetIPv4(p);
5788  p->l4.csum = TCPChecksum(ip4h->s_ip_addrs, (uint16_t *)tcph,
5789  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5790  p->l4.csum_set = true;
5791  } else if (PacketIsIPv6(p)) {
5792  const IPV6Hdr *ip6h = PacketGetIPv6(p);
5793  p->l4.csum = TCPV6Checksum(ip6h->s_ip6_addrs, (uint16_t *)tcph,
5794  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5795  p->l4.csum_set = true;
5796  }
5797  }
5798 
5799  if (p->l4.csum != 0) {
5800  ret = 0;
5801  if (p->livedev) {
5802  (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1);
5803  } else if (p->pcap_cnt) {
5805  }
5806  }
5807 
5808  return ret;
5809 }
5810 
5811 /** \internal
5812  * \brief check if a packet is a valid stream started
5813  * \retval bool true/false */
5814 static int TcpSessionPacketIsStreamStarter(const Packet *p)
5815 {
5816  const TCPHdr *tcph = PacketGetTCP(p);
5817  if (tcph->th_flags & (TH_RST | TH_FIN)) {
5818  return 0;
5819  }
5820 
5821  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5822  SCLogDebug("packet %" PRIu64 " is a stream starter: %02x", p->pcap_cnt, tcph->th_flags);
5823  return 1;
5824  }
5825 
5827  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5828  SCLogDebug("packet %" PRIu64 " is a midstream stream starter: %02x", p->pcap_cnt,
5829  tcph->th_flags);
5830  return 1;
5831  }
5832  }
5833  return 0;
5834 }
5835 
5836 /** \internal
5837  * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused
5838  * \retval bool true yes reuse, false no keep tracking old ssn */
5839 static bool TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn)
5840 {
5841  const TCPHdr *tcph = PacketGetTCP(p);
5842  if (FlowGetPacketDirection(f, p) == TOSERVER) {
5843  if (ssn == NULL) {
5844  /* most likely a flow that was picked up after the 3whs, or a flow that
5845  * does not have a session due to memcap issues. */
5846  SCLogDebug("steam starter packet %" PRIu64 ", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5847  return true;
5848  }
5850  SCLogDebug("steam starter packet %" PRIu64
5851  ", ssn %p. STREAMTCP_FLAG_TFO_DATA_IGNORED set. Reuse.",
5852  p->pcap_cnt, ssn);
5853  return true;
5854  }
5855  if (SEQ_EQ(ssn->client.isn, TCP_GET_RAW_SEQ(tcph))) {
5856  SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5857  return false;
5858  }
5859  if (ssn->state >= TCP_LAST_ACK) {
5860  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5861  return true;
5862  } else if (ssn->state == TCP_NONE) {
5863  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5864  return true;
5865  } else { // < TCP_LAST_ACK
5866  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5867  return false;
5868  }
5869 
5870  } else {
5871  if (ssn == NULL) {
5872  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5873  return true;
5874  }
5875  if (ssn->state >= TCP_LAST_ACK) {
5876  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5877  return true;
5878  } else if (ssn->state == TCP_NONE) {
5879  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5880  return true;
5881  } else { // < TCP_LAST_ACK
5882  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5883  return false;
5884  }
5885  }
5886 
5887  SCLogDebug("default: how did we get here?");
5888  return false;
5889 }
5890 
5891 /** \internal
5892  * \brief check if ssn is done enough for reuse by syn/ack
5893  * \note should only be called if midstream is enabled
5894  */
5895 static bool TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn)
5896 {
5897  const TCPHdr *tcph = PacketGetTCP(p);
5898  if (FlowGetPacketDirection(f, p) == TOCLIENT) {
5899  if (ssn == NULL) {
5900  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
5901  return false;
5902  }
5903  if (SEQ_EQ(ssn->server.isn, TCP_GET_RAW_SEQ(tcph))) {
5904  SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5905  return false;
5906  }
5907  if (ssn->state >= TCP_LAST_ACK) {
5908  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5909  return true;
5910  } else if (ssn->state == TCP_NONE) {
5911  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5912  return true;
5913  } else { // < TCP_LAST_ACK
5914  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5915  return false;
5916  }
5917 
5918  } else {
5919  if (ssn == NULL) {
5920  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5921  return true;
5922  }
5923  if (ssn->state >= TCP_LAST_ACK) {
5924  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5925  return true;
5926  } else if (ssn->state == TCP_NONE) {
5927  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5928  return true;
5929  } else { // < TCP_LAST_ACK
5930  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5931  return false;
5932  }
5933  }
5934 
5935  SCLogDebug("default: how did we get here?");
5936  return false;
5937 }
5938 
5939 /** \brief Check if SSN is done enough for reuse
5940  *
5941  * Reuse means a new TCP session reuses the tuple (flow in suri)
5942  *
5943  * \retval bool true if ssn can be reused, false if not */
5944 static bool TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn)
5945 {
5946  const TCPHdr *tcph = PacketGetTCP(p);
5947  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5948  return TcpSessionReuseDoneEnoughSyn(p, f, ssn);
5949  }
5950 
5952  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5953  return TcpSessionReuseDoneEnoughSynAck(p, f, ssn);
5954  }
5955  }
5956 
5957  return false;
5958 }
5959 
5960 bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
5961 {
5962  if (p->proto == IPPROTO_TCP && PacketIsTCP(p)) {
5963  if (TcpSessionPacketIsStreamStarter(p) == 1) {
5964  if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) {
5965  return true;
5966  }
5967  }
5968  }
5969  return false;
5970 }
5971 
5973 {
5974  DEBUG_VALIDATE_BUG_ON(p->flow == NULL);
5975  if (unlikely(p->flow == NULL)) {
5976  return TM_ECODE_OK;
5977  }
5978 
5979  StreamTcpThread *stt = (StreamTcpThread *)data;
5980 
5981  SCLogDebug("p->pcap_cnt %" PRIu64 " direction %s pkt_src %s", p->pcap_cnt,
5982  p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
5983  : "noflow",
5984  PktSrcToString(p->pkt_src));
5985  t_pcapcnt = p->pcap_cnt;
5986 
5987  if (!(PacketIsTCP(p))) {
5988  return TM_ECODE_OK;
5989  }
5990 
5991  HandleThreadId(tv, p, stt);
5992 
5993  /* only TCP packets with a flow from here */
5994 
5995  if (!(p->flags & PKT_PSEUDO_STREAM_END)) {
5997  if (StreamTcpValidateChecksum(p) == 0) {
5999  return TM_ECODE_OK;
6000  }
6001  } else {
6002  p->flags |= PKT_IGNORE_CHECKSUM;
6003  }
6004  } else {
6005  p->flags |= PKT_IGNORE_CHECKSUM; //TODO check that this is set at creation
6006  }
6008 
6009  (void)StreamTcpPacket(tv, p, stt, pq);
6010 
6011  return TM_ECODE_OK;
6012 }
6013 
6014 TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
6015 {
6016  SCEnter();
6017  StreamTcpThread *stt = SCCalloc(1, sizeof(StreamTcpThread));
6018  if (unlikely(stt == NULL))
6020  stt->ssn_pool_id = -1;
6022 
6023  *data = (void *)stt;
6024 
6025  stt->counter_tcp_active_sessions = StatsRegisterCounter("tcp.active_sessions", tv);
6026  stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv);
6027  stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv);
6028  stt->counter_tcp_ssn_from_cache = StatsRegisterCounter("tcp.ssn_from_cache", tv);
6029  stt->counter_tcp_ssn_from_pool = StatsRegisterCounter("tcp.ssn_from_pool", tv);
6031  stream_config.ssn_memcap_policy, "tcp.ssn_memcap_exception_policy.",
6032  IsStreamTcpSessionMemcapExceptionPolicyStatsValid);
6033 
6034  stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv);
6035  stt->counter_tcp_pseudo_failed = StatsRegisterCounter("tcp.pseudo_failed", tv);
6036  stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv);
6037  stt->counter_tcp_midstream_pickups = StatsRegisterCounter("tcp.midstream_pickups", tv);
6038  if (stream_config.midstream) {
6041  "tcp.midstream_exception_policy.", IsMidstreamExceptionPolicyStatsValid);
6042  } else {
6045  "tcp.midstream_exception_policy.", IsMidstreamExceptionPolicyStatsValid);
6046  }
6047 
6048  stt->counter_tcp_wrong_thread = StatsRegisterCounter("tcp.pkt_on_wrong_thread", tv);
6049  stt->counter_tcp_ack_unseen_data = StatsRegisterCounter("tcp.ack_unseen_data", tv);
6050 
6051  /* init reassembly ctx */
6053  if (stt->ra_ctx == NULL)
6055 
6056  stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv);
6057 
6060  "tcp.reassembly_exception_policy.", IsReassemblyMemcapExceptionPolicyStatsValid);
6061 
6063  StatsRegisterCounter("tcp.segment_from_cache", tv);
6064  stt->ra_ctx->counter_tcp_segment_from_pool = StatsRegisterCounter("tcp.segment_from_pool", tv);
6065  stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv);
6066  stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv);
6067  stt->ra_ctx->counter_tcp_reass_overlap = StatsRegisterCounter("tcp.overlap", tv);
6068  stt->ra_ctx->counter_tcp_reass_overlap_diff_data = StatsRegisterCounter("tcp.overlap_diff_data", tv);
6069 
6070  stt->ra_ctx->counter_tcp_reass_data_normal_fail = StatsRegisterCounter("tcp.insert_data_normal_fail", tv);
6071  stt->ra_ctx->counter_tcp_reass_data_overlap_fail = StatsRegisterCounter("tcp.insert_data_overlap_fail", tv);
6072  stt->ra_ctx->counter_tcp_urgent_oob = StatsRegisterCounter("tcp.urgent_oob_data", tv);
6073 
6074  SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p",
6075  stt, stt->ra_ctx);
6076 
6077  SCMutexLock(&ssn_pool_mutex);
6078  if (ssn_pool == NULL) {
6079  ssn_pool = PoolThreadInit(1, /* thread */
6080  0, /* unlimited */
6082  sizeof(TcpSession),
6083  StreamTcpSessionPoolAlloc,
6084  StreamTcpSessionPoolInit, NULL,
6085  StreamTcpSessionPoolCleanup, NULL);
6086  stt->ssn_pool_id = 0;
6087  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6088  } else {
6089  /* grow ssn_pool until we have a element for our thread id */
6091  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6092  }
6093  SCMutexUnlock(&ssn_pool_mutex);
6094  if (stt->ssn_pool_id < 0 || ssn_pool == NULL) {
6095  SCLogError("failed to setup/expand stream session pool. Expand stream.memcap?");
6097  }
6098 
6100 }
6101 
6103 {
6104  SCEnter();
6105  StreamTcpThread *stt = (StreamTcpThread *)data;
6106  if (stt == NULL) {
6107  return TM_ECODE_OK;
6108  }
6109 
6110  /* XXX */
6111 
6112  /* free reassembly ctx */
6114 
6115  /* clear memory */
6116  memset(stt, 0, sizeof(StreamTcpThread));
6117 
6118  SCFree(stt);
6120 }
6121 
6122 /**
6123  * \brief Function to check the validity of the RST packets based on the
6124  * target OS of the given packet.
6125  *
6126  * \param ssn TCP session to which the given packet belongs
6127  * \param p Packet which has to be checked for its validity
6128  *
6129  * \retval 0 unacceptable RST
6130  * \retval 1 acceptable RST
6131  *
6132  * WebSense sends RST packets that are:
6133  * - RST flag, win 0, ack 0, seq = nextseq
6134  *
6135  */
6136 
6137 static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
6138 {
6139  uint8_t os_policy;
6140  const TCPHdr *tcph = PacketGetTCP(p);
6141  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6142 
6144  SCReturnInt(1);
6145  }
6146 
6147  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
6148  if (!StreamTcpValidateTimestamp(ssn, p)) {
6149  SCReturnInt(0);
6150  }
6151  }
6152 
6153  /* RST with data, it's complicated:
6154 
6155  4.2.2.12 RST Segment: RFC-793 Section 3.4
6156 
6157  A TCP SHOULD allow a received RST segment to include data.
6158 
6159  DISCUSSION
6160  It has been suggested that a RST segment could contain
6161  ASCII text that encoded and explained the cause of the
6162  RST. No standard has yet been established for such
6163  data.
6164  */
6165  if (p->payload_len)
6167 
6168  /* Set up the os_policy to be used in validating the RST packets based on
6169  target system */
6170  if (PKT_IS_TOSERVER(p)) {
6171  if (ssn->server.os_policy == 0)
6172  StreamTcpSetOSPolicy(&ssn->server, p);
6173 
6174  os_policy = ssn->server.os_policy;
6175 
6176  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6177  StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
6178  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6180  SCReturnInt(0);
6181  }
6182 
6183  } else {
6184  if (ssn->client.os_policy == 0)
6185  StreamTcpSetOSPolicy(&ssn->client, p);
6186 
6187  os_policy = ssn->client.os_policy;
6188 
6189  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6190  StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
6191  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6193  SCReturnInt(0);
6194  }
6195  }
6196 
6197  /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
6198  * validate these (requires key that is set/transferred out of band), we can't know
6199  * if the RST will be accepted or rejected by the end host. We accept it, but keep
6200  * tracking if the sender of it ignores it, which would be a sign of injection. */
6202  TcpStream *receiver_stream;
6203  if (PKT_IS_TOSERVER(p)) {
6204  receiver_stream = &ssn->server;
6205  } else {
6206  receiver_stream = &ssn->client;
6207  }
6208  SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
6209  receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
6210  }
6211 
6212  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
6213  if (PKT_IS_TOSERVER(p)) {
6214  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6215  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6216  return 1;
6217  }
6218  } else {
6219  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6220  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6221  return 1;
6222  }
6223  }
6224  SCLogDebug("ssn %p: ASYNC reject RST", ssn);
6225  return 0;
6226  }
6227 
6228  switch (os_policy) {
6229  case OS_POLICY_HPUX11:
6230  if(PKT_IS_TOSERVER(p)){
6231  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6232  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6233  return 1;
6234  } else {
6235  SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " "
6236  "and server SEQ: %" PRIu32 "",
6237  seq, ssn->client.next_seq);
6238  return 0;
6239  }
6240  } else { /* implied to client */
6241  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6242  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6243  return 1;
6244  } else {
6245  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6246  "and client SEQ: %" PRIu32 "",
6247  seq, ssn->server.next_seq);
6248  return 0;
6249  }
6250  }
6251  break;
6252  case OS_POLICY_OLD_LINUX:
6253  case OS_POLICY_LINUX:
6254  case OS_POLICY_SOLARIS:
6255  if(PKT_IS_TOSERVER(p)){
6256  if (SEQ_GEQ((seq + p->payload_len),
6257  ssn->client.last_ack)) { /*window base is needed !!*/
6258  if (SEQ_LT(seq, (ssn->client.next_seq + ssn->client.window))) {
6259  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6260  return 1;
6261  }
6262  } else {
6263  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6264  " server SEQ: %" PRIu32 "",
6265  seq, ssn->client.next_seq);
6266  return 0;
6267  }
6268  } else { /* implied to client */
6269  if (SEQ_GEQ((seq + p->payload_len),
6270  ssn->server.last_ack)) { /*window base is needed !!*/
6271  if (SEQ_LT(seq, (ssn->server.next_seq + ssn->server.window))) {
6272  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6273  return 1;
6274  }
6275  } else {
6276  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6277  " client SEQ: %" PRIu32 "",
6278  seq, ssn->server.next_seq);
6279  return 0;
6280  }
6281  }
6282  break;
6283  default:
6284  case OS_POLICY_BSD:
6285  case OS_POLICY_FIRST:
6286  case OS_POLICY_HPUX10:
6287  case OS_POLICY_IRIX:
6288  case OS_POLICY_MACOS:
6289  case OS_POLICY_LAST:
6290  case OS_POLICY_WINDOWS:
6291  case OS_POLICY_WINDOWS2K3:
6292  case OS_POLICY_VISTA:
6293  if(PKT_IS_TOSERVER(p)) {
6294  if (SEQ_EQ(seq, ssn->client.next_seq)) {
6295  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6296  return 1;
6297  } else {
6298  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6299  "and server SEQ: %" PRIu32 "",
6300  seq, ssn->client.next_seq);
6301  return 0;
6302  }
6303  } else { /* implied to client */
6304  if (SEQ_EQ(seq, ssn->server.next_seq)) {
6305  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u", seq,
6306  ssn->server.next_seq);
6307  return 1;
6308  } else {
6309  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6310  " client SEQ: %" PRIu32 "",
6311  seq, ssn->server.next_seq);
6312  return 0;
6313  }
6314  }
6315  break;
6316  }
6317  return 0;
6318 }
6319 
6320 /**
6321  * \brief Function to check the validity of the received timestamp based on
6322  * the target OS of the given stream.
6323  *
6324  * It's passive except for:
6325  * 1. it sets the os policy on the stream if necessary
6326  * 2. it sets an event in the packet if necessary
6327  *
6328  * \param ssn TCP session to which the given packet belongs
6329  * \param p Packet which has to be checked for its validity
6330  *
6331  * \retval 1 if the timestamp is valid
6332  * \retval 0 if the timestamp is invalid
6333  */
6334 static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p)
6335 {
6336  SCEnter();
6337 
6338  TcpStream *sender_stream;
6339  TcpStream *receiver_stream;
6340  uint8_t ret = 1;
6341  uint8_t check_ts = 1;
6342  const TCPHdr *tcph = PacketGetTCP(p);
6343  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6344 
6345  if (PKT_IS_TOSERVER(p)) {
6346  sender_stream = &ssn->client;
6347  receiver_stream = &ssn->server;
6348  } else {
6349  sender_stream = &ssn->server;
6350  receiver_stream = &ssn->client;
6351  }
6352 
6353  /* Set up the os_policy to be used in validating the timestamps based on
6354  the target system */
6355  if (receiver_stream->os_policy == 0) {
6356  StreamTcpSetOSPolicy(receiver_stream, p);
6357  }
6358 
6359  if (TCP_HAS_TS(p)) {
6360  uint32_t ts = TCP_GET_TSVAL(p);
6361  uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
6362  uint32_t last_ts = sender_stream->last_ts;
6363 
6364  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6365  /* The 3whs used the timestamp with 0 value. */
6366  switch (receiver_stream->os_policy) {
6367  case OS_POLICY_LINUX:
6368  case OS_POLICY_WINDOWS2K3:
6369  /* Linux and windows 2003 does not allow the use of 0 as
6370  * timestamp in the 3whs. */
6371  check_ts = 0;
6372  break;
6373 
6374  case OS_POLICY_OLD_LINUX:
6375  case OS_POLICY_WINDOWS:
6376  case OS_POLICY_VISTA:
6377  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6378  last_ts = ts;
6379  check_ts = 0; /*next packet will be checked for validity
6380  and stream TS has been updated with this
6381  one.*/
6382  }
6383  break;
6384  }
6385  }
6386 
6387  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6388  /* HPUX11 ignores the timestamp of out of order packets */
6389  if (!SEQ_EQ(sender_stream->next_seq, seq))
6390  check_ts = 0;
6391  }
6392 
6393  if (ts == 0) {
6394  switch (receiver_stream->os_policy) {
6395  case OS_POLICY_OLD_LINUX:
6396  case OS_POLICY_WINDOWS:
6397  case OS_POLICY_WINDOWS2K3:
6398  case OS_POLICY_VISTA:
6399  case OS_POLICY_SOLARIS:
6400  /* Old Linux and windows allowed packet with 0 timestamp. */
6401  break;
6402  default:
6403  /* other OS simply drop the packet with 0 timestamp, when
6404  * 3whs has valid timestamp*/
6405  goto invalid;
6406  }
6407  }
6408 
6409  if (check_ts) {
6410  int32_t result = 0;
6411 
6412  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts);
6413 
6414  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6415  /* Linux accepts TS which are off by one.*/
6416  result = (int32_t) ((ts - last_ts) + 1);
6417  } else {
6418  result = (int32_t) (ts - last_ts);
6419  }
6420 
6421  SCLogDebug("result %" PRIi32 ", p->ts(secs) %" PRIuMAX "", result,
6422  (uintmax_t)SCTIME_SECS(p->ts));
6423 
6424  if (last_pkt_ts == 0 &&
6426  {
6427  last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6428  }
6429 
6430  if (result < 0) {
6431  SCLogDebug("timestamp is not valid last_ts "
6432  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6433  "%" PRId32 "", last_ts, ts, result);
6434  /* candidate for rejection */
6435  ret = 0;
6436  } else if ((sender_stream->last_ts != 0) &&
6437  (((uint32_t)SCTIME_SECS(p->ts)) > last_pkt_ts + PAWS_24DAYS)) {
6438  SCLogDebug("packet is not valid last_pkt_ts "
6439  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6440  last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6441  /* candidate for rejection */
6442  ret = 0;
6443  }
6444 
6445  if (ret == 0) {
6446  /* if the timestamp of packet is not valid then, check if the
6447  * current stream timestamp is not so old. if so then we need to
6448  * accept the packet and update the stream->last_ts (RFC 1323)*/
6449  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6450  (((uint32_t)SCTIME_SECS(p->ts) > (last_pkt_ts + PAWS_24DAYS)))) {
6451  SCLogDebug("timestamp considered valid anyway");
6452  } else {
6453  goto invalid;
6454  }
6455  }
6456  }
6457  }
6458 
6459  SCReturnInt(1);
6460 
6461 invalid:
6463  SCReturnInt(0);
6464 }
6465 
6466 /**
6467  * \brief Function to check the validity of the received timestamp based on
6468  * the target OS of the given stream and update the session.
6469  *
6470  * \param ssn TCP session to which the given packet belongs
6471  * \param p Packet which has to be checked for its validity
6472  *
6473  * \retval 1 if the timestamp is valid
6474  * \retval 0 if the timestamp is invalid
6475  */
6476 static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p)
6477 {
6478  SCEnter();
6479 
6480  TcpStream *sender_stream;
6481  TcpStream *receiver_stream;
6482  uint8_t ret = 1;
6483  uint8_t check_ts = 1;
6484  const TCPHdr *tcph = PacketGetTCP(p);
6485  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6486 
6487  if (PKT_IS_TOSERVER(p)) {
6488  sender_stream = &ssn->client;
6489  receiver_stream = &ssn->server;
6490  } else {
6491  sender_stream = &ssn->server;
6492  receiver_stream = &ssn->client;
6493  }
6494 
6495  /* Set up the os_policy to be used in validating the timestamps based on
6496  the target system */
6497  if (receiver_stream->os_policy == 0) {
6498  StreamTcpSetOSPolicy(receiver_stream, p);
6499  }
6500 
6501  if (TCP_HAS_TS(p)) {
6502  uint32_t ts = TCP_GET_TSVAL(p);
6503 
6504  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6505  /* The 3whs used the timestamp with 0 value. */
6506  switch (receiver_stream->os_policy) {
6507  case OS_POLICY_LINUX:
6508  case OS_POLICY_WINDOWS2K3:
6509  /* Linux and windows 2003 does not allow the use of 0 as
6510  * timestamp in the 3whs. */
6512  check_ts = 0;
6513  break;
6514 
6515  case OS_POLICY_OLD_LINUX:
6516  case OS_POLICY_WINDOWS:
6517  case OS_POLICY_VISTA:
6518  sender_stream->flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
6519  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6520  sender_stream->last_ts = ts;
6521  check_ts = 0; /*next packet will be checked for validity
6522  and stream TS has been updated with this
6523  one.*/
6524  }
6525  break;
6526  default:
6527  break;
6528  }
6529  }
6530 
6531  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6532  /*HPUX11 ignores the timestamp of out of order packets*/
6533  if (!SEQ_EQ(sender_stream->next_seq, seq))
6534  check_ts = 0;
6535  }
6536 
6537  if (ts == 0) {
6538  switch (receiver_stream->os_policy) {
6539  case OS_POLICY_OLD_LINUX:
6540  case OS_POLICY_WINDOWS:
6541  case OS_POLICY_WINDOWS2K3:
6542  case OS_POLICY_VISTA:
6543  case OS_POLICY_SOLARIS:
6544  /* Old Linux and windows allowed packet with 0 timestamp. */
6545  break;
6546  default:
6547  /* other OS simply drop the packet with 0 timestamp, when
6548  * 3whs has valid timestamp*/
6549  goto invalid;
6550  }
6551  }
6552 
6553  if (check_ts) {
6554  int32_t result = 0;
6555 
6556  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts);
6557 
6558  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6559  /* Linux accepts TS which are off by one.*/
6560  result = (int32_t) ((ts - sender_stream->last_ts) + 1);
6561  } else {
6562  result = (int32_t) (ts - sender_stream->last_ts);
6563  }
6564 
6565  SCLogDebug("result %" PRIi32 ", p->ts(sec) %" PRIuMAX "", result,
6566  (uintmax_t)SCTIME_SECS(p->ts));
6567 
6568  if (sender_stream->last_pkt_ts == 0 &&
6570  {
6571  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6572  }
6573 
6574  if (result < 0) {
6575  SCLogDebug("timestamp is not valid sender_stream->last_ts "
6576  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6577  "%" PRId32 "", sender_stream->last_ts, ts, result);
6578  /* candidate for rejection */
6579  ret = 0;
6580  } else if ((sender_stream->last_ts != 0) &&
6581  (((uint32_t)SCTIME_SECS(p->ts)) >
6582  sender_stream->last_pkt_ts + PAWS_24DAYS)) {
6583  SCLogDebug("packet is not valid sender_stream->last_pkt_ts "
6584  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6585  sender_stream->last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6586  /* candidate for rejection */
6587  ret = 0;
6588  }
6589 
6590  if (ret == 1) {
6591  /* Update the timestamp and last seen packet time for this
6592  * stream */
6593  if (SEQ_EQ(sender_stream->next_seq, seq))
6594  sender_stream->last_ts = ts;
6595 
6596  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6597 
6598  } else if (ret == 0) {
6599  /* if the timestamp of packet is not valid then, check if the
6600  * current stream timestamp is not so old. if so then we need to
6601  * accept the packet and update the stream->last_ts (RFC 1323)*/
6602  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6603  (((uint32_t)SCTIME_SECS(p->ts) >
6604  (sender_stream->last_pkt_ts + PAWS_24DAYS)))) {
6605  sender_stream->last_ts = ts;
6606  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6607 
6608  SCLogDebug("timestamp considered valid anyway");
6609  } else {
6610  goto invalid;
6611  }
6612  }
6613  }
6614  } else {
6615  /* Solaris stops using timestamps if a packet is received
6616  without a timestamp and timestamps were used on that stream. */
6617  if (receiver_stream->os_policy == OS_POLICY_SOLARIS)
6619  }
6620 
6621  SCReturnInt(1);
6622 
6623 invalid:
6625  SCReturnInt(0);
6626 }
6627 
6628 /**
6629  * \brief Function to test the received ACK values against the stream window
6630  * and previous ack value. ACK values should be higher than previous
6631  * ACK value and less than the next_win value.
6632  *
6633  * \param ssn TcpSession for state access
6634  * \param stream TcpStream of which last_ack needs to be tested
6635  * \param p Packet which is used to test the last_ack
6636  *
6637  * \retval 0 ACK is valid, last_ack is updated if ACK was higher
6638  * \retval -1 ACK is invalid
6639  */
6640 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p)
6641 {
6642  SCEnter();
6643 
6644  const TCPHdr *tcph = PacketGetTCP(p);
6645  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
6646 
6647  if (!(tcph->th_flags & TH_ACK))
6648  SCReturnInt(0);
6649 
6650  /* fast track */
6651  if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win))
6652  {
6653  SCLogDebug("ssn %p: ACK %u in bounds > %u <= %u", ssn, ack, stream->last_ack,
6654  stream->next_win);
6655  SCReturnInt(0);
6656  }
6657  /* fast track */
6658  else if (SEQ_EQ(ack, stream->last_ack)) {
6659  SCLogDebug("ssn %p: pkt ACK %" PRIu32 " == stream last ACK %" PRIu32, ssn, ack,
6660  stream->last_ack);
6661  SCReturnInt(0);
6662  }
6663 
6664  /* exception handling */
6665  if (SEQ_LT(ack, stream->last_ack)) {
6666  SCLogDebug("pkt ACK %" PRIu32 " < stream last ACK %" PRIu32, ack, stream->last_ack);
6667 
6668  /* This is an attempt to get a 'left edge' value that we can check against.
6669  * It doesn't work when the window is 0, need to think of a better way. */
6670 
6671  if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) {
6672  SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window "
6673  "%"PRIu32" = %"PRIu32, ack, stream->last_ack,
6674  stream->window, stream->last_ack - stream->window);
6675  goto invalid;
6676  }
6677 
6678  SCReturnInt(0);
6679  }
6680 
6681  /* no further checks possible for ASYNC */
6682  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
6683  SCReturnInt(0);
6684  }
6685 
6686  if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) {
6687  SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win);
6688  goto invalid;
6689  /* a toclient RST as a response to SYN, next_win is 0, ack will be isn+1, just like
6690  * the syn ack */
6691  } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && tcph->th_flags & TH_RST &&
6692  SEQ_EQ(ack, stream->isn + 1)) {
6693  SCReturnInt(0);
6694  }
6695 
6696  SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32
6697  " next_win %"PRIu32, ack, stream->last_ack, stream->next_win);
6698 invalid:
6700  SCReturnInt(-1);
6701 }
6702 
6703 /** \brief update reassembly progress
6704 
6705  * \param ssn TCP Session
6706  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6707  */
6709  const uint32_t progress)
6710 {
6711  if (direction) {
6712  ssn->server.app_progress_rel += progress;
6713  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->server));
6714  } else {
6715  ssn->client.app_progress_rel += progress;
6716  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->client));
6717  }
6718 }
6719 
6720 /** \brief disable reassembly
6721 
6722  * Disable app layer and set raw inspect to no longer accept new data.
6723  * Stream engine will then fully disable raw after last inspection.
6724  *
6725  * \param ssn TCP Session to set the flag in
6726  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6727  */
6729 {
6731  if (direction) {
6733  } else {
6735  }
6736 }
6737 
6738 /** \brief Set the No reassembly flag for the given direction in given TCP
6739  * session.
6740  *
6741  * \param ssn TCP Session to set the flag in
6742  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6743  */
6745 {
6746  direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) :
6748 }
6749 
6750 /** \brief enable bypass
6751  *
6752  * \param ssn TCP Session to set the flag in
6753  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6754  */
6756 {
6757  ssn->flags |= STREAMTCP_FLAG_BYPASS;
6758 }
6759 
6760 /** \brief Create a pseudo packet injected into the engine to signal the
6761  * opposing direction of this stream trigger detection/logging.
6762  *
6763  * \param parent real packet
6764  * \param pq packet queue to store the new pseudo packet in
6765  * \param dir 0 ts 1 tc
6766  */
6767 static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv,
6768  StreamTcpThread *stt, Packet *parent,
6769  TcpSession *ssn, PacketQueueNoLock *pq, int dir)
6770 {
6771  SCEnter();
6772  Flow *f = parent->flow;
6773  TCPHdr *tcph = NULL;
6774 
6775  if (parent->flags & PKT_PSEUDO_DETECTLOG_FLUSH) {
6776  SCReturn;
6777  }
6778  if ((f->flags & (FLOW_IPV4 | FLOW_IPV6)) == 0) {
6779  SCReturn;
6780  }
6781 
6782  Packet *np = PacketPoolGetPacket();
6783  if (np == NULL) {
6784  SCReturn;
6785  }
6787 
6788  np->tenant_id = f->tenant_id;
6789  np->datalink = DLT_RAW;
6790  np->proto = IPPROTO_TCP;
6791  FlowReference(&np->flow, f);
6792  np->flags |= PKT_STREAM_EST;
6793  np->flags |= PKT_HAS_FLOW;
6794  np->flags |= PKT_IGNORE_CHECKSUM;
6796  memcpy(&np->vlan_id[0], &f->vlan_id[0], sizeof(np->vlan_id));
6797  np->vlan_idx = f->vlan_idx;
6798  np->livedev = (struct LiveDevice_ *)f->livedev;
6799 
6800  if (parent->flags & PKT_NOPACKET_INSPECTION) {
6801  DecodeSetNoPacketInspectionFlag(np);
6802  }
6803  if (parent->flags & PKT_NOPAYLOAD_INSPECTION) {
6804  DecodeSetNoPayloadInspectionFlag(np);
6805  }
6806 
6807  if (dir == 0) {
6808  SCLogDebug("pseudo is to_server");
6810  } else {
6811  SCLogDebug("pseudo is to_client");
6813  }
6815  np->payload = NULL;
6816  np->payload_len = 0;
6817 
6818  if (FLOW_IS_IPV4(f)) {
6819  if (dir == 0) {
6822  np->sp = f->sp;
6823  np->dp = f->dp;
6824  } else {
6827  np->sp = f->dp;
6828  np->dp = f->sp;
6829  }
6830 
6831  /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
6832  * Force an allocation if it is not the case.
6833  */
6834  if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) {
6835  if (PacketCallocExtPkt(np, 40) == -1) {
6836  goto error;
6837  }
6838  }
6839  /* set the ip header */
6840  IPV4Hdr *ip4h = PacketSetIPV4(np, GET_PKT_DATA(np));
6841  /* version 4 and length 20 bytes for the tcp header */
6842  ip4h->ip_verhl = 0x45;
6843  ip4h->ip_tos = 0;
6844  ip4h->ip_len = htons(40);
6845  ip4h->ip_id = 0;
6846  ip4h->ip_off = 0;
6847  ip4h->ip_ttl = 64;
6848  ip4h->ip_proto = IPPROTO_TCP;
6849  if (dir == 0) {
6850  ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
6851  ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
6852  } else {
6853  ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
6854  ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
6855  }
6856 
6857  /* set the tcp header */
6858  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 20);
6859 
6860  SET_PKT_LEN(np, 40); /* ipv4 hdr + tcp hdr */
6861  } else {
6862  /* implied IPv6 */
6863 
6864  if (dir == 0) {
6867  np->sp = f->sp;
6868  np->dp = f->dp;
6869  } else {
6872  np->sp = f->dp;
6873  np->dp = f->sp;
6874  }
6875 
6876  /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
6877  * Force an allocation if it is not the case.
6878  */
6879  if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) {
6880  if (PacketCallocExtPkt(np, 60) == -1) {
6881  goto error;
6882  }
6883  }
6884  /* set the ip header */
6885  IPV6Hdr *ip6h = PacketSetIPV6(np, GET_PKT_DATA(np));
6886  /* version 6 */
6887  ip6h->s_ip6_vfc = 0x60;
6888  ip6h->s_ip6_flow = 0;
6889  ip6h->s_ip6_nxt = IPPROTO_TCP;
6890  ip6h->s_ip6_plen = htons(20);
6891  ip6h->s_ip6_hlim = 64;
6892  if (dir == 0) {
6893  ip6h->s_ip6_src[0] = f->src.addr_data32[0];
6894  ip6h->s_ip6_src[1] = f->src.addr_data32[1];
6895  ip6h->s_ip6_src[2] = f->src.addr_data32[2];
6896  ip6h->s_ip6_src[3] = f->src.addr_data32[3];
6897  ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
6898  ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
6899  ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
6900  ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
6901  } else {
6902  ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
6903  ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
6904  ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
6905  ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
6906  ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
6907  ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
6908  ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
6909  ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
6910  }
6911 
6912  /* set the tcp header */
6913  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 40);
6914 
6915  SET_PKT_LEN(np, 60); /* ipv6 hdr + tcp hdr */
6916  }
6917 
6918  tcph->th_offx2 = 0x50;
6919  tcph->th_flags |= TH_ACK;
6920  tcph->th_win = 10;
6921  tcph->th_urp = 0;
6922 
6923  /* to server */
6924  if (dir == 0) {
6925  tcph->th_sport = htons(f->sp);
6926  tcph->th_dport = htons(f->dp);
6927 
6928  tcph->th_seq = htonl(ssn->client.next_seq);
6929  tcph->th_ack = htonl(ssn->server.last_ack);
6930 
6931  /* to client */
6932  } else {
6933  tcph->th_sport = htons(f->dp);
6934  tcph->th_dport = htons(f->sp);
6935 
6936  tcph->th_seq = htonl(ssn->server.next_seq);
6937  tcph->th_ack = htonl(ssn->client.last_ack);
6938  }
6939 
6940  /* use parent time stamp */
6941  np->ts = parent->ts;
6942 
6943  SCLogDebug("np %p", np);
6944  PacketEnqueueNoLock(pq, np);
6945 
6947  SCReturn;
6948 error:
6949  FlowDeReference(&np->flow);
6950  SCReturn;
6951 }
6952 
6953 /** \brief create packets in both directions to flush out logging
6954  * and detection before switching protocols.
6955  * In IDS mode, create first in packet dir, 2nd in opposing
6956  * In IPS mode, do the reverse.
6957  * Flag TCP engine that data needs to be inspected regardless
6958  * of how far we are wrt inspect limits.
6959  */
6961  PacketQueueNoLock *pq)
6962 {
6963  TcpSession *ssn = f->protoctx;
6966  bool ts = PKT_IS_TOSERVER(p) ? true : false;
6967  ts ^= StreamTcpInlineMode();
6968  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^0);
6969  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^1);
6970 }
6971 
6972 /**
6973  * \brief Run callback function on each TCP segment in a single direction.
6974  *
6975  * \note when stream engine is running in inline mode all segments are used,
6976  * in IDS/non-inline mode only ack'd segments are iterated.
6977  *
6978  * \note Must be called under flow lock.
6979  * \var flag determines the direction to run callback on (either to server or to client).
6980  *
6981  * \return -1 in case of error, the number of segment in case of success
6982  *
6983  */
6984 int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
6985 {
6986  TcpStream *stream = NULL;
6987  int cnt = 0;
6988 
6989  if (p->flow == NULL)
6990  return 0;
6991 
6992  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
6993  if (ssn == NULL) {
6994  return 0;
6995  }
6996 
6997  if (flag & STREAM_DUMP_TOSERVER) {
6998  stream = &(ssn->server);
6999  } else {
7000  stream = &(ssn->client);
7001  }
7002 
7003  /* for IDS, return ack'd segments. For IPS all. */
7004  TcpSegment *seg;
7005  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
7007  if (PKT_IS_PSEUDOPKT(p)) {
7008  /* use un-ACK'd data as well */
7009  } else {
7010  /* in IDS mode, use ACK'd data */
7011  if (SEQ_GEQ(seg->seq, stream->last_ack)) {
7012  break;
7013  }
7014  }
7015  }
7016 
7017  const uint8_t *seg_data;
7018  uint32_t seg_datalen;
7019  StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
7020 
7021  int ret = CallbackFunc(p, seg, data, seg_data, seg_datalen);
7022  if (ret != 1) {
7023  SCLogDebug("Callback function has failed");
7024  return -1;
7025  }
7026 
7027  cnt++;
7028  }
7029  return cnt;
7030 }
7031 
7032 /**
7033  * \brief Run callback function on each TCP segment in both directions of a session.
7034  *
7035  * \note when stream engine is running in inline mode all segments are used,
7036  * in IDS/non-inline mode only ack'd segments are iterated.
7037  *
7038  * \note Must be called under flow lock.
7039  *
7040  * \return -1 in case of error, the number of segment in case of success
7041  *
7042  */
7044  const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
7045 {
7046  int ret = 0;
7047  int cnt = 0;
7048 
7049  if (p->flow == NULL)
7050  return 0;
7051 
7052  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
7053 
7054  if (ssn == NULL) {
7055  return -1;
7056  }
7057 
7058  TcpStream *server_stream = &(ssn->server);
7059  TcpStream *client_stream = &(ssn->client);
7060 
7061  TcpSegment *server_node = RB_MIN(TCPSEG, &server_stream->seg_tree);
7062  TcpSegment *client_node = RB_MIN(TCPSEG, &client_stream->seg_tree);
7063  if (server_node == NULL && client_node == NULL) {
7064  return cnt;
7065  }
7066 
7067  while (server_node != NULL || client_node != NULL) {
7068  const uint8_t *seg_data;
7069  uint32_t seg_datalen;
7070  if (server_node == NULL) {
7071  /*
7072  * This means the server side RB Tree has been completely searched,
7073  * thus all that remains is to dump the TcpSegments on the client
7074  * side.
7075  */
7077  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7078  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7079  if (ret != 1) {
7080  SCLogDebug("Callback function has failed");
7081  return -1;
7082  }
7083  client_node = TCPSEG_RB_NEXT(client_node);
7084  } else if (client_node == NULL) {
7085  /*
7086  * This means the client side RB Tree has been completely searched,
7087  * thus all that remains is to dump the TcpSegments on the server
7088  * side.
7089  */
7091  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7092  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7093  if (ret != 1) {
7094  SCLogDebug("Callback function has failed");
7095  return -1;
7096  }
7097  server_node = TCPSEG_RB_NEXT(server_node);
7098  } else {
7099  if (SCTIME_CMP_LT(
7100  client_node->pcap_hdr_storage->ts, server_node->pcap_hdr_storage->ts)) {
7102  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7103  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7104  if (ret != 1) {
7105  SCLogDebug("Callback function has failed");
7106  return -1;
7107  }
7108  client_node = TCPSEG_RB_NEXT(client_node);
7109  } else {
7111  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7112  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7113  if (ret != 1) {
7114  SCLogDebug("Callback function has failed");
7115  return -1;
7116  }
7117  server_node = TCPSEG_RB_NEXT(server_node);
7118  }
7119  }
7120 
7121  cnt++;
7122  }
7123  return cnt;
7124 }
7125 
7127 {
7129 }
7130 
7131 /**
7132  * \brief See if stream engine is operating in inline mode
7133  *
7134  * \retval 0 no
7135  * \retval 1 yes
7136  */
7138 {
7140 }
7141 
7142 
7143 void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
7144 {
7145  if (size > ssn->reassembly_depth || size == 0) {
7146  ssn->reassembly_depth = size;
7147  }
7148 }
7149 
7150 const char *StreamTcpStateAsString(const enum TcpState state)
7151 {
7152  const char *tcp_state = NULL;
7153  switch (state) {
7154  case TCP_NONE:
7155  tcp_state = "none";
7156  break;
7157  case TCP_SYN_SENT:
7158  tcp_state = "syn_sent";
7159  break;
7160  case TCP_SYN_RECV:
7161  tcp_state = "syn_recv";
7162  break;
7163  case TCP_ESTABLISHED:
7164  tcp_state = "established";
7165  break;
7166  case TCP_FIN_WAIT1:
7167  tcp_state = "fin_wait1";
7168  break;
7169  case TCP_FIN_WAIT2:
7170  tcp_state = "fin_wait2";
7171  break;
7172  case TCP_TIME_WAIT:
7173  tcp_state = "time_wait";
7174  break;
7175  case TCP_LAST_ACK:
7176  tcp_state = "last_ack";
7177  break;
7178  case TCP_CLOSE_WAIT:
7179  tcp_state = "close_wait";
7180  break;
7181  case TCP_CLOSING:
7182  tcp_state = "closing";
7183  break;
7184  case TCP_CLOSED:
7185  tcp_state = "closed";
7186  break;
7187  }
7188  return tcp_state;
7189 }
7190 
7191 const char *StreamTcpSsnStateAsString(const TcpSession *ssn)
7192 {
7193  if (ssn == NULL)
7194  return NULL;
7195  return StreamTcpStateAsString(ssn->state);
7196 }
7197 
7198 #ifdef UNITTESTS
7199 #include "tests/stream-tcp.c"
7200 #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:110
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:507
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:5960
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:7137
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:6728
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:356
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:6014
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:6708
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:372
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:446
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:359
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_HAS_SEEN_DATA
#define STREAM_HAS_SEEN_DATA(stream)
Definition: stream-tcp-private.h:104
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:7043
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:114
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:108
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
StreamTcp
TmEcode StreamTcp(ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq)
Definition: stream-tcp.c:5972
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:5567
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:6984
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:333
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
SCReturnUInt
#define SCReturnUInt(x)
Definition: util-debug.h:277
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:382
PcapIncreaseInvalidChecksum
void PcapIncreaseInvalidChecksum(void)
Definition: source-pcap-file.c:480
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:251
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:1161
Flow_::src
FlowAddress src
Definition: flow.h:359
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
StreamTcpThread_::counter_tcp_pseudo_failed
uint16_t counter_tcp_pseudo_failed
Definition: stream-tcp.h:106
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:1124
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:403
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:6960
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:508
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:7143
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:426
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:119
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:228
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:7150
Flow_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: flow.h:380
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:361
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:7191
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:455
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:116
TcpStream_::tcp_flags
uint8_t tcp_flags
Definition: stream-tcp-private.h:111
STREAM_SEQ_RIGHT_EDGE
#define STREAM_SEQ_RIGHT_EDGE(stream)
Definition: stream-tcp-private.h:101
IPV4Hdr_::ip_verhl
uint8_t ip_verhl
Definition: decode-ipv4.h:73
StreamTcpReassembleMemuseGlobalCounter
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
Definition: stream-tcp-reassemble.c: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:112
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:421
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:6102
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:399
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:6744
STREAM_3WHS_SYN_FLOOD
@ STREAM_3WHS_SYN_FLOOD
Definition: decode-events.h:239
StreamTcpSetSessionBypassFlag
void StreamTcpSetSessionBypassFlag(TcpSession *ssn)
enable bypass
Definition: stream-tcp.c:6755
StreamTcpBypassEnabled
int StreamTcpBypassEnabled(void)
Definition: stream-tcp.c:7126
STREAM_CLOSEWAIT_INVALID_ACK
@ STREAM_CLOSEWAIT_INVALID_ACK
Definition: decode-events.h:249