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