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