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