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