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