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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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  /* special case: normally the packet following the 3whs is
2524  * considered flow established, but with data we need it to
2525  * be established now. This can happen if the original ACK was
2526  * lost. */
2527  if (p->payload_len) {
2529  }
2530 
2531  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2532 
2533  /* If asynchronous stream handling is allowed then set the session,
2534  if packet's seq number is equal the expected seq no.*/
2535  } else if (stream_config.async_oneside &&
2536  (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2537  /*set the ASYNC flag used to indicate the session as async stream
2538  and helps in relaxing the windows checks.*/
2539  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2540  ssn->server.next_seq += p->payload_len;
2541  ssn->server.last_ack = TCP_GET_RAW_SEQ(tcph);
2542 
2543  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2544  ssn->client.last_ack = TCP_GET_RAW_ACK(tcph);
2545 
2546  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2547  StreamTcpHandleTimestamp(ssn, p);
2548  }
2549 
2550  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2551  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2552  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2553  /* window scaling for midstream pickups, we can't do much
2554  * other than assume that it's set to the max value: 14 */
2555  ssn->server.wscale = TCP_WSCALE_MAX;
2556  ssn->client.wscale = TCP_WSCALE_MAX;
2557  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2558  }
2559 
2560  SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
2561  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2562  "ssn->server.next_seq %" PRIu32,
2563  ssn, TCP_GET_RAW_SEQ(tcph), p->payload_len,
2564  TCP_GET_RAW_SEQ(tcph) + p->payload_len, ssn->server.next_seq);
2565 
2566  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2567  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2568 
2569  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2570  /* Upon receiving the packet with correct seq number and wrong
2571  ACK number, it causes the other end to send RST. But some target
2572  system (Linux & solaris) does not RST the connection, so it is
2573  likely to avoid the detection */
2574  } else if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) {
2576  SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
2577  ssn);
2578 
2580  return -1;
2581 
2582  /* SYN/ACK followed by more TOCLIENT suggesting packet loss */
2583  } else if (PKT_IS_TOCLIENT(p) && !StreamTcpInlineMode() &&
2584  SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2585  SEQ_GT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
2586  SCLogDebug("ssn %p: ACK for missing data", ssn);
2587 
2588  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2589  StreamTcpHandleTimestamp(ssn, p);
2590  }
2591 
2592  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_RAW_ACK(tcph));
2593 
2594  ssn->server.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
2595  SCLogDebug("ssn %p: ACK for missing data: ssn->server.next_seq %u", ssn,
2596  ssn->server.next_seq);
2597  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2598 
2599  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2600 
2601  ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2602  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2603 
2604  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2605  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2606 
2607  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2608 
2609  /* if we get a packet with a proper ack, but a seq that is beyond
2610  * next_seq but in-window, we probably missed some packets */
2611  } else if (SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2612  SEQ_LEQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_win) &&
2613  SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.next_seq)) {
2614  SCLogDebug("ssn %p: ACK for missing data", ssn);
2615 
2616  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2617  StreamTcpHandleTimestamp(ssn, p);
2618  }
2619 
2620  ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
2621  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_RAW_ACK(tcph));
2622 
2623  SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
2624  ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2625  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2626 
2627  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2628  ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2629  ssn->server.next_win = ssn->server.last_ack +
2630  ssn->server.window;
2631  /* window scaling for midstream pickups, we can't do much
2632  * other than assume that it's set to the max value: 14 */
2633  ssn->server.wscale = TCP_WSCALE_MAX;
2634  ssn->client.wscale = TCP_WSCALE_MAX;
2635  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2636  }
2637 
2638  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2639  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2640 
2641  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2642 
2643  /* toclient packet: after having missed the 3whs's final ACK */
2644  } else if ((ack_indicates_missed_3whs_ack_packet ||
2645  (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN)) &&
2646  SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack) &&
2647  SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq)) {
2648  if (ack_indicates_missed_3whs_ack_packet) {
2649  SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2650  } else {
2651  SCLogDebug("ssn %p: (TFO) expected packet fits perfectly after SYN/ACK", ssn);
2652  }
2653 
2654  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_RAW_SEQ(tcph) + p->payload_len));
2655 
2656  ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2657  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2658 
2659  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2660  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2661 
2662  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2663 
2664  } else {
2665  SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2666 
2668  return -1;
2669  }
2670 
2671  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2672  "ssn->server.last_ack %"PRIu32"", ssn,
2673  ssn->server.next_win, ssn->server.last_ack);
2674  } else {
2675  SCLogDebug("ssn %p: default case", ssn);
2676  }
2677 
2678  return 0;
2679 }
2680 
2681 /**
2682  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2683  * sent by the client to server. The function handles
2684  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2685  * the reassembly.
2686  *
2687  * Timestamp has already been checked at this point.
2688  *
2689  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2690  * \param ssn Pointer to the current TCP session
2691  * \param p Packet which has to be handled in this TCP state.
2692  * \param stt Stream Thread module registered to handle the stream handling
2693  */
2694 static int HandleEstablishedPacketToServer(
2695  ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt)
2696 {
2697  const TCPHdr *tcph = PacketGetTCP(p);
2698  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
2699  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
2700  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
2701 
2702  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2703  "ACK %" PRIu32 ", WIN %" PRIu16 "",
2704  ssn, p->payload_len, seq, ack, window);
2705 
2706  const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
2707  if (has_ack) {
2708  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TC) && ack == ssn->server.next_seq + 1) {
2709  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2711 
2712  } else if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2713  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2715  return -1;
2716  }
2717  }
2718 
2719  /* check for Keep Alive */
2720  if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->client.next_seq - 1))) {
2721  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2722 
2723  /* normal pkt */
2724  } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->client.last_ack))) {
2725  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2726  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2727  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2728  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2729  "%" PRIu32 "(%" PRIu32 ")",
2730  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2731  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2732 
2733  /* update the last_ack to current seq number as the session is
2734  * async and other stream is not updating it anymore :( */
2735  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2736 
2737  } else if (SEQ_EQ(ssn->client.next_seq, seq) && stream_config.async_oneside &&
2738  (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2739  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2740  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2741  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2742  "%" PRIu32 "(%" PRIu32 ")",
2743  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2744  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2745 
2746  /* it seems we missed SYN and SYN/ACK packets of this session.
2747  * Update the last_ack to current seq number as the session
2748  * is async and other stream is not updating it anymore :( */
2749  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2750  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2751 
2752  } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2754  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2755  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2756  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2757  "%" PRIu32 "(%" PRIu32 ")",
2758  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2759  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2760 
2761  /* it seems we missed SYN and SYN/ACK packets of this session.
2762  * Update the last_ack to current seq number as the session
2763  * is async and other stream is not updating it anymore :(*/
2764  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2765  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2766 
2767  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2768  * In this case we do accept the data before last_ack if it is (partly)
2769  * beyond next seq */
2770  } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
2771  SEQ_GT((seq + p->payload_len), ssn->client.next_seq)) {
2772  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2773  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
2774  " acked data that we haven't seen before",
2775  ssn, seq, p->payload_len, ssn->client.last_ack, ssn->client.next_seq);
2776  } else {
2777  SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
2778  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2779  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2780  "%" PRIu32 "(%" PRIu32 ")",
2781  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2782  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2783 
2784  SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
2786  return -1;
2787  }
2788  }
2789 
2790  int zerowindowprobe = 0;
2791  /* zero window probe */
2792  if (p->payload_len == 1 && seq == ssn->client.next_seq && ssn->client.window == 0) {
2793  SCLogDebug("ssn %p: zero window probe", ssn);
2794  zerowindowprobe = 1;
2796  ssn->flags |= STREAMTCP_FLAG_ZWP_TS;
2797  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2798 
2799  } else if (SEQ_GEQ(seq + p->payload_len, ssn->client.next_seq)) {
2800  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
2801  }
2802 
2803  /* in window check */
2804  if (zerowindowprobe) {
2805  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2806  } else if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
2808  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
2809  "%" PRIu32 "",
2810  ssn, seq, ssn->client.next_win);
2811 
2812  ssn->server.window = window << ssn->server.wscale;
2813  SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
2814  ssn->server.window);
2815 
2816  /* Check if the ACK value is sane and inside the window limit */
2817  if (tcph->th_flags & TH_ACK) {
2818  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
2819  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
2820  SEQ_GT(ssn->server.last_ack, ssn->server.next_seq)) {
2823  }
2824  }
2825 
2826  SCLogDebug(
2827  "ack %u last_ack %u next_seq %u", ack, ssn->server.last_ack, ssn->server.next_seq);
2828 
2829  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2830  StreamTcpHandleTimestamp(ssn, p);
2831  }
2832 
2834 
2835  /* update next_win */
2836  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
2837 
2838  /* handle data (if any) */
2839  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2840 
2841  } else {
2842  SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
2843  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2844  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2845  "%" PRIu32 "(%" PRIu32 ")",
2846  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2847  ssn->client.next_win, (seq + p->payload_len) - ssn->client.next_win);
2848  SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
2849  StreamTcpSackedSize(&ssn->client));
2851  return -1;
2852  }
2853  return 0;
2854 }
2855 
2856 /**
2857  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2858  * sent by the server to client. The function handles
2859  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2860  * the reassembly
2861  *
2862  * Timestamp has already been checked at this point.
2863  *
2864  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2865  * \param ssn Pointer to the current TCP session
2866  * \param p Packet which has to be handled in this TCP state.
2867  * \param stt Stream Thread module registered to handle the stream handling
2868  */
2869 static int HandleEstablishedPacketToClient(
2870  ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt)
2871 {
2872  const TCPHdr *tcph = PacketGetTCP(p);
2873  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
2874  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
2875  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
2876 
2877  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
2878  " ACK %" PRIu32 ", WIN %" PRIu16 "",
2879  ssn, p->payload_len, seq, ack, window);
2880 
2881  const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
2882  if (has_ack) {
2883  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TS) && ack == ssn->client.next_seq + 1) {
2884  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2886 
2887  } else if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2888  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2890  return -1;
2891  }
2892  }
2893 
2894  /* To get the server window value from the servers packet, when connection
2895  is picked up as midstream */
2896  if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
2898  {
2899  ssn->server.window = window << ssn->server.wscale;
2900  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2902  SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
2903  "%" PRIu32 "", ssn, ssn->server.next_win);
2904  }
2905 
2906  /* check for Keep Alive */
2907  if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->server.next_seq - 1))) {
2908  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2909 
2910  /* normal pkt */
2911  } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->server.last_ack))) {
2912  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2913 
2914  SCLogDebug("ssn %p: client => Asynchronous stream, packet SEQ"
2915  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2916  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2917  " %" PRIu32 "(%" PRIu32 ")",
2918  ssn, seq, p->payload_len, seq + p->payload_len, ssn->server.last_ack,
2919  ssn->server.next_win, seq + p->payload_len - ssn->server.next_win);
2920 
2921  ssn->server.last_ack = seq;
2922 
2923  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2924  * In this case we do accept the data before last_ack if it is (partly)
2925  * beyond next seq */
2926  } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
2927  SEQ_GT((seq + p->payload_len), ssn->server.next_seq)) {
2928  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2929  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
2930  " acked data that we haven't seen before",
2931  ssn, seq, p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2932  } else {
2933  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2934  " before last_ack %" PRIu32 ". next_seq %" PRIu32,
2935  ssn, seq, p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2937  return -1;
2938  }
2939  }
2940 
2941  int zerowindowprobe = 0;
2942  /* zero window probe */
2943  if (p->payload_len == 1 && seq == ssn->server.next_seq && ssn->server.window == 0) {
2944  SCLogDebug("ssn %p: zero window probe", ssn);
2945  zerowindowprobe = 1;
2947  ssn->flags |= STREAMTCP_FLAG_ZWP_TC;
2948 
2949  /* accept the segment */
2950  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2951 
2952  } else if (SEQ_GEQ(seq + p->payload_len, ssn->server.next_seq)) {
2953  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
2954  }
2955 
2956  if (zerowindowprobe) {
2957  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2958  } else if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
2960  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
2961  "%" PRIu32 "",
2962  ssn, seq, ssn->server.next_win);
2963  ssn->client.window = window << ssn->client.wscale;
2964  SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
2965  ssn->client.window);
2966 
2967  if (tcph->th_flags & TH_ACK) {
2968  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
2969  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
2970  SEQ_GT(ssn->client.last_ack, ssn->client.next_seq)) {
2973  }
2974  }
2975 
2976  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2977  StreamTcpHandleTimestamp(ssn, p);
2978  }
2979 
2981 
2982  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
2983 
2984  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2985  } else {
2986  SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
2987  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2988  " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
2989  "%" PRIu32 "(%" PRIu32 ")",
2990  ssn, seq, p->payload_len, seq + p->payload_len, ssn->server.last_ack,
2991  ssn->server.next_win, seq + p->payload_len - ssn->server.next_win);
2993  return -1;
2994  }
2995  return 0;
2996 }
2997 
2998 /**
2999  * \internal
3000  *
3001  * \brief Find the highest sequence number needed to consider all segments as ACK'd
3002  *
3003  * Used to treat all segments as ACK'd upon receiving a valid RST.
3004  *
3005  * \param stream stream to inspect the segments from
3006  * \param seq sequence number to check against
3007  *
3008  * \retval ack highest ack we need to set
3009  */
3010 static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
3011 {
3012  uint32_t ack = seq;
3013 
3014  if (STREAM_HAS_SEEN_DATA(stream)) {
3015  const uint32_t tail_seq = STREAM_SEQ_RIGHT_EDGE(stream);
3016  if (SEQ_GT(tail_seq, ack)) {
3017  ack = tail_seq;
3018  }
3019  }
3020 
3021  SCReturnUInt(ack);
3022 }
3023 
3024 static bool StreamTcpPacketIsZeroWindowProbeAck(const TcpSession *ssn, const Packet *p)
3025 {
3026  const TCPHdr *tcph = PacketGetTCP(p);
3027  if (ssn->state < TCP_ESTABLISHED)
3028  return false;
3029  if (p->payload_len != 0)
3030  return false;
3031  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3032  return false;
3033 
3034  const TcpStream *snd, *rcv;
3035  if (PKT_IS_TOCLIENT(p)) {
3036  snd = &ssn->server;
3037  rcv = &ssn->client;
3038  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TS))
3039  return false;
3040  } else {
3041  snd = &ssn->client;
3042  rcv = &ssn->server;
3043  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TC))
3044  return false;
3045  }
3046 
3047  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3048  if (pkt_win != 0)
3049  return false;
3050  if (pkt_win != rcv->window)
3051  return false;
3052 
3053  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3054  return false;
3055  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3056  return false;
3057  SCLogDebug("ssn %p: packet %" PRIu64 " is a Zero Window Probe ACK", ssn, p->pcap_cnt);
3058  return true;
3059 }
3060 
3061 /** \internal
3062  * \brief check if an ACK packet is a dup-ACK
3063  */
3064 static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p)
3065 {
3066  const TCPHdr *tcph = PacketGetTCP(p);
3067  if (ssn->state < TCP_ESTABLISHED)
3068  return false;
3069  if (p->payload_len != 0)
3070  return false;
3071  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3072  return false;
3073 
3074  const TcpStream *snd, *rcv;
3075  if (PKT_IS_TOCLIENT(p)) {
3076  snd = &ssn->server;
3077  rcv = &ssn->client;
3078  } else {
3079  snd = &ssn->client;
3080  rcv = &ssn->server;
3081  }
3082 
3083  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3084  if (pkt_win == 0 || rcv->window == 0)
3085  return false;
3086  if (pkt_win != rcv->window)
3087  return false;
3088 
3089  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3090  return false;
3091  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3092  return false;
3093 
3094  SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn,
3095  p->pcap_cnt, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph), pkt_win, snd->next_seq,
3096  snd->last_ack, rcv->window, snd->next_seq, rcv->last_ack, rcv->window);
3097  return true;
3098 }
3099 
3100 /** \internal
3101  * \brief check if a ACK packet is outdated so processing can be fast tracked
3102  *
3103  * Consider a packet outdated ack if:
3104  * - state is >= ESTABLISHED
3105  * - ACK < last_ACK
3106  * - SACK acks nothing new
3107  * - packet has no data
3108  * - SEQ == next_SEQ
3109  * - flags has ACK set but don't contain SYN/FIN/RST
3110  *
3111  * \todo the most likely explanation for this packet is that we already
3112  * accepted a "newer" ACK. We will not consider an outdated timestamp
3113  * option an issue for this packet, but we should probably still
3114  * check if the ts isn't too far off.
3115  */
3116 static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p)
3117 {
3118  const TCPHdr *tcph = PacketGetTCP(p);
3119  if (ssn->state < TCP_ESTABLISHED)
3120  return false;
3121  if (p->payload_len != 0)
3122  return false;
3123  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3124  return false;
3125 
3126  /* lets see if this is a packet that is entirely eclipsed by earlier ACKs */
3127  if (PKT_IS_TOSERVER(p)) {
3128  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
3129  SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->server.last_ack)) {
3130  if (!TCP_HAS_SACK(p)) {
3131  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3132  ssn->client.next_seq);
3133  return true;
3134  }
3135 
3136  if (StreamTcpSackPacketIsOutdated(&ssn->server, p)) {
3137  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3138  ssn->client.next_seq);
3139  return true;
3140  }
3141  }
3142  } else {
3143  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq) &&
3144  SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
3145  if (!TCP_HAS_SACK(p)) {
3146  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3147  ssn->client.next_seq);
3148  return true;
3149  }
3150 
3151  if (StreamTcpSackPacketIsOutdated(&ssn->client, p)) {
3152  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3153  ssn->client.next_seq);
3154  return true;
3155  }
3156  }
3157  }
3158  return false;
3159 }
3160 
3161 /** \internal
3162  * \brief check if packet is before ack'd windows
3163  * If packet is before last ack, we will not accept it
3164  *
3165  * \retval 0 not spurious retransmission
3166  * \retval 1 before last_ack, after base_seq
3167  * \retval 2 before last_ack and base_seq
3168  */
3169 static int StreamTcpPacketIsSpuriousRetransmission(const TcpSession *ssn, Packet *p)
3170 {
3171  const TcpStream *stream;
3172  if (PKT_IS_TOCLIENT(p)) {
3173  stream = &ssn->server;
3174  } else {
3175  stream = &ssn->client;
3176  }
3177  if (p->payload_len == 0)
3178  return 0;
3179 
3180  const TCPHdr *tcph = PacketGetTCP(p);
3181  /* take base_seq into account to avoid edge cases where last_ack might be
3182  * too far ahead during heavy packet loss */
3183  if (!(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3184  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->base_seq))) {
3185  SCLogDebug(
3186  "ssn %p: spurious retransmission; packet entirely before base_seq: SEQ %u(%u) "
3187  "last_ack %u base_seq %u",
3188  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3189  stream->last_ack, stream->base_seq);
3191  return 2;
3192  }
3193  }
3194 
3195  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack))) {
3196  SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) "
3197  "last_ack %u",
3198  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3199  stream->last_ack);
3201  return 1;
3202  }
3203 
3204  SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ "
3205  "%u(%u) last_ack %u, base_seq %u",
3206  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack,
3207  stream->base_seq);
3208  return 0;
3209 }
3210 
3211 /**
3212  * \brief Function to handle the TCP_ESTABLISHED state. The function handles
3213  * ACK, FIN, RST packets and correspondingly changes the connection
3214  * state. The function handles the data inside packets and call
3215  * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
3216  *
3217  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3218  * \param p Packet which has to be handled in this TCP state.
3219  * \param stt Stream Thread module registered to handle the stream handling
3220  */
3221 
3222 static int StreamTcpPacketStateEstablished(
3223  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3224 {
3225  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3226  const TCPHdr *tcph = PacketGetTCP(p);
3227  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3228  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3229  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3230 
3231  if (tcph->th_flags & TH_RST) {
3232  if (!StreamTcpValidateRst(ssn, p))
3233  return -1;
3234 
3235  if (PKT_IS_TOSERVER(p)) {
3236  StreamTcpCloseSsnWithReset(p, ssn);
3237 
3238  ssn->server.next_seq = ack;
3239  ssn->client.next_seq = seq + p->payload_len;
3240  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3241  ssn->server.next_seq);
3242  ssn->client.window = window << ssn->client.wscale;
3243 
3244  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3246  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, window));
3247 
3248  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
3249 
3250  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3251  StreamTcpHandleTimestamp(ssn, p);
3252  }
3253 
3254  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3255  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3256  "%" PRIu32 "", ssn, ssn->client.next_seq,
3257  ssn->server.last_ack);
3258 
3259  /* don't return packets to pools here just yet, the pseudo
3260  * packet will take care, otherwise the normal session
3261  * cleanup. */
3262  } else {
3263  StreamTcpCloseSsnWithReset(p, ssn);
3264 
3265  ssn->server.next_seq = seq + p->payload_len + 1;
3266  ssn->client.next_seq = ack;
3267 
3268  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3269  ssn->server.next_seq);
3270  ssn->server.window = window << ssn->server.wscale;
3271 
3272  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3274  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
3275 
3276  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
3277 
3278  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3279  StreamTcpHandleTimestamp(ssn, p);
3280  }
3281 
3282  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3283  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3284  "%" PRIu32 "", ssn, ssn->server.next_seq,
3285  ssn->client.last_ack);
3286 
3287  /* don't return packets to pools here just yet, the pseudo
3288  * packet will take care, otherwise the normal session
3289  * cleanup. */
3290  }
3291 
3292  } else if (tcph->th_flags & TH_FIN) {
3293  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3294  if (!StreamTcpValidateTimestamp(ssn, p))
3295  return -1;
3296  }
3297 
3298  SCLogDebug("ssn (%p: FIN received SEQ"
3299  " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
3300  " win %" PRIu32 "", ssn, ssn->server.next_seq,
3301  ssn->client.last_ack, ssn->server.next_win,
3302  ssn->server.window);
3303 
3304  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
3305  return -1;
3306 
3307  /* SYN/ACK */
3308  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
3309  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
3310  ssn);
3311 
3312  if (PKT_IS_TOSERVER(p)) {
3313  SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
3314 
3316  return -1;
3317  }
3318 
3319  /* Check if the SYN/ACK packets ACK matches the earlier
3320  * received SYN/ACK packet. */
3321  if (!(SEQ_EQ(ack, ssn->client.last_ack))) {
3322  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
3323  "%" PRIu32 " from stream",
3324  ssn, ack, ssn->client.isn + 1);
3325 
3327  return -1;
3328  }
3329 
3330  /* Check if the SYN/ACK packet SEQ the earlier
3331  * received SYN packet. */
3332  if (!(SEQ_EQ(seq, ssn->server.isn))) {
3333  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
3334  "%" PRIu32 " from stream",
3335  ssn, ack, ssn->client.isn + 1);
3336 
3338  return -1;
3339  }
3340 
3341  if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
3342  /* a resend of a SYN while we are established already -- fishy */
3344  return -1;
3345  }
3346 
3347  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
3348  "Likely due server not receiving final ACK in 3whs", ssn);
3349  return 0;
3350 
3351  } else if (tcph->th_flags & TH_SYN) {
3352  SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
3353  if (PKT_IS_TOCLIENT(p)) {
3354  SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
3355 
3357  return -1;
3358  }
3359 
3360  if (!(SEQ_EQ(ack, ssn->client.isn))) {
3361  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
3362 
3364  return -1;
3365  }
3366 
3367  /* a resend of a SYN while we are established already -- fishy */
3369  return -1;
3370 
3371  } else if (tcph->th_flags & TH_ACK) {
3372  /* Urgent pointer size can be more than the payload size, as it tells
3373  * the future coming data from the sender will be handled urgently
3374  * until data of size equal to urgent offset has been processed
3375  * (RFC 2147) */
3376 
3377  /* If the timestamp option is enabled for both the streams, then
3378  * validate the received packet timestamp value against the
3379  * stream->last_ts. If the timestamp is valid then process the
3380  * packet normally otherwise the drop the packet (RFC 1323) */
3381  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3382  if (!StreamTcpValidateTimestamp(ssn, p))
3383  return -1;
3384  }
3385 
3386  if (PKT_IS_TOSERVER(p)) {
3387  /* Process the received packet to server */
3388  HandleEstablishedPacketToServer(tv, ssn, p, stt);
3389 
3390  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3391  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3392  ssn->client.next_seq, ssn->server.last_ack
3393  ,ssn->client.next_win, ssn->client.window);
3394 
3395  } else { /* implied to client */
3396  if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
3398  SCLogDebug("3whs is now confirmed by server");
3399  }
3400 
3401  /* Process the received packet to client */
3402  HandleEstablishedPacketToClient(tv, ssn, p, stt);
3403 
3404  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3405  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3406  ssn->server.next_seq, ssn->client.last_ack,
3407  ssn->server.next_win, ssn->server.window);
3408  }
3409  } else {
3410  SCLogDebug("ssn %p: default case", ssn);
3411  }
3412 
3413  return 0;
3414 }
3415 
3416 /**
3417  * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
3418  * TCP_ESTABLISHED and changes to another TCP state as required.
3419  *
3420  * \param tv Thread Variable containing input/output queue, cpu affinity
3421  * \param p Packet which has to be handled in this TCP state.
3422  * \param stt Stream Thread module registered to handle the stream handling
3423  *
3424  * \retval 0 success
3425  * \retval -1 something wrong with the packet
3426  */
3427 
3428 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession *ssn, Packet *p)
3429 {
3430  const TCPHdr *tcph = PacketGetTCP(p);
3431  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3432  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3433  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3434 
3435  if (PKT_IS_TOSERVER(p)) {
3436  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
3437  " ACK %" PRIu32 "",
3438  ssn, p->payload_len, seq, ack);
3439 
3440  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3441  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3443  return -1;
3444  }
3445 
3446  const uint32_t pkt_re = seq + p->payload_len;
3447  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3448  ssn->client.last_ack, ssn->client.next_win);
3449  if (SEQ_GEQ(seq, ssn->client.last_ack) && SEQ_LEQ(pkt_re, ssn->client.next_win)) {
3450  // within expectations
3451  } else {
3452  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3453  "%" PRIu32 " from stream",
3454  ssn, seq, ssn->client.next_seq);
3455 
3457  return -1;
3458  }
3459 
3460  if (tcph->th_flags & TH_SYN) {
3461  SCLogDebug("ssn %p: FIN+SYN", ssn);
3463  return -1;
3464  }
3465  StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
3466  SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
3467 
3468  /* if we accept the FIN, next_seq needs to reflect the FIN */
3469  ssn->client.next_seq = seq + p->payload_len;
3470 
3471  SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
3472  ssn->client.next_seq);
3473  ssn->server.window = window << ssn->server.wscale;
3474 
3475  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3476  StreamTcpHandleTimestamp(ssn, p);
3477  }
3478 
3479  /* Update the next_seq, in case if we have missed the client packet
3480  and server has already received and acked it */
3481  if (SEQ_LT(ssn->server.next_seq, ack))
3482  ssn->server.next_seq = ack;
3483 
3484  if (tcph->th_flags & TH_ACK)
3485  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3486 
3487  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3488 
3489  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3490  ssn, ssn->client.next_seq, ssn->server.last_ack);
3491  } else { /* implied to client */
3492  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
3493  "ACK %" PRIu32 "",
3494  ssn, p->payload_len, seq, ack);
3495 
3496  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3497  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3499  return -1;
3500  }
3501 
3502  const uint32_t pkt_re = seq + p->payload_len;
3503  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3504  ssn->server.last_ack, ssn->server.next_win);
3505  if (SEQ_GEQ(seq, ssn->server.last_ack) && SEQ_LEQ(pkt_re, ssn->server.next_win)) {
3506  // within expectations
3507  } else {
3508  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3509  "%" PRIu32 " from stream (last_ack %u win %u = %u)",
3510  ssn, seq, ssn->server.next_seq, ssn->server.last_ack, ssn->server.window,
3511  (ssn->server.last_ack + ssn->server.window));
3512 
3514  return -1;
3515  }
3516 
3517  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
3518  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
3519 
3520  /* if we accept the FIN, next_seq needs to reflect the FIN */
3521  ssn->server.next_seq = seq + p->payload_len + 1;
3522  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 " updated", ssn, ssn->server.next_seq);
3523 
3524  ssn->client.window = window << ssn->client.wscale;
3525 
3526  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3527  StreamTcpHandleTimestamp(ssn, p);
3528  }
3529 
3530  /* Update the next_seq, in case if we have missed the client packet
3531  and server has already received and acked it */
3532  if (SEQ_LT(ssn->client.next_seq, ack))
3533  ssn->client.next_seq = ack;
3534 
3535  if (tcph->th_flags & TH_ACK)
3536  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3537 
3538  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3539 
3540  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3541  ssn, ssn->server.next_seq, ssn->client.last_ack);
3542  }
3543 
3544  return 0;
3545 }
3546 
3547 /**
3548  * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
3549  * ACK, FIN, RST packets and correspondingly changes the connection
3550  * state.
3551  *
3552  * \param tv Thread Variable containing input/output queue, cpu affinity
3553  * \param p Packet which has to be handled in this TCP state.
3554  * \param stt Stream Thread module registered to handle the stream handling
3555  *
3556  * \retval 0 success
3557  * \retval -1 something wrong with the packet
3558  */
3559 
3560 static int StreamTcpPacketStateFinWait1(
3561  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3562 {
3563  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3564  const TCPHdr *tcph = PacketGetTCP(p);
3565  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3566  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3567  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3568 
3569  if (tcph->th_flags & TH_RST) {
3570  if (!StreamTcpValidateRst(ssn, p))
3571  return -1;
3572 
3573  StreamTcpCloseSsnWithReset(p, ssn);
3574 
3575  if (PKT_IS_TOSERVER(p)) {
3576  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3578  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
3579 
3580  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
3581 
3582  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3583  StreamTcpHandleTimestamp(ssn, p);
3584  }
3585 
3586  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3587  } else {
3588  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3590  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
3591 
3592  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
3593 
3594  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3595  StreamTcpHandleTimestamp(ssn, p);
3596  }
3597 
3598  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3599  }
3600 
3601  } else if ((tcph->th_flags & (TH_FIN | TH_ACK)) == (TH_FIN | TH_ACK)) {
3602  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3603  if (!StreamTcpValidateTimestamp(ssn, p))
3604  return -1;
3605  }
3606 
3607  if (PKT_IS_TOSERVER(p)) {
3608  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3609  "%" PRIu32 ", ACK %" PRIu32 "",
3610  ssn, p->payload_len, seq, ack);
3611  int retransmission = 0;
3612 
3613  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3614  SCLogDebug("ssn %p: packet is retransmission", ssn);
3615  retransmission = 1;
3617 
3618  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3619  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3620  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3621  " != %" PRIu32 " from stream",
3622  ssn, seq, ssn->client.next_seq);
3624  return -1;
3625  }
3626 
3627  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3628  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3630  return -1;
3631  }
3632 
3633  if (!retransmission) {
3634  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3635  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3636 
3637  ssn->server.window = window << ssn->server.wscale;
3638  }
3639 
3640  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3641  StreamTcpHandleTimestamp(ssn, p);
3642  }
3643 
3644  /* Update the next_seq, in case if we have missed the client
3645  packet and server has already received and acked it */
3646  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3647  ssn->server.next_seq = ack;
3648 
3649  if (SEQ_EQ(ssn->client.next_seq, seq)) {
3650  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3651  }
3652 
3653  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3654 
3655  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3656 
3657  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3658  "%" PRIu32 "", ssn, ssn->client.next_seq,
3659  ssn->server.last_ack);
3660  } else { /* implied to client */
3661  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3662  "%" PRIu32 ", ACK %" PRIu32 "",
3663  ssn, p->payload_len, seq, ack);
3664  int retransmission = 0;
3665 
3666  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3667  SCLogDebug("ssn %p: packet is retransmission", ssn);
3668  retransmission = 1;
3670 
3671  } else if (SEQ_EQ(ssn->server.next_seq - 1, seq) && SEQ_EQ(ssn->client.last_ack, ack)) {
3672  SCLogDebug("ssn %p: packet is retransmission", ssn);
3673  retransmission = 1;
3675 
3676  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3677  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3678  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3679  " != %" PRIu32 " from stream",
3680  ssn, seq, ssn->server.next_seq);
3682  return -1;
3683  }
3684 
3685  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3686  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3688  return -1;
3689  }
3690 
3691  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3692  StreamTcpHandleTimestamp(ssn, p);
3693  }
3694 
3695  if (!retransmission) {
3696  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3697  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3698 
3699  ssn->client.window = window << ssn->client.wscale;
3700 
3701  /* Update the next_seq, in case if we have missed the client
3702  packet and server has already received and acked it */
3703  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3704  ssn->client.next_seq = ack;
3705 
3706  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3707  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3708  }
3709 
3710  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3711  }
3712 
3713  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3714 
3715  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3716  "%" PRIu32 "", ssn, ssn->server.next_seq,
3717  ssn->client.last_ack);
3718  }
3719 
3720  } else if (tcph->th_flags & TH_FIN) {
3721  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3722  if (!StreamTcpValidateTimestamp(ssn, p))
3723  return -1;
3724  }
3725 
3726  if (PKT_IS_TOSERVER(p)) {
3727  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3728  "%" PRIu32 ", ACK %" PRIu32 "",
3729  ssn, p->payload_len, seq, ack);
3730  int retransmission = 0;
3731 
3732  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3733  SCLogDebug("ssn %p: packet is retransmission", ssn);
3734  retransmission = 1;
3736 
3737  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3738  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3739  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3740  " != %" PRIu32 " from stream",
3741  ssn, seq, ssn->client.next_seq);
3743  return -1;
3744  }
3745 
3746  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3747  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3749  return -1;
3750  }
3751 
3752  if (!retransmission) {
3753  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3754  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3755 
3756  ssn->server.window = window << ssn->server.wscale;
3757  }
3758 
3759  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3760  StreamTcpHandleTimestamp(ssn, p);
3761  }
3762 
3763  /* Update the next_seq, in case if we have missed the client
3764  packet and server has already received and acked it */
3765  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3766  ssn->server.next_seq = ack;
3767 
3768  if (SEQ_EQ(ssn->client.next_seq - 1, seq)) {
3769  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3770  }
3771 
3772  if (tcph->th_flags & TH_ACK)
3773  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3774 
3775  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3776 
3777  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3778  "%" PRIu32 "", ssn, ssn->client.next_seq,
3779  ssn->server.last_ack);
3780  } else { /* implied to client */
3781  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3782  "%" PRIu32 ", ACK %" PRIu32 "",
3783  ssn, p->payload_len, seq, ack);
3784 
3785  int retransmission = 0;
3786 
3787  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3788  SCLogDebug("ssn %p: packet is retransmission", ssn);
3789  retransmission = 1;
3791 
3792  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3793  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3794  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3795  " != %" PRIu32 " from stream",
3796  ssn, seq, ssn->server.next_seq);
3798  return -1;
3799  }
3800 
3801  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3802  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3804  return -1;
3805  }
3806 
3807  if (!retransmission) {
3808  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3809  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3810 
3811  ssn->client.window = window << ssn->client.wscale;
3812  }
3813 
3814  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3815  StreamTcpHandleTimestamp(ssn, p);
3816  }
3817 
3818  /* Update the next_seq, in case if we have missed the client
3819  packet and server has already received and acked it */
3820  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3821  ssn->client.next_seq = ack;
3822 
3823  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3824  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3825  }
3826 
3827  if (tcph->th_flags & TH_ACK)
3828  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3829 
3830  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3831 
3832  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3833  "%" PRIu32 "", ssn, ssn->server.next_seq,
3834  ssn->client.last_ack);
3835  }
3836  } else if (tcph->th_flags & TH_SYN) {
3837  SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
3839  return -1;
3840 
3841  } else if (tcph->th_flags & TH_ACK) {
3842  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3843  if (!StreamTcpValidateTimestamp(ssn, p))
3844  return -1;
3845  }
3846 
3847  if (PKT_IS_TOSERVER(p)) {
3848  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3849  "%" PRIu32 ", ACK %" PRIu32 "",
3850  ssn, p->payload_len, seq, ack);
3851  int retransmission = 0;
3852 
3853  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3854  SCLogDebug("ssn %p: packet is retransmission", ssn);
3855  retransmission = 1;
3857  }
3858 
3859  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3860  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3862  return -1;
3863  }
3864 
3865  if (SEQ_LT(ack, ssn->server.next_seq)) {
3866  SCLogDebug(
3867  "ssn %p: ACK's older segment as %u < %u", ssn, ack, ssn->server.next_seq);
3868  } else if (!retransmission) {
3869  if (SEQ_EQ(ack, ssn->server.next_seq)) {
3870  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
3872  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
3873  "%" PRIu32 "",
3874  ssn, seq, ssn->client.next_win);
3875  SCLogDebug("seq %u client.next_seq %u", seq, ssn->client.next_seq);
3876  if (seq == ssn->client.next_seq) {
3877  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3878  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3879  }
3880  } else {
3881  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3882  " != %" PRIu32 " from stream",
3883  ssn, seq, ssn->client.next_seq);
3884 
3886  return -1;
3887  }
3888 
3889  ssn->server.window = window << ssn->server.wscale;
3890  }
3891  }
3892 
3893  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3894  StreamTcpHandleTimestamp(ssn, p);
3895  }
3896 
3897  /* Update the next_seq, in case if we have missed the client
3898  packet and server has already received and acked it */
3899  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3900  ssn->server.next_seq = ack;
3901 
3902  if (SEQ_EQ(ssn->client.next_seq, seq)) {
3903  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3904  }
3905 
3906  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3907 
3909 
3910  /* update next_win */
3911  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3912 
3913  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3914 
3915  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3916  "%" PRIu32 "", ssn, ssn->client.next_seq,
3917  ssn->server.last_ack);
3918 
3919  } else { /* implied to client */
3920 
3921  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3922  "%" PRIu32 ", ACK %" PRIu32 "",
3923  ssn, p->payload_len, seq, ack);
3924 
3925  int retransmission = 0;
3926 
3927  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3928  SCLogDebug("ssn %p: packet is retransmission", ssn);
3929  retransmission = 1;
3931  }
3932 
3933  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3934  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3936  return -1;
3937  }
3938 
3939  if (!retransmission) {
3940  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
3942  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
3943  "%" PRIu32 "",
3944  ssn, seq, ssn->server.next_win);
3945 
3946  if (seq == ssn->server.next_seq - 1) {
3947  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3948  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3949  }
3950  } else {
3951  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3952  " != %" PRIu32 " from stream",
3953  ssn, seq, ssn->server.next_seq);
3955  return -1;
3956  }
3957 
3958  ssn->client.window = window << ssn->client.wscale;
3959  }
3960 
3961  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3962  StreamTcpHandleTimestamp(ssn, p);
3963  }
3964 
3965  /* Update the next_seq, in case if we have missed the client
3966  packet and server has already received and acked it */
3967  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3968  ssn->client.next_seq = ack;
3969 
3970  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3971  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3972  }
3973 
3974  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3975 
3977 
3978  /* update next_win */
3979  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3980 
3981  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3982 
3983  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3984  "%" PRIu32 "", ssn, ssn->server.next_seq,
3985  ssn->client.last_ack);
3986  }
3987  } else {
3988  SCLogDebug("ssn (%p): default case", ssn);
3989  }
3990 
3991  return 0;
3992 }
3993 
3994 /**
3995  * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
3996  * ACK, RST, FIN packets and correspondingly changes the connection
3997  * state.
3998  *
3999  * \param tv Thread Variable containing input/output queue, cpu affinity
4000  * \param p Packet which has to be handled in this TCP state.
4001  * \param stt Stream Thread module registered to handle the stream handling
4002  */
4003 
4004 static int StreamTcpPacketStateFinWait2(
4005  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4006 {
4007  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4008  const TCPHdr *tcph = PacketGetTCP(p);
4009  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4010  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4011  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4012 
4013  if (tcph->th_flags & TH_RST) {
4014  if (!StreamTcpValidateRst(ssn, p))
4015  return -1;
4016 
4017  StreamTcpCloseSsnWithReset(p, ssn);
4018 
4019  if (PKT_IS_TOSERVER(p)) {
4020  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4022  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4023 
4024  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4025 
4026  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4027  StreamTcpHandleTimestamp(ssn, p);
4028  }
4029 
4030  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4031  } else {
4032  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4034  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4035 
4036  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4037 
4038  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4039  StreamTcpHandleTimestamp(ssn, p);
4040  }
4041 
4042  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4043  }
4044 
4045  } else if (tcph->th_flags & TH_FIN) {
4046  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4047  if (!StreamTcpValidateTimestamp(ssn, p))
4048  return -1;
4049  }
4050 
4051  if (PKT_IS_TOSERVER(p)) {
4052  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4053  "%" PRIu32 ", ACK %" PRIu32 "",
4054  ssn, p->payload_len, seq, ack);
4055  int retransmission = 0;
4056 
4057  if (SEQ_EQ(seq, ssn->client.next_seq - 1) && SEQ_EQ(ack, ssn->server.last_ack)) {
4058  SCLogDebug("ssn %p: retransmission", ssn);
4059  retransmission = 1;
4061  } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4062  SCLogDebug("ssn %p: packet is retransmission", ssn);
4063  retransmission = 1;
4065 
4066  } else if (SEQ_LT(seq, ssn->client.next_seq) ||
4067  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4068  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4069  "%" PRIu32 " != %" PRIu32 " from stream",
4070  ssn, seq, ssn->client.next_seq);
4072  return -1;
4073  }
4074 
4075  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4076  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4078  return -1;
4079  }
4080 
4081  if (!retransmission) {
4082  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4083  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4084 
4085  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4087  ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4088  }
4089  ssn->server.window = window << ssn->server.wscale;
4090  }
4091 
4092  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4093  StreamTcpHandleTimestamp(ssn, p);
4094  }
4095 
4096  /* Update the next_seq, in case if we have missed the client
4097  packet and server has already received and acked it */
4098  if (SEQ_LT(ssn->server.next_seq, ack))
4099  ssn->server.next_seq = ack;
4100 
4101  if (tcph->th_flags & TH_ACK)
4102  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4103 
4104  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4105 
4106  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4107  "%" PRIu32 "", ssn, ssn->client.next_seq,
4108  ssn->server.last_ack);
4109  } else { /* implied to client */
4110  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4111  "%" PRIu32 ", ACK %" PRIu32 "",
4112  ssn, p->payload_len, seq, ack);
4113  int retransmission = 0;
4114 
4115  if (SEQ_EQ(seq, ssn->server.next_seq - 1) && SEQ_EQ(ack, ssn->client.last_ack)) {
4116  SCLogDebug("ssn %p: retransmission", ssn);
4117  retransmission = 1;
4119  } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4120  SCLogDebug("ssn %p: packet is retransmission", ssn);
4121  retransmission = 1;
4123 
4124  } else if (SEQ_LT(seq, ssn->server.next_seq) ||
4125  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4126  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4127  "%" PRIu32 " != %" PRIu32 " from stream",
4128  ssn, seq, ssn->server.next_seq);
4130  return -1;
4131  }
4132 
4133  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4134  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4136  return -1;
4137  }
4138 
4139  if (!retransmission) {
4140  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4141  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4142 
4143  ssn->client.window = window << ssn->client.wscale;
4144  }
4145 
4146  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4147  StreamTcpHandleTimestamp(ssn, p);
4148  }
4149 
4150  /* Update the next_seq, in case if we have missed the client
4151  packet and server has already received and acked it */
4152  if (SEQ_LT(ssn->client.next_seq, ack))
4153  ssn->client.next_seq = ack;
4154 
4155  if (tcph->th_flags & TH_ACK)
4156  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4157 
4158  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4159  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4160  "%" PRIu32 "", ssn, ssn->server.next_seq,
4161  ssn->client.last_ack);
4162  }
4163 
4164  } else if (tcph->th_flags & TH_SYN) {
4165  SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
4167  return -1;
4168 
4169  } else if (tcph->th_flags & TH_ACK) {
4170  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4171  if (!StreamTcpValidateTimestamp(ssn, p))
4172  return -1;
4173  }
4174 
4175  if (PKT_IS_TOSERVER(p)) {
4176  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4177  "%" PRIu32 ", ACK %" PRIu32 "",
4178  ssn, p->payload_len, seq, ack);
4179  int retransmission = 0;
4180 
4181  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4182  SCLogDebug("ssn %p: packet is retransmission", ssn);
4183  retransmission = 1;
4185  }
4186 
4187  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4188  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4190  return -1;
4191  }
4192 
4193  if (!retransmission) {
4194  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
4196  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
4197  "%" PRIu32 "",
4198  ssn, seq, ssn->client.next_win);
4199 
4200  } else {
4201  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4202  " != %" PRIu32 " from stream",
4203  ssn, seq, ssn->client.next_seq);
4205  return -1;
4206  }
4207 
4208  ssn->server.window = window << ssn->server.wscale;
4209  }
4210 
4211  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4212  StreamTcpHandleTimestamp(ssn, p);
4213  }
4214 
4215  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4216  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4217  }
4218 
4219  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4220 
4222 
4223  /* update next_win */
4224  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
4225 
4226  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4227 
4228  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4229  "%" PRIu32 "", ssn, ssn->client.next_seq,
4230  ssn->server.last_ack);
4231  } else { /* implied to client */
4232  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4233  "%" PRIu32 ", ACK %" PRIu32 "",
4234  ssn, p->payload_len, seq, ack);
4235  int retransmission = 0;
4236 
4237  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4238  SCLogDebug("ssn %p: packet is retransmission", ssn);
4239  retransmission = 1;
4241  }
4242 
4243  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4244  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4246  return -1;
4247  }
4248 
4249  if (!retransmission) {
4250  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4252  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4253  "%" PRIu32 "",
4254  ssn, seq, ssn->server.next_win);
4255  } else {
4256  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4257  " != %" PRIu32 " from stream",
4258  ssn, seq, ssn->server.next_seq);
4260  return -1;
4261  }
4262 
4263  ssn->client.window = window << ssn->client.wscale;
4264  }
4265 
4266  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4267  StreamTcpHandleTimestamp(ssn, p);
4268  }
4269 
4270  if (SEQ_EQ(ssn->server.next_seq, seq)) {
4271  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4272  }
4273 
4274  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4275 
4277 
4278  /* update next_win */
4279  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4280 
4281  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4282 
4283  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4284  "%" PRIu32 "", ssn, ssn->server.next_seq,
4285  ssn->client.last_ack);
4286  }
4287  } else {
4288  SCLogDebug("ssn %p: default case", ssn);
4289  }
4290 
4291  return 0;
4292 }
4293 
4294 /**
4295  * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
4296  * the connection goes to TCP_TIME_WAIT state. The state has been
4297  * reached as both end application has been closed.
4298  *
4299  * \param tv Thread Variable containing input/output queue, cpu affinity
4300  * \param p Packet which has to be handled in this TCP state.
4301  * \param stt Stream Thread module registered to handle the stream handling
4302  */
4303 
4304 static int StreamTcpPacketStateClosing(
4305  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4306 {
4307  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4308  const TCPHdr *tcph = PacketGetTCP(p);
4309  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4310  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4311  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4312 
4313  if (tcph->th_flags & TH_RST) {
4314  if (!StreamTcpValidateRst(ssn, p))
4315  return -1;
4316 
4317  StreamTcpCloseSsnWithReset(p, ssn);
4318 
4319  if (PKT_IS_TOSERVER(p)) {
4320  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4322  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4323 
4324  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4325 
4326  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4327  StreamTcpHandleTimestamp(ssn, p);
4328  }
4329 
4330  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4331  } else {
4332  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4334  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4335 
4336  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4337 
4338  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4339  StreamTcpHandleTimestamp(ssn, p);
4340  }
4341 
4342  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4343  }
4344 
4345  } else if (tcph->th_flags & TH_SYN) {
4346  SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
4348  return -1;
4349 
4350  } else if (tcph->th_flags & TH_ACK) {
4351  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4352  if (!StreamTcpValidateTimestamp(ssn, p))
4353  return -1;
4354  }
4355 
4356  if (PKT_IS_TOSERVER(p)) {
4357  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4358  "%" PRIu32 ", ACK %" PRIu32 "",
4359  ssn, p->payload_len, seq, ack);
4360  int retransmission = 0;
4361  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4362  SCLogDebug("ssn %p: packet is retransmission", ssn);
4363  retransmission = 1;
4365  }
4366 
4367  if (seq != ssn->client.next_seq) {
4368  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4369  " != %" PRIu32 " from stream",
4370  ssn, seq, ssn->client.next_seq);
4372  return -1;
4373  }
4374 
4375  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4376  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4378  return -1;
4379  }
4380 
4381  if (!retransmission) {
4382  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4383  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4384 
4385  ssn->client.window = window << ssn->client.wscale;
4386  }
4387 
4388  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4389  StreamTcpHandleTimestamp(ssn, p);
4390  }
4391  /* Update the next_seq, in case if we have missed the client
4392  packet and server has already received and acked it */
4393  if (SEQ_LT(ssn->server.next_seq, ack))
4394  ssn->server.next_seq = ack;
4395 
4396  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4397 
4398  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4399  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4400  "%" PRIu32 "", ssn, ssn->client.next_seq,
4401  ssn->server.last_ack);
4402  } else { /* implied to client */
4403  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4404  "%" PRIu32 ", ACK %" PRIu32 "",
4405  ssn, p->payload_len, seq, ack);
4406  int retransmission = 0;
4407  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4408  SCLogDebug("ssn %p: packet is retransmission", ssn);
4409  retransmission = 1;
4411  }
4412 
4413  if (seq != ssn->server.next_seq) {
4414  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4415  " != %" PRIu32 " from stream",
4416  ssn, seq, ssn->server.next_seq);
4418  return -1;
4419  }
4420 
4421  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4422  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4424  return -1;
4425  }
4426 
4427  if (!retransmission) {
4428  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4429  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4430 
4431  ssn->client.window = window << ssn->client.wscale;
4432  }
4433 
4434  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4435  StreamTcpHandleTimestamp(ssn, p);
4436  }
4437 
4438  /* Update the next_seq, in case if we have missed the client
4439  packet and server has already received and acked it */
4440  if (SEQ_LT(ssn->client.next_seq, ack))
4441  ssn->client.next_seq = ack;
4442 
4443  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4444 
4445  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4446  SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
4447  "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
4448  ssn->server.next_seq, ssn->client.last_ack);
4449  }
4450  } else {
4451  SCLogDebug("ssn %p: default case", ssn);
4452  }
4453 
4454  return 0;
4455 }
4456 
4457 /**
4458  * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
4459  * packet from server the connection goes to TCP_LAST_ACK state.
4460  * The state is possible only for server host.
4461  *
4462  * \param tv Thread Variable containing input/output queue, cpu affinity
4463  * \param p Packet which has to be handled in this TCP state.
4464  * \param stt Stream Thread module registered to handle the stream handling
4465  */
4466 
4467 static int StreamTcpPacketStateCloseWait(
4468  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4469 {
4470  SCEnter();
4471  const TCPHdr *tcph = PacketGetTCP(p);
4472  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4473  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4474  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4475 
4476  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4477 
4478  if (PKT_IS_TOCLIENT(p)) {
4479  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4480  "%" PRIu32 ", ACK %" PRIu32 "",
4481  ssn, p->payload_len, seq, ack);
4482  } else {
4483  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4484  "%" PRIu32 ", ACK %" PRIu32 "",
4485  ssn, p->payload_len, seq, ack);
4486  }
4487 
4488  if (tcph->th_flags & TH_RST) {
4489  if (!StreamTcpValidateRst(ssn, p))
4490  return -1;
4491 
4492  StreamTcpCloseSsnWithReset(p, ssn);
4493 
4494  if (PKT_IS_TOSERVER(p)) {
4495  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4497  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4498 
4499  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4500 
4501  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4502  StreamTcpHandleTimestamp(ssn, p);
4503  }
4504 
4505  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4506  } else {
4507  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4509  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4510 
4511  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4512 
4513  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4514  StreamTcpHandleTimestamp(ssn, p);
4515  }
4516 
4517  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4518  }
4519 
4520  } else if (tcph->th_flags & TH_FIN) {
4521  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4522  if (!StreamTcpValidateTimestamp(ssn, p))
4523  SCReturnInt(-1);
4524  }
4525 
4526  if (PKT_IS_TOSERVER(p)) {
4527  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4528  "%" PRIu32 ", ACK %" PRIu32 "",
4529  ssn, p->payload_len, seq, ack);
4530 
4531  int retransmission = 0;
4532  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4533  SCLogDebug("ssn %p: packet is retransmission", ssn);
4534  retransmission = 1;
4536  }
4537 
4538  if (!retransmission) {
4539  if (SEQ_LT(seq, ssn->client.next_seq) ||
4540  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4541  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4542  " != %" PRIu32 " from stream",
4543  ssn, seq, ssn->client.next_seq);
4545  SCReturnInt(-1);
4546  }
4547  }
4548 
4549  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4550  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4552  SCReturnInt(-1);
4553  }
4554 
4555  /* don't update to LAST_ACK here as we want a toclient FIN for that */
4556 
4557  if (!retransmission)
4558  ssn->server.window = window << ssn->server.wscale;
4559 
4560  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4561  StreamTcpHandleTimestamp(ssn, p);
4562  }
4563 
4564  /* Update the next_seq, in case if we have missed the client
4565  packet and server has already received and acked it */
4566  if (SEQ_LT(ssn->server.next_seq, ack))
4567  ssn->server.next_seq = ack;
4568 
4569  if (tcph->th_flags & TH_ACK)
4570  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4571 
4572  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4573  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4574  "%" PRIu32 "", ssn, ssn->client.next_seq,
4575  ssn->server.last_ack);
4576  } else {
4577  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4578  "%" PRIu32 ", ACK %" PRIu32 "",
4579  ssn, p->payload_len, seq, ack);
4580 
4581  int retransmission = 0;
4582  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4583  SCLogDebug("ssn %p: packet is retransmission", ssn);
4584  retransmission = 1;
4586  }
4587 
4588  if (!retransmission) {
4589  if (SEQ_LT(seq, ssn->server.next_seq) ||
4590  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4591  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4592  " != %" PRIu32 " from stream",
4593  ssn, seq, ssn->server.next_seq);
4595  SCReturnInt(-1);
4596  }
4597  }
4598 
4599  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4600  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4602  SCReturnInt(-1);
4603  }
4604 
4605  if (!retransmission) {
4606  StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
4607  SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
4608 
4609  ssn->client.window = window << ssn->client.wscale;
4610  }
4611 
4612  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4613  StreamTcpHandleTimestamp(ssn, p);
4614  }
4615 
4616  /* Update the next_seq, in case if we have missed the client
4617  packet and server has already received and acked it */
4618  if (SEQ_LT(ssn->client.next_seq, ack))
4619  ssn->client.next_seq = ack;
4620 
4621  if (tcph->th_flags & TH_ACK)
4622  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4623 
4624  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4625  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4626  "%" PRIu32 "", ssn, ssn->server.next_seq,
4627  ssn->client.last_ack);
4628  }
4629 
4630  } else if (tcph->th_flags & TH_SYN) {
4631  SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
4633  SCReturnInt(-1);
4634 
4635  } else if (tcph->th_flags & TH_ACK) {
4636  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4637  if (!StreamTcpValidateTimestamp(ssn, p))
4638  SCReturnInt(-1);
4639  }
4640 
4641  if (PKT_IS_TOSERVER(p)) {
4642  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4643  "%" PRIu32 ", ACK %" PRIu32 "",
4644  ssn, p->payload_len, seq, ack);
4645 
4646  int retransmission = 0;
4647  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4648  SCLogDebug("ssn %p: packet is retransmission", ssn);
4649  retransmission = 1;
4651  }
4652 
4653  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->client.last_ack))) {
4654  SCLogDebug("ssn %p: -> retransmission", ssn);
4656  SCReturnInt(-1);
4657 
4658  } else if (SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4659  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4660  " != %" PRIu32 " from stream",
4661  ssn, seq, ssn->client.next_seq);
4663  SCReturnInt(-1);
4664  }
4665 
4666  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4667  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4669  SCReturnInt(-1);
4670  }
4671 
4672  if (!retransmission) {
4673  ssn->server.window = window << ssn->server.wscale;
4674  }
4675 
4676  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4677  StreamTcpHandleTimestamp(ssn, p);
4678  }
4679 
4680  /* Update the next_seq, in case if we have missed the client
4681  packet and server has already received and acked it */
4682  if (SEQ_LT(ssn->server.next_seq, ack))
4683  ssn->server.next_seq = ack;
4684 
4685  if (SEQ_EQ(seq, ssn->client.next_seq))
4686  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4687 
4688  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4689 
4690  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4691  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4692  "%" PRIu32 "", ssn, ssn->client.next_seq,
4693  ssn->server.last_ack);
4694  } else {
4695  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4696  "%" PRIu32 ", ACK %" PRIu32 "",
4697  ssn, p->payload_len, seq, ack);
4698  int retransmission = 0;
4699  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4700  SCLogDebug("ssn %p: packet is retransmission", ssn);
4701  retransmission = 1;
4703  }
4704 
4705  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->server.last_ack))) {
4706  SCLogDebug("ssn %p: -> retransmission", ssn);
4708  SCReturnInt(-1);
4709 
4710  } else if (SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4711  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4712  " != %" PRIu32 " from stream",
4713  ssn, seq, ssn->server.next_seq);
4715  SCReturnInt(-1);
4716  }
4717 
4718  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4719  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4721  SCReturnInt(-1);
4722  }
4723 
4724  if (!retransmission) {
4725  ssn->client.window = window << ssn->client.wscale;
4726  }
4727 
4728  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4729  StreamTcpHandleTimestamp(ssn, p);
4730  }
4731 
4732  /* Update the next_seq, in case if we have missed the client
4733  packet and server has already received and acked it */
4734  if (SEQ_LT(ssn->client.next_seq, ack))
4735  ssn->client.next_seq = ack;
4736 
4737  if (SEQ_EQ(seq, ssn->server.next_seq))
4738  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4739 
4740  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4741 
4742  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4743  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4744  "%" PRIu32 "", ssn, ssn->server.next_seq,
4745  ssn->client.last_ack);
4746  }
4747 
4748  } else {
4749  SCLogDebug("ssn %p: default case", ssn);
4750  }
4751  SCReturnInt(0);
4752 }
4753 
4754 /**
4755  * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
4756  * the connection goes to TCP_CLOSED state and stream memory is
4757  * returned back to pool. The state is possible only for server host.
4758  *
4759  * \param tv Thread Variable containing input/output queue, cpu affinity
4760  * \param p Packet which has to be handled in this TCP state.
4761  * \param stt Stream Thread module registered to handle the stream handling
4762  */
4763 
4764 static int StreamTcpPacketStateLastAck(
4765  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4766 {
4767  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4768  const TCPHdr *tcph = PacketGetTCP(p);
4769  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4770  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4771  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4772 
4773  if (tcph->th_flags & TH_RST) {
4774  if (!StreamTcpValidateRst(ssn, p))
4775  return -1;
4776 
4777  StreamTcpCloseSsnWithReset(p, ssn);
4778 
4779  if (PKT_IS_TOSERVER(p)) {
4780  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4782  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4783 
4784  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4785 
4786  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4787  StreamTcpHandleTimestamp(ssn, p);
4788  }
4789 
4790  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4791  } else {
4792  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4794  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4795 
4796  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4797 
4798  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4799  StreamTcpHandleTimestamp(ssn, p);
4800  }
4801 
4802  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4803  }
4804 
4805  } else if (tcph->th_flags & TH_FIN) {
4806  /** \todo */
4807  SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
4808 
4809  } else if (tcph->th_flags & TH_SYN) {
4810  SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
4812  return -1;
4813 
4814  } else if (tcph->th_flags & TH_ACK) {
4815  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4816  if (!StreamTcpValidateTimestamp(ssn, p))
4817  return -1;
4818  }
4819 
4820  if (PKT_IS_TOSERVER(p)) {
4821  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4822  "%" PRIu32 ", ACK %" PRIu32 "",
4823  ssn, p->payload_len, seq, ack);
4824 
4825  int retransmission = 0;
4826  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4827  SCLogDebug("ssn %p: packet is retransmission", ssn);
4828  retransmission = 1;
4830  }
4831 
4832  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4833  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4835  SCReturnInt(-1);
4836  }
4837 
4838  if (!retransmission) {
4839  if (SEQ_LT(seq, ssn->client.next_seq)) {
4840  SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
4841  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
4842  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4843  " != %" PRIu32 " from stream",
4844  ssn, seq, ssn->client.next_seq);
4846  return -1;
4847  } else {
4848  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4849  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4850  }
4851  ssn->server.window = window << ssn->server.wscale;
4852  }
4853 
4854  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4855  StreamTcpHandleTimestamp(ssn, p);
4856  }
4857 
4858  /* Update the next_seq, in case if we have missed the client
4859  packet and server has already received and acked it */
4860  if (SEQ_LT(ssn->server.next_seq, ack))
4861  ssn->server.next_seq = ack;
4862 
4863  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4864 
4865  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4866  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4867  "%" PRIu32 "", ssn, ssn->client.next_seq,
4868  ssn->server.last_ack);
4869  }
4870  } else {
4871  SCLogDebug("ssn %p: default case", ssn);
4872  }
4873 
4874  return 0;
4875 }
4876 
4877 /**
4878  * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
4879  * the connection goes to TCP_CLOSED state and stream memory is
4880  * returned back to pool.
4881  *
4882  * \param tv Thread Variable containing input/output queue, cpu affinity
4883  * \param p Packet which has to be handled in this TCP state.
4884  * \param stt Stream Thread module registered to handle the stream handling
4885  */
4886 
4887 static int StreamTcpPacketStateTimeWait(
4888  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4889 {
4890  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4891  const TCPHdr *tcph = PacketGetTCP(p);
4892  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4893  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4894  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4895 
4896  if (tcph->th_flags & TH_RST) {
4897  if (!StreamTcpValidateRst(ssn, p))
4898  return -1;
4899 
4900  StreamTcpCloseSsnWithReset(p, ssn);
4901 
4902  if (PKT_IS_TOSERVER(p)) {
4903  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4905  ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, ack));
4906 
4907  StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, seq));
4908 
4909  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4910  StreamTcpHandleTimestamp(ssn, p);
4911  }
4912 
4913  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4914  } else {
4915  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4917  ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, ack));
4918 
4919  StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, seq));
4920 
4921  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4922  StreamTcpHandleTimestamp(ssn, p);
4923  }
4924 
4925  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4926  }
4927 
4928  } else if (tcph->th_flags & TH_FIN) {
4929  /** \todo */
4930 
4931  } else if (tcph->th_flags & TH_SYN) {
4932  SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
4934  return -1;
4935 
4936  } else if (tcph->th_flags & TH_ACK) {
4937  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4938  if (!StreamTcpValidateTimestamp(ssn, p))
4939  return -1;
4940  }
4941 
4942  if (PKT_IS_TOSERVER(p)) {
4943  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4944  "%" PRIu32 ", ACK %" PRIu32 "",
4945  ssn, p->payload_len, seq, ack);
4946  int retransmission = 0;
4947  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4948  SCLogDebug("ssn %p: packet is retransmission", ssn);
4949  retransmission = 1;
4951 
4952  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
4953  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4954  " != %" PRIu32 " from stream",
4955  ssn, seq, ssn->client.next_seq);
4957  return -1;
4958  }
4959 
4960  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4961  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4963  SCReturnInt(-1);
4964  }
4965 
4966  if (!retransmission) {
4967  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4968  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4969 
4970  ssn->server.window = window << ssn->server.wscale;
4971  }
4972 
4973  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4974  StreamTcpHandleTimestamp(ssn, p);
4975  }
4976 
4977  /* Update the next_seq, in case if we have missed the client
4978  packet and server has already received and acked it */
4979  if (SEQ_LT(ssn->server.next_seq, ack))
4980  ssn->server.next_seq = ack;
4981 
4982  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4983 
4984  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4985  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4986  "%" PRIu32 "", ssn, ssn->client.next_seq,
4987  ssn->server.last_ack);
4988  } else {
4989  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4990  "%" PRIu32 ", ACK %" PRIu32 "",
4991  ssn, p->payload_len, seq, ack);
4992  int retransmission = 0;
4993  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4994  SCLogDebug("ssn %p: packet is retransmission", ssn);
4995  retransmission = 1;
4997  } else if (seq != ssn->server.next_seq - 1 && seq != ssn->server.next_seq) {
4998  if (p->payload_len > 0 && seq == ssn->server.last_ack) {
4999  SCLogDebug("ssn %p: -> retransmission", ssn);
5000  SCReturnInt(0);
5001  } else {
5002  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5003  " != %" PRIu32 " from stream",
5004  ssn, seq, ssn->server.next_seq);
5006  return -1;
5007  }
5008  }
5009 
5010  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
5011  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5013  SCReturnInt(-1);
5014  }
5015 
5016  if (!retransmission) {
5017  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5018  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5019 
5020  ssn->client.window = window << ssn->client.wscale;
5021  }
5022 
5023  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5024  StreamTcpHandleTimestamp(ssn, p);
5025  }
5026 
5027  /* Update the next_seq, in case if we have missed the client
5028  packet and server has already received and acked it */
5029  if (SEQ_LT(ssn->client.next_seq, ack))
5030  ssn->client.next_seq = ack;
5031 
5032  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
5033 
5034  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5035  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5036  "%" PRIu32 "", ssn, ssn->server.next_seq,
5037  ssn->client.last_ack);
5038  }
5039 
5040  } else {
5041  SCLogDebug("ssn %p: default case", ssn);
5042  }
5043 
5044  return 0;
5045 }
5046 
5047 static int StreamTcpPacketStateClosed(
5048  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
5049 {
5050  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5051 
5052  const TCPHdr *tcph = PacketGetTCP(p);
5053  if (tcph->th_flags & TH_RST) {
5054  SCLogDebug("RST on closed state");
5055  return 0;
5056  }
5057 
5058  TcpStream *stream = NULL, *ostream = NULL;
5059  if (PKT_IS_TOSERVER(p)) {
5060  stream = &ssn->client;
5061  ostream = &ssn->server;
5062  } else {
5063  stream = &ssn->server;
5064  ostream = &ssn->client;
5065  }
5066 
5067  SCLogDebug("stream %s ostream %s",
5068  stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
5069  ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
5070 
5071  /* if we've seen a RST on our direction, but not on the other
5072  * see if we perhaps need to continue processing anyway. */
5073  if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
5074  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5075  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->pstate) < 0)
5076  return -1;
5077  /* if state is still "closed", it wasn't updated by our dispatch. */
5078  if (ssn->state == TCP_CLOSED)
5079  ssn->state = ssn->pstate;
5080  }
5081  }
5082  return 0;
5083 }
5084 
5085 static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
5086 {
5087  if (p->flags & PKT_PSEUDO_STREAM_END) {
5088  return;
5089  }
5090  const TCPHdr *tcph = PacketGetTCP(p);
5091  /* more RSTs are not unusual */
5092  if ((tcph->th_flags & (TH_RST)) != 0) {
5093  return;
5094  }
5095 
5096  TcpStream *ostream = NULL;
5097  if (PKT_IS_TOSERVER(p)) {
5098  ostream = &ssn->server;
5099  } else {
5100  ostream = &ssn->client;
5101  }
5102 
5103  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5104  SCLogDebug("regular packet %"PRIu64" from same sender as "
5105  "the previous RST. Looks like it injected!", p->pcap_cnt);
5109  return;
5110  }
5111 }
5112 
5113 /**
5114  * \retval 1 packet is a keep alive pkt
5115  * \retval 0 packet is not a keep alive pkt
5116  */
5117 static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
5118 {
5119  if (p->flags & PKT_PSEUDO_STREAM_END)
5120  return 0;
5121 
5122  /* rfc 1122:
5123  An implementation SHOULD send a keep-alive segment with no
5124  data; however, it MAY be configurable to send a keep-alive
5125  segment containing one garbage octet, for compatibility with
5126  erroneous TCP implementations.
5127  */
5128  if (p->payload_len > 1)
5129  return 0;
5130 
5131  const TCPHdr *tcph = PacketGetTCP(p);
5132  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) {
5133  return 0;
5134  }
5135 
5136  TcpStream *stream = NULL, *ostream = NULL;
5137  if (PKT_IS_TOSERVER(p)) {
5138  stream = &ssn->client;
5139  ostream = &ssn->server;
5140  } else {
5141  stream = &ssn->server;
5142  ostream = &ssn->client;
5143  }
5144 
5145  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
5146  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
5147  if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
5148  SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
5151  return 1;
5152  }
5153  SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
5154  return 0;
5155 }
5156 
5157 /**
5158  * \retval 1 packet is a keep alive ACK pkt
5159  * \retval 0 packet is not a keep alive ACK pkt
5160  */
5161 static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
5162 {
5163  TcpStream *stream = NULL, *ostream = NULL;
5164  uint32_t seq;
5165  uint32_t ack;
5166  uint32_t pkt_win;
5167 
5168  if (p->flags & PKT_PSEUDO_STREAM_END)
5169  return 0;
5170  /* should get a normal ACK to a Keep Alive */
5171  if (p->payload_len > 0)
5172  return 0;
5173 
5174  const TCPHdr *tcph = PacketGetTCP(p);
5175  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5176  return 0;
5177 
5178  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5179  return 0;
5180 
5181  if (PKT_IS_TOSERVER(p)) {
5182  stream = &ssn->client;
5183  ostream = &ssn->server;
5184  } else {
5185  stream = &ssn->server;
5186  ostream = &ssn->client;
5187  }
5188 
5189  seq = TCP_GET_RAW_SEQ(tcph);
5190  ack = TCP_GET_RAW_ACK(tcph);
5191 
5192  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5193  if (pkt_win != ostream->window)
5194  return 0;
5195 
5196  if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
5197  SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
5198  ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
5200  return 1;
5201  }
5202  SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
5203  ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
5204  return 0;
5205 }
5206 
5207 static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
5208 {
5209  TcpStream *stream = NULL;
5210 
5211  if (p->flags & PKT_PSEUDO_STREAM_END)
5212  return;
5213 
5214  if (PKT_IS_TOSERVER(p)) {
5215  stream = &ssn->client;
5216  } else {
5217  stream = &ssn->server;
5218  }
5219 
5220  if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
5222  SCLogDebug("FLAG_KEEPALIVE cleared");
5223  }
5224 }
5225 
5226 /**
5227  * \retval 1 packet is a window update pkt
5228  * \retval 0 packet is not a window update pkt
5229  */
5230 static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
5231 {
5232  TcpStream *stream = NULL, *ostream = NULL;
5233  uint32_t seq;
5234  uint32_t ack;
5235  uint32_t pkt_win;
5236 
5237  if (p->flags & PKT_PSEUDO_STREAM_END)
5238  return 0;
5239 
5240  if (ssn->state < TCP_ESTABLISHED)
5241  return 0;
5242 
5243  if (p->payload_len > 0)
5244  return 0;
5245 
5246  const TCPHdr *tcph = PacketGetTCP(p);
5247  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5248  return 0;
5249 
5250  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5251  return 0;
5252 
5253  if (PKT_IS_TOSERVER(p)) {
5254  stream = &ssn->client;
5255  ostream = &ssn->server;
5256  } else {
5257  stream = &ssn->server;
5258  ostream = &ssn->client;
5259  }
5260 
5261  seq = TCP_GET_RAW_SEQ(tcph);
5262  ack = TCP_GET_RAW_ACK(tcph);
5263 
5264  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5265  if (pkt_win == ostream->window)
5266  return 0;
5267 
5268  if (ack == ostream->last_ack && seq == stream->next_seq) {
5269  SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
5271  return 1;
5272  }
5273  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5274  return 0;
5275 }
5276 
5277 /**
5278  * Try to detect whether a packet is a valid FIN 4whs final ack.
5279  *
5280  */
5281 static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
5282 {
5283  TcpStream *stream = NULL, *ostream = NULL;
5284  uint32_t seq;
5285  uint32_t ack;
5286 
5287  if (p->flags & PKT_PSEUDO_STREAM_END)
5288  return 0;
5289  if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
5290  return 0;
5291  const TCPHdr *tcph = PacketGetTCP(p);
5292  if (tcph->th_flags != TH_ACK)
5293  return 0;
5294  if (p->payload_len != 0)
5295  return 0;
5296 
5297  if (PKT_IS_TOSERVER(p)) {
5298  stream = &ssn->client;
5299  ostream = &ssn->server;
5300  } else {
5301  stream = &ssn->server;
5302  ostream = &ssn->client;
5303  }
5304 
5305  seq = TCP_GET_RAW_SEQ(tcph);
5306  ack = TCP_GET_RAW_ACK(tcph);
5307 
5308  SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
5309  p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
5310 
5311  if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
5312  return 1;
5313  }
5314  return 0;
5315 }
5316 
5317 /**
5318  * Try to detect packets doing bad window updates
5319  *
5320  * See bug 1238.
5321  *
5322  * Find packets that are unexpected, and shrink the window to the point
5323  * where the packets we do expect are rejected for being out of window.
5324  *
5325  * The logic we use here is:
5326  * - packet seq > next_seq
5327  * - packet ack > next_seq (packet acks unseen data)
5328  * - packet shrinks window more than it's own data size
5329  * - packet shrinks window more than the diff between it's ack and the
5330  * last_ack value
5331  *
5332  * Packets coming in after packet loss can look quite a bit like this.
5333  */
5334 static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
5335 {
5336  TcpStream *stream = NULL, *ostream = NULL;
5337  uint32_t seq;
5338  uint32_t ack;
5339  uint32_t pkt_win;
5340 
5341  if (p->flags & PKT_PSEUDO_STREAM_END)
5342  return 0;
5343 
5344  if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
5345  return 0;
5346 
5347  const TCPHdr *tcph = PacketGetTCP(p);
5348  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5349  return 0;
5350 
5351  if (PKT_IS_TOSERVER(p)) {
5352  stream = &ssn->client;
5353  ostream = &ssn->server;
5354  } else {
5355  stream = &ssn->server;
5356  ostream = &ssn->client;
5357  }
5358 
5359  seq = TCP_GET_RAW_SEQ(tcph);
5360  ack = TCP_GET_RAW_ACK(tcph);
5361  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5362 
5363  if (pkt_win < ostream->window) {
5364  uint32_t diff = ostream->window - pkt_win;
5365  if (diff > p->payload_len &&
5366  SEQ_GT(ack, ostream->next_seq) &&
5367  SEQ_GT(seq, stream->next_seq))
5368  {
5369  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
5370  p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
5371  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
5372  p->pcap_cnt, pkt_win, ostream->window);
5373  SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
5374  p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
5375  ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
5376 
5377  /* get the expected window shrinking from looking at ack vs last_ack.
5378  * Observed a lot of just a little overrunning that value. So added some
5379  * margin that is still ok. To make sure this isn't a loophole to still
5380  * close the window, this is limited to windows above 1024. Both values
5381  * are rather arbitrary. */
5382  uint32_t adiff = ack - ostream->last_ack;
5383  if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
5384  ((pkt_win <= 1024) && (diff > adiff)))
5385  {
5386  SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
5387  "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
5388  SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
5390  return 1;
5391  }
5392  }
5393 
5394  }
5395  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5396  return 0;
5397 }
5398 
5399 /** \internal
5400  * \brief call packet handling function for 'state'
5401  * \param state current TCP state
5402  */
5403 static inline int StreamTcpStateDispatch(
5404  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state)
5405 {
5406  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5407 
5408  SCLogDebug("ssn: %p", ssn);
5409  switch (state) {
5410  case TCP_SYN_SENT:
5411  SCLogDebug("packet received on TCP_SYN_SENT state");
5412  if (StreamTcpPacketStateSynSent(tv, p, stt, ssn)) {
5413  return -1;
5414  }
5415  break;
5416  case TCP_SYN_RECV:
5417  SCLogDebug("packet received on TCP_SYN_RECV state");
5418  if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn)) {
5419  return -1;
5420  }
5421  break;
5422  case TCP_ESTABLISHED:
5423  SCLogDebug("packet received on TCP_ESTABLISHED state");
5424  if (StreamTcpPacketStateEstablished(tv, p, stt, ssn)) {
5425  return -1;
5426  }
5427  break;
5428  case TCP_FIN_WAIT1:
5429  SCLogDebug("packet received on TCP_FIN_WAIT1 state");
5430  if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn)) {
5431  return -1;
5432  }
5433  break;
5434  case TCP_FIN_WAIT2:
5435  SCLogDebug("packet received on TCP_FIN_WAIT2 state");
5436  if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn)) {
5437  return -1;
5438  }
5439  break;
5440  case TCP_CLOSING:
5441  SCLogDebug("packet received on TCP_CLOSING state");
5442  if (StreamTcpPacketStateClosing(tv, p, stt, ssn)) {
5443  return -1;
5444  }
5445  break;
5446  case TCP_CLOSE_WAIT:
5447  SCLogDebug("packet received on TCP_CLOSE_WAIT state");
5448  if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn)) {
5449  return -1;
5450  }
5451  break;
5452  case TCP_LAST_ACK:
5453  SCLogDebug("packet received on TCP_LAST_ACK state");
5454  if (StreamTcpPacketStateLastAck(tv, p, stt, ssn)) {
5455  return -1;
5456  }
5457  break;
5458  case TCP_TIME_WAIT:
5459  SCLogDebug("packet received on TCP_TIME_WAIT state");
5460  if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn)) {
5461  return -1;
5462  }
5463  break;
5464  case TCP_CLOSED:
5465  /* TCP session memory is not returned to pool until timeout. */
5466  SCLogDebug("packet received on closed state");
5467 
5468  if (StreamTcpPacketStateClosed(tv, p, stt, ssn)) {
5469  return -1;
5470  }
5471 
5472  break;
5473  default:
5474  SCLogDebug("packet received on default state");
5475  break;
5476  }
5477  return 0;
5478 }
5479 
5480 static inline void HandleThreadId(ThreadVars *tv, Packet *p, StreamTcpThread *stt)
5481 {
5482  const int idx = (!(PKT_IS_TOSERVER(p)));
5483 
5484  /* assign the thread id to the flow */
5485  if (unlikely(p->flow->thread_id[idx] == 0)) {
5486  p->flow->thread_id[idx] = (FlowThreadId)tv->id;
5487  } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id[idx])) {
5488  SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id[idx], tv->id);
5489  if (p->pkt_src == PKT_SRC_WIRE) {
5491  if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
5492  p->flow->flags |= FLOW_WRONG_THREAD;
5494  }
5495  }
5496  }
5497 }
5498 
5499 /* flow is and stays locked */
5501  PacketQueueNoLock *pq)
5502 {
5503  SCEnter();
5504 
5506 
5507  SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
5508 
5509  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
5510  const TCPHdr *tcph = PacketGetTCP(p);
5511 
5512  /* track TCP flags */
5513  if (ssn != NULL) {
5514  ssn->tcp_packet_flags |= tcph->th_flags;
5515  if (PKT_IS_TOSERVER(p))
5516  ssn->client.tcp_flags |= tcph->th_flags;
5517  else if (PKT_IS_TOCLIENT(p))
5518  ssn->server.tcp_flags |= tcph->th_flags;
5519 
5520  /* check if we need to unset the ASYNC flag */
5521  if (ssn->flags & STREAMTCP_FLAG_ASYNC &&
5522  ssn->client.tcp_flags != 0 &&
5523  ssn->server.tcp_flags != 0)
5524  {
5525  SCLogDebug("ssn %p: removing ASYNC flag as we have packets on both sides", ssn);
5526  ssn->flags &= ~STREAMTCP_FLAG_ASYNC;
5527  }
5528  }
5529 
5530  /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */
5531  if (!(tcph->th_flags & TH_ACK) && TCP_GET_RAW_ACK(tcph) != 0) {
5533  }
5534 
5535  /* If we are on IPS mode, and got a drop action triggered from
5536  * the IP only module, or from a reassembled msg and/or from an
5537  * applayer detection, then drop the rest of the packets of the
5538  * same stream and avoid inspecting it any further */
5539  if (StreamTcpCheckFlowDrops(p) == 1) {
5541  SCLogDebug("flow triggered a drop rule");
5543  /* return the segments to the pool */
5545  SCReturnInt(0);
5546  }
5547 
5548  if (ssn == NULL || ssn->state == TCP_NONE) {
5549  if (StreamTcpPacketStateNone(tv, p, stt, ssn) == -1) {
5550  goto error;
5551  }
5552 
5553  if (ssn != NULL)
5554  SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto);
5555  } else {
5556  /* special case for PKT_PSEUDO_STREAM_END packets:
5557  * bypass the state handling and various packet checks,
5558  * we care about reassembly here. */
5559  if (p->flags & PKT_PSEUDO_STREAM_END) {
5560  if (PKT_IS_TOCLIENT(p)) {
5561  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5562  } else {
5563  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5564  }
5565  /* straight to 'skip' as we already handled reassembly */
5566  goto skip;
5567  }
5568 
5569  if (p->flow->flags & FLOW_WRONG_THREAD) {
5570  /* Stream and/or session in known bad condition. Block events
5571  * from being set. */
5573  }
5574 
5575  if (StreamTcpPacketIsKeepAlive(ssn, p) == 1) {
5576  goto skip;
5577  }
5578  if (StreamTcpPacketIsKeepAliveACK(ssn, p) == 1) {
5579  StreamTcpClearKeepAliveFlag(ssn, p);
5580  goto skip;
5581  }
5582  StreamTcpClearKeepAliveFlag(ssn, p);
5583 
5584  const bool is_zwp_ack = StreamTcpPacketIsZeroWindowProbeAck(ssn, p);
5585  if (PKT_IS_TOCLIENT(p)) {
5586  ssn->flags &= ~STREAMTCP_FLAG_ZWP_TS;
5587  } else {
5588  ssn->flags &= ~STREAMTCP_FLAG_ZWP_TC;
5589  }
5590  if (is_zwp_ack) {
5592  goto skip;
5593  }
5594 
5595  if (StreamTcpPacketIsDupAck(ssn, p) == true) {
5597  // TODO see if we can skip work on these
5598  }
5599 
5600  /* if packet is not a valid window update, check if it is perhaps
5601  * a bad window update that we should ignore (and alert on) */
5602  if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) {
5603  if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0) {
5604  if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
5605  goto skip;
5606  if (StreamTcpPacketIsOutdatedAck(ssn, p))
5607  goto skip;
5608  }
5609  }
5610 
5611  int ret = StreamTcpPacketIsSpuriousRetransmission(ssn, p);
5612  if (ret > 0) {
5614  /* skip packet if fully before base_seq */
5615  if (ret == 2)
5616  goto skip;
5617  }
5618 
5619  /* handle the per 'state' logic */
5620  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->state) < 0)
5621  goto error;
5622 
5623  skip:
5624  StreamTcpPacketCheckPostRst(ssn, p);
5625 
5626  if (ssn->state >= TCP_ESTABLISHED) {
5627  p->flags |= PKT_STREAM_EST;
5628  }
5629  }
5630 
5631  if (ssn != NULL) {
5632  /* recalc the csum on the packet if it was modified */
5633  if (p->flags & PKT_STREAM_MODIFIED) {
5635  }
5636  /* check for conditions that may make us not want to log this packet */
5637 
5638  /* streams that hit depth */
5641  {
5642  /* we can call bypass callback, if enabled */
5643  if (StreamTcpBypassEnabled()) {
5645  }
5646  }
5647 
5650  {
5652  }
5653 
5654  /* encrypted packets */
5657  {
5659  }
5660 
5661  if (ssn->flags & STREAMTCP_FLAG_BYPASS) {
5662  /* we can call bypass callback, if enabled */
5663  if (StreamTcpBypassEnabled()) {
5665  }
5666 
5667  /* if stream is dead and we have no detect engine at all, bypass. */
5668  } else if (g_detect_disabled &&
5672  {
5673  SCLogDebug("bypass as stream is dead and we have no rules");
5675  }
5676  }
5677 
5678  SCReturnInt(0);
5679 
5680 error:
5681  /* recalc the csum on the packet if it was modified */
5682  if (p->flags & PKT_STREAM_MODIFIED) {
5684  }
5685 
5686  if (StreamTcpInlineDropInvalid()) {
5687  /* disable payload inspection as we're dropping this packet
5688  * anyway. Doesn't disable all detection, so we can still
5689  * match on the stream event that was set. */
5690  DecodeSetNoPayloadInspectionFlag(p);
5692  }
5693  SCReturnInt(-1);
5694 }
5695 
5696 /**
5697  * \brief Function to validate the checksum of the received packet. If the
5698  * checksum is invalid, packet will be dropped, as the end system will
5699  * also drop the packet.
5700  *
5701  * \param p Packet of which checksum has to be validated
5702  * \retval 1 if the checksum is valid, otherwise 0
5703  */
5704 static inline int StreamTcpValidateChecksum(Packet *p)
5705 {
5706  int ret = 1;
5707 
5708  if (p->flags & PKT_IGNORE_CHECKSUM)
5709  return ret;
5710 
5711  if (!p->l4.csum_set) {
5712  const TCPHdr *tcph = PacketGetTCP(p);
5713  if (PacketIsIPv4(p)) {
5714  const IPV4Hdr *ip4h = PacketGetIPv4(p);
5715  p->l4.csum = TCPChecksum(ip4h->s_ip_addrs, (uint16_t *)tcph,
5716  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5717  p->l4.csum_set = true;
5718  } else if (PacketIsIPv6(p)) {
5719  const IPV6Hdr *ip6h = PacketGetIPv6(p);
5720  p->l4.csum = TCPV6Checksum(ip6h->s_ip6_addrs, (uint16_t *)tcph,
5721  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5722  p->l4.csum_set = true;
5723  }
5724  }
5725 
5726  if (p->l4.csum != 0) {
5727  ret = 0;
5728  if (p->livedev) {
5729  (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1);
5730  } else if (p->pcap_cnt) {
5732  }
5733  }
5734 
5735  return ret;
5736 }
5737 
5738 /** \internal
5739  * \brief check if a packet is a valid stream started
5740  * \retval bool true/false */
5741 static int TcpSessionPacketIsStreamStarter(const Packet *p)
5742 {
5743  const TCPHdr *tcph = PacketGetTCP(p);
5744  if (tcph->th_flags & (TH_RST | TH_FIN)) {
5745  return 0;
5746  }
5747 
5748  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5749  SCLogDebug("packet %" PRIu64 " is a stream starter: %02x", p->pcap_cnt, tcph->th_flags);
5750  return 1;
5751  }
5752 
5754  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5755  SCLogDebug("packet %" PRIu64 " is a midstream stream starter: %02x", p->pcap_cnt,
5756  tcph->th_flags);
5757  return 1;
5758  }
5759  }
5760  return 0;
5761 }
5762 
5763 /** \internal
5764  * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused
5765  * \retval bool true yes reuse, false no keep tracking old ssn */
5766 static bool TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn)
5767 {
5768  const TCPHdr *tcph = PacketGetTCP(p);
5769  if (FlowGetPacketDirection(f, p) == TOSERVER) {
5770  if (ssn == NULL) {
5771  /* most likely a flow that was picked up after the 3whs, or a flow that
5772  * does not have a session due to memcap issues. */
5773  SCLogDebug("steam starter packet %" PRIu64 ", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5774  return true;
5775  }
5777  SCLogDebug("steam starter packet %" PRIu64
5778  ", ssn %p. STREAMTCP_FLAG_TFO_DATA_IGNORED set. Reuse.",
5779  p->pcap_cnt, ssn);
5780  return true;
5781  }
5782  if (SEQ_EQ(ssn->client.isn, TCP_GET_RAW_SEQ(tcph))) {
5783  SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5784  return false;
5785  }
5786  if (ssn->state >= TCP_LAST_ACK) {
5787  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5788  return true;
5789  } else if (ssn->state == TCP_NONE) {
5790  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5791  return true;
5792  } else { // < TCP_LAST_ACK
5793  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5794  return false;
5795  }
5796 
5797  } else {
5798  if (ssn == NULL) {
5799  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5800  return true;
5801  }
5802  if (ssn->state >= TCP_LAST_ACK) {
5803  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5804  return true;
5805  } else if (ssn->state == TCP_NONE) {
5806  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5807  return true;
5808  } else { // < TCP_LAST_ACK
5809  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5810  return false;
5811  }
5812  }
5813 
5814  SCLogDebug("default: how did we get here?");
5815  return false;
5816 }
5817 
5818 /** \internal
5819  * \brief check if ssn is done enough for reuse by syn/ack
5820  * \note should only be called if midstream is enabled
5821  */
5822 static bool TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn)
5823 {
5824  const TCPHdr *tcph = PacketGetTCP(p);
5825  if (FlowGetPacketDirection(f, p) == TOCLIENT) {
5826  if (ssn == NULL) {
5827  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
5828  return false;
5829  }
5830  if (SEQ_EQ(ssn->server.isn, TCP_GET_RAW_SEQ(tcph))) {
5831  SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5832  return false;
5833  }
5834  if (ssn->state >= TCP_LAST_ACK) {
5835  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5836  return true;
5837  } else if (ssn->state == TCP_NONE) {
5838  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5839  return true;
5840  } else { // < TCP_LAST_ACK
5841  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5842  return false;
5843  }
5844 
5845  } else {
5846  if (ssn == NULL) {
5847  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5848  return true;
5849  }
5850  if (ssn->state >= TCP_LAST_ACK) {
5851  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5852  return true;
5853  } else if (ssn->state == TCP_NONE) {
5854  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5855  return true;
5856  } else { // < TCP_LAST_ACK
5857  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5858  return false;
5859  }
5860  }
5861 
5862  SCLogDebug("default: how did we get here?");
5863  return false;
5864 }
5865 
5866 /** \brief Check if SSN is done enough for reuse
5867  *
5868  * Reuse means a new TCP session reuses the tuple (flow in suri)
5869  *
5870  * \retval bool true if ssn can be reused, false if not */
5871 static bool TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn)
5872 {
5873  const TCPHdr *tcph = PacketGetTCP(p);
5874  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5875  return TcpSessionReuseDoneEnoughSyn(p, f, ssn);
5876  }
5877 
5879  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5880  return TcpSessionReuseDoneEnoughSynAck(p, f, ssn);
5881  }
5882  }
5883 
5884  return false;
5885 }
5886 
5887 bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
5888 {
5889  if (p->proto == IPPROTO_TCP && PacketIsTCP(p)) {
5890  if (TcpSessionPacketIsStreamStarter(p) == 1) {
5891  if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) {
5892  return true;
5893  }
5894  }
5895  }
5896  return false;
5897 }
5898 
5900 {
5901  DEBUG_VALIDATE_BUG_ON(p->flow == NULL);
5902  if (unlikely(p->flow == NULL)) {
5903  return TM_ECODE_OK;
5904  }
5905 
5906  StreamTcpThread *stt = (StreamTcpThread *)data;
5907 
5908  SCLogDebug("p->pcap_cnt %" PRIu64 " direction %s pkt_src %s", p->pcap_cnt,
5909  p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
5910  : "noflow",
5911  PktSrcToString(p->pkt_src));
5912  t_pcapcnt = p->pcap_cnt;
5913 
5914  if (!(PacketIsTCP(p))) {
5915  return TM_ECODE_OK;
5916  }
5917 
5918  HandleThreadId(tv, p, stt);
5919 
5920  /* only TCP packets with a flow from here */
5921 
5922  if (!(p->flags & PKT_PSEUDO_STREAM_END)) {
5924  if (StreamTcpValidateChecksum(p) == 0) {
5926  return TM_ECODE_OK;
5927  }
5928  } else {
5929  p->flags |= PKT_IGNORE_CHECKSUM;
5930  }
5931  } else {
5932  p->flags |= PKT_IGNORE_CHECKSUM; //TODO check that this is set at creation
5933  }
5935 
5936  (void)StreamTcpPacket(tv, p, stt, pq);
5937 
5938  return TM_ECODE_OK;
5939 }
5940 
5941 TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
5942 {
5943  SCEnter();
5944  StreamTcpThread *stt = SCCalloc(1, sizeof(StreamTcpThread));
5945  if (unlikely(stt == NULL))
5947  stt->ssn_pool_id = -1;
5949 
5950  *data = (void *)stt;
5951 
5952  stt->counter_tcp_active_sessions = StatsRegisterCounter("tcp.active_sessions", tv);
5953  stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv);
5954  stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv);
5955  stt->counter_tcp_ssn_from_cache = StatsRegisterCounter("tcp.ssn_from_cache", tv);
5956  stt->counter_tcp_ssn_from_pool = StatsRegisterCounter("tcp.ssn_from_pool", tv);
5958  stream_config.ssn_memcap_policy, "tcp.ssn_memcap_exception_policy.",
5959  IsStreamTcpSessionMemcapExceptionPolicyStatsValid);
5960 
5961  stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv);
5962  stt->counter_tcp_pseudo_failed = StatsRegisterCounter("tcp.pseudo_failed", tv);
5963  stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv);
5964  stt->counter_tcp_midstream_pickups = StatsRegisterCounter("tcp.midstream_pickups", tv);
5965  if (stream_config.midstream) {
5968  "tcp.midstream_exception_policy.", IsMidstreamExceptionPolicyStatsValid);
5969  } else {
5972  "tcp.midstream_exception_policy.", IsMidstreamExceptionPolicyStatsValid);
5973  }
5974 
5975  stt->counter_tcp_wrong_thread = StatsRegisterCounter("tcp.pkt_on_wrong_thread", tv);
5976  stt->counter_tcp_ack_unseen_data = StatsRegisterCounter("tcp.ack_unseen_data", tv);
5977 
5978  /* init reassembly ctx */
5980  if (stt->ra_ctx == NULL)
5982 
5983  stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv);
5984 
5987  "tcp.reassembly_exception_policy.", IsReassemblyMemcapExceptionPolicyStatsValid);
5988 
5990  StatsRegisterCounter("tcp.segment_from_cache", tv);
5991  stt->ra_ctx->counter_tcp_segment_from_pool = StatsRegisterCounter("tcp.segment_from_pool", tv);
5992  stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv);
5993  stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv);
5994  stt->ra_ctx->counter_tcp_reass_overlap = StatsRegisterCounter("tcp.overlap", tv);
5995  stt->ra_ctx->counter_tcp_reass_overlap_diff_data = StatsRegisterCounter("tcp.overlap_diff_data", tv);
5996 
5997  stt->ra_ctx->counter_tcp_reass_data_normal_fail = StatsRegisterCounter("tcp.insert_data_normal_fail", tv);
5998  stt->ra_ctx->counter_tcp_reass_data_overlap_fail = StatsRegisterCounter("tcp.insert_data_overlap_fail", tv);
5999 
6000  SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p",
6001  stt, stt->ra_ctx);
6002 
6003  SCMutexLock(&ssn_pool_mutex);
6004  if (ssn_pool == NULL) {
6005  ssn_pool = PoolThreadInit(1, /* thread */
6006  0, /* unlimited */
6008  sizeof(TcpSession),
6009  StreamTcpSessionPoolAlloc,
6010  StreamTcpSessionPoolInit, NULL,
6011  StreamTcpSessionPoolCleanup, NULL);
6012  stt->ssn_pool_id = 0;
6013  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6014  } else {
6015  /* grow ssn_pool until we have a element for our thread id */
6017  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6018  }
6019  SCMutexUnlock(&ssn_pool_mutex);
6020  if (stt->ssn_pool_id < 0 || ssn_pool == NULL) {
6021  SCLogError("failed to setup/expand stream session pool. Expand stream.memcap?");
6023  }
6024 
6026 }
6027 
6029 {
6030  SCEnter();
6031  StreamTcpThread *stt = (StreamTcpThread *)data;
6032  if (stt == NULL) {
6033  return TM_ECODE_OK;
6034  }
6035 
6036  /* XXX */
6037 
6038  /* free reassembly ctx */
6040 
6041  /* clear memory */
6042  memset(stt, 0, sizeof(StreamTcpThread));
6043 
6044  SCFree(stt);
6046 }
6047 
6048 /**
6049  * \brief Function to check the validity of the RST packets based on the
6050  * target OS of the given packet.
6051  *
6052  * \param ssn TCP session to which the given packet belongs
6053  * \param p Packet which has to be checked for its validity
6054  *
6055  * \retval 0 unacceptable RST
6056  * \retval 1 acceptable RST
6057  *
6058  * WebSense sends RST packets that are:
6059  * - RST flag, win 0, ack 0, seq = nextseq
6060  *
6061  */
6062 
6063 static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
6064 {
6065  uint8_t os_policy;
6066  const TCPHdr *tcph = PacketGetTCP(p);
6067  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6068 
6070  SCReturnInt(1);
6071  }
6072 
6073  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
6074  if (!StreamTcpValidateTimestamp(ssn, p)) {
6075  SCReturnInt(0);
6076  }
6077  }
6078 
6079  /* RST with data, it's complicated:
6080 
6081  4.2.2.12 RST Segment: RFC-793 Section 3.4
6082 
6083  A TCP SHOULD allow a received RST segment to include data.
6084 
6085  DISCUSSION
6086  It has been suggested that a RST segment could contain
6087  ASCII text that encoded and explained the cause of the
6088  RST. No standard has yet been established for such
6089  data.
6090  */
6091  if (p->payload_len)
6093 
6094  /* Set up the os_policy to be used in validating the RST packets based on
6095  target system */
6096  if (PKT_IS_TOSERVER(p)) {
6097  if (ssn->server.os_policy == 0)
6098  StreamTcpSetOSPolicy(&ssn->server, p);
6099 
6100  os_policy = ssn->server.os_policy;
6101 
6102  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6103  StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
6104  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6106  SCReturnInt(0);
6107  }
6108 
6109  } else {
6110  if (ssn->client.os_policy == 0)
6111  StreamTcpSetOSPolicy(&ssn->client, p);
6112 
6113  os_policy = ssn->client.os_policy;
6114 
6115  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6116  StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
6117  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6119  SCReturnInt(0);
6120  }
6121  }
6122 
6123  /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
6124  * validate these (requires key that is set/transferred out of band), we can't know
6125  * if the RST will be accepted or rejected by the end host. We accept it, but keep
6126  * tracking if the sender of it ignores it, which would be a sign of injection. */
6128  TcpStream *receiver_stream;
6129  if (PKT_IS_TOSERVER(p)) {
6130  receiver_stream = &ssn->server;
6131  } else {
6132  receiver_stream = &ssn->client;
6133  }
6134  SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
6135  receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
6136  }
6137 
6138  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
6139  if (PKT_IS_TOSERVER(p)) {
6140  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6141  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6142  return 1;
6143  }
6144  } else {
6145  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6146  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6147  return 1;
6148  }
6149  }
6150  SCLogDebug("ssn %p: ASYNC reject RST", ssn);
6151  return 0;
6152  }
6153 
6154  switch (os_policy) {
6155  case OS_POLICY_HPUX11:
6156  if(PKT_IS_TOSERVER(p)){
6157  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6158  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6159  return 1;
6160  } else {
6161  SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " "
6162  "and server SEQ: %" PRIu32 "",
6163  seq, ssn->client.next_seq);
6164  return 0;
6165  }
6166  } else { /* implied to client */
6167  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6168  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6169  return 1;
6170  } else {
6171  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6172  "and client SEQ: %" PRIu32 "",
6173  seq, ssn->server.next_seq);
6174  return 0;
6175  }
6176  }
6177  break;
6178  case OS_POLICY_OLD_LINUX:
6179  case OS_POLICY_LINUX:
6180  case OS_POLICY_SOLARIS:
6181  if(PKT_IS_TOSERVER(p)){
6182  if (SEQ_GEQ((seq + p->payload_len),
6183  ssn->client.last_ack)) { /*window base is needed !!*/
6184  if (SEQ_LT(seq, (ssn->client.next_seq + ssn->client.window))) {
6185  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6186  return 1;
6187  }
6188  } else {
6189  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6190  " server SEQ: %" PRIu32 "",
6191  seq, ssn->client.next_seq);
6192  return 0;
6193  }
6194  } else { /* implied to client */
6195  if (SEQ_GEQ((seq + p->payload_len),
6196  ssn->server.last_ack)) { /*window base is needed !!*/
6197  if (SEQ_LT(seq, (ssn->server.next_seq + ssn->server.window))) {
6198  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6199  return 1;
6200  }
6201  } else {
6202  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6203  " client SEQ: %" PRIu32 "",
6204  seq, ssn->server.next_seq);
6205  return 0;
6206  }
6207  }
6208  break;
6209  default:
6210  case OS_POLICY_BSD:
6211  case OS_POLICY_FIRST:
6212  case OS_POLICY_HPUX10:
6213  case OS_POLICY_IRIX:
6214  case OS_POLICY_MACOS:
6215  case OS_POLICY_LAST:
6216  case OS_POLICY_WINDOWS:
6217  case OS_POLICY_WINDOWS2K3:
6218  case OS_POLICY_VISTA:
6219  if(PKT_IS_TOSERVER(p)) {
6220  if (SEQ_EQ(seq, ssn->client.next_seq)) {
6221  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6222  return 1;
6223  } else {
6224  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6225  "and server SEQ: %" PRIu32 "",
6226  seq, ssn->client.next_seq);
6227  return 0;
6228  }
6229  } else { /* implied to client */
6230  if (SEQ_EQ(seq, ssn->server.next_seq)) {
6231  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u", seq,
6232  ssn->server.next_seq);
6233  return 1;
6234  } else {
6235  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6236  " client SEQ: %" PRIu32 "",
6237  seq, ssn->server.next_seq);
6238  return 0;
6239  }
6240  }
6241  break;
6242  }
6243  return 0;
6244 }
6245 
6246 /**
6247  * \brief Function to check the validity of the received timestamp based on
6248  * the target OS of the given stream.
6249  *
6250  * It's passive except for:
6251  * 1. it sets the os policy on the stream if necessary
6252  * 2. it sets an event in the packet if necessary
6253  *
6254  * \param ssn TCP session to which the given packet belongs
6255  * \param p Packet which has to be checked for its validity
6256  *
6257  * \retval 1 if the timestamp is valid
6258  * \retval 0 if the timestamp is invalid
6259  */
6260 static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p)
6261 {
6262  SCEnter();
6263 
6264  TcpStream *sender_stream;
6265  TcpStream *receiver_stream;
6266  uint8_t ret = 1;
6267  uint8_t check_ts = 1;
6268  const TCPHdr *tcph = PacketGetTCP(p);
6269  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6270 
6271  if (PKT_IS_TOSERVER(p)) {
6272  sender_stream = &ssn->client;
6273  receiver_stream = &ssn->server;
6274  } else {
6275  sender_stream = &ssn->server;
6276  receiver_stream = &ssn->client;
6277  }
6278 
6279  /* Set up the os_policy to be used in validating the timestamps based on
6280  the target system */
6281  if (receiver_stream->os_policy == 0) {
6282  StreamTcpSetOSPolicy(receiver_stream, p);
6283  }
6284 
6285  if (TCP_HAS_TS(p)) {
6286  uint32_t ts = TCP_GET_TSVAL(p);
6287  uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
6288  uint32_t last_ts = sender_stream->last_ts;
6289 
6290  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6291  /* The 3whs used the timestamp with 0 value. */
6292  switch (receiver_stream->os_policy) {
6293  case OS_POLICY_LINUX:
6294  case OS_POLICY_WINDOWS2K3:
6295  /* Linux and windows 2003 does not allow the use of 0 as
6296  * timestamp in the 3whs. */
6297  check_ts = 0;
6298  break;
6299 
6300  case OS_POLICY_OLD_LINUX:
6301  case OS_POLICY_WINDOWS:
6302  case OS_POLICY_VISTA:
6303  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6304  last_ts = ts;
6305  check_ts = 0; /*next packet will be checked for validity
6306  and stream TS has been updated with this
6307  one.*/
6308  }
6309  break;
6310  }
6311  }
6312 
6313  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6314  /* HPUX11 ignores the timestamp of out of order packets */
6315  if (!SEQ_EQ(sender_stream->next_seq, seq))
6316  check_ts = 0;
6317  }
6318 
6319  if (ts == 0) {
6320  switch (receiver_stream->os_policy) {
6321  case OS_POLICY_OLD_LINUX:
6322  case OS_POLICY_WINDOWS:
6323  case OS_POLICY_WINDOWS2K3:
6324  case OS_POLICY_VISTA:
6325  case OS_POLICY_SOLARIS:
6326  /* Old Linux and windows allowed packet with 0 timestamp. */
6327  break;
6328  default:
6329  /* other OS simply drop the packet with 0 timestamp, when
6330  * 3whs has valid timestamp*/
6331  goto invalid;
6332  }
6333  }
6334 
6335  if (check_ts) {
6336  int32_t result = 0;
6337 
6338  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts);
6339 
6340  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6341  /* Linux accepts TS which are off by one.*/
6342  result = (int32_t) ((ts - last_ts) + 1);
6343  } else {
6344  result = (int32_t) (ts - last_ts);
6345  }
6346 
6347  SCLogDebug("result %" PRIi32 ", p->ts(secs) %" PRIuMAX "", result,
6348  (uintmax_t)SCTIME_SECS(p->ts));
6349 
6350  if (last_pkt_ts == 0 &&
6352  {
6353  last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6354  }
6355 
6356  if (result < 0) {
6357  SCLogDebug("timestamp is not valid last_ts "
6358  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6359  "%" PRId32 "", last_ts, ts, result);
6360  /* candidate for rejection */
6361  ret = 0;
6362  } else if ((sender_stream->last_ts != 0) &&
6363  (((uint32_t)SCTIME_SECS(p->ts)) > last_pkt_ts + PAWS_24DAYS)) {
6364  SCLogDebug("packet is not valid last_pkt_ts "
6365  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6366  last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6367  /* candidate for rejection */
6368  ret = 0;
6369  }
6370 
6371  if (ret == 0) {
6372  /* if the timestamp of packet is not valid then, check if the
6373  * current stream timestamp is not so old. if so then we need to
6374  * accept the packet and update the stream->last_ts (RFC 1323)*/
6375  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6376  (((uint32_t)SCTIME_SECS(p->ts) > (last_pkt_ts + PAWS_24DAYS)))) {
6377  SCLogDebug("timestamp considered valid anyway");
6378  } else {
6379  goto invalid;
6380  }
6381  }
6382  }
6383  }
6384 
6385  SCReturnInt(1);
6386 
6387 invalid:
6389  SCReturnInt(0);
6390 }
6391 
6392 /**
6393  * \brief Function to check the validity of the received timestamp based on
6394  * the target OS of the given stream and update the session.
6395  *
6396  * \param ssn TCP session to which the given packet belongs
6397  * \param p Packet which has to be checked for its validity
6398  *
6399  * \retval 1 if the timestamp is valid
6400  * \retval 0 if the timestamp is invalid
6401  */
6402 static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p)
6403 {
6404  SCEnter();
6405 
6406  TcpStream *sender_stream;
6407  TcpStream *receiver_stream;
6408  uint8_t ret = 1;
6409  uint8_t check_ts = 1;
6410  const TCPHdr *tcph = PacketGetTCP(p);
6411  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6412 
6413  if (PKT_IS_TOSERVER(p)) {
6414  sender_stream = &ssn->client;
6415  receiver_stream = &ssn->server;
6416  } else {
6417  sender_stream = &ssn->server;
6418  receiver_stream = &ssn->client;
6419  }
6420 
6421  /* Set up the os_policy to be used in validating the timestamps based on
6422  the target system */
6423  if (receiver_stream->os_policy == 0) {
6424  StreamTcpSetOSPolicy(receiver_stream, p);
6425  }
6426 
6427  if (TCP_HAS_TS(p)) {
6428  uint32_t ts = TCP_GET_TSVAL(p);
6429 
6430  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6431  /* The 3whs used the timestamp with 0 value. */
6432  switch (receiver_stream->os_policy) {
6433  case OS_POLICY_LINUX:
6434  case OS_POLICY_WINDOWS2K3:
6435  /* Linux and windows 2003 does not allow the use of 0 as
6436  * timestamp in the 3whs. */
6438  check_ts = 0;
6439  break;
6440 
6441  case OS_POLICY_OLD_LINUX:
6442  case OS_POLICY_WINDOWS:
6443  case OS_POLICY_VISTA:
6444  sender_stream->flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
6445  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6446  sender_stream->last_ts = ts;
6447  check_ts = 0; /*next packet will be checked for validity
6448  and stream TS has been updated with this
6449  one.*/
6450  }
6451  break;
6452  default:
6453  break;
6454  }
6455  }
6456 
6457  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6458  /*HPUX11 ignores the timestamp of out of order packets*/
6459  if (!SEQ_EQ(sender_stream->next_seq, seq))
6460  check_ts = 0;
6461  }
6462 
6463  if (ts == 0) {
6464  switch (receiver_stream->os_policy) {
6465  case OS_POLICY_OLD_LINUX:
6466  case OS_POLICY_WINDOWS:
6467  case OS_POLICY_WINDOWS2K3:
6468  case OS_POLICY_VISTA:
6469  case OS_POLICY_SOLARIS:
6470  /* Old Linux and windows allowed packet with 0 timestamp. */
6471  break;
6472  default:
6473  /* other OS simply drop the packet with 0 timestamp, when
6474  * 3whs has valid timestamp*/
6475  goto invalid;
6476  }
6477  }
6478 
6479  if (check_ts) {
6480  int32_t result = 0;
6481 
6482  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts);
6483 
6484  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6485  /* Linux accepts TS which are off by one.*/
6486  result = (int32_t) ((ts - sender_stream->last_ts) + 1);
6487  } else {
6488  result = (int32_t) (ts - sender_stream->last_ts);
6489  }
6490 
6491  SCLogDebug("result %" PRIi32 ", p->ts(sec) %" PRIuMAX "", result,
6492  (uintmax_t)SCTIME_SECS(p->ts));
6493 
6494  if (sender_stream->last_pkt_ts == 0 &&
6496  {
6497  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6498  }
6499 
6500  if (result < 0) {
6501  SCLogDebug("timestamp is not valid sender_stream->last_ts "
6502  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6503  "%" PRId32 "", sender_stream->last_ts, ts, result);
6504  /* candidate for rejection */
6505  ret = 0;
6506  } else if ((sender_stream->last_ts != 0) &&
6507  (((uint32_t)SCTIME_SECS(p->ts)) >
6508  sender_stream->last_pkt_ts + PAWS_24DAYS)) {
6509  SCLogDebug("packet is not valid sender_stream->last_pkt_ts "
6510  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6511  sender_stream->last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6512  /* candidate for rejection */
6513  ret = 0;
6514  }
6515 
6516  if (ret == 1) {
6517  /* Update the timestamp and last seen packet time for this
6518  * stream */
6519  if (SEQ_EQ(sender_stream->next_seq, seq))
6520  sender_stream->last_ts = ts;
6521 
6522  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6523 
6524  } else if (ret == 0) {
6525  /* if the timestamp of packet is not valid then, check if the
6526  * current stream timestamp is not so old. if so then we need to
6527  * accept the packet and update the stream->last_ts (RFC 1323)*/
6528  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6529  (((uint32_t)SCTIME_SECS(p->ts) >
6530  (sender_stream->last_pkt_ts + PAWS_24DAYS)))) {
6531  sender_stream->last_ts = ts;
6532  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6533 
6534  SCLogDebug("timestamp considered valid anyway");
6535  } else {
6536  goto invalid;
6537  }
6538  }
6539  }
6540  } else {
6541  /* Solaris stops using timestamps if a packet is received
6542  without a timestamp and timestamps were used on that stream. */
6543  if (receiver_stream->os_policy == OS_POLICY_SOLARIS)
6545  }
6546 
6547  SCReturnInt(1);
6548 
6549 invalid:
6551  SCReturnInt(0);
6552 }
6553 
6554 /**
6555  * \brief Function to test the received ACK values against the stream window
6556  * and previous ack value. ACK values should be higher than previous
6557  * ACK value and less than the next_win value.
6558  *
6559  * \param ssn TcpSession for state access
6560  * \param stream TcpStream of which last_ack needs to be tested
6561  * \param p Packet which is used to test the last_ack
6562  *
6563  * \retval 0 ACK is valid, last_ack is updated if ACK was higher
6564  * \retval -1 ACK is invalid
6565  */
6566 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p)
6567 {
6568  SCEnter();
6569 
6570  const TCPHdr *tcph = PacketGetTCP(p);
6571  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
6572 
6573  if (!(tcph->th_flags & TH_ACK))
6574  SCReturnInt(0);
6575 
6576  /* fast track */
6577  if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win))
6578  {
6579  SCLogDebug("ssn %p: ACK %u in bounds > %u <= %u", ssn, ack, stream->last_ack,
6580  stream->next_win);
6581  SCReturnInt(0);
6582  }
6583  /* fast track */
6584  else if (SEQ_EQ(ack, stream->last_ack)) {
6585  SCLogDebug("ssn %p: pkt ACK %" PRIu32 " == stream last ACK %" PRIu32, ssn, ack,
6586  stream->last_ack);
6587  SCReturnInt(0);
6588  }
6589 
6590  /* exception handling */
6591  if (SEQ_LT(ack, stream->last_ack)) {
6592  SCLogDebug("pkt ACK %" PRIu32 " < stream last ACK %" PRIu32, ack, stream->last_ack);
6593 
6594  /* This is an attempt to get a 'left edge' value that we can check against.
6595  * It doesn't work when the window is 0, need to think of a better way. */
6596 
6597  if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) {
6598  SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window "
6599  "%"PRIu32" = %"PRIu32, ack, stream->last_ack,
6600  stream->window, stream->last_ack - stream->window);
6601  goto invalid;
6602  }
6603 
6604  SCReturnInt(0);
6605  }
6606 
6607  /* no further checks possible for ASYNC */
6608  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
6609  SCReturnInt(0);
6610  }
6611 
6612  if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) {
6613  SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win);
6614  goto invalid;
6615  /* a toclient RST as a response to SYN, next_win is 0, ack will be isn+1, just like
6616  * the syn ack */
6617  } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && tcph->th_flags & TH_RST &&
6618  SEQ_EQ(ack, stream->isn + 1)) {
6619  SCReturnInt(0);
6620  }
6621 
6622  SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32
6623  " next_win %"PRIu32, ack, stream->last_ack, stream->next_win);
6624 invalid:
6626  SCReturnInt(-1);
6627 }
6628 
6629 /** \brief update reassembly progress
6630 
6631  * \param ssn TCP Session
6632  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6633  */
6635  const uint32_t progress)
6636 {
6637  if (direction) {
6638  ssn->server.app_progress_rel += progress;
6639  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->server));
6640  } else {
6641  ssn->client.app_progress_rel += progress;
6642  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->client));
6643  }
6644 }
6645 
6646 /** \brief disable reassembly
6647 
6648  * Disable app layer and set raw inspect to no longer accept new data.
6649  * Stream engine will then fully disable raw after last inspection.
6650  *
6651  * \param ssn TCP Session to set the flag in
6652  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6653  */
6655 {
6657  if (direction) {
6659  } else {
6661  }
6662 }
6663 
6664 /** \brief Set the No reassembly flag for the given direction in given TCP
6665  * session.
6666  *
6667  * \param ssn TCP Session to set the flag in
6668  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6669  */
6671 {
6672  direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) :
6674 }
6675 
6676 /** \brief enable bypass
6677  *
6678  * \param ssn TCP Session to set the flag in
6679  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6680  */
6682 {
6683  ssn->flags |= STREAMTCP_FLAG_BYPASS;
6684 }
6685 
6686 /** \brief Create a pseudo packet injected into the engine to signal the
6687  * opposing direction of this stream trigger detection/logging.
6688  *
6689  * \param parent real packet
6690  * \param pq packet queue to store the new pseudo packet in
6691  * \param dir 0 ts 1 tc
6692  */
6693 static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv,
6694  StreamTcpThread *stt, Packet *parent,
6695  TcpSession *ssn, PacketQueueNoLock *pq, int dir)
6696 {
6697  SCEnter();
6698  Flow *f = parent->flow;
6699  TCPHdr *tcph = NULL;
6700 
6701  if (parent->flags & PKT_PSEUDO_DETECTLOG_FLUSH) {
6702  SCReturn;
6703  }
6704  if ((f->flags & (FLOW_IPV4 | FLOW_IPV6)) == 0) {
6705  SCReturn;
6706  }
6707 
6708  Packet *np = PacketPoolGetPacket();
6709  if (np == NULL) {
6710  SCReturn;
6711  }
6713 
6714  np->tenant_id = f->tenant_id;
6715  np->datalink = DLT_RAW;
6716  np->proto = IPPROTO_TCP;
6717  FlowReference(&np->flow, f);
6718  np->flags |= PKT_STREAM_EST;
6719  np->flags |= PKT_HAS_FLOW;
6720  np->flags |= PKT_IGNORE_CHECKSUM;
6722  memcpy(&np->vlan_id[0], &f->vlan_id[0], sizeof(np->vlan_id));
6723  np->vlan_idx = f->vlan_idx;
6724  np->livedev = (struct LiveDevice_ *)f->livedev;
6725 
6726  if (parent->flags & PKT_NOPACKET_INSPECTION) {
6727  DecodeSetNoPacketInspectionFlag(np);
6728  }
6729  if (parent->flags & PKT_NOPAYLOAD_INSPECTION) {
6730  DecodeSetNoPayloadInspectionFlag(np);
6731  }
6732 
6733  if (dir == 0) {
6734  SCLogDebug("pseudo is to_server");
6736  } else {
6737  SCLogDebug("pseudo is to_client");
6739  }
6741  np->payload = NULL;
6742  np->payload_len = 0;
6743 
6744  if (FLOW_IS_IPV4(f)) {
6745  if (dir == 0) {
6748  np->sp = f->sp;
6749  np->dp = f->dp;
6750  } else {
6753  np->sp = f->dp;
6754  np->dp = f->sp;
6755  }
6756 
6757  /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
6758  * Force an allocation if it is not the case.
6759  */
6760  if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) {
6761  if (PacketCallocExtPkt(np, 40) == -1) {
6762  goto error;
6763  }
6764  }
6765  /* set the ip header */
6766  IPV4Hdr *ip4h = PacketSetIPV4(np, GET_PKT_DATA(np));
6767  /* version 4 and length 20 bytes for the tcp header */
6768  ip4h->ip_verhl = 0x45;
6769  ip4h->ip_tos = 0;
6770  ip4h->ip_len = htons(40);
6771  ip4h->ip_id = 0;
6772  ip4h->ip_off = 0;
6773  ip4h->ip_ttl = 64;
6774  ip4h->ip_proto = IPPROTO_TCP;
6775  if (dir == 0) {
6776  ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
6777  ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
6778  } else {
6779  ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
6780  ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
6781  }
6782 
6783  /* set the tcp header */
6784  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 20);
6785 
6786  SET_PKT_LEN(np, 40); /* ipv4 hdr + tcp hdr */
6787  } else {
6788  /* implied IPv6 */
6789 
6790  if (dir == 0) {
6793  np->sp = f->sp;
6794  np->dp = f->dp;
6795  } else {
6798  np->sp = f->dp;
6799  np->dp = f->sp;
6800  }
6801 
6802  /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
6803  * Force an allocation if it is not the case.
6804  */
6805  if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) {
6806  if (PacketCallocExtPkt(np, 60) == -1) {
6807  goto error;
6808  }
6809  }
6810  /* set the ip header */
6811  IPV6Hdr *ip6h = PacketSetIPV6(np, GET_PKT_DATA(np));
6812  /* version 6 */
6813  ip6h->s_ip6_vfc = 0x60;
6814  ip6h->s_ip6_flow = 0;
6815  ip6h->s_ip6_nxt = IPPROTO_TCP;
6816  ip6h->s_ip6_plen = htons(20);
6817  ip6h->s_ip6_hlim = 64;
6818  if (dir == 0) {
6819  ip6h->s_ip6_src[0] = f->src.addr_data32[0];
6820  ip6h->s_ip6_src[1] = f->src.addr_data32[1];
6821  ip6h->s_ip6_src[2] = f->src.addr_data32[2];
6822  ip6h->s_ip6_src[3] = f->src.addr_data32[3];
6823  ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
6824  ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
6825  ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
6826  ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
6827  } else {
6828  ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
6829  ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
6830  ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
6831  ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
6832  ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
6833  ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
6834  ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
6835  ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
6836  }
6837 
6838  /* set the tcp header */
6839  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 40);
6840 
6841  SET_PKT_LEN(np, 60); /* ipv6 hdr + tcp hdr */
6842  }
6843 
6844  tcph->th_offx2 = 0x50;
6845  tcph->th_flags |= TH_ACK;
6846  tcph->th_win = 10;
6847  tcph->th_urp = 0;
6848 
6849  /* to server */
6850  if (dir == 0) {
6851  tcph->th_sport = htons(f->sp);
6852  tcph->th_dport = htons(f->dp);
6853 
6854  tcph->th_seq = htonl(ssn->client.next_seq);
6855  tcph->th_ack = htonl(ssn->server.last_ack);
6856 
6857  /* to client */
6858  } else {
6859  tcph->th_sport = htons(f->dp);
6860  tcph->th_dport = htons(f->sp);
6861 
6862  tcph->th_seq = htonl(ssn->server.next_seq);
6863  tcph->th_ack = htonl(ssn->client.last_ack);
6864  }
6865 
6866  /* use parent time stamp */
6867  np->ts = parent->ts;
6868 
6869  SCLogDebug("np %p", np);
6870  PacketEnqueueNoLock(pq, np);
6871 
6873  SCReturn;
6874 error:
6875  FlowDeReference(&np->flow);
6876  SCReturn;
6877 }
6878 
6879 /** \brief create packets in both directions to flush out logging
6880  * and detection before switching protocols.
6881  * In IDS mode, create first in packet dir, 2nd in opposing
6882  * In IPS mode, do the reverse.
6883  * Flag TCP engine that data needs to be inspected regardless
6884  * of how far we are wrt inspect limits.
6885  */
6887  PacketQueueNoLock *pq)
6888 {
6889  TcpSession *ssn = f->protoctx;
6892  bool ts = PKT_IS_TOSERVER(p) ? true : false;
6893  ts ^= StreamTcpInlineMode();
6894  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^0);
6895  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^1);
6896 }
6897 
6898 /**
6899  * \brief Run callback function on each TCP segment in a single direction.
6900  *
6901  * \note when stream engine is running in inline mode all segments are used,
6902  * in IDS/non-inline mode only ack'd segments are iterated.
6903  *
6904  * \note Must be called under flow lock.
6905  * \var flag determines the direction to run callback on (either to server or to client).
6906  *
6907  * \return -1 in case of error, the number of segment in case of success
6908  *
6909  */
6910 int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
6911 {
6912  TcpStream *stream = NULL;
6913  int cnt = 0;
6914 
6915  if (p->flow == NULL)
6916  return 0;
6917 
6918  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
6919  if (ssn == NULL) {
6920  return 0;
6921  }
6922 
6923  if (flag & STREAM_DUMP_TOSERVER) {
6924  stream = &(ssn->server);
6925  } else {
6926  stream = &(ssn->client);
6927  }
6928 
6929  /* for IDS, return ack'd segments. For IPS all. */
6930  TcpSegment *seg;
6931  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
6933  if (PKT_IS_PSEUDOPKT(p)) {
6934  /* use un-ACK'd data as well */
6935  } else {
6936  /* in IDS mode, use ACK'd data */
6937  if (SEQ_GEQ(seg->seq, stream->last_ack)) {
6938  break;
6939  }
6940  }
6941  }
6942 
6943  const uint8_t *seg_data;
6944  uint32_t seg_datalen;
6945  StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
6946 
6947  int ret = CallbackFunc(p, seg, data, seg_data, seg_datalen);
6948  if (ret != 1) {
6949  SCLogDebug("Callback function has failed");
6950  return -1;
6951  }
6952 
6953  cnt++;
6954  }
6955  return cnt;
6956 }
6957 
6958 /**
6959  * \brief Run callback function on each TCP segment in both directions of a session.
6960  *
6961  * \note when stream engine is running in inline mode all segments are used,
6962  * in IDS/non-inline mode only ack'd segments are iterated.
6963  *
6964  * \note Must be called under flow lock.
6965  *
6966  * \return -1 in case of error, the number of segment in case of success
6967  *
6968  */
6970  const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
6971 {
6972  int ret = 0;
6973  int cnt = 0;
6974 
6975  if (p->flow == NULL)
6976  return 0;
6977 
6978  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
6979 
6980  if (ssn == NULL) {
6981  return -1;
6982  }
6983 
6984  TcpStream *server_stream = &(ssn->server);
6985  TcpStream *client_stream = &(ssn->client);
6986 
6987  TcpSegment *server_node = RB_MIN(TCPSEG, &server_stream->seg_tree);
6988  TcpSegment *client_node = RB_MIN(TCPSEG, &client_stream->seg_tree);
6989  if (server_node == NULL && client_node == NULL) {
6990  return cnt;
6991  }
6992 
6993  while (server_node != NULL || client_node != NULL) {
6994  const uint8_t *seg_data;
6995  uint32_t seg_datalen;
6996  if (server_node == NULL) {
6997  /*
6998  * This means the server side RB Tree has been completely searched,
6999  * thus all that remains is to dump the TcpSegments on the client
7000  * side.
7001  */
7003  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7004  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7005  if (ret != 1) {
7006  SCLogDebug("Callback function has failed");
7007  return -1;
7008  }
7009  client_node = TCPSEG_RB_NEXT(client_node);
7010  } else if (client_node == NULL) {
7011  /*
7012  * This means the client side RB Tree has been completely searched,
7013  * thus all that remains is to dump the TcpSegments on the server
7014  * side.
7015  */
7017  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7018  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7019  if (ret != 1) {
7020  SCLogDebug("Callback function has failed");
7021  return -1;
7022  }
7023  server_node = TCPSEG_RB_NEXT(server_node);
7024  } else {
7025  if (SCTIME_CMP_LT(
7026  client_node->pcap_hdr_storage->ts, server_node->pcap_hdr_storage->ts)) {
7028  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7029  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7030  if (ret != 1) {
7031  SCLogDebug("Callback function has failed");
7032  return -1;
7033  }
7034  client_node = TCPSEG_RB_NEXT(client_node);
7035  } else {
7037  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7038  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7039  if (ret != 1) {
7040  SCLogDebug("Callback function has failed");
7041  return -1;
7042  }
7043  server_node = TCPSEG_RB_NEXT(server_node);
7044  }
7045  }
7046 
7047  cnt++;
7048  }
7049  return cnt;
7050 }
7051 
7053 {
7055 }
7056 
7057 /**
7058  * \brief See if stream engine is operating in inline mode
7059  *
7060  * \retval 0 no
7061  * \retval 1 yes
7062  */
7064 {
7066 }
7067 
7068 
7069 void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
7070 {
7071  if (size > ssn->reassembly_depth || size == 0) {
7072  ssn->reassembly_depth = size;
7073  }
7074 }
7075 
7076 const char *StreamTcpStateAsString(const enum TcpState state)
7077 {
7078  const char *tcp_state = NULL;
7079  switch (state) {
7080  case TCP_NONE:
7081  tcp_state = "none";
7082  break;
7083  case TCP_SYN_SENT:
7084  tcp_state = "syn_sent";
7085  break;
7086  case TCP_SYN_RECV:
7087  tcp_state = "syn_recv";
7088  break;
7089  case TCP_ESTABLISHED:
7090  tcp_state = "established";
7091  break;
7092  case TCP_FIN_WAIT1:
7093  tcp_state = "fin_wait1";
7094  break;
7095  case TCP_FIN_WAIT2:
7096  tcp_state = "fin_wait2";
7097  break;
7098  case TCP_TIME_WAIT:
7099  tcp_state = "time_wait";
7100  break;
7101  case TCP_LAST_ACK:
7102  tcp_state = "last_ack";
7103  break;
7104  case TCP_CLOSE_WAIT:
7105  tcp_state = "close_wait";
7106  break;
7107  case TCP_CLOSING:
7108  tcp_state = "closing";
7109  break;
7110  case TCP_CLOSED:
7111  tcp_state = "closed";
7112  break;
7113  }
7114  return tcp_state;
7115 }
7116 
7117 const char *StreamTcpSsnStateAsString(const TcpSession *ssn)
7118 {
7119  if (ssn == NULL)
7120  return NULL;
7121  return StreamTcpStateAsString(ssn->state);
7122 }
7123 
7124 #ifdef UNITTESTS
7125 #include "tests/stream-tcp.c"
7126 #endif
PKT_IS_TOCLIENT
#define PKT_IS_TOCLIENT(p)
Definition: decode.h:235
PacketL4::csum_set
bool csum_set
Definition: decode.h:438
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:49
STREAM_TIMEWAIT_ACK_WRONG_SEQ
@ STREAM_TIMEWAIT_ACK_WRONG_SEQ
Definition: decode-events.h:276
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:43
StreamTcpIncrMemuse
void StreamTcpIncrMemuse(uint64_t size)
Definition: stream-tcp.c:228
STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK
@ STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK
Definition: decode-events.h:231
STREAMTCP_QUEUE_FLAG_WS
#define STREAMTCP_QUEUE_FLAG_WS
Definition: stream-tcp-private.h:31
TcpStateQueue_::next
struct TcpStateQueue_ * next
Definition: stream-tcp-private.h:43
host.h
StreamSegmentCallback
int(* StreamSegmentCallback)(const Packet *, TcpSegment *, void *, const uint8_t *, uint32_t)
Definition: stream.h:36
tm-threads.h
TCP_SYN_RECV
@ TCP_SYN_RECV
Definition: stream-tcp-private.h:154
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:399
OS_POLICY_VISTA
@ OS_POLICY_VISTA
Definition: stream-tcp-reassemble.h:48
TCPVars_::ao_option_present
uint8_t ao_option_present
Definition: decode-tcp.h:165
Packet_::proto
uint8_t proto
Definition: decode.h:495
STREAM_CLOSING_INVALID_ACK
@ STREAM_CLOSING_INVALID_ACK
Definition: decode-events.h:251
TcpStream_
Definition: stream-tcp-private.h:106
ts
uint64_t ts
Definition: source-erf-file.c:55
ExceptionPolicyApply
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
Definition: util-exception-policy.c:69
STREAM_3WHS_SYNACK_WITH_WRONG_ACK
@ STREAM_3WHS_SYNACK_WITH_WRONG_ACK
Definition: decode-events.h:234
TCPHdr_::th_dport
uint16_t th_dport
Definition: decode-tcp.h:151
TcpSession_::pstate
uint8_t pstate
Definition: stream-tcp-private.h:286
STREAMTCP_FLAG_CLIENT_SACKOK
#define STREAMTCP_FLAG_CLIENT_SACKOK
Definition: stream-tcp-private.h:190
STREAM_EST_SYNACK_TOSERVER
@ STREAM_EST_SYNACK_TOSERVER
Definition: decode-events.h:257
StreamTcpSessionPktFree
void StreamTcpSessionPktFree(Packet *p)
Function to return the stream segments back to the pool.
Definition: stream-tcp.c:380
TcpStream_::isn
uint32_t isn
Definition: stream-tcp-private.h:113
EXCEPTION_POLICY_PASS_FLOW
@ EXCEPTION_POLICY_PASS_FLOW
Definition: util-exception-policy-types.h:29
TcpReassemblyThreadCtx_::counter_tcp_reas_eps
ExceptionPolicyCounters counter_tcp_reas_eps
Definition: stream-tcp-reassemble.h:69
STREAM_RST_INVALID_ACK
@ STREAM_RST_INVALID_ACK
Definition: decode-events.h:282
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:1264
TCP_HAS_TFO
#define TCP_HAS_TFO(p)
Definition: decode-tcp.h:97
stream-tcp-inline.h
IPV4Hdr_::ip_ttl
uint8_t ip_ttl
Definition: decode-ipv4.h:78
STREAM_EST_PKT_BEFORE_LAST_ACK
@ STREAM_EST_PKT_BEFORE_LAST_ACK
Definition: decode-events.h:253
STREAM_DUMP_TOSERVER
#define STREAM_DUMP_TOSERVER
Definition: stream.h:33
StreamTcpUpdateNextSeq
#define StreamTcpUpdateNextSeq(ssn, stream, seq)
Definition: stream-tcp.c: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:288
FLOW_STATE_ESTABLISHED
@ FLOW_STATE_ESTABLISHED
Definition: flow.h:507
TCP_SYN_SENT
@ TCP_SYN_SENT
Definition: stream-tcp-private.h:153
flow-util.h
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
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:1317
TcpSessionPacketSsnReuse
bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
Definition: stream-tcp.c:5887
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:7063
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:369
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:1269
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:439
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:592
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:190
STREAM_4WHS_WRONG_SEQ
@ STREAM_4WHS_WRONG_SEQ
Definition: decode-events.h:244
util-pool-thread.h
seq
uint32_t seq
Definition: stream-tcp-private.h:2
StatsRegisterGlobalCounter
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
Definition: counters.c:1009
StreamTcpThread_
Definition: stream-tcp.h:80
StreamTcpSetSessionNoReassemblyFlag
void StreamTcpSetSessionNoReassemblyFlag(TcpSession *ssn, char direction)
disable reassembly
Definition: stream-tcp.c:6654
StreamTcpThreadCacheReturnSession
void StreamTcpThreadCacheReturnSession(TcpSession *ssn)
Definition: stream-tcp-cache.c:93
StreamTcpSackFreeList
void StreamTcpSackFreeList(TcpStream *stream)
Free SACK tree from a stream.
Definition: stream-tcp-sack.c:438
STREAM_TIMEWAIT_INVALID_ACK
@ STREAM_TIMEWAIT_INVALID_ACK
Definition: decode-events.h:277
TCP_FIN_WAIT2
@ TCP_FIN_WAIT2
Definition: stream-tcp-private.h:157
OS_POLICY_SOLARIS
@ OS_POLICY_SOLARIS
Definition: stream-tcp-reassemble.h:42
StreamTcpGetFlowState
int StreamTcpGetFlowState(void *)
STREAM_PKT_FLAG_DUP_ACK
#define STREAM_PKT_FLAG_DUP_ACK
Definition: stream-tcp-private.h:317
Packet_::payload
uint8_t * payload
Definition: decode.h:571
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:510
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:501
Flow_
Flow data structure.
Definition: flow.h:356
TcpSegment::sbseg
StreamingBufferSegment sbseg
Definition: stream-tcp-private.h:77
STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV
@ STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV
Definition: decode-events.h:237
TcpStreamCnf_::flags
uint8_t flags
Definition: stream-tcp.h: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
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:40
LiveDevice_
Definition: util-device.h:50
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
ExceptionPolicyStatsSetts_
Definition: util-exception-policy-types.h:48
StreamTcpThread_::counter_tcp_sessions
uint16_t counter_tcp_sessions
Definition: stream-tcp.h:84
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
STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK
@ STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK
Definition: decode-events.h:248
OS_POLICY_MACOS
@ OS_POLICY_MACOS
Definition: stream-tcp-reassemble.h:46
TcpStateQueue_::win
uint16_t win
Definition: stream-tcp-private.h:38
TCP_GET_RAW_HLEN
#define TCP_GET_RAW_HLEN(tcph)
Definition: decode-tcp.h:72
IPV4Hdr_::ip_id
uint16_t ip_id
Definition: decode-ipv4.h:76
STREAM_PKT_FLAG_RETRANSMISSION
#define STREAM_PKT_FLAG_RETRANSMISSION
Definition: stream-tcp-private.h: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:5941
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:6634
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:1310
PKT_NOPAYLOAD_INSPECTION
#define PKT_NOPAYLOAD_INSPECTION
Definition: decode.h:1253
Flow_::dp
Port dp
Definition: flow.h:372
TCP_GET_SACKOK
#define TCP_GET_SACKOK(p)
Definition: decode-tcp.h:102
STREAM_LASTACK_INVALID_ACK
@ STREAM_LASTACK_INVALID_ACK
Definition: decode-events.h:274
STREAM_EST_INVALID_ACK
@ STREAM_EST_INVALID_ACK
Definition: decode-events.h:261
TcpStreamCnf_::midstream_policy
enum ExceptionPolicy midstream_policy
Definition: stream-tcp.h:72
OS_POLICY_FIRST
@ OS_POLICY_FIRST
Definition: stream-tcp-reassemble.h:50
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:504
STREAM_PKT_RETRANSMISSION
@ STREAM_PKT_RETRANSMISSION
Definition: decode-events.h:284
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
Flow_::protoctx
void * protoctx
Definition: flow.h:446
STREAMTCP_INIT_FLAG_DROP_INVALID
#define STREAMTCP_INIT_FLAG_DROP_INVALID
Definition: stream-tcp.h:39
TCP_GET_RAW_WINDOW
#define TCP_GET_RAW_WINDOW(tcph)
Definition: decode-tcp.h:83
EXCEPTION_POLICY_NOT_SET
@ EXCEPTION_POLICY_NOT_SET
Definition: util-exception-policy-types.h:26
ExceptionPolicyParse
enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow)
Definition: util-exception-policy.c:232
TcpStateQueue_
Definition: stream-tcp-private.h:35
STREAM_RST_BUT_NO_SESSION
@ STREAM_RST_BUT_NO_SESSION
Definition: decode-events.h:275
GET_PKT_DIRECT_MAX_SIZE
#define GET_PKT_DIRECT_MAX_SIZE(p)
Definition: decode.h:207
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:99
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:572
PacketQueueNoLock_
simple fifo queue for packets
Definition: packet-queue.h:34
STREAMTCP_STREAM_FLAG_DEPTH_REACHED
#define STREAMTCP_STREAM_FLAG_DEPTH_REACHED
Definition: stream-tcp-private.h:223
GET_IPV6_DST_ADDR
#define GET_IPV6_DST_ADDR(p)
Definition: decode.h:200
STREAM_EST_PACKET_OUT_OF_WINDOW
@ STREAM_EST_PACKET_OUT_OF_WINDOW
Definition: decode-events.h:252
util-unittest.h
OS_POLICY_IRIX
@ OS_POLICY_IRIX
Definition: stream-tcp-reassemble.h:45
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:80
STREAMTCP_FLAG_TFO_DATA_IGNORED
#define STREAMTCP_FLAG_TFO_DATA_IGNORED
Definition: stream-tcp-private.h:207
TCP_GET_WSCALE
#define TCP_GET_WSCALE(p)
Definition: decode-tcp.h:100
FLOW_COPY_IPV6_ADDR_TO_PACKET
#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa)
Definition: flow.h:184
StreamTcpReassembleInit
int StreamTcpReassembleInit(bool quiet)
Definition: stream-tcp-reassemble.c:522
TcpState
TcpState
Definition: stream-tcp-private.h:150
STREAMTCP_FLAG_MIDSTREAM
#define STREAMTCP_FLAG_MIDSTREAM
Definition: stream-tcp-private.h:170
STREAMTCP_FLAG_LOSSY_BE_LIBERAL
#define STREAMTCP_FLAG_LOSSY_BE_LIBERAL
Definition: stream-tcp-private.h:194
STREAM_RST_WITH_DATA
@ STREAM_RST_WITH_DATA
Definition: decode-events.h:283
StreamTcpUpdateLastAck
#define StreamTcpUpdateLastAck(ssn, stream, ack)
macro to update last_ack only if the new value is higher
Definition: stream-tcp.c: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:605
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1320
DLT_RAW
#define DLT_RAW
Definition: decode.h:1220
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:359
SET_PKT_LEN
#define SET_PKT_LEN(p, len)
Definition: decode.h:209
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
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:51
TOSERVER
#define TOSERVER
Definition: flow.h:45
StreamTcpCheckMemcap
int StreamTcpCheckMemcap(uint64_t size)
Check if alloc'ing "size" would mean we're over memcap.
Definition: stream-tcp.c:266
GET_IPV4_DST_ADDR_PTR
#define GET_IPV4_DST_ADDR_PTR(p)
Definition: decode.h:195
TcpStateQueue_::seq
uint32_t seq
Definition: stream-tcp-private.h:39
PKT_IS_TOSERVER
#define PKT_IS_TOSERVER(p)
Definition: decode.h:234
STREAM_HAS_SEEN_DATA
#define STREAM_HAS_SEEN_DATA(stream)
Definition: stream-tcp-private.h:104
STREAM_PKT_BAD_WINDOW_UPDATE
@ STREAM_PKT_BAD_WINDOW_UPDATE
Definition: decode-events.h:286
STREAMTCP_FLAG_ASYNC
#define STREAMTCP_FLAG_ASYNC
Definition: stream-tcp-private.h:182
TCPHdr_::th_seq
uint32_t th_seq
Definition: decode-tcp.h:152
STREAMTCP_FLAG_BYPASS
#define STREAMTCP_FLAG_BYPASS
Definition: stream-tcp-private.h:203
Packet_::ts
SCTime_t ts
Definition: decode.h:521
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:6969
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
TCPHdr_::th_offx2
uint8_t th_offx2
Definition: decode-tcp.h:154
TcpSegmentPcapHdrStorage_::ts
SCTime_t ts
Definition: stream-tcp-private.h:66
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1266
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:205
ExceptionPolicySetStatsCounters
void ExceptionPolicySetStatsCounters(ThreadVars *tv, ExceptionPolicyCounters *counter, ExceptionPolicyStatsSetts *setting, enum ExceptionPolicy conf_policy, const char *default_str, bool(*isExceptionPolicyValid)(enum ExceptionPolicy))
Definition: util-exception-policy.c:298
detect.h
StreamTcpThread_::counter_tcp_invalid_checksum
uint16_t counter_tcp_invalid_checksum
Definition: stream-tcp.h:96
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
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:5899
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:450
StreamTcpPacket
int StreamTcpPacket(ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueueNoLock *pq)
Definition: stream-tcp.c:5500
Packet_::sp
Port sp
Definition: decode.h:480
TCP_GET_TSECR
#define TCP_GET_TSECR(p)
Definition: decode-tcp.h:91
OS_POLICY_BSD_RIGHT
@ OS_POLICY_BSD_RIGHT
Definition: stream-tcp-reassemble.h:38
TcpSession_::state
uint8_t state
Definition: stream-tcp-private.h:285
FLOW_WRONG_THREAD
#define FLOW_WRONG_THREAD
Definition: flow.h:109
PAWS_24DAYS
#define PAWS_24DAYS
Definition: stream-tcp-private.h:247
PktSrcToString
const char * PktSrcToString(enum PktSrcEnum pkt_src)
Definition: decode.c: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:6910
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:87
STREAM_LASTACK_ACK_WRONG_SEQ
@ STREAM_LASTACK_ACK_WRONG_SEQ
Definition: decode-events.h:273
TcpStream_::next_win
uint32_t next_win
Definition: stream-tcp-private.h:116
stream_config
TcpStreamCnf stream_config
Definition: stream-tcp.c:219
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:300
FLOW_IS_IPV4
#define FLOW_IS_IPV4(f)
Definition: flow.h:169
STREAM_SHUTDOWN_SYN_RESEND
@ STREAM_SHUTDOWN_SYN_RESEND
Definition: decode-events.h:278
RB_FOREACH
#define RB_FOREACH(x, name, head)
Definition: tree.h:781
TcpStreamCnf_::liberal_timestamps
bool liberal_timestamps
Definition: stream-tcp.h: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:333
SCReturn
#define SCReturn
Definition: util-debug.h:273
PKT_SRC_STREAM_TCP_DETECTLOG_FLUSH
@ PKT_SRC_STREAM_TCP_DETECTLOG_FLUSH
Definition: decode.h:58
STREAMTCP_QUEUE_FLAG_SACK
#define STREAMTCP_QUEUE_FLAG_SACK
Definition: stream-tcp-private.h:32
stream.h
STREAM_PKT_INVALID_ACK
@ STREAM_PKT_INVALID_ACK
Definition: decode-events.h:280
t_pcapcnt
thread_local uint64_t t_pcapcnt
Definition: stream-tcp-reassemble.c: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:473
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:567
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:368
TcpStream_::window
uint32_t window
Definition: stream-tcp-private.h:117
PKT_IGNORE_CHECKSUM
#define PKT_IGNORE_CHECKSUM
Definition: decode.h:1280
TCP_HAS_TS
#define TCP_HAS_TS(p)
Definition: decode-tcp.h:95
Packet_::livedev
struct LiveDevice_ * livedev
Definition: decode.h:584
StreamTcpReassembleFreeThreadCtx
void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx)
Definition: stream-tcp-reassemble.c:595
TmEcode
TmEcode
Definition: tm-threads-common.h:79
Flow_::vlan_idx
uint8_t vlan_idx
Definition: flow.h:382
PcapIncreaseInvalidChecksum
void PcapIncreaseInvalidChecksum(void)
Definition: source-pcap-file.c:480
STREAM_PKT_FLAG_KEEPALIVE
#define STREAM_PKT_FLAG_KEEPALIVE
Definition: stream-tcp-private.h: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
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:251
STREAMING_BUFFER_INITIALIZER
#define STREAMING_BUFFER_INITIALIZER
Definition: util-streaming-buffer.h:137
StreamTcpReassembleFree
void StreamTcpReassembleFree(bool quiet)
Definition: stream-tcp-reassemble.c: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:1161
Flow_::src
FlowAddress src
Definition: flow.h:359
util-host-os-info.h
ReCalculateChecksum
int ReCalculateChecksum(Packet *p)
Definition: util-checksum.c:29
StreamingBuffer_
Definition: util-streaming-buffer.h:108
STREAM_FIN_OUT_OF_WINDOW
@ STREAM_FIN_OUT_OF_WINDOW
Definition: decode-events.h:271
IPV4Hdr_
Definition: decode-ipv4.h:72
STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION
@ STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION
Definition: decode-events.h:230
SCTIME_CMP_LT
#define SCTIME_CMP_LT(a, b)
Definition: util-time.h:105
TCP_CLOSED
@ TCP_CLOSED
Definition: stream-tcp-private.h:162
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:47
TcpStateQueue_::wscale
uint8_t wscale
Definition: stream-tcp-private.h:37
stream_midstream_disabled_eps_stats
ExceptionPolicyStatsSetts stream_midstream_disabled_eps_stats
Definition: stream-tcp.c:173
StreamTcpThread_::counter_tcp_pseudo_failed
uint16_t counter_tcp_pseudo_failed
Definition: stream-tcp.h: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:631
Packet_::flow
struct Flow_ * flow
Definition: decode.h:512
STREAMTCP_FLAG_TIMESTAMP
#define STREAMTCP_FLAG_TIMESTAMP
Definition: stream-tcp-private.h:176
FlowSetProtoFreeFunc
int FlowSetProtoFreeFunc(uint8_t, void(*Free)(void *))
Function to set the function to get protocol specific flow state.
Definition: flow.c:1124
SEQ_GEQ
#define SEQ_GEQ(a, b)
Definition: stream-tcp-private.h:260
stream-tcp.c
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c: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
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:37
OS_POLICY_OLD_SOLARIS
@ OS_POLICY_OLD_SOLARIS
Definition: stream-tcp-reassemble.h:41
TcpStream_::base_seq
uint32_t base_seq
Definition: stream-tcp-private.h:124
packet.h
PKT_STREAM_NOPCAPLOG
#define PKT_STREAM_NOPCAPLOG
Definition: decode.h:1275
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
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:1945
TCP_CLOSING
@ TCP_CLOSING
Definition: stream-tcp-private.h:161
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
ParseSizeStringU32
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:173
Flow_::livedev
struct LiveDevice_ * livedev
Definition: flow.h:403
TcpStreamCnf_::midstream
bool midstream
Definition: stream-tcp.h:60
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
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:51
threadvars.h
util-validate.h
FlowSwap
void FlowSwap(Flow *f)
swap the flow's direction
Definition: flow.c:255
StreamTcpDetectLogFlush
void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p, PacketQueueNoLock *pq)
create packets in both directions to flush out logging and detection before switching protocols....
Definition: stream-tcp.c:6886
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:508
stream_midstream_enabled_eps_stats
ExceptionPolicyStatsSetts stream_midstream_enabled_eps_stats
Definition: stream-tcp.c:147
STREAM_FIN2_FIN_WRONG_SEQ
@ STREAM_FIN2_FIN_WRONG_SEQ
Definition: decode-events.h:268
STREAM_PKT_FLAG_ACK_UNSEEN_DATA
#define STREAM_PKT_FLAG_ACK_UNSEEN_DATA
Definition: stream-tcp-private.h:319
PKT_PSEUDO_DETECTLOG_FLUSH
#define PKT_PSEUDO_DETECTLOG_FLUSH
Definition: decode.h:1306
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:577
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:7069
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:426
TcpStream_::app_progress_rel
uint32_t app_progress_rel
Definition: stream-tcp-private.h:127
STREAM_3WHS_SYNACK_TFO_DATA_IGNORED
@ STREAM_3WHS_SYNACK_TFO_DATA_IGNORED
Definition: decode-events.h:236
StreamTcpSessionCleanup
void StreamTcpSessionCleanup(TcpSession *ssn)
Session cleanup function. Does not free the ssn.
Definition: stream-tcp.c:327
TcpReassemblyThreadCtx_::counter_tcp_reass_data_overlap_fail
uint16_t counter_tcp_reass_data_overlap_fail
Definition: stream-tcp-reassemble.h:85
TcpStateQueue_::ts
uint32_t ts
Definition: stream-tcp-private.h:41
stream_reassembly_memcap_eps_stats
ExceptionPolicyStatsSetts stream_reassembly_memcap_eps_stats
Definition: stream-tcp.c:121
StreamTcpMemuseCounter
uint64_t StreamTcpMemuseCounter(void)
Definition: stream-tcp.c:254
StreamTcpUpdateNextWin
#define StreamTcpUpdateNextWin(ssn, stream, win)
macro to update next_win only if the new value is higher
Definition: stream-tcp.c:1019
PoolThread_
Definition: util-pool-thread.h:53
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:49
TcpStateQueue_::pkt_ts
uint32_t pkt_ts
Definition: stream-tcp-private.h:42
STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ
@ STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ
Definition: decode-events.h:256
stream-tcp-cache.h
TcpStream_::last_pkt_ts
uint32_t last_pkt_ts
Definition: stream-tcp-private.h:120
stream-tcp-util.h
TCP_TIME_WAIT
@ TCP_TIME_WAIT
Definition: stream-tcp-private.h:158
PacketPoolGetPacket
Packet * PacketPoolGetPacket(void)
Get a new packet from the packet pool.
Definition: tmqh-packetpool.c:127
SEQ_EQ
#define SEQ_EQ(a, b)
Definition: stream-tcp-private.h:256
util-random.h
StreamTcpThread_::counter_tcp_pseudo
uint16_t counter_tcp_pseudo
Definition: stream-tcp.h:92
StreamTcpThreadCacheEnable
void StreamTcpThreadCacheEnable(void)
enable segment cache. Should only be done for worker threads
Definition: stream-tcp-cache.c:48
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:234
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:33
PoolThreadGetById
void * PoolThreadGetById(PoolThread *pt, uint16_t id)
get data from thread pool by thread id
Definition: util-pool-thread.c:173
StreamTcpThread_::counter_tcp_ssn_memcap_eps
ExceptionPolicyCounters counter_tcp_ssn_memcap_eps
Definition: stream-tcp.h:90
AppLayerProfilingReset
#define AppLayerProfilingReset(app_tctx)
Definition: app-layer.h:127
app-layer-htp-mem.h
EngineModeIsIPS
int EngineModeIsIPS(void)
Definition: suricata.c:228
g_detect_disabled
int g_detect_disabled
Definition: suricata.c:183
STREAM_PKT_FLAG_SET
#define STREAM_PKT_FLAG_SET(p, f)
Definition: stream-tcp-private.h: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:478
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:7076
Flow_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: flow.h:380
STREAMTCP_FLAG_3WHS_CONFIRMED
#define STREAMTCP_FLAG_3WHS_CONFIRMED
Definition: stream-tcp-private.h:199
STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION
#define STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION
Definition: stream-tcp.h:38
SEQ_LEQ
#define SEQ_LEQ(a, b)
Definition: stream-tcp-private.h:258
STREAM_3WHS_ACK_DATA_INJECT
@ STREAM_3WHS_ACK_DATA_INJECT
Definition: decode-events.h:241
PKT_NOPACKET_INSPECTION
#define PKT_NOPACKET_INSPECTION
Definition: decode.h:1248
TCP_HAS_WSCALE
#define TCP_HAS_WSCALE(p)
Definition: decode-tcp.h:93
STREAM_FIN2_ACK_WRONG_SEQ
@ STREAM_FIN2_ACK_WRONG_SEQ
Definition: decode-events.h:267
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:39
STREAM_EST_ACK_ZWP_DATA
@ STREAM_EST_ACK_ZWP_DATA
Definition: decode-events.h:262
TcpReassemblyThreadCtx_::counter_tcp_segment_from_pool
uint16_t counter_tcp_segment_from_pool
Definition: stream-tcp-reassemble.h:72
STREAMTCP_STREAM_FLAG_DISABLE_RAW
#define STREAMTCP_STREAM_FLAG_DISABLE_RAW
Definition: stream-tcp-private.h:238
Packet_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: decode.h:500
likely
#define likely(expr)
Definition: util-optimize.h:32
STREAM_APP_PROGRESS
#define STREAM_APP_PROGRESS(stream)
Definition: stream-tcp-private.h:145
STREAMTCP_FLAG_ZWP_TS
#define STREAMTCP_FLAG_ZWP_TS
Definition: stream-tcp-private.h:209
OS_POLICY_DEFAULT
#define OS_POLICY_DEFAULT
Definition: stream-tcp-reassemble.h: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
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:44
Flow_::sp
Port sp
Definition: flow.h:361
STREAM_4WHS_INVALID_ACK
@ STREAM_4WHS_INVALID_ACK
Definition: decode-events.h:245
STREAMTCP_FLAG_4WHS
#define STREAMTCP_FLAG_4WHS
Definition: stream-tcp-private.h:185
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
TcpSession_
Definition: stream-tcp-private.h:283
StreamTcpSsnStateAsString
const char * StreamTcpSsnStateAsString(const TcpSession *ssn)
Definition: stream-tcp.c:7117
StreamTcpThread_::ssn_pool_id
int ssn_pool_id
Definition: stream-tcp.h:81
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:370
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:455
Packet_::dp
Port dp
Definition: decode.h:488
ExceptionPolicy
ExceptionPolicy
Definition: util-exception-policy-types.h:25
StatsRegisterCounter
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:951
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV
@ STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV
Definition: decode-events.h:238
ssn_pool
PoolThread * ssn_pool
Definition: stream-tcp.c:213
STREAMTCP_STREAM_FLAG_TRIGGER_RAW
#define STREAMTCP_STREAM_FLAG_TRIGGER_RAW
Definition: stream-tcp-private.h:225
IPV4Hdr_::ip_proto
uint8_t ip_proto
Definition: decode-ipv4.h:79
PoolThreadSize
int PoolThreadSize(PoolThread *pt)
get size of PoolThread (number of 'threads', so array elements)
Definition: util-pool-thread.c:148
TCP_GET_RAW_ACK
#define TCP_GET_RAW_ACK(tcph)
Definition: decode-tcp.h:81
util-pool.h
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:120
STREAM_FIN2_INVALID_ACK
@ STREAM_FIN2_INVALID_ACK
Definition: decode-events.h:269
StreamTcpDecrMemuse
void StreamTcpDecrMemuse(uint64_t size)
Definition: stream-tcp.c:234
TOCLIENT
#define TOCLIENT
Definition: flow.h:46
StreamTcpThread_::counter_tcp_ack_unseen_data
uint16_t counter_tcp_ack_unseen_data
Definition: stream-tcp.h: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:477
Flow_::tenant_id
uint32_t tenant_id
Definition: flow.h:421
TcpReassemblyThreadCtx_::counter_tcp_segment_from_cache
uint16_t counter_tcp_segment_from_cache
Definition: stream-tcp-reassemble.h:71
PacketL4::vars
union PacketL4::L4Vars vars
STREAMTCP_FLAG_TCP_FAST_OPEN
#define STREAMTCP_FLAG_TCP_FAST_OPEN
Definition: stream-tcp-private.h:205
TcpStream_::wscale
uint16_t wscale
Definition: stream-tcp-private.h:109
STREAM_FIN_INVALID_ACK
@ STREAM_FIN_INVALID_ACK
Definition: decode-events.h:263
STREAMTCP_INIT_FLAG_INLINE
#define STREAMTCP_INIT_FLAG_INLINE
Definition: stream-tcp.h:41
StreamTcpThreadDeinit
TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data)
Definition: stream-tcp.c:6028
STREAMTCP_DEFAULT_PREALLOC
#define STREAMTCP_DEFAULT_PREALLOC
Definition: stream-tcp.c:85
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1261
STREAM_3WHS_ACK_IN_WRONG_DIR
@ STREAM_3WHS_ACK_IN_WRONG_DIR
Definition: decode-events.h:227
Flow_::thread_id
FlowThreadId thread_id[2]
Definition: flow.h:399
TcpStateQueue_::ack
uint32_t ack
Definition: stream-tcp-private.h:40
app-layer.h
STREAMTCP_FLAG_SERVER_WSCALE
#define STREAMTCP_FLAG_SERVER_WSCALE
Definition: stream-tcp-private.h:178
FLOW_COPY_IPV4_ADDR_TO_PACKET
#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa)
Definition: flow.h:179
StreamTcpSetDisableRawReassemblyFlag
void StreamTcpSetDisableRawReassemblyFlag(TcpSession *ssn, char direction)
Set the No reassembly flag for the given direction in given TCP session.
Definition: stream-tcp.c:6670
STREAM_3WHS_SYN_FLOOD
@ STREAM_3WHS_SYN_FLOOD
Definition: decode-events.h:239
StreamTcpSetSessionBypassFlag
void StreamTcpSetSessionBypassFlag(TcpSession *ssn)
enable bypass
Definition: stream-tcp.c:6681
StreamTcpBypassEnabled
int StreamTcpBypassEnabled(void)
Definition: stream-tcp.c:7052
STREAM_CLOSEWAIT_INVALID_ACK
@ STREAM_CLOSEWAIT_INVALID_ACK
Definition: decode-events.h:249