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