suricata
stream-tcp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2026 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-print.h"
49 #include "util-debug.h"
50 #include "util-device-private.h"
51 
52 #include "stream-tcp-private.h"
53 #include "stream-tcp.h"
54 #include "stream-tcp-cache.h"
55 #include "stream-tcp-inline.h"
56 #include "stream-tcp-reassemble.h"
57 #include "stream-tcp-sack.h"
58 #include "stream-tcp-util.h"
59 #include "stream.h"
60 
61 #include "pkt-var.h"
62 #include "host.h"
63 
64 #include "app-layer.h"
65 #include "app-layer-parser.h"
66 #include "app-layer-protos.h"
67 #include "app-layer-htp-mem.h"
68 
69 #include "util-host-os-info.h"
70 #include "util-privs.h"
71 #include "util-profiling.h"
72 #include "util-misc.h"
73 #include "util-validate.h"
74 #include "util-runmodes.h"
75 #include "util-random.h"
76 #include "util-exception-policy.h"
77 
78 #include "source-pcap-file.h"
79 #include "action-globals.h"
80 
81 //#define DEBUG
82 
83 #define STREAMTCP_DEFAULT_PREALLOC 2048
84 #define STREAMTCP_DEFAULT_MEMCAP (64 * 1024 * 1024) /* 64mb */
85 #define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP (256 * 1024 * 1024) /* 256mb */
86 #define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE 2560
87 #define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE 2560
88 #define STREAMTCP_DEFAULT_MAX_SYN_QUEUED 10
89 #define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED 5
90 // 1 MiB
91 #define STREAM_DEPTH_DEFAULT 1024 * 1024
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 #if defined(DEBUG) || defined(QA_SIMULATION)
223 static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */
224 extern thread_local uint64_t t_pcapcnt;
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 
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)
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 (SCConfGetNonNull("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 (SCConfGetNonNull("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 (SCConfGetNonNull("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 (SCConfGetNonNull("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 (SCConfGetNonNull("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 (SCConfGetNonNull("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 (SCConfGetNonNull("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 */
856  stream_config.prealloc_sessions, sizeof(TcpSession), StreamTcpSessionPoolAlloc,
857  StreamTcpSessionPoolInit, StreamTcpSessionPoolCleanup);
858  }
859  SCMutexUnlock(&ssn_pool_mutex);
860  }
861 #endif
862 }
863 
864 void StreamTcpFreeConfig(bool quiet)
865 {
867 
868  SCMutexLock(&ssn_pool_mutex);
869  if (ssn_pool != NULL) {
871  ssn_pool = NULL;
872  }
873  SCMutexUnlock(&ssn_pool_mutex);
874  SCMutexDestroy(&ssn_pool_mutex);
875 
876  SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt);
877 }
878 
879 static bool IsReassemblyMemcapExceptionPolicyStatsValid(enum ExceptionPolicy exception_policy)
880 {
881  if (EngineModeIsIPS()) {
883  }
885 }
886 
887 static bool IsStreamTcpSessionMemcapExceptionPolicyStatsValid(enum ExceptionPolicy policy)
888 {
889  if (EngineModeIsIPS()) {
891  }
893 }
894 
895 static void StreamTcpSsnMemcapExceptionPolicyStatsIncr(
896  ThreadVars *tv, StreamTcpThread *stt, enum ExceptionPolicy policy)
897 {
898  const StatsCounterId id = stt->counter_tcp_ssn_memcap_eps.eps_id[policy];
899  if (likely(tv && id.id > 0)) {
900  StatsCounterIncr(&tv->stats, id);
901  }
902 }
903 
905 {
907 }
908 
910 {
912 }
913 
915 {
917 }
918 
919 /** \internal
920  * \brief The function is used to fetch a TCP session from the
921  * ssn_pool, when a TCP SYN is received.
922  *
923  * \param p packet starting the new TCP session.
924  * \param id thread pool id
925  *
926  * \retval ssn new TCP session.
927  */
928 static TcpSession *StreamTcpNewSession(ThreadVars *tv, StreamTcpThread *stt, Packet *p, int id)
929 {
931 
932  if (ssn == NULL) {
933  DEBUG_VALIDATE_BUG_ON(id < 0 || id > UINT16_MAX);
935  if (p->flow->protoctx != NULL) {
936 #ifdef UNITTESTS
937  if (tv)
938 #endif
940  } else {
941  p->flow->protoctx = PoolThreadGetById(ssn_pool, (uint16_t)id);
942  if (p->flow->protoctx != NULL)
943 #ifdef UNITTESTS
944  if (tv)
945 #endif
947  }
948 #if defined(DEBUG) || defined(QA_SIMULATION)
949  SCMutexLock(&ssn_pool_mutex);
950  if (p->flow->protoctx != NULL)
951  ssn_pool_cnt++;
952  SCMutexUnlock(&ssn_pool_mutex);
953 #ifdef QA_SIMULATION
954  if (unlikely((g_eps_stream_ssn_memcap != UINT64_MAX &&
955  g_eps_stream_ssn_memcap == t_pcapcnt))) {
956  SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt);
958  StreamTcpSsnMemcapExceptionPolicyStatsIncr(tv, stt, stream_config.ssn_memcap_policy);
959  return NULL;
960  }
961 #endif
962 #endif
963  ssn = (TcpSession *)p->flow->protoctx;
964  if (ssn == NULL) {
965  SCLogDebug("ssn_pool is empty");
967  StreamTcpSsnMemcapExceptionPolicyStatsIncr(tv, stt, stream_config.ssn_memcap_policy);
968  return NULL;
969  }
970 
971  const TCPHdr *tcph = PacketGetTCP(p);
972  ssn->state = TCP_NONE;
974  ssn->tcp_packet_flags = tcph->th_flags;
977 
979  ssn->client.sb = x;
980  ssn->server.sb = x;
981 
982  if (PKT_IS_TOSERVER(p)) {
983  ssn->client.tcp_flags = tcph->th_flags;
984  ssn->server.tcp_flags = 0;
985  } else if (PKT_IS_TOCLIENT(p)) {
986  ssn->server.tcp_flags = tcph->th_flags;
987  ssn->client.tcp_flags = 0;
988  }
989  }
990 
991  return ssn;
992 }
993 
994 static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn,
995  uint8_t state)
996 {
997  if (state == ssn->state || PKT_IS_PSEUDOPKT(p))
998  return;
999 
1000  ssn->pstate = ssn->state;
1001  ssn->state = state;
1003 
1004  /* update the flow state */
1005  switch(ssn->state) {
1006  case TCP_ESTABLISHED:
1007  case TCP_FIN_WAIT1:
1008  case TCP_FIN_WAIT2:
1009  case TCP_CLOSING:
1010  case TCP_CLOSE_WAIT:
1012  break;
1013  case TCP_LAST_ACK:
1014  case TCP_TIME_WAIT:
1015  case TCP_CLOSED:
1017  break;
1018  }
1019 }
1020 
1021 /**
1022  * \brief Function to set the OS policy for the given stream based on the
1023  * destination of the received packet.
1024  *
1025  * \param stream TcpStream of which os_policy needs to set
1026  * \param p Packet which is used to set the os policy
1027  */
1029 {
1030  if (PacketIsIPv4(p)) {
1031  /* Get the OS policy based on destination IP address, as destination
1032  OS will decide how to react on the anomalies of newly received
1033  packets */
1034  int ret = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
1035  if (ret > 0)
1036  stream->os_policy = (uint8_t)ret;
1037  else
1038  stream->os_policy = OS_POLICY_DEFAULT;
1039 
1040  } else if (PacketIsIPv6(p)) {
1041  /* Get the OS policy based on destination IP address, as destination
1042  OS will decide how to react on the anomalies of newly received
1043  packets */
1044  int ret = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
1045  if (ret > 0)
1046  stream->os_policy = (uint8_t)ret;
1047  else
1048  stream->os_policy = OS_POLICY_DEFAULT;
1049  }
1050 
1051  if (stream->os_policy == OS_POLICY_BSD_RIGHT)
1052  stream->os_policy = OS_POLICY_BSD;
1053  else if (stream->os_policy == OS_POLICY_OLD_SOLARIS)
1054  stream->os_policy = OS_POLICY_SOLARIS;
1055 
1056  SCLogDebug("Policy is %" PRIu8 "", stream->os_policy);
1057 }
1058 
1059 /**
1060  * \brief check if the reassembly base of a stream can still bound an ACK
1061  *
1062  * The base_seq of a direction is the sequence number of the first byte the
1063  * reassembly buffer holds, and it only moves when StreamTcpPruneSession()
1064  * slides that buffer. A direction that is done reassembling (reassembly depth
1065  * reached, or app-layer and raw both finished) never slides again, so its
1066  * base_seq stays behind while the sequence numbers of the stream keep
1067  * advancing. Since SEQ_GT() only compares within half the sequence space, such
1068  * a stale anchor reads as "ahead of the ACK" once 2^31 bytes went by, which
1069  * would freeze last_ack (and with it next_win) until the sequence space came
1070  * all the way round again 2^32 bytes later. Nothing is inserted in that
1071  * direction anymore, so the bound has nothing to protect there.
1072  *
1073  * \param stream stream to check
1074  * \retval true base_seq still tracks the stream, so it can bound an ACK
1075  * \retval false base_seq went stale, do not bound the ACK with it
1076  */
1077 static inline bool StreamTcpBaseSeqBoundsAck(const TcpStream *stream)
1078 {
1079  return (stream->flags &
1081 }
1082 
1083 /**
1084  * \brief macro to update last_ack only if the new value is higher
1085  *
1086  * \param ssn session
1087  * \param stream stream to update
1088  * \param ack ACK value to test and set
1089  */
1090 #define StreamTcpUpdateLastAck(ssn, stream, ack) \
1091  { \
1092  if (SEQ_GT((ack), (stream)->last_ack) && \
1093  (!StreamTcpBaseSeqBoundsAck(stream) || SEQ_GT(ack, (stream)->base_seq))) { \
1094  SCLogDebug("ssn %p: last_ack set to %" PRIu32 ", moved %u forward", (ssn), (ack), \
1095  (ack) - (stream)->last_ack); \
1096  if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && \
1097  SEQ_GT((ack), (stream)->next_seq))) { \
1098  SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), \
1099  (stream)->last_ack, (stream)->next_seq); \
1100  } else { \
1101  SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, \
1102  (int)(stream)->next_seq - (ack)); \
1103  } \
1104  (stream)->last_ack = (ack); \
1105  StreamTcpSackPruneList((stream)); \
1106  } else { \
1107  SCLogDebug("ssn %p: no update: ack %u, last_ack %" PRIu32 ", next_seq %u (state %u)", \
1108  (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \
1109  } \
1110  }
1111 
1112 #define StreamTcpAsyncLastAckUpdate(ssn, stream) { \
1113  if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \
1114  if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \
1115  uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \
1116  (stream)->last_ack += ack_diff; \
1117  SCLogDebug("ssn %p: ASYNC last_ack set to %"PRIu32", moved %u forward", \
1118  (ssn), (stream)->next_seq, ack_diff); \
1119  } \
1120  } \
1121 }
1122 
1123 #define StreamTcpUpdateNextSeq(ssn, stream, seq) { \
1124  (stream)->next_seq = seq; \
1125  SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \
1126  StreamTcpAsyncLastAckUpdate((ssn), (stream)); \
1127 }
1128 
1129 /**
1130  * \brief macro to update next_win only if the new value is higher
1131  *
1132  * \param ssn session
1133  * \param stream stream to update
1134  * \param win window value to test and set
1135  */
1136 #define StreamTcpUpdateNextWin(ssn, stream, win) { \
1137  uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \
1138  if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \
1139  (stream)->next_win = ((win) + sacked_size__); \
1140  SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \
1141  } \
1142 }
1143 
1144 static inline void StreamTcpCloseSsnWithReset(Packet *p, TcpSession *ssn)
1145 {
1147  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1148  SCLogDebug("ssn %p: (state: %s) Reset received and state changed to "
1149  "TCP_CLOSED", ssn, StreamTcpStateAsString(ssn->state));
1150 }
1151 
1152 static bool IsMidstreamExceptionPolicyStatsValid(enum ExceptionPolicy policy)
1153 {
1154  if (EngineModeIsIPS()) {
1155  if (stream_config.midstream) {
1157  }
1159  }
1160  if (stream_config.midstream) {
1162  }
1164 }
1165 
1166 static void StreamTcpMidstreamExceptionPolicyStatsIncr(
1167  ThreadVars *tv, StreamTcpThread *stt, enum ExceptionPolicy policy)
1168 {
1169  const StatsCounterId id = stt->counter_tcp_midstream_eps.eps_id[policy];
1170  if (likely(tv && id.id > 0)) {
1171  StatsCounterIncr(&tv->stats, id);
1172  }
1173 }
1174 
1175 static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p)
1176 {
1177  if (p->payload_len == 0)
1178  SCReturnInt(0);
1179 
1180  const TCPHdr *tcph = PacketGetTCP(p);
1181  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
1182  /* retransmission of already partially ack'd data */
1183  if (SEQ_LT(seq, stream->last_ack) && SEQ_GT((seq + p->payload_len), stream->last_ack)) {
1185  SCReturnInt(1);
1186  }
1187 
1188  /* retransmission of already ack'd data */
1189  if (SEQ_LEQ((seq + p->payload_len), stream->last_ack)) {
1191  SCReturnInt(1);
1192  }
1193 
1194  /* retransmission of in flight data */
1195  if (SEQ_LEQ((seq + p->payload_len), stream->next_seq)) {
1197  SCReturnInt(2);
1198  }
1199 
1200  SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", seq, p->payload_len,
1201  (seq + p->payload_len), stream->last_ack, stream->next_seq);
1202  SCReturnInt(0);
1203 }
1204 
1205 /**
1206  * \internal
1207  * \brief Function to handle the TCP_CLOSED or NONE state. The function handles
1208  * packets while the session state is None which means a newly
1209  * initialized structure, or a fully closed session.
1210  *
1211  * \param tv Thread Variable containing input/output queue, cpu affinity
1212  * \param p Packet which has to be handled in this TCP state.
1213  * \param stt Stream Thread module registered to handle the stream handling
1214  *
1215  * \retval 0 ok
1216  * \retval -1 error
1217  */
1218 static int StreamTcpPacketStateNone(
1220 {
1221  const TCPHdr *tcph = PacketGetTCP(p);
1222  if (tcph->th_flags & TH_RST) {
1224  SCLogDebug("RST packet received, no session setup");
1225  return -1;
1226 
1227  } else if (tcph->th_flags & TH_FIN) {
1228  /* Drop reason will only be used if midstream policy is set to fail closed */
1230  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1231 
1232  if (!stream_config.midstream || p->payload_len == 0) {
1234  SCLogDebug("FIN packet received, no session setup");
1235  return -1;
1236  }
1240  SCLogDebug("FIN packet received, no session setup");
1241  return -1;
1242  }
1243  SCLogDebug("midstream picked up");
1244 
1245  if (ssn == NULL) {
1246  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1247  if (ssn == NULL) {
1249  return -1;
1250  }
1254  }
1255  /* set the state */
1256  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
1257  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1258  "TCP_FIN_WAIT1",
1259  ssn);
1260 
1264  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1266  }
1267 
1268  /** window scaling for midstream pickups, we can't do much other
1269  * than assume that it's set to the max value: 14 */
1272 
1273  /* set the sequence numbers and window */
1274  ssn->client.isn = TCP_GET_RAW_SEQ(tcph) - 1;
1276  ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len + 1;
1280  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", ssn, ssn->client.isn,
1281  ssn->client.next_seq);
1282 
1283  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
1285  ssn->server.next_seq = ssn->server.isn + 1;
1288 
1289  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
1290  "ssn->server.next_win %" PRIu32 "",
1292  SCLogDebug("ssn %p: ssn->client.last_ack %" PRIu32 ", "
1293  "ssn->server.last_ack %" PRIu32 "",
1295 
1296  /* Set the timestamp value for both streams, if packet has timestamp
1297  * option enabled.*/
1298  if (TCP_HAS_TS(p)) {
1301  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " "
1302  "ssn->client.last_ts %" PRIu32 "",
1304 
1306 
1307  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1308  if (ssn->server.last_ts == 0)
1310  if (ssn->client.last_ts == 0)
1312 
1313  } else {
1314  ssn->server.last_ts = 0;
1315  ssn->client.last_ts = 0;
1316  }
1317 
1319 
1321  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1322 
1323  /* SYN/ACK */
1324  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
1325  /* Drop reason will only be used if midstream policy is set to fail closed */
1327  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1328 
1330  SCLogDebug("Midstream not enabled, so won't pick up a session");
1331  return 0;
1332  }
1335  SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1336  return 0;
1337  }
1338  SCLogDebug("midstream picked up");
1339 
1340  if (ssn == NULL) {
1341  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1342  if (ssn == NULL) {
1344  return -1;
1345  }
1349  }
1350 
1351  /* reverse packet and flow */
1352  SCLogDebug("reversing flow and packet");
1353  PacketSwap(p);
1354  FlowSwap(p->flow);
1355 
1356  /* set the state */
1357  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1358  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1359  "TCP_SYN_RECV", ssn);
1361  /* Flag used to change the direct in the later stage in the session */
1364  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1366  }
1367 
1368  /* sequence number & window */
1369  ssn->server.isn = TCP_GET_RAW_SEQ(tcph);
1371  ssn->server.next_seq = ssn->server.isn + 1;
1373  SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
1374 
1375  ssn->client.isn = TCP_GET_RAW_ACK(tcph) - 1;
1377  ssn->client.next_seq = ssn->client.isn + 1;
1378 
1381 
1383 
1384  /** If the client has a wscale option the server had it too,
1385  * so set the wscale for the server to max. Otherwise none
1386  * will have the wscale opt just like it should. */
1387  if (TCP_HAS_WSCALE(p)) {
1390  SCLogDebug("ssn %p: wscale enabled. client %u server %u",
1392  }
1393 
1394  SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
1395  " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
1397  ssn->client.last_ack);
1398  SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
1399  " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
1401  ssn->server.last_ack);
1402 
1403  /* Set the timestamp value for both streams, if packet has timestamp
1404  * option enabled.*/
1405  if (TCP_HAS_TS(p)) {
1408  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1409  "ssn->client.last_ts %" PRIu32"", ssn,
1411 
1413 
1414  ssn->server.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1415  if (ssn->server.last_ts == 0)
1417  if (ssn->client.last_ts == 0)
1419 
1420  } else {
1421  ssn->server.last_ts = 0;
1422  ssn->client.last_ts = 0;
1423  }
1424 
1425  if (TCP_GET_SACKOK(p)) {
1427  SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
1428  "SACK permitted for both sides", ssn);
1429  }
1430  return 0;
1431 
1432  } else if (tcph->th_flags & TH_SYN) {
1433  if (ssn == NULL) {
1434  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1435  if (ssn == NULL) {
1437  return -1;
1438  }
1439 
1442  }
1443 
1444  /* set the state */
1445  StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
1446  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
1447 
1449  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1451  }
1452 
1453  /* set the sequence numbers and window */
1454  ssn->client.isn = TCP_GET_RAW_SEQ(tcph);
1456  ssn->client.next_seq = ssn->client.isn + 1;
1457 
1458  /* Set the stream timestamp value, if packet has timestamp option
1459  * enabled. */
1460  if (TCP_HAS_TS(p)) {
1462  SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
1463 
1464  if (ssn->client.last_ts == 0)
1466 
1467  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1469  }
1470 
1472  if (TCP_HAS_WSCALE(p)) {
1475  }
1476 
1477  if (TCP_GET_SACKOK(p)) {
1479  SCLogDebug("ssn %p: SACK permitted on SYN packet", ssn);
1480  }
1481 
1482  if (TCP_HAS_TFO(p)) {
1484  if (p->payload_len) {
1486  SCLogDebug("ssn: %p (TFO) isn %u base_seq %u next_seq %u payload len %u", ssn,
1488  p->payload_len);
1490  p->flags |= PKT_STREAM_EST;
1491  }
1492  }
1493 
1494  SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
1495  "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
1496  "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
1497  ssn->client.last_ack);
1498 
1499  } else if (tcph->th_flags & TH_ACK) {
1500  /* Drop reason will only be used if midstream policy is set to fail closed */
1502  StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1503 
1504  if (!stream_config.midstream) {
1505  SCLogDebug("Midstream not enabled, so won't pick up a session");
1506  return 0;
1507  }
1510  SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1511  return 0;
1512  }
1513  SCLogDebug("midstream picked up");
1514 
1515  if (ssn == NULL) {
1516  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1517  if (ssn == NULL) {
1519  return -1;
1520  }
1524  }
1525  /* set the state */
1526  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1527  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1528  "TCP_ESTABLISHED", ssn);
1529 
1533  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1535  }
1536 
1537  /** window scaling for midstream pickups, we can't do much other
1538  * than assume that it's set to the max value: 14 */
1541 
1542  /* set the sequence numbers and window */
1543  ssn->client.isn = TCP_GET_RAW_SEQ(tcph) - 1;
1549  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
1551 
1552  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
1554  ssn->server.next_seq = ssn->server.isn + 1;
1557 
1558  SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
1559  "ssn->server.next_win %"PRIu32"", ssn,
1561  SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
1562  "ssn->server.last_ack %"PRIu32"", ssn,
1564 
1565  /* Set the timestamp value for both streams, if packet has timestamp
1566  * option enabled.*/
1567  if (TCP_HAS_TS(p)) {
1570  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1571  "ssn->client.last_ts %" PRIu32"", ssn,
1573 
1575 
1576  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1577  if (ssn->server.last_ts == 0)
1579  if (ssn->client.last_ts == 0)
1581 
1582  } else {
1583  ssn->server.last_ts = 0;
1584  ssn->client.last_ts = 0;
1585  }
1586 
1588 
1590  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1591 
1592  } else {
1593  SCLogDebug("default case");
1594  }
1595 
1596  return 0;
1597 }
1598 
1599 /** \internal
1600  * \brief Setup TcpStateQueue based on SYN/ACK packet
1601  */
1602 static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
1603 {
1604  const TCPHdr *tcph = PacketGetTCP(p);
1605  q->flags = 0;
1606  q->wscale = 0;
1607  q->ts = 0;
1608  q->win = TCP_GET_RAW_WINDOW(tcph);
1609  q->seq = TCP_GET_RAW_SEQ(tcph);
1610  q->ack = TCP_GET_RAW_ACK(tcph);
1611  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1612 
1613  if (TCP_GET_SACKOK(p))
1615 
1616  if (TCP_HAS_WSCALE(p)) {
1618  q->wscale = TCP_GET_WSCALE(p);
1619  }
1620  if (TCP_HAS_TS(p)) {
1622  q->ts = TCP_GET_TSVAL(p);
1623  }
1624 }
1625 
1626 /** \internal
1627  * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
1628  * \retval q or NULL */
1629 static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
1630 {
1631  TcpStateQueue *q = ssn->queue;
1632  TcpStateQueue search;
1633 
1634  StreamTcp3whsSynAckToStateQueue(p, &search);
1635 
1636  while (q != NULL) {
1637  if (search.flags == q->flags &&
1638  search.wscale == q->wscale &&
1639  search.win == q->win &&
1640  search.seq == q->seq &&
1641  search.ack == q->ack &&
1642  search.ts == q->ts) {
1643  return q;
1644  }
1645 
1646  q = q->next;
1647  }
1648 
1649  return q;
1650 }
1651 
1652 static int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
1653 {
1654  /* first see if this is already in our list */
1655  if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
1656  return 0;
1657 
1659  SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
1661  return -1;
1662  }
1663 
1664  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1665  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
1666  return -1;
1667  }
1668 
1669  TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1670  if (unlikely(q == NULL)) {
1671  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
1672  return -1;
1673  }
1674  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1675 
1676  StreamTcp3whsSynAckToStateQueue(p, q);
1677 
1678  /* put in list */
1679  q->next = ssn->queue;
1680  ssn->queue = q;
1681  ssn->queue_len++;
1682  return 0;
1683 }
1684 
1685 /** \internal
1686  * \brief Find the Queued SYN/ACK that goes with this ACK
1687  * \retval q or NULL */
1688 static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
1689 {
1690  const TCPHdr *tcph = PacketGetTCP(p);
1691  const uint32_t ack = TCP_GET_RAW_SEQ(tcph);
1692  const uint32_t seq = TCP_GET_RAW_ACK(tcph) - 1;
1693  TcpStateQueue *q = ssn->queue;
1694 
1695  while (q != NULL) {
1696  if (seq == q->seq &&
1697  ack == q->ack) {
1698  return q;
1699  }
1700 
1701  q = q->next;
1702  }
1703 
1704  return NULL;
1705 }
1706 
1707 /** \internal
1708  * \brief Update SSN after receiving a valid SYN/ACK
1709  *
1710  * Normally we update the SSN from the SYN/ACK packet. But in case
1711  * of queued SYN/ACKs, we can use one of those.
1712  *
1713  * \param ssn TCP session
1714  * \param p Packet
1715  * \param q queued state if used, NULL otherwise
1716  *
1717  * To make sure all SYN/ACK based state updates are in one place,
1718  * this function can updated based on Packet or TcpStateQueue, where
1719  * the latter takes precedence.
1720  */
1721 static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
1722 {
1723  TcpStateQueue update;
1724  if (likely(q == NULL)) {
1725  StreamTcp3whsSynAckToStateQueue(p, &update);
1726  q = &update;
1727  }
1728 
1729  if (ssn->state != TCP_SYN_RECV) {
1730  /* update state */
1731  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1732  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
1733  }
1734  /* sequence number & window */
1735  ssn->server.isn = q->seq;
1737  ssn->server.next_seq = ssn->server.isn + 1;
1738 
1739  ssn->client.window = q->win;
1740  SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
1741 
1742  /* Set the timestamp values used to validate the timestamp of
1743  * received packets.*/
1744  if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
1746  {
1747  ssn->server.last_ts = q->ts;
1748  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1749  "ssn->client.last_ts %" PRIu32"", ssn,
1752  ssn->server.last_pkt_ts = q->pkt_ts;
1753  if (ssn->server.last_ts == 0)
1755  } else {
1756  ssn->client.last_ts = 0;
1757  ssn->server.last_ts = 0;
1759  }
1760 
1761  ssn->client.last_ack = q->ack;
1762  ssn->server.last_ack = ssn->server.isn + 1;
1763 
1764  /** check for the presence of the ws ptr to determine if we
1765  * support wscale at all */
1768  {
1769  ssn->client.wscale = q->wscale;
1770  } else {
1771  ssn->client.wscale = 0;
1772  }
1773 
1777  SCLogDebug("ssn %p: SACK permitted for session", ssn);
1778  } else {
1780  }
1781 
1784  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
1785  ssn->server.next_win);
1786  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
1787  ssn->client.next_win);
1788  SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
1789  "ssn->server.next_seq %" PRIu32 ", "
1790  "ssn->server.last_ack %" PRIu32 " "
1791  "(ssn->client.last_ack %" PRIu32 ")", ssn,
1794 
1795  /* unset the 4WHS flag as we received this SYN/ACK as part of a
1796  * (so far) valid 3WHS */
1797  if (ssn->flags & STREAMTCP_FLAG_4WHS)
1798  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
1799  " so considering 3WHS", ssn);
1800 
1802 }
1803 
1804 /** \internal
1805  * \brief detect timestamp anomalies when processing responses to the
1806  * SYN packet.
1807  * \retval true packet is ok
1808  * \retval false packet is bad
1809  */
1810 static inline bool StateSynSentValidateTimestamp(TcpSession *ssn, Packet *p)
1811 {
1812  /* we only care about evil server here, so skip TS packets */
1813  if (PKT_IS_TOSERVER(p) || !(TCP_HAS_TS(p))) {
1814  return true;
1815  }
1816 
1817  TcpStream *receiver_stream = &ssn->client;
1818  const uint32_t ts_echo = TCP_GET_TSECR(p);
1819  if ((receiver_stream->flags & STREAMTCP_STREAM_FLAG_TIMESTAMP) != 0) {
1820  if (receiver_stream->last_ts != 0 && ts_echo != 0 &&
1821  ts_echo != receiver_stream->last_ts)
1822  {
1823  SCLogDebug("%" PRIu64 ": ssn %p: BAD TSECR echo %u recv %u", PcapPacketCntGet(p), ssn,
1824  ts_echo, receiver_stream->last_ts);
1825  return false;
1826  }
1827  } else {
1828  if (receiver_stream->last_ts == 0 && ts_echo != 0) {
1829  SCLogDebug("%" PRIu64 ": ssn %p: BAD TSECR echo %u recv %u", PcapPacketCntGet(p), ssn,
1830  ts_echo, receiver_stream->last_ts);
1831  return false;
1832  }
1833  }
1834  return true;
1835 }
1836 
1837 static void TcpStateQueueInitFromSsnSyn(const TcpSession *ssn, TcpStateQueue *q)
1838 {
1840  memset(q, 0, sizeof(*q));
1841 
1842  q->seq = ssn->client.isn;
1843  /* SYN won't use wscale yet. So window should be limited to 16 bits. */
1844  DEBUG_VALIDATE_BUG_ON(ssn->server.window > UINT16_MAX);
1845  q->win = (uint16_t)ssn->server.window;
1846 
1847  q->pkt_ts = ssn->client.last_pkt_ts;
1848 
1851  }
1854  q->wscale = ssn->server.wscale;
1855  }
1858  q->ts = ssn->client.last_ts;
1859  }
1860 
1861  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1863 }
1864 
1865 static void TcpStateQueueInitFromPktSyn(const Packet *p, TcpStateQueue *q)
1866 {
1867 #if defined(DEBUG_VALIDATION) || defined(DEBUG)
1868  const TcpSession *ssn = p->flow->protoctx;
1870 #endif
1871  memset(q, 0, sizeof(*q));
1872  const TCPHdr *tcph = PacketGetTCP(p);
1873 
1874  q->seq = TCP_GET_RAW_SEQ(tcph);
1875  q->win = TCP_GET_RAW_WINDOW(tcph);
1876  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1877 
1878  if (TCP_GET_SACKOK(p)) {
1880  }
1881  if (TCP_HAS_WSCALE(p)) {
1883  q->wscale = TCP_GET_WSCALE(p);
1884  }
1885  if (TCP_HAS_TS(p)) {
1887  q->ts = TCP_GET_TSVAL(p);
1888  }
1889 
1890 #if defined(DEBUG)
1891  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1893 #endif
1894 }
1895 
1896 static void TcpStateQueueInitFromPktSynAck(const Packet *p, TcpStateQueue *q)
1897 {
1898 #if defined(DEBUG_VALIDATION) || defined(DEBUG)
1899  const TcpSession *ssn = p->flow->protoctx;
1901 #endif
1902  memset(q, 0, sizeof(*q));
1903 
1904  const TCPHdr *tcph = PacketGetTCP(p);
1905  q->seq = TCP_GET_RAW_ACK(tcph) - 1;
1906  q->win = TCP_GET_RAW_WINDOW(tcph);
1907  q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1908 
1909  if (TCP_GET_SACKOK(p)) {
1911  }
1912  if (TCP_HAS_WSCALE(p)) {
1914  q->wscale = TCP_GET_WSCALE(p);
1915  }
1916  if (TCP_HAS_TS(p)) {
1918  q->ts = TCP_GET_TSECR(p);
1919  }
1920 
1921 #if defined(DEBUG)
1922  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1924 #endif
1925 }
1926 
1927 /** \internal
1928  * \brief Find the Queued SYN that is the same as this SYN/ACK
1929  * \param[in] ignore_ts if true, ignore the timestamp
1930  * \retval q or NULL
1931  *
1932  * \note When `ignore_ts`, the following is accepted: SYN w/o TS, SYN/ACK with TS.
1933  * \note When `ignore_ts` is set, `s` corresponds to the SYN/ACK packet and the
1934  * queue holds the stored SYN packets. */
1935 static const TcpStateQueue *StreamTcp3whsFindSyn(
1936  const TcpSession *ssn, TcpStateQueue *s, TcpStateQueue **ret_tail, const bool ignore_ts)
1937 {
1938  SCLogDebug("ssn %p: search state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, s, s->seq, s->win,
1940 
1941  TcpStateQueue *last = NULL;
1942  for (TcpStateQueue *q = ssn->queue; q != NULL; q = q->next) {
1943  SCLogDebug("ssn %p: queue state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u (last:%s)", ssn, q,
1944  q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS), q->ts,
1945  BOOL2STR(q->next == NULL));
1946 
1947  if (s->flags & STREAMTCP_QUEUE_FLAG_TS) {
1948  if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) && s->ts == q->ts && s->seq == q->seq) {
1949  return q;
1950  }
1951  } else if (ignore_ts) {
1952  if (s->seq == q->seq) {
1953  return q;
1954  }
1955  }
1956  last = q;
1957  }
1958  if (ret_tail)
1959  *ret_tail = last;
1960  return NULL;
1961 }
1962 
1963 /** \internal
1964  * \brief take oldest element in the list and replace it with the new data
1965  */
1966 static void AddAndRotate(TcpSession *ssn, TcpStateQueue *tail, TcpStateQueue *search)
1967 {
1968  TcpStateQueue *old_head = ssn->queue;
1969 
1970  if (tail == old_head) {
1971  /* single-element list: overwrite in place */
1972  *old_head = *search;
1973  old_head->next = NULL;
1974  return;
1975  }
1976 
1977  /* multi-element list: pop head, append after tail, reuse as new tail */
1978  ssn->queue = old_head->next;
1979  tail->next = old_head;
1980 
1981  *old_head = *search;
1982  old_head->next = NULL;
1983 }
1984 
1985 static int StreamTcp3whsStoreSyn(TcpSession *ssn, Packet *p)
1986 {
1987  TcpStateQueue search;
1988  TcpStateQueueInitFromSsnSyn(ssn, &search);
1989  TcpStateQueue *tail = NULL;
1990 
1991  /* first see if this is already in our list */
1992  if (ssn->queue != NULL && StreamTcp3whsFindSyn(ssn, &search, &tail, false) != NULL)
1993  return 0;
1994 
1995  if (ssn->queue != NULL && ssn->queue_len == stream_config.max_syn_queued) {
1996  SCLogDebug("%" PRIu64 ": ssn %p: =~ SYN queue limit reached, rotate", PcapPacketCntGet(p),
1997  ssn);
1999 
2000  /* add to the list, evicting the oldest entry */
2001  AddAndRotate(ssn, tail, &search);
2002  return 0;
2003  }
2004 
2005  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
2006  SCLogDebug("ssn %p: =~ SYN queue failed: stream memcap reached", ssn);
2007  return -1;
2008  }
2009 
2010  TcpStateQueue *q = SCCalloc(1, sizeof(*q));
2011  if (unlikely(q == NULL)) {
2012  SCLogDebug("ssn %p: =~ SYN queue failed: alloc failed", ssn);
2013  return -1;
2014  }
2015  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
2016 
2017  *q = search;
2018  /* put in list */
2019  if (tail) {
2020  tail->next = q;
2021  } else {
2022  DEBUG_VALIDATE_BUG_ON(ssn->queue != NULL);
2023  ssn->queue = q;
2024  }
2025  ssn->queue_len++;
2026  SCLogDebug("%" PRIu64 ": ssn %p: =~ SYN with SEQ %u added (queue_len %u)", PcapPacketCntGet(p),
2027  ssn, q->seq, ssn->queue_len);
2028  return 0;
2029 }
2030 
2031 static inline void StreamTcp3whsStoreSynApplyToSsn(TcpSession *ssn, const TcpStateQueue *q)
2032 {
2033  if (q->flags & STREAMTCP_QUEUE_FLAG_TS) {
2034  ssn->client.last_pkt_ts = q->pkt_ts;
2035  ssn->client.last_ts = q->ts;
2037  SCLogDebug("ssn: %p client.last_ts updated to %u", ssn, ssn->client.last_ts);
2038  }
2039  if (q->flags & STREAMTCP_QUEUE_FLAG_WS) {
2041  ssn->server.wscale = q->wscale;
2042  } else {
2044  ssn->server.wscale = 0;
2045  }
2046  ssn->server.window = q->win;
2047 
2048  if (q->flags & STREAMTCP_QUEUE_FLAG_SACK) {
2050  } else {
2052  }
2053  ssn->client.isn = q->seq;
2055  SCLogDebug("ssn: %p client.isn updated to %u", ssn, ssn->client.isn);
2056 }
2057 
2058 /** \internal
2059  * \brief handle SYN/ACK on SYN_SENT state (non-TFO case)
2060  *
2061  * If packet doesn't match the session, check queued states (if any)
2062  *
2063  * \retval true packet is accepted
2064  * \retval false packet is rejected
2065  */
2066 static inline bool StateSynSentCheckSynAck3Whs(TcpSession *ssn, Packet *p, const bool ts_mismatch)
2067 {
2068  const TCPHdr *tcph = PacketGetTCP(p);
2069  const bool seq_match = SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2070  if (seq_match && !ts_mismatch) {
2071  return true;
2072  }
2073 
2074  /* check the queued syns */
2075  if (ssn->queue == NULL) {
2076  goto failure;
2077  }
2078 
2079  TcpStateQueue search;
2080  TcpStateQueueInitFromPktSynAck(p, &search);
2081  SCLogDebug("%" PRIu64 ": ssn %p: SYN/ACK looking for SEQ %u", PcapPacketCntGet(p), ssn,
2082  search.seq);
2083 
2084  const TcpStateQueue *q =
2085  StreamTcp3whsFindSyn(ssn, &search, NULL, stream_config.liberal_timestamps);
2086  if (q == NULL) {
2087  SCLogDebug("not found: mismatch");
2088  goto failure;
2089  }
2090 
2091  SCLogDebug("ssn %p: found queued SYN state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q,
2092  q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS), q->ts);
2093  StreamTcp3whsStoreSynApplyToSsn(ssn, q);
2094  return true;
2095 failure:
2096  if (!seq_match) {
2098  } else if (ts_mismatch) {
2100  }
2101  return false;
2102 }
2103 
2104 /** \internal
2105  * \brief handle SYN/ACK on SYN_SENT state (TFO case)
2106  *
2107  * If packet doesn't match the session, check queued states (if any)
2108  *
2109  * \retval true packet is accepted
2110  * \retval false packet is rejected
2111  */
2112 static inline bool StateSynSentCheckSynAckTFO(TcpSession *ssn, Packet *p, const bool ts_mismatch)
2113 {
2114  const TCPHdr *tcph = PacketGetTCP(p);
2115  const bool seq_match_tfo = SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
2116  const bool seq_match_nodata = SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2117  if (seq_match_tfo && !ts_mismatch) {
2118  // ok
2119  } else if (seq_match_nodata && !ts_mismatch) {
2120  ssn->client.next_seq = ssn->client.isn; // reset to ISN
2121  SCLogDebug("ssn %p: (TFO) next_seq reset to isn (%u)", ssn, ssn->client.next_seq);
2124  } else {
2125  /* check the queued syns */
2126  if (ssn->queue == NULL) {
2127  goto failure;
2128  }
2129 
2130  TcpStateQueue search;
2131  TcpStateQueueInitFromPktSynAck(p, &search);
2132  SCLogDebug("%" PRIu64 ": ssn %p: SYN/ACK looking for SEQ %u", PcapPacketCntGet(p), ssn,
2133  search.seq);
2134 
2135  const TcpStateQueue *q =
2136  StreamTcp3whsFindSyn(ssn, &search, NULL, stream_config.liberal_timestamps);
2137  if (q == NULL) {
2138  SCLogDebug("not found: mismatch");
2139  goto failure;
2140  }
2141 
2142  SCLogDebug("ssn %p: found queued SYN state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q,
2143  q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS), q->ts);
2144  StreamTcp3whsStoreSynApplyToSsn(ssn, q);
2145  }
2147  return true;
2148 failure:
2149  if (!seq_match_tfo && !seq_match_nodata) {
2151  } else if (ts_mismatch) {
2153  }
2154  return false;
2155 }
2156 
2157 /**
2158  * \brief Function to handle the TCP_SYN_SENT state. The function handles
2159  * SYN, SYN/ACK, RST packets and correspondingly changes the connection
2160  * state.
2161  *
2162  * \param tv Thread Variable containing input/output queue, cpu affinity
2163  * \param p Packet which has to be handled in this TCP state.
2164  * \param stt Stream Thread module registered to handle the stream handling
2165  */
2166 
2167 static int StreamTcpPacketStateSynSent(
2169 {
2170  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
2171  const TCPHdr *tcph = PacketGetTCP(p);
2172 
2173  SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ? "toclient" : "toserver");
2174 
2175  /* common case: SYN/ACK from server to client */
2176  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOCLIENT(p)) {
2177  SCLogDebug("%" PRIu64 ": ssn %p: SYN/ACK on SYN_SENT state for packet %" PRIu64,
2179  /* if timestamps are liberal, allow a SYN/ACK with TS even if the SYN
2180  * had none (violates RFC 7323, see bug #4702). */
2181  const bool ts_mismatch =
2182  !(stream_config.liberal_timestamps || StateSynSentValidateTimestamp(ssn, p));
2183  SCLogDebug("ts_mismatch %s", BOOL2STR(ts_mismatch));
2184 
2186  if (StateSynSentCheckSynAck3Whs(ssn, p, ts_mismatch)) {
2187  SCLogDebug("ssn %p: ACK match, packet ACK %" PRIu32 " == "
2188  "%" PRIu32 " from stream",
2189  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2190  } else {
2191  SCLogDebug("ssn %p: (3WHS) ACK mismatch, packet ACK %" PRIu32 " != "
2192  "%" PRIu32 " from stream",
2194  return -1;
2195  }
2196  } else {
2197  if (StateSynSentCheckSynAckTFO(ssn, p, ts_mismatch)) {
2198  SCLogDebug("ssn %p: (TFO) ACK matches next_seq, packet ACK %" PRIu32 " == "
2199  "%" PRIu32 " from stream",
2201  } else {
2202  SCLogDebug("ssn %p: (TFO) ACK mismatch, packet ACK %" PRIu32 " != "
2203  "%" PRIu32 " from stream",
2205  return -1;
2206  }
2207  }
2208  /* clear ssn->queue on state change: TcpSession can be reused by SYN/ACK */
2209  StreamTcp3wsFreeQueue(ssn);
2210 
2211  StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
2212  SCLogDebug("%" PRIu64 ": ssn %p: SYN/ACK on SYN_SENT state: accepted", PcapPacketCntGet(p),
2213  ssn);
2214  return 0;
2215 
2216  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOSERVER(p)) {
2217 
2218  if (!(ssn->flags & STREAMTCP_FLAG_4WHS)) {
2220  SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
2221  return -1;
2222  }
2223 
2224  SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
2225 
2226  /* Check if the SYN/ACK packet ack's the earlier
2227  * received SYN packet. */
2228  if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.isn + 1))) {
2230 
2231  SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %" PRIu32 ""
2232  " != %" PRIu32 " from stream",
2233  ssn, TCP_GET_RAW_ACK(tcph), ssn->server.isn + 1);
2234  return -1;
2235  }
2236 
2237  /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
2238  * packet. */
2239  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn))) {
2241 
2242  SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %" PRIu32 ""
2243  " != %" PRIu32 " from *first* SYN pkt",
2244  ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.isn);
2245  return -1;
2246  }
2247 
2248  /* update state */
2249  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
2250  SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
2251 
2252  /* sequence number & window */
2253  ssn->client.isn = TCP_GET_RAW_SEQ(tcph);
2255  ssn->client.next_seq = ssn->client.isn + 1;
2256 
2258  SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn, ssn->client.window);
2259 
2260  /* Set the timestamp values used to validate the timestamp of
2261  * received packets. */
2264  SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32 " "
2265  "ssn->server.last_ts %" PRIu32 "",
2268  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2269  if (ssn->client.last_ts == 0)
2271  } else {
2272  ssn->server.last_ts = 0;
2273  ssn->client.last_ts = 0;
2275  }
2276 
2278  ssn->client.last_ack = ssn->client.isn + 1;
2279 
2280  /** check for the presense of the ws ptr to determine if we
2281  * support wscale at all */
2284  } else {
2285  ssn->server.wscale = 0;
2286  }
2287 
2290  SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
2291  }
2292 
2295  SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win);
2296  SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win);
2297  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2298  "ssn->client.next_seq %" PRIu32 ", "
2299  "ssn->client.last_ack %" PRIu32 " "
2300  "(ssn->server.last_ack %" PRIu32 ")",
2302  ssn->server.last_ack);
2303 
2304  /* done here */
2305  return 0;
2306  }
2307 
2308  /* check for bad responses */
2309  if (!StateSynSentValidateTimestamp(ssn, p)) {
2311  return -1;
2312  }
2313 
2314  /* RST */
2315  if (tcph->th_flags & TH_RST) {
2316 
2317  if (!StreamTcpValidateRst(ssn, p))
2318  return -1;
2319 
2320  if (PKT_IS_TOSERVER(p)) {
2321  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn) &&
2322  SEQ_EQ(TCP_GET_RAW_WINDOW(tcph), 0) &&
2323  SEQ_EQ(TCP_GET_RAW_ACK(tcph), (ssn->client.isn + 1))) {
2324  SCLogDebug("ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
2326  StreamTcpCloseSsnWithReset(p, ssn);
2327  StreamTcp3wsFreeQueue(ssn);
2328  }
2329  } else {
2331  SCLogDebug("ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
2332  StreamTcpCloseSsnWithReset(p, ssn);
2333  StreamTcp3wsFreeQueue(ssn);
2334  }
2335 
2336  /* FIN */
2337  } else if (tcph->th_flags & TH_FIN) {
2338  /** \todo */
2339 
2340  } else if (tcph->th_flags & TH_SYN) {
2341  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
2342  if (ssn->flags & STREAMTCP_FLAG_4WHS) {
2343  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
2344  "4WHS SYN", ssn);
2345  }
2346 
2347  if (PKT_IS_TOCLIENT(p)) {
2348  /** a SYN only packet in the opposite direction could be:
2349  * http://www.breakingpointsystems.com/community/blog/tcp-
2350  * portals-the-three-way-handshake-is-a-lie
2351  *
2352  * \todo improve resetting the session */
2353 
2354  /* indicate that we're dealing with 4WHS here */
2356  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
2357 
2358  /* set the sequence numbers and window for server
2359  * We leave the ssn->client.isn in place as we will
2360  * check the SYN/ACK pkt with that.
2361  */
2362  ssn->server.isn = TCP_GET_RAW_SEQ(tcph);
2364  ssn->server.next_seq = ssn->server.isn + 1;
2365 
2366  /* Set the stream timestamp value, if packet has timestamp
2367  * option enabled. */
2368  if (TCP_HAS_TS(p)) {
2370  SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
2371 
2372  if (ssn->server.last_ts == 0)
2374  ssn->server.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2376  }
2377 
2379  if (TCP_HAS_WSCALE(p)) {
2382  } else {
2384  ssn->server.wscale = 0;
2385  }
2386 
2387  if (TCP_GET_SACKOK(p)) {
2389  } else {
2391  }
2392 
2393  SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
2394  "ssn->server.next_seq %" PRIu32 ", "
2395  "ssn->server.last_ack %"PRIu32"", ssn,
2397  ssn->server.last_ack);
2398  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2399  "ssn->client.next_seq %" PRIu32 ", "
2400  "ssn->client.last_ack %"PRIu32"", ssn,
2402  ssn->client.last_ack);
2403  } else if (PKT_IS_TOSERVER(p)) {
2404  /* on a SYN resend we queue up the SYN's until a SYN/ACK moves the state
2405  * to SYN_RECV. We update the ssn to the most recent, as it is most likely
2406  * to be correct. */
2407 
2408  TcpStateQueue syn_pkt, syn_ssn;
2409  TcpStateQueueInitFromPktSyn(p, &syn_pkt);
2410  TcpStateQueueInitFromSsnSyn(ssn, &syn_ssn);
2411 
2412  if (memcmp(&syn_pkt, &syn_ssn, sizeof(TcpStateQueue)) != 0) {
2413  /* store the old session settings */
2414  StreamTcp3whsStoreSyn(ssn, p);
2415  SCLogDebug("ssn %p: Retransmitted SYN. Updating ssn from packet %" PRIu64
2416  ". Stored previous state",
2417  ssn, PcapPacketCntGet(p));
2418  }
2419  StreamTcp3whsStoreSynApplyToSsn(ssn, &syn_pkt);
2420  }
2421  } else if (tcph->th_flags & TH_ACK) {
2422  /* Handle the asynchronous stream, when we receive a SYN packet
2423  and now instead of receiving a SYN/ACK we receive a ACK from the
2424  same host, which sent the SYN, this suggests the ASYNC streams.*/
2426  return 0;
2427 
2428  /* we are in ASYNC (one side) mode now. */
2429 
2430  /* one side async means we won't see a SYN/ACK, so we can
2431  * only check the SYN. */
2432  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq))) {
2434 
2435  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2436  "%" PRIu32 " from stream",
2438  return -1;
2439  }
2440 
2442  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2443  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2444  StreamTcp3wsFreeQueue(ssn);
2445 
2449 
2450  /* Set the server side parameters */
2451  ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
2453  ssn->server.next_seq = ssn->server.isn + 1;
2456 
2457  SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
2458  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2459  "ssn->client.next_seq %" PRIu32 "",
2461  ssn->client.next_seq);
2462 
2463  /* if SYN had wscale, assume it to be supported. Otherwise
2464  * we know it not to be supported. */
2467  }
2468 
2469  /* Set the timestamp values used to validate the timestamp of
2470  * received packets.*/
2471  if (TCP_HAS_TS(p) &&
2473  {
2476  ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2477  } else {
2478  ssn->client.last_ts = 0;
2480  }
2481 
2484  }
2485 
2487 
2488  } else {
2489  SCLogDebug("ssn %p: default case", ssn);
2490  }
2491 
2492  return 0;
2493 }
2494 
2495 /**
2496  * \brief Function to handle the TCP_SYN_RECV state. The function handles
2497  * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
2498  * the connection state.
2499  *
2500  * \param tv Thread Variable containing input/output queue, cpu affinity
2501  * \param p Packet which has to be handled in this TCP state.
2502  * \param stt Stream Thread module registered to handle the stream handling
2503  *
2504  * \retval 0 ok
2505  * \retval -1 error
2506  */
2507 
2508 static int StreamTcpPacketStateSynRecv(
2510 {
2511  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
2512  const TCPHdr *tcph = PacketGetTCP(p);
2513 
2514  if (tcph->th_flags & TH_RST) {
2515  if (!StreamTcpValidateRst(ssn, p))
2516  return -1;
2517 
2518  bool reset = true;
2519  /* After receiving the RST in SYN_RECV state and if detection
2520  evasion flags has been set, then the following operating
2521  systems will not closed the connection. As they consider the
2522  packet as stray packet and not belonging to the current
2523  session, for more information check
2524  http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
2526  if (PKT_IS_TOSERVER(p)) {
2527  if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
2530  {
2531  reset = false;
2532  SCLogDebug("Detection evasion has been attempted, so"
2533  " not resetting the connection !!");
2534  }
2535  } else {
2536  if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
2539  {
2540  reset = false;
2541  SCLogDebug("Detection evasion has been attempted, so"
2542  " not resetting the connection !!");
2543  }
2544  }
2545  }
2546 
2547  if (reset) {
2548  StreamTcpCloseSsnWithReset(p, ssn);
2549 
2551  StreamTcpHandleTimestamp(ssn, p);
2552  }
2553  }
2554 
2555  } else if (tcph->th_flags & TH_FIN) {
2556  /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
2558  if (!StreamTcpValidateTimestamp(ssn, p))
2559  return -1;
2560  }
2561 
2562  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
2563  return -1;
2564 
2565  /* SYN/ACK */
2566  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
2567  SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
2568 
2569  if (PKT_IS_TOSERVER(p)) {
2570  SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
2571 
2573  return -1;
2574  }
2575 
2576  /* Check if the SYN/ACK packets ACK matches the earlier
2577  * received SYN/ACK packet. */
2578  if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack))) {
2579  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
2580  "%" PRIu32 " from stream",
2581  ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2582 
2584  return -1;
2585  }
2586 
2587  /* Check if the SYN/ACK packet SEQ the earlier
2588  * received SYN/ACK packet, server resend with different ISN. */
2589  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.isn))) {
2590  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2591  "%" PRIu32 " from stream",
2592  ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.isn);
2593 
2594  if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
2595  return -1;
2596  SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
2597  }
2598 
2599  } else if (tcph->th_flags & TH_SYN) {
2600  SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
2601 
2602  if (PKT_IS_TOCLIENT(p)) {
2603  SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
2604 
2606  return -1;
2607  }
2608 
2609  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn))) {
2610  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
2611 
2613  return -1;
2614  }
2615 
2616  } else if (tcph->th_flags & TH_ACK) {
2617  if (ssn->queue_len) {
2618  SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
2619  TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
2620  if (q != NULL) {
2621  SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
2622  StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
2623  } else {
2624  SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
2625  }
2626  }
2627 
2628 
2629  /* If the timestamp option is enabled for both the streams, then
2630  * validate the received packet timestamp value against the
2631  * stream->last_ts. If the timestamp is valid then process the
2632  * packet normally otherwise the drop the packet (RFC 1323)*/
2634  if (!(StreamTcpValidateTimestamp(ssn, p))) {
2635  return -1;
2636  }
2637  }
2638 
2640  SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
2641 
2642  if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2643  SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
2645  return -1;
2646  }
2647 
2648  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2649  SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
2651  return -1;
2652  }
2653 
2654  SCLogDebug("4WHS normal pkt");
2655  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2656  "%" PRIu32 ", ACK %" PRIu32 "",
2657  ssn, p->payload_len, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph));
2658 
2660  StreamTcpHandleTimestamp(ssn, p);
2661  }
2662 
2667 
2668  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2669  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2670 
2672 
2673  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
2674  "ssn->client.last_ack %"PRIu32"", ssn,
2676  return 0;
2677  }
2678 
2679  bool ack_indicates_missed_3whs_ack_packet = false;
2680  /* Check if the ACK received is in right direction. But when we have
2681  * picked up a mid stream session after missing the initial SYN pkt,
2682  * in this case the ACK packet can arrive from either client (normal
2683  * case) or from server itself (asynchronous streams). Therefore
2684  * the check has been avoided in this case */
2685  if (PKT_IS_TOCLIENT(p)) {
2686  /* special case, handle 4WHS, so SYN/ACK in the opposite
2687  * direction */
2689  SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
2690  "pickup session",ssn);
2691  /* fall through */
2692  } else if (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) {
2693  SCLogDebug("ssn %p: ACK received on TFO session",ssn);
2694  /* fall through */
2695 
2696  } else {
2697  /* if we missed traffic between the S/SA and the current
2698  * 'wrong direction' ACK, we could end up here. In IPS
2699  * reject it. But in IDS mode we continue.
2700  *
2701  * IPS rejects as it should see all packets, so pktloss
2702  * should lead to retransmissions. As this can also be
2703  * pattern for MOTS/MITM injection attacks, we need to be
2704  * careful.
2705  */
2706  if (StreamTcpInlineMode()) {
2707  if (p->payload_len > 0 && SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack) &&
2709  /* packet loss is possible but unlikely here */
2710  SCLogDebug("ssn %p: possible data injection", ssn);
2712  return -1;
2713  }
2714 
2715  SCLogDebug("ssn %p: ACK received in the wrong direction",
2716  ssn);
2718  return -1;
2719  }
2720  ack_indicates_missed_3whs_ack_packet = true;
2721  }
2722  }
2723 
2724  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
2725  ", ACK %" PRIu32 "",
2726  ssn, p->payload_len, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph));
2727 
2728  /* Check both seq and ack number before accepting the packet and
2729  changing to ESTABLISHED state */
2730  if ((SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) &&
2732  SCLogDebug("normal pkt");
2733 
2734  /* process the packet normal, No Async streams :) */
2735 
2737  StreamTcpHandleTimestamp(ssn, p);
2738  }
2739 
2743 
2745 
2750  ssn->server.window;
2752  /* window scaling for midstream pickups, we can't do much
2753  * other than assume that it's set to the max value: 14 */
2757  }
2758  }
2759 
2760  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2761  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2762 
2763  /* special case: normally the packet following the 3whs is
2764  * considered flow established, but with data we need it to
2765  * be established now. This can happen if the original ACK was
2766  * lost. */
2767  if (p->payload_len) {
2769  }
2770 
2772 
2773  /* If asynchronous stream handling is allowed then set the session,
2774  if packet's seq number is equal the expected seq no.*/
2775  } else if (stream_config.async_oneside &&
2776  (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2777  /*set the ASYNC flag used to indicate the session as async stream
2778  and helps in relaxing the windows checks.*/
2782 
2785 
2787  StreamTcpHandleTimestamp(ssn, p);
2788  }
2789 
2793  /* window scaling for midstream pickups, we can't do much
2794  * other than assume that it's set to the max value: 14 */
2798  }
2799 
2800  SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
2801  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2802  "ssn->server.next_seq %" PRIu32,
2803  ssn, TCP_GET_RAW_SEQ(tcph), p->payload_len,
2805 
2806  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2807  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2808 
2810  /* Upon receiving the packet with correct seq number and wrong
2811  ACK number, it causes the other end to send RST. But some target
2812  system (Linux & solaris) does not RST the connection, so it is
2813  likely to avoid the detection */
2814  } else if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) {
2816  SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
2817  ssn);
2818 
2820  return -1;
2821 
2822  /* SYN/ACK followed by more TOCLIENT suggesting packet loss */
2823  } else if (PKT_IS_TOCLIENT(p) && !StreamTcpInlineMode() &&
2826  SCLogDebug("ssn %p: ACK for missing data", ssn);
2827 
2829  StreamTcpHandleTimestamp(ssn, p);
2830  }
2831 
2833 
2835  SCLogDebug("ssn %p: ACK for missing data: ssn->server.next_seq %u", ssn,
2836  ssn->server.next_seq);
2838 
2840 
2843 
2844  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2845  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2846 
2848 
2849  /* if we get a packet with a proper ack, but a seq that is beyond
2850  * next_seq but in-window, we probably missed some packets */
2851  } else if (SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2854  SCLogDebug("ssn %p: ACK for missing data", ssn);
2855 
2857  StreamTcpHandleTimestamp(ssn, p);
2858  }
2859 
2862 
2863  SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
2866 
2870  ssn->server.window;
2871  /* window scaling for midstream pickups, we can't do much
2872  * other than assume that it's set to the max value: 14 */
2876  }
2877 
2878  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2879  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2880 
2882 
2883  /* toclient packet: after having missed the 3whs's final ACK */
2884  } else if ((ack_indicates_missed_3whs_ack_packet ||
2888  if (ack_indicates_missed_3whs_ack_packet) {
2889  SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2890  } else {
2891  SCLogDebug("ssn %p: (TFO) expected packet fits perfectly after SYN/ACK", ssn);
2892  }
2893 
2895 
2898 
2899  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2900  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2901 
2903 
2904  } else {
2905  SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2906 
2908  return -1;
2909  }
2910 
2911  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2912  "ssn->server.last_ack %"PRIu32"", ssn,
2914  } else {
2915  SCLogDebug("ssn %p: default case", ssn);
2916  }
2917 
2918  return 0;
2919 }
2920 
2921 /**
2922  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2923  * sent by the client to server. The function handles
2924  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2925  * the reassembly.
2926  *
2927  * Timestamp has already been checked at this point.
2928  *
2929  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2930  * \param ssn Pointer to the current TCP session
2931  * \param p Packet which has to be handled in this TCP state.
2932  * \param stt Stream Thread module registered to handle the stream handling
2933  */
2934 static int HandleEstablishedPacketToServer(
2936 {
2937  const TCPHdr *tcph = PacketGetTCP(p);
2938  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
2939  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
2940  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
2941 
2942  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2943  "ACK %" PRIu32 ", WIN %" PRIu16 "",
2944  ssn, p->payload_len, seq, ack, window);
2945 
2946  const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
2947  if (has_ack) {
2948  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TC) && ack == ssn->server.next_seq + 1) {
2949  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2951 
2952  } else if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2953  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2955  return -1;
2956  }
2957  }
2958 
2959  /* check for Keep Alive */
2960  if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->client.next_seq - 1))) {
2961  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2962 
2963  /* normal pkt */
2964  } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->client.last_ack))) {
2965  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2966  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2967  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2968  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2969  "%" PRIu32 "(%" PRIu32 ")",
2972 
2973  /* update the last_ack to current seq number as the session is
2974  * async and other stream is not updating it anymore :( */
2976 
2979  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2980  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2981  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2982  "%" PRIu32 "(%" PRIu32 ")",
2985 
2986  /* it seems we missed SYN and SYN/ACK packets of this session.
2987  * Update the last_ack to current seq number as the session
2988  * is async and other stream is not updating it anymore :( */
2991 
2992  } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2994  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2995  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2996  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2997  "%" PRIu32 "(%" PRIu32 ")",
3000 
3001  /* it seems we missed SYN and SYN/ACK packets of this session.
3002  * Update the last_ack to current seq number as the session
3003  * is async and other stream is not updating it anymore :(*/
3006 
3007  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
3008  * In this case we do accept the data before last_ack if it is (partly)
3009  * beyond next seq */
3010  } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
3012  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
3013  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
3014  " acked data that we haven't seen before",
3016  } else {
3017  SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
3018  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
3019  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
3020  "%" PRIu32 "(%" PRIu32 ")",
3023 
3024  SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
3026  return -1;
3027  }
3028  }
3029 
3030  int zerowindowprobe = 0;
3031  /* zero window probe */
3032  if (p->payload_len == 1 && seq == ssn->client.next_seq && ssn->client.window == 0) {
3033  SCLogDebug("ssn %p: zero window probe", ssn);
3034  zerowindowprobe = 1;
3038 
3039  } else if (SEQ_GEQ(seq + p->payload_len, ssn->client.next_seq)) {
3041  }
3042 
3043  /* in window check */
3044  if (zerowindowprobe) {
3045  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
3046  } else if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
3048  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
3049  "%" PRIu32 "",
3050  ssn, seq, ssn->client.next_win);
3051 
3052  ssn->server.window = window << ssn->server.wscale;
3053  SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
3054  ssn->server.window);
3055 
3056  /* Check if the ACK value is sane and inside the window limit */
3057  if (tcph->th_flags & TH_ACK) {
3059  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
3063  }
3064  }
3065 
3066  SCLogDebug(
3067  "ack %u last_ack %u next_seq %u", ack, ssn->server.last_ack, ssn->server.next_seq);
3068 
3070  StreamTcpHandleTimestamp(ssn, p);
3071  }
3072 
3074 
3075  /* update next_win */
3077 
3078  /* handle data (if any) */
3080 
3081  } else {
3082  SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
3083  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
3084  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
3085  "%" PRIu32 "(%" PRIu32 ")",
3088  SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
3089  StreamTcpSackedSize(&ssn->client));
3091  return -1;
3092  }
3093  return 0;
3094 }
3095 
3096 /**
3097  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
3098  * sent by the server to client. The function handles
3099  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
3100  * the reassembly
3101  *
3102  * Timestamp has already been checked at this point.
3103  *
3104  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3105  * \param ssn Pointer to the current TCP session
3106  * \param p Packet which has to be handled in this TCP state.
3107  * \param stt Stream Thread module registered to handle the stream handling
3108  */
3109 static int HandleEstablishedPacketToClient(
3111 {
3112  const TCPHdr *tcph = PacketGetTCP(p);
3113  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3114  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3115  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3116 
3117  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
3118  " ACK %" PRIu32 ", WIN %" PRIu16 "",
3119  ssn, p->payload_len, seq, ack, window);
3120 
3121  const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
3122  if (has_ack) {
3123  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TS) && ack == ssn->client.next_seq + 1) {
3124  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
3126 
3127  } else if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3128  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3130  return -1;
3131  }
3132  }
3133 
3134  /* To get the server window value from the servers packet, when connection
3135  is picked up as midstream */
3136  if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
3138  {
3139  ssn->server.window = window << ssn->server.wscale;
3142  SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
3143  "%" PRIu32 "", ssn, ssn->server.next_win);
3144  }
3145 
3146  /* check for Keep Alive */
3147  if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->server.next_seq - 1))) {
3148  SCLogDebug("ssn %p: pkt is keep alive", ssn);
3149 
3150  /* normal pkt */
3151  } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->server.last_ack))) {
3152  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
3153 
3154  SCLogDebug("ssn %p: client => Asynchronous stream, packet SEQ"
3155  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
3156  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
3157  " %" PRIu32 "(%" PRIu32 ")",
3160 
3161  ssn->server.last_ack = seq;
3162 
3163  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
3164  * In this case we do accept the data before last_ack if it is (partly)
3165  * beyond next seq */
3166  } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
3168  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
3169  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
3170  " acked data that we haven't seen before",
3172  } else {
3173  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
3174  " before last_ack %" PRIu32 ". next_seq %" PRIu32,
3177  return -1;
3178  }
3179  }
3180 
3181  int zerowindowprobe = 0;
3182  /* zero window probe */
3183  if (p->payload_len == 1 && seq == ssn->server.next_seq && ssn->server.window == 0) {
3184  SCLogDebug("ssn %p: zero window probe", ssn);
3185  zerowindowprobe = 1;
3188 
3189  /* accept the segment */
3191 
3192  } else if (SEQ_GEQ(seq + p->payload_len, ssn->server.next_seq)) {
3194  }
3195 
3196  if (zerowindowprobe) {
3197  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
3198  } else if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
3200  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
3201  "%" PRIu32 "",
3202  ssn, seq, ssn->server.next_win);
3203  ssn->client.window = window << ssn->client.wscale;
3204  SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
3205  ssn->client.window);
3206 
3207  if (tcph->th_flags & TH_ACK) {
3209  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
3213  }
3214  }
3215 
3217  StreamTcpHandleTimestamp(ssn, p);
3218  }
3219 
3221 
3223 
3225  } else {
3226  SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
3227  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
3228  " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
3229  "%" PRIu32 "(%" PRIu32 ")",
3233  return -1;
3234  }
3235  return 0;
3236 }
3237 
3238 static bool StreamTcpPacketIsZeroWindowProbeAck(const TcpSession *ssn, const Packet *p)
3239 {
3240  const TCPHdr *tcph = PacketGetTCP(p);
3241  if (ssn->state < TCP_ESTABLISHED)
3242  return false;
3243  if (p->payload_len != 0)
3244  return false;
3245  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3246  return false;
3247 
3248  const TcpStream *snd, *rcv;
3249  if (PKT_IS_TOCLIENT(p)) {
3250  snd = &ssn->server;
3251  rcv = &ssn->client;
3252  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TS))
3253  return false;
3254  } else {
3255  snd = &ssn->client;
3256  rcv = &ssn->server;
3257  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TC))
3258  return false;
3259  }
3260 
3261  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3262  if (pkt_win != 0)
3263  return false;
3264  if (pkt_win != rcv->window)
3265  return false;
3266 
3267  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3268  return false;
3269  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3270  return false;
3271  SCLogDebug("ssn %p: packet %" PRIu64 " is a Zero Window Probe ACK", ssn, PcapPacketCntGet(p));
3272  return true;
3273 }
3274 
3275 /** \internal
3276  * \brief check if an ACK packet is a dup-ACK
3277  */
3278 static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p)
3279 {
3280  const TCPHdr *tcph = PacketGetTCP(p);
3281  if (ssn->state < TCP_ESTABLISHED)
3282  return false;
3283  if (p->payload_len != 0)
3284  return false;
3285  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3286  return false;
3287 
3288  const TcpStream *snd, *rcv;
3289  if (PKT_IS_TOCLIENT(p)) {
3290  snd = &ssn->server;
3291  rcv = &ssn->client;
3292  } else {
3293  snd = &ssn->client;
3294  rcv = &ssn->server;
3295  }
3296 
3297  const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3298  if (pkt_win == 0 || rcv->window == 0)
3299  return false;
3300  if (pkt_win != rcv->window)
3301  return false;
3302 
3303  if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3304  return false;
3305  if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3306  return false;
3307 
3308  SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn,
3309  PcapPacketCntGet(p), TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph), pkt_win,
3310  snd->next_seq, snd->last_ack, rcv->window, snd->next_seq, rcv->last_ack, rcv->window);
3311  return true;
3312 }
3313 
3314 /** \internal
3315  * \brief check if a ACK packet is outdated so processing can be fast tracked
3316  *
3317  * Consider a packet outdated ack if:
3318  * - state is >= ESTABLISHED
3319  * - ACK < last_ACK
3320  * - SACK acks nothing new
3321  * - packet has no data
3322  * - SEQ == next_SEQ
3323  * - flags has ACK set but don't contain SYN/FIN/RST
3324  *
3325  * \todo the most likely explanation for this packet is that we already
3326  * accepted a "newer" ACK. We will not consider an outdated timestamp
3327  * option an issue for this packet, but we should probably still
3328  * check if the ts isn't too far off.
3329  */
3330 static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p)
3331 {
3332  const TCPHdr *tcph = PacketGetTCP(p);
3333  if (ssn->state < TCP_ESTABLISHED)
3334  return false;
3335  if (p->payload_len != 0)
3336  return false;
3337  if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3338  return false;
3339 
3340  /* lets see if this is a packet that is entirely eclipsed by earlier ACKs */
3341  if (PKT_IS_TOSERVER(p)) {
3342  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
3344  if (!TCP_HAS_SACK(p)) {
3345  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3346  ssn->client.next_seq);
3347  return true;
3348  }
3349 
3351  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3352  ssn->client.next_seq);
3353  return true;
3354  }
3355  }
3356  } else {
3357  if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq) &&
3359  if (!TCP_HAS_SACK(p)) {
3360  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3361  ssn->client.next_seq);
3362  return true;
3363  }
3364 
3366  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3367  ssn->client.next_seq);
3368  return true;
3369  }
3370  }
3371  }
3372  return false;
3373 }
3374 
3375 /** \internal
3376  * \brief check if packet is before ack'd windows
3377  * If packet is before last ack, we will not accept it
3378  *
3379  * \retval 0 not spurious retransmission
3380  * \retval 1 before last_ack, after base_seq
3381  * \retval 2 before last_ack and base_seq
3382  */
3383 static int StreamTcpPacketIsSpuriousRetransmission(const TcpSession *ssn, Packet *p)
3384 {
3385  const TcpStream *stream;
3386  if (PKT_IS_TOCLIENT(p)) {
3387  stream = &ssn->server;
3388  } else {
3389  stream = &ssn->client;
3390  }
3391  if (p->payload_len == 0)
3392  return 0;
3393 
3394  const TCPHdr *tcph = PacketGetTCP(p);
3395  /* take base_seq into account to avoid edge cases where last_ack might be
3396  * too far ahead during heavy packet loss */
3397  if (!(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3398  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->base_seq))) {
3399  SCLogDebug(
3400  "ssn %p: spurious retransmission; packet entirely before base_seq: SEQ %u(%u) "
3401  "last_ack %u base_seq %u",
3402  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3403  stream->last_ack, stream->base_seq);
3405  return 2;
3406  }
3407  }
3408 
3409  if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack))) {
3410  SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) "
3411  "last_ack %u",
3412  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3413  stream->last_ack);
3415  return 1;
3416  }
3417 
3418  SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ "
3419  "%u(%u) last_ack %u, base_seq %u",
3420  ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack,
3421  stream->base_seq);
3422  return 0;
3423 }
3424 
3425 /**
3426  * \brief Function to handle the TCP_ESTABLISHED state. The function handles
3427  * ACK, FIN, RST packets and correspondingly changes the connection
3428  * state. The function handles the data inside packets and call
3429  * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
3430  *
3431  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3432  * \param p Packet which has to be handled in this TCP state.
3433  * \param stt Stream Thread module registered to handle the stream handling
3434  */
3435 
3436 static int StreamTcpPacketStateEstablished(
3438 {
3439  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3440  const TCPHdr *tcph = PacketGetTCP(p);
3441  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3442  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3443  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3444 
3445  if (tcph->th_flags & TH_RST) {
3446  if (!StreamTcpValidateRst(ssn, p))
3447  return -1;
3448 
3449  if (PKT_IS_TOSERVER(p)) {
3450  StreamTcpCloseSsnWithReset(p, ssn);
3451 
3452  ssn->server.next_seq = ack;
3454  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3455  ssn->server.next_seq);
3456  ssn->client.window = window << ssn->client.wscale;
3457 
3458  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3460 
3462 
3464  StreamTcpHandleTimestamp(ssn, p);
3465  }
3466 
3468  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3469  "%" PRIu32 "", ssn, ssn->client.next_seq,
3470  ssn->server.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  } else {
3476  StreamTcpCloseSsnWithReset(p, ssn);
3477 
3478  ssn->server.next_seq = seq + p->payload_len + 1;
3479  ssn->client.next_seq = ack;
3480 
3481  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3482  ssn->server.next_seq);
3483  ssn->server.window = window << ssn->server.wscale;
3484 
3485  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3487 
3489 
3491  StreamTcpHandleTimestamp(ssn, p);
3492  }
3493 
3495  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3496  "%" PRIu32 "", ssn, ssn->server.next_seq,
3497  ssn->client.last_ack);
3498 
3499  /* don't return packets to pools here just yet, the pseudo
3500  * packet will take care, otherwise the normal session
3501  * cleanup. */
3502  }
3503 
3504  } else if (tcph->th_flags & TH_FIN) {
3506  if (!StreamTcpValidateTimestamp(ssn, p))
3507  return -1;
3508  }
3509 
3510  SCLogDebug("ssn (%p: FIN received SEQ"
3511  " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
3512  " win %" PRIu32 "", ssn, ssn->server.next_seq,
3514  ssn->server.window);
3515 
3516  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
3517  return -1;
3518 
3519  /* SYN/ACK */
3520  } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
3521  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
3522  ssn);
3523 
3524  if (PKT_IS_TOSERVER(p)) {
3525  SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
3526 
3528  return -1;
3529  }
3530 
3531  /* Check if the SYN/ACK packets ACK matches the earlier
3532  * received SYN/ACK packet. */
3533  if (!(SEQ_EQ(ack, ssn->client.last_ack))) {
3534  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
3535  "%" PRIu32 " from stream",
3536  ssn, ack, ssn->client.isn + 1);
3537 
3539  return -1;
3540  }
3541 
3542  /* Check if the SYN/ACK packet SEQ the earlier
3543  * received SYN packet. */
3544  if (!(SEQ_EQ(seq, ssn->server.isn))) {
3545  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
3546  "%" PRIu32 " from stream",
3547  ssn, ack, ssn->client.isn + 1);
3548 
3550  return -1;
3551  }
3552 
3554  /* a resend of a SYN while we are established already -- fishy */
3556  return -1;
3557  }
3558 
3559  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
3560  "Likely due server not receiving final ACK in 3whs", ssn);
3561  return 0;
3562 
3563  } else if (tcph->th_flags & TH_SYN) {
3564  SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
3565  if (PKT_IS_TOCLIENT(p)) {
3566  SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
3567 
3569  return -1;
3570  }
3571 
3572  if (!(SEQ_EQ(ack, ssn->client.isn))) {
3573  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
3574 
3576  return -1;
3577  }
3578 
3579  /* a resend of a SYN while we are established already -- fishy */
3581  return -1;
3582 
3583  } else if (tcph->th_flags & TH_ACK) {
3584  /* Urgent pointer size can be more than the payload size, as it tells
3585  * the future coming data from the sender will be handled urgently
3586  * until data of size equal to urgent offset has been processed
3587  * (RFC 2147) */
3588 
3589  /* If the timestamp option is enabled for both the streams, then
3590  * validate the received packet timestamp value against the
3591  * stream->last_ts. If the timestamp is valid then process the
3592  * packet normally otherwise the drop the packet (RFC 1323) */
3594  if (!StreamTcpValidateTimestamp(ssn, p))
3595  return -1;
3596  }
3597 
3598  if (PKT_IS_TOSERVER(p)) {
3599  /* Process the received packet to server */
3600  HandleEstablishedPacketToServer(tv, ssn, p, stt);
3601 
3602  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3603  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3606 
3607  } else { /* implied to client */
3610  SCLogDebug("3whs is now confirmed by server");
3611  }
3612 
3613  /* Process the received packet to client */
3614  HandleEstablishedPacketToClient(tv, ssn, p, stt);
3615 
3616  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3617  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3620  }
3621  } else {
3622  SCLogDebug("ssn %p: default case", ssn);
3623  }
3624 
3625  return 0;
3626 }
3627 
3628 /**
3629  * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
3630  * TCP_ESTABLISHED and changes to another TCP state as required.
3631  *
3632  * \param tv Thread Variable containing input/output queue, cpu affinity
3633  * \param p Packet which has to be handled in this TCP state.
3634  * \param stt Stream Thread module registered to handle the stream handling
3635  *
3636  * \retval 0 success
3637  * \retval -1 something wrong with the packet
3638  */
3639 
3640 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession *ssn, Packet *p)
3641 {
3642  const TCPHdr *tcph = PacketGetTCP(p);
3643  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3644  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3645  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3646 
3647  if (PKT_IS_TOSERVER(p)) {
3648  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
3649  " ACK %" PRIu32 "",
3650  ssn, p->payload_len, seq, ack);
3651 
3652  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3653  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3655  return -1;
3656  }
3657 
3658  const uint32_t pkt_re = seq + p->payload_len;
3659  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3661  if (SEQ_GEQ(seq, ssn->client.last_ack) && SEQ_LEQ(pkt_re, ssn->client.next_win)) {
3662  // within expectations
3663  } else {
3664  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3665  "%" PRIu32 " from stream",
3666  ssn, seq, ssn->client.next_seq);
3667 
3669  return -1;
3670  }
3671 
3672  if (tcph->th_flags & TH_SYN) {
3673  SCLogDebug("ssn %p: FIN+SYN", ssn);
3675  return -1;
3676  }
3677  StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
3678  SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
3679 
3680  /* if we accept the FIN, next_seq needs to reflect the FIN */
3682 
3683  SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
3684  ssn->client.next_seq);
3685  ssn->server.window = window << ssn->server.wscale;
3686 
3688  StreamTcpHandleTimestamp(ssn, p);
3689  }
3690 
3691  /* Update the next_seq, in case if we have missed the client packet
3692  and server has already received and acked it */
3693  if (SEQ_LT(ssn->server.next_seq, ack))
3694  ssn->server.next_seq = ack;
3695 
3696  if (tcph->th_flags & TH_ACK)
3698 
3700 
3701  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3703  } else { /* implied to client */
3704  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
3705  "ACK %" PRIu32 "",
3706  ssn, p->payload_len, seq, ack);
3707 
3708  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3709  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3711  return -1;
3712  }
3713 
3714  const uint32_t pkt_re = seq + p->payload_len;
3715  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3717  if (SEQ_GEQ(seq, ssn->server.last_ack) && SEQ_LEQ(pkt_re, ssn->server.next_win)) {
3718  // within expectations
3719  } else {
3720  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3721  "%" PRIu32 " from stream (last_ack %u win %u = %u)",
3724 
3726  return -1;
3727  }
3728 
3729  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
3730  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
3731 
3732  /* if we accept the FIN, next_seq needs to reflect the FIN */
3733  ssn->server.next_seq = seq + p->payload_len + 1;
3734  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 " updated", ssn, ssn->server.next_seq);
3735 
3736  ssn->client.window = window << ssn->client.wscale;
3737 
3739  StreamTcpHandleTimestamp(ssn, p);
3740  }
3741 
3742  /* Update the next_seq, in case if we have missed the client packet
3743  and server has already received and acked it */
3744  if (SEQ_LT(ssn->client.next_seq, ack))
3745  ssn->client.next_seq = ack;
3746 
3747  if (tcph->th_flags & TH_ACK)
3749 
3751 
3752  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3754  }
3755 
3756  return 0;
3757 }
3758 
3759 /**
3760  * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
3761  * ACK, FIN, RST packets and correspondingly changes the connection
3762  * state.
3763  *
3764  * \param tv Thread Variable containing input/output queue, cpu affinity
3765  * \param p Packet which has to be handled in this TCP state.
3766  * \param stt Stream Thread module registered to handle the stream handling
3767  *
3768  * \retval 0 success
3769  * \retval -1 something wrong with the packet
3770  */
3771 
3772 static int StreamTcpPacketStateFinWait1(
3774 {
3775  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3776  const TCPHdr *tcph = PacketGetTCP(p);
3777  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3778  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3779  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3780 
3781  if (tcph->th_flags & TH_RST) {
3782  if (!StreamTcpValidateRst(ssn, p))
3783  return -1;
3784 
3785  StreamTcpCloseSsnWithReset(p, ssn);
3786 
3787  if (PKT_IS_TOSERVER(p)) {
3788  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3790 
3792 
3794  StreamTcpHandleTimestamp(ssn, p);
3795  }
3796 
3798  } else {
3799  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3801 
3803 
3805  StreamTcpHandleTimestamp(ssn, p);
3806  }
3807 
3809  }
3810 
3811  } else if ((tcph->th_flags & (TH_FIN | TH_ACK)) == (TH_FIN | TH_ACK)) {
3813  if (!StreamTcpValidateTimestamp(ssn, p))
3814  return -1;
3815  }
3816 
3817  if (PKT_IS_TOSERVER(p)) {
3818  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3819  "%" PRIu32 ", ACK %" PRIu32 "",
3820  ssn, p->payload_len, seq, ack);
3821  int retransmission = 0;
3822 
3823  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3824  SCLogDebug("ssn %p: packet is retransmission", ssn);
3825  retransmission = 1;
3827 
3828  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3830  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3831  " != %" PRIu32 " from stream",
3832  ssn, seq, ssn->client.next_seq);
3834  return -1;
3835  }
3836 
3837  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3838  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3840  return -1;
3841  }
3842 
3843  if (!retransmission) {
3844  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3845  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3846 
3847  ssn->server.window = window << ssn->server.wscale;
3848  }
3849 
3851  StreamTcpHandleTimestamp(ssn, p);
3852  }
3853 
3854  /* Update the next_seq, in case if we have missed the client
3855  packet and server has already received and acked it */
3856  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3857  ssn->server.next_seq = ack;
3858 
3859  if (SEQ_EQ(ssn->client.next_seq, seq)) {
3861  }
3862 
3864 
3866 
3867  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3868  "%" PRIu32 "", ssn, ssn->client.next_seq,
3869  ssn->server.last_ack);
3870  } else { /* implied to client */
3871  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3872  "%" PRIu32 ", ACK %" PRIu32 "",
3873  ssn, p->payload_len, seq, ack);
3874  int retransmission = 0;
3875 
3876  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3877  SCLogDebug("ssn %p: packet is retransmission", ssn);
3878  retransmission = 1;
3880 
3881  } else if (SEQ_EQ(ssn->server.next_seq - 1, seq) && SEQ_EQ(ssn->client.last_ack, ack)) {
3882  SCLogDebug("ssn %p: packet is retransmission", ssn);
3883  retransmission = 1;
3885 
3886  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3888  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3889  " != %" PRIu32 " from stream",
3890  ssn, seq, ssn->server.next_seq);
3892  return -1;
3893  }
3894 
3895  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3896  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3898  return -1;
3899  }
3900 
3902  StreamTcpHandleTimestamp(ssn, p);
3903  }
3904 
3905  if (!retransmission) {
3906  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3907  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3908 
3909  ssn->client.window = window << ssn->client.wscale;
3910 
3911  /* Update the next_seq, in case if we have missed the client
3912  packet and server has already received and acked it */
3913  if (SEQ_LT(ssn->client.next_seq - 1, ack))
3914  ssn->client.next_seq = ack;
3915 
3916  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3918  }
3919 
3921  }
3922 
3924 
3925  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3926  "%" PRIu32 "", ssn, ssn->server.next_seq,
3927  ssn->client.last_ack);
3928  }
3929 
3930  } else if (tcph->th_flags & TH_FIN) {
3932  if (!StreamTcpValidateTimestamp(ssn, p))
3933  return -1;
3934  }
3935 
3936  if (PKT_IS_TOSERVER(p)) {
3937  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3938  "%" PRIu32 ", ACK %" PRIu32 "",
3939  ssn, p->payload_len, seq, ack);
3940  int retransmission = 0;
3941 
3942  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3943  SCLogDebug("ssn %p: packet is retransmission", ssn);
3944  retransmission = 1;
3946 
3947  } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3949  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3950  " != %" PRIu32 " from stream",
3951  ssn, seq, ssn->client.next_seq);
3953  return -1;
3954  }
3955 
3956  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3957  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3959  return -1;
3960  }
3961 
3962  if (!retransmission) {
3963  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3964  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3965 
3966  ssn->server.window = window << ssn->server.wscale;
3967  }
3968 
3970  StreamTcpHandleTimestamp(ssn, p);
3971  }
3972 
3973  /* Update the next_seq, in case if we have missed the client
3974  packet and server has already received and acked it */
3975  if (SEQ_LT(ssn->server.next_seq - 1, ack))
3976  ssn->server.next_seq = ack;
3977 
3978  if (SEQ_EQ(ssn->client.next_seq - 1, seq)) {
3980  }
3981 
3982  if (tcph->th_flags & TH_ACK)
3984 
3986 
3987  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3988  "%" PRIu32 "", ssn, ssn->client.next_seq,
3989  ssn->server.last_ack);
3990  } else { /* implied to client */
3991  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3992  "%" PRIu32 ", ACK %" PRIu32 "",
3993  ssn, p->payload_len, seq, ack);
3994 
3995  int retransmission = 0;
3996 
3997  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3998  SCLogDebug("ssn %p: packet is retransmission", ssn);
3999  retransmission = 1;
4001 
4002  } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
4004  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4005  " != %" PRIu32 " from stream",
4006  ssn, seq, ssn->server.next_seq);
4008  return -1;
4009  }
4010 
4011  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4012  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4014  return -1;
4015  }
4016 
4017  if (!retransmission) {
4018  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
4019  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
4020 
4021  ssn->client.window = window << ssn->client.wscale;
4022  }
4023 
4025  StreamTcpHandleTimestamp(ssn, p);
4026  }
4027 
4028  /* Update the next_seq, in case if we have missed the client
4029  packet and server has already received and acked it */
4030  if (SEQ_LT(ssn->client.next_seq - 1, ack))
4031  ssn->client.next_seq = ack;
4032 
4033  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
4035  }
4036 
4037  if (tcph->th_flags & TH_ACK)
4039 
4041 
4042  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4043  "%" PRIu32 "", ssn, ssn->server.next_seq,
4044  ssn->client.last_ack);
4045  }
4046  } else if (tcph->th_flags & TH_SYN) {
4047  SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
4049  return -1;
4050 
4051  } else if (tcph->th_flags & TH_ACK) {
4053  if (!StreamTcpValidateTimestamp(ssn, p))
4054  return -1;
4055  }
4056 
4057  if (PKT_IS_TOSERVER(p)) {
4058  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4059  "%" PRIu32 ", ACK %" PRIu32 "",
4060  ssn, p->payload_len, seq, ack);
4061  int retransmission = 0;
4062 
4063  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4064  SCLogDebug("ssn %p: packet is retransmission", ssn);
4065  retransmission = 1;
4067  }
4068 
4069  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4070  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4072  return -1;
4073  }
4074 
4075  if (SEQ_LT(ack, ssn->server.next_seq)) {
4076  SCLogDebug(
4077  "ssn %p: ACK's older segment as %u < %u", ssn, ack, ssn->server.next_seq);
4078  } else if (!retransmission) {
4079  if (SEQ_EQ(ack, ssn->server.next_seq)) {
4080  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
4082  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
4083  "%" PRIu32 "",
4084  ssn, seq, ssn->client.next_win);
4085  SCLogDebug("seq %u client.next_seq %u", seq, ssn->client.next_seq);
4086  if (seq == ssn->client.next_seq) {
4087  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
4088  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
4089  }
4090  } else {
4091  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4092  " != %" PRIu32 " from stream",
4093  ssn, seq, ssn->client.next_seq);
4094 
4096  return -1;
4097  }
4098 
4099  ssn->server.window = window << ssn->server.wscale;
4100  }
4101  }
4102 
4104  StreamTcpHandleTimestamp(ssn, p);
4105  }
4106 
4107  /* Update the next_seq, in case if we have missed the client
4108  packet and server has already received and acked it */
4109  if (SEQ_LT(ssn->server.next_seq - 1, ack))
4110  ssn->server.next_seq = ack;
4111 
4112  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4114  }
4115 
4117 
4119 
4120  /* update next_win */
4122 
4124 
4125  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4126  "%" PRIu32 "", ssn, ssn->client.next_seq,
4127  ssn->server.last_ack);
4128 
4129  } else { /* implied to client */
4130 
4131  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4132  "%" PRIu32 ", ACK %" PRIu32 "",
4133  ssn, p->payload_len, seq, ack);
4134 
4135  int retransmission = 0;
4136 
4137  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4138  SCLogDebug("ssn %p: packet is retransmission", ssn);
4139  retransmission = 1;
4141  }
4142 
4143  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4144  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4146  return -1;
4147  }
4148 
4149  if (!retransmission) {
4150  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4152  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4153  "%" PRIu32 "",
4154  ssn, seq, ssn->server.next_win);
4155 
4156  if (seq == ssn->server.next_seq - 1) {
4157  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
4158  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
4159  }
4160  } else {
4161  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4162  " != %" PRIu32 " from stream",
4163  ssn, seq, ssn->server.next_seq);
4165  return -1;
4166  }
4167 
4168  ssn->client.window = window << ssn->client.wscale;
4169  }
4170 
4172  StreamTcpHandleTimestamp(ssn, p);
4173  }
4174 
4175  /* Update the next_seq, in case if we have missed the client
4176  packet and server has already received and acked it */
4177  if (SEQ_LT(ssn->client.next_seq - 1, ack))
4178  ssn->client.next_seq = ack;
4179 
4180  if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
4182  }
4183 
4185 
4187 
4188  /* update next_win */
4190 
4192 
4193  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4194  "%" PRIu32 "", ssn, ssn->server.next_seq,
4195  ssn->client.last_ack);
4196  }
4197  } else {
4198  SCLogDebug("ssn (%p): default case", ssn);
4199  }
4200 
4201  return 0;
4202 }
4203 
4204 /**
4205  * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
4206  * ACK, RST, FIN packets and correspondingly changes the connection
4207  * state.
4208  *
4209  * \param tv Thread Variable containing input/output queue, cpu affinity
4210  * \param p Packet which has to be handled in this TCP state.
4211  * \param stt Stream Thread module registered to handle the stream handling
4212  */
4213 
4214 static int StreamTcpPacketStateFinWait2(
4216 {
4217  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4218  const TCPHdr *tcph = PacketGetTCP(p);
4219  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4220  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4221  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4222 
4223  if (tcph->th_flags & TH_RST) {
4224  if (!StreamTcpValidateRst(ssn, p))
4225  return -1;
4226 
4227  StreamTcpCloseSsnWithReset(p, ssn);
4228 
4229  if (PKT_IS_TOSERVER(p)) {
4230  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4232 
4234 
4236  StreamTcpHandleTimestamp(ssn, p);
4237  }
4238 
4240  } else {
4241  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4243 
4245 
4247  StreamTcpHandleTimestamp(ssn, p);
4248  }
4249 
4251  }
4252 
4253  } else if (tcph->th_flags & TH_FIN) {
4255  if (!StreamTcpValidateTimestamp(ssn, p))
4256  return -1;
4257  }
4258 
4259  if (PKT_IS_TOSERVER(p)) {
4260  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4261  "%" PRIu32 ", ACK %" PRIu32 "",
4262  ssn, p->payload_len, seq, ack);
4263  int retransmission = 0;
4264 
4265  if (SEQ_EQ(seq, ssn->client.next_seq - 1) && SEQ_EQ(ack, ssn->server.last_ack)) {
4266  SCLogDebug("ssn %p: retransmission", ssn);
4267  retransmission = 1;
4269  } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4270  SCLogDebug("ssn %p: packet is retransmission", ssn);
4271  retransmission = 1;
4273 
4274  } else if (SEQ_LT(seq, ssn->client.next_seq) ||
4276  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4277  "%" PRIu32 " != %" PRIu32 " from stream",
4278  ssn, seq, ssn->client.next_seq);
4280  return -1;
4281  }
4282 
4283  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4284  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4286  return -1;
4287  }
4288 
4289  if (!retransmission) {
4290  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4291  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4292 
4293  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4296  }
4297  ssn->server.window = window << ssn->server.wscale;
4298  }
4299 
4301  StreamTcpHandleTimestamp(ssn, p);
4302  }
4303 
4304  /* Update the next_seq, in case if we have missed the client
4305  packet and server has already received and acked it */
4306  if (SEQ_LT(ssn->server.next_seq, ack))
4307  ssn->server.next_seq = ack;
4308 
4309  if (tcph->th_flags & TH_ACK)
4311 
4313 
4314  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4315  "%" PRIu32 "", ssn, ssn->client.next_seq,
4316  ssn->server.last_ack);
4317  } else { /* implied to client */
4318  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4319  "%" PRIu32 ", ACK %" PRIu32 "",
4320  ssn, p->payload_len, seq, ack);
4321  int retransmission = 0;
4322 
4323  if (SEQ_EQ(seq, ssn->server.next_seq - 1) && SEQ_EQ(ack, ssn->client.last_ack)) {
4324  SCLogDebug("ssn %p: retransmission", ssn);
4325  retransmission = 1;
4327  } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4328  SCLogDebug("ssn %p: packet is retransmission", ssn);
4329  retransmission = 1;
4331 
4332  } else if (SEQ_LT(seq, ssn->server.next_seq) ||
4334  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4335  "%" PRIu32 " != %" PRIu32 " from stream",
4336  ssn, seq, ssn->server.next_seq);
4338  return -1;
4339  }
4340 
4341  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4342  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4344  return -1;
4345  }
4346 
4347  if (!retransmission) {
4348  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4349  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4350 
4351  ssn->client.window = window << ssn->client.wscale;
4352  }
4353 
4355  StreamTcpHandleTimestamp(ssn, p);
4356  }
4357 
4358  /* Update the next_seq, in case if we have missed the client
4359  packet and server has already received and acked it */
4360  if (SEQ_LT(ssn->client.next_seq, ack))
4361  ssn->client.next_seq = ack;
4362 
4363  if (tcph->th_flags & TH_ACK)
4365 
4367  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4368  "%" PRIu32 "", ssn, ssn->server.next_seq,
4369  ssn->client.last_ack);
4370  }
4371 
4372  } else if (tcph->th_flags & TH_SYN) {
4373  SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
4375  return -1;
4376 
4377  } else if (tcph->th_flags & TH_ACK) {
4379  if (!StreamTcpValidateTimestamp(ssn, p))
4380  return -1;
4381  }
4382 
4383  if (PKT_IS_TOSERVER(p)) {
4384  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4385  "%" PRIu32 ", ACK %" PRIu32 "",
4386  ssn, p->payload_len, seq, ack);
4387  int retransmission = 0;
4388 
4389  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4390  SCLogDebug("ssn %p: packet is retransmission", ssn);
4391  retransmission = 1;
4393  }
4394 
4395  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4396  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4398  return -1;
4399  }
4400 
4401  if (!retransmission) {
4402  if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
4404  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
4405  "%" PRIu32 "",
4406  ssn, seq, ssn->client.next_win);
4407 
4408  } else {
4409  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4410  " != %" PRIu32 " from stream",
4411  ssn, seq, ssn->client.next_seq);
4413  return -1;
4414  }
4415 
4416  ssn->server.window = window << ssn->server.wscale;
4417  }
4418 
4420  StreamTcpHandleTimestamp(ssn, p);
4421  }
4422 
4423  if (SEQ_EQ(ssn->client.next_seq, seq)) {
4425  }
4426 
4428 
4430 
4431  /* update next_win */
4433 
4435 
4436  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4437  "%" PRIu32 "", ssn, ssn->client.next_seq,
4438  ssn->server.last_ack);
4439  } else { /* implied to client */
4440  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4441  "%" PRIu32 ", ACK %" PRIu32 "",
4442  ssn, p->payload_len, seq, ack);
4443  int retransmission = 0;
4444 
4445  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4446  SCLogDebug("ssn %p: packet is retransmission", ssn);
4447  retransmission = 1;
4449  }
4450 
4451  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4452  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4454  return -1;
4455  }
4456 
4457  if (!retransmission) {
4458  if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4460  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4461  "%" PRIu32 "",
4462  ssn, seq, ssn->server.next_win);
4463  } else {
4464  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4465  " != %" PRIu32 " from stream",
4466  ssn, seq, ssn->server.next_seq);
4468  return -1;
4469  }
4470 
4471  ssn->client.window = window << ssn->client.wscale;
4472  }
4473 
4475  StreamTcpHandleTimestamp(ssn, p);
4476  }
4477 
4478  if (SEQ_EQ(ssn->server.next_seq, seq)) {
4480  }
4481 
4483 
4485 
4486  /* update next_win */
4488 
4490 
4491  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4492  "%" PRIu32 "", ssn, ssn->server.next_seq,
4493  ssn->client.last_ack);
4494  }
4495  } else {
4496  SCLogDebug("ssn %p: default case", ssn);
4497  }
4498 
4499  return 0;
4500 }
4501 
4502 /**
4503  * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
4504  * the connection goes to TCP_TIME_WAIT state. The state has been
4505  * reached as both end application has been closed.
4506  *
4507  * \param tv Thread Variable containing input/output queue, cpu affinity
4508  * \param p Packet which has to be handled in this TCP state.
4509  * \param stt Stream Thread module registered to handle the stream handling
4510  */
4511 
4512 static int StreamTcpPacketStateClosing(
4514 {
4515  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4516  const TCPHdr *tcph = PacketGetTCP(p);
4517  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4518  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4519  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4520 
4521  if (tcph->th_flags & TH_RST) {
4522  if (!StreamTcpValidateRst(ssn, p))
4523  return -1;
4524 
4525  StreamTcpCloseSsnWithReset(p, ssn);
4526 
4527  if (PKT_IS_TOSERVER(p)) {
4528  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4530 
4532 
4534  StreamTcpHandleTimestamp(ssn, p);
4535  }
4536 
4538  } else {
4539  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4541 
4543 
4545  StreamTcpHandleTimestamp(ssn, p);
4546  }
4547 
4549  }
4550 
4551  } else if (tcph->th_flags & TH_SYN) {
4552  SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
4554  return -1;
4555 
4556  } else if (tcph->th_flags & TH_ACK) {
4558  if (!StreamTcpValidateTimestamp(ssn, p))
4559  return -1;
4560  }
4561 
4562  if (PKT_IS_TOSERVER(p)) {
4563  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4564  "%" PRIu32 ", ACK %" PRIu32 "",
4565  ssn, p->payload_len, seq, ack);
4566  int retransmission = 0;
4567  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4568  SCLogDebug("ssn %p: packet is retransmission", ssn);
4569  retransmission = 1;
4571  }
4572 
4573  if (seq != ssn->client.next_seq) {
4574  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4575  " != %" PRIu32 " from stream",
4576  ssn, seq, ssn->client.next_seq);
4578  return -1;
4579  }
4580 
4581  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4582  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4584  return -1;
4585  }
4586 
4587  if (!retransmission) {
4588  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4589  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4590 
4591  ssn->client.window = window << ssn->client.wscale;
4592  }
4593 
4595  StreamTcpHandleTimestamp(ssn, p);
4596  }
4597  /* Update the next_seq, in case if we have missed the client
4598  packet and server has already received and acked it */
4599  if (SEQ_LT(ssn->server.next_seq, ack))
4600  ssn->server.next_seq = ack;
4601 
4603 
4605  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4606  "%" PRIu32 "", ssn, ssn->client.next_seq,
4607  ssn->server.last_ack);
4608  } else { /* implied to client */
4609  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4610  "%" PRIu32 ", ACK %" PRIu32 "",
4611  ssn, p->payload_len, seq, ack);
4612  int retransmission = 0;
4613  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4614  SCLogDebug("ssn %p: packet is retransmission", ssn);
4615  retransmission = 1;
4617  }
4618 
4619  if (seq != ssn->server.next_seq) {
4620  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4621  " != %" PRIu32 " from stream",
4622  ssn, seq, ssn->server.next_seq);
4624  return -1;
4625  }
4626 
4627  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4628  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4630  return -1;
4631  }
4632 
4633  if (!retransmission) {
4634  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4635  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4636 
4637  ssn->client.window = window << ssn->client.wscale;
4638  }
4639 
4641  StreamTcpHandleTimestamp(ssn, p);
4642  }
4643 
4644  /* Update the next_seq, in case if we have missed the client
4645  packet and server has already received and acked it */
4646  if (SEQ_LT(ssn->client.next_seq, ack))
4647  ssn->client.next_seq = ack;
4648 
4650 
4652  SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
4653  "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
4655  }
4656  } else {
4657  SCLogDebug("ssn %p: default case", ssn);
4658  }
4659 
4660  return 0;
4661 }
4662 
4663 /**
4664  * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
4665  * packet from server the connection goes to TCP_LAST_ACK state.
4666  * The state is possible only for server host.
4667  *
4668  * \param tv Thread Variable containing input/output queue, cpu affinity
4669  * \param p Packet which has to be handled in this TCP state.
4670  * \param stt Stream Thread module registered to handle the stream handling
4671  */
4672 
4673 static int StreamTcpPacketStateCloseWait(
4675 {
4676  SCEnter();
4677  const TCPHdr *tcph = PacketGetTCP(p);
4678  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4679  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4680  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4681 
4682  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4683 
4684  if (PKT_IS_TOCLIENT(p)) {
4685  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4686  "%" PRIu32 ", ACK %" PRIu32 "",
4687  ssn, p->payload_len, seq, ack);
4688  } else {
4689  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4690  "%" PRIu32 ", ACK %" PRIu32 "",
4691  ssn, p->payload_len, seq, ack);
4692  }
4693 
4694  if (tcph->th_flags & TH_RST) {
4695  if (!StreamTcpValidateRst(ssn, p))
4696  return -1;
4697 
4698  StreamTcpCloseSsnWithReset(p, ssn);
4699 
4700  if (PKT_IS_TOSERVER(p)) {
4701  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4703 
4705 
4707  StreamTcpHandleTimestamp(ssn, p);
4708  }
4709 
4711  } else {
4712  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4714 
4716 
4718  StreamTcpHandleTimestamp(ssn, p);
4719  }
4720 
4722  }
4723 
4724  } else if (tcph->th_flags & TH_FIN) {
4726  if (!StreamTcpValidateTimestamp(ssn, p))
4727  SCReturnInt(-1);
4728  }
4729 
4730  if (PKT_IS_TOSERVER(p)) {
4731  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4732  "%" PRIu32 ", ACK %" PRIu32 "",
4733  ssn, p->payload_len, seq, ack);
4734 
4735  int retransmission = 0;
4736  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4737  SCLogDebug("ssn %p: packet is retransmission", ssn);
4738  retransmission = 1;
4740  }
4741 
4742  if (!retransmission) {
4743  if (SEQ_LT(seq, ssn->client.next_seq) ||
4745  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4746  " != %" PRIu32 " from stream",
4747  ssn, seq, ssn->client.next_seq);
4749  SCReturnInt(-1);
4750  }
4751  }
4752 
4753  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4754  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4756  SCReturnInt(-1);
4757  }
4758 
4759  /* don't update to LAST_ACK here as we want a toclient FIN for that */
4760 
4761  if (!retransmission)
4762  ssn->server.window = window << ssn->server.wscale;
4763 
4765  StreamTcpHandleTimestamp(ssn, p);
4766  }
4767 
4768  /* Update the next_seq, in case if we have missed the client
4769  packet and server has already received and acked it */
4770  if (SEQ_LT(ssn->server.next_seq, ack))
4771  ssn->server.next_seq = ack;
4772 
4773  if (tcph->th_flags & TH_ACK)
4775 
4777  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4778  "%" PRIu32 "", ssn, ssn->client.next_seq,
4779  ssn->server.last_ack);
4780  } else {
4781  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4782  "%" PRIu32 ", ACK %" PRIu32 "",
4783  ssn, p->payload_len, seq, ack);
4784 
4785  int retransmission = 0;
4786  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4787  SCLogDebug("ssn %p: packet is retransmission", ssn);
4788  retransmission = 1;
4790  }
4791 
4792  if (!retransmission) {
4793  if (SEQ_LT(seq, ssn->server.next_seq) ||
4795  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4796  " != %" PRIu32 " from stream",
4797  ssn, seq, ssn->server.next_seq);
4799  SCReturnInt(-1);
4800  }
4801  }
4802 
4803  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4804  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4806  SCReturnInt(-1);
4807  }
4808 
4809  if (!retransmission) {
4810  StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
4811  SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
4812 
4813  ssn->client.window = window << ssn->client.wscale;
4814  }
4815 
4817  StreamTcpHandleTimestamp(ssn, p);
4818  }
4819 
4820  /* Update the next_seq, in case if we have missed the client
4821  packet and server has already received and acked it */
4822  if (SEQ_LT(ssn->client.next_seq, ack))
4823  ssn->client.next_seq = ack;
4824 
4825  if (tcph->th_flags & TH_ACK)
4827 
4829  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4830  "%" PRIu32 "", ssn, ssn->server.next_seq,
4831  ssn->client.last_ack);
4832  }
4833 
4834  } else if (tcph->th_flags & TH_SYN) {
4835  SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
4837  SCReturnInt(-1);
4838 
4839  } else if (tcph->th_flags & TH_ACK) {
4841  if (!StreamTcpValidateTimestamp(ssn, p))
4842  SCReturnInt(-1);
4843  }
4844 
4845  if (PKT_IS_TOSERVER(p)) {
4846  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4847  "%" PRIu32 ", ACK %" PRIu32 "",
4848  ssn, p->payload_len, seq, ack);
4849 
4850  int retransmission = 0;
4851  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4852  SCLogDebug("ssn %p: packet is retransmission", ssn);
4853  retransmission = 1;
4855  }
4856 
4857  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->client.last_ack))) {
4858  SCLogDebug("ssn %p: -> retransmission", ssn);
4860  SCReturnInt(-1);
4861 
4862  } else if (SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4863  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4864  " != %" PRIu32 " from stream",
4865  ssn, seq, ssn->client.next_seq);
4867  SCReturnInt(-1);
4868  }
4869 
4870  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4871  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4873  SCReturnInt(-1);
4874  }
4875 
4876  if (!retransmission) {
4877  ssn->server.window = window << ssn->server.wscale;
4878  }
4879 
4881  StreamTcpHandleTimestamp(ssn, p);
4882  }
4883 
4884  /* Update the next_seq, in case if we have missed the client
4885  packet and server has already received and acked it */
4886  if (SEQ_LT(ssn->server.next_seq, ack))
4887  ssn->server.next_seq = ack;
4888 
4889  if (SEQ_EQ(seq, ssn->client.next_seq))
4891 
4893 
4895  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4896  "%" PRIu32 "", ssn, ssn->client.next_seq,
4897  ssn->server.last_ack);
4898  } else {
4899  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4900  "%" PRIu32 ", ACK %" PRIu32 "",
4901  ssn, p->payload_len, seq, ack);
4902  int retransmission = 0;
4903  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4904  SCLogDebug("ssn %p: packet is retransmission", ssn);
4905  retransmission = 1;
4907  }
4908 
4909  if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->server.last_ack))) {
4910  SCLogDebug("ssn %p: -> retransmission", ssn);
4912  SCReturnInt(-1);
4913 
4914  } else if (SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4915  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4916  " != %" PRIu32 " from stream",
4917  ssn, seq, ssn->server.next_seq);
4919  SCReturnInt(-1);
4920  }
4921 
4922  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4923  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4925  SCReturnInt(-1);
4926  }
4927 
4928  if (!retransmission) {
4929  ssn->client.window = window << ssn->client.wscale;
4930  }
4931 
4933  StreamTcpHandleTimestamp(ssn, p);
4934  }
4935 
4936  /* Update the next_seq, in case if we have missed the client
4937  packet and server has already received and acked it */
4938  if (SEQ_LT(ssn->client.next_seq, ack))
4939  ssn->client.next_seq = ack;
4940 
4941  if (SEQ_EQ(seq, ssn->server.next_seq))
4943 
4945 
4947  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4948  "%" PRIu32 "", ssn, ssn->server.next_seq,
4949  ssn->client.last_ack);
4950  }
4951 
4952  } else {
4953  SCLogDebug("ssn %p: default case", ssn);
4954  }
4955  SCReturnInt(0);
4956 }
4957 
4958 /**
4959  * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
4960  * the connection goes to TCP_CLOSED state and stream memory is
4961  * returned back to pool. The state is possible only for server host.
4962  *
4963  * \param tv Thread Variable containing input/output queue, cpu affinity
4964  * \param p Packet which has to be handled in this TCP state.
4965  * \param stt Stream Thread module registered to handle the stream handling
4966  */
4967 
4968 static int StreamTcpPacketStateLastAck(
4970 {
4971  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4972  const TCPHdr *tcph = PacketGetTCP(p);
4973  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4974  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4975  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4976 
4977  if (tcph->th_flags & TH_RST) {
4978  if (!StreamTcpValidateRst(ssn, p))
4979  return -1;
4980 
4981  StreamTcpCloseSsnWithReset(p, ssn);
4982 
4983  if (PKT_IS_TOSERVER(p)) {
4984  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4986 
4988 
4990  StreamTcpHandleTimestamp(ssn, p);
4991  }
4992 
4994  } else {
4995  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4997 
4999 
5001  StreamTcpHandleTimestamp(ssn, p);
5002  }
5003 
5005  }
5006 
5007  } else if (tcph->th_flags & TH_FIN) {
5008  /** \todo */
5009  SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
5010 
5011  } else if (tcph->th_flags & TH_SYN) {
5012  SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
5014  return -1;
5015 
5016  } else if (tcph->th_flags & TH_ACK) {
5018  if (!StreamTcpValidateTimestamp(ssn, p))
5019  return -1;
5020  }
5021 
5022  if (PKT_IS_TOSERVER(p)) {
5023  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
5024  "%" PRIu32 ", ACK %" PRIu32 "",
5025  ssn, p->payload_len, seq, ack);
5026 
5027  int retransmission = 0;
5028  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
5029  SCLogDebug("ssn %p: packet is retransmission", ssn);
5030  retransmission = 1;
5032  }
5033 
5034  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
5035  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5037  SCReturnInt(-1);
5038  }
5039 
5040  if (!retransmission) {
5041  if (SEQ_LT(seq, ssn->client.next_seq)) {
5042  SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
5043  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
5044  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5045  " != %" PRIu32 " from stream",
5046  ssn, seq, ssn->client.next_seq);
5048  return -1;
5049  } else {
5050  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5051  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5052  }
5053  ssn->server.window = window << ssn->server.wscale;
5054  }
5055 
5057  StreamTcpHandleTimestamp(ssn, p);
5058  }
5059 
5060  /* Update the next_seq, in case if we have missed the client
5061  packet and server has already received and acked it */
5062  if (SEQ_LT(ssn->server.next_seq, ack))
5063  ssn->server.next_seq = ack;
5064 
5066 
5068  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5069  "%" PRIu32 "", ssn, ssn->client.next_seq,
5070  ssn->server.last_ack);
5071  }
5072  } else {
5073  SCLogDebug("ssn %p: default case", ssn);
5074  }
5075 
5076  return 0;
5077 }
5078 
5079 /**
5080  * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
5081  * the connection goes to TCP_CLOSED state and stream memory is
5082  * returned back to pool.
5083  *
5084  * \param tv Thread Variable containing input/output queue, cpu affinity
5085  * \param p Packet which has to be handled in this TCP state.
5086  * \param stt Stream Thread module registered to handle the stream handling
5087  */
5088 
5089 static int StreamTcpPacketStateTimeWait(
5091 {
5092  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5093  const TCPHdr *tcph = PacketGetTCP(p);
5094  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
5095  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
5096  const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
5097 
5098  if (tcph->th_flags & TH_RST) {
5099  if (!StreamTcpValidateRst(ssn, p))
5100  return -1;
5101 
5102  StreamTcpCloseSsnWithReset(p, ssn);
5103 
5104  if (PKT_IS_TOSERVER(p)) {
5105  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
5107 
5109 
5111  StreamTcpHandleTimestamp(ssn, p);
5112  }
5113 
5115  } else {
5116  if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
5118 
5120 
5122  StreamTcpHandleTimestamp(ssn, p);
5123  }
5124 
5126  }
5127 
5128  } else if (tcph->th_flags & TH_FIN) {
5129  /** \todo */
5130 
5131  } else if (tcph->th_flags & TH_SYN) {
5132  SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
5134  return -1;
5135 
5136  } else if (tcph->th_flags & TH_ACK) {
5138  if (!StreamTcpValidateTimestamp(ssn, p))
5139  return -1;
5140  }
5141 
5142  if (PKT_IS_TOSERVER(p)) {
5143  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
5144  "%" PRIu32 ", ACK %" PRIu32 "",
5145  ssn, p->payload_len, seq, ack);
5146  int retransmission = 0;
5147  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
5148  SCLogDebug("ssn %p: packet is retransmission", ssn);
5149  retransmission = 1;
5151 
5152  } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
5153  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5154  " != %" PRIu32 " from stream",
5155  ssn, seq, ssn->client.next_seq);
5157  return -1;
5158  }
5159 
5160  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
5161  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5163  SCReturnInt(-1);
5164  }
5165 
5166  if (!retransmission) {
5167  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5168  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5169 
5170  ssn->server.window = window << ssn->server.wscale;
5171  }
5172 
5174  StreamTcpHandleTimestamp(ssn, p);
5175  }
5176 
5177  /* Update the next_seq, in case if we have missed the client
5178  packet and server has already received and acked it */
5179  if (SEQ_LT(ssn->server.next_seq, ack))
5180  ssn->server.next_seq = ack;
5181 
5183 
5185  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5186  "%" PRIu32 "", ssn, ssn->client.next_seq,
5187  ssn->server.last_ack);
5188  } else {
5189  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
5190  "%" PRIu32 ", ACK %" PRIu32 "",
5191  ssn, p->payload_len, seq, ack);
5192  int retransmission = 0;
5193  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
5194  SCLogDebug("ssn %p: packet is retransmission", ssn);
5195  retransmission = 1;
5197  } else if (seq != ssn->server.next_seq - 1 && seq != ssn->server.next_seq) {
5198  if (p->payload_len > 0 && seq == ssn->server.last_ack) {
5199  SCLogDebug("ssn %p: -> retransmission", ssn);
5200  SCReturnInt(0);
5201  } else {
5202  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5203  " != %" PRIu32 " from stream",
5204  ssn, seq, ssn->server.next_seq);
5206  return -1;
5207  }
5208  }
5209 
5210  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
5211  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5213  SCReturnInt(-1);
5214  }
5215 
5216  if (!retransmission) {
5217  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5218  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5219 
5220  ssn->client.window = window << ssn->client.wscale;
5221  }
5222 
5224  StreamTcpHandleTimestamp(ssn, p);
5225  }
5226 
5227  /* Update the next_seq, in case if we have missed the client
5228  packet and server has already received and acked it */
5229  if (SEQ_LT(ssn->client.next_seq, ack))
5230  ssn->client.next_seq = ack;
5231 
5233 
5235  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5236  "%" PRIu32 "", ssn, ssn->server.next_seq,
5237  ssn->client.last_ack);
5238  }
5239 
5240  } else {
5241  SCLogDebug("ssn %p: default case", ssn);
5242  }
5243 
5244  return 0;
5245 }
5246 
5247 static int StreamTcpPacketStateClosed(
5249 {
5250  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5251 
5252  const TCPHdr *tcph = PacketGetTCP(p);
5253  if (tcph->th_flags & TH_RST) {
5254  SCLogDebug("RST on closed state");
5255  return 0;
5256  }
5257 
5258  TcpStream *stream = NULL, *ostream = NULL;
5259  if (PKT_IS_TOSERVER(p)) {
5260  stream = &ssn->client;
5261  ostream = &ssn->server;
5262  } else {
5263  stream = &ssn->server;
5264  ostream = &ssn->client;
5265  }
5266 
5267  SCLogDebug("stream %s ostream %s",
5268  stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
5269  ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
5270 
5271  /* if we've seen a RST on our direction, but not on the other
5272  * see if we perhaps need to continue processing anyway. */
5273  if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
5274  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5275  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->pstate) < 0)
5276  return -1;
5277  /* if state is still "closed", it wasn't updated by our dispatch. */
5278  if (ssn->state == TCP_CLOSED)
5279  ssn->state = ssn->pstate;
5280  }
5281  }
5282  return 0;
5283 }
5284 
5285 static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
5286 {
5287  if (p->flags & PKT_PSEUDO_STREAM_END) {
5288  return;
5289  }
5290  const TCPHdr *tcph = PacketGetTCP(p);
5291  /* more RSTs are not unusual */
5292  if ((tcph->th_flags & (TH_RST)) != 0) {
5293  return;
5294  }
5295 
5296  TcpStream *ostream = NULL;
5297  if (PKT_IS_TOSERVER(p)) {
5298  ostream = &ssn->server;
5299  } else {
5300  ostream = &ssn->client;
5301  }
5302 
5303  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5304  SCLogDebug("regular packet %" PRIu64 " from same sender as "
5305  "the previous RST. Looks like it injected!",
5306  PcapPacketCntGet(p));
5310  return;
5311  }
5312 }
5313 
5314 /**
5315  * \retval 1 packet is a keep alive pkt
5316  * \retval 0 packet is not a keep alive pkt
5317  */
5318 static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
5319 {
5320  if (p->flags & PKT_PSEUDO_STREAM_END)
5321  return 0;
5322 
5323  /* rfc 1122:
5324  An implementation SHOULD send a keep-alive segment with no
5325  data; however, it MAY be configurable to send a keep-alive
5326  segment containing one garbage octet, for compatibility with
5327  erroneous TCP implementations.
5328  */
5329  if (p->payload_len > 1)
5330  return 0;
5331 
5332  const TCPHdr *tcph = PacketGetTCP(p);
5333  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) {
5334  return 0;
5335  }
5336 
5337  TcpStream *stream = NULL, *ostream = NULL;
5338  if (PKT_IS_TOSERVER(p)) {
5339  stream = &ssn->client;
5340  ostream = &ssn->server;
5341  } else {
5342  stream = &ssn->server;
5343  ostream = &ssn->client;
5344  }
5345 
5346  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
5347  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
5348  if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
5349  SCLogDebug("packet is TCP keep-alive: %" PRIu64, PcapPacketCntGet(p));
5352  return 1;
5353  }
5354  SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
5355  return 0;
5356 }
5357 
5358 /**
5359  * \retval 1 packet is a keep alive ACK pkt
5360  * \retval 0 packet is not a keep alive ACK pkt
5361  */
5362 static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
5363 {
5364  TcpStream *stream = NULL, *ostream = NULL;
5365  uint32_t seq;
5366  uint32_t ack;
5367  uint32_t pkt_win;
5368 
5369  if (p->flags & PKT_PSEUDO_STREAM_END)
5370  return 0;
5371  /* should get a normal ACK to a Keep Alive */
5372  if (p->payload_len > 0)
5373  return 0;
5374 
5375  const TCPHdr *tcph = PacketGetTCP(p);
5376  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5377  return 0;
5378 
5379  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5380  return 0;
5381 
5382  if (PKT_IS_TOSERVER(p)) {
5383  stream = &ssn->client;
5384  ostream = &ssn->server;
5385  } else {
5386  stream = &ssn->server;
5387  ostream = &ssn->client;
5388  }
5389 
5390  seq = TCP_GET_RAW_SEQ(tcph);
5391  ack = TCP_GET_RAW_ACK(tcph);
5392 
5393  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5394  if (pkt_win != ostream->window)
5395  return 0;
5396 
5397  if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
5398  SCLogDebug("packet is TCP keep-aliveACK: %" PRIu64, PcapPacketCntGet(p));
5399  ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
5401  return 1;
5402  }
5403  SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
5404  ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
5405  return 0;
5406 }
5407 
5408 static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
5409 {
5410  TcpStream *stream = NULL;
5411 
5412  if (p->flags & PKT_PSEUDO_STREAM_END)
5413  return;
5414 
5415  if (PKT_IS_TOSERVER(p)) {
5416  stream = &ssn->client;
5417  } else {
5418  stream = &ssn->server;
5419  }
5420 
5421  if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
5423  SCLogDebug("FLAG_KEEPALIVE cleared");
5424  }
5425 }
5426 
5427 /**
5428  * \retval 1 packet is a window update pkt
5429  * \retval 0 packet is not a window update pkt
5430  */
5431 static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
5432 {
5433  TcpStream *stream = NULL, *ostream = NULL;
5434  uint32_t seq;
5435  uint32_t ack;
5436  uint32_t pkt_win;
5437 
5438  if (p->flags & PKT_PSEUDO_STREAM_END)
5439  return 0;
5440 
5441  if (ssn->state < TCP_ESTABLISHED)
5442  return 0;
5443 
5444  if (p->payload_len > 0)
5445  return 0;
5446 
5447  const TCPHdr *tcph = PacketGetTCP(p);
5448  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5449  return 0;
5450 
5451  if (TCP_GET_RAW_WINDOW(tcph) == 0)
5452  return 0;
5453 
5454  if (PKT_IS_TOSERVER(p)) {
5455  stream = &ssn->client;
5456  ostream = &ssn->server;
5457  } else {
5458  stream = &ssn->server;
5459  ostream = &ssn->client;
5460  }
5461 
5462  seq = TCP_GET_RAW_SEQ(tcph);
5463  ack = TCP_GET_RAW_ACK(tcph);
5464 
5465  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5466  if (pkt_win == ostream->window)
5467  return 0;
5468 
5469  if (ack == ostream->last_ack && seq == stream->next_seq) {
5470  SCLogDebug("packet is TCP window update: %" PRIu64, PcapPacketCntGet(p));
5472  return 1;
5473  }
5474  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5475  return 0;
5476 }
5477 
5478 /**
5479  * Try to detect whether a packet is a valid FIN 4whs final ack.
5480  *
5481  */
5482 static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
5483 {
5484  TcpStream *stream = NULL, *ostream = NULL;
5485  uint32_t seq;
5486  uint32_t ack;
5487 
5488  if (p->flags & PKT_PSEUDO_STREAM_END)
5489  return 0;
5490  if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
5491  return 0;
5492  const TCPHdr *tcph = PacketGetTCP(p);
5493  if (tcph->th_flags != TH_ACK)
5494  return 0;
5495  if (p->payload_len != 0)
5496  return 0;
5497 
5498  if (PKT_IS_TOSERVER(p)) {
5499  stream = &ssn->client;
5500  ostream = &ssn->server;
5501  } else {
5502  stream = &ssn->server;
5503  ostream = &ssn->client;
5504  }
5505 
5506  seq = TCP_GET_RAW_SEQ(tcph);
5507  ack = TCP_GET_RAW_ACK(tcph);
5508 
5509  SCLogDebug("%" PRIu64 ", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
5510  PcapPacketCntGet(p), seq, ack, stream->next_seq, ostream->next_seq);
5511 
5512  if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
5513  return 1;
5514  }
5515  return 0;
5516 }
5517 
5518 /**
5519  * Try to detect packets doing bad window updates
5520  *
5521  * See bug 1238.
5522  *
5523  * Find packets that are unexpected, and shrink the window to the point
5524  * where the packets we do expect are rejected for being out of window.
5525  *
5526  * The logic we use here is:
5527  * - packet seq > next_seq
5528  * - packet ack > next_seq (packet acks unseen data)
5529  * - packet shrinks window more than it's own data size
5530  * - packet shrinks window more than the diff between it's ack and the
5531  * last_ack value
5532  *
5533  * Packets coming in after packet loss can look quite a bit like this.
5534  */
5535 static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
5536 {
5537  TcpStream *stream = NULL, *ostream = NULL;
5538  uint32_t seq;
5539  uint32_t ack;
5540  uint32_t pkt_win;
5541 
5542  if (p->flags & PKT_PSEUDO_STREAM_END)
5543  return 0;
5544 
5545  if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
5546  return 0;
5547 
5548  const TCPHdr *tcph = PacketGetTCP(p);
5549  if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5550  return 0;
5551 
5552  if (PKT_IS_TOSERVER(p)) {
5553  stream = &ssn->client;
5554  ostream = &ssn->server;
5555  } else {
5556  stream = &ssn->server;
5557  ostream = &ssn->client;
5558  }
5559 
5560  seq = TCP_GET_RAW_SEQ(tcph);
5561  ack = TCP_GET_RAW_ACK(tcph);
5562  pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5563 
5564  if (pkt_win < ostream->window) {
5565  uint32_t diff = ostream->window - pkt_win;
5566  if (diff > p->payload_len &&
5567  SEQ_GT(ack, ostream->next_seq) &&
5568  SEQ_GT(seq, stream->next_seq))
5569  {
5570  SCLogDebug("%" PRIu64 ", pkt_win %u, stream win %u, diff %u, dsize %u",
5571  PcapPacketCntGet(p), pkt_win, ostream->window, diff, p->payload_len);
5572  SCLogDebug("%" PRIu64 ", pkt_win %u, stream win %u", PcapPacketCntGet(p), pkt_win,
5573  ostream->window);
5574  SCLogDebug("%" PRIu64 ", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, "
5575  "ostream->next_win %u, diff %u (%u)",
5576  PcapPacketCntGet(p), seq, ack, ostream->next_seq, ostream->last_ack,
5577  ostream->next_win, ostream->next_seq - ostream->last_ack,
5578  stream->next_seq - stream->last_ack);
5579 
5580  /* get the expected window shrinking from looking at ack vs last_ack.
5581  * Observed a lot of just a little overrunning that value. So added some
5582  * margin that is still ok. To make sure this isn't a loophole to still
5583  * close the window, this is limited to windows above 1024. Both values
5584  * are rather arbitrary. */
5585  uint32_t adiff = ack - ostream->last_ack;
5586  if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
5587  ((pkt_win <= 1024) && (diff > adiff)))
5588  {
5589  SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
5590  "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
5591  SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
5593  return 1;
5594  }
5595  }
5596 
5597  }
5598  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5599  return 0;
5600 }
5601 
5602 /** \internal
5603  * \brief call packet handling function for 'state'
5604  * \param state current TCP state
5605  */
5606 static inline int StreamTcpStateDispatch(
5607  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state)
5608 {
5609  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5610 
5611  SCLogDebug("ssn: %p", ssn);
5612  switch (state) {
5613  case TCP_SYN_SENT:
5614  SCLogDebug("packet received on TCP_SYN_SENT state");
5615  if (StreamTcpPacketStateSynSent(tv, p, stt, ssn)) {
5616  return -1;
5617  }
5618  break;
5619  case TCP_SYN_RECV:
5620  SCLogDebug("packet received on TCP_SYN_RECV state");
5621  if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn)) {
5622  return -1;
5623  }
5624  break;
5625  case TCP_ESTABLISHED:
5626  SCLogDebug("packet received on TCP_ESTABLISHED state");
5627  if (StreamTcpPacketStateEstablished(tv, p, stt, ssn)) {
5628  return -1;
5629  }
5630  break;
5631  case TCP_FIN_WAIT1:
5632  SCLogDebug("packet received on TCP_FIN_WAIT1 state");
5633  if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn)) {
5634  return -1;
5635  }
5636  break;
5637  case TCP_FIN_WAIT2:
5638  SCLogDebug("packet received on TCP_FIN_WAIT2 state");
5639  if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn)) {
5640  return -1;
5641  }
5642  break;
5643  case TCP_CLOSING:
5644  SCLogDebug("packet received on TCP_CLOSING state");
5645  if (StreamTcpPacketStateClosing(tv, p, stt, ssn)) {
5646  return -1;
5647  }
5648  break;
5649  case TCP_CLOSE_WAIT:
5650  SCLogDebug("packet received on TCP_CLOSE_WAIT state");
5651  if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn)) {
5652  return -1;
5653  }
5654  break;
5655  case TCP_LAST_ACK:
5656  SCLogDebug("packet received on TCP_LAST_ACK state");
5657  if (StreamTcpPacketStateLastAck(tv, p, stt, ssn)) {
5658  return -1;
5659  }
5660  break;
5661  case TCP_TIME_WAIT:
5662  SCLogDebug("packet received on TCP_TIME_WAIT state");
5663  if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn)) {
5664  return -1;
5665  }
5666  break;
5667  case TCP_CLOSED:
5668  /* TCP session memory is not returned to pool until timeout. */
5669  SCLogDebug("packet received on closed state");
5670 
5671  if (StreamTcpPacketStateClosed(tv, p, stt, ssn)) {
5672  return -1;
5673  }
5674 
5675  break;
5676  default:
5677  SCLogDebug("packet received on default state");
5678  break;
5679  }
5680  return 0;
5681 }
5682 
5683 static inline void CheckThreadId(ThreadVars *tv, Packet *p, StreamTcpThread *stt)
5684 {
5685  const int idx = (!(PKT_IS_TOSERVER(p)));
5686 
5687  /* assign the thread id to the flow */
5688  if (likely(p->flow->thread_id[idx] != 0)) {
5689  if (unlikely((FlowThreadId)tv->id != p->flow->thread_id[idx])) {
5690  SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id[idx], tv->id);
5691  if (p->pkt_src == PKT_SRC_WIRE) {
5693  if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
5696  }
5697  }
5698  }
5699  }
5700 }
5701 
5702 /* flow is and stays locked */
5704  PacketQueueNoLock *pq)
5705 {
5706  SCEnter();
5707 
5709 
5710  SCLogDebug("pcap_cnt %" PRIu64, PcapPacketCntGet(p));
5711 
5713  const TCPHdr *tcph = PacketGetTCP(p);
5714 
5715  /* track TCP flags */
5716  if (ssn != NULL) {
5717  ssn->tcp_packet_flags |= tcph->th_flags;
5718  if (PKT_IS_TOSERVER(p))
5719  ssn->client.tcp_flags |= tcph->th_flags;
5720  else if (PKT_IS_TOCLIENT(p))
5721  ssn->server.tcp_flags |= tcph->th_flags;
5722 
5723  /* check if we need to unset the ASYNC flag */
5724  if (ssn->flags & STREAMTCP_FLAG_ASYNC &&
5725  ssn->client.tcp_flags != 0 &&
5726  ssn->server.tcp_flags != 0)
5727  {
5728  SCLogDebug("ssn %p: removing ASYNC flag as we have packets on both sides", ssn);
5730  }
5731  }
5732 
5733  /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */
5734  if (!(tcph->th_flags & TH_ACK) && TCP_GET_RAW_ACK(tcph) != 0) {
5736  }
5737 
5738  if ((tcph->th_flags & TH_URG) && StreamTcpInlineDropUrg()) {
5740  SCLogDebug("dropping urgent packet");
5741  SCReturnInt(0);
5742  }
5743 
5744  /* If we are on IPS mode, and got a drop action triggered from
5745  * the IP only module, or from a reassembled msg and/or from an
5746  * applayer detection, then drop the rest of the packets of the
5747  * same stream and avoid inspecting it any further */
5748  if (StreamTcpCheckFlowDrops(p) == 1) {
5750  SCLogDebug("flow triggered a drop rule");
5752  /* return the segments to the pool */
5754  SCReturnInt(0);
5755  }
5756 
5757  if (ssn == NULL || ssn->state == TCP_NONE) {
5758  if (StreamTcpPacketStateNone(tv, p, stt, ssn) == -1) {
5759  goto error;
5760  }
5761  ssn = (TcpSession *)p->flow->protoctx;
5762 
5763  if (ssn != NULL)
5764  SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto);
5765  } else {
5766  /* special case for PKT_PSEUDO_STREAM_END packets:
5767  * bypass the state handling and various packet checks,
5768  * we care about reassembly here. */
5769  if (p->flags & PKT_PSEUDO_STREAM_END) {
5770  if (PKT_IS_TOCLIENT(p)) {
5772  } else {
5774  }
5775  /* straight to 'skip' as we already handled reassembly */
5776  goto skip;
5777  }
5778 
5779  if (p->flow->flags & FLOW_WRONG_THREAD) {
5780  /* Stream and/or session in known bad condition. Block events
5781  * from being set. */
5783  }
5784 
5785  if (StreamTcpPacketIsKeepAlive(ssn, p) == 1) {
5786  goto skip;
5787  }
5788  if (StreamTcpPacketIsKeepAliveACK(ssn, p) == 1) {
5789  StreamTcpClearKeepAliveFlag(ssn, p);
5790  goto skip;
5791  }
5792  StreamTcpClearKeepAliveFlag(ssn, p);
5793 
5794  const bool is_zwp_ack = StreamTcpPacketIsZeroWindowProbeAck(ssn, p);
5795  if (PKT_IS_TOCLIENT(p)) {
5797  } else {
5799  }
5800  if (is_zwp_ack) {
5802  goto skip;
5803  }
5804 
5805  if (StreamTcpPacketIsDupAck(ssn, p)) {
5807  // TODO see if we can skip work on these
5808  }
5809 
5810  /* if packet is not a valid window update, check if it is perhaps
5811  * a bad window update that we should ignore (and alert on) */
5812  if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) {
5813  if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0) {
5814  if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
5815  goto skip;
5816  if (StreamTcpPacketIsOutdatedAck(ssn, p))
5817  goto skip;
5818  }
5819  }
5820 
5821  int ret = StreamTcpPacketIsSpuriousRetransmission(ssn, p);
5822  if (ret > 0) {
5824  /* skip packet if fully before base_seq */
5825  if (ret == 2)
5826  goto skip;
5827  }
5828 
5829  /* handle the per 'state' logic */
5830  if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->state) < 0)
5831  goto error;
5832 
5833  skip:
5834  StreamTcpPacketCheckPostRst(ssn, p);
5835  }
5836 
5837  if (ssn != NULL) {
5838  /* recalc the csum on the packet if it was modified */
5839  if (p->flags & PKT_STREAM_MODIFIED) {
5841  }
5842 
5843  /* if ssn was set in this run, reflect TCP state on the packet */
5844  if (ssn->state >= TCP_ESTABLISHED) {
5845  p->flags |= PKT_STREAM_EST;
5846  }
5847 
5848  /* check for conditions that may make us not want to log this packet */
5849 
5850  /* streams that hit depth */
5853  {
5854  /* we can call bypass callback, if enabled */
5855  if (StreamTcpBypassEnabled()) {
5857  }
5858  }
5859 
5862  {
5864  }
5865 
5866  /* encrypted packets */
5869  {
5871  }
5872 
5873  if (ssn->flags & STREAMTCP_FLAG_BYPASS) {
5875  } else if (g_detect_disabled &&
5879  {
5880  /* if stream is dead and we have no detect engine at all, bypass. */
5881  SCLogDebug("bypass as stream is dead and we have no rules");
5883  }
5884  }
5885 
5886  SCReturnInt(0);
5887 
5888 error:
5889  /* recalc the csum on the packet if it was modified */
5890  if (p->flags & PKT_STREAM_MODIFIED) {
5892  }
5893 
5894  if (StreamTcpInlineDropInvalid()) {
5895  /* disable payload inspection as we're dropping this packet
5896  * anyway. Doesn't disable all detection, so we can still
5897  * match on the stream event that was set. */
5898  DecodeSetNoPayloadInspectionFlag(p);
5900  }
5901  SCReturnInt(-1);
5902 }
5903 
5904 /**
5905  * \brief Function to validate the checksum of the received packet. If the
5906  * checksum is invalid, packet will be dropped, as the end system will
5907  * also drop the packet.
5908  *
5909  * \param p Packet of which checksum has to be validated
5910  * \retval 1 if the checksum is valid, otherwise 0
5911  */
5912 static inline int StreamTcpValidateChecksum(Packet *p)
5913 {
5914  int ret = 1;
5915 
5916  if (p->flags & PKT_IGNORE_CHECKSUM)
5917  return ret;
5918 
5919  if (!p->l4.csum_set) {
5920  const TCPHdr *tcph = PacketGetTCP(p);
5921  if (PacketIsIPv4(p)) {
5922  const IPV4Hdr *ip4h = PacketGetIPv4(p);
5923  p->l4.csum = TCPChecksum(ip4h->s_ip_addrs, (uint16_t *)tcph,
5924  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5925  p->l4.csum_set = true;
5926  } else if (PacketIsIPv6(p)) {
5927  const IPV6Hdr *ip6h = PacketGetIPv6(p);
5928  p->l4.csum = TCPV6Checksum(ip6h->s_ip6_addrs, (uint16_t *)tcph,
5929  (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5930  p->l4.csum_set = true;
5931  }
5932  }
5933 
5934  if (p->l4.csum != 0) {
5935  ret = 0;
5937  if (dev) {
5938  (void)SC_ATOMIC_ADD(dev->invalid_checksums, 1);
5939  } else if (PcapPacketCntGet(p)) {
5941  }
5942  }
5943 
5944  return ret;
5945 }
5946 
5947 /** \internal
5948  * \brief check if a packet is a valid stream started
5949  * \retval bool true/false */
5950 static int TcpSessionPacketIsStreamStarter(const Packet *p)
5951 {
5952  const TCPHdr *tcph = PacketGetTCP(p);
5953  if (tcph->th_flags & (TH_RST | TH_FIN)) {
5954  return 0;
5955  }
5956 
5957  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5958  SCLogDebug("packet %" PRIu64 " is a stream starter: %02x", PcapPacketCntGet(p),
5959  tcph->th_flags);
5960  return 1;
5961  }
5962 
5964  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5965  SCLogDebug("packet %" PRIu64 " is a midstream stream starter: %02x",
5966  PcapPacketCntGet(p), tcph->th_flags);
5967  return 1;
5968  }
5969  }
5970  return 0;
5971 }
5972 
5973 /** \internal
5974  * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused
5975  * \retval bool true yes reuse, false no keep tracking old ssn */
5976 static bool TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn)
5977 {
5978  const TCPHdr *tcph = PacketGetTCP(p);
5979  if (FlowGetPacketDirection(f, p) == TOSERVER) {
5980  if (ssn == NULL) {
5981  /* most likely a flow that was picked up after the 3whs, or a flow that
5982  * does not have a session due to memcap issues. */
5983  SCLogDebug("stream starter packet %" PRIu64 ", ssn %p null. Reuse.",
5984  PcapPacketCntGet(p), ssn);
5985  return true;
5986  }
5988  SCLogDebug("stream starter packet %" PRIu64
5989  ", ssn %p. STREAMTCP_FLAG_TFO_DATA_IGNORED set. Reuse.",
5990  PcapPacketCntGet(p), ssn);
5991  return true;
5992  }
5993  if (SEQ_EQ(ssn->client.isn, TCP_GET_RAW_SEQ(tcph))) {
5994  SCLogDebug("stream starter packet %" PRIu64
5995  ", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.",
5996  PcapPacketCntGet(p), ssn);
5997  return false;
5998  }
5999  if (ssn->state >= TCP_LAST_ACK) {
6000  SCLogDebug("stream starter packet %" PRIu64
6001  ", ssn %p state >= TCP_LAST_ACK (%u). Reuse.",
6003  return true;
6004  } else if (ssn->state == TCP_NONE) {
6005  SCLogDebug("stream starter packet %" PRIu64 ", ssn %p state == TCP_NONE (%u). Reuse.",
6007  return true;
6008  } else { // < TCP_LAST_ACK
6009  SCLogDebug("stream starter packet %" PRIu64
6010  ", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.",
6012  return false;
6013  }
6014 
6015  } else {
6016  if (ssn == NULL) {
6017  SCLogDebug("stream starter packet %" PRIu64 ", ssn %p null. Reuse.",
6018  PcapPacketCntGet(p), ssn);
6019  return true;
6020  }
6021  if (ssn->state >= TCP_LAST_ACK) {
6022  SCLogDebug("stream starter packet %" PRIu64
6023  ", ssn %p state >= TCP_LAST_ACK (%u). Reuse.",
6025  return true;
6026  } else if (ssn->state == TCP_NONE) {
6027  SCLogDebug("stream starter packet %" PRIu64 ", ssn %p state == TCP_NONE (%u). Reuse.",
6029  return true;
6030  } else { // < TCP_LAST_ACK
6031  SCLogDebug("stream starter packet %" PRIu64
6032  ", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.",
6034  return false;
6035  }
6036  }
6037 
6038  SCLogDebug("default: how did we get here?");
6039  return false;
6040 }
6041 
6042 /** \internal
6043  * \brief check if ssn is done enough for reuse by syn/ack
6044  * \note should only be called if midstream is enabled
6045  */
6046 static bool TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn)
6047 {
6048  const TCPHdr *tcph = PacketGetTCP(p);
6049  if (FlowGetPacketDirection(f, p) == TOCLIENT) {
6050  if (ssn == NULL) {
6051  SCLogDebug("stream starter packet %" PRIu64 ", ssn %p null. No reuse.",
6052  PcapPacketCntGet(p), ssn);
6053  return false;
6054  }
6055  if (SEQ_EQ(ssn->server.isn, TCP_GET_RAW_SEQ(tcph))) {
6056  SCLogDebug("stream starter packet %" PRIu64
6057  ", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.",
6058  PcapPacketCntGet(p), ssn);
6059  return false;
6060  }
6061  if (ssn->state >= TCP_LAST_ACK) {
6062  SCLogDebug("stream starter packet %" PRIu64
6063  ", ssn %p state >= TCP_LAST_ACK (%u). Reuse.",
6065  return true;
6066  } else if (ssn->state == TCP_NONE) {
6067  SCLogDebug("stream starter packet %" PRIu64 ", ssn %p state == TCP_NONE (%u). Reuse.",
6069  return true;
6070  } else { // < TCP_LAST_ACK
6071  SCLogDebug("stream starter packet %" PRIu64
6072  ", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.",
6074  return false;
6075  }
6076 
6077  } else {
6078  if (ssn == NULL) {
6079  SCLogDebug("stream starter packet %" PRIu64 ", ssn %p null. Reuse.",
6080  PcapPacketCntGet(p), ssn);
6081  return true;
6082  }
6083  if (ssn->state >= TCP_LAST_ACK) {
6084  SCLogDebug("stream starter packet %" PRIu64
6085  ", ssn %p state >= TCP_LAST_ACK (%u). Reuse.",
6087  return true;
6088  } else if (ssn->state == TCP_NONE) {
6089  SCLogDebug("stream starter packet %" PRIu64 ", ssn %p state == TCP_NONE (%u). Reuse.",
6091  return true;
6092  } else { // < TCP_LAST_ACK
6093  SCLogDebug("stream starter packet %" PRIu64
6094  ", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.",
6096  return false;
6097  }
6098  }
6099 
6100  SCLogDebug("default: how did we get here?");
6101  return false;
6102 }
6103 
6104 /** \brief Check if SSN is done enough for reuse
6105  *
6106  * Reuse means a new TCP session reuses the tuple (flow in suri)
6107  *
6108  * \retval bool true if ssn can be reused, false if not */
6109 static bool TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn)
6110 {
6111  const TCPHdr *tcph = PacketGetTCP(p);
6112  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
6113  return TcpSessionReuseDoneEnoughSyn(p, f, ssn);
6114  }
6115 
6117  if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
6118  return TcpSessionReuseDoneEnoughSynAck(p, f, ssn);
6119  }
6120  }
6121 
6122  return false;
6123 }
6124 
6125 bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
6126 {
6127  if (p->proto == IPPROTO_TCP && PacketIsTCP(p)) {
6128  if (TcpSessionPacketIsStreamStarter(p) == 1) {
6129  if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) {
6130  return true;
6131  }
6132  }
6133  }
6134  return false;
6135 }
6136 
6138 {
6139  DEBUG_VALIDATE_BUG_ON(p->flow == NULL);
6140  if (unlikely(p->flow == NULL)) {
6141  return TM_ECODE_OK;
6142  }
6143 
6144  StreamTcpThread *stt = (StreamTcpThread *)data;
6145 
6146  SCLogDebug("pcap_cnt %" PRIu64 " direction %s pkt_src %s", PcapPacketCntGet(p),
6147  p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
6148  : "noflow",
6150 
6151 #ifdef QA_SIMULATION
6152  t_pcapcnt = PcapPacketCntGet(p);
6153 #endif
6154 
6155  if (!(PacketIsTCP(p))) {
6156  return TM_ECODE_OK;
6157  }
6158 
6159  CheckThreadId(tv, p, stt);
6160 
6161  /* only TCP packets with a flow from here */
6162 
6163  if (!(p->flags & PKT_PSEUDO_STREAM_END)) {
6165  if (StreamTcpValidateChecksum(p) == 0) {
6167  return TM_ECODE_OK;
6168  }
6169  }
6170  }
6172 
6173  (void)StreamTcpPacket(tv, p, stt, pq);
6174 
6175  return TM_ECODE_OK;
6176 }
6177 
6178 TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
6179 {
6180  SCEnter();
6181  StreamTcpThread *stt = SCCalloc(1, sizeof(StreamTcpThread));
6182  if (unlikely(stt == NULL))
6184  stt->ssn_pool_id = -1;
6186 
6187  *data = (void *)stt;
6188 
6189  stt->counter_tcp_active_sessions = StatsRegisterCounter("tcp.active_sessions", &tv->stats);
6190  stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", &tv->stats);
6191  stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", &tv->stats);
6192  stt->counter_tcp_ssn_from_cache = StatsRegisterCounter("tcp.ssn_from_cache", &tv->stats);
6193  stt->counter_tcp_ssn_from_pool = StatsRegisterCounter("tcp.ssn_from_pool", &tv->stats);
6195  stream_config.ssn_memcap_policy, "exception_policy.tcp.ssn_memcap.",
6196  IsStreamTcpSessionMemcapExceptionPolicyStatsValid);
6197 
6198  stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", &tv->stats);
6199  stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", &tv->stats);
6200  stt->counter_tcp_midstream_pickups = StatsRegisterCounter("tcp.midstream_pickups", &tv->stats);
6201  if (stream_config.midstream) {
6204  "exception_policy.tcp.midstream.", IsMidstreamExceptionPolicyStatsValid);
6205  } else {
6208  "exception_policy.tcp.midstream.", IsMidstreamExceptionPolicyStatsValid);
6209  }
6210 
6211  stt->counter_tcp_wrong_thread = StatsRegisterCounter("tcp.pkt_on_wrong_thread", &tv->stats);
6212  stt->counter_tcp_ack_unseen_data = StatsRegisterCounter("tcp.ack_unseen_data", &tv->stats);
6213 
6214  /* init reassembly ctx */
6216  if (stt->ra_ctx == NULL)
6218 
6220  StatsRegisterCounter("tcp.segment_memcap_drop", &tv->stats);
6221 
6224  "exception_policy.tcp.reassembly.", IsReassemblyMemcapExceptionPolicyStatsValid);
6225 
6227  StatsRegisterCounter("tcp.segment_from_cache", &tv->stats);
6229  StatsRegisterCounter("tcp.segment_from_pool", &tv->stats);
6231  StatsRegisterCounter("tcp.stream_depth_reached", &tv->stats);
6232  stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", &tv->stats);
6233  stt->ra_ctx->counter_tcp_reass_overlap = StatsRegisterCounter("tcp.overlap", &tv->stats);
6235  StatsRegisterCounter("tcp.overlap_diff_data", &tv->stats);
6236 
6238  StatsRegisterCounter("tcp.insert_data_normal_fail", &tv->stats);
6240  StatsRegisterCounter("tcp.insert_data_overlap_fail", &tv->stats);
6241  stt->ra_ctx->counter_tcp_urgent_oob = StatsRegisterCounter("tcp.urgent_oob_data", &tv->stats);
6242 
6243  SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p",
6244  stt, stt->ra_ctx);
6245 
6246  SCMutexLock(&ssn_pool_mutex);
6247  if (ssn_pool == NULL) {
6248  ssn_pool = PoolThreadInit(1, /* thread */
6249  0, /* unlimited */
6250  stream_config.prealloc_sessions, sizeof(TcpSession), StreamTcpSessionPoolAlloc,
6251  StreamTcpSessionPoolInit, StreamTcpSessionPoolCleanup);
6252  stt->ssn_pool_id = 0;
6253  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6254  } else {
6255  /* grow ssn_pool until we have a element for our thread id */
6257  SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6258  }
6259  SCMutexUnlock(&ssn_pool_mutex);
6260  if (stt->ssn_pool_id < 0 || ssn_pool == NULL) {
6261  SCLogError("failed to setup/expand stream session pool. Expand stream.memcap?");
6263  }
6264 
6266 }
6267 
6269 {
6270  SCEnter();
6271  StreamTcpThread *stt = (StreamTcpThread *)data;
6272  if (stt == NULL) {
6273  return TM_ECODE_OK;
6274  }
6275 
6276  /* XXX */
6277 
6278  /* free reassembly ctx */
6280 
6281  /* clear memory */
6282  memset(stt, 0, sizeof(StreamTcpThread));
6283 
6284  SCFree(stt);
6286 }
6287 
6288 /**
6289  * \brief Function to check the validity of the RST packets based on the
6290  * target OS of the given packet.
6291  *
6292  * \param ssn TCP session to which the given packet belongs
6293  * \param p Packet which has to be checked for its validity
6294  *
6295  * \retval 0 unacceptable RST
6296  * \retval 1 acceptable RST
6297  *
6298  * WebSense sends RST packets that are:
6299  * - RST flag, win 0, ack 0, seq = nextseq
6300  *
6301  */
6302 
6303 static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
6304 {
6305  uint8_t os_policy;
6306  const TCPHdr *tcph = PacketGetTCP(p);
6307  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6308 
6310  SCReturnInt(1);
6311  }
6312 
6314  if (!StreamTcpValidateTimestamp(ssn, p)) {
6315  SCReturnInt(0);
6316  }
6317  }
6318 
6319  /* RST with data, it's complicated:
6320 
6321  4.2.2.12 RST Segment: RFC-793 Section 3.4
6322 
6323  A TCP SHOULD allow a received RST segment to include data.
6324 
6325  DISCUSSION
6326  It has been suggested that a RST segment could contain
6327  ASCII text that encoded and explained the cause of the
6328  RST. No standard has yet been established for such
6329  data.
6330  */
6331  if (p->payload_len)
6333 
6334  /* Set up the os_policy to be used in validating the RST packets based on
6335  target system */
6336  if (PKT_IS_TOSERVER(p)) {
6337  if (ssn->server.os_policy == 0)
6339 
6340  os_policy = ssn->server.os_policy;
6341 
6342  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6343  StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
6344  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6346  SCReturnInt(0);
6347  }
6348 
6349  } else {
6350  if (ssn->client.os_policy == 0)
6352 
6353  os_policy = ssn->client.os_policy;
6354 
6355  if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6356  StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
6357  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6359  SCReturnInt(0);
6360  }
6361  }
6362 
6363  /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
6364  * validate these (requires key that is set/transferred out of band), we can't know
6365  * if the RST will be accepted or rejected by the end host. We accept it, but keep
6366  * tracking if the sender of it ignores it, which would be a sign of injection. */
6368  TcpStream *receiver_stream;
6369  if (PKT_IS_TOSERVER(p)) {
6370  receiver_stream = &ssn->server;
6371  } else {
6372  receiver_stream = &ssn->client;
6373  }
6374  SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
6375  receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
6376  }
6377 
6378  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
6379  if (PKT_IS_TOSERVER(p)) {
6380  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6381  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6382  return 1;
6383  }
6384  } else {
6385  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6386  SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6387  return 1;
6388  }
6389  }
6390  SCLogDebug("ssn %p: ASYNC reject RST", ssn);
6391  return 0;
6392  }
6393 
6394  switch (os_policy) {
6395  case OS_POLICY_HPUX11:
6396  if(PKT_IS_TOSERVER(p)){
6397  if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6398  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6399  return 1;
6400  } else {
6401  SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " "
6402  "and server SEQ: %" PRIu32 "",
6403  seq, ssn->client.next_seq);
6404  return 0;
6405  }
6406  } else { /* implied to client */
6407  if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6408  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6409  return 1;
6410  } else {
6411  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6412  "and client SEQ: %" PRIu32 "",
6413  seq, ssn->server.next_seq);
6414  return 0;
6415  }
6416  }
6417  break;
6418  case OS_POLICY_OLD_LINUX:
6419  case OS_POLICY_LINUX:
6420  case OS_POLICY_SOLARIS:
6421  if(PKT_IS_TOSERVER(p)){
6422  if (SEQ_GEQ((seq + p->payload_len),
6423  ssn->client.last_ack)) { /*window base is needed !!*/
6424  if (SEQ_LT(seq, (ssn->client.next_seq + ssn->client.window))) {
6425  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6426  return 1;
6427  }
6428  } else {
6429  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6430  " server SEQ: %" PRIu32 "",
6431  seq, ssn->client.next_seq);
6432  return 0;
6433  }
6434  } else { /* implied to client */
6435  if (SEQ_GEQ((seq + p->payload_len),
6436  ssn->server.last_ack)) { /*window base is needed !!*/
6437  if (SEQ_LT(seq, (ssn->server.next_seq + ssn->server.window))) {
6438  SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6439  return 1;
6440  }
6441  } else {
6442  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6443  " client SEQ: %" PRIu32 "",
6444  seq, ssn->server.next_seq);
6445  return 0;
6446  }
6447  }
6448  break;
6449  default:
6450  case OS_POLICY_BSD:
6451  case OS_POLICY_FIRST:
6452  case OS_POLICY_HPUX10:
6453  case OS_POLICY_IRIX:
6454  case OS_POLICY_MACOS:
6455  case OS_POLICY_LAST:
6456  case OS_POLICY_WINDOWS:
6457  case OS_POLICY_WINDOWS2K3:
6458  case OS_POLICY_VISTA:
6459  if(PKT_IS_TOSERVER(p)) {
6460  if (SEQ_EQ(seq, ssn->client.next_seq)) {
6461  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6462  return 1;
6463  } else {
6464  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6465  "and server SEQ: %" PRIu32 "",
6466  seq, ssn->client.next_seq);
6467  return 0;
6468  }
6469  } else { /* implied to client */
6470  if (SEQ_EQ(seq, ssn->server.next_seq)) {
6471  SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u", seq,
6472  ssn->server.next_seq);
6473  return 1;
6474  } else {
6475  SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6476  " client SEQ: %" PRIu32 "",
6477  seq, ssn->server.next_seq);
6478  return 0;
6479  }
6480  }
6481  break;
6482  }
6483  return 0;
6484 }
6485 
6486 /**
6487  * \brief Function to check the validity of the received timestamp based on
6488  * the target OS of the given stream.
6489  *
6490  * It's passive except for:
6491  * 1. it sets the os policy on the stream if necessary
6492  * 2. it sets an event in the packet if necessary
6493  *
6494  * \param ssn TCP session to which the given packet belongs
6495  * \param p Packet which has to be checked for its validity
6496  *
6497  * \retval 1 if the timestamp is valid
6498  * \retval 0 if the timestamp is invalid
6499  */
6500 static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p)
6501 {
6502  SCEnter();
6503 
6504  TcpStream *sender_stream;
6505  TcpStream *receiver_stream;
6506  uint8_t ret = 1;
6507  uint8_t check_ts = 1;
6508  const TCPHdr *tcph = PacketGetTCP(p);
6509  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6510 
6511  if (PKT_IS_TOSERVER(p)) {
6512  sender_stream = &ssn->client;
6513  receiver_stream = &ssn->server;
6514  } else {
6515  sender_stream = &ssn->server;
6516  receiver_stream = &ssn->client;
6517  }
6518 
6519  /* Set up the os_policy to be used in validating the timestamps based on
6520  the target system */
6521  if (receiver_stream->os_policy == 0) {
6522  StreamTcpSetOSPolicy(receiver_stream, p);
6523  }
6524 
6525  if (TCP_HAS_TS(p)) {
6526  uint32_t ts = TCP_GET_TSVAL(p);
6527  uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
6528  uint32_t last_ts = sender_stream->last_ts;
6529 
6530  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6531  /* The 3whs used the timestamp with 0 value. */
6532  switch (receiver_stream->os_policy) {
6533  case OS_POLICY_LINUX:
6534  case OS_POLICY_WINDOWS2K3:
6535  /* Linux and windows 2003 does not allow the use of 0 as
6536  * timestamp in the 3whs. */
6537  check_ts = 0;
6538  break;
6539 
6540  case OS_POLICY_OLD_LINUX:
6541  case OS_POLICY_WINDOWS:
6542  case OS_POLICY_VISTA:
6543  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6544  last_ts = ts;
6545  check_ts = 0; /*next packet will be checked for validity
6546  and stream TS has been updated with this
6547  one.*/
6548  }
6549  break;
6550  }
6551  }
6552 
6553  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6554  /* HPUX11 ignores the timestamp of out of order packets */
6555  if (!SEQ_EQ(sender_stream->next_seq, seq))
6556  check_ts = 0;
6557  }
6558 
6559  if (ts == 0) {
6560  switch (receiver_stream->os_policy) {
6561  case OS_POLICY_OLD_LINUX:
6562  case OS_POLICY_WINDOWS:
6563  case OS_POLICY_WINDOWS2K3:
6564  case OS_POLICY_VISTA:
6565  case OS_POLICY_SOLARIS:
6566  /* Old Linux and windows allowed packet with 0 timestamp. */
6567  break;
6568  default:
6569  /* other OS simply drop the packet with 0 timestamp, when
6570  * 3whs has valid timestamp*/
6571  goto invalid;
6572  }
6573  }
6574 
6575  if (check_ts) {
6576  int32_t result = 0;
6577 
6578  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts);
6579 
6580  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6581  /* Linux accepts TS which are off by one.*/
6582  result = (int32_t) ((ts - last_ts) + 1);
6583  } else {
6584  result = (int32_t) (ts - last_ts);
6585  }
6586 
6587  SCLogDebug("result %" PRIi32 ", p->ts(secs) %" PRIuMAX "", result,
6588  (uintmax_t)SCTIME_SECS(p->ts));
6589 
6590  if (last_pkt_ts == 0 &&
6592  {
6593  last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6594  }
6595 
6596  if (result < 0) {
6597  SCLogDebug("timestamp is not valid last_ts "
6598  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6599  "%" PRId32 "", last_ts, ts, result);
6600  /* candidate for rejection */
6601  ret = 0;
6602  } else if ((sender_stream->last_ts != 0) &&
6603  (((uint32_t)SCTIME_SECS(p->ts)) > last_pkt_ts + PAWS_24DAYS)) {
6604  SCLogDebug("packet is not valid last_pkt_ts "
6605  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6606  last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6607  /* candidate for rejection */
6608  ret = 0;
6609  }
6610 
6611  if (ret == 0) {
6612  /* if the timestamp of packet is not valid then, check if the
6613  * current stream timestamp is not so old. if so then we need to
6614  * accept the packet and update the stream->last_ts (RFC 1323)*/
6615  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6616  (((uint32_t)SCTIME_SECS(p->ts) > (last_pkt_ts + PAWS_24DAYS)))) {
6617  SCLogDebug("timestamp considered valid anyway");
6618  } else {
6619  goto invalid;
6620  }
6621  }
6622  }
6623  }
6624 
6625  SCReturnInt(1);
6626 
6627 invalid:
6629  SCReturnInt(0);
6630 }
6631 
6632 /**
6633  * \brief Function to check the validity of the received timestamp based on
6634  * the target OS of the given stream and update the session.
6635  *
6636  * \param ssn TCP session to which the given packet belongs
6637  * \param p Packet which has to be checked for its validity
6638  *
6639  * \retval 1 if the timestamp is valid
6640  * \retval 0 if the timestamp is invalid
6641  */
6642 static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p)
6643 {
6644  SCEnter();
6645 
6646  TcpStream *sender_stream;
6647  TcpStream *receiver_stream;
6648  uint8_t ret = 1;
6649  uint8_t check_ts = 1;
6650  const TCPHdr *tcph = PacketGetTCP(p);
6651  const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6652 
6653  if (PKT_IS_TOSERVER(p)) {
6654  sender_stream = &ssn->client;
6655  receiver_stream = &ssn->server;
6656  } else {
6657  sender_stream = &ssn->server;
6658  receiver_stream = &ssn->client;
6659  }
6660 
6661  /* Set up the os_policy to be used in validating the timestamps based on
6662  the target system */
6663  if (receiver_stream->os_policy == 0) {
6664  StreamTcpSetOSPolicy(receiver_stream, p);
6665  }
6666 
6667  if (TCP_HAS_TS(p)) {
6668  uint32_t ts = TCP_GET_TSVAL(p);
6669 
6670  if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6671  /* The 3whs used the timestamp with 0 value. */
6672  switch (receiver_stream->os_policy) {
6673  case OS_POLICY_LINUX:
6674  case OS_POLICY_WINDOWS2K3:
6675  /* Linux and windows 2003 does not allow the use of 0 as
6676  * timestamp in the 3whs. */
6678  check_ts = 0;
6679  break;
6680 
6681  case OS_POLICY_OLD_LINUX:
6682  case OS_POLICY_WINDOWS:
6683  case OS_POLICY_VISTA:
6684  sender_stream->flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
6685  if (SEQ_EQ(sender_stream->next_seq, seq)) {
6686  sender_stream->last_ts = ts;
6687  check_ts = 0; /*next packet will be checked for validity
6688  and stream TS has been updated with this
6689  one.*/
6690  }
6691  break;
6692  default:
6693  break;
6694  }
6695  }
6696 
6697  if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6698  /*HPUX11 ignores the timestamp of out of order packets*/
6699  if (!SEQ_EQ(sender_stream->next_seq, seq))
6700  check_ts = 0;
6701  }
6702 
6703  if (ts == 0) {
6704  switch (receiver_stream->os_policy) {
6705  case OS_POLICY_OLD_LINUX:
6706  case OS_POLICY_WINDOWS:
6707  case OS_POLICY_WINDOWS2K3:
6708  case OS_POLICY_VISTA:
6709  case OS_POLICY_SOLARIS:
6710  /* Old Linux and windows allowed packet with 0 timestamp. */
6711  break;
6712  default:
6713  /* other OS simply drop the packet with 0 timestamp, when
6714  * 3whs has valid timestamp*/
6715  goto invalid;
6716  }
6717  }
6718 
6719  if (check_ts) {
6720  int32_t result = 0;
6721 
6722  SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts);
6723 
6724  if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6725  /* Linux accepts TS which are off by one.*/
6726  result = (int32_t) ((ts - sender_stream->last_ts) + 1);
6727  } else {
6728  result = (int32_t) (ts - sender_stream->last_ts);
6729  }
6730 
6731  SCLogDebug("result %" PRIi32 ", p->ts(sec) %" PRIuMAX "", result,
6732  (uintmax_t)SCTIME_SECS(p->ts));
6733 
6734  if (sender_stream->last_pkt_ts == 0 &&
6736  {
6737  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6738  }
6739 
6740  if (result < 0) {
6741  SCLogDebug("timestamp is not valid sender_stream->last_ts "
6742  "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6743  "%" PRId32 "", sender_stream->last_ts, ts, result);
6744  /* candidate for rejection */
6745  ret = 0;
6746  } else if ((sender_stream->last_ts != 0) &&
6747  (((uint32_t)SCTIME_SECS(p->ts)) >
6748  sender_stream->last_pkt_ts + PAWS_24DAYS)) {
6749  SCLogDebug("packet is not valid sender_stream->last_pkt_ts "
6750  "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6751  sender_stream->last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6752  /* candidate for rejection */
6753  ret = 0;
6754  }
6755 
6756  if (ret == 1) {
6757  /* Update the timestamp and last seen packet time for this
6758  * stream */
6759  if (SEQ_EQ(sender_stream->next_seq, seq))
6760  sender_stream->last_ts = ts;
6761 
6762  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6763 
6764  } else if (ret == 0) {
6765  /* if the timestamp of packet is not valid then, check if the
6766  * current stream timestamp is not so old. if so then we need to
6767  * accept the packet and update the stream->last_ts (RFC 1323)*/
6768  if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6769  (((uint32_t)SCTIME_SECS(p->ts) >
6770  (sender_stream->last_pkt_ts + PAWS_24DAYS)))) {
6771  sender_stream->last_ts = ts;
6772  sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6773 
6774  SCLogDebug("timestamp considered valid anyway");
6775  } else {
6776  goto invalid;
6777  }
6778  }
6779  }
6780  } else {
6781  /* Solaris stops using timestamps if a packet is received
6782  without a timestamp and timestamps were used on that stream. */
6783  if (receiver_stream->os_policy == OS_POLICY_SOLARIS)
6785  }
6786 
6787  SCReturnInt(1);
6788 
6789 invalid:
6791  SCReturnInt(0);
6792 }
6793 
6794 /**
6795  * \brief Function to test the received ACK values against the stream window
6796  * and previous ack value. ACK values should be higher than previous
6797  * ACK value and less than the next_win value.
6798  *
6799  * \param ssn TcpSession for state access
6800  * \param stream TcpStream of which last_ack needs to be tested
6801  * \param p Packet which is used to test the last_ack
6802  *
6803  * \retval 0 ACK is valid, last_ack is updated if ACK was higher
6804  * \retval -1 ACK is invalid
6805  */
6806 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p)
6807 {
6808  SCEnter();
6809 
6810  const TCPHdr *tcph = PacketGetTCP(p);
6811  const uint32_t ack = TCP_GET_RAW_ACK(tcph);
6812 
6813  if (!(tcph->th_flags & TH_ACK))
6814  SCReturnInt(0);
6815 
6816  /* fast track */
6817  if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win))
6818  {
6819  SCLogDebug("ssn %p: ACK %u in bounds > %u <= %u", ssn, ack, stream->last_ack,
6820  stream->next_win);
6821  SCReturnInt(0);
6822  }
6823  /* fast track */
6824  else if (SEQ_EQ(ack, stream->last_ack)) {
6825  SCLogDebug("ssn %p: pkt ACK %" PRIu32 " == stream last ACK %" PRIu32, ssn, ack,
6826  stream->last_ack);
6827  SCReturnInt(0);
6828  }
6829 
6830  /* exception handling */
6831  if (SEQ_LT(ack, stream->last_ack)) {
6832  SCLogDebug("pkt ACK %" PRIu32 " < stream last ACK %" PRIu32, ack, stream->last_ack);
6833 
6834  /* This is an attempt to get a 'left edge' value that we can check against.
6835  * It doesn't work when the window is 0, need to think of a better way. */
6836 
6837  if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) {
6838  SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window "
6839  "%"PRIu32" = %"PRIu32, ack, stream->last_ack,
6840  stream->window, stream->last_ack - stream->window);
6841  goto invalid;
6842  }
6843 
6844  SCReturnInt(0);
6845  }
6846 
6847  /* no further checks possible for ASYNC */
6848  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
6849  SCReturnInt(0);
6850  }
6851 
6852  if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) {
6853  SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win);
6854  goto invalid;
6855  /* a toclient RST as a response to SYN, next_win is 0, ack will be isn+1, just like
6856  * the syn ack */
6857  } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && tcph->th_flags & TH_RST &&
6858  SEQ_EQ(ack, stream->isn + 1)) {
6859  SCReturnInt(0);
6860  }
6861 
6862  SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32
6863  " next_win %"PRIu32, ack, stream->last_ack, stream->next_win);
6864 invalid:
6866  SCReturnInt(-1);
6867 }
6868 
6869 /** \brief update reassembly progress
6870 
6871  * \param ssn TCP Session
6872  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6873  */
6875  const uint32_t progress)
6876 {
6877  if (direction) {
6878  ssn->server.app_progress_rel += progress;
6879  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->server));
6880  } else {
6881  ssn->client.app_progress_rel += progress;
6882  SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->client));
6883  }
6884 }
6885 
6886 /** \brief disable reassembly
6887 
6888  * Disable app layer and set raw inspect to no longer accept new data.
6889  * Stream engine will then fully disable raw after last inspection.
6890  *
6891  * \param ssn TCP Session to set the flag in
6892  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6893  */
6895 {
6898 }
6899 
6900 /** \brief Set the No reassembly flag for the given direction in given TCP
6901  * session.
6902  *
6903  * \param ssn TCP Session to set the flag in
6904  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6905  */
6907 {
6910 }
6911 
6912 /** \brief enable bypass
6913  *
6914  * \param ssn TCP Session to set the flag in
6915  * \param direction direction to set the flag in: 0 toserver, 1 toclient
6916  */
6918 {
6920 }
6921 
6922 /** \brief Create a pseudo packet injected into the engine to signal the
6923  * opposing direction of this stream trigger detection/logging.
6924  *
6925  * \param parent real packet
6926  * \param pq packet queue to store the new pseudo packet in
6927  * \param dir 0 ts 1 tc
6928  */
6929 static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv,
6930  StreamTcpThread *stt, Packet *parent,
6931  TcpSession *ssn, PacketQueueNoLock *pq, int dir)
6932 {
6933  SCEnter();
6934  Flow *f = parent->flow;
6935  TCPHdr *tcph = NULL;
6936 
6937  if (parent->flags & PKT_PSEUDO_DETECTLOG_FLUSH) {
6938  SCReturn;
6939  }
6940  if ((f->flags & (FLOW_IPV4 | FLOW_IPV6)) == 0) {
6941  SCReturn;
6942  }
6943 
6944  Packet *np = PacketPoolGetPacket();
6945  if (np == NULL) {
6946  SCReturn;
6947  }
6949 
6950  np->tenant_id = f->tenant_id;
6951  np->datalink = DLT_RAW;
6952  np->proto = IPPROTO_TCP;
6953  FlowReference(&np->flow, f);
6954  np->flags |= PKT_STREAM_EST;
6955  np->flags |= PKT_HAS_FLOW;
6956  np->flags |= PKT_IGNORE_CHECKSUM;
6958  memcpy(&np->vlan_id[0], &f->vlan_id[0], sizeof(np->vlan_id));
6959  np->vlan_idx = f->vlan_idx;
6960  np->livedev_id = f->livedev_id;
6961 
6962  if (parent->flags & PKT_NOPACKET_INSPECTION) {
6963  DecodeSetNoPacketInspectionFlag(np);
6964  }
6965  if (parent->flags & PKT_NOPAYLOAD_INSPECTION) {
6966  DecodeSetNoPayloadInspectionFlag(np);
6967  }
6968 
6969  if (dir == 0) {
6970  SCLogDebug("pseudo is to_server");
6972  } else {
6973  SCLogDebug("pseudo is to_client");
6975  }
6977  np->payload = NULL;
6978  np->payload_len = 0;
6979 
6980  if (FLOW_IS_IPV4(f)) {
6981  if (dir == 0) {
6984  np->sp = f->sp;
6985  np->dp = f->dp;
6986  } else {
6989  np->sp = f->dp;
6990  np->dp = f->sp;
6991  }
6992 
6993  /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
6994  * Force an allocation if it is not the case.
6995  */
6996  if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) {
6997  if (PacketCallocExtPkt(np, 40) == -1) {
6998  goto error;
6999  }
7000  }
7001  /* set the ip header */
7002  IPV4Hdr *ip4h = PacketSetIPV4(np, GET_PKT_DATA(np));
7003  /* version 4 and length 20 bytes for the tcp header */
7004  ip4h->ip_verhl = 0x45;
7005  ip4h->ip_tos = 0;
7006  ip4h->ip_len = htons(40);
7007  ip4h->ip_id = 0;
7008  ip4h->ip_off = 0;
7009  ip4h->ip_ttl = 64;
7010  ip4h->ip_proto = IPPROTO_TCP;
7011  if (dir == 0) {
7012  ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
7013  ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
7014  } else {
7015  ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
7016  ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
7017  }
7018 
7019  /* set the tcp header */
7020  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 20);
7021 
7022  SET_PKT_LEN(np, 40); /* ipv4 hdr + tcp hdr */
7023  } else {
7024  /* implied IPv6 */
7025 
7026  if (dir == 0) {
7029  np->sp = f->sp;
7030  np->dp = f->dp;
7031  } else {
7034  np->sp = f->dp;
7035  np->dp = f->sp;
7036  }
7037 
7038  /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
7039  * Force an allocation if it is not the case.
7040  */
7041  if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) {
7042  if (PacketCallocExtPkt(np, 60) == -1) {
7043  goto error;
7044  }
7045  }
7046  /* set the ip header */
7047  IPV6Hdr *ip6h = PacketSetIPV6(np, GET_PKT_DATA(np));
7048  /* version 6 */
7049  ip6h->s_ip6_vfc = 0x60;
7050  ip6h->s_ip6_flow = 0;
7051  ip6h->s_ip6_nxt = IPPROTO_TCP;
7052  ip6h->s_ip6_plen = htons(20);
7053  ip6h->s_ip6_hlim = 64;
7054  if (dir == 0) {
7055  ip6h->s_ip6_src[0] = f->src.addr_data32[0];
7056  ip6h->s_ip6_src[1] = f->src.addr_data32[1];
7057  ip6h->s_ip6_src[2] = f->src.addr_data32[2];
7058  ip6h->s_ip6_src[3] = f->src.addr_data32[3];
7059  ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
7060  ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
7061  ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
7062  ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
7063  } else {
7064  ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
7065  ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
7066  ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
7067  ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
7068  ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
7069  ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
7070  ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
7071  ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
7072  }
7073 
7074  /* set the tcp header */
7075  tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 40);
7076 
7077  SET_PKT_LEN(np, 60); /* ipv6 hdr + tcp hdr */
7078  }
7079 
7080  tcph->th_offx2 = 0x50;
7081  tcph->th_flags |= TH_ACK;
7082  tcph->th_win = 10;
7083  tcph->th_urp = 0;
7084 
7085  /* to server */
7086  if (dir == 0) {
7087  tcph->th_sport = htons(f->sp);
7088  tcph->th_dport = htons(f->dp);
7089 
7090  tcph->th_seq = htonl(ssn->client.next_seq);
7091  tcph->th_ack = htonl(ssn->server.last_ack);
7092 
7093  /* to client */
7094  } else {
7095  tcph->th_sport = htons(f->dp);
7096  tcph->th_dport = htons(f->sp);
7097 
7098  tcph->th_seq = htonl(ssn->server.next_seq);
7099  tcph->th_ack = htonl(ssn->client.last_ack);
7100  }
7101 
7102  /* use parent time stamp */
7103  np->ts = parent->ts;
7104 
7105  SCLogDebug("np %p", np);
7106  PacketEnqueueNoLock(pq, np);
7107 
7109  SCReturn;
7110 error:
7111  FlowDeReference(&np->flow);
7112  SCReturn;
7113 }
7114 
7115 /** \brief create packets in both directions to flush out logging
7116  * and detection before switching protocols.
7117  * In IDS mode, create first in packet dir, 2nd in opposing
7118  * In IPS mode, do the reverse.
7119  * Flag TCP engine that data needs to be inspected regardless
7120  * of how far we are wrt inspect limits.
7121  */
7123  PacketQueueNoLock *pq)
7124 {
7125  TcpSession *ssn = f->protoctx;
7128  bool ts = PKT_IS_TOSERVER(p);
7129  ts ^= StreamTcpInlineMode();
7130  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^1);
7131  StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts ^ 0);
7132 }
7133 
7134 /**
7135  * \brief Run callback function on each TCP segment in a single direction.
7136  *
7137  * \note when stream engine is running in inline mode all segments are used,
7138  * in IDS/non-inline mode only ack'd segments are iterated.
7139  *
7140  * \note Must be called under flow lock.
7141  * \var flag determines the direction to run callback on (either to server or to client).
7142  *
7143  * \return -1 in case of error, the number of segment in case of success
7144  *
7145  */
7146 int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
7147 {
7148  TcpStream *stream = NULL;
7149  int cnt = 0;
7150 
7151  if (p->flow == NULL)
7152  return 0;
7153 
7155  if (ssn == NULL) {
7156  return 0;
7157  }
7158 
7159  if (flag & STREAM_DUMP_TOSERVER) {
7160  stream = &(ssn->server);
7161  } else {
7162  stream = &(ssn->client);
7163  }
7164 
7165  /* for IDS, return ack'd segments. For IPS all. */
7166  TcpSegment *seg;
7167  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
7169  if (PKT_IS_PSEUDOPKT(p)) {
7170  /* use un-ACK'd data as well */
7171  } else {
7172  /* in IDS mode, use ACK'd data */
7173  if (SEQ_GEQ(seg->seq, stream->last_ack)) {
7174  break;
7175  }
7176  }
7177  }
7178 
7179  const uint8_t *seg_data;
7180  uint32_t seg_datalen;
7181  StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
7182 
7183  int ret = CallbackFunc(p, seg, data, seg_data, seg_datalen);
7184  if (ret != 1) {
7185  SCLogDebug("Callback function has failed");
7186  return -1;
7187  }
7188 
7189  cnt++;
7190  }
7191  return cnt;
7192 }
7193 
7194 /**
7195  * \brief Run callback function on each TCP segment in both directions of a session.
7196  *
7197  * \note when stream engine is running in inline mode all segments are used,
7198  * in IDS/non-inline mode only ack'd segments are iterated.
7199  *
7200  * \note Must be called under flow lock.
7201  *
7202  * \return -1 in case of error, the number of segment in case of success
7203  *
7204  */
7206  const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
7207 {
7208  int ret = 0;
7209  int cnt = 0;
7210 
7211  if (p->flow == NULL)
7212  return 0;
7213 
7215 
7216  if (ssn == NULL) {
7217  return -1;
7218  }
7219 
7220  TcpStream *server_stream = &(ssn->server);
7221  TcpStream *client_stream = &(ssn->client);
7222 
7223  TcpSegment *server_node = RB_MIN(TCPSEG, &server_stream->seg_tree);
7224  TcpSegment *client_node = RB_MIN(TCPSEG, &client_stream->seg_tree);
7225  if (server_node == NULL && client_node == NULL) {
7226  return cnt;
7227  }
7228 
7229  while (server_node != NULL || client_node != NULL) {
7230  const uint8_t *seg_data;
7231  uint32_t seg_datalen;
7232  if (server_node == NULL) {
7233  /*
7234  * This means the server side RB Tree has been completely searched,
7235  * thus all that remains is to dump the TcpSegments on the client
7236  * side.
7237  */
7239  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7240  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7241  if (ret != 1) {
7242  SCLogDebug("Callback function has failed");
7243  return -1;
7244  }
7245  client_node = TCPSEG_RB_NEXT(client_node);
7246  } else if (client_node == NULL) {
7247  /*
7248  * This means the client side RB Tree has been completely searched,
7249  * thus all that remains is to dump the TcpSegments on the server
7250  * side.
7251  */
7253  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7254  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7255  if (ret != 1) {
7256  SCLogDebug("Callback function has failed");
7257  return -1;
7258  }
7259  server_node = TCPSEG_RB_NEXT(server_node);
7260  } else {
7261  if (SCTIME_CMP_LT(
7262  client_node->pcap_hdr_storage->ts, server_node->pcap_hdr_storage->ts)) {
7264  &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7265  ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7266  if (ret != 1) {
7267  SCLogDebug("Callback function has failed");
7268  return -1;
7269  }
7270  client_node = TCPSEG_RB_NEXT(client_node);
7271  } else {
7273  &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7274  ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7275  if (ret != 1) {
7276  SCLogDebug("Callback function has failed");
7277  return -1;
7278  }
7279  server_node = TCPSEG_RB_NEXT(server_node);
7280  }
7281  }
7282 
7283  cnt++;
7284  }
7285  return cnt;
7286 }
7287 
7289 {
7291 }
7292 
7293 /**
7294  * \brief See if stream engine is operating in inline mode
7295  *
7296  * \retval 0 no
7297  * \retval 1 yes
7298  */
7300 {
7302 }
7303 
7304 
7306 {
7307  if (size > ssn->reassembly_depth || size == 0) {
7308  ssn->reassembly_depth = size;
7309  }
7310 }
7311 
7312 const char *StreamTcpStateAsString(const enum TcpState state)
7313 {
7314  const char *tcp_state = NULL;
7315  switch (state) {
7316  case TCP_NONE:
7317  tcp_state = "none";
7318  break;
7319  case TCP_SYN_SENT:
7320  tcp_state = "syn_sent";
7321  break;
7322  case TCP_SYN_RECV:
7323  tcp_state = "syn_recv";
7324  break;
7325  case TCP_ESTABLISHED:
7326  tcp_state = "established";
7327  break;
7328  case TCP_FIN_WAIT1:
7329  tcp_state = "fin_wait1";
7330  break;
7331  case TCP_FIN_WAIT2:
7332  tcp_state = "fin_wait2";
7333  break;
7334  case TCP_TIME_WAIT:
7335  tcp_state = "time_wait";
7336  break;
7337  case TCP_LAST_ACK:
7338  tcp_state = "last_ack";
7339  break;
7340  case TCP_CLOSE_WAIT:
7341  tcp_state = "close_wait";
7342  break;
7343  case TCP_CLOSING:
7344  tcp_state = "closing";
7345  break;
7346  case TCP_CLOSED:
7347  tcp_state = "closed";
7348  break;
7349  }
7350  return tcp_state;
7351 }
7352 
7353 #ifdef UNITTESTS
7354 #include "tests/stream-tcp.c"
7355 #endif
PKT_IS_TOCLIENT
#define PKT_IS_TOCLIENT(p)
Definition: decode.h:240
STREAM_EST_SYN_RESEND_DIFF_SEQ
@ STREAM_EST_SYN_RESEND_DIFF_SEQ
Definition: decode-events.h:283
PacketL4::csum_set
bool csum_set
Definition: decode.h:478
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
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:282
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:1093
TCPVars_::ao_option_present
uint8_t ao_option_present
Definition: decode-tcp.h:165
Packet_::proto
uint8_t proto
Definition: decode.h:538
TcpStream_
Definition: stream-tcp-private.h:106
ts
uint64_t ts
Definition: source-erf-file.c:68
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:306
OS_POLICY_FIRST
@ OS_POLICY_FIRST
Definition: stream-tcp-reassemble.h:50
Flow_::flags
uint64_t flags
Definition: flow.h:408
PoolThreadExpand
int PoolThreadExpand(PoolThread *pt)
expand pool by one for a new thread
Definition: util-pool-thread.c:96
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1311
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:47
TCP_HAS_TFO
#define TCP_HAS_TFO(p)
Definition: decode-tcp.h:97
stream-tcp-inline.h
TcpReassemblyThreadCtx_::counter_tcp_reass_data_overlap_fail
StatsCounterId counter_tcp_reass_data_overlap_fail
Definition: stream-tcp-reassemble.h:85
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:1123
FlowGetPacketDirection
int FlowGetPacketDirection(const Flow *f, const Packet *p)
determine the direction of the packet compared to the flow
Definition: flow.c:283
STREAM_FIN1_ACK_WRONG_SEQ
@ STREAM_FIN1_ACK_WRONG_SEQ
Definition: decode-events.h:288
FLOW_STATE_ESTABLISHED
@ FLOW_STATE_ESTABLISHED
Definition: flow.h:510
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:298
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:251
OS_POLICY_OLD_SOLARIS
@ OS_POLICY_OLD_SOLARIS
Definition: stream-tcp-reassemble.h:41
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:549
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1364
TcpSessionPacketSsnReuse
bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
Definition: stream-tcp.c:6125
ParseSizeStringU16
int ParseSizeStringU16(const char *size, uint16_t *res)
Definition: util-misc.c:156
stream-tcp.h
StreamTcpInlineMode
bool StreamTcpInlineMode(void)
See if stream engine is operating in inline mode.
Definition: stream-tcp.c:7299
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:396
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:303
PKT_STREAM_MODIFIED
#define PKT_STREAM_MODIFIED
Definition: decode.h:1316
TcpStream_::seg_tree
struct TCPSEG seg_tree
Definition: stream-tcp-private.h:136
PcapPacketCntGet
uint64_t PcapPacketCntGet(const Packet *p)
Definition: decode.c:1193
PacketL4::csum
uint16_t csum
Definition: decode.h:479
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:190
StatsRegisterCounter
StatsCounterId StatsRegisterCounter(const char *name, StatsThreadContext *stats)
Registers a normal, unqualified counter.
Definition: counters.c:1038
util-pool-thread.h
seq
uint32_t seq
Definition: stream-tcp-private.h:2
OS_POLICY_VISTA
@ OS_POLICY_VISTA
Definition: stream-tcp-reassemble.h:48
StreamTcpThread_
Definition: stream-tcp.h:92
StreamTcpSetSessionNoReassemblyFlag
void StreamTcpSetSessionNoReassemblyFlag(TcpSession *ssn, char direction)
disable reassembly
Definition: stream-tcp.c:6894
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:437
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
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:44
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:620
util-checksum.h
STREAM_FIN_BUT_NO_SESSION
@ STREAM_FIN_BUT_NO_SESSION
Definition: decode-events.h:294
action-globals.h
TcpReassemblyThreadCtx_::app_tctx
void * app_tctx
Definition: stream-tcp-reassemble.h:62
Packet_::flags
uint32_t flags
Definition: decode.h:562
STREAM_PKT_FLAG_KEEPALIVEACK
#define STREAM_PKT_FLAG_KEEPALIVEACK
Definition: stream-tcp-private.h:316
ssn
TcpSession ssn
Definition: fuzz_dataset.c:31
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:1028
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:286
STREAMTCP_DEFAULT_MAX_SYN_QUEUED
#define STREAMTCP_DEFAULT_MAX_SYN_QUEUED
Definition: stream-tcp.c:88
STREAM_4WHS_SYNACK_WITH_WRONG_SYN
@ STREAM_4WHS_SYNACK_WITH_WRONG_SYN
Definition: decode-events.h:267
TcpStreamCnf_::reassembly_depth
uint32_t reassembly_depth
Definition: stream-tcp.h:75
Packet_::vlan_idx
uint8_t vlan_idx
Definition: decode.h:544
Flow_
Flow data structure.
Definition: flow.h:359
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
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:37
STREAM_EST_PACKET_OUT_OF_WINDOW
@ STREAM_EST_PACKET_OUT_OF_WINDOW
Definition: decode-events.h:276
SCConfGet
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:352
STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK
@ STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK
Definition: decode-events.h:279
TCP_FIN_WAIT1
@ TCP_FIN_WAIT1
Definition: stream-tcp-private.h:156
STREAM_DEPTH_DEFAULT
#define STREAM_DEPTH_DEFAULT
Definition: stream-tcp.c:91
TCP_LAST_ACK
@ TCP_LAST_ACK
Definition: stream-tcp-private.h:159
TcpStreamCnf_::sbcnf
StreamingBufferConfig sbcnf
Definition: stream-tcp.h:89
util-runmodes.h
TcpStateQueue_::win
uint16_t win
Definition: stream-tcp-private.h:38
LiveDeviceGetById
LiveDevice * LiveDeviceGetById(const int id)
Definition: util-device.c:460
STREAM_CLOSING_ACK_WRONG_SEQ
@ STREAM_CLOSING_ACK_WRONG_SEQ
Definition: decode-events.h:274
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:6178
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:258
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:236
RB_MIN
#define RB_MIN(name, x)
Definition: tree.h:778
STREAM_3WHS_SYNACK_FLOOD
@ STREAM_3WHS_SYNACK_FLOOD
Definition: decode-events.h:259
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:6874
SCConfGetBool
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition: conf.c:523
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:301
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:252
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:299
STREAMTCP_STREAM_FLAG_KEEPALIVE
#define STREAMTCP_STREAM_FLAG_KEEPALIVE
Definition: stream-tcp-private.h:221
p
Packet * p
Definition: fuzz_dataset.c:30
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:151
TCP_STREAM_URGENT_GAP
@ TCP_STREAM_URGENT_GAP
Definition: stream-tcp.h:50
Flow_::livedev_id
uint16_t livedev_id
Definition: flow.h:404
PKT_STREAM_NO_EVENTS
#define PKT_STREAM_NO_EVENTS
Definition: decode.h:1357
PKT_NOPAYLOAD_INSPECTION
#define PKT_NOPAYLOAD_INSPECTION
Definition: decode.h:1297
Flow_::dp
Port dp
Definition: flow.h:375
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:547
OS_POLICY_IRIX
@ OS_POLICY_IRIX
Definition: stream-tcp-reassemble.h:45
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
Flow_::protoctx
void * protoctx
Definition: flow.h:438
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:312
TcpStateQueue_
Definition: stream-tcp-private.h:35
GET_PKT_DIRECT_MAX_SIZE
#define GET_PKT_DIRECT_MAX_SIZE(p)
Definition: decode.h:212
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:99
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:49
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:621
OS_POLICY_BSD_RIGHT
@ OS_POLICY_BSD_RIGHT
Definition: stream-tcp-reassemble.h:38
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:205
STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV
@ STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV
Definition: decode-events.h:261
STREAM_FIN1_FIN_WRONG_SEQ
@ STREAM_FIN1_FIN_WRONG_SEQ
Definition: decode-events.h:289
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:188
StreamTcpReassembleInit
int StreamTcpReassembleInit(bool quiet)
Definition: stream-tcp-reassemble.c:530
PKT_DROP_REASON_STREAM_URG
@ PKT_DROP_REASON_STREAM_URG
Definition: decode.h:399
STREAM_FIN_OUT_OF_WINDOW
@ STREAM_FIN_OUT_OF_WINDOW
Definition: decode-events.h:295
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:1090
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:652
STREAM_FIN2_FIN_WRONG_SEQ
@ STREAM_FIN2_FIN_WRONG_SEQ
Definition: decode-events.h:292
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1366
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:362
SET_PKT_LEN
#define SET_PKT_LEN(p, len)
Definition: decode.h:214
StreamTcpReassembleInitThreadCtx
TcpReassemblyThreadCtx * StreamTcpReassembleInitThreadCtx(ThreadVars *tv)
Definition: stream-tcp-reassemble.c:564
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:271
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:280
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:260
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:302
GET_IPV4_DST_ADDR_PTR
#define GET_IPV4_DST_ADDR_PTR(p)
Definition: decode.h:200
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:40
TcpStateQueue_::seq
uint32_t seq
Definition: stream-tcp-private.h:39
PKT_IS_TOSERVER
#define PKT_IS_TOSERVER(p)
Definition: decode.h:239
OS_POLICY_SOLARIS
@ OS_POLICY_SOLARIS
Definition: stream-tcp-reassemble.h:42
STREAM_4WHS_SYNACK_WITH_WRONG_ACK
@ STREAM_4WHS_SYNACK_WITH_WRONG_ACK
Definition: decode-events.h:266
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:570
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:7205
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:1313
PacketSwap
void PacketSwap(Packet *p)
switch direction of a packet
Definition: decode.c:596
util-exception-policy.h
SCConfGetInt
int SCConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:440
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:87
STREAM_3WHS_WRONG_SEQ_WRONG_ACK
@ STREAM_3WHS_WRONG_SEQ_WRONG_ACK
Definition: decode-events.h:264
STREAM_FIN_SYN
@ STREAM_FIN_SYN
Definition: decode-events.h:296
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:210
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:378
SCConfGetNonNull
int SCConfGetNonNull(const char *name, const char **vptr)
Retrieve the non-null value of a configuration node.
Definition: conf.c:380
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV
@ STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV
Definition: decode-events.h:262
StreamTcp
TmEcode StreamTcp(ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq)
Definition: stream-tcp.c:6137
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:267
pkt-var.h
PacketL4::L4Vars::tcp
TCPVars tcp
Definition: decode.h:491
StreamTcpPacket
int StreamTcpPacket(ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueueNoLock *pq)
Definition: stream-tcp.c:5703
Packet_::sp
Port sp
Definition: decode.h:523
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:43
STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION
@ STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION
Definition: decode-events.h:254
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:163
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:297
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:894
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
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:7146
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:85
STREAM_FIN2_INVALID_ACK
@ STREAM_FIN2_INVALID_ACK
Definition: decode-events.h:293
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:322
FLOW_IS_IPV4
#define FLOW_IS_IPV4(f)
Definition: flow.h:173
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:337
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:314
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:336
STREAM_FIN1_INVALID_ACK
@ STREAM_FIN1_INVALID_ACK
Definition: decode-events.h:290
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:516
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:248
stream-tcp-sack.h
stream-tcp-private.h
conf.h
Packet_::l4
struct PacketL4 l4
Definition: decode.h:616
DEBUG_ASSERT_FLOW_LOCKED
#define DEBUG_ASSERT_FLOW_LOCKED(f)
Definition: util-validate.h:106
STREAM_3WHS_SYN_FLOOD
@ STREAM_3WHS_SYN_FLOOD
Definition: decode-events.h:263
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:395
TcpStream_::window
uint32_t window
Definition: stream-tcp-private.h:117
PKT_IGNORE_CHECKSUM
#define PKT_IGNORE_CHECKSUM
Definition: decode.h:1327
STREAM_RST_WITH_DATA
@ STREAM_RST_WITH_DATA
Definition: decode-events.h:307
TCP_HAS_TS
#define TCP_HAS_TS(p)
Definition: decode-tcp.h:95
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:600
TmEcode
TmEcode
Definition: tm-threads-common.h:80
Flow_::vlan_idx
uint8_t vlan_idx
Definition: flow.h:385
PcapIncreaseInvalidChecksum
void PcapIncreaseInvalidChecksum(void)
Definition: source-pcap-file.c:508
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:84
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:278
FLOW_PKT_TOCLIENT
#define FLOW_PKT_TOCLIENT
Definition: flow.h:237
TcpStreamCnf_::reassembly_memcap_policy
enum ExceptionPolicy reassembly_memcap_policy
Definition: stream-tcp.h:81
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:293
STREAMING_BUFFER_INITIALIZER
#define STREAMING_BUFFER_INITIALIZER
Definition: util-streaming-buffer.h:137
StreamTcpReassembleFree
void StreamTcpReassembleFree(bool quiet)
Definition: stream-tcp-reassemble.c:546
TH_URG
#define TH_URG
Definition: decode-tcp.h:39
WarnInvalidConfEntry
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition: util-misc.h:35
FlowUpdateState
void FlowUpdateState(Flow *f, const enum FlowState s)
Definition: flow.c:1194
STREAM_PKT_BAD_WINDOW_UPDATE
@ STREAM_PKT_BAD_WINDOW_UPDATE
Definition: decode-events.h:310
Flow_::src
FlowAddress src
Definition: flow.h:362
util-host-os-info.h
STREAM_FIN_INVALID_ACK
@ STREAM_FIN_INVALID_ACK
Definition: decode-events.h:287
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
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:51
STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW
@ STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW
Definition: decode-events.h:270
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:909
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:277
PoolThreadInit
PoolThread * PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int(*Init)(void *), void(*Cleanup)(void *))
per thread Pool, initialization function
Definition: util-pool-thread.c:43
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:260
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:253
PacketEnqueueNoLock
void PacketEnqueueNoLock(PacketQueueNoLock *qnl, Packet *p)
Definition: packet-queue.c:168
STREAM_SUSPECTED_RST_INJECT
@ STREAM_SUSPECTED_RST_INJECT
Definition: decode-events.h:312
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:268
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:678
Packet_::flow
struct Flow_ * flow
Definition: decode.h:564
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:1152
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:864
STREAM_4WHS_INVALID_ACK
@ STREAM_4WHS_INVALID_ACK
Definition: decode-events.h:269
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:356
STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK
@ STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK
Definition: decode-events.h:272
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:444
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:1322
TcpStream_::sb
StreamingBuffer sb
Definition: stream-tcp-private.h:135
Packet_::livedev_id
uint16_t livedev_id
Definition: decode.h:633
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:85
STREAM_PKT_SPURIOUS_RETRANSMISSION
@ STREAM_PKT_SPURIOUS_RETRANSMISSION
Definition: decode-events.h:309
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:257
FatalError
#define FatalError(...)
Definition: util-debug.h:517
STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
Definition: stream-tcp-private.h:236
TCPVars_::md5_option_present
uint8_t md5_option_present
Definition: decode-tcp.h:164
STREAMTCP_FLAG_MIDSTREAM_SYNACK
#define STREAMTCP_FLAG_MIDSTREAM_SYNACK
Definition: stream-tcp-private.h:174
STREAM_WRONG_THREAD
@ STREAM_WRONG_THREAD
Definition: decode-events.h:313
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:2008
OS_POLICY_MACOS
@ OS_POLICY_MACOS
Definition: stream-tcp-reassemble.h:46
TCP_CLOSING
@ TCP_CLOSING
Definition: stream-tcp-private.h:161
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:34
ParseSizeStringU32
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:173
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:243
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:7122
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
STREAM_CLOSEWAIT_INVALID_ACK
@ STREAM_CLOSEWAIT_INVALID_ACK
Definition: decode-events.h:273
TcpSession_::server
TcpStream server
Definition: stream-tcp-private.h:296
FLOW_STATE_CLOSED
@ FLOW_STATE_CLOSED
Definition: flow.h:511
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:304
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:1353
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:183
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:89
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:914
Packet_::pkt_src
uint8_t pkt_src
Definition: decode.h:626
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:7305
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
TcpStream_::app_progress_rel
uint32_t app_progress_rel
Definition: stream-tcp-private.h:127
StreamTcpSessionCleanup
void StreamTcpSessionCleanup(TcpSession *ssn)
Session cleanup function. Does not free the ssn.
Definition: stream-tcp.c:335
TcpStateQueue_::ts
uint32_t ts
Definition: stream-tcp-private.h:41
STREAM_EST_INVALID_ACK
@ STREAM_EST_INVALID_ACK
Definition: decode-events.h:285
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:1136
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:904
STREAM_PKT_RETRANSMISSION
@ STREAM_PKT_RETRANSMISSION
Definition: decode-events.h:308
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:238
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:243
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:395
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:169
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:247
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:191
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:521
STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE
#define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE
Definition: stream-tcp.c:86
STREAM_CLOSING_INVALID_ACK
@ STREAM_CLOSING_INVALID_ACK
Definition: decode-events.h:275
StreamTcpStateAsString
const char * StreamTcpStateAsString(const enum TcpState state)
Definition: stream-tcp.c:7312
Flow_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: flow.h:383
STREAM_PKT_BROKEN_ACK
@ STREAM_PKT_BROKEN_ACK
Definition: decode-events.h:305
STREAMTCP_FLAG_3WHS_CONFIRMED
#define STREAMTCP_FLAG_3WHS_CONFIRMED
Definition: stream-tcp-private.h:199
STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION
#define STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION
Definition: stream-tcp.h:38
SEQ_LEQ
#define SEQ_LEQ(a, b)
Definition: stream-tcp-private.h:258
PKT_NOPACKET_INSPECTION
#define PKT_NOPACKET_INSPECTION
Definition: decode.h:1292
TCP_HAS_WSCALE
#define TCP_HAS_WSCALE(p)
Definition: decode-tcp.h:93
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:39
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:543
TCP_STREAM_URGENT_INLINE
@ TCP_STREAM_URGENT_INLINE
Definition: stream-tcp.h:46
likely
#define likely(expr)
Definition: util-optimize.h:32
TcpStreamUrgentHandling
TcpStreamUrgentHandling
Definition: stream-tcp.h:45
STREAM_APP_PROGRESS
#define STREAM_APP_PROGRESS(stream)
Definition: stream-tcp-private.h:145
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:300
STREAM_EST_SYN_TOCLIENT
@ STREAM_EST_SYN_TOCLIENT
Definition: decode-events.h:284
STREAM_3WHS_ACK_DATA_INJECT
@ STREAM_3WHS_ACK_DATA_INJECT
Definition: decode-events.h:265
IPV4Hdr_::ip_off
uint16_t ip_off
Definition: decode-ipv4.h:77
Flow_::sp
Port sp
Definition: flow.h:364
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:291
util-misc.h
flow.h
PKT_DROP_REASON_STREAM_MIDSTREAM
@ PKT_DROP_REASON_STREAM_MIDSTREAM
Definition: decode.h:397
STREAM_EST_SYNACK_TOSERVER
@ STREAM_EST_SYNACK_TOSERVER
Definition: decode-events.h:281
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:1760
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:455
Packet_::dp
Port dp
Definition: decode.h:531
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:144
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:120
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:150
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:109
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:520
Flow_::tenant_id
uint32_t tenant_id
Definition: flow.h:429
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:6268
STREAMTCP_DEFAULT_PREALLOC
#define STREAMTCP_DEFAULT_PREALLOC
Definition: stream-tcp.c:83
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1307
STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK
@ STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK
Definition: decode-events.h:255
Flow_::thread_id
FlowThreadId thread_id[2]
Definition: flow.h:397
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:183
StreamTcpSetDisableRawReassemblyFlag
void StreamTcpSetDisableRawReassemblyFlag(TcpSession *ssn, char direction)
Set the No reassembly flag for the given direction in given TCP session.
Definition: stream-tcp.c:6906
f
Flow f
Definition: fuzz_dataset.c:32
StreamTcpSetSessionBypassFlag
void StreamTcpSetSessionBypassFlag(TcpSession *ssn)
enable bypass
Definition: stream-tcp.c:6917
StreamTcpBypassEnabled
int StreamTcpBypassEnabled(void)
Definition: stream-tcp.c:7288