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 uint16_t id = stt->counter_tcp_ssn_memcap_eps.eps_id[policy];
902  if (likely(tv && id > 0)) {
903  StatsIncr(tv, 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  if (SEQ_GT((ack), (stream)->last_ack)) \
1070  { \
1071  SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \
1072  if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \
1073  SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \
1074  } else { \
1075  SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \
1076  }\
1077  (stream)->last_ack = (ack); \
1078  StreamTcpSackPruneList((stream)); \
1079  } else { \
1080  SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \
1081  (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \
1082  }\
1083 }
1084 
1085 #define StreamTcpAsyncLastAckUpdate(ssn, stream) { \
1086  if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \
1087  if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \
1088  uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \
1089  (stream)->last_ack += ack_diff; \
1090  SCLogDebug("ssn %p: ASYNC last_ack set to %"PRIu32", moved %u forward", \
1091  (ssn), (stream)->next_seq, ack_diff); \
1092  } \
1093  } \
1094 }
1095 
1096 #define StreamTcpUpdateNextSeq(ssn, stream, seq) { \
1097  (stream)->next_seq = seq; \
1098  SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \
1099  StreamTcpAsyncLastAckUpdate((ssn), (stream)); \
1100 }
1101 
1102 /**
1103  * \brief macro to update next_win only if the new value is higher
1104  *
1105  * \param ssn session
1106  * \param stream stream to update
1107  * \param win window value to test and set
1108  */
1109 #define StreamTcpUpdateNextWin(ssn, stream, win) { \
1110  uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \
1111  if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \
1112  (stream)->next_win = ((win) + sacked_size__); \
1113  SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \
1114  } \
1115 }
1116 
1117 static inline void StreamTcpCloseSsnWithReset(Packet *p, TcpSession *ssn)
1118 {
1120  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1121  SCLogDebug("ssn %p: (state: %s) Reset received and state changed to "
1122  "TCP_CLOSED", ssn, StreamTcpStateAsString(ssn->state));
1123 }
1124 
1125 static bool IsMidstreamExceptionPolicyStatsValid(enum ExceptionPolicy policy)
1126 {
1127  if (EngineModeIsIPS()) {
1128  if (stream_config.midstream) {
1130  }
1132  }
1133  if (stream_config.midstream) {
1135  }
1137 }
1138 
1139 static void StreamTcpMidstreamExceptionPolicyStatsIncr(
1140  ThreadVars *tv, StreamTcpThread *stt, enum ExceptionPolicy policy)
1141 {
1142  const uint16_t id = stt->counter_tcp_midstream_eps.eps_id[policy];
1143  if (likely(tv && id > 0)) {
1144  StatsIncr(tv, id);
1145  }
1146 }
1147 
1148 static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p)
1149 {
1150  if (p->payload_len == 0)
1151  SCReturnInt(0);
1152 
1153  const TCPHdr *tcph = PacketGetTCP(p);
1154  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
1155  /* retransmission of already partially ack'd data */
1156  if (SEQ_LT(seq, stream->last_ack) && SEQ_GT((seq + p->payload_len), stream->last_ack)) {
1158  SCReturnInt(1);
1159  }
1160 
1161  /* retransmission of already ack'd data */
1162  if (SEQ_LEQ((seq + p->payload_len), stream->last_ack)) {
1164  SCReturnInt(1);
1165  }
1166 
1167  /* retransmission of in flight data */
1168  if (SEQ_LEQ((seq + p->payload_len), stream->next_seq)) {
1170  SCReturnInt(2);
1171  }
1172 
1173  SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", seq, p->payload_len,
1174  (seq + p->payload_len), stream->last_ack, stream->next_seq);
1175  SCReturnInt(0);
1176 }
1177 
1178 /**
1179  * \internal
1180  * \brief Function to handle the TCP_CLOSED or NONE state. The function handles
1181  * packets while the session state is None which means a newly
1182  * initialized structure, or a fully closed session.
1183  *
1184  * \param tv Thread Variable containing input/output queue, cpu affinity
1185  * \param p Packet which has to be handled in this TCP state.
1186  * \param stt Stream Thread module registered to handle the stream handling
1187  *
1188  * \retval 0 ok
1189  * \retval -1 error
1190  */
1191 static int StreamTcpPacketStateNone(
1192  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
1193 {
1194  const TCPHdr *tcph = PacketGetTCP(p);
1195  if (tcph->th_flags & TH_RST) {
1197  SCLogDebug("RST packet received, no session setup");
1198  return -1;
1199 
1200  } else if (tcph->th_flags & TH_FIN) {
1201  /* Drop reason will only be used if midstream policy is set to fail closed */
1203  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1204 
1205  if (!stream_config.midstream || p->payload_len == 0) {
1207  SCLogDebug("FIN packet received, no session setup");
1208  return -1;
1209  }
1213  SCLogDebug("FIN packet received, no session setup");
1214  return -1;
1215  }
1216  SCLogDebug("midstream picked up");
1217 
1218  if (ssn == NULL) {
1219  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1220  if (ssn == NULL) {
1222  return -1;
1223  }
1227  }
1228  /* set the state */
1229  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
1230  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1231  "TCP_FIN_WAIT1",
1232  ssn);
1233 
1237  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1238  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1239  }
1240 
1241  /** window scaling for midstream pickups, we can't do much other
1242  * than assume that it's set to the max value: 14 */
1243  ssn->client.wscale = TCP_WSCALE_MAX;
1244  ssn->server.wscale = TCP_WSCALE_MAX;
1245 
1246  /* set the sequence numbers and window */
1247  ssn->client.isn = TCP_GET_RAW_SEQ(tcph) - 1;
1249  ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len + 1;
1250  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
1251  ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
1252  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1253  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", ssn, ssn->client.isn,
1254  ssn->client.next_seq);
1255 
1256  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
1258  ssn->server.next_seq = ssn->server.isn + 1;
1259  ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
1260  ssn->server.next_win = ssn->server.last_ack;
1261 
1262  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
1263  "ssn->server.next_win %" PRIu32 "",
1264  ssn, ssn->client.next_win, ssn->server.next_win);
1265  SCLogDebug("ssn %p: ssn->client.last_ack %" PRIu32 ", "
1266  "ssn->server.last_ack %" PRIu32 "",
1267  ssn, ssn->client.last_ack, ssn->server.last_ack);
1268 
1269  /* Set the timestamp value for both streams, if packet has timestamp
1270  * option enabled.*/
1271  if (TCP_HAS_TS(p)) {
1272  ssn->client.last_ts = TCP_GET_TSVAL(p);
1273  ssn->server.last_ts = TCP_GET_TSECR(p);
1274  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " "
1275  "ssn->client.last_ts %" PRIu32 "",
1276  ssn, ssn->server.last_ts, ssn->client.last_ts);
1277 
1279 
1280  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1281  if (ssn->server.last_ts == 0)
1283  if (ssn->client.last_ts == 0)
1285 
1286  } else {
1287  ssn->server.last_ts = 0;
1288  ssn->client.last_ts = 0;
1289  }
1290 
1291  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1292 
1293  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1294  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1295 
1296  /* SYN/ACK */
1297  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
1298  /* Drop reason will only be used if midstream policy is set to fail closed */
1300  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1301 
1303  SCLogDebug("Midstream not enabled, so won't pick up a session");
1304  return 0;
1305  }
1308  SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1309  return 0;
1310  }
1311  SCLogDebug("midstream picked up");
1312 
1313  if (ssn == NULL) {
1314  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1315  if (ssn == NULL) {
1317  return -1;
1318  }
1322  }
1323 
1324  /* reverse packet and flow */
1325  SCLogDebug("reversing flow and packet");
1326  PacketSwap(p);
1327  FlowSwap(p->flow);
1328 
1329  /* set the state */
1330  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1331  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1332  "TCP_SYN_RECV", ssn);
1334  /* Flag used to change the direct in the later stage in the session */
1337  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1338  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1339  }
1340 
1341  /* sequence number & window */
1342  ssn->server.isn = TCP_GET_RAW_SEQ(tcph);
1344  ssn->server.next_seq = ssn->server.isn + 1;
1345  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
1346  SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
1347 
1348  ssn->client.isn = TCP_GET_RAW_ACK(tcph) - 1;
1350  ssn->client.next_seq = ssn->client.isn + 1;
1351 
1352  ssn->client.last_ack = TCP_GET_RAW_ACK(tcph);
1353  ssn->server.last_ack = TCP_GET_RAW_SEQ(tcph);
1354 
1355  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1356 
1357  /** If the client has a wscale option the server had it too,
1358  * so set the wscale for the server to max. Otherwise none
1359  * will have the wscale opt just like it should. */
1360  if (TCP_HAS_WSCALE(p)) {
1361  ssn->client.wscale = TCP_GET_WSCALE(p);
1362  ssn->server.wscale = TCP_WSCALE_MAX;
1363  SCLogDebug("ssn %p: wscale enabled. client %u server %u",
1364  ssn, ssn->client.wscale, ssn->server.wscale);
1365  }
1366 
1367  SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
1368  " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
1369  ssn->client.isn, ssn->client.next_seq,
1370  ssn->client.last_ack);
1371  SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
1372  " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
1373  ssn->server.isn, ssn->server.next_seq,
1374  ssn->server.last_ack);
1375 
1376  /* Set the timestamp value for both streams, if packet has timestamp
1377  * option enabled.*/
1378  if (TCP_HAS_TS(p)) {
1379  ssn->server.last_ts = TCP_GET_TSVAL(p);
1380  ssn->client.last_ts = TCP_GET_TSECR(p);
1381  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1382  "ssn->client.last_ts %" PRIu32"", ssn,
1383  ssn->server.last_ts, ssn->client.last_ts);
1384 
1386 
1387  ssn->server.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1388  if (ssn->server.last_ts == 0)
1390  if (ssn->client.last_ts == 0)
1392 
1393  } else {
1394  ssn->server.last_ts = 0;
1395  ssn->client.last_ts = 0;
1396  }
1397 
1398  if (TCP_GET_SACKOK(p)) {
1399  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1400  SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
1401  "SACK permitted for both sides", ssn);
1402  }
1403  return 0;
1404 
1405  } else if (tcph->th_flags & TH_SYN) {
1406  if (ssn == NULL) {
1407  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1408  if (ssn == NULL) {
1410  return -1;
1411  }
1412 
1415  }
1416 
1417  /* set the state */
1418  StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
1419  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
1420 
1422  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1423  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1424  }
1425 
1426  /* set the sequence numbers and window */
1427  ssn->client.isn = TCP_GET_RAW_SEQ(tcph);
1429  ssn->client.next_seq = ssn->client.isn + 1;
1430 
1431  /* Set the stream timestamp value, if packet has timestamp option
1432  * enabled. */
1433  if (TCP_HAS_TS(p)) {
1434  ssn->client.last_ts = TCP_GET_TSVAL(p);
1435  SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
1436 
1437  if (ssn->client.last_ts == 0)
1439 
1440  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1442  }
1443 
1444  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
1445  if (TCP_HAS_WSCALE(p)) {
1447  ssn->server.wscale = TCP_GET_WSCALE(p);
1448  }
1449 
1450  if (TCP_GET_SACKOK(p)) {
1452  SCLogDebug("ssn %p: SACK permitted on SYN packet", ssn);
1453  }
1454 
1455  if (TCP_HAS_TFO(p)) {
1457  if (p->payload_len) {
1458  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
1459  SCLogDebug("ssn: %p (TFO) isn %u base_seq %u next_seq %u payload len %u", ssn,
1460  ssn->client.isn, ssn->client.base_seq, ssn->client.next_seq,
1461  p->payload_len);
1462  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1463  }
1464  }
1465 
1466  SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
1467  "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
1468  "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
1469  ssn->client.last_ack);
1470 
1471  } else if (tcph->th_flags & TH_ACK) {
1472  /* Drop reason will only be used if midstream policy is set to fail closed */
1474  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1475 
1476  if (!stream_config.midstream) {
1477  SCLogDebug("Midstream not enabled, so won't pick up a session");
1478  return 0;
1479  }
1482  SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1483  return 0;
1484  }
1485  SCLogDebug("midstream picked up");
1486 
1487  if (ssn == NULL) {
1488  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1489  if (ssn == NULL) {
1491  return -1;
1492  }
1496  }
1497  /* set the state */
1498  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1499  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1500  "TCP_ESTABLISHED", ssn);
1501 
1505  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1506  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1507  }
1508 
1509  /** window scaling for midstream pickups, we can't do much other
1510  * than assume that it's set to the max value: 14 */
1511  ssn->client.wscale = TCP_WSCALE_MAX;
1512  ssn->server.wscale = TCP_WSCALE_MAX;
1513 
1514  /* set the sequence numbers and window */
1515  ssn->client.isn = TCP_GET_RAW_SEQ(tcph) - 1;
1517  ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
1518  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
1519  ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
1520  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1521  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
1522  ssn, ssn->client.isn, ssn->client.next_seq);
1523 
1524  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
1526  ssn->server.next_seq = ssn->server.isn + 1;
1527  ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
1528  ssn->server.next_win = ssn->server.last_ack;
1529 
1530  SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
1531  "ssn->server.next_win %"PRIu32"", ssn,
1532  ssn->client.next_win, ssn->server.next_win);
1533  SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
1534  "ssn->server.last_ack %"PRIu32"", ssn,
1535  ssn->client.last_ack, ssn->server.last_ack);
1536 
1537  /* Set the timestamp value for both streams, if packet has timestamp
1538  * option enabled.*/
1539  if (TCP_HAS_TS(p)) {
1540  ssn->client.last_ts = TCP_GET_TSVAL(p);
1541  ssn->server.last_ts = TCP_GET_TSECR(p);
1542  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1543  "ssn->client.last_ts %" PRIu32"", ssn,
1544  ssn->server.last_ts, ssn->client.last_ts);
1545 
1547 
1548  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1549  if (ssn->server.last_ts == 0)
1551  if (ssn->client.last_ts == 0)
1553 
1554  } else {
1555  ssn->server.last_ts = 0;
1556  ssn->client.last_ts = 0;
1557  }
1558 
1559  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1560 
1561  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1562  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1563 
1564  } else {
1565  SCLogDebug("default case");
1566  }
1567 
1568  return 0;
1569 }
1570 
1571 /** \internal
1572  * \brief Setup TcpStateQueue based on SYN/ACK packet
1573  */
1574 static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
1575 {
1576  const TCPHdr *tcph = PacketGetTCP(p);
1577  q->flags = 0;
1578  q->wscale = 0;
1579  q->ts = 0;
1580  q->win = TCP_GET_RAW_WINDOW(tcph);
1581  q->seq = TCP_GET_RAW_SEQ(tcph);
1582  q->ack = TCP_GET_RAW_ACK(tcph);
1583  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1584 
1585  if (TCP_GET_SACKOK(p))
1587 
1588  if (TCP_HAS_WSCALE(p)) {
1590  q->wscale = TCP_GET_WSCALE(p);
1591  }
1592  if (TCP_HAS_TS(p)) {
1594  q->ts = TCP_GET_TSVAL(p);
1595  }
1596 }
1597 
1598 /** \internal
1599  * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
1600  * \retval q or NULL */
1601 static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
1602 {
1603  TcpStateQueue *q = ssn->queue;
1604  TcpStateQueue search;
1605 
1606  StreamTcp3whsSynAckToStateQueue(p, &search);
1607 
1608  while (q != NULL) {
1609  if (search.flags == q->flags &&
1610  search.wscale == q->wscale &&
1611  search.win == q->win &&
1612  search.seq == q->seq &&
1613  search.ack == q->ack &&
1614  search.ts == q->ts) {
1615  return q;
1616  }
1617 
1618  q = q->next;
1619  }
1620 
1621  return q;
1622 }
1623 
1624 static int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
1625 {
1626  /* first see if this is already in our list */
1627  if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
1628  return 0;
1629 
1631  SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
1633  return -1;
1634  }
1635 
1636  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1637  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
1638  return -1;
1639  }
1640 
1641  TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1642  if (unlikely(q == NULL)) {
1643  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
1644  return -1;
1645  }
1646  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1647 
1648  StreamTcp3whsSynAckToStateQueue(p, q);
1649 
1650  /* put in list */
1651  q->next = ssn->queue;
1652  ssn->queue = q;
1653  ssn->queue_len++;
1654  return 0;
1655 }
1656 
1657 /** \internal
1658  * \brief Find the Queued SYN/ACK that goes with this ACK
1659  * \retval q or NULL */
1660 static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
1661 {
1662  const TCPHdr *tcph = PacketGetTCP(p);
1663  const uint32_t ack = TCP_GET_RAW_SEQ(tcph);
1664  const uint32_t seq = TCP_GET_RAW_ACK(tcph) - 1;
1665  TcpStateQueue *q = ssn->queue;
1666 
1667  while (q != NULL) {
1668  if (seq == q->seq &&
1669  ack == q->ack) {
1670  return q;
1671  }
1672 
1673  q = q->next;
1674  }
1675 
1676  return NULL;
1677 }
1678 
1679 /** \internal
1680  * \brief Update SSN after receiving a valid SYN/ACK
1681  *
1682  * Normally we update the SSN from the SYN/ACK packet. But in case
1683  * of queued SYN/ACKs, we can use one of those.
1684  *
1685  * \param ssn TCP session
1686  * \param p Packet
1687  * \param q queued state if used, NULL otherwise
1688  *
1689  * To make sure all SYN/ACK based state updates are in one place,
1690  * this function can updated based on Packet or TcpStateQueue, where
1691  * the latter takes precedence.
1692  */
1693 static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
1694 {
1695  TcpStateQueue update;
1696  if (likely(q == NULL)) {
1697  StreamTcp3whsSynAckToStateQueue(p, &update);
1698  q = &update;
1699  }
1700 
1701  if (ssn->state != TCP_SYN_RECV) {
1702  /* update state */
1703  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1704  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
1705  }
1706  /* sequence number & window */
1707  ssn->server.isn = q->seq;
1709  ssn->server.next_seq = ssn->server.isn + 1;
1710 
1711  ssn->client.window = q->win;
1712  SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
1713 
1714  /* Set the timestamp values used to validate the timestamp of
1715  * received packets.*/
1716  if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
1718  {
1719  ssn->server.last_ts = q->ts;
1720  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1721  "ssn->client.last_ts %" PRIu32"", ssn,
1722  ssn->server.last_ts, ssn->client.last_ts);
1724  ssn->server.last_pkt_ts = q->pkt_ts;
1725  if (ssn->server.last_ts == 0)
1727  } else {
1728  ssn->client.last_ts = 0;
1729  ssn->server.last_ts = 0;
1731  }
1732 
1733  ssn->client.last_ack = q->ack;
1734  ssn->server.last_ack = ssn->server.isn + 1;
1735 
1736  /** check for the presence of the ws ptr to determine if we
1737  * support wscale at all */
1738  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1740  {
1741  ssn->client.wscale = q->wscale;
1742  } else {
1743  ssn->client.wscale = 0;
1744  }
1745 
1746  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1748  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1749  SCLogDebug("ssn %p: SACK permitted for session", ssn);
1750  } else {
1751  ssn->flags &= ~STREAMTCP_FLAG_SACKOK;
1752  }
1753 
1754  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1755  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1756  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
1757  ssn->server.next_win);
1758  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
1759  ssn->client.next_win);
1760  SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
1761  "ssn->server.next_seq %" PRIu32 ", "
1762  "ssn->server.last_ack %" PRIu32 " "
1763  "(ssn->client.last_ack %" PRIu32 ")", ssn,
1764  ssn->server.isn, ssn->server.next_seq,
1765  ssn->server.last_ack, ssn->client.last_ack);
1766 
1767  /* unset the 4WHS flag as we received this SYN/ACK as part of a
1768  * (so far) valid 3WHS */
1769  if (ssn->flags & STREAMTCP_FLAG_4WHS)
1770  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
1771  " so considering 3WHS", ssn);
1772 
1773  ssn->flags &=~ STREAMTCP_FLAG_4WHS;
1774 }
1775 
1776 /** \internal
1777  * \brief detect timestamp anomalies when processing responses to the
1778  * SYN packet.
1779  * \retval true packet is ok
1780  * \retval false packet is bad
1781  */
1782 static inline bool StateSynSentValidateTimestamp(TcpSession *ssn, Packet *p)
1783 {
1784  /* we only care about evil server here, so skip TS packets */
1785  if (PKT_IS_TOSERVER(p) || !(TCP_HAS_TS(p))) {
1786  return true;
1787  }
1788 
1789  TcpStream *receiver_stream = &ssn->client;
1790  const uint32_t ts_echo = TCP_GET_TSECR(p);
1791  if ((receiver_stream->flags & STREAMTCP_STREAM_FLAG_TIMESTAMP) != 0) {
1792  if (receiver_stream->last_ts != 0 && ts_echo != 0 &&
1793  ts_echo != receiver_stream->last_ts)
1794  {
1795  SCLogDebug("%" PRIu64 ": ssn %p: BAD TSECR echo %u recv %u", p->pcap_cnt, ssn, ts_echo,
1796  receiver_stream->last_ts);
1797  return false;
1798  }
1799  } else {
1800  if (receiver_stream->last_ts == 0 && ts_echo != 0) {
1801  SCLogDebug("%" PRIu64 ": ssn %p: BAD TSECR echo %u recv %u", p->pcap_cnt, ssn, ts_echo,
1802  receiver_stream->last_ts);
1803  return false;
1804  }
1805  }
1806  return true;
1807 }
1808 
1809 static void TcpStateQueueInitFromSsnSyn(const TcpSession *ssn, TcpStateQueue *q)
1810 {
1811  DEBUG_VALIDATE_BUG_ON(ssn->state != TCP_SYN_SENT); // TODO
1812  memset(q, 0, sizeof(*q));
1813 
1814  q->seq = ssn->client.isn;
1815  /* SYN won't use wscale yet. So window should be limited to 16 bits. */
1816  DEBUG_VALIDATE_BUG_ON(ssn->server.window > UINT16_MAX);
1817  q->win = (uint16_t)ssn->server.window;
1818 
1819  q->pkt_ts = ssn->client.last_pkt_ts;
1820 
1821  if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
1823  }
1824  if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
1826  q->wscale = ssn->server.wscale;
1827  }
1830  q->ts = ssn->client.last_ts;
1831  }
1832 
1833  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1835 }
1836 
1837 static void TcpStateQueueInitFromPktSyn(const Packet *p, TcpStateQueue *q)
1838 {
1839 #if defined(DEBUG_VALIDATION) || defined(DEBUG)
1840  const TcpSession *ssn = p->flow->protoctx;
1841  BUG_ON(ssn->state != TCP_SYN_SENT);
1842 #endif
1843  memset(q, 0, sizeof(*q));
1844  const TCPHdr *tcph = PacketGetTCP(p);
1845 
1846  q->seq = TCP_GET_RAW_SEQ(tcph);
1847  q->win = TCP_GET_RAW_WINDOW(tcph);
1848  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1849 
1850  if (TCP_GET_SACKOK(p)) {
1852  }
1853  if (TCP_HAS_WSCALE(p)) {
1855  q->wscale = TCP_GET_WSCALE(p);
1856  }
1857  if (TCP_HAS_TS(p)) {
1859  q->ts = TCP_GET_TSVAL(p);
1860  }
1861 
1862 #if defined(DEBUG)
1863  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1865 #endif
1866 }
1867 
1868 static void TcpStateQueueInitFromPktSynAck(const Packet *p, TcpStateQueue *q)
1869 {
1870 #if defined(DEBUG_VALIDATION) || defined(DEBUG)
1871  const TcpSession *ssn = p->flow->protoctx;
1872  BUG_ON(ssn->state != TCP_SYN_SENT);
1873 #endif
1874  memset(q, 0, sizeof(*q));
1875 
1876  const TCPHdr *tcph = PacketGetTCP(p);
1877  q->seq = TCP_GET_RAW_ACK(tcph) - 1;
1878  q->win = TCP_GET_RAW_WINDOW(tcph);
1879  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1880 
1881  if (TCP_GET_SACKOK(p)) {
1883  }
1884  if (TCP_HAS_WSCALE(p)) {
1886  q->wscale = TCP_GET_WSCALE(p);
1887  }
1888  if (TCP_HAS_TS(p)) {
1890  q->ts = TCP_GET_TSECR(p);
1891  }
1892 
1893 #if defined(DEBUG)
1894  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1896 #endif
1897 }
1898 
1899 /** \internal
1900  * \brief Find the Queued SYN that is the same as this SYN/ACK
1901  * \param[in] ignore_ts if true, ignore the timestamp
1902  * \retval q or NULL
1903  *
1904  * \note When `ignore_ts`, the following is accepted: SYN w/o TS, SYN/ACK with TS.
1905  * \note When `ignore_ts` is set, `s` corresponds to the SYN/ACK packet and the
1906  * queue holds the stored SYN packets. */
1907 static const TcpStateQueue *StreamTcp3whsFindSyn(
1908  const TcpSession *ssn, TcpStateQueue *s, TcpStateQueue **ret_tail, const bool ignore_ts)
1909 {
1910  SCLogDebug("ssn %p: search state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, s, s->seq, s->win,
1912 
1913  TcpStateQueue *last = NULL;
1914  for (TcpStateQueue *q = ssn->queue; q != NULL; q = q->next) {
1915  SCLogDebug("ssn %p: queue state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u (last:%s)", ssn, q,
1916  q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS), q->ts,
1917  BOOL2STR(q->next == NULL));
1918 
1919  if (s->flags & STREAMTCP_QUEUE_FLAG_TS) {
1920  if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) && s->ts == q->ts && s->seq == q->seq) {
1921  return q;
1922  }
1923  } else if (ignore_ts) {
1924  if (s->seq == q->seq) {
1925  return q;
1926  }
1927  }
1928  last = q;
1929  }
1930  if (ret_tail)
1931  *ret_tail = last;
1932  return NULL;
1933 }
1934 
1935 /** \internal
1936  * \brief take oldest element in the list and replace it with the new data
1937  */
1938 static void AddAndRotate(TcpSession *ssn, TcpStateQueue *tail, TcpStateQueue *search)
1939 {
1940  TcpStateQueue *old_head = ssn->queue;
1941  TcpStateQueue *new_head = old_head->next;
1942  /* set new head */
1943  ssn->queue = new_head;
1944 
1945  /* old head node is now appended to the list tail */
1946  tail->next = old_head;
1947 
1948  *old_head = *search;
1949  old_head->next = NULL;
1950 }
1951 
1952 static int StreamTcp3whsStoreSyn(TcpSession *ssn, Packet *p)
1953 {
1954  TcpStateQueue search;
1955  TcpStateQueueInitFromSsnSyn(ssn, &search);
1956  TcpStateQueue *tail = NULL;
1957 
1958  /* first see if this is already in our list */
1959  if (ssn->queue != NULL && StreamTcp3whsFindSyn(ssn, &search, &tail, false) != NULL)
1960  return 0;
1961 
1962  if (ssn->queue_len > 0 && ssn->queue_len == stream_config.max_syn_queued) {
1963  DEBUG_VALIDATE_BUG_ON(ssn->queue == NULL);
1964  SCLogDebug("%" PRIu64 ": ssn %p: =~ SYN queue limit reached, rotate", p->pcap_cnt, ssn);
1966 
1967  /* add to the list, evicting the oldest entry */
1968  AddAndRotate(ssn, tail, &search);
1969  return 0;
1970  }
1971 
1972  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1973  SCLogDebug("ssn %p: =~ SYN queue failed: stream memcap reached", ssn);
1974  return -1;
1975  }
1976 
1977  TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1978  if (unlikely(q == NULL)) {
1979  SCLogDebug("ssn %p: =~ SYN queue failed: alloc failed", ssn);
1980  return -1;
1981  }
1982  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1983 
1984  *q = search;
1985  /* put in list */
1986  if (tail) {
1987  tail->next = q;
1988  } else {
1989  DEBUG_VALIDATE_BUG_ON(ssn->queue != NULL);
1990  ssn->queue = q;
1991  }
1992  ssn->queue_len++;
1993  SCLogDebug("%" PRIu64 ": ssn %p: =~ SYN with SEQ %u added (queue_len %u)", p->pcap_cnt, ssn,
1994  q->seq, ssn->queue_len);
1995  return 0;
1996 }
1997 
1998 static inline void StreamTcp3whsStoreSynApplyToSsn(TcpSession *ssn, const TcpStateQueue *q)
1999 {
2000  if (q->flags & STREAMTCP_QUEUE_FLAG_TS) {
2001  ssn->client.last_pkt_ts = q->pkt_ts;
2002  ssn->client.last_ts = q->ts;
2004  SCLogDebug("ssn: %p client.last_ts updated to %u", ssn, ssn->client.last_ts);
2005  }
2006  if (q->flags & STREAMTCP_QUEUE_FLAG_WS) {
2008  ssn->server.wscale = q->wscale;
2009  } else {
2011  ssn->server.wscale = 0;
2012  }
2013  ssn->server.window = q->win;
2014 
2015  if (q->flags & STREAMTCP_QUEUE_FLAG_SACK) {
2017  } else {
2019  }
2020  ssn->client.isn = q->seq;
2021  ssn->client.base_seq = ssn->client.next_seq = ssn->client.isn + 1;
2022  SCLogDebug("ssn: %p client.isn updated to %u", ssn, ssn->client.isn);
2023 }
2024 
2025 /** \internal
2026  * \brief handle SYN/ACK on SYN_SENT state (non-TFO case)
2027  *
2028  * If packet doesn't match the session, check queued states (if any)
2029  *
2030  * \retval true packet is accepted
2031  * \retval false packet is rejected
2032  */
2033 static inline bool StateSynSentCheckSynAck3Whs(TcpSession *ssn, Packet *p, const bool ts_mismatch)
2034 {
2035  const TCPHdr *tcph = PacketGetTCP(p);
2036  const bool seq_match = SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2037  if (seq_match && !ts_mismatch) {
2038  return true;
2039  }
2040 
2041  /* check the queued syns */
2042  if (ssn->queue == NULL) {
2043  goto failure;
2044  }
2045 
2046  TcpStateQueue search;
2047  TcpStateQueueInitFromPktSynAck(p, &search);
2048  SCLogDebug("%" PRIu64 ": ssn %p: SYN/ACK looking for SEQ %u", p->pcap_cnt, ssn, search.seq);
2049 
2050  const TcpStateQueue *q =
2051  StreamTcp3whsFindSyn(ssn, &search, NULL, stream_config.liberal_timestamps);
2052  if (q == NULL) {
2053  SCLogDebug("not found: mismatch");
2054  goto failure;
2055  }
2056 
2057  SCLogDebug("ssn %p: found queued SYN state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q,
2058  q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS), q->ts);
2059  StreamTcp3whsStoreSynApplyToSsn(ssn, q);
2060  return true;
2061 failure:
2062  if (!seq_match) {
2064  } else if (ts_mismatch) {
2066  }
2067  return false;
2068 }
2069 
2070 /** \internal
2071  * \brief handle SYN/ACK on SYN_SENT state (TFO case)
2072  *
2073  * If packet doesn't match the session, check queued states (if any)
2074  *
2075  * \retval true packet is accepted
2076  * \retval false packet is rejected
2077  */
2078 static inline bool StateSynSentCheckSynAckTFO(TcpSession *ssn, Packet *p, const bool ts_mismatch)
2079 {
2080  const TCPHdr *tcph = PacketGetTCP(p);
2081  const bool seq_match_tfo = SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
2082  const bool seq_match_nodata = SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2083  if (seq_match_tfo && !ts_mismatch) {
2084  // ok
2085  } else if (seq_match_nodata && !ts_mismatch) {
2086  ssn->client.next_seq = ssn->client.isn; // reset to ISN
2087  SCLogDebug("ssn %p: (TFO) next_seq reset to isn (%u)", ssn, ssn->client.next_seq);
2090  } else {
2091  /* check the queued syns */
2092  if (ssn->queue == NULL) {
2093  goto failure;
2094  }
2095 
2096  TcpStateQueue search;
2097  TcpStateQueueInitFromPktSynAck(p, &search);
2098  SCLogDebug("%" PRIu64 ": ssn %p: SYN/ACK looking for SEQ %u", p->pcap_cnt, ssn, search.seq);
2099 
2100  const TcpStateQueue *q =
2101  StreamTcp3whsFindSyn(ssn, &search, NULL, stream_config.liberal_timestamps);
2102  if (q == NULL) {
2103  SCLogDebug("not found: mismatch");
2104  goto failure;
2105  }
2106 
2107  SCLogDebug("ssn %p: found queued SYN state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q,
2108  q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS), q->ts);
2109  StreamTcp3whsStoreSynApplyToSsn(ssn, q);
2110  }
2112  return true;
2113 failure:
2114  if (!seq_match_tfo && !seq_match_nodata) {
2116  } else if (ts_mismatch) {
2118  }
2119  return false;
2120 }
2121 
2122 /**
2123  * \brief Function to handle the TCP_SYN_SENT state. The function handles
2124  * SYN, SYN/ACK, RST packets and correspondingly changes the connection
2125  * state.
2126  *
2127  * \param tv Thread Variable containing input/output queue, cpu affinity
2128  * \param p Packet which has to be handled in this TCP state.
2129  * \param stt Stream Thread module registered to handle the stream handling
2130  */
2131 
2132 static int StreamTcpPacketStateSynSent(
2133  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
2134 {
2135  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
2136  const TCPHdr *tcph = PacketGetTCP(p);
2137 
2138  SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ? "toclient" : "toserver");
2139 
2140  /* common case: SYN/ACK from server to client */
2141  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOCLIENT(p)) {
2142  SCLogDebug("%" PRIu64 ": ssn %p: SYN/ACK on SYN_SENT state for packet %" PRIu64,
2143  p->pcap_cnt, ssn, p->pcap_cnt);
2144  /* if timestamps are liberal, allow a SYN/ACK with TS even if the SYN
2145  * had none (violates RFC 7323, see bug #4702). */
2146  const bool ts_mismatch =
2147  !(stream_config.liberal_timestamps || StateSynSentValidateTimestamp(ssn, p));
2148  SCLogDebug("ts_mismatch %s", BOOL2STR(ts_mismatch));
2149 
2150  if (!(TCP_HAS_TFO(p) || (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN))) {
2151  if (StateSynSentCheckSynAck3Whs(ssn, p, ts_mismatch)) {
2152  SCLogDebug("ssn %p: ACK match, packet ACK %" PRIu32 " == "
2153  "%" PRIu32 " from stream",
2154  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2155  } else {
2156  SCLogDebug("ssn %p: (3WHS) ACK mismatch, packet ACK %" PRIu32 " != "
2157  "%" PRIu32 " from stream",
2158  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
2159  return -1;
2160  }
2161  } else {
2162  if (StateSynSentCheckSynAckTFO(ssn, p, ts_mismatch)) {
2163  SCLogDebug("ssn %p: (TFO) ACK matches next_seq, packet ACK %" PRIu32 " == "
2164  "%" PRIu32 " from stream",
2165  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
2166  } else {
2167  SCLogDebug("ssn %p: (TFO) ACK mismatch, packet ACK %" PRIu32 " != "
2168  "%" PRIu32 " from stream",
2169  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
2170  return -1;
2171  }
2172  }
2173  /* clear ssn->queue on state change: TcpSession can be reused by SYN/ACK */
2174  StreamTcp3wsFreeQueue(ssn);
2175 
2176  StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
2177  SCLogDebug("%" PRIu64 ": ssn %p: SYN/ACK on SYN_SENT state: accepted", p->pcap_cnt, ssn);
2178  return 0;
2179 
2180  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOSERVER(p)) {
2181 
2182  if (!(ssn->flags & STREAMTCP_FLAG_4WHS)) {
2184  SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
2185  return -1;
2186  }
2187 
2188  SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
2189 
2190  /* Check if the SYN/ACK packet ack's the earlier
2191  * received SYN packet. */
2192  if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.isn + 1))) {
2194 
2195  SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %" PRIu32 ""
2196  " != %" PRIu32 " from stream",
2197  ssn, TCP_GET_RAW_ACK(tcph), ssn->server.isn + 1);
2198  return -1;
2199  }
2200 
2201  /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
2202  * packet. */
2203  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn))) {
2205 
2206  SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %" PRIu32 ""
2207  " != %" PRIu32 " from *first* SYN pkt",
2208  ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.isn);
2209  return -1;
2210  }
2211 
2212  /* update state */
2213  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
2214  SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
2215 
2216  /* sequence number & window */
2217  ssn->client.isn = TCP_GET_RAW_SEQ(tcph);
2219  ssn->client.next_seq = ssn->client.isn + 1;
2220 
2221  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2222  SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn, ssn->client.window);
2223 
2224  /* Set the timestamp values used to validate the timestamp of
2225  * received packets. */
2226  if ((TCP_HAS_TS(p)) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) {
2227  ssn->client.last_ts = TCP_GET_TSVAL(p);
2228  SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32 " "
2229  "ssn->server.last_ts %" PRIu32 "",
2230  ssn, ssn->client.last_ts, ssn->server.last_ts);
2232  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2233  if (ssn->client.last_ts == 0)
2235  } else {
2236  ssn->server.last_ts = 0;
2237  ssn->client.last_ts = 0;
2239  }
2240 
2241  ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
2242  ssn->client.last_ack = ssn->client.isn + 1;
2243 
2244  /** check for the presense of the ws ptr to determine if we
2245  * support wscale at all */
2246  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && (TCP_HAS_WSCALE(p))) {
2247  ssn->server.wscale = TCP_GET_WSCALE(p);
2248  } else {
2249  ssn->server.wscale = 0;
2250  }
2251 
2252  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) && TCP_GET_SACKOK(p)) {
2253  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2254  SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
2255  }
2256 
2257  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2258  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2259  SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win);
2260  SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win);
2261  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2262  "ssn->client.next_seq %" PRIu32 ", "
2263  "ssn->client.last_ack %" PRIu32 " "
2264  "(ssn->server.last_ack %" PRIu32 ")",
2265  ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack,
2266  ssn->server.last_ack);
2267 
2268  /* done here */
2269  return 0;
2270  }
2271 
2272  /* check for bad responses */
2273  if (!StateSynSentValidateTimestamp(ssn, p)) {
2275  return -1;
2276  }
2277 
2278  /* RST */
2279  if (tcph->th_flags & TH_RST) {
2280 
2281  if (!StreamTcpValidateRst(ssn, p))
2282  return -1;
2283 
2284  if (PKT_IS_TOSERVER(p)) {
2285  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn) &&
2286  SEQ_EQ(TCP_GET_RAW_WINDOW(tcph), 0) &&
2287  SEQ_EQ(TCP_GET_RAW_ACK(tcph), (ssn->client.isn + 1))) {
2288  SCLogDebug("ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
2290  StreamTcpCloseSsnWithReset(p, ssn);
2291  StreamTcp3wsFreeQueue(ssn);
2292  }
2293  } else {
2295  SCLogDebug("ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
2296  StreamTcpCloseSsnWithReset(p, ssn);
2297  StreamTcp3wsFreeQueue(ssn);
2298  }
2299 
2300  /* FIN */
2301  } else if (tcph->th_flags & TH_FIN) {
2302  /** \todo */
2303 
2304  } else if (tcph->th_flags & TH_SYN) {
2305  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
2306  if (ssn->flags & STREAMTCP_FLAG_4WHS) {
2307  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
2308  "4WHS SYN", ssn);
2309  }
2310 
2311  if (PKT_IS_TOCLIENT(p)) {
2312  /** a SYN only packet in the opposite direction could be:
2313  * http://www.breakingpointsystems.com/community/blog/tcp-
2314  * portals-the-three-way-handshake-is-a-lie
2315  *
2316  * \todo improve resetting the session */
2317 
2318  /* indicate that we're dealing with 4WHS here */
2319  ssn->flags |= STREAMTCP_FLAG_4WHS;
2320  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
2321 
2322  /* set the sequence numbers and window for server
2323  * We leave the ssn->client.isn in place as we will
2324  * check the SYN/ACK pkt with that.
2325  */
2326  ssn->server.isn = TCP_GET_RAW_SEQ(tcph);
2328  ssn->server.next_seq = ssn->server.isn + 1;
2329 
2330  /* Set the stream timestamp value, if packet has timestamp
2331  * option enabled. */
2332  if (TCP_HAS_TS(p)) {
2333  ssn->server.last_ts = TCP_GET_TSVAL(p);
2334  SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
2335 
2336  if (ssn->server.last_ts == 0)
2338  ssn->server.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2340  }
2341 
2342  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2343  if (TCP_HAS_WSCALE(p)) {
2345  ssn->server.wscale = TCP_GET_WSCALE(p);
2346  } else {
2348  ssn->server.wscale = 0;
2349  }
2350 
2351  if (TCP_GET_SACKOK(p)) {
2353  } else {
2355  }
2356 
2357  SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
2358  "ssn->server.next_seq %" PRIu32 ", "
2359  "ssn->server.last_ack %"PRIu32"", ssn,
2360  ssn->server.isn, ssn->server.next_seq,
2361  ssn->server.last_ack);
2362  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2363  "ssn->client.next_seq %" PRIu32 ", "
2364  "ssn->client.last_ack %"PRIu32"", ssn,
2365  ssn->client.isn, ssn->client.next_seq,
2366  ssn->client.last_ack);
2367  } else if (PKT_IS_TOSERVER(p)) {
2368  /* on a SYN resend we queue up the SYN's until a SYN/ACK moves the state
2369  * to SYN_RECV. We update the ssn to the most recent, as it is most likely
2370  * to be correct. */
2371 
2372  TcpStateQueue syn_pkt, syn_ssn;
2373  TcpStateQueueInitFromPktSyn(p, &syn_pkt);
2374  TcpStateQueueInitFromSsnSyn(ssn, &syn_ssn);
2375 
2376  if (memcmp(&syn_pkt, &syn_ssn, sizeof(TcpStateQueue)) != 0) {
2377  /* store the old session settings */
2378  StreamTcp3whsStoreSyn(ssn, p);
2379  SCLogDebug("ssn %p: Retransmitted SYN. Updating ssn from packet %" PRIu64
2380  ". Stored previous state",
2381  ssn, p->pcap_cnt);
2382  }
2383  StreamTcp3whsStoreSynApplyToSsn(ssn, &syn_pkt);
2384  }
2385  } else if (tcph->th_flags & TH_ACK) {
2386  /* Handle the asynchronous stream, when we receive a SYN packet
2387  and now instead of receiving a SYN/ACK we receive a ACK from the
2388  same host, which sent the SYN, this suggests the ASYNC streams.*/
2390  return 0;
2391 
2392  /* we are in ASYNC (one side) mode now. */
2393 
2394  /* one side async means we won't see a SYN/ACK, so we can
2395  * only check the SYN. */
2396  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq))) {
2398 
2399  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2400  "%" PRIu32 " from stream",
2401  ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq);
2402  return -1;
2403  }
2404 
2405  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2406  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2407  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2408  StreamTcp3wsFreeQueue(ssn);
2409 
2410  ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2411  ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
2412  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2413 
2414  /* Set the server side parameters */
2415  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
2417  ssn->server.next_seq = ssn->server.isn + 1;
2418  ssn->server.last_ack = ssn->server.next_seq;
2419  ssn->server.next_win = ssn->server.last_ack;
2420 
2421  SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
2422  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2423  "ssn->client.next_seq %" PRIu32 "",
2424  ssn, TCP_GET_RAW_SEQ(tcph), p->payload_len, TCP_GET_RAW_SEQ(tcph) + p->payload_len,
2425  ssn->client.next_seq);
2426 
2427  /* if SYN had wscale, assume it to be supported. Otherwise
2428  * we know it not to be supported. */
2429  if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
2430  ssn->client.wscale = TCP_WSCALE_MAX;
2431  }
2432 
2433  /* Set the timestamp values used to validate the timestamp of
2434  * received packets.*/
2435  if (TCP_HAS_TS(p) &&
2437  {
2440  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2441  } else {
2442  ssn->client.last_ts = 0;
2444  }
2445 
2446  if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
2447  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2448  }
2449 
2450  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2451 
2452  } else {
2453  SCLogDebug("ssn %p: default case", ssn);
2454  }
2455 
2456  return 0;
2457 }
2458 
2459 /**
2460  * \brief Function to handle the TCP_SYN_RECV state. The function handles
2461  * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
2462  * the connection state.
2463  *
2464  * \param tv Thread Variable containing input/output queue, cpu affinity
2465  * \param p Packet which has to be handled in this TCP state.
2466  * \param stt Stream Thread module registered to handle the stream handling
2467  *
2468  * \retval 0 ok
2469  * \retval -1 error
2470  */
2471 
2472 static int StreamTcpPacketStateSynRecv(
2473  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
2474 {
2475  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
2476  const TCPHdr *tcph = PacketGetTCP(p);
2477 
2478  if (tcph->th_flags & TH_RST) {
2479  if (!StreamTcpValidateRst(ssn, p))
2480  return -1;
2481 
2482  bool reset = true;
2483  /* After receiving the RST in SYN_RECV state and if detection
2484  evasion flags has been set, then the following operating
2485  systems will not closed the connection. As they consider the
2486  packet as stray packet and not belonging to the current
2487  session, for more information check
2488  http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
2490  if (PKT_IS_TOSERVER(p)) {
2491  if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
2492  (ssn->server.os_policy == OS_POLICY_OLD_LINUX) ||
2494  {
2495  reset = false;
2496  SCLogDebug("Detection evasion has been attempted, so"
2497  " not resetting the connection !!");
2498  }
2499  } else {
2500  if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
2501  (ssn->client.os_policy == OS_POLICY_OLD_LINUX) ||
2503  {
2504  reset = false;
2505  SCLogDebug("Detection evasion has been attempted, so"
2506  " not resetting the connection !!");
2507  }
2508  }
2509  }
2510 
2511  if (reset) {
2512  StreamTcpCloseSsnWithReset(p, ssn);
2513 
2514  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2515  StreamTcpHandleTimestamp(ssn, p);
2516  }
2517  }
2518 
2519  } else if (tcph->th_flags & TH_FIN) {
2520  /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
2521  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2522  if (!StreamTcpValidateTimestamp(ssn, p))
2523  return -1;
2524  }
2525 
2526  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
2527  return -1;
2528 
2529  /* SYN/ACK */
2530  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
2531  SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
2532 
2533  if (PKT_IS_TOSERVER(p)) {
2534  SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
2535 
2537  return -1;
2538  }
2539 
2540  /* Check if the SYN/ACK packets ACK matches the earlier
2541  * received SYN/ACK packet. */
2542  if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack))) {
2543  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
2544  "%" PRIu32 " from stream",
2545  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2546 
2548  return -1;
2549  }
2550 
2551  /* Check if the SYN/ACK packet SEQ the earlier
2552  * received SYN/ACK packet, server resend with different ISN. */
2553  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.isn))) {
2554  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2555  "%" PRIu32 " from stream",
2556  ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.isn);
2557 
2558  if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
2559  return -1;
2560  SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
2561  }
2562 
2563  } else if (tcph->th_flags & TH_SYN) {
2564  SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
2565 
2566  if (PKT_IS_TOCLIENT(p)) {
2567  SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
2568 
2570  return -1;
2571  }
2572 
2573  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn))) {
2574  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
2575 
2577  return -1;
2578  }
2579 
2580  } else if (tcph->th_flags & TH_ACK) {
2581  if (ssn->queue_len) {
2582  SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
2583  TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
2584  if (q != NULL) {
2585  SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
2586  StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
2587  } else {
2588  SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
2589  }
2590  }
2591 
2592 
2593  /* If the timestamp option is enabled for both the streams, then
2594  * validate the received packet timestamp value against the
2595  * stream->last_ts. If the timestamp is valid then process the
2596  * packet normally otherwise the drop the packet (RFC 1323)*/
2597  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2598  if (!(StreamTcpValidateTimestamp(ssn, p))) {
2599  return -1;
2600  }
2601  }
2602 
2603  if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) {
2604  SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
2605 
2606  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2607  SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
2609  return -1;
2610  }
2611 
2612  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2613  SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
2615  return -1;
2616  }
2617 
2618  SCLogDebug("4WHS normal pkt");
2619  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2620  "%" PRIu32 ", ACK %" PRIu32 "",
2621  ssn, p->payload_len, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph));
2622 
2623  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2624  StreamTcpHandleTimestamp(ssn, p);
2625  }
2626 
2627  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_RAW_ACK(tcph));
2628  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2629  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2630  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2631 
2632  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2633  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2634 
2635  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2636 
2637  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
2638  "ssn->client.last_ack %"PRIu32"", ssn,
2639  ssn->client.next_win, ssn->client.last_ack);
2640  return 0;
2641  }
2642 
2643  bool ack_indicates_missed_3whs_ack_packet = false;
2644  /* Check if the ACK received is in right direction. But when we have
2645  * picked up a mid stream session after missing the initial SYN pkt,
2646  * in this case the ACK packet can arrive from either client (normal
2647  * case) or from server itself (asynchronous streams). Therefore
2648  * the check has been avoided in this case */
2649  if (PKT_IS_TOCLIENT(p)) {
2650  /* special case, handle 4WHS, so SYN/ACK in the opposite
2651  * direction */
2653  SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
2654  "pickup session",ssn);
2655  /* fall through */
2656  } else if (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) {
2657  SCLogDebug("ssn %p: ACK received on TFO session",ssn);
2658  /* fall through */
2659 
2660  } else {
2661  /* if we missed traffic between the S/SA and the current
2662  * 'wrong direction' ACK, we could end up here. In IPS
2663  * reject it. But in IDS mode we continue.
2664  *
2665  * IPS rejects as it should see all packets, so pktloss
2666  * should lead to retransmissions. As this can also be
2667  * pattern for MOTS/MITM injection attacks, we need to be
2668  * careful.
2669  */
2670  if (StreamTcpInlineMode()) {
2671  if (p->payload_len > 0 && SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack) &&
2672  SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq)) {
2673  /* packet loss is possible but unlikely here */
2674  SCLogDebug("ssn %p: possible data injection", ssn);
2676  return -1;
2677  }
2678 
2679  SCLogDebug("ssn %p: ACK received in the wrong direction",
2680  ssn);
2682  return -1;
2683  }
2684  ack_indicates_missed_3whs_ack_packet = true;
2685  }
2686  }
2687 
2688  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
2689  ", ACK %" PRIu32 "",
2690  ssn, p->payload_len, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph));
2691 
2692  /* Check both seq and ack number before accepting the packet and
2693  changing to ESTABLISHED state */
2694  if ((SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) &&
2695  SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.next_seq)) {
2696  SCLogDebug("normal pkt");
2697 
2698  /* process the packet normal, No Async streams :) */
2699 
2700  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2701  StreamTcpHandleTimestamp(ssn, p);
2702  }
2703 
2704  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_RAW_ACK(tcph));
2705  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2706  ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2707 
2708  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2709 
2710  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2711  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2712  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2713  ssn->server.next_win = ssn->server.last_ack +
2714  ssn->server.window;
2715  if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
2716  /* window scaling for midstream pickups, we can't do much
2717  * other than assume that it's set to the max value: 14 */
2718  ssn->server.wscale = TCP_WSCALE_MAX;
2719  ssn->client.wscale = TCP_WSCALE_MAX;
2720  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2721  }
2722  }
2723 
2724  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2725  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2726 
2727  /* special case: normally the packet following the 3whs is
2728  * considered flow established, but with data we need it to
2729  * be established now. This can happen if the original ACK was
2730  * lost. */
2731  if (p->payload_len) {
2733  }
2734 
2735  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2736 
2737  /* If asynchronous stream handling is allowed then set the session,
2738  if packet's seq number is equal the expected seq no.*/
2739  } else if (stream_config.async_oneside &&
2740  (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2741  /*set the ASYNC flag used to indicate the session as async stream
2742  and helps in relaxing the windows checks.*/
2743  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2744  ssn->server.next_seq += p->payload_len;
2745  ssn->server.last_ack = TCP_GET_RAW_SEQ(tcph);
2746 
2747  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2748  ssn->client.last_ack = TCP_GET_RAW_ACK(tcph);
2749 
2750  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2751  StreamTcpHandleTimestamp(ssn, p);
2752  }
2753 
2754  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2755  ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2756  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2757  /* window scaling for midstream pickups, we can't do much
2758  * other than assume that it's set to the max value: 14 */
2759  ssn->server.wscale = TCP_WSCALE_MAX;
2760  ssn->client.wscale = TCP_WSCALE_MAX;
2761  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2762  }
2763 
2764  SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
2765  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2766  "ssn->server.next_seq %" PRIu32,
2767  ssn, TCP_GET_RAW_SEQ(tcph), p->payload_len,
2768  TCP_GET_RAW_SEQ(tcph) + p->payload_len, ssn->server.next_seq);
2769 
2770  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2771  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2772 
2773  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2774  /* Upon receiving the packet with correct seq number and wrong
2775  ACK number, it causes the other end to send RST. But some target
2776  system (Linux & solaris) does not RST the connection, so it is
2777  likely to avoid the detection */
2778  } else if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) {
2780  SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
2781  ssn);
2782 
2784  return -1;
2785 
2786  /* SYN/ACK followed by more TOCLIENT suggesting packet loss */
2787  } else if (PKT_IS_TOCLIENT(p) && !StreamTcpInlineMode() &&
2788  SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2789  SEQ_GT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
2790  SCLogDebug("ssn %p: ACK for missing data", ssn);
2791 
2792  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2793  StreamTcpHandleTimestamp(ssn, p);
2794  }
2795 
2796  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_RAW_ACK(tcph));
2797 
2798  ssn->server.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
2799  SCLogDebug("ssn %p: ACK for missing data: ssn->server.next_seq %u", ssn,
2800  ssn->server.next_seq);
2801  ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2802 
2803  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2804 
2805  ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2806  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2807 
2808  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2809  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2810 
2811  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2812 
2813  /* if we get a packet with a proper ack, but a seq that is beyond
2814  * next_seq but in-window, we probably missed some packets */
2815  } else if (SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2816  SEQ_LEQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_win) &&
2817  SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.next_seq)) {
2818  SCLogDebug("ssn %p: ACK for missing data", ssn);
2819 
2820  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2821  StreamTcpHandleTimestamp(ssn, p);
2822  }
2823 
2824  ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
2825  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_RAW_ACK(tcph));
2826 
2827  SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
2828  ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2829  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2830 
2831  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2832  ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2833  ssn->server.next_win = ssn->server.last_ack +
2834  ssn->server.window;
2835  /* window scaling for midstream pickups, we can't do much
2836  * other than assume that it's set to the max value: 14 */
2837  ssn->server.wscale = TCP_WSCALE_MAX;
2838  ssn->client.wscale = TCP_WSCALE_MAX;
2839  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2840  }
2841 
2842  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2843  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2844 
2845  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2846 
2847  /* toclient packet: after having missed the 3whs's final ACK */
2848  } else if ((ack_indicates_missed_3whs_ack_packet ||
2849  (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN)) &&
2850  SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack) &&
2851  SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq)) {
2852  if (ack_indicates_missed_3whs_ack_packet) {
2853  SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2854  } else {
2855  SCLogDebug("ssn %p: (TFO) expected packet fits perfectly after SYN/ACK", ssn);
2856  }
2857 
2858  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_RAW_SEQ(tcph) + p->payload_len));
2859 
2860  ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2861  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2862 
2863  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2864  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2865 
2866  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2867 
2868  } else {
2869  SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2870 
2872  return -1;
2873  }
2874 
2875  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2876  "ssn->server.last_ack %"PRIu32"", ssn,
2877  ssn->server.next_win, ssn->server.last_ack);
2878  } else {
2879  SCLogDebug("ssn %p: default case", ssn);
2880  }
2881 
2882  return 0;
2883 }
2884 
2885 /**
2886  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2887  * sent by the client to server. The function handles
2888  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2889  * the reassembly.
2890  *
2891  * Timestamp has already been checked at this point.
2892  *
2893  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2894  * \param ssn Pointer to the current TCP session
2895  * \param p Packet which has to be handled in this TCP state.
2896  * \param stt Stream Thread module registered to handle the stream handling
2897  */
2898 static int HandleEstablishedPacketToServer(
2899  ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt)
2900 {
2901  const TCPHdr *tcph = PacketGetTCP(p);
2902  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
2903  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
2904  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
2905 
2906  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2907  "ACK %" PRIu32 ", WIN %" PRIu16 "",
2908  ssn, p->payload_len, seq, ack, window);
2909 
2910  const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
2911  if (has_ack) {
2912  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TC) && ack == ssn->server.next_seq + 1) {
2913  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2915 
2916  } else if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2917  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2919  return -1;
2920  }
2921  }
2922 
2923  /* check for Keep Alive */
2924  if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->client.next_seq - 1))) {
2925  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2926 
2927  /* normal pkt */
2928  } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->client.last_ack))) {
2929  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2930  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2931  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2932  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2933  "%" PRIu32 "(%" PRIu32 ")",
2934  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2935  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2936 
2937  /* update the last_ack to current seq number as the session is
2938  * async and other stream is not updating it anymore :( */
2939  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2940 
2941  } else if (SEQ_EQ(ssn->client.next_seq, seq) && stream_config.async_oneside &&
2942  (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2943  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2944  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2945  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2946  "%" PRIu32 "(%" PRIu32 ")",
2947  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2948  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2949 
2950  /* it seems we missed SYN and SYN/ACK packets of this session.
2951  * Update the last_ack to current seq number as the session
2952  * is async and other stream is not updating it anymore :( */
2953  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2954  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2955 
2956  } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2958  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2959  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2960  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2961  "%" PRIu32 "(%" PRIu32 ")",
2962  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2963  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2964 
2965  /* it seems we missed SYN and SYN/ACK packets of this session.
2966  * Update the last_ack to current seq number as the session
2967  * is async and other stream is not updating it anymore :(*/
2968  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2969  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2970 
2971  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2972  * In this case we do accept the data before last_ack if it is (partly)
2973  * beyond next seq */
2974  } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
2975  SEQ_GT((seq + p->payload_len), ssn->client.next_seq)) {
2976  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2977  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
2978  " acked data that we haven't seen before",
2979  ssn, seq, p->payload_len, ssn->client.last_ack, ssn->client.next_seq);
2980  } else {
2981  SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
2982  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2983  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2984  "%" PRIu32 "(%" PRIu32 ")",
2985  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2986  ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2987 
2988  SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
2990  return -1;
2991  }
2992  }
2993 
2994  int zerowindowprobe = 0;
2995  /* zero window probe */
2996  if (p->payload_len == 1 && seq == ssn->client.next_seq && ssn->client.window == 0) {
2997  SCLogDebug("ssn %p: zero window probe", ssn);
2998  zerowindowprobe = 1;
3000  ssn->flags |= STREAMTCP_FLAG_ZWP_TS;
3001  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3002 
3003  } else if (SEQ_GEQ(seq + p->payload_len, ssn->client.next_seq)) {
3004  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3005  }
3006 
3007  /* in window check */
3008  if (zerowindowprobe) {
3009  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
3010  } else if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
3012  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
3013  "%" PRIu32 "",
3014  ssn, seq, ssn->client.next_win);
3015 
3016  ssn->server.window = window << ssn->server.wscale;
3017  SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
3018  ssn->server.window);
3019 
3020  /* Check if the ACK value is sane and inside the window limit */
3021  if (tcph->th_flags & TH_ACK) {
3022  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3023  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
3024  SEQ_GT(ssn->server.last_ack, ssn->server.next_seq)) {
3027  }
3028  }
3029 
3030  SCLogDebug(
3031  "ack %u last_ack %u next_seq %u", ack, ssn->server.last_ack, ssn->server.next_seq);
3032 
3033  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3034  StreamTcpHandleTimestamp(ssn, p);
3035  }
3036 
3038 
3039  /* update next_win */
3040  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3041 
3042  /* handle data (if any) */
3043  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3044 
3045  } else {
3046  SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
3047  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
3048  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
3049  "%" PRIu32 "(%" PRIu32 ")",
3050  ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
3051  ssn->client.next_win, (seq + p->payload_len) - ssn->client.next_win);
3052  SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
3053  StreamTcpSackedSize(&ssn->client));
3055  return -1;
3056  }
3057  return 0;
3058 }
3059 
3060 /**
3061  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
3062  * sent by the server to client. The function handles
3063  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
3064  * the reassembly
3065  *
3066  * Timestamp has already been checked at this point.
3067  *
3068  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3069  * \param ssn Pointer to the current TCP session
3070  * \param p Packet which has to be handled in this TCP state.
3071  * \param stt Stream Thread module registered to handle the stream handling
3072  */
3073 static int HandleEstablishedPacketToClient(
3074  ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt)
3075 {
3076  const TCPHdr *tcph = PacketGetTCP(p);
3077  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3078  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3079  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3080 
3081  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
3082  " ACK %" PRIu32 ", WIN %" PRIu16 "",
3083  ssn, p->payload_len, seq, ack, window);
3084 
3085  const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
3086  if (has_ack) {
3087  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TS) && ack == ssn->client.next_seq + 1) {
3088  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
3090 
3091  } else if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3092  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3094  return -1;
3095  }
3096  }
3097 
3098  /* To get the server window value from the servers packet, when connection
3099  is picked up as midstream */
3100  if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
3102  {
3103  ssn->server.window = window << ssn->server.wscale;
3104  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
3106  SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
3107  "%" PRIu32 "", ssn, ssn->server.next_win);
3108  }
3109 
3110  /* check for Keep Alive */
3111  if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->server.next_seq - 1))) {
3112  SCLogDebug("ssn %p: pkt is keep alive", ssn);
3113 
3114  /* normal pkt */
3115  } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->server.last_ack))) {
3116  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
3117 
3118  SCLogDebug("ssn %p: client => Asynchronous stream, packet SEQ"
3119  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
3120  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
3121  " %" PRIu32 "(%" PRIu32 ")",
3122  ssn, seq, p->payload_len, seq + p->payload_len, ssn->server.last_ack,
3123  ssn->server.next_win, seq + p->payload_len - ssn->server.next_win);
3124 
3125  ssn->server.last_ack = seq;
3126 
3127  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
3128  * In this case we do accept the data before last_ack if it is (partly)
3129  * beyond next seq */
3130  } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
3131  SEQ_GT((seq + p->payload_len), ssn->server.next_seq)) {
3132  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
3133  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
3134  " acked data that we haven't seen before",
3135  ssn, seq, p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
3136  } else {
3137  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
3138  " before last_ack %" PRIu32 ". next_seq %" PRIu32,
3139  ssn, seq, p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
3141  return -1;
3142  }
3143  }
3144 
3145  int zerowindowprobe = 0;
3146  /* zero window probe */
3147  if (p->payload_len == 1 && seq == ssn->server.next_seq && ssn->server.window == 0) {
3148  SCLogDebug("ssn %p: zero window probe", ssn);
3149  zerowindowprobe = 1;
3151  ssn->flags |= STREAMTCP_FLAG_ZWP_TC;
3152 
3153  /* accept the segment */
3154  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3155 
3156  } else if (SEQ_GEQ(seq + p->payload_len, ssn->server.next_seq)) {
3157  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3158  }
3159 
3160  if (zerowindowprobe) {
3161  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
3162  } else if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
3164  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
3165  "%" PRIu32 "",
3166  ssn, seq, ssn->server.next_win);
3167  ssn->client.window = window << ssn->client.wscale;
3168  SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
3169  ssn->client.window);
3170 
3171  if (tcph->th_flags & TH_ACK) {
3172  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3173  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
3174  SEQ_GT(ssn->client.last_ack, ssn->client.next_seq)) {
3177  }
3178  }
3179 
3180  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3181  StreamTcpHandleTimestamp(ssn, p);
3182  }
3183 
3185 
3186  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3187 
3188  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3189  } else {
3190  SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
3191  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
3192  " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
3193  "%" PRIu32 "(%" PRIu32 ")",
3194  ssn, seq, p->payload_len, seq + p->payload_len, ssn->server.last_ack,
3195  ssn->server.next_win, seq + p->payload_len - ssn->server.next_win);
3197  return -1;
3198  }
3199  return 0;
3200 }
3201 
3202 static bool StreamTcpPacketIsZeroWindowProbeAck(const TcpSession *ssn, const Packet *p)
3203 {
3204  const TCPHdr *tcph = PacketGetTCP(p);
3205  if (ssn->state < TCP_ESTABLISHED)
3206  return false;
3207  if (p->payload_len != 0)
3208  return false;
3209  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3210  return false;
3211 
3212  const TcpStream *snd, *rcv;
3213  if (PKT_IS_TOCLIENT(p)) {
3214  snd = &ssn->server;
3215  rcv = &ssn->client;
3216  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TS))
3217  return false;
3218  } else {
3219  snd = &ssn->client;
3220  rcv = &ssn->server;
3221  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TC))
3222  return false;
3223  }
3224 
3225  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3226  if (pkt_win != 0)
3227  return false;
3228  if (pkt_win != rcv->window)
3229  return false;
3230 
3231  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3232  return false;
3233  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3234  return false;
3235  SCLogDebug("ssn %p: packet %" PRIu64 " is a Zero Window Probe ACK", ssn, p->pcap_cnt);
3236  return true;
3237 }
3238 
3239 /** \internal
3240  * \brief check if an ACK packet is a dup-ACK
3241  */
3242 static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p)
3243 {
3244  const TCPHdr *tcph = PacketGetTCP(p);
3245  if (ssn->state < TCP_ESTABLISHED)
3246  return false;
3247  if (p->payload_len != 0)
3248  return false;
3249  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3250  return false;
3251 
3252  const TcpStream *snd, *rcv;
3253  if (PKT_IS_TOCLIENT(p)) {
3254  snd = &ssn->server;
3255  rcv = &ssn->client;
3256  } else {
3257  snd = &ssn->client;
3258  rcv = &ssn->server;
3259  }
3260 
3261  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3262  if (pkt_win == 0 || rcv->window == 0)
3263  return false;
3264  if (pkt_win != rcv->window)
3265  return false;
3266 
3267  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3268  return false;
3269  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3270  return false;
3271 
3272  SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn,
3273  p->pcap_cnt, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph), pkt_win, snd->next_seq,
3274  snd->last_ack, rcv->window, snd->next_seq, rcv->last_ack, rcv->window);
3275  return true;
3276 }
3277 
3278 /** \internal
3279  * \brief check if a ACK packet is outdated so processing can be fast tracked
3280  *
3281  * Consider a packet outdated ack if:
3282  * - state is >= ESTABLISHED
3283  * - ACK < last_ACK
3284  * - SACK acks nothing new
3285  * - packet has no data
3286  * - SEQ == next_SEQ
3287  * - flags has ACK set but don't contain SYN/FIN/RST
3288  *
3289  * \todo the most likely explanation for this packet is that we already
3290  * accepted a "newer" ACK. We will not consider an outdated timestamp
3291  * option an issue for this packet, but we should probably still
3292  * check if the ts isn't too far off.
3293  */
3294 static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p)
3295 {
3296  const TCPHdr *tcph = PacketGetTCP(p);
3297  if (ssn->state < TCP_ESTABLISHED)
3298  return false;
3299  if (p->payload_len != 0)
3300  return false;
3301  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3302  return false;
3303 
3304  /* lets see if this is a packet that is entirely eclipsed by earlier ACKs */
3305  if (PKT_IS_TOSERVER(p)) {
3306  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
3307  SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->server.last_ack)) {
3308  if (!TCP_HAS_SACK(p)) {
3309  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3310  ssn->client.next_seq);
3311  return true;
3312  }
3313 
3314  if (StreamTcpSackPacketIsOutdated(&ssn->server, p)) {
3315  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3316  ssn->client.next_seq);
3317  return true;
3318  }
3319  }
3320  } else {
3321  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq) &&
3322  SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
3323  if (!TCP_HAS_SACK(p)) {
3324  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3325  ssn->client.next_seq);
3326  return true;
3327  }
3328 
3329  if (StreamTcpSackPacketIsOutdated(&ssn->client, p)) {
3330  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3331  ssn->client.next_seq);
3332  return true;
3333  }
3334  }
3335  }
3336  return false;
3337 }
3338 
3339 /** \internal
3340  * \brief check if packet is before ack'd windows
3341  * If packet is before last ack, we will not accept it
3342  *
3343  * \retval 0 not spurious retransmission
3344  * \retval 1 before last_ack, after base_seq
3345  * \retval 2 before last_ack and base_seq
3346  */
3347 static int StreamTcpPacketIsSpuriousRetransmission(const TcpSession *ssn, Packet *p)
3348 {
3349  const TcpStream *stream;
3350  if (PKT_IS_TOCLIENT(p)) {
3351  stream = &ssn->server;
3352  } else {
3353  stream = &ssn->client;
3354  }
3355  if (p->payload_len == 0)
3356  return 0;
3357 
3358  const TCPHdr *tcph = PacketGetTCP(p);
3359  /* take base_seq into account to avoid edge cases where last_ack might be
3360  * too far ahead during heavy packet loss */
3361  if (!(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3362  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->base_seq))) {
3363  SCLogDebug(
3364  "ssn %p: spurious retransmission; packet entirely before base_seq: SEQ %u(%u) "
3365  "last_ack %u base_seq %u",
3366  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3367  stream->last_ack, stream->base_seq);
3369  return 2;
3370  }
3371  }
3372 
3373  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack))) {
3374  SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) "
3375  "last_ack %u",
3376  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3377  stream->last_ack);
3379  return 1;
3380  }
3381 
3382  SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ "
3383  "%u(%u) last_ack %u, base_seq %u",
3384  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack,
3385  stream->base_seq);
3386  return 0;
3387 }
3388 
3389 /**
3390  * \brief Function to handle the TCP_ESTABLISHED state. The function handles
3391  * ACK, FIN, RST packets and correspondingly changes the connection
3392  * state. The function handles the data inside packets and call
3393  * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
3394  *
3395  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3396  * \param p Packet which has to be handled in this TCP state.
3397  * \param stt Stream Thread module registered to handle the stream handling
3398  */
3399 
3400 static int StreamTcpPacketStateEstablished(
3401  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3402 {
3403  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3404  const TCPHdr *tcph = PacketGetTCP(p);
3405  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3406  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3407  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3408 
3409  if (tcph->th_flags & TH_RST) {
3410  if (!StreamTcpValidateRst(ssn, p))
3411  return -1;
3412 
3413  if (PKT_IS_TOSERVER(p)) {
3414  StreamTcpCloseSsnWithReset(p, ssn);
3415 
3416  ssn->server.next_seq = ack;
3417  ssn->client.next_seq = seq + p->payload_len;
3418  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3419  ssn->server.next_seq);
3420  ssn->client.window = window << ssn->client.wscale;
3421 
3422  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3423  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3424 
3425  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
3426 
3427  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3428  StreamTcpHandleTimestamp(ssn, p);
3429  }
3430 
3431  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3432  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3433  "%" PRIu32 "", ssn, ssn->client.next_seq,
3434  ssn->server.last_ack);
3435 
3436  /* don't return packets to pools here just yet, the pseudo
3437  * packet will take care, otherwise the normal session
3438  * cleanup. */
3439  } else {
3440  StreamTcpCloseSsnWithReset(p, ssn);
3441 
3442  ssn->server.next_seq = seq + p->payload_len + 1;
3443  ssn->client.next_seq = ack;
3444 
3445  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3446  ssn->server.next_seq);
3447  ssn->server.window = window << ssn->server.wscale;
3448 
3449  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3450  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3451 
3452  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
3453 
3454  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3455  StreamTcpHandleTimestamp(ssn, p);
3456  }
3457 
3458  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3459  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3460  "%" PRIu32 "", ssn, ssn->server.next_seq,
3461  ssn->client.last_ack);
3462 
3463  /* don't return packets to pools here just yet, the pseudo
3464  * packet will take care, otherwise the normal session
3465  * cleanup. */
3466  }
3467 
3468  } else if (tcph->th_flags & TH_FIN) {
3469  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3470  if (!StreamTcpValidateTimestamp(ssn, p))
3471  return -1;
3472  }
3473 
3474  SCLogDebug("ssn (%p: FIN received SEQ"
3475  " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
3476  " win %" PRIu32 "", ssn, ssn->server.next_seq,
3477  ssn->client.last_ack, ssn->server.next_win,
3478  ssn->server.window);
3479 
3480  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
3481  return -1;
3482 
3483  /* SYN/ACK */
3484  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
3485  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
3486  ssn);
3487 
3488  if (PKT_IS_TOSERVER(p)) {
3489  SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
3490 
3492  return -1;
3493  }
3494 
3495  /* Check if the SYN/ACK packets ACK matches the earlier
3496  * received SYN/ACK packet. */
3497  if (!(SEQ_EQ(ack, ssn->client.last_ack))) {
3498  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
3499  "%" PRIu32 " from stream",
3500  ssn, ack, ssn->client.isn + 1);
3501 
3503  return -1;
3504  }
3505 
3506  /* Check if the SYN/ACK packet SEQ the earlier
3507  * received SYN packet. */
3508  if (!(SEQ_EQ(seq, ssn->server.isn))) {
3509  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
3510  "%" PRIu32 " from stream",
3511  ssn, ack, ssn->client.isn + 1);
3512 
3514  return -1;
3515  }
3516 
3517  if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
3518  /* a resend of a SYN while we are established already -- fishy */
3520  return -1;
3521  }
3522 
3523  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
3524  "Likely due server not receiving final ACK in 3whs", ssn);
3525  return 0;
3526 
3527  } else if (tcph->th_flags & TH_SYN) {
3528  SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
3529  if (PKT_IS_TOCLIENT(p)) {
3530  SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
3531 
3533  return -1;
3534  }
3535 
3536  if (!(SEQ_EQ(ack, ssn->client.isn))) {
3537  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
3538 
3540  return -1;
3541  }
3542 
3543  /* a resend of a SYN while we are established already -- fishy */
3545  return -1;
3546 
3547  } else if (tcph->th_flags & TH_ACK) {
3548  /* Urgent pointer size can be more than the payload size, as it tells
3549  * the future coming data from the sender will be handled urgently
3550  * until data of size equal to urgent offset has been processed
3551  * (RFC 2147) */
3552 
3553  /* If the timestamp option is enabled for both the streams, then
3554  * validate the received packet timestamp value against the
3555  * stream->last_ts. If the timestamp is valid then process the
3556  * packet normally otherwise the drop the packet (RFC 1323) */
3557  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3558  if (!StreamTcpValidateTimestamp(ssn, p))
3559  return -1;
3560  }
3561 
3562  if (PKT_IS_TOSERVER(p)) {
3563  /* Process the received packet to server */
3564  HandleEstablishedPacketToServer(tv, ssn, p, stt);
3565 
3566  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3567  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3568  ssn->client.next_seq, ssn->server.last_ack
3569  ,ssn->client.next_win, ssn->client.window);
3570 
3571  } else { /* implied to client */
3572  if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
3574  SCLogDebug("3whs is now confirmed by server");
3575  }
3576 
3577  /* Process the received packet to client */
3578  HandleEstablishedPacketToClient(tv, ssn, p, stt);
3579 
3580  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3581  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3582  ssn->server.next_seq, ssn->client.last_ack,
3583  ssn->server.next_win, ssn->server.window);
3584  }
3585  } else {
3586  SCLogDebug("ssn %p: default case", ssn);
3587  }
3588 
3589  return 0;
3590 }
3591 
3592 /**
3593  * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
3594  * TCP_ESTABLISHED and changes to another TCP state as required.
3595  *
3596  * \param tv Thread Variable containing input/output queue, cpu affinity
3597  * \param p Packet which has to be handled in this TCP state.
3598  * \param stt Stream Thread module registered to handle the stream handling
3599  *
3600  * \retval 0 success
3601  * \retval -1 something wrong with the packet
3602  */
3603 
3604 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession *ssn, Packet *p)
3605 {
3606  const TCPHdr *tcph = PacketGetTCP(p);
3607  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3608  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3609  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3610 
3611  if (PKT_IS_TOSERVER(p)) {
3612  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
3613  " ACK %" PRIu32 "",
3614  ssn, p->payload_len, seq, ack);
3615 
3616  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3617  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3619  return -1;
3620  }
3621 
3622  const uint32_t pkt_re = seq + p->payload_len;
3623  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3624  ssn->client.last_ack, ssn->client.next_win);
3625  if (SEQ_GEQ(seq, ssn->client.last_ack) && SEQ_LEQ(pkt_re, ssn->client.next_win)) {
3626  // within expectations
3627  } else {
3628  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3629  "%" PRIu32 " from stream",
3630  ssn, seq, ssn->client.next_seq);
3631 
3633  return -1;
3634  }
3635 
3636  if (tcph->th_flags & TH_SYN) {
3637  SCLogDebug("ssn %p: FIN+SYN", ssn);
3639  return -1;
3640  }
3641  StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
3642  SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
3643 
3644  /* if we accept the FIN, next_seq needs to reflect the FIN */
3645  ssn->client.next_seq = seq + p->payload_len;
3646 
3647  SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
3648  ssn->client.next_seq);
3649  ssn->server.window = window << ssn->server.wscale;
3650 
3651  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3652  StreamTcpHandleTimestamp(ssn, p);
3653  }
3654 
3655  /* Update the next_seq, in case if we have missed the client packet
3656  and server has already received and acked it */
3657  if (SEQ_LT(ssn->server.next_seq, ack))
3658  ssn->server.next_seq = ack;
3659 
3660  if (tcph->th_flags & TH_ACK)
3661  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3662 
3663  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3664 
3665  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3666  ssn, ssn->client.next_seq, ssn->server.last_ack);
3667  } else { /* implied to client */
3668  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
3669  "ACK %" PRIu32 "",
3670  ssn, p->payload_len, seq, ack);
3671 
3672  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3673  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3675  return -1;
3676  }
3677 
3678  const uint32_t pkt_re = seq + p->payload_len;
3679  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3680  ssn->server.last_ack, ssn->server.next_win);
3681  if (SEQ_GEQ(seq, ssn->server.last_ack) && SEQ_LEQ(pkt_re, ssn->server.next_win)) {
3682  // within expectations
3683  } else {
3684  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3685  "%" PRIu32 " from stream (last_ack %u win %u = %u)",
3686  ssn, seq, ssn->server.next_seq, ssn->server.last_ack, ssn->server.window,
3687  (ssn->server.last_ack + ssn->server.window));
3688 
3690  return -1;
3691  }
3692 
3693  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
3694  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
3695 
3696  /* if we accept the FIN, next_seq needs to reflect the FIN */
3697  ssn->server.next_seq = seq + p->payload_len + 1;
3698  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 " updated", ssn, ssn->server.next_seq);
3699 
3700  ssn->client.window = window << ssn->client.wscale;
3701 
3702  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3703  StreamTcpHandleTimestamp(ssn, p);
3704  }
3705 
3706  /* Update the next_seq, in case if we have missed the client packet
3707  and server has already received and acked it */
3708  if (SEQ_LT(ssn->client.next_seq, ack))
3709  ssn->client.next_seq = ack;
3710 
3711  if (tcph->th_flags & TH_ACK)
3712  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3713 
3714  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3715 
3716  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3717  ssn, ssn->server.next_seq, ssn->client.last_ack);
3718  }
3719 
3720  return 0;
3721 }
3722 
3723 /**
3724  * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
3725  * ACK, FIN, RST packets and correspondingly changes the connection
3726  * state.
3727  *
3728  * \param tv Thread Variable containing input/output queue, cpu affinity
3729  * \param p Packet which has to be handled in this TCP state.
3730  * \param stt Stream Thread module registered to handle the stream handling
3731  *
3732  * \retval 0 success
3733  * \retval -1 something wrong with the packet
3734  */
3735 
3736 static int StreamTcpPacketStateFinWait1(
3737  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3738 {
3739  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3740  const TCPHdr *tcph = PacketGetTCP(p);
3741  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3742  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3743  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3744 
3745  if (tcph->th_flags & TH_RST) {
3746  if (!StreamTcpValidateRst(ssn, p))
3747  return -1;
3748 
3749  StreamTcpCloseSsnWithReset(p, ssn);
3750 
3751  if (PKT_IS_TOSERVER(p)) {
3752  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3753  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3754 
3755  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
3756 
3757  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3758  StreamTcpHandleTimestamp(ssn, p);
3759  }
3760 
3761  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3762  } else {
3763  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3764  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3765 
3766  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
3767 
3768  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3769  StreamTcpHandleTimestamp(ssn, p);
3770  }
3771 
3772  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3773  }
3774 
3775  } else if ((tcph->th_flags & (TH_FIN | TH_ACK)) == (TH_FIN | TH_ACK)) {
3776  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3777  if (!StreamTcpValidateTimestamp(ssn, p))
3778  return -1;
3779  }
3780 
3781  if (PKT_IS_TOSERVER(p)) {
3782  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3783  "%" PRIu32 ", ACK %" PRIu32 "",
3784  ssn, p->payload_len, seq, ack);
3785  int retransmission = 0;
3786 
3787  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3788  SCLogDebug("ssn %p: packet is retransmission", ssn);
3789  retransmission = 1;
3791 
3792  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3793  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3794  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3795  " != %" PRIu32 " from stream",
3796  ssn, seq, ssn->client.next_seq);
3798  return -1;
3799  }
3800 
3801  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3802  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3804  return -1;
3805  }
3806 
3807  if (!retransmission) {
3808  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3809  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3810 
3811  ssn->server.window = window << ssn->server.wscale;
3812  }
3813 
3814  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3815  StreamTcpHandleTimestamp(ssn, p);
3816  }
3817 
3818  /* Update the next_seq, in case if we have missed the client
3819  packet and server has already received and acked it */
3820  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3821  ssn->server.next_seq = ack;
3822 
3823  if (SEQ_EQ(ssn->client.next_seq, seq)) {
3824  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3825  }
3826 
3827  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3828 
3829  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3830 
3831  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3832  "%" PRIu32 "", ssn, ssn->client.next_seq,
3833  ssn->server.last_ack);
3834  } else { /* implied to client */
3835  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3836  "%" PRIu32 ", ACK %" PRIu32 "",
3837  ssn, p->payload_len, seq, ack);
3838  int retransmission = 0;
3839 
3840  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3841  SCLogDebug("ssn %p: packet is retransmission", ssn);
3842  retransmission = 1;
3844 
3845  } else if (SEQ_EQ(ssn->server.next_seq - 1, seq) && SEQ_EQ(ssn->client.last_ack, ack)) {
3846  SCLogDebug("ssn %p: packet is retransmission", ssn);
3847  retransmission = 1;
3849 
3850  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3851  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3852  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3853  " != %" PRIu32 " from stream",
3854  ssn, seq, ssn->server.next_seq);
3856  return -1;
3857  }
3858 
3859  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3860  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3862  return -1;
3863  }
3864 
3865  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3866  StreamTcpHandleTimestamp(ssn, p);
3867  }
3868 
3869  if (!retransmission) {
3870  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3871  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3872 
3873  ssn->client.window = window << ssn->client.wscale;
3874 
3875  /* Update the next_seq, in case if we have missed the client
3876  packet and server has already received and acked it */
3877  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3878  ssn->client.next_seq = ack;
3879 
3880  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3881  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3882  }
3883 
3884  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3885  }
3886 
3887  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3888 
3889  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3890  "%" PRIu32 "", ssn, ssn->server.next_seq,
3891  ssn->client.last_ack);
3892  }
3893 
3894  } else if (tcph->th_flags & TH_FIN) {
3895  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3896  if (!StreamTcpValidateTimestamp(ssn, p))
3897  return -1;
3898  }
3899 
3900  if (PKT_IS_TOSERVER(p)) {
3901  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3902  "%" PRIu32 ", ACK %" PRIu32 "",
3903  ssn, p->payload_len, seq, ack);
3904  int retransmission = 0;
3905 
3906  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3907  SCLogDebug("ssn %p: packet is retransmission", ssn);
3908  retransmission = 1;
3910 
3911  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3912  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3913  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3914  " != %" PRIu32 " from stream",
3915  ssn, seq, ssn->client.next_seq);
3917  return -1;
3918  }
3919 
3920  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3921  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3923  return -1;
3924  }
3925 
3926  if (!retransmission) {
3927  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3928  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3929 
3930  ssn->server.window = window << ssn->server.wscale;
3931  }
3932 
3933  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3934  StreamTcpHandleTimestamp(ssn, p);
3935  }
3936 
3937  /* Update the next_seq, in case if we have missed the client
3938  packet and server has already received and acked it */
3939  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3940  ssn->server.next_seq = ack;
3941 
3942  if (SEQ_EQ(ssn->client.next_seq - 1, seq)) {
3943  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3944  }
3945 
3946  if (tcph->th_flags & TH_ACK)
3947  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3948 
3949  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3950 
3951  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3952  "%" PRIu32 "", ssn, ssn->client.next_seq,
3953  ssn->server.last_ack);
3954  } else { /* implied to client */
3955  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3956  "%" PRIu32 ", ACK %" PRIu32 "",
3957  ssn, p->payload_len, seq, ack);
3958 
3959  int retransmission = 0;
3960 
3961  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3962  SCLogDebug("ssn %p: packet is retransmission", ssn);
3963  retransmission = 1;
3965 
3966  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3967  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3968  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3969  " != %" PRIu32 " from stream",
3970  ssn, seq, ssn->server.next_seq);
3972  return -1;
3973  }
3974 
3975  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3976  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3978  return -1;
3979  }
3980 
3981  if (!retransmission) {
3982  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3983  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3984 
3985  ssn->client.window = window << ssn->client.wscale;
3986  }
3987 
3988  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3989  StreamTcpHandleTimestamp(ssn, p);
3990  }
3991 
3992  /* Update the next_seq, in case if we have missed the client
3993  packet and server has already received and acked it */
3994  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3995  ssn->client.next_seq = ack;
3996 
3997  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3998  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3999  }
4000 
4001  if (tcph->th_flags & TH_ACK)
4002  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4003 
4004  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4005 
4006  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4007  "%" PRIu32 "", ssn, ssn->server.next_seq,
4008  ssn->client.last_ack);
4009  }
4010  } else if (tcph->th_flags & TH_SYN) {
4011  SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
4013  return -1;
4014 
4015  } else if (tcph->th_flags & TH_ACK) {
4016  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4017  if (!StreamTcpValidateTimestamp(ssn, p))
4018  return -1;
4019  }
4020 
4021  if (PKT_IS_TOSERVER(p)) {
4022  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4023  "%" PRIu32 ", ACK %" PRIu32 "",
4024  ssn, p->payload_len, seq, ack);
4025  int retransmission = 0;
4026 
4027  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4028  SCLogDebug("ssn %p: packet is retransmission", ssn);
4029  retransmission = 1;
4031  }
4032 
4033  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4034  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4036  return -1;
4037  }
4038 
4039  if (SEQ_LT(ack, ssn->server.next_seq)) {
4040  SCLogDebug(
4041  "ssn %p: ACK's older segment as %u < %u", ssn, ack, ssn->server.next_seq);
4042  } else if (!retransmission) {
4043  if (SEQ_EQ(ack, ssn->server.next_seq)) {
4044  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
4046  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
4047  "%" PRIu32 "",
4048  ssn, seq, ssn->client.next_win);
4049  SCLogDebug("seq %u client.next_seq %u", seq, ssn->client.next_seq);
4050  if (seq == ssn->client.next_seq) {
4051  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
4052  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
4053  }
4054  } else {
4055  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4056  " != %" PRIu32 " from stream",
4057  ssn, seq, ssn->client.next_seq);
4058 
4060  return -1;
4061  }
4062 
4063  ssn->server.window = window << ssn->server.wscale;
4064  }
4065  }
4066 
4067  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4068  StreamTcpHandleTimestamp(ssn, p);
4069  }
4070 
4071  /* Update the next_seq, in case if we have missed the client
4072  packet and server has already received and acked it */
4073  if (SEQ_LT(ssn->server.next_seq - 1, ack))
4074  ssn->server.next_seq = ack;
4075 
4076  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4077  StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
4078  }
4079 
4080  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4081 
4083 
4084  /* update next_win */
4085  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
4086 
4087  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4088 
4089  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4090  "%" PRIu32 "", ssn, ssn->client.next_seq,
4091  ssn->server.last_ack);
4092 
4093  } else { /* implied to client */
4094 
4095  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4096  "%" PRIu32 ", ACK %" PRIu32 "",
4097  ssn, p->payload_len, seq, ack);
4098 
4099  int retransmission = 0;
4100 
4101  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4102  SCLogDebug("ssn %p: packet is retransmission", ssn);
4103  retransmission = 1;
4105  }
4106 
4107  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4108  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4110  return -1;
4111  }
4112 
4113  if (!retransmission) {
4114  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4116  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4117  "%" PRIu32 "",
4118  ssn, seq, ssn->server.next_win);
4119 
4120  if (seq == ssn->server.next_seq - 1) {
4121  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
4122  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
4123  }
4124  } else {
4125  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4126  " != %" PRIu32 " from stream",
4127  ssn, seq, ssn->server.next_seq);
4129  return -1;
4130  }
4131 
4132  ssn->client.window = window << ssn->client.wscale;
4133  }
4134 
4135  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4136  StreamTcpHandleTimestamp(ssn, p);
4137  }
4138 
4139  /* Update the next_seq, in case if we have missed the client
4140  packet and server has already received and acked it */
4141  if (SEQ_LT(ssn->client.next_seq - 1, ack))
4142  ssn->client.next_seq = ack;
4143 
4144  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
4145  StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
4146  }
4147 
4148  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4149 
4151 
4152  /* update next_win */
4153  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4154 
4155  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4156 
4157  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4158  "%" PRIu32 "", ssn, ssn->server.next_seq,
4159  ssn->client.last_ack);
4160  }
4161  } else {
4162  SCLogDebug("ssn (%p): default case", ssn);
4163  }
4164 
4165  return 0;
4166 }
4167 
4168 /**
4169  * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
4170  * ACK, RST, FIN packets and correspondingly changes the connection
4171  * state.
4172  *
4173  * \param tv Thread Variable containing input/output queue, cpu affinity
4174  * \param p Packet which has to be handled in this TCP state.
4175  * \param stt Stream Thread module registered to handle the stream handling
4176  */
4177 
4178 static int StreamTcpPacketStateFinWait2(
4179  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4180 {
4181  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4182  const TCPHdr *tcph = PacketGetTCP(p);
4183  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4184  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4185  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4186 
4187  if (tcph->th_flags & TH_RST) {
4188  if (!StreamTcpValidateRst(ssn, p))
4189  return -1;
4190 
4191  StreamTcpCloseSsnWithReset(p, ssn);
4192 
4193  if (PKT_IS_TOSERVER(p)) {
4194  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4195  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4196 
4197  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4198 
4199  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4200  StreamTcpHandleTimestamp(ssn, p);
4201  }
4202 
4203  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4204  } else {
4205  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4206  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4207 
4208  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4209 
4210  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4211  StreamTcpHandleTimestamp(ssn, p);
4212  }
4213 
4214  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4215  }
4216 
4217  } else if (tcph->th_flags & TH_FIN) {
4218  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4219  if (!StreamTcpValidateTimestamp(ssn, p))
4220  return -1;
4221  }
4222 
4223  if (PKT_IS_TOSERVER(p)) {
4224  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4225  "%" PRIu32 ", ACK %" PRIu32 "",
4226  ssn, p->payload_len, seq, ack);
4227  int retransmission = 0;
4228 
4229  if (SEQ_EQ(seq, ssn->client.next_seq - 1) && SEQ_EQ(ack, ssn->server.last_ack)) {
4230  SCLogDebug("ssn %p: retransmission", ssn);
4231  retransmission = 1;
4233  } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4234  SCLogDebug("ssn %p: packet is retransmission", ssn);
4235  retransmission = 1;
4237 
4238  } else if (SEQ_LT(seq, ssn->client.next_seq) ||
4239  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4240  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4241  "%" PRIu32 " != %" PRIu32 " from stream",
4242  ssn, seq, ssn->client.next_seq);
4244  return -1;
4245  }
4246 
4247  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4248  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4250  return -1;
4251  }
4252 
4253  if (!retransmission) {
4254  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4255  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4256 
4257  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4259  ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4260  }
4261  ssn->server.window = window << ssn->server.wscale;
4262  }
4263 
4264  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4265  StreamTcpHandleTimestamp(ssn, p);
4266  }
4267 
4268  /* Update the next_seq, in case if we have missed the client
4269  packet and server has already received and acked it */
4270  if (SEQ_LT(ssn->server.next_seq, ack))
4271  ssn->server.next_seq = ack;
4272 
4273  if (tcph->th_flags & TH_ACK)
4274  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4275 
4276  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4277 
4278  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4279  "%" PRIu32 "", ssn, ssn->client.next_seq,
4280  ssn->server.last_ack);
4281  } else { /* implied to client */
4282  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4283  "%" PRIu32 ", ACK %" PRIu32 "",
4284  ssn, p->payload_len, seq, ack);
4285  int retransmission = 0;
4286 
4287  if (SEQ_EQ(seq, ssn->server.next_seq - 1) && SEQ_EQ(ack, ssn->client.last_ack)) {
4288  SCLogDebug("ssn %p: retransmission", ssn);
4289  retransmission = 1;
4291  } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4292  SCLogDebug("ssn %p: packet is retransmission", ssn);
4293  retransmission = 1;
4295 
4296  } else if (SEQ_LT(seq, ssn->server.next_seq) ||
4297  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4298  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4299  "%" PRIu32 " != %" PRIu32 " from stream",
4300  ssn, seq, ssn->server.next_seq);
4302  return -1;
4303  }
4304 
4305  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4306  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4308  return -1;
4309  }
4310 
4311  if (!retransmission) {
4312  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4313  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4314 
4315  ssn->client.window = window << ssn->client.wscale;
4316  }
4317 
4318  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4319  StreamTcpHandleTimestamp(ssn, p);
4320  }
4321 
4322  /* Update the next_seq, in case if we have missed the client
4323  packet and server has already received and acked it */
4324  if (SEQ_LT(ssn->client.next_seq, ack))
4325  ssn->client.next_seq = ack;
4326 
4327  if (tcph->th_flags & TH_ACK)
4328  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4329 
4330  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4331  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4332  "%" PRIu32 "", ssn, ssn->server.next_seq,
4333  ssn->client.last_ack);
4334  }
4335 
4336  } else if (tcph->th_flags & TH_SYN) {
4337  SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
4339  return -1;
4340 
4341  } else if (tcph->th_flags & TH_ACK) {
4342  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4343  if (!StreamTcpValidateTimestamp(ssn, p))
4344  return -1;
4345  }
4346 
4347  if (PKT_IS_TOSERVER(p)) {
4348  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4349  "%" PRIu32 ", ACK %" PRIu32 "",
4350  ssn, p->payload_len, seq, ack);
4351  int retransmission = 0;
4352 
4353  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4354  SCLogDebug("ssn %p: packet is retransmission", ssn);
4355  retransmission = 1;
4357  }
4358 
4359  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4360  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4362  return -1;
4363  }
4364 
4365  if (!retransmission) {
4366  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
4368  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
4369  "%" PRIu32 "",
4370  ssn, seq, ssn->client.next_win);
4371 
4372  } else {
4373  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4374  " != %" PRIu32 " from stream",
4375  ssn, seq, ssn->client.next_seq);
4377  return -1;
4378  }
4379 
4380  ssn->server.window = window << ssn->server.wscale;
4381  }
4382 
4383  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4384  StreamTcpHandleTimestamp(ssn, p);
4385  }
4386 
4387  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4388  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4389  }
4390 
4391  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4392 
4394 
4395  /* update next_win */
4396  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
4397 
4398  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4399 
4400  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4401  "%" PRIu32 "", ssn, ssn->client.next_seq,
4402  ssn->server.last_ack);
4403  } else { /* implied to client */
4404  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4405  "%" PRIu32 ", ACK %" PRIu32 "",
4406  ssn, p->payload_len, seq, ack);
4407  int retransmission = 0;
4408 
4409  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4410  SCLogDebug("ssn %p: packet is retransmission", ssn);
4411  retransmission = 1;
4413  }
4414 
4415  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4416  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4418  return -1;
4419  }
4420 
4421  if (!retransmission) {
4422  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4424  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4425  "%" PRIu32 "",
4426  ssn, seq, ssn->server.next_win);
4427  } else {
4428  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4429  " != %" PRIu32 " from stream",
4430  ssn, seq, ssn->server.next_seq);
4432  return -1;
4433  }
4434 
4435  ssn->client.window = window << ssn->client.wscale;
4436  }
4437 
4438  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4439  StreamTcpHandleTimestamp(ssn, p);
4440  }
4441 
4442  if (SEQ_EQ(ssn->server.next_seq, seq)) {
4443  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4444  }
4445 
4446  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4447 
4449 
4450  /* update next_win */
4451  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4452 
4453  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4454 
4455  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4456  "%" PRIu32 "", ssn, ssn->server.next_seq,
4457  ssn->client.last_ack);
4458  }
4459  } else {
4460  SCLogDebug("ssn %p: default case", ssn);
4461  }
4462 
4463  return 0;
4464 }
4465 
4466 /**
4467  * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
4468  * the connection goes to TCP_TIME_WAIT state. The state has been
4469  * reached as both end application has been closed.
4470  *
4471  * \param tv Thread Variable containing input/output queue, cpu affinity
4472  * \param p Packet which has to be handled in this TCP state.
4473  * \param stt Stream Thread module registered to handle the stream handling
4474  */
4475 
4476 static int StreamTcpPacketStateClosing(
4477  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4478 {
4479  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4480  const TCPHdr *tcph = PacketGetTCP(p);
4481  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4482  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4483  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4484 
4485  if (tcph->th_flags & TH_RST) {
4486  if (!StreamTcpValidateRst(ssn, p))
4487  return -1;
4488 
4489  StreamTcpCloseSsnWithReset(p, ssn);
4490 
4491  if (PKT_IS_TOSERVER(p)) {
4492  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4493  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4494 
4495  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4496 
4497  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4498  StreamTcpHandleTimestamp(ssn, p);
4499  }
4500 
4501  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4502  } else {
4503  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4504  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4505 
4506  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4507 
4508  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4509  StreamTcpHandleTimestamp(ssn, p);
4510  }
4511 
4512  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4513  }
4514 
4515  } else if (tcph->th_flags & TH_SYN) {
4516  SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
4518  return -1;
4519 
4520  } else if (tcph->th_flags & TH_ACK) {
4521  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4522  if (!StreamTcpValidateTimestamp(ssn, p))
4523  return -1;
4524  }
4525 
4526  if (PKT_IS_TOSERVER(p)) {
4527  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4528  "%" PRIu32 ", ACK %" PRIu32 "",
4529  ssn, p->payload_len, seq, ack);
4530  int retransmission = 0;
4531  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4532  SCLogDebug("ssn %p: packet is retransmission", ssn);
4533  retransmission = 1;
4535  }
4536 
4537  if (seq != ssn->client.next_seq) {
4538  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4539  " != %" PRIu32 " from stream",
4540  ssn, seq, ssn->client.next_seq);
4542  return -1;
4543  }
4544 
4545  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4546  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4548  return -1;
4549  }
4550 
4551  if (!retransmission) {
4552  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4553  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4554 
4555  ssn->client.window = window << ssn->client.wscale;
4556  }
4557 
4558  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4559  StreamTcpHandleTimestamp(ssn, p);
4560  }
4561  /* Update the next_seq, in case if we have missed the client
4562  packet and server has already received and acked it */
4563  if (SEQ_LT(ssn->server.next_seq, ack))
4564  ssn->server.next_seq = ack;
4565 
4566  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4567 
4568  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4569  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4570  "%" PRIu32 "", ssn, ssn->client.next_seq,
4571  ssn->server.last_ack);
4572  } else { /* implied to client */
4573  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4574  "%" PRIu32 ", ACK %" PRIu32 "",
4575  ssn, p->payload_len, seq, ack);
4576  int retransmission = 0;
4577  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4578  SCLogDebug("ssn %p: packet is retransmission", ssn);
4579  retransmission = 1;
4581  }
4582 
4583  if (seq != ssn->server.next_seq) {
4584  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4585  " != %" PRIu32 " from stream",
4586  ssn, seq, ssn->server.next_seq);
4588  return -1;
4589  }
4590 
4591  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4592  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4594  return -1;
4595  }
4596 
4597  if (!retransmission) {
4598  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4599  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4600 
4601  ssn->client.window = window << ssn->client.wscale;
4602  }
4603 
4604  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4605  StreamTcpHandleTimestamp(ssn, p);
4606  }
4607 
4608  /* Update the next_seq, in case if we have missed the client
4609  packet and server has already received and acked it */
4610  if (SEQ_LT(ssn->client.next_seq, ack))
4611  ssn->client.next_seq = ack;
4612 
4613  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4614 
4615  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4616  SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
4617  "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
4618  ssn->server.next_seq, ssn->client.last_ack);
4619  }
4620  } else {
4621  SCLogDebug("ssn %p: default case", ssn);
4622  }
4623 
4624  return 0;
4625 }
4626 
4627 /**
4628  * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
4629  * packet from server the connection goes to TCP_LAST_ACK state.
4630  * The state is possible only for server host.
4631  *
4632  * \param tv Thread Variable containing input/output queue, cpu affinity
4633  * \param p Packet which has to be handled in this TCP state.
4634  * \param stt Stream Thread module registered to handle the stream handling
4635  */
4636 
4637 static int StreamTcpPacketStateCloseWait(
4638  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4639 {
4640  SCEnter();
4641  const TCPHdr *tcph = PacketGetTCP(p);
4642  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4643  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4644  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4645 
4646  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4647 
4648  if (PKT_IS_TOCLIENT(p)) {
4649  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4650  "%" PRIu32 ", ACK %" PRIu32 "",
4651  ssn, p->payload_len, seq, ack);
4652  } else {
4653  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4654  "%" PRIu32 ", ACK %" PRIu32 "",
4655  ssn, p->payload_len, seq, ack);
4656  }
4657 
4658  if (tcph->th_flags & TH_RST) {
4659  if (!StreamTcpValidateRst(ssn, p))
4660  return -1;
4661 
4662  StreamTcpCloseSsnWithReset(p, ssn);
4663 
4664  if (PKT_IS_TOSERVER(p)) {
4665  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4666  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4667 
4668  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4669 
4670  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4671  StreamTcpHandleTimestamp(ssn, p);
4672  }
4673 
4674  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4675  } else {
4676  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4677  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4678 
4679  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4680 
4681  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4682  StreamTcpHandleTimestamp(ssn, p);
4683  }
4684 
4685  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4686  }
4687 
4688  } else if (tcph->th_flags & TH_FIN) {
4689  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4690  if (!StreamTcpValidateTimestamp(ssn, p))
4691  SCReturnInt(-1);
4692  }
4693 
4694  if (PKT_IS_TOSERVER(p)) {
4695  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4696  "%" PRIu32 ", ACK %" PRIu32 "",
4697  ssn, p->payload_len, seq, ack);
4698 
4699  int retransmission = 0;
4700  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4701  SCLogDebug("ssn %p: packet is retransmission", ssn);
4702  retransmission = 1;
4704  }
4705 
4706  if (!retransmission) {
4707  if (SEQ_LT(seq, ssn->client.next_seq) ||
4708  SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4709  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4710  " != %" PRIu32 " from stream",
4711  ssn, seq, ssn->client.next_seq);
4713  SCReturnInt(-1);
4714  }
4715  }
4716 
4717  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4718  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4720  SCReturnInt(-1);
4721  }
4722 
4723  /* don't update to LAST_ACK here as we want a toclient FIN for that */
4724 
4725  if (!retransmission)
4726  ssn->server.window = window << ssn->server.wscale;
4727 
4728  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4729  StreamTcpHandleTimestamp(ssn, p);
4730  }
4731 
4732  /* Update the next_seq, in case if we have missed the client
4733  packet and server has already received and acked it */
4734  if (SEQ_LT(ssn->server.next_seq, ack))
4735  ssn->server.next_seq = ack;
4736 
4737  if (tcph->th_flags & TH_ACK)
4738  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4739 
4740  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4741  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4742  "%" PRIu32 "", ssn, ssn->client.next_seq,
4743  ssn->server.last_ack);
4744  } else {
4745  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4746  "%" PRIu32 ", ACK %" PRIu32 "",
4747  ssn, p->payload_len, seq, ack);
4748 
4749  int retransmission = 0;
4750  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4751  SCLogDebug("ssn %p: packet is retransmission", ssn);
4752  retransmission = 1;
4754  }
4755 
4756  if (!retransmission) {
4757  if (SEQ_LT(seq, ssn->server.next_seq) ||
4758  SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4759  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4760  " != %" PRIu32 " from stream",
4761  ssn, seq, ssn->server.next_seq);
4763  SCReturnInt(-1);
4764  }
4765  }
4766 
4767  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4768  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4770  SCReturnInt(-1);
4771  }
4772 
4773  if (!retransmission) {
4774  StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
4775  SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
4776 
4777  ssn->client.window = window << ssn->client.wscale;
4778  }
4779 
4780  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4781  StreamTcpHandleTimestamp(ssn, p);
4782  }
4783 
4784  /* Update the next_seq, in case if we have missed the client
4785  packet and server has already received and acked it */
4786  if (SEQ_LT(ssn->client.next_seq, ack))
4787  ssn->client.next_seq = ack;
4788 
4789  if (tcph->th_flags & TH_ACK)
4790  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4791 
4792  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4793  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4794  "%" PRIu32 "", ssn, ssn->server.next_seq,
4795  ssn->client.last_ack);
4796  }
4797 
4798  } else if (tcph->th_flags & TH_SYN) {
4799  SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
4801  SCReturnInt(-1);
4802 
4803  } else if (tcph->th_flags & TH_ACK) {
4804  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4805  if (!StreamTcpValidateTimestamp(ssn, p))
4806  SCReturnInt(-1);
4807  }
4808 
4809  if (PKT_IS_TOSERVER(p)) {
4810  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4811  "%" PRIu32 ", ACK %" PRIu32 "",
4812  ssn, p->payload_len, seq, ack);
4813 
4814  int retransmission = 0;
4815  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4816  SCLogDebug("ssn %p: packet is retransmission", ssn);
4817  retransmission = 1;
4819  }
4820 
4821  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->client.last_ack))) {
4822  SCLogDebug("ssn %p: -> retransmission", ssn);
4824  SCReturnInt(-1);
4825 
4826  } else if (SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4827  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4828  " != %" PRIu32 " from stream",
4829  ssn, seq, ssn->client.next_seq);
4831  SCReturnInt(-1);
4832  }
4833 
4834  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4835  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4837  SCReturnInt(-1);
4838  }
4839 
4840  if (!retransmission) {
4841  ssn->server.window = window << ssn->server.wscale;
4842  }
4843 
4844  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4845  StreamTcpHandleTimestamp(ssn, p);
4846  }
4847 
4848  /* Update the next_seq, in case if we have missed the client
4849  packet and server has already received and acked it */
4850  if (SEQ_LT(ssn->server.next_seq, ack))
4851  ssn->server.next_seq = ack;
4852 
4853  if (SEQ_EQ(seq, ssn->client.next_seq))
4854  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4855 
4856  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4857 
4858  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4859  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4860  "%" PRIu32 "", ssn, ssn->client.next_seq,
4861  ssn->server.last_ack);
4862  } else {
4863  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4864  "%" PRIu32 ", ACK %" PRIu32 "",
4865  ssn, p->payload_len, seq, ack);
4866  int retransmission = 0;
4867  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4868  SCLogDebug("ssn %p: packet is retransmission", ssn);
4869  retransmission = 1;
4871  }
4872 
4873  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->server.last_ack))) {
4874  SCLogDebug("ssn %p: -> retransmission", ssn);
4876  SCReturnInt(-1);
4877 
4878  } else if (SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4879  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4880  " != %" PRIu32 " from stream",
4881  ssn, seq, ssn->server.next_seq);
4883  SCReturnInt(-1);
4884  }
4885 
4886  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4887  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4889  SCReturnInt(-1);
4890  }
4891 
4892  if (!retransmission) {
4893  ssn->client.window = window << ssn->client.wscale;
4894  }
4895 
4896  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4897  StreamTcpHandleTimestamp(ssn, p);
4898  }
4899 
4900  /* Update the next_seq, in case if we have missed the client
4901  packet and server has already received and acked it */
4902  if (SEQ_LT(ssn->client.next_seq, ack))
4903  ssn->client.next_seq = ack;
4904 
4905  if (SEQ_EQ(seq, ssn->server.next_seq))
4906  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4907 
4908  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4909 
4910  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4911  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4912  "%" PRIu32 "", ssn, ssn->server.next_seq,
4913  ssn->client.last_ack);
4914  }
4915 
4916  } else {
4917  SCLogDebug("ssn %p: default case", ssn);
4918  }
4919  SCReturnInt(0);
4920 }
4921 
4922 /**
4923  * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
4924  * the connection goes to TCP_CLOSED state and stream memory is
4925  * returned back to pool. The state is possible only for server host.
4926  *
4927  * \param tv Thread Variable containing input/output queue, cpu affinity
4928  * \param p Packet which has to be handled in this TCP state.
4929  * \param stt Stream Thread module registered to handle the stream handling
4930  */
4931 
4932 static int StreamTcpPacketStateLastAck(
4933  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4934 {
4935  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4936  const TCPHdr *tcph = PacketGetTCP(p);
4937  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4938  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4939  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4940 
4941  if (tcph->th_flags & TH_RST) {
4942  if (!StreamTcpValidateRst(ssn, p))
4943  return -1;
4944 
4945  StreamTcpCloseSsnWithReset(p, ssn);
4946 
4947  if (PKT_IS_TOSERVER(p)) {
4948  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4949  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4950 
4951  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4952 
4953  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4954  StreamTcpHandleTimestamp(ssn, p);
4955  }
4956 
4957  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4958  } else {
4959  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4960  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4961 
4962  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4963 
4964  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4965  StreamTcpHandleTimestamp(ssn, p);
4966  }
4967 
4968  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4969  }
4970 
4971  } else if (tcph->th_flags & TH_FIN) {
4972  /** \todo */
4973  SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
4974 
4975  } else if (tcph->th_flags & TH_SYN) {
4976  SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
4978  return -1;
4979 
4980  } else if (tcph->th_flags & TH_ACK) {
4981  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4982  if (!StreamTcpValidateTimestamp(ssn, p))
4983  return -1;
4984  }
4985 
4986  if (PKT_IS_TOSERVER(p)) {
4987  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4988  "%" PRIu32 ", ACK %" PRIu32 "",
4989  ssn, p->payload_len, seq, ack);
4990 
4991  int retransmission = 0;
4992  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4993  SCLogDebug("ssn %p: packet is retransmission", ssn);
4994  retransmission = 1;
4996  }
4997 
4998  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4999  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5001  SCReturnInt(-1);
5002  }
5003 
5004  if (!retransmission) {
5005  if (SEQ_LT(seq, ssn->client.next_seq)) {
5006  SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
5007  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
5008  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5009  " != %" PRIu32 " from stream",
5010  ssn, seq, ssn->client.next_seq);
5012  return -1;
5013  } else {
5014  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5015  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5016  }
5017  ssn->server.window = window << ssn->server.wscale;
5018  }
5019 
5020  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5021  StreamTcpHandleTimestamp(ssn, p);
5022  }
5023 
5024  /* Update the next_seq, in case if we have missed the client
5025  packet and server has already received and acked it */
5026  if (SEQ_LT(ssn->server.next_seq, ack))
5027  ssn->server.next_seq = ack;
5028 
5029  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
5030 
5031  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5032  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5033  "%" PRIu32 "", ssn, ssn->client.next_seq,
5034  ssn->server.last_ack);
5035  }
5036  } else {
5037  SCLogDebug("ssn %p: default case", ssn);
5038  }
5039 
5040  return 0;
5041 }
5042 
5043 /**
5044  * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
5045  * the connection goes to TCP_CLOSED state and stream memory is
5046  * returned back to pool.
5047  *
5048  * \param tv Thread Variable containing input/output queue, cpu affinity
5049  * \param p Packet which has to be handled in this TCP state.
5050  * \param stt Stream Thread module registered to handle the stream handling
5051  */
5052 
5053 static int StreamTcpPacketStateTimeWait(
5054  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
5055 {
5056  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5057  const TCPHdr *tcph = PacketGetTCP(p);
5058  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
5059  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
5060  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
5061 
5062  if (tcph->th_flags & TH_RST) {
5063  if (!StreamTcpValidateRst(ssn, p))
5064  return -1;
5065 
5066  StreamTcpCloseSsnWithReset(p, ssn);
5067 
5068  if (PKT_IS_TOSERVER(p)) {
5069  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
5070  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
5071 
5072  StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
5073 
5074  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5075  StreamTcpHandleTimestamp(ssn, p);
5076  }
5077 
5078  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5079  } else {
5080  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
5081  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
5082 
5083  StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
5084 
5085  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5086  StreamTcpHandleTimestamp(ssn, p);
5087  }
5088 
5089  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5090  }
5091 
5092  } else if (tcph->th_flags & TH_FIN) {
5093  /** \todo */
5094 
5095  } else if (tcph->th_flags & TH_SYN) {
5096  SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
5098  return -1;
5099 
5100  } else if (tcph->th_flags & TH_ACK) {
5101  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5102  if (!StreamTcpValidateTimestamp(ssn, p))
5103  return -1;
5104  }
5105 
5106  if (PKT_IS_TOSERVER(p)) {
5107  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
5108  "%" PRIu32 ", ACK %" PRIu32 "",
5109  ssn, p->payload_len, seq, ack);
5110  int retransmission = 0;
5111  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
5112  SCLogDebug("ssn %p: packet is retransmission", ssn);
5113  retransmission = 1;
5115 
5116  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
5117  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5118  " != %" PRIu32 " from stream",
5119  ssn, seq, ssn->client.next_seq);
5121  return -1;
5122  }
5123 
5124  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
5125  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5127  SCReturnInt(-1);
5128  }
5129 
5130  if (!retransmission) {
5131  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5132  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5133 
5134  ssn->server.window = window << ssn->server.wscale;
5135  }
5136 
5137  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5138  StreamTcpHandleTimestamp(ssn, p);
5139  }
5140 
5141  /* Update the next_seq, in case if we have missed the client
5142  packet and server has already received and acked it */
5143  if (SEQ_LT(ssn->server.next_seq, ack))
5144  ssn->server.next_seq = ack;
5145 
5146  StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
5147 
5148  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5149  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5150  "%" PRIu32 "", ssn, ssn->client.next_seq,
5151  ssn->server.last_ack);
5152  } else {
5153  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
5154  "%" PRIu32 ", ACK %" PRIu32 "",
5155  ssn, p->payload_len, seq, ack);
5156  int retransmission = 0;
5157  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
5158  SCLogDebug("ssn %p: packet is retransmission", ssn);
5159  retransmission = 1;
5161  } else if (seq != ssn->server.next_seq - 1 && seq != ssn->server.next_seq) {
5162  if (p->payload_len > 0 && seq == ssn->server.last_ack) {
5163  SCLogDebug("ssn %p: -> retransmission", ssn);
5164  SCReturnInt(0);
5165  } else {
5166  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5167  " != %" PRIu32 " from stream",
5168  ssn, seq, ssn->server.next_seq);
5170  return -1;
5171  }
5172  }
5173 
5174  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
5175  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5177  SCReturnInt(-1);
5178  }
5179 
5180  if (!retransmission) {
5181  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5182  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5183 
5184  ssn->client.window = window << ssn->client.wscale;
5185  }
5186 
5187  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5188  StreamTcpHandleTimestamp(ssn, p);
5189  }
5190 
5191  /* Update the next_seq, in case if we have missed the client
5192  packet and server has already received and acked it */
5193  if (SEQ_LT(ssn->client.next_seq, ack))
5194  ssn->client.next_seq = ack;
5195 
5196  StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
5197 
5198  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5199  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5200  "%" PRIu32 "", ssn, ssn->server.next_seq,
5201  ssn->client.last_ack);
5202  }
5203 
5204  } else {
5205  SCLogDebug("ssn %p: default case", ssn);
5206  }
5207 
5208  return 0;
5209 }
5210 
5211 static int StreamTcpPacketStateClosed(
5212  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
5213 {
5214  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5215 
5216  const TCPHdr *tcph = PacketGetTCP(p);
5217  if (tcph->th_flags & TH_RST) {
5218  SCLogDebug("RST on closed state");
5219  return 0;
5220  }
5221 
5222  TcpStream *stream = NULL, *ostream = NULL;
5223  if (PKT_IS_TOSERVER(p)) {
5224  stream = &ssn->client;
5225  ostream = &ssn->server;
5226  } else {
5227  stream = &ssn->server;
5228  ostream = &ssn->client;
5229  }
5230 
5231  SCLogDebug("stream %s ostream %s",
5232  stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
5233  ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
5234 
5235  /* if we've seen a RST on our direction, but not on the other
5236  * see if we perhaps need to continue processing anyway. */
5237  if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
5238  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5239  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->pstate) < 0)
5240  return -1;
5241  /* if state is still "closed", it wasn't updated by our dispatch. */
5242  if (ssn->state == TCP_CLOSED)
5243  ssn->state = ssn->pstate;
5244  }
5245  }
5246  return 0;
5247 }
5248 
5249 static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
5250 {
5251  if (p->flags & PKT_PSEUDO_STREAM_END) {
5252  return;
5253  }
5254  const TCPHdr *tcph = PacketGetTCP(p);
5255  /* more RSTs are not unusual */
5256  if ((tcph->th_flags & (TH_RST)) != 0) {
5257  return;
5258  }
5259 
5260  TcpStream *ostream = NULL;
5261  if (PKT_IS_TOSERVER(p)) {
5262  ostream = &ssn->server;
5263  } else {
5264  ostream = &ssn->client;
5265  }
5266 
5267  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5268  SCLogDebug("regular packet %"PRIu64" from same sender as "
5269  "the previous RST. Looks like it injected!", p->pcap_cnt);
5273  return;
5274  }
5275 }
5276 
5277 /**
5278  * \retval 1 packet is a keep alive pkt
5279  * \retval 0 packet is not a keep alive pkt
5280  */
5281 static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
5282 {
5283  if (p->flags & PKT_PSEUDO_STREAM_END)
5284  return 0;
5285 
5286  /* rfc 1122:
5287  An implementation SHOULD send a keep-alive segment with no
5288  data; however, it MAY be configurable to send a keep-alive
5289  segment containing one garbage octet, for compatibility with
5290  erroneous TCP implementations.
5291  */
5292  if (p->payload_len > 1)
5293  return 0;
5294 
5295  const TCPHdr *tcph = PacketGetTCP(p);
5296  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) {
5297  return 0;
5298  }
5299 
5300  TcpStream *stream = NULL, *ostream = NULL;
5301  if (PKT_IS_TOSERVER(p)) {
5302  stream = &ssn->client;
5303  ostream = &ssn->server;
5304  } else {
5305  stream = &ssn->server;
5306  ostream = &ssn->client;
5307  }
5308 
5309  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
5310  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
5311  if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
5312  SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
5315  return 1;
5316  }
5317  SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
5318  return 0;
5319 }
5320 
5321 /**
5322  * \retval 1 packet is a keep alive ACK pkt
5323  * \retval 0 packet is not a keep alive ACK pkt
5324  */
5325 static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
5326 {
5327  TcpStream *stream = NULL, *ostream = NULL;
5328  uint32_t seq;
5329  uint32_t ack;
5330  uint32_t pkt_win;
5331 
5332  if (p->flags & PKT_PSEUDO_STREAM_END)
5333  return 0;
5334  /* should get a normal ACK to a Keep Alive */
5335  if (p->payload_len > 0)
5336  return 0;
5337 
5338  const TCPHdr *tcph = PacketGetTCP(p);
5339  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5340  return 0;
5341 
5342  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5343  return 0;
5344 
5345  if (PKT_IS_TOSERVER(p)) {
5346  stream = &ssn->client;
5347  ostream = &ssn->server;
5348  } else {
5349  stream = &ssn->server;
5350  ostream = &ssn->client;
5351  }
5352 
5353  seq = TCP_GET_RAW_SEQ(tcph);
5354  ack = TCP_GET_RAW_ACK(tcph);
5355 
5356  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5357  if (pkt_win != ostream->window)
5358  return 0;
5359 
5360  if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
5361  SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
5362  ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
5364  return 1;
5365  }
5366  SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
5367  ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
5368  return 0;
5369 }
5370 
5371 static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
5372 {
5373  TcpStream *stream = NULL;
5374 
5375  if (p->flags & PKT_PSEUDO_STREAM_END)
5376  return;
5377 
5378  if (PKT_IS_TOSERVER(p)) {
5379  stream = &ssn->client;
5380  } else {
5381  stream = &ssn->server;
5382  }
5383 
5384  if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
5386  SCLogDebug("FLAG_KEEPALIVE cleared");
5387  }
5388 }
5389 
5390 /**
5391  * \retval 1 packet is a window update pkt
5392  * \retval 0 packet is not a window update pkt
5393  */
5394 static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
5395 {
5396  TcpStream *stream = NULL, *ostream = NULL;
5397  uint32_t seq;
5398  uint32_t ack;
5399  uint32_t pkt_win;
5400 
5401  if (p->flags & PKT_PSEUDO_STREAM_END)
5402  return 0;
5403 
5404  if (ssn->state < TCP_ESTABLISHED)
5405  return 0;
5406 
5407  if (p->payload_len > 0)
5408  return 0;
5409 
5410  const TCPHdr *tcph = PacketGetTCP(p);
5411  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5412  return 0;
5413 
5414  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5415  return 0;
5416 
5417  if (PKT_IS_TOSERVER(p)) {
5418  stream = &ssn->client;
5419  ostream = &ssn->server;
5420  } else {
5421  stream = &ssn->server;
5422  ostream = &ssn->client;
5423  }
5424 
5425  seq = TCP_GET_RAW_SEQ(tcph);
5426  ack = TCP_GET_RAW_ACK(tcph);
5427 
5428  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5429  if (pkt_win == ostream->window)
5430  return 0;
5431 
5432  if (ack == ostream->last_ack && seq == stream->next_seq) {
5433  SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
5435  return 1;
5436  }
5437  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5438  return 0;
5439 }
5440 
5441 /**
5442  * Try to detect whether a packet is a valid FIN 4whs final ack.
5443  *
5444  */
5445 static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
5446 {
5447  TcpStream *stream = NULL, *ostream = NULL;
5448  uint32_t seq;
5449  uint32_t ack;
5450 
5451  if (p->flags & PKT_PSEUDO_STREAM_END)
5452  return 0;
5453  if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
5454  return 0;
5455  const TCPHdr *tcph = PacketGetTCP(p);
5456  if (tcph->th_flags != TH_ACK)
5457  return 0;
5458  if (p->payload_len != 0)
5459  return 0;
5460 
5461  if (PKT_IS_TOSERVER(p)) {
5462  stream = &ssn->client;
5463  ostream = &ssn->server;
5464  } else {
5465  stream = &ssn->server;
5466  ostream = &ssn->client;
5467  }
5468 
5469  seq = TCP_GET_RAW_SEQ(tcph);
5470  ack = TCP_GET_RAW_ACK(tcph);
5471 
5472  SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
5473  p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
5474 
5475  if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
5476  return 1;
5477  }
5478  return 0;
5479 }
5480 
5481 /**
5482  * Try to detect packets doing bad window updates
5483  *
5484  * See bug 1238.
5485  *
5486  * Find packets that are unexpected, and shrink the window to the point
5487  * where the packets we do expect are rejected for being out of window.
5488  *
5489  * The logic we use here is:
5490  * - packet seq > next_seq
5491  * - packet ack > next_seq (packet acks unseen data)
5492  * - packet shrinks window more than it's own data size
5493  * - packet shrinks window more than the diff between it's ack and the
5494  * last_ack value
5495  *
5496  * Packets coming in after packet loss can look quite a bit like this.
5497  */
5498 static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
5499 {
5500  TcpStream *stream = NULL, *ostream = NULL;
5501  uint32_t seq;
5502  uint32_t ack;
5503  uint32_t pkt_win;
5504 
5505  if (p->flags & PKT_PSEUDO_STREAM_END)
5506  return 0;
5507 
5508  if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
5509  return 0;
5510 
5511  const TCPHdr *tcph = PacketGetTCP(p);
5512  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5513  return 0;
5514 
5515  if (PKT_IS_TOSERVER(p)) {
5516  stream = &ssn->client;
5517  ostream = &ssn->server;
5518  } else {
5519  stream = &ssn->server;
5520  ostream = &ssn->client;
5521  }
5522 
5523  seq = TCP_GET_RAW_SEQ(tcph);
5524  ack = TCP_GET_RAW_ACK(tcph);
5525  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5526 
5527  if (pkt_win < ostream->window) {
5528  uint32_t diff = ostream->window - pkt_win;
5529  if (diff > p->payload_len &&
5530  SEQ_GT(ack, ostream->next_seq) &&
5531  SEQ_GT(seq, stream->next_seq))
5532  {
5533  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
5534  p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
5535  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
5536  p->pcap_cnt, pkt_win, ostream->window);
5537  SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
5538  p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
5539  ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
5540 
5541  /* get the expected window shrinking from looking at ack vs last_ack.
5542  * Observed a lot of just a little overrunning that value. So added some
5543  * margin that is still ok. To make sure this isn't a loophole to still
5544  * close the window, this is limited to windows above 1024. Both values
5545  * are rather arbitrary. */
5546  uint32_t adiff = ack - ostream->last_ack;
5547  if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
5548  ((pkt_win <= 1024) && (diff > adiff)))
5549  {
5550  SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
5551  "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
5552  SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
5554  return 1;
5555  }
5556  }
5557 
5558  }
5559  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5560  return 0;
5561 }
5562 
5563 /** \internal
5564  * \brief call packet handling function for 'state'
5565  * \param state current TCP state
5566  */
5567 static inline int StreamTcpStateDispatch(
5568  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state)
5569 {
5570  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5571 
5572  SCLogDebug("ssn: %p", ssn);
5573  switch (state) {
5574  case TCP_SYN_SENT:
5575  SCLogDebug("packet received on TCP_SYN_SENT state");
5576  if (StreamTcpPacketStateSynSent(tv, p, stt, ssn)) {
5577  return -1;
5578  }
5579  break;
5580  case TCP_SYN_RECV:
5581  SCLogDebug("packet received on TCP_SYN_RECV state");
5582  if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn)) {
5583  return -1;
5584  }
5585  break;
5586  case TCP_ESTABLISHED:
5587  SCLogDebug("packet received on TCP_ESTABLISHED state");
5588  if (StreamTcpPacketStateEstablished(tv, p, stt, ssn)) {
5589  return -1;
5590  }
5591  break;
5592  case TCP_FIN_WAIT1:
5593  SCLogDebug("packet received on TCP_FIN_WAIT1 state");
5594  if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn)) {
5595  return -1;
5596  }
5597  break;
5598  case TCP_FIN_WAIT2:
5599  SCLogDebug("packet received on TCP_FIN_WAIT2 state");
5600  if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn)) {
5601  return -1;
5602  }
5603  break;
5604  case TCP_CLOSING:
5605  SCLogDebug("packet received on TCP_CLOSING state");
5606  if (StreamTcpPacketStateClosing(tv, p, stt, ssn)) {
5607  return -1;
5608  }
5609  break;
5610  case TCP_CLOSE_WAIT:
5611  SCLogDebug("packet received on TCP_CLOSE_WAIT state");
5612  if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn)) {
5613  return -1;
5614  }
5615  break;
5616  case TCP_LAST_ACK:
5617  SCLogDebug("packet received on TCP_LAST_ACK state");
5618  if (StreamTcpPacketStateLastAck(tv, p, stt, ssn)) {
5619  return -1;
5620  }
5621  break;
5622  case TCP_TIME_WAIT:
5623  SCLogDebug("packet received on TCP_TIME_WAIT state");
5624  if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn)) {
5625  return -1;
5626  }
5627  break;
5628  case TCP_CLOSED:
5629  /* TCP session memory is not returned to pool until timeout. */
5630  SCLogDebug("packet received on closed state");
5631 
5632  if (StreamTcpPacketStateClosed(tv, p, stt, ssn)) {
5633  return -1;
5634  }
5635 
5636  break;
5637  default:
5638  SCLogDebug("packet received on default state");
5639  break;
5640  }
5641  return 0;
5642 }
5643 
5644 static inline void CheckThreadId(ThreadVars *tv, Packet *p, StreamTcpThread *stt)
5645 {
5646  const int idx = (!(PKT_IS_TOSERVER(p)));
5647 
5648  /* assign the thread id to the flow */
5649  if (likely(p->flow->thread_id[idx] != 0)) {
5650  if (unlikely((FlowThreadId)tv->id != p->flow->thread_id[idx])) {
5651  SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id[idx], tv->id);
5652  if (p->pkt_src == PKT_SRC_WIRE) {
5654  if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
5655  p->flow->flags |= FLOW_WRONG_THREAD;
5657  }
5658  }
5659  }
5660  }
5661 }
5662 
5663 /* flow is and stays locked */
5665  PacketQueueNoLock *pq)
5666 {
5667  SCEnter();
5668 
5670 
5671  SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
5672 
5673  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
5674  const TCPHdr *tcph = PacketGetTCP(p);
5675 
5676  /* track TCP flags */
5677  if (ssn != NULL) {
5678  ssn->tcp_packet_flags |= tcph->th_flags;
5679  if (PKT_IS_TOSERVER(p))
5680  ssn->client.tcp_flags |= tcph->th_flags;
5681  else if (PKT_IS_TOCLIENT(p))
5682  ssn->server.tcp_flags |= tcph->th_flags;
5683 
5684  /* check if we need to unset the ASYNC flag */
5685  if (ssn->flags & STREAMTCP_FLAG_ASYNC &&
5686  ssn->client.tcp_flags != 0 &&
5687  ssn->server.tcp_flags != 0)
5688  {
5689  SCLogDebug("ssn %p: removing ASYNC flag as we have packets on both sides", ssn);
5690  ssn->flags &= ~STREAMTCP_FLAG_ASYNC;
5691  }
5692  }
5693 
5694  /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */
5695  if (!(tcph->th_flags & TH_ACK) && TCP_GET_RAW_ACK(tcph) != 0) {
5697  }
5698 
5699  if ((tcph->th_flags & TH_URG) && StreamTcpInlineDropUrg()) {
5701  SCLogDebug("dropping urgent packet");
5702  SCReturnInt(0);
5703  }
5704 
5705  /* If we are on IPS mode, and got a drop action triggered from
5706  * the IP only module, or from a reassembled msg and/or from an
5707  * applayer detection, then drop the rest of the packets of the
5708  * same stream and avoid inspecting it any further */
5709  if (StreamTcpCheckFlowDrops(p) == 1) {
5711  SCLogDebug("flow triggered a drop rule");
5713  /* return the segments to the pool */
5715  SCReturnInt(0);
5716  }
5717 
5718  if (ssn == NULL || ssn->state == TCP_NONE) {
5719  if (StreamTcpPacketStateNone(tv, p, stt, ssn) == -1) {
5720  goto error;
5721  }
5722 
5723  if (ssn != NULL)
5724  SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto);
5725  } else {
5726  /* special case for PKT_PSEUDO_STREAM_END packets:
5727  * bypass the state handling and various packet checks,
5728  * we care about reassembly here. */
5729  if (p->flags & PKT_PSEUDO_STREAM_END) {
5730  if (PKT_IS_TOCLIENT(p)) {
5731  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5732  } else {
5733  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5734  }
5735  /* straight to 'skip' as we already handled reassembly */
5736  goto skip;
5737  }
5738 
5739  if (p->flow->flags & FLOW_WRONG_THREAD) {
5740  /* Stream and/or session in known bad condition. Block events
5741  * from being set. */
5743  }
5744 
5745  if (StreamTcpPacketIsKeepAlive(ssn, p) == 1) {
5746  goto skip;
5747  }
5748  if (StreamTcpPacketIsKeepAliveACK(ssn, p) == 1) {
5749  StreamTcpClearKeepAliveFlag(ssn, p);
5750  goto skip;
5751  }
5752  StreamTcpClearKeepAliveFlag(ssn, p);
5753 
5754  const bool is_zwp_ack = StreamTcpPacketIsZeroWindowProbeAck(ssn, p);
5755  if (PKT_IS_TOCLIENT(p)) {
5756  ssn->flags &= ~STREAMTCP_FLAG_ZWP_TS;
5757  } else {
5758  ssn->flags &= ~STREAMTCP_FLAG_ZWP_TC;
5759  }
5760  if (is_zwp_ack) {
5762  goto skip;
5763  }
5764 
5765  if (StreamTcpPacketIsDupAck(ssn, p)) {
5767  // TODO see if we can skip work on these
5768  }
5769 
5770  /* if packet is not a valid window update, check if it is perhaps
5771  * a bad window update that we should ignore (and alert on) */
5772  if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) {
5773  if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0) {
5774  if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
5775  goto skip;
5776  if (StreamTcpPacketIsOutdatedAck(ssn, p))
5777  goto skip;
5778  }
5779  }
5780 
5781  int ret = StreamTcpPacketIsSpuriousRetransmission(ssn, p);
5782  if (ret > 0) {
5784  /* skip packet if fully before base_seq */
5785  if (ret == 2)
5786  goto skip;
5787  }
5788 
5789  /* handle the per 'state' logic */
5790  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->state) < 0)
5791  goto error;
5792 
5793  skip:
5794  StreamTcpPacketCheckPostRst(ssn, p);
5795 
5796  if (ssn->state >= TCP_ESTABLISHED) {
5797  p->flags |= PKT_STREAM_EST;
5798  }
5799  }
5800 
5801  if (ssn != NULL) {
5802  /* recalc the csum on the packet if it was modified */
5803  if (p->flags & PKT_STREAM_MODIFIED) {
5805  }
5806  /* check for conditions that may make us not want to log this packet */
5807 
5808  /* streams that hit depth */
5811  {
5812  /* we can call bypass callback, if enabled */
5813  if (StreamTcpBypassEnabled()) {
5815  }
5816  }
5817 
5820  {
5822  }
5823 
5824  /* encrypted packets */
5827  {
5829  }
5830 
5831  if (ssn->flags & STREAMTCP_FLAG_BYPASS) {
5833  } else if (g_detect_disabled &&
5837  {
5838  /* if stream is dead and we have no detect engine at all, bypass. */
5839  SCLogDebug("bypass as stream is dead and we have no rules");
5841  }
5842  }
5843 
5844  SCReturnInt(0);
5845 
5846 error:
5847  /* recalc the csum on the packet if it was modified */
5848  if (p->flags & PKT_STREAM_MODIFIED) {
5850  }
5851 
5852  if (StreamTcpInlineDropInvalid()) {
5853  /* disable payload inspection as we're dropping this packet
5854  * anyway. Doesn't disable all detection, so we can still
5855  * match on the stream event that was set. */
5856  DecodeSetNoPayloadInspectionFlag(p);
5858  }
5859  SCReturnInt(-1);
5860 }
5861 
5862 /**
5863  * \brief Function to validate the checksum of the received packet. If the
5864  * checksum is invalid, packet will be dropped, as the end system will
5865  * also drop the packet.
5866  *
5867  * \param p Packet of which checksum has to be validated
5868  * \retval 1 if the checksum is valid, otherwise 0
5869  */
5870 static inline int StreamTcpValidateChecksum(Packet *p)
5871 {
5872  int ret = 1;
5873 
5874  if (p->flags & PKT_IGNORE_CHECKSUM)
5875  return ret;
5876 
5877  if (!p->l4.csum_set) {
5878  const TCPHdr *tcph = PacketGetTCP(p);
5879  if (PacketIsIPv4(p)) {
5880  const IPV4Hdr *ip4h = PacketGetIPv4(p);
5881  p->l4.csum = TCPChecksum(ip4h->s_ip_addrs, (uint16_t *)tcph,
5882  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5883  p->l4.csum_set = true;
5884  } else if (PacketIsIPv6(p)) {
5885  const IPV6Hdr *ip6h = PacketGetIPv6(p);
5886  p->l4.csum = TCPV6Checksum(ip6h->s_ip6_addrs, (uint16_t *)tcph,
5887  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5888  p->l4.csum_set = true;
5889  }
5890  }
5891 
5892  if (p->l4.csum != 0) {
5893  ret = 0;
5894  if (p->livedev) {
5895  (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1);
5896  } else if (p->pcap_cnt) {
5898  }
5899  }
5900 
5901  return ret;
5902 }
5903 
5904 /** \internal
5905  * \brief check if a packet is a valid stream started
5906  * \retval bool true/false */
5907 static int TcpSessionPacketIsStreamStarter(const Packet *p)
5908 {
5909  const TCPHdr *tcph = PacketGetTCP(p);
5910  if (tcph->th_flags & (TH_RST | TH_FIN)) {
5911  return 0;
5912  }
5913 
5914  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5915  SCLogDebug("packet %" PRIu64 " is a stream starter: %02x", p->pcap_cnt, tcph->th_flags);
5916  return 1;
5917  }
5918 
5920  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5921  SCLogDebug("packet %" PRIu64 " is a midstream stream starter: %02x", p->pcap_cnt,
5922  tcph->th_flags);
5923  return 1;
5924  }
5925  }
5926  return 0;
5927 }
5928 
5929 /** \internal
5930  * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused
5931  * \retval bool true yes reuse, false no keep tracking old ssn */
5932 static bool TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn)
5933 {
5934  const TCPHdr *tcph = PacketGetTCP(p);
5935  if (FlowGetPacketDirection(f, p) == TOSERVER) {
5936  if (ssn == NULL) {
5937  /* most likely a flow that was picked up after the 3whs, or a flow that
5938  * does not have a session due to memcap issues. */
5939  SCLogDebug("steam starter packet %" PRIu64 ", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5940  return true;
5941  }
5943  SCLogDebug("steam starter packet %" PRIu64
5944  ", ssn %p. STREAMTCP_FLAG_TFO_DATA_IGNORED set. Reuse.",
5945  p->pcap_cnt, ssn);
5946  return true;
5947  }
5948  if (SEQ_EQ(ssn->client.isn, TCP_GET_RAW_SEQ(tcph))) {
5949  SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5950  return false;
5951  }
5952  if (ssn->state >= TCP_LAST_ACK) {
5953  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5954  return true;
5955  } else if (ssn->state == TCP_NONE) {
5956  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5957  return true;
5958  } else { // < TCP_LAST_ACK
5959  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5960  return false;
5961  }
5962 
5963  } else {
5964  if (ssn == NULL) {
5965  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5966  return true;
5967  }
5968  if (ssn->state >= TCP_LAST_ACK) {
5969  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5970  return true;
5971  } else if (ssn->state == TCP_NONE) {
5972  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5973  return true;
5974  } else { // < TCP_LAST_ACK
5975  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5976  return false;
5977  }
5978  }
5979 
5980  SCLogDebug("default: how did we get here?");
5981  return false;
5982 }
5983 
5984 /** \internal
5985  * \brief check if ssn is done enough for reuse by syn/ack
5986  * \note should only be called if midstream is enabled
5987  */
5988 static bool TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn)
5989 {
5990  const TCPHdr *tcph = PacketGetTCP(p);
5991  if (FlowGetPacketDirection(f, p) == TOCLIENT) {
5992  if (ssn == NULL) {
5993  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
5994  return false;
5995  }
5996  if (SEQ_EQ(ssn->server.isn, TCP_GET_RAW_SEQ(tcph))) {
5997  SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5998  return false;
5999  }
6000  if (ssn->state >= TCP_LAST_ACK) {
6001  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
6002  return true;
6003  } else if (ssn->state == TCP_NONE) {
6004  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
6005  return true;
6006  } else { // < TCP_LAST_ACK
6007  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
6008  return false;
6009  }
6010 
6011  } else {
6012  if (ssn == NULL) {
6013  SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
6014  return true;
6015  }
6016  if (ssn->state >= TCP_LAST_ACK) {
6017  SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
6018  return true;
6019  } else if (ssn->state == TCP_NONE) {
6020  SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
6021  return true;
6022  } else { // < TCP_LAST_ACK
6023  SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
6024  return false;
6025  }
6026  }
6027 
6028  SCLogDebug("default: how did we get here?");
6029  return false;
6030 }
6031 
6032 /** \brief Check if SSN is done enough for reuse
6033  *
6034  * Reuse means a new TCP session reuses the tuple (flow in suri)
6035  *
6036  * \retval bool true if ssn can be reused, false if not */
6037 static bool TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn)
6038 {
6039  const TCPHdr *tcph = PacketGetTCP(p);
6040  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
6041  return TcpSessionReuseDoneEnoughSyn(p, f, ssn);
6042  }
6043 
6045  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
6046  return TcpSessionReuseDoneEnoughSynAck(p, f, ssn);
6047  }
6048  }
6049 
6050  return false;
6051 }
6052 
6053 bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
6054 {
6055  if (p->proto == IPPROTO_TCP && PacketIsTCP(p)) {
6056  if (TcpSessionPacketIsStreamStarter(p) == 1) {
6057  if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) {
6058  return true;
6059  }
6060  }
6061  }
6062  return false;
6063 }
6064 
6066 {
6067  DEBUG_VALIDATE_BUG_ON(p->flow == NULL);
6068  if (unlikely(p->flow == NULL)) {
6069  return TM_ECODE_OK;
6070  }
6071 
6072  StreamTcpThread *stt = (StreamTcpThread *)data;
6073 
6074  SCLogDebug("p->pcap_cnt %" PRIu64 " direction %s pkt_src %s", p->pcap_cnt,
6075  p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
6076  : "noflow",
6077  PktSrcToString(p->pkt_src));
6078  t_pcapcnt = p->pcap_cnt;
6079 
6080  if (!(PacketIsTCP(p))) {
6081  return TM_ECODE_OK;
6082  }
6083 
6084  CheckThreadId(tv, p, stt);
6085 
6086  /* only TCP packets with a flow from here */
6087 
6088  if (!(p->flags & PKT_PSEUDO_STREAM_END)) {
6090  if (StreamTcpValidateChecksum(p) == 0) {
6092  return TM_ECODE_OK;
6093  }
6094  }
6095  }
6097 
6098  (void)StreamTcpPacket(tv, p, stt, pq);
6099 
6100  return TM_ECODE_OK;
6101 }
6102 
6103 TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
6104 {
6105  SCEnter();
6106  StreamTcpThread *stt = SCCalloc(1, sizeof(StreamTcpThread));
6107  if (unlikely(stt == NULL))
6109  stt->ssn_pool_id = -1;
6111 
6112  *data = (void *)stt;
6113 
6114  stt->counter_tcp_active_sessions = StatsRegisterCounter("tcp.active_sessions", tv);
6115  stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv);
6116  stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv);
6117  stt->counter_tcp_ssn_from_cache = StatsRegisterCounter("tcp.ssn_from_cache", tv);
6118  stt->counter_tcp_ssn_from_pool = StatsRegisterCounter("tcp.ssn_from_pool", tv);
6120  stream_config.ssn_memcap_policy, "exception_policy.tcp.ssn_memcap.",
6121  IsStreamTcpSessionMemcapExceptionPolicyStatsValid);
6122 
6123  stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv);
6124  stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv);
6125  stt->counter_tcp_midstream_pickups = StatsRegisterCounter("tcp.midstream_pickups", tv);
6126  if (stream_config.midstream) {
6129  "exception_policy.tcp.midstream.", IsMidstreamExceptionPolicyStatsValid);
6130  } else {
6133  "exception_policy.tcp.midstream.", IsMidstreamExceptionPolicyStatsValid);
6134  }
6135 
6136  stt->counter_tcp_wrong_thread = StatsRegisterCounter("tcp.pkt_on_wrong_thread", tv);
6137  stt->counter_tcp_ack_unseen_data = StatsRegisterCounter("tcp.ack_unseen_data", tv);
6138 
6139  /* init reassembly ctx */
6141  if (stt->ra_ctx == NULL)
6143 
6144  stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv);
6145 
6148  "exception_policy.tcp.reassembly.", IsReassemblyMemcapExceptionPolicyStatsValid);
6149 
6151  StatsRegisterCounter("tcp.segment_from_cache", tv);
6152  stt->ra_ctx->counter_tcp_segment_from_pool = StatsRegisterCounter("tcp.segment_from_pool", tv);
6153  stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv);
6154  stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv);
6155  stt->ra_ctx->counter_tcp_reass_overlap = StatsRegisterCounter("tcp.overlap", tv);
6156  stt->ra_ctx->counter_tcp_reass_overlap_diff_data = StatsRegisterCounter("tcp.overlap_diff_data", tv);
6157 
6158  stt->ra_ctx->counter_tcp_reass_data_normal_fail = StatsRegisterCounter("tcp.insert_data_normal_fail", tv);
6159  stt->ra_ctx->counter_tcp_reass_data_overlap_fail = StatsRegisterCounter("tcp.insert_data_overlap_fail", tv);
6160  stt->ra_ctx->counter_tcp_urgent_oob = StatsRegisterCounter("tcp.urgent_oob_data", tv);
6161 
6162  SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p",
6163  stt, stt->ra_ctx);
6164 
6165  SCMutexLock(&ssn_pool_mutex);
6166  if (ssn_pool == NULL) {
6167  ssn_pool = PoolThreadInit(1, /* thread */
6168  0, /* unlimited */
6170  sizeof(TcpSession),
6171  StreamTcpSessionPoolAlloc,
6172  StreamTcpSessionPoolInit, NULL,
6173  StreamTcpSessionPoolCleanup, NULL);
6174  stt->ssn_pool_id = 0;
6175  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6176  } else {
6177  /* grow ssn_pool until we have a element for our thread id */
6179  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6180  }
6181  SCMutexUnlock(&ssn_pool_mutex);
6182  if (stt->ssn_pool_id < 0 || ssn_pool == NULL) {
6183  SCLogError("failed to setup/expand stream session pool. Expand stream.memcap?");
6185  }
6186 
6188 }
6189 
6191 {
6192  SCEnter();
6193  StreamTcpThread *stt = (StreamTcpThread *)data;
6194  if (stt == NULL) {
6195  return TM_ECODE_OK;
6196  }
6197 
6198  /* XXX */
6199 
6200  /* free reassembly ctx */
6202 
6203  /* clear memory */
6204  memset(stt, 0, sizeof(StreamTcpThread));
6205 
6206  SCFree(stt);
6208 }
6209 
6210 /**
6211  * \brief Function to check the validity of the RST packets based on the
6212  * target OS of the given packet.
6213  *
6214  * \param ssn TCP session to which the given packet belongs
6215  * \param p Packet which has to be checked for its validity
6216  *
6217  * \retval 0 unacceptable RST
6218  * \retval 1 acceptable RST
6219  *
6220  * WebSense sends RST packets that are:
6221  * - RST flag, win 0, ack 0, seq = nextseq
6222  *
6223  */
6224 
6225 static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
6226 {
6227  uint8_t os_policy;
6228  const TCPHdr *tcph = PacketGetTCP(p);
6229  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6230 
6232  SCReturnInt(1);
6233  }
6234 
6235  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
6236  if (!StreamTcpValidateTimestamp(ssn, p)) {
6237  SCReturnInt(0);
6238  }
6239  }
6240 
6241  /* RST with data, it's complicated:
6242 
6243  4.2.2.12 RST Segment: RFC-793 Section 3.4
6244 
6245  A TCP SHOULD allow a received RST segment to include data.
6246 
6247  DISCUSSION
6248  It has been suggested that a RST segment could contain
6249  ASCII text that encoded and explained the cause of the
6250  RST. No standard has yet been established for such
6251  data.
6252  */
6253  if (p->payload_len)
6255 
6256  /* Set up the os_policy to be used in validating the RST packets based on
6257  target system */
6258  if (PKT_IS_TOSERVER(p)) {
6259  if (ssn->server.os_policy == 0)
6260  StreamTcpSetOSPolicy(&ssn->server, p);
6261 
6262  os_policy = ssn->server.os_policy;
6263 
6264  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6265  StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
6266  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6268  SCReturnInt(0);
6269  }
6270 
6271  } else {
6272  if (ssn->client.os_policy == 0)
6273  StreamTcpSetOSPolicy(&ssn->client, p);
6274 
6275  os_policy = ssn->client.os_policy;
6276 
6277  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6278  StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
6279  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6281  SCReturnInt(0);
6282  }
6283  }
6284 
6285  /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
6286  * validate these (requires key that is set/transferred out of band), we can't know
6287  * if the RST will be accepted or rejected by the end host. We accept it, but keep
6288  * tracking if the sender of it ignores it, which would be a sign of injection. */
6290  TcpStream *receiver_stream;
6291  if (PKT_IS_TOSERVER(p)) {
6292  receiver_stream = &ssn->server;
6293  } else {
6294  receiver_stream = &ssn->client;
6295  }
6296  SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
6297  receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
6298  }
6299 
6300  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
6301  if (PKT_IS_TOSERVER(p)) {
6302  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6303  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6304  return 1;
6305  }
6306  } else {
6307  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6308  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6309  return 1;
6310  }
6311  }
6312  SCLogDebug("ssn %p: ASYNC reject RST", ssn);
6313  return 0;
6314  }
6315 
6316  switch (os_policy) {
6317  case OS_POLICY_HPUX11:
6318  if(PKT_IS_TOSERVER(p)){
6319  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6320  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6321  return 1;
6322  } else {
6323  SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " "
6324  "and server SEQ: %" PRIu32 "",
6325  seq, ssn->client.next_seq);
6326  return 0;
6327  }
6328  } else { /* implied to client */
6329  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6330  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6331  return 1;
6332  } else {
6333  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6334  "and client SEQ: %" PRIu32 "",
6335  seq, ssn->server.next_seq);
6336  return 0;
6337  }
6338  }
6339  break;
6340  case OS_POLICY_OLD_LINUX:
6341  case OS_POLICY_LINUX:
6342  case OS_POLICY_SOLARIS:
6343  if(PKT_IS_TOSERVER(p)){
6344  if (SEQ_GEQ((seq + p->payload_len),
6345  ssn->client.last_ack)) { /*window base is needed !!*/
6346  if (SEQ_LT(seq, (ssn->client.next_seq + ssn->client.window))) {
6347  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6348  return 1;
6349  }
6350  } else {
6351  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6352  " server SEQ: %" PRIu32 "",
6353  seq, ssn->client.next_seq);
6354  return 0;
6355  }
6356  } else { /* implied to client */
6357  if (SEQ_GEQ((seq + p->payload_len),
6358  ssn->server.last_ack)) { /*window base is needed !!*/
6359  if (SEQ_LT(seq, (ssn->server.next_seq + ssn->server.window))) {
6360  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6361  return 1;
6362  }
6363  } else {
6364  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6365  " client SEQ: %" PRIu32 "",
6366  seq, ssn->server.next_seq);
6367  return 0;
6368  }
6369  }
6370  break;
6371  default:
6372  case OS_POLICY_BSD:
6373  case OS_POLICY_FIRST:
6374  case OS_POLICY_HPUX10:
6375  case OS_POLICY_IRIX:
6376  case OS_POLICY_MACOS:
6377  case OS_POLICY_LAST:
6378  case OS_POLICY_WINDOWS:
6379  case OS_POLICY_WINDOWS2K3:
6380  case OS_POLICY_VISTA:
6381  if(PKT_IS_TOSERVER(p)) {
6382  if (SEQ_EQ(seq, ssn->client.next_seq)) {
6383  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6384  return 1;
6385  } else {
6386  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6387  "and server SEQ: %" PRIu32 "",
6388  seq, ssn->client.next_seq);
6389  return 0;
6390  }
6391  } else { /* implied to client */
6392  if (SEQ_EQ(seq, ssn->server.next_seq)) {
6393  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u", seq,
6394  ssn->server.next_seq);
6395  return 1;
6396  } else {
6397  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6398  " client SEQ: %" PRIu32 "",
6399  seq, ssn->server.next_seq);
6400  return 0;
6401  }
6402  }
6403  break;
6404  }
6405  return 0;
6406 }
6407 
6408 /**
6409  * \brief Function to check the validity of the received timestamp based on
6410  * the target OS of the given stream.
6411  *
6412  * It's passive except for:
6413  * 1. it sets the os policy on the stream if necessary
6414  * 2. it sets an event in the packet if necessary
6415  *
6416  * \param ssn TCP session to which the given packet belongs
6417  * \param p Packet which has to be checked for its validity
6418  *
6419  * \retval 1 if the timestamp is valid
6420  * \retval 0 if the timestamp is invalid
6421  */
6422 static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p)
6423 {
6424  SCEnter();
6425 
6426  TcpStream *sender_stream;
6427  TcpStream *receiver_stream;
6428  uint8_t ret = 1;
6429  uint8_t check_ts = 1;
6430  const TCPHdr *tcph = PacketGetTCP(p);
6431  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6432 
6433  if (PKT_IS_TOSERVER(p)) {
6434  sender_stream = &ssn->client;
6435  receiver_stream = &ssn->server;
6436  } else {
6437  sender_stream = &ssn->server;
6438  receiver_stream = &ssn->client;
6439  }
6440 
6441  /* Set up the os_policy to be used in validating the timestamps based on
6442  the target system */
6443  if (receiver_stream->os_policy == 0) {
6444  StreamTcpSetOSPolicy(receiver_stream, p);
6445  }
6446 
6447  if (TCP_HAS_TS(p)) {
6448  uint32_t ts = TCP_GET_TSVAL(p);
6449  uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
6450  uint32_t last_ts = sender_stream->last_ts;
6451 
6452  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6453  /* The 3whs used the timestamp with 0 value. */
6454  switch (receiver_stream->os_policy) {
6455  case OS_POLICY_LINUX:
6456  case OS_POLICY_WINDOWS2K3:
6457  /* Linux and windows 2003 does not allow the use of 0 as
6458  * timestamp in the 3whs. */
6459  check_ts = 0;
6460  break;
6461 
6462  case OS_POLICY_OLD_LINUX:
6463  case OS_POLICY_WINDOWS:
6464  case OS_POLICY_VISTA:
6465  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6466  last_ts = ts;
6467  check_ts = 0; /*next packet will be checked for validity
6468  and stream TS has been updated with this
6469  one.*/
6470  }
6471  break;
6472  }
6473  }
6474 
6475  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6476  /* HPUX11 ignores the timestamp of out of order packets */
6477  if (!SEQ_EQ(sender_stream->next_seq, seq))
6478  check_ts = 0;
6479  }
6480 
6481  if (ts == 0) {
6482  switch (receiver_stream->os_policy) {
6483  case OS_POLICY_OLD_LINUX:
6484  case OS_POLICY_WINDOWS:
6485  case OS_POLICY_WINDOWS2K3:
6486  case OS_POLICY_VISTA:
6487  case OS_POLICY_SOLARIS:
6488  /* Old Linux and windows allowed packet with 0 timestamp. */
6489  break;
6490  default:
6491  /* other OS simply drop the packet with 0 timestamp, when
6492  * 3whs has valid timestamp*/
6493  goto invalid;
6494  }
6495  }
6496 
6497  if (check_ts) {
6498  int32_t result = 0;
6499 
6500  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts);
6501 
6502  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6503  /* Linux accepts TS which are off by one.*/
6504  result = (int32_t) ((ts - last_ts) + 1);
6505  } else {
6506  result = (int32_t) (ts - last_ts);
6507  }
6508 
6509  SCLogDebug("result %" PRIi32 ", p->ts(secs) %" PRIuMAX "", result,
6510  (uintmax_t)SCTIME_SECS(p->ts));
6511 
6512  if (last_pkt_ts == 0 &&
6514  {
6515  last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6516  }
6517 
6518  if (result < 0) {
6519  SCLogDebug("timestamp is not valid last_ts "
6520  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6521  "%" PRId32 "", last_ts, ts, result);
6522  /* candidate for rejection */
6523  ret = 0;
6524  } else if ((sender_stream->last_ts != 0) &&
6525  (((uint32_t)SCTIME_SECS(p->ts)) > last_pkt_ts + PAWS_24DAYS)) {
6526  SCLogDebug("packet is not valid last_pkt_ts "
6527  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6528  last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6529  /* candidate for rejection */
6530  ret = 0;
6531  }
6532 
6533  if (ret == 0) {
6534  /* if the timestamp of packet is not valid then, check if the
6535  * current stream timestamp is not so old. if so then we need to
6536  * accept the packet and update the stream->last_ts (RFC 1323)*/
6537  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6538  (((uint32_t)SCTIME_SECS(p->ts) > (last_pkt_ts + PAWS_24DAYS)))) {
6539  SCLogDebug("timestamp considered valid anyway");
6540  } else {
6541  goto invalid;
6542  }
6543  }
6544  }
6545  }
6546 
6547  SCReturnInt(1);
6548 
6549 invalid:
6551  SCReturnInt(0);
6552 }
6553 
6554 /**
6555  * \brief Function to check the validity of the received timestamp based on
6556  * the target OS of the given stream and update the session.
6557  *
6558  * \param ssn TCP session to which the given packet belongs
6559  * \param p Packet which has to be checked for its validity
6560  *
6561  * \retval 1 if the timestamp is valid
6562  * \retval 0 if the timestamp is invalid
6563  */
6564 static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p)
6565 {
6566  SCEnter();
6567 
6568  TcpStream *sender_stream;
6569  TcpStream *receiver_stream;
6570  uint8_t ret = 1;
6571  uint8_t check_ts = 1;
6572  const TCPHdr *tcph = PacketGetTCP(p);
6573  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6574 
6575  if (PKT_IS_TOSERVER(p)) {
6576  sender_stream = &ssn->client;
6577  receiver_stream = &ssn->server;
6578  } else {
6579  sender_stream = &ssn->server;
6580  receiver_stream = &ssn->client;
6581  }
6582 
6583  /* Set up the os_policy to be used in validating the timestamps based on
6584  the target system */
6585  if (receiver_stream->os_policy == 0) {
6586  StreamTcpSetOSPolicy(receiver_stream, p);
6587  }
6588 
6589  if (TCP_HAS_TS(p)) {
6590  uint32_t ts = TCP_GET_TSVAL(p);
6591 
6592  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6593  /* The 3whs used the timestamp with 0 value. */
6594  switch (receiver_stream->os_policy) {
6595  case OS_POLICY_LINUX:
6596  case OS_POLICY_WINDOWS2K3:
6597  /* Linux and windows 2003 does not allow the use of 0 as
6598  * timestamp in the 3whs. */
6600  check_ts = 0;
6601  break;
6602 
6603  case OS_POLICY_OLD_LINUX:
6604  case OS_POLICY_WINDOWS:
6605  case OS_POLICY_VISTA:
6606  sender_stream->flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
6607  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6608  sender_stream->last_ts = ts;
6609  check_ts = 0; /*next packet will be checked for validity
6610  and stream TS has been updated with this
6611  one.*/
6612  }
6613  break;
6614  default:
6615  break;
6616  }
6617  }
6618 
6619  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6620  /*HPUX11 ignores the timestamp of out of order packets*/
6621  if (!SEQ_EQ(sender_stream->next_seq, seq))
6622  check_ts = 0;
6623  }
6624 
6625  if (ts == 0) {
6626  switch (receiver_stream->os_policy) {
6627  case OS_POLICY_OLD_LINUX:
6628  case OS_POLICY_WINDOWS:
6629  case OS_POLICY_WINDOWS2K3:
6630  case OS_POLICY_VISTA:
6631  case OS_POLICY_SOLARIS:
6632  /* Old Linux and windows allowed packet with 0 timestamp. */
6633  break;
6634  default:
6635  /* other OS simply drop the packet with 0 timestamp, when
6636  * 3whs has valid timestamp*/
6637  goto invalid;
6638  }
6639  }
6640 
6641  if (check_ts) {
6642  int32_t result = 0;
6643 
6644  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts);
6645 
6646  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6647  /* Linux accepts TS which are off by one.*/
6648  result = (int32_t) ((ts - sender_stream->last_ts) + 1);
6649  } else {
6650  result = (int32_t) (ts - sender_stream->last_ts);
6651  }
6652 
6653  SCLogDebug("result %" PRIi32 ", p->ts(sec) %" PRIuMAX "", result,
6654  (uintmax_t)SCTIME_SECS(p->ts));
6655 
6656  if (sender_stream->last_pkt_ts == 0 &&
6658  {
6659  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6660  }
6661 
6662  if (result < 0) {
6663  SCLogDebug("timestamp is not valid sender_stream->last_ts "
6664  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6665  "%" PRId32 "", sender_stream->last_ts, ts, result);
6666  /* candidate for rejection */
6667  ret = 0;
6668  } else if ((sender_stream->last_ts != 0) &&
6669  (((uint32_t)SCTIME_SECS(p->ts)) >
6670  sender_stream->last_pkt_ts + PAWS_24DAYS)) {
6671  SCLogDebug("packet is not valid sender_stream->last_pkt_ts "
6672  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6673  sender_stream->last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6674  /* candidate for rejection */
6675  ret = 0;
6676  }
6677 
6678  if (ret == 1) {
6679  /* Update the timestamp and last seen packet time for this
6680  * stream */
6681  if (SEQ_EQ(sender_stream->next_seq, seq))
6682  sender_stream->last_ts = ts;
6683 
6684  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6685 
6686  } else if (ret == 0) {
6687  /* if the timestamp of packet is not valid then, check if the
6688  * current stream timestamp is not so old. if so then we need to
6689  * accept the packet and update the stream->last_ts (RFC 1323)*/
6690  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6691  (((uint32_t)SCTIME_SECS(p->ts) >
6692  (sender_stream->last_pkt_ts + PAWS_24DAYS)))) {
6693  sender_stream->last_ts = ts;
6694  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6695 
6696  SCLogDebug("timestamp considered valid anyway");
6697  } else {
6698  goto invalid;
6699  }
6700  }
6701  }
6702  } else {
6703  /* Solaris stops using timestamps if a packet is received
6704  without a timestamp and timestamps were used on that stream. */
6705  if (receiver_stream->os_policy == OS_POLICY_SOLARIS)
6707  }
6708 
6709  SCReturnInt(1);
6710 
6711 invalid:
6713  SCReturnInt(0);
6714 }
6715 
6716 /**
6717  * \brief Function to test the received ACK values against the stream window
6718  * and previous ack value. ACK values should be higher than previous
6719  * ACK value and less than the next_win value.
6720  *
6721  * \param ssn TcpSession for state access
6722  * \param stream TcpStream of which last_ack needs to be tested
6723  * \param p Packet which is used to test the last_ack
6724  *
6725  * \retval 0 ACK is valid, last_ack is updated if ACK was higher
6726  * \retval -1 ACK is invalid
6727  */
6728 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p)
6729 {
6730  SCEnter();
6731 
6732  const TCPHdr *tcph = PacketGetTCP(p);
6733  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
6734 
6735  if (!(tcph->th_flags & TH_ACK))
6736  SCReturnInt(0);
6737 
6738  /* fast track */
6739  if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win))
6740  {
6741  SCLogDebug("ssn %p: ACK %u in bounds > %u <= %u", ssn, ack, stream->last_ack,
6742  stream->next_win);
6743  SCReturnInt(0);
6744  }
6745  /* fast track */
6746  else if (SEQ_EQ(ack, stream->last_ack)) {
6747  SCLogDebug("ssn %p: pkt ACK %" PRIu32 " == stream last ACK %" PRIu32, ssn, ack,
6748  stream->last_ack);
6749  SCReturnInt(0);
6750  }
6751 
6752  /* exception handling */
6753  if (SEQ_LT(ack, stream->last_ack)) {
6754  SCLogDebug("pkt ACK %" PRIu32 " < stream last ACK %" PRIu32, ack, stream->last_ack);
6755 
6756  /* This is an attempt to get a 'left edge' value that we can check against.
6757  * It doesn't work when the window is 0, need to think of a better way. */
6758 
6759  if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) {
6760  SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window "
6761  "%"PRIu32" = %"PRIu32, ack, stream->last_ack,
6762  stream->window, stream->last_ack - stream->window);
6763  goto invalid;
6764  }
6765 
6766  SCReturnInt(0);
6767  }
6768 
6769  /* no further checks possible for ASYNC */
6770  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
6771  SCReturnInt(0);
6772  }
6773 
6774  if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) {
6775  SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win);
6776  goto invalid;
6777  /* a toclient RST as a response to SYN, next_win is 0, ack will be isn+1, just like
6778  * the syn ack */
6779  } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && tcph->th_flags & TH_RST &&
6780  SEQ_EQ(ack, stream->isn + 1)) {
6781  SCReturnInt(0);
6782  }
6783 
6784  SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32
6785  " next_win %"PRIu32, ack, stream->last_ack, stream->next_win);
6786 invalid:
6788  SCReturnInt(-1);
6789 }
6790 
6791 /** \brief update reassembly progress
6792 
6793  * \param ssn TCP Session
6794  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6795  */
6797  const uint32_t progress)
6798 {
6799  if (direction) {
6800  ssn->server.app_progress_rel += progress;
6801  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->server));
6802  } else {
6803  ssn->client.app_progress_rel += progress;
6804  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->client));
6805  }
6806 }
6807 
6808 /** \brief disable reassembly
6809 
6810  * Disable app layer and set raw inspect to no longer accept new data.
6811  * Stream engine will then fully disable raw after last inspection.
6812  *
6813  * \param ssn TCP Session to set the flag in
6814  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6815  */
6817 {
6819  StreamTcpSetDisableRawReassemblyFlag(ssn, direction);
6820 }
6821 
6822 /** \brief Set the No reassembly flag for the given direction in given TCP
6823  * session.
6824  *
6825  * \param ssn TCP Session to set the flag in
6826  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6827  */
6829 {
6830  direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) :
6832 }
6833 
6834 /** \brief enable bypass
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  ssn->flags |= STREAMTCP_FLAG_BYPASS;
6842 }
6843 
6844 /** \brief Create a pseudo packet injected into the engine to signal the
6845  * opposing direction of this stream trigger detection/logging.
6846  *
6847  * \param parent real packet
6848  * \param pq packet queue to store the new pseudo packet in
6849  * \param dir 0 ts 1 tc
6850  */
6851 static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv,
6852  StreamTcpThread *stt, Packet *parent,
6853  TcpSession *ssn, PacketQueueNoLock *pq, int dir)
6854 {
6855  SCEnter();
6856  Flow *f = parent->flow;
6857  TCPHdr *tcph = NULL;
6858 
6859  if (parent->flags & PKT_PSEUDO_DETECTLOG_FLUSH) {
6860  SCReturn;
6861  }
6862  if ((f->flags & (FLOW_IPV4 | FLOW_IPV6)) == 0) {
6863  SCReturn;
6864  }
6865 
6866  Packet *np = PacketPoolGetPacket();
6867  if (np == NULL) {
6868  SCReturn;
6869  }
6871 
6872  np->tenant_id = f->tenant_id;
6873  np->datalink = DLT_RAW;
6874  np->proto = IPPROTO_TCP;
6875  FlowReference(&np->flow, f);
6876  np->flags |= PKT_STREAM_EST;
6877  np->flags |= PKT_HAS_FLOW;
6878  np->flags |= PKT_IGNORE_CHECKSUM;
6880  memcpy(&np->vlan_id[0], &f->vlan_id[0], sizeof(np->vlan_id));
6881  np->vlan_idx = f->vlan_idx;
6882  np->livedev = (struct LiveDevice_ *)f->livedev;
6883 
6884  if (parent->flags & PKT_NOPACKET_INSPECTION) {
6885  DecodeSetNoPacketInspectionFlag(np);
6886  }
6887  if (parent->flags & PKT_NOPAYLOAD_INSPECTION) {
6888  DecodeSetNoPayloadInspectionFlag(np);
6889  }
6890 
6891  if (dir == 0) {
6892  SCLogDebug("pseudo is to_server");
6894  } else {
6895  SCLogDebug("pseudo is to_client");
6897  }
6899  np->payload = NULL;
6900  np->payload_len = 0;
6901 
6902  if (FLOW_IS_IPV4(f)) {
6903  if (dir == 0) {
6906  np->sp = f->sp;
6907  np->dp = f->dp;
6908  } else {
6911  np->sp = f->dp;
6912  np->dp = f->sp;
6913  }
6914 
6915  /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
6916  * Force an allocation if it is not the case.
6917  */
6918  if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) {
6919  if (PacketCallocExtPkt(np, 40) == -1) {
6920  goto error;
6921  }
6922  }
6923  /* set the ip header */
6924  IPV4Hdr *ip4h = PacketSetIPV4(np, GET_PKT_DATA(np));
6925  /* version 4 and length 20 bytes for the tcp header */
6926  ip4h->ip_verhl = 0x45;
6927  ip4h->ip_tos = 0;
6928  ip4h->ip_len = htons(40);
6929  ip4h->ip_id = 0;
6930  ip4h->ip_off = 0;
6931  ip4h->ip_ttl = 64;
6932  ip4h->ip_proto = IPPROTO_TCP;
6933  if (dir == 0) {
6934  ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
6935  ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
6936  } else {
6937  ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
6938  ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
6939  }
6940 
6941  /* set the tcp header */
6942  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 20);
6943 
6944  SET_PKT_LEN(np, 40); /* ipv4 hdr + tcp hdr */
6945  } else {
6946  /* implied IPv6 */
6947 
6948  if (dir == 0) {
6951  np->sp = f->sp;
6952  np->dp = f->dp;
6953  } else {
6956  np->sp = f->dp;
6957  np->dp = f->sp;
6958  }
6959 
6960  /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
6961  * Force an allocation if it is not the case.
6962  */
6963  if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) {
6964  if (PacketCallocExtPkt(np, 60) == -1) {
6965  goto error;
6966  }
6967  }
6968  /* set the ip header */
6969  IPV6Hdr *ip6h = PacketSetIPV6(np, GET_PKT_DATA(np));
6970  /* version 6 */
6971  ip6h->s_ip6_vfc = 0x60;
6972  ip6h->s_ip6_flow = 0;
6973  ip6h->s_ip6_nxt = IPPROTO_TCP;
6974  ip6h->s_ip6_plen = htons(20);
6975  ip6h->s_ip6_hlim = 64;
6976  if (dir == 0) {
6977  ip6h->s_ip6_src[0] = f->src.addr_data32[0];
6978  ip6h->s_ip6_src[1] = f->src.addr_data32[1];
6979  ip6h->s_ip6_src[2] = f->src.addr_data32[2];
6980  ip6h->s_ip6_src[3] = f->src.addr_data32[3];
6981  ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
6982  ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
6983  ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
6984  ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
6985  } else {
6986  ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
6987  ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
6988  ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
6989  ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
6990  ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
6991  ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
6992  ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
6993  ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
6994  }
6995 
6996  /* set the tcp header */
6997  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 40);
6998 
6999  SET_PKT_LEN(np, 60); /* ipv6 hdr + tcp hdr */
7000  }
7001 
7002  tcph->th_offx2 = 0x50;
7003  tcph->th_flags |= TH_ACK;
7004  tcph->th_win = 10;
7005  tcph->th_urp = 0;
7006 
7007  /* to server */
7008  if (dir == 0) {
7009  tcph->th_sport = htons(f->sp);
7010  tcph->th_dport = htons(f->dp);
7011 
7012  tcph->th_seq = htonl(ssn->client.next_seq);
7013  tcph->th_ack = htonl(ssn->server.last_ack);
7014 
7015  /* to client */
7016  } else {
7017  tcph->th_sport = htons(f->dp);
7018  tcph->th_dport = htons(f->sp);
7019 
7020  tcph->th_seq = htonl(ssn->server.next_seq);
7021  tcph->th_ack = htonl(ssn->client.last_ack);
7022  }
7023 
7024  /* use parent time stamp */
7025  np->ts = parent->ts;
7026 
7027  SCLogDebug("np %p", np);
7028  PacketEnqueueNoLock(pq, np);
7029 
7031  SCReturn;
7032 error:
7033  FlowDeReference(&np->flow);
7034  SCReturn;
7035 }
7036 
7037 /** \brief create packets in both directions to flush out logging
7038  * and detection before switching protocols.
7039  * In IDS mode, create first in packet dir, 2nd in opposing
7040  * In IPS mode, do the reverse.
7041  * Flag TCP engine that data needs to be inspected regardless
7042  * of how far we are wrt inspect limits.
7043  */
7045  PacketQueueNoLock *pq)
7046 {
7047  TcpSession *ssn = f->protoctx;
7050  bool ts = PKT_IS_TOSERVER(p) ? true : false;
7051  ts ^= StreamTcpInlineMode();
7052  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^0);
7053  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^1);
7054 }
7055 
7056 /**
7057  * \brief Run callback function on each TCP segment in a single direction.
7058  *
7059  * \note when stream engine is running in inline mode all segments are used,
7060  * in IDS/non-inline mode only ack'd segments are iterated.
7061  *
7062  * \note Must be called under flow lock.
7063  * \var flag determines the direction to run callback on (either to server or to client).
7064  *
7065  * \return -1 in case of error, the number of segment in case of success
7066  *
7067  */
7068 int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
7069 {
7070  TcpStream *stream = NULL;
7071  int cnt = 0;
7072 
7073  if (p->flow == NULL)
7074  return 0;
7075 
7076  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
7077  if (ssn == NULL) {
7078  return 0;
7079  }
7080 
7081  if (flag & STREAM_DUMP_TOSERVER) {
7082  stream = &(ssn->server);
7083  } else {
7084  stream = &(ssn->client);
7085  }
7086 
7087  /* for IDS, return ack'd segments. For IPS all. */
7088  TcpSegment *seg;
7089  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
7091  if (PKT_IS_PSEUDOPKT(p)) {
7092  /* use un-ACK'd data as well */
7093  } else {
7094  /* in IDS mode, use ACK'd data */
7095  if (SEQ_GEQ(seg->seq, stream->last_ack)) {
7096  break;
7097  }
7098  }
7099  }
7100 
7101  const uint8_t *seg_data;
7102  uint32_t seg_datalen;
7103  StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
7104 
7105  int ret = CallbackFunc(p, seg, data, seg_data, seg_datalen);
7106  if (ret != 1) {
7107  SCLogDebug("Callback function has failed");
7108  return -1;
7109  }
7110 
7111  cnt++;
7112  }
7113  return cnt;
7114 }
7115 
7116 /**
7117  * \brief Run callback function on each TCP segment in both directions of a session.
7118  *
7119  * \note when stream engine is running in inline mode all segments are used,
7120  * in IDS/non-inline mode only ack'd segments are iterated.
7121  *
7122  * \note Must be called under flow lock.
7123  *
7124  * \return -1 in case of error, the number of segment in case of success
7125  *
7126  */
7128  const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
7129 {
7130  int ret = 0;
7131  int cnt = 0;
7132 
7133  if (p->flow == NULL)
7134  return 0;
7135 
7136  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
7137 
7138  if (ssn == NULL) {
7139  return -1;
7140  }
7141 
7142  TcpStream *server_stream = &(ssn->server);
7143  TcpStream *client_stream = &(ssn->client);
7144 
7145  TcpSegment *server_node = RB_MIN(TCPSEG, &server_stream->seg_tree);
7146  TcpSegment *client_node = RB_MIN(TCPSEG, &client_stream->seg_tree);
7147  if (server_node == NULL && client_node == NULL) {
7148  return cnt;
7149  }
7150 
7151  while (server_node != NULL || client_node != NULL) {
7152  const uint8_t *seg_data;
7153  uint32_t seg_datalen;
7154  if (server_node == NULL) {
7155  /*
7156  * This means the server side RB Tree has been completely searched,
7157  * thus all that remains is to dump the TcpSegments on the client
7158  * side.
7159  */
7161  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7162  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7163  if (ret != 1) {
7164  SCLogDebug("Callback function has failed");
7165  return -1;
7166  }
7167  client_node = TCPSEG_RB_NEXT(client_node);
7168  } else if (client_node == NULL) {
7169  /*
7170  * This means the client side RB Tree has been completely searched,
7171  * thus all that remains is to dump the TcpSegments on the server
7172  * side.
7173  */
7175  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7176  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7177  if (ret != 1) {
7178  SCLogDebug("Callback function has failed");
7179  return -1;
7180  }
7181  server_node = TCPSEG_RB_NEXT(server_node);
7182  } else {
7183  if (SCTIME_CMP_LT(
7184  client_node->pcap_hdr_storage->ts, server_node->pcap_hdr_storage->ts)) {
7186  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7187  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7188  if (ret != 1) {
7189  SCLogDebug("Callback function has failed");
7190  return -1;
7191  }
7192  client_node = TCPSEG_RB_NEXT(client_node);
7193  } else {
7195  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7196  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7197  if (ret != 1) {
7198  SCLogDebug("Callback function has failed");
7199  return -1;
7200  }
7201  server_node = TCPSEG_RB_NEXT(server_node);
7202  }
7203  }
7204 
7205  cnt++;
7206  }
7207  return cnt;
7208 }
7209 
7211 {
7213 }
7214 
7215 /**
7216  * \brief See if stream engine is operating in inline mode
7217  *
7218  * \retval 0 no
7219  * \retval 1 yes
7220  */
7222 {
7224 }
7225 
7226 
7227 void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
7228 {
7229  if (size > ssn->reassembly_depth || size == 0) {
7230  ssn->reassembly_depth = size;
7231  }
7232 }
7233 
7234 const char *StreamTcpStateAsString(const enum TcpState state)
7235 {
7236  const char *tcp_state = NULL;
7237  switch (state) {
7238  case TCP_NONE:
7239  tcp_state = "none";
7240  break;
7241  case TCP_SYN_SENT:
7242  tcp_state = "syn_sent";
7243  break;
7244  case TCP_SYN_RECV:
7245  tcp_state = "syn_recv";
7246  break;
7247  case TCP_ESTABLISHED:
7248  tcp_state = "established";
7249  break;
7250  case TCP_FIN_WAIT1:
7251  tcp_state = "fin_wait1";
7252  break;
7253  case TCP_FIN_WAIT2:
7254  tcp_state = "fin_wait2";
7255  break;
7256  case TCP_TIME_WAIT:
7257  tcp_state = "time_wait";
7258  break;
7259  case TCP_LAST_ACK:
7260  tcp_state = "last_ack";
7261  break;
7262  case TCP_CLOSE_WAIT:
7263  tcp_state = "close_wait";
7264  break;
7265  case TCP_CLOSING:
7266  tcp_state = "closing";
7267  break;
7268  case TCP_CLOSED:
7269  tcp_state = "closed";
7270  break;
7271  }
7272  return tcp_state;
7273 }
7274 
7275 #ifdef UNITTESTS
7276 #include "tests/stream-tcp.c"
7277 #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
StreamTcpThread_::counter_tcp_midstream_pickups
uint16_t counter_tcp_midstream_pickups
Definition: stream-tcp.h:108
TCP_GET_RAW_SEQ
#define TCP_GET_RAW_SEQ(tcph)
Definition: decode-tcp.h:80
PoolThreadInit
PoolThread * PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int(*Init)(void *, void *), void *InitData, void(*Cleanup)(void *), void(*Free)(void *))
per thread Pool, initialization function
Definition: util-pool-thread.c: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
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
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
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:166
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
OS_POLICY_FIRST
@ OS_POLICY_FIRST
Definition: stream-tcp-reassemble.h:50
OS_POLICY_MACOS
@ OS_POLICY_MACOS
Definition: stream-tcp-reassemble.h:46
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:1096
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
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:6053
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:7221
StreamTcpThreadCacheGetSession
TcpSession * StreamTcpThreadCacheGetSession(void)
Definition: stream-tcp-cache.c:190
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
PKT_DROP_REASON_STREAM_MEMCAP
@ PKT_DROP_REASON_STREAM_MEMCAP
Definition: decode.h:392
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:49
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:279
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
util-pool-thread.h
seq
uint32_t seq
Definition: stream-tcp-private.h:2
StatsRegisterGlobalCounter
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
Definition: counters.c:1026
StreamTcpThread_
Definition: stream-tcp.h:92
StreamTcpSetSessionNoReassemblyFlag
void StreamTcpSetSessionNoReassemblyFlag(TcpSession *ssn, char direction)
disable reassembly
Definition: stream-tcp.c:6816
StreamTcpThreadCacheReturnSession
void StreamTcpThreadCacheReturnSession(TcpSession *ssn)
Definition: stream-tcp-cache.c:93
StreamTcpSackFreeList
void StreamTcpSackFreeList(TcpStream *stream)
Free SACK tree from a stream.
Definition: stream-tcp-sack.c:438
STREAM_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
StreamTcpThread_::counter_tcp_ssn_from_cache
uint16_t counter_tcp_ssn_from_cache
Definition: stream-tcp.h:99
TcpReassemblyThreadCtx_::counter_tcp_stream_depth
uint16_t counter_tcp_stream_depth
Definition: stream-tcp-reassemble.h:75
STREAMTCP_FLAG_ZWP_TC
#define STREAMTCP_FLAG_ZWP_TC
Definition: stream-tcp-private.h:210
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
StreamTcpThread_::counter_tcp_sessions
uint16_t counter_tcp_sessions
Definition: stream-tcp.h:96
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
OS_POLICY_IRIX
@ OS_POLICY_IRIX
Definition: stream-tcp-reassemble.h:45
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:6103
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
TcpReassemblyThreadCtx_::counter_tcp_reass_overlap
uint16_t counter_tcp_reass_overlap
Definition: stream-tcp-reassemble.h:80
StreamTcpUpdateAppLayerProgress
void StreamTcpUpdateAppLayerProgress(TcpSession *ssn, char direction, const uint32_t progress)
update reassembly progress
Definition: stream-tcp.c:6796
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
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
PoolThreadFree
void PoolThreadFree(PoolThread *pt)
destroy the thread pool
Definition: util-pool-thread.c:156
TcpReassemblyThreadCtx_::counter_tcp_reass_overlap_diff_data
uint16_t counter_tcp_reass_overlap_diff_data
Definition: stream-tcp-reassemble.h:82
TCP_STREAM_URGENT_GAP
@ TCP_STREAM_URGENT_GAP
Definition: stream-tcp.h:50
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
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
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
StreamTcpThread_::counter_tcp_ssn_memcap
uint16_t counter_tcp_ssn_memcap
Definition: stream-tcp.h:98
TcpReassemblyThreadCtx_::counter_tcp_reass_data_normal_fail
uint16_t counter_tcp_reass_data_normal_fail
Definition: stream-tcp-reassemble.h:84
TcpStream_::last_ack
uint32_t last_ack
Definition: stream-tcp-private.h:115
IPV4Hdr_::ip_len
uint16_t ip_len
Definition: decode-ipv4.h:75
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
TCP_CLOSE_WAIT
@ TCP_CLOSE_WAIT
Definition: stream-tcp-private.h:160
TCP_GET_TSVAL
#define TCP_GET_TSVAL(p)
Definition: decode-tcp.h:88
TcpStream_::last_ts
uint32_t last_ts
Definition: stream-tcp-private.h:119
TCPHdr_::th_flags
uint8_t th_flags
Definition: decode-tcp.h:155
decode.h
TcpStreamCnf_::ssn_memcap_policy
enum ExceptionPolicy ssn_memcap_policy
Definition: stream-tcp.h:80
util-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:7127
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
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:539
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
ExceptionPolicyCounters_::eps_id
uint16_t eps_id[EXCEPTION_POLICY_MAX]
Definition: util-exception-policy-types.h:54
util-print.h
STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE
#define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE
Definition: stream-tcp.c:89
StreamTcpThread_::counter_tcp_wrong_thread
uint16_t counter_tcp_wrong_thread
Definition: stream-tcp.h:112
SCEnter
#define SCEnter(...)
Definition: util-debug.h:281
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
StreamTcpThread_::counter_tcp_invalid_checksum
uint16_t counter_tcp_invalid_checksum
Definition: stream-tcp.h:106
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
StreamTcp
TmEcode StreamTcp(ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq)
Definition: stream-tcp.c:6065
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:5664
Packet_::sp
Port sp
Definition: decode.h:508
TCP_GET_TSECR
#define TCP_GET_TSECR(p)
Definition: decode-tcp.h:91
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:860
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:7068
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:259
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:87
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:283
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
stream-tcp-sack.h
stream-tcp-private.h
TcpReassemblyThreadCtx_::counter_tcp_urgent_oob
uint16_t counter_tcp_urgent_oob
Definition: stream-tcp-reassemble.h:88
conf.h
Packet_::l4
struct PacketL4 l4
Definition: decode.h: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
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
StreamTcpThread_::counter_tcp_ssn_from_pool
uint16_t counter_tcp_ssn_from_pool
Definition: stream-tcp.h:100
STREAMTCP_DEFAULT_MEMCAP
#define STREAMTCP_DEFAULT_MEMCAP
Definition: stream-tcp.c:86
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:270
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
OS_POLICY_BSD_RIGHT
@ OS_POLICY_BSD_RIGHT
Definition: stream-tcp-reassemble.h:38
TcpReassemblyThreadCtx_::counter_tcp_reass_gap
uint16_t counter_tcp_reass_gap
Definition: stream-tcp-reassemble.h:77
WarnInvalidConfEntry
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition: util-misc.h:35
FlowUpdateState
void FlowUpdateState(Flow *f, const enum FlowState s)
Definition: flow.c:1164
Flow_::src
FlowAddress src
Definition: flow.h:351
util-host-os-info.h
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
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
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
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
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
TcpStream_::sb
StreamingBuffer sb
Definition: stream-tcp-private.h:135
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
StreamTcpThread_::counter_tcp_active_sessions
uint16_t counter_tcp_active_sessions
Definition: stream-tcp.h:95
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP
#define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP
Definition: stream-tcp.c:87
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:514
STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
Definition: stream-tcp-private.h:236
OS_POLICY_SOLARIS
@ OS_POLICY_SOLARIS
Definition: stream-tcp-reassemble.h:42
TCPVars_::md5_option_present
uint8_t md5_option_present
Definition: decode-tcp.h:164
STREAMTCP_FLAG_MIDSTREAM_SYNACK
#define STREAMTCP_FLAG_MIDSTREAM_SYNACK
Definition: stream-tcp-private.h:174
TcpSession_::client
TcpStream client
Definition: stream-tcp-private.h:297
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:2000
TCP_CLOSING
@ TCP_CLOSING
Definition: stream-tcp-private.h:161
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
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:7044
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
OS_POLICY_OLD_SOLARIS
@ OS_POLICY_OLD_SOLARIS
Definition: stream-tcp-reassemble.h:41
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
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:271
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
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:7227
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
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:51
Flow_::flags
uint32_t flags
Definition: flow.h:413
TcpStream_::app_progress_rel
uint32_t app_progress_rel
Definition: stream-tcp-private.h:127
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:40
StreamTcpSessionCleanup
void StreamTcpSessionCleanup(TcpSession *ssn)
Session cleanup function. Does not free the ssn.
Definition: stream-tcp.c:335
TcpReassemblyThreadCtx_::counter_tcp_reass_data_overlap_fail
uint16_t counter_tcp_reass_data_overlap_fail
Definition: stream-tcp-reassemble.h:85
TcpStateQueue_::ts
uint32_t ts
Definition: stream-tcp-private.h:41
stream_reassembly_memcap_eps_stats
ExceptionPolicyStatsSetts stream_reassembly_memcap_eps_stats
Definition: stream-tcp.c: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:1109
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
StreamTcpThread_::counter_tcp_pseudo
uint16_t counter_tcp_pseudo
Definition: stream-tcp.h:104
StreamTcpThreadCacheEnable
void StreamTcpThreadCacheEnable(void)
enable segment cache. Should only be done for worker threads
Definition: stream-tcp-cache.c:48
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h: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:242
g_detect_disabled
int g_detect_disabled
Definition: suricata.c:186
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:7234
Flow_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: flow.h:372
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:39
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
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:47
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
TcpReassemblyThreadCtx_::counter_tcp_segment_from_pool
uint16_t counter_tcp_segment_from_pool
Definition: stream-tcp-reassemble.h:72
STREAMTCP_STREAM_FLAG_DISABLE_RAW
#define STREAMTCP_STREAM_FLAG_DISABLE_RAW
Definition: stream-tcp-private.h:238
Packet_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: decode.h:528
TCP_STREAM_URGENT_INLINE
@ TCP_STREAM_URGENT_INLINE
Definition: stream-tcp.h:46
likely
#define likely(expr)
Definition: util-optimize.h:32
OS_POLICY_VISTA
@ OS_POLICY_VISTA
Definition: stream-tcp-reassemble.h:48
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
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:44
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
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:43
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:247
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
StatsRegisterCounter
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:968
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
ssn_pool
PoolThread * ssn_pool
Definition: stream-tcp.c:221
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
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:285
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
StreamTcpThread_::counter_tcp_ack_unseen_data
uint16_t counter_tcp_ack_unseen_data
Definition: stream-tcp.h:114
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
TcpReassemblyThreadCtx_::counter_tcp_segment_memcap
uint16_t counter_tcp_segment_memcap
Definition: stream-tcp-reassemble.h:67
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
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
TcpReassemblyThreadCtx_::counter_tcp_segment_from_cache
uint16_t counter_tcp_segment_from_cache
Definition: stream-tcp-reassemble.h:71
PacketL4::vars
union PacketL4::L4Vars vars
STREAMTCP_FLAG_TCP_FAST_OPEN
#define STREAMTCP_FLAG_TCP_FAST_OPEN
Definition: stream-tcp-private.h:205
TcpStream_::wscale
uint16_t wscale
Definition: stream-tcp-private.h:109
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:6190
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:6828
StreamTcpSetSessionBypassFlag
void StreamTcpSetSessionBypassFlag(TcpSession *ssn)
enable bypass
Definition: stream-tcp.c:6839
StreamTcpBypassEnabled
int StreamTcpBypassEnabled(void)
Definition: stream-tcp.c:7210