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