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);
472  stream_config.midstream_policy = ExceptionPolicyParse("stream.midstream-policy", true);
474  SCLogWarning("stream.midstream_policy setting conflicting with stream.midstream enabled. "
475  "Ignoring stream.midstream_policy. Bug #5825.");
477  }
478 
479  if (!quiet) {
480  SCLogConfig("stream.\"inline\": %s",
482  ? "enabled" : "disabled");
483  }
484 
485  int bypass = 0;
486  if ((ConfGetBool("stream.bypass", &bypass)) == 1) {
487  if (bypass == 1) {
489  }
490  }
491 
492  if (!quiet) {
493  SCLogConfig("stream \"bypass\": %s",
495  ? "enabled" : "disabled");
496  }
497 
498  int drop_invalid = 0;
499  if ((ConfGetBool("stream.drop-invalid", &drop_invalid)) == 1) {
500  if (drop_invalid == 1) {
502  }
503  } else {
505  }
506 
507  if ((ConfGetInt("stream.max-syn-queued", &value)) == 1) {
508  if (value >= 0 && value <= 255) {
509  stream_config.max_syn_queued = (uint8_t)value;
510  } else {
512  }
513  } else {
515  }
516  if (!quiet) {
517  SCLogConfig("stream \"max-syn-queued\": %" PRIu8, stream_config.max_syn_queued);
518  }
519 
520  if ((ConfGetInt("stream.max-synack-queued", &value)) == 1) {
521  if (value >= 0 && value <= 255) {
522  stream_config.max_synack_queued = (uint8_t)value;
523  } else {
525  }
526  } else {
528  }
529  if (!quiet) {
530  SCLogConfig("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued);
531  }
532 
533  const char *temp_stream_reassembly_memcap_str;
534  if (ConfGet("stream.reassembly.memcap", &temp_stream_reassembly_memcap_str) == 1) {
535  uint64_t stream_reassembly_memcap_copy;
536  if (ParseSizeStringU64(temp_stream_reassembly_memcap_str,
537  &stream_reassembly_memcap_copy) < 0) {
538  SCLogError("Error parsing "
539  "stream.reassembly.memcap "
540  "from conf file - %s. Killing engine",
541  temp_stream_reassembly_memcap_str);
542  exit(EXIT_FAILURE);
543  } else {
544  SC_ATOMIC_SET(stream_config.reassembly_memcap, stream_reassembly_memcap_copy);
545  }
546  } else {
548  }
549 
550  if (!quiet) {
551  SCLogConfig("stream.reassembly \"memcap\": %"PRIu64"",
552  SC_ATOMIC_GET(stream_config.reassembly_memcap));
553  }
554 
555  const char *temp_stream_reassembly_depth_str;
556  if (ConfGet("stream.reassembly.depth", &temp_stream_reassembly_depth_str) == 1) {
557  if (ParseSizeStringU32(temp_stream_reassembly_depth_str,
559  SCLogError("Error parsing "
560  "stream.reassembly.depth "
561  "from conf file - %s. Killing engine",
562  temp_stream_reassembly_depth_str);
563  exit(EXIT_FAILURE);
564  }
565  } else {
567  }
568 
569  if (!quiet) {
570  SCLogConfig("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth);
571  }
572 
573  int randomize = 0;
574  if ((ConfGetBool("stream.reassembly.randomize-chunk-size", &randomize)) == 0) {
575  /* randomize by default if value not set
576  * In ut mode we disable, to get predictable test results */
577  if (!(RunmodeIsUnittests()))
578  randomize = 1;
579  }
580 
581  if (randomize) {
582  const char *temp_rdrange;
583  if (ConfGet("stream.reassembly.randomize-chunk-range", &temp_rdrange) == 1) {
584  if (ParseSizeStringU16(temp_rdrange, &rdrange) < 0) {
585  SCLogError("Error parsing "
586  "stream.reassembly.randomize-chunk-range "
587  "from conf file - %s. Killing engine",
588  temp_rdrange);
589  exit(EXIT_FAILURE);
590  } else if (rdrange >= 100) {
591  FatalError("stream.reassembly.randomize-chunk-range "
592  "must be lower than 100");
593  }
594  }
595  }
596 
597  const char *temp_stream_reassembly_toserver_chunk_size_str;
598  if (ConfGet("stream.reassembly.toserver-chunk-size",
599  &temp_stream_reassembly_toserver_chunk_size_str) == 1) {
600  if (ParseSizeStringU16(temp_stream_reassembly_toserver_chunk_size_str,
602  SCLogError("Error parsing "
603  "stream.reassembly.toserver-chunk-size "
604  "from conf file - %s. Killing engine",
605  temp_stream_reassembly_toserver_chunk_size_str);
606  exit(EXIT_FAILURE);
607  }
608  } else {
611  }
612 
613  if (randomize) {
614  long int r = RandomGetWrap();
616  (int)(stream_config.reassembly_toserver_chunk_size * ((double)r / RAND_MAX - 0.5) *
617  rdrange / 100);
618  }
619  const char *temp_stream_reassembly_toclient_chunk_size_str;
620  if (ConfGet("stream.reassembly.toclient-chunk-size",
621  &temp_stream_reassembly_toclient_chunk_size_str) == 1) {
622  if (ParseSizeStringU16(temp_stream_reassembly_toclient_chunk_size_str,
624  SCLogError("Error parsing "
625  "stream.reassembly.toclient-chunk-size "
626  "from conf file - %s. Killing engine",
627  temp_stream_reassembly_toclient_chunk_size_str);
628  exit(EXIT_FAILURE);
629  }
630  } else {
633  }
634 
635  if (randomize) {
636  long int r = RandomGetWrap();
638  (int)(stream_config.reassembly_toclient_chunk_size * ((double)r / RAND_MAX - 0.5) *
639  rdrange / 100);
640  }
641  if (!quiet) {
642  SCLogConfig("stream.reassembly \"toserver-chunk-size\": %"PRIu16,
644  SCLogConfig("stream.reassembly \"toclient-chunk-size\": %"PRIu16,
646  }
647 
648  int enable_raw = 1;
649  if (ConfGetBool("stream.reassembly.raw", &enable_raw) == 1) {
650  if (!enable_raw) {
652  }
653  } else {
654  enable_raw = 1;
655  }
656  if (!quiet)
657  SCLogConfig("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled");
658 
659  /* default to true. Not many ppl (correctly) set up host-os policies, so be permissive. */
661  int liberal_timestamps = 0;
662  if (ConfGetBool("stream.liberal-timestamps", &liberal_timestamps) == 1) {
663  stream_config.liberal_timestamps = liberal_timestamps;
664  }
665  if (!quiet)
666  SCLogConfig("stream.liberal-timestamps: %s", liberal_timestamps ? "enabled" : "disabled");
667 
668  /* init the memcap/use tracking */
671 
673 
674  /* set the default free function and flow state function
675  * values. */
677 
678 #ifdef UNITTESTS
679  if (RunmodeIsUnittests()) {
680  SCMutexLock(&ssn_pool_mutex);
681  if (ssn_pool == NULL) {
682  ssn_pool = PoolThreadInit(1, /* thread */
683  0, /* unlimited */
685  sizeof(TcpSession),
686  StreamTcpSessionPoolAlloc,
687  StreamTcpSessionPoolInit, NULL,
688  StreamTcpSessionPoolCleanup, NULL);
689  }
690  SCMutexUnlock(&ssn_pool_mutex);
691  }
692 #endif
693 }
694 
695 void StreamTcpFreeConfig(bool quiet)
696 {
698 
699  SCMutexLock(&ssn_pool_mutex);
700  if (ssn_pool != NULL) {
702  ssn_pool = NULL;
703  }
704  SCMutexUnlock(&ssn_pool_mutex);
705  SCMutexDestroy(&ssn_pool_mutex);
706 
707  SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt);
708 }
709 
710 /** \internal
711  * \brief The function is used to fetch a TCP session from the
712  * ssn_pool, when a TCP SYN is received.
713  *
714  * \param p packet starting the new TCP session.
715  * \param id thread pool id
716  *
717  * \retval ssn new TCP session.
718  */
719 static TcpSession *StreamTcpNewSession(ThreadVars *tv, StreamTcpThread *stt, Packet *p, int id)
720 {
721  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
722 
723  if (ssn == NULL) {
724  DEBUG_VALIDATE_BUG_ON(id < 0 || id > UINT16_MAX);
726  if (p->flow->protoctx != NULL) {
727 #ifdef UNITTESTS
728  if (tv)
729 #endif
731  } else {
732  p->flow->protoctx = PoolThreadGetById(ssn_pool, (uint16_t)id);
733  if (p->flow->protoctx != NULL)
734 #ifdef UNITTESTS
735  if (tv)
736 #endif
738  }
739 #ifdef DEBUG
740  SCMutexLock(&ssn_pool_mutex);
741  if (p->flow->protoctx != NULL)
742  ssn_pool_cnt++;
743  SCMutexUnlock(&ssn_pool_mutex);
744 
745  if (unlikely((g_eps_stream_ssn_memcap != UINT64_MAX &&
746  g_eps_stream_ssn_memcap == t_pcapcnt))) {
747  SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt);
749  return NULL;
750  }
751 #endif
752  ssn = (TcpSession *)p->flow->protoctx;
753  if (ssn == NULL) {
754  SCLogDebug("ssn_pool is empty");
756  return NULL;
757  }
758 
759  ssn->state = TCP_NONE;
761  ssn->tcp_packet_flags = p->tcph ? p->tcph->th_flags : 0;
764 
766  ssn->client.sb = x;
767  ssn->server.sb = x;
768 
769  if (PKT_IS_TOSERVER(p)) {
770  ssn->client.tcp_flags = p->tcph ? p->tcph->th_flags : 0;
771  ssn->server.tcp_flags = 0;
772  } else if (PKT_IS_TOCLIENT(p)) {
773  ssn->server.tcp_flags = p->tcph ? p->tcph->th_flags : 0;
774  ssn->client.tcp_flags = 0;
775  }
776  }
777 
778  return ssn;
779 }
780 
781 static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn,
782  uint8_t state)
783 {
784  if (state == ssn->state || PKT_IS_PSEUDOPKT(p))
785  return;
786 
787  ssn->pstate = ssn->state;
788  ssn->state = state;
790 
791  /* update the flow state */
792  switch(ssn->state) {
793  case TCP_ESTABLISHED:
794  case TCP_FIN_WAIT1:
795  case TCP_FIN_WAIT2:
796  case TCP_CLOSING:
797  case TCP_CLOSE_WAIT:
799  break;
800  case TCP_LAST_ACK:
801  case TCP_TIME_WAIT:
802  case TCP_CLOSED:
804  break;
805  }
806 }
807 
808 /**
809  * \brief Function to set the OS policy for the given stream based on the
810  * destination of the received packet.
811  *
812  * \param stream TcpStream of which os_policy needs to set
813  * \param p Packet which is used to set the os policy
814  */
816 {
817  if (PKT_IS_IPV4(p)) {
818  /* Get the OS policy based on destination IP address, as destination
819  OS will decide how to react on the anomalies of newly received
820  packets */
821  int ret = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
822  if (ret > 0)
823  stream->os_policy = (uint8_t)ret;
824  else
825  stream->os_policy = OS_POLICY_DEFAULT;
826 
827  } else if (PKT_IS_IPV6(p)) {
828  /* Get the OS policy based on destination IP address, as destination
829  OS will decide how to react on the anomalies of newly received
830  packets */
831  int ret = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
832  if (ret > 0)
833  stream->os_policy = (uint8_t)ret;
834  else
835  stream->os_policy = OS_POLICY_DEFAULT;
836  }
837 
838  if (stream->os_policy == OS_POLICY_BSD_RIGHT)
839  stream->os_policy = OS_POLICY_BSD;
840  else if (stream->os_policy == OS_POLICY_OLD_SOLARIS)
841  stream->os_policy = OS_POLICY_SOLARIS;
842 
843  SCLogDebug("Policy is %"PRIu8"", stream->os_policy);
844 
845 }
846 
847 /**
848  * \brief macro to update last_ack only if the new value is higher
849  *
850  * \param ssn session
851  * \param stream stream to update
852  * \param ack ACK value to test and set
853  */
854 #define StreamTcpUpdateLastAck(ssn, stream, ack) { \
855  if (SEQ_GT((ack), (stream)->last_ack)) \
856  { \
857  SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \
858  if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \
859  SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \
860  } else { \
861  SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \
862  }\
863  (stream)->last_ack = (ack); \
864  StreamTcpSackPruneList((stream)); \
865  } else { \
866  SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \
867  (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \
868  }\
869 }
870 
871 #define StreamTcpAsyncLastAckUpdate(ssn, stream) { \
872  if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \
873  if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \
874  uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \
875  (stream)->last_ack += ack_diff; \
876  SCLogDebug("ssn %p: ASYNC last_ack set to %"PRIu32", moved %u forward", \
877  (ssn), (stream)->next_seq, ack_diff); \
878  } \
879  } \
880 }
881 
882 #define StreamTcpUpdateNextSeq(ssn, stream, seq) { \
883  (stream)->next_seq = seq; \
884  SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \
885  StreamTcpAsyncLastAckUpdate((ssn), (stream)); \
886 }
887 
888 /**
889  * \brief macro to update next_win only if the new value is higher
890  *
891  * \param ssn session
892  * \param stream stream to update
893  * \param win window value to test and set
894  */
895 #define StreamTcpUpdateNextWin(ssn, stream, win) { \
896  uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \
897  if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \
898  (stream)->next_win = ((win) + sacked_size__); \
899  SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \
900  } \
901 }
902 
903 static inline void StreamTcpCloseSsnWithReset(Packet *p, TcpSession *ssn)
904 {
906  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
907  SCLogDebug("ssn %p: (state: %s) Reset received and state changed to "
908  "TCP_CLOSED", ssn, StreamTcpStateAsString(ssn->state));
909 }
910 
911 static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p)
912 {
913  if (p->payload_len == 0)
914  SCReturnInt(0);
915 
916  /* retransmission of already partially ack'd data */
917  if (SEQ_LT(TCP_GET_SEQ(p), stream->last_ack) && SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack))
918  {
920  SCReturnInt(1);
921  }
922 
923  /* retransmission of already ack'd data */
924  if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) {
926  SCReturnInt(1);
927  }
928 
929  /* retransmission of in flight data */
930  if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->next_seq)) {
932  SCReturnInt(2);
933  }
934 
935  SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", TCP_GET_SEQ(p),
936  p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack, stream->next_seq);
937  SCReturnInt(0);
938 }
939 
940 /**
941  * \internal
942  * \brief Function to handle the TCP_CLOSED or NONE state. The function handles
943  * packets while the session state is None which means a newly
944  * initialized structure, or a fully closed session.
945  *
946  * \param tv Thread Variable containing input/output queue, cpu affinity
947  * \param p Packet which has to be handled in this TCP state.
948  * \param stt Stream Thread module registered to handle the stream handling
949  *
950  * \retval 0 ok
951  * \retval -1 error
952  */
953 static int StreamTcpPacketStateNone(
954  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
955 {
956  if (p->tcph->th_flags & TH_RST) {
958  SCLogDebug("RST packet received, no session setup");
959  return -1;
960 
961  } else if (p->tcph->th_flags & TH_FIN) {
962  /* Drop reason will only be used if midstream policy is set to fail closed */
964 
965  if (!stream_config.midstream || p->payload_len == 0) {
967  SCLogDebug("FIN packet received, no session setup");
968  return -1;
969  }
974  SCLogDebug("FIN packet received, no session setup");
975  return -1;
976  }
977  SCLogDebug("midstream picked up");
978 
979  if (ssn == NULL) {
980  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
981  if (ssn == NULL) {
983  return -1;
984  }
988  }
989  /* set the state */
990  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
991  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
992  "TCP_FIN_WAIT1",
993  ssn);
994 
998  SCLogDebug("ssn %p: =~ ASYNC", ssn);
999  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1000  }
1001 
1002  /** window scaling for midstream pickups, we can't do much other
1003  * than assume that it's set to the max value: 14 */
1004  ssn->client.wscale = TCP_WSCALE_MAX;
1005  ssn->server.wscale = TCP_WSCALE_MAX;
1006 
1007  /* set the sequence numbers and window */
1008  ssn->client.isn = TCP_GET_SEQ(p) - 1;
1010  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1;
1011  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1012  ssn->client.last_ack = TCP_GET_SEQ(p);
1013  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1014  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", ssn, ssn->client.isn,
1015  ssn->client.next_seq);
1016 
1017  ssn->server.isn = TCP_GET_ACK(p) - 1;
1019  ssn->server.next_seq = ssn->server.isn + 1;
1020  ssn->server.last_ack = TCP_GET_ACK(p);
1021  ssn->server.next_win = ssn->server.last_ack;
1022 
1023  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
1024  "ssn->server.next_win %" PRIu32 "",
1025  ssn, ssn->client.next_win, ssn->server.next_win);
1026  SCLogDebug("ssn %p: ssn->client.last_ack %" PRIu32 ", "
1027  "ssn->server.last_ack %" PRIu32 "",
1028  ssn, ssn->client.last_ack, ssn->server.last_ack);
1029 
1030  /* Set the timestamp value for both streams, if packet has timestamp
1031  * option enabled.*/
1032  if (TCP_HAS_TS(p)) {
1033  ssn->client.last_ts = TCP_GET_TSVAL(p);
1034  ssn->server.last_ts = TCP_GET_TSECR(p);
1035  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " "
1036  "ssn->client.last_ts %" PRIu32 "",
1037  ssn, ssn->server.last_ts, ssn->client.last_ts);
1038 
1040 
1041  ssn->client.last_pkt_ts = SCTIME_SECS(p->ts);
1042  if (ssn->server.last_ts == 0)
1044  if (ssn->client.last_ts == 0)
1046 
1047  } else {
1048  ssn->server.last_ts = 0;
1049  ssn->client.last_ts = 0;
1050  }
1051 
1052  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1053 
1054  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1055  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1056 
1057  /* SYN/ACK */
1058  } else if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
1059  /* Drop reason will only be used if midstream policy is set to fail closed */
1061 
1063  SCLogDebug("Midstream not enabled, so won't pick up a session");
1064  return 0;
1065  }
1069  SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1070  return 0;
1071  }
1072  SCLogDebug("midstream picked up");
1073 
1074  if (ssn == NULL) {
1075  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1076  if (ssn == NULL) {
1078  return -1;
1079  }
1083  }
1084 
1085  /* reverse packet and flow */
1086  SCLogDebug("reversing flow and packet");
1087  PacketSwap(p);
1088  FlowSwap(p->flow);
1089 
1090  /* set the state */
1091  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1092  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1093  "TCP_SYN_RECV", ssn);
1095  /* Flag used to change the direct in the later stage in the session */
1098  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1099  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1100  }
1101 
1102  /* sequence number & window */
1103  ssn->server.isn = TCP_GET_SEQ(p);
1105  ssn->server.next_seq = ssn->server.isn + 1;
1106  ssn->server.window = TCP_GET_WINDOW(p);
1107  SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
1108 
1109  ssn->client.isn = TCP_GET_ACK(p) - 1;
1111  ssn->client.next_seq = ssn->client.isn + 1;
1112 
1113  ssn->client.last_ack = TCP_GET_ACK(p);
1114  ssn->server.last_ack = TCP_GET_SEQ(p);
1115 
1116  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1117 
1118  /** If the client has a wscale option the server had it too,
1119  * so set the wscale for the server to max. Otherwise none
1120  * will have the wscale opt just like it should. */
1121  if (TCP_HAS_WSCALE(p)) {
1122  ssn->client.wscale = TCP_GET_WSCALE(p);
1123  ssn->server.wscale = TCP_WSCALE_MAX;
1124  SCLogDebug("ssn %p: wscale enabled. client %u server %u",
1125  ssn, ssn->client.wscale, ssn->server.wscale);
1126  }
1127 
1128  SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
1129  " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
1130  ssn->client.isn, ssn->client.next_seq,
1131  ssn->client.last_ack);
1132  SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
1133  " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
1134  ssn->server.isn, ssn->server.next_seq,
1135  ssn->server.last_ack);
1136 
1137  /* Set the timestamp value for both streams, if packet has timestamp
1138  * option enabled.*/
1139  if (TCP_HAS_TS(p)) {
1140  ssn->server.last_ts = TCP_GET_TSVAL(p);
1141  ssn->client.last_ts = TCP_GET_TSECR(p);
1142  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1143  "ssn->client.last_ts %" PRIu32"", ssn,
1144  ssn->server.last_ts, ssn->client.last_ts);
1145 
1147 
1148  ssn->server.last_pkt_ts = SCTIME_SECS(p->ts);
1149  if (ssn->server.last_ts == 0)
1151  if (ssn->client.last_ts == 0)
1153 
1154  } else {
1155  ssn->server.last_ts = 0;
1156  ssn->client.last_ts = 0;
1157  }
1158 
1159  if (TCP_GET_SACKOK(p) == 1) {
1160  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1161  SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
1162  "SACK permitted for both sides", ssn);
1163  }
1164  return 0;
1165 
1166  } else if (p->tcph->th_flags & TH_SYN) {
1167  if (ssn == NULL) {
1168  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1169  if (ssn == NULL) {
1171  return -1;
1172  }
1173 
1176  }
1177 
1178  /* set the state */
1179  StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
1180  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
1181 
1183  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1184  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1185  }
1186 
1187  /* set the sequence numbers and window */
1188  ssn->client.isn = TCP_GET_SEQ(p);
1190  ssn->client.next_seq = ssn->client.isn + 1;
1191 
1192  /* Set the stream timestamp value, if packet has timestamp option
1193  * enabled. */
1194  if (TCP_HAS_TS(p)) {
1195  ssn->client.last_ts = TCP_GET_TSVAL(p);
1196  SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
1197 
1198  if (ssn->client.last_ts == 0)
1200 
1201  ssn->client.last_pkt_ts = SCTIME_SECS(p->ts);
1203  }
1204 
1205  ssn->server.window = TCP_GET_WINDOW(p);
1206  if (TCP_HAS_WSCALE(p)) {
1208  ssn->server.wscale = TCP_GET_WSCALE(p);
1209  }
1210 
1211  if (TCP_GET_SACKOK(p) == 1) {
1213  SCLogDebug("ssn %p: SACK permitted on SYN packet", ssn);
1214  }
1215 
1216  if (TCP_HAS_TFO(p)) {
1218  if (p->payload_len) {
1219  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
1220  SCLogDebug("ssn: %p (TFO) [len: %d] isn %u base_seq %u next_seq %u payload len %u",
1221  ssn, p->tcpvars.tfo.len, ssn->client.isn, ssn->client.base_seq, ssn->client.next_seq, p->payload_len);
1222  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1223  }
1224  }
1225 
1226  SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
1227  "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
1228  "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
1229  ssn->client.last_ack);
1230 
1231  } else if (p->tcph->th_flags & TH_ACK) {
1232  /* Drop reason will only be used if midstream policy is set to fail closed */
1234 
1235  if (!stream_config.midstream) {
1236  SCLogDebug("Midstream not enabled, so won't pick up a session");
1237  return 0;
1238  }
1242  SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1243  return 0;
1244  }
1245  SCLogDebug("midstream picked up");
1246 
1247  if (ssn == NULL) {
1248  ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1249  if (ssn == NULL) {
1251  return -1;
1252  }
1256  }
1257  /* set the state */
1258  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1259  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1260  "TCP_ESTABLISHED", ssn);
1261 
1265  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1266  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1267  }
1268 
1269  /** window scaling for midstream pickups, we can't do much other
1270  * than assume that it's set to the max value: 14 */
1271  ssn->client.wscale = TCP_WSCALE_MAX;
1272  ssn->server.wscale = TCP_WSCALE_MAX;
1273 
1274  /* set the sequence numbers and window */
1275  ssn->client.isn = TCP_GET_SEQ(p) - 1;
1277  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
1278  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1279  ssn->client.last_ack = TCP_GET_SEQ(p);
1280  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1281  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
1282  ssn, ssn->client.isn, ssn->client.next_seq);
1283 
1284  ssn->server.isn = TCP_GET_ACK(p) - 1;
1286  ssn->server.next_seq = ssn->server.isn + 1;
1287  ssn->server.last_ack = TCP_GET_ACK(p);
1288  ssn->server.next_win = ssn->server.last_ack;
1289 
1290  SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
1291  "ssn->server.next_win %"PRIu32"", ssn,
1292  ssn->client.next_win, ssn->server.next_win);
1293  SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
1294  "ssn->server.last_ack %"PRIu32"", ssn,
1295  ssn->client.last_ack, ssn->server.last_ack);
1296 
1297  /* Set the timestamp value for both streams, if packet has timestamp
1298  * option enabled.*/
1299  if (TCP_HAS_TS(p)) {
1300  ssn->client.last_ts = TCP_GET_TSVAL(p);
1301  ssn->server.last_ts = TCP_GET_TSECR(p);
1302  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1303  "ssn->client.last_ts %" PRIu32"", ssn,
1304  ssn->server.last_ts, ssn->client.last_ts);
1305 
1307 
1308  ssn->client.last_pkt_ts = SCTIME_SECS(p->ts);
1309  if (ssn->server.last_ts == 0)
1311  if (ssn->client.last_ts == 0)
1313 
1314  } else {
1315  ssn->server.last_ts = 0;
1316  ssn->client.last_ts = 0;
1317  }
1318 
1319  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1320 
1321  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1322  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1323 
1324  } else {
1325  SCLogDebug("default case");
1326  }
1327 
1328  return 0;
1329 }
1330 
1331 /** \internal
1332  * \brief Setup TcpStateQueue based on SYN/ACK packet
1333  */
1334 static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
1335 {
1336  q->flags = 0;
1337  q->wscale = 0;
1338  q->ts = 0;
1339  q->win = TCP_GET_WINDOW(p);
1340  q->seq = TCP_GET_SEQ(p);
1341  q->ack = TCP_GET_ACK(p);
1342  q->pkt_ts = SCTIME_SECS(p->ts);
1343 
1344  if (TCP_GET_SACKOK(p) == 1)
1346 
1347  if (TCP_HAS_WSCALE(p)) {
1349  q->wscale = TCP_GET_WSCALE(p);
1350  }
1351  if (TCP_HAS_TS(p)) {
1353  q->ts = TCP_GET_TSVAL(p);
1354  }
1355 }
1356 
1357 /** \internal
1358  * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
1359  * \retval q or NULL */
1360 static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
1361 {
1362  TcpStateQueue *q = ssn->queue;
1363  TcpStateQueue search;
1364 
1365  StreamTcp3whsSynAckToStateQueue(p, &search);
1366 
1367  while (q != NULL) {
1368  if (search.flags == q->flags &&
1369  search.wscale == q->wscale &&
1370  search.win == q->win &&
1371  search.seq == q->seq &&
1372  search.ack == q->ack &&
1373  search.ts == q->ts) {
1374  return q;
1375  }
1376 
1377  q = q->next;
1378  }
1379 
1380  return q;
1381 }
1382 
1383 static int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
1384 {
1385  /* first see if this is already in our list */
1386  if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
1387  return 0;
1388 
1390  SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
1392  return -1;
1393  }
1394 
1395  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1396  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
1397  return -1;
1398  }
1399 
1400  TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1401  if (unlikely(q == NULL)) {
1402  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
1403  return -1;
1404  }
1405  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1406 
1407  StreamTcp3whsSynAckToStateQueue(p, q);
1408 
1409  /* put in list */
1410  q->next = ssn->queue;
1411  ssn->queue = q;
1412  ssn->queue_len++;
1413  return 0;
1414 }
1415 
1416 /** \internal
1417  * \brief Find the Queued SYN/ACK that goes with this ACK
1418  * \retval q or NULL */
1419 static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
1420 {
1421  uint32_t ack = TCP_GET_SEQ(p);
1422  uint32_t seq = TCP_GET_ACK(p) - 1;
1423  TcpStateQueue *q = ssn->queue;
1424 
1425  while (q != NULL) {
1426  if (seq == q->seq &&
1427  ack == q->ack) {
1428  return q;
1429  }
1430 
1431  q = q->next;
1432  }
1433 
1434  return NULL;
1435 }
1436 
1437 /** \internal
1438  * \brief Update SSN after receiving a valid SYN/ACK
1439  *
1440  * Normally we update the SSN from the SYN/ACK packet. But in case
1441  * of queued SYN/ACKs, we can use one of those.
1442  *
1443  * \param ssn TCP session
1444  * \param p Packet
1445  * \param q queued state if used, NULL otherwise
1446  *
1447  * To make sure all SYN/ACK based state updates are in one place,
1448  * this function can updated based on Packet or TcpStateQueue, where
1449  * the latter takes precedence.
1450  */
1451 static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
1452 {
1453  TcpStateQueue update;
1454  if (likely(q == NULL)) {
1455  StreamTcp3whsSynAckToStateQueue(p, &update);
1456  q = &update;
1457  }
1458 
1459  if (ssn->state != TCP_SYN_RECV) {
1460  /* update state */
1461  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1462  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
1463  }
1464  /* sequence number & window */
1465  ssn->server.isn = q->seq;
1467  ssn->server.next_seq = ssn->server.isn + 1;
1468 
1469  ssn->client.window = q->win;
1470  SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
1471 
1472  /* Set the timestamp values used to validate the timestamp of
1473  * received packets.*/
1474  if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
1476  {
1477  ssn->server.last_ts = q->ts;
1478  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1479  "ssn->client.last_ts %" PRIu32"", ssn,
1480  ssn->server.last_ts, ssn->client.last_ts);
1482  ssn->server.last_pkt_ts = q->pkt_ts;
1483  if (ssn->server.last_ts == 0)
1485  } else {
1486  ssn->client.last_ts = 0;
1487  ssn->server.last_ts = 0;
1489  }
1490 
1491  ssn->client.last_ack = q->ack;
1492  ssn->server.last_ack = ssn->server.isn + 1;
1493 
1494  /** check for the presence of the ws ptr to determine if we
1495  * support wscale at all */
1496  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1498  {
1499  ssn->client.wscale = q->wscale;
1500  } else {
1501  ssn->client.wscale = 0;
1502  }
1503 
1504  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1506  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1507  SCLogDebug("ssn %p: SACK permitted for session", ssn);
1508  } else {
1509  ssn->flags &= ~STREAMTCP_FLAG_SACKOK;
1510  }
1511 
1512  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1513  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1514  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
1515  ssn->server.next_win);
1516  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
1517  ssn->client.next_win);
1518  SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
1519  "ssn->server.next_seq %" PRIu32 ", "
1520  "ssn->server.last_ack %" PRIu32 " "
1521  "(ssn->client.last_ack %" PRIu32 ")", ssn,
1522  ssn->server.isn, ssn->server.next_seq,
1523  ssn->server.last_ack, ssn->client.last_ack);
1524 
1525  /* unset the 4WHS flag as we received this SYN/ACK as part of a
1526  * (so far) valid 3WHS */
1527  if (ssn->flags & STREAMTCP_FLAG_4WHS)
1528  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
1529  " so considering 3WHS", ssn);
1530 
1531  ssn->flags &=~ STREAMTCP_FLAG_4WHS;
1532 }
1533 
1534 /** \internal
1535  * \brief detect timestamp anomalies when processing responses to the
1536  * SYN packet.
1537  * \retval true packet is ok
1538  * \retval false packet is bad
1539  */
1540 static inline bool StateSynSentValidateTimestamp(TcpSession *ssn, Packet *p)
1541 {
1542  /* we only care about evil server here, so skip TS packets */
1543  if (PKT_IS_TOSERVER(p) || !(TCP_HAS_TS(p))) {
1544  return true;
1545  }
1546 
1547  TcpStream *receiver_stream = &ssn->client;
1548  const uint32_t ts_echo = TCP_GET_TSECR(p);
1549  if ((receiver_stream->flags & STREAMTCP_STREAM_FLAG_TIMESTAMP) != 0) {
1550  if (receiver_stream->last_ts != 0 && ts_echo != 0 &&
1551  ts_echo != receiver_stream->last_ts)
1552  {
1553  SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn,
1554  ts_echo, receiver_stream->last_ts);
1555  return false;
1556  }
1557  } else {
1558  if (receiver_stream->last_ts == 0 && ts_echo != 0) {
1559  SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn,
1560  ts_echo, receiver_stream->last_ts);
1561  return false;
1562  }
1563  }
1564  return true;
1565 }
1566 
1567 static void TcpStateQueueInitFromSsnSyn(const TcpSession *ssn, TcpStateQueue *q)
1568 {
1569  BUG_ON(ssn->state != TCP_SYN_SENT); // TODO
1570  memset(q, 0, sizeof(*q));
1571 
1572  /* SYN won't use wscale yet. So window should be limited to 16 bits. */
1573  DEBUG_VALIDATE_BUG_ON(ssn->server.window > UINT16_MAX);
1574  q->win = (uint16_t)ssn->server.window;
1575 
1576  q->pkt_ts = ssn->client.last_pkt_ts;
1577 
1578  if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
1580  }
1581  if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
1583  q->wscale = ssn->server.wscale;
1584  }
1587  q->ts = ssn->client.last_ts;
1588  }
1589 
1590  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1592 }
1593 
1594 static void TcpStateQueueInitFromPktSyn(const Packet *p, TcpStateQueue *q)
1595 {
1596 #if defined(DEBUG_VALIDATION) || defined(DEBUG)
1597  const TcpSession *ssn = p->flow->protoctx;
1598  BUG_ON(ssn->state != TCP_SYN_SENT);
1599 #endif
1600  memset(q, 0, sizeof(*q));
1601 
1602  q->win = TCP_GET_WINDOW(p);
1603  q->pkt_ts = SCTIME_SECS(p->ts);
1604 
1605  if (TCP_GET_SACKOK(p) == 1) {
1607  }
1608  if (TCP_HAS_WSCALE(p)) {
1610  q->wscale = TCP_GET_WSCALE(p);
1611  }
1612  if (TCP_HAS_TS(p)) {
1614  q->ts = TCP_GET_TSVAL(p);
1615  }
1616 
1617 #if defined(DEBUG)
1618  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1620 #endif
1621 }
1622 
1623 static void TcpStateQueueInitFromPktSynAck(const Packet *p, TcpStateQueue *q)
1624 {
1625 #if defined(DEBUG_VALIDATION) || defined(DEBUG)
1626  const TcpSession *ssn = p->flow->protoctx;
1627  if ((ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) == 0)
1628  BUG_ON(ssn->state != TCP_SYN_SENT);
1629  else
1630  BUG_ON(ssn->state != TCP_ESTABLISHED);
1631 #endif
1632  memset(q, 0, sizeof(*q));
1633 
1634  q->win = TCP_GET_WINDOW(p);
1635  q->pkt_ts = SCTIME_SECS(p->ts);
1636 
1637  if (TCP_GET_SACKOK(p) == 1) {
1639  }
1640  if (TCP_HAS_WSCALE(p)) {
1642  q->wscale = TCP_GET_WSCALE(p);
1643  }
1644  if (TCP_HAS_TS(p)) {
1646  q->ts = TCP_GET_TSECR(p);
1647  }
1648 
1649 #if defined(DEBUG)
1650  SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1652 #endif
1653 }
1654 
1655 /** \internal
1656  * \brief Find the Queued SYN that is the same as this SYN/ACK
1657  * \retval q or NULL */
1658 static const TcpStateQueue *StreamTcp3whsFindSyn(const TcpSession *ssn, TcpStateQueue *s)
1659 {
1660  SCLogDebug("ssn %p: search state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, s, s->seq, s->win,
1662 
1663  for (const TcpStateQueue *q = ssn->queue; q != NULL; q = q->next) {
1664  SCLogDebug("ssn %p: queue state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq,
1665  q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS), q->ts);
1667  s->ts == q->ts) {
1668  return q;
1669  }
1670  }
1671  return NULL;
1672 }
1673 
1674 /** \note the SEQ values *must* be the same */
1675 static int StreamTcp3whsStoreSyn(TcpSession *ssn, Packet *p)
1676 {
1677  TcpStateQueue search;
1678  TcpStateQueueInitFromSsnSyn(ssn, &search);
1679 
1680  /* first see if this is already in our list */
1681  if (ssn->queue != NULL && StreamTcp3whsFindSyn(ssn, &search) != NULL)
1682  return 0;
1683 
1684  if (ssn->queue_len == stream_config.max_syn_queued) {
1685  SCLogDebug("ssn %p: =~ SYN queue limit reached", ssn);
1687  return -1;
1688  }
1689 
1690  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1691  SCLogDebug("ssn %p: =~ SYN queue failed: stream memcap reached", ssn);
1692  return -1;
1693  }
1694 
1695  TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1696  if (unlikely(q == NULL)) {
1697  SCLogDebug("ssn %p: =~ SYN queue failed: alloc failed", ssn);
1698  return -1;
1699  }
1700  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1701 
1702  *q = search;
1703  /* put in list */
1704  q->next = ssn->queue;
1705  ssn->queue = q;
1706  ssn->queue_len++;
1707  return 0;
1708 }
1709 
1710 static inline void StreamTcp3whsStoreSynApplyToSsn(TcpSession *ssn, const TcpStateQueue *q)
1711 {
1712  if (q->flags & STREAMTCP_QUEUE_FLAG_TS) {
1713  ssn->client.last_pkt_ts = q->pkt_ts;
1714  ssn->client.last_ts = q->ts;
1716  SCLogDebug("ssn: %p client.last_ts updated to %u", ssn, ssn->client.last_ts);
1717  }
1718  if (q->flags & STREAMTCP_QUEUE_FLAG_WS) {
1720  ssn->server.wscale = q->wscale;
1721  } else {
1723  ssn->server.wscale = 0;
1724  }
1725  ssn->server.window = q->win;
1726 
1727  if (q->flags & STREAMTCP_QUEUE_FLAG_SACK) {
1729  } else {
1731  }
1732 }
1733 
1734 /**
1735  * \brief Function to handle the TCP_SYN_SENT state. The function handles
1736  * SYN, SYN/ACK, RST packets and correspondingly changes the connection
1737  * state.
1738  *
1739  * \param tv Thread Variable containing input/output queue, cpu affinity
1740  * \param p Packet which has to be handled in this TCP state.
1741  * \param stt Stream Thread module registered to handle the stream handling
1742  */
1743 
1744 static int StreamTcpPacketStateSynSent(
1745  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
1746 {
1747  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
1748 
1749  SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ? "toclient" : "toserver");
1750 
1751  /* common case: SYN/ACK from server to client */
1752  if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOCLIENT(p)) {
1753  SCLogDebug("ssn %p: SYN/ACK on SYN_SENT state for packet %" PRIu64, ssn, p->pcap_cnt);
1754 
1755  if (!(TCP_HAS_TFO(p) || (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN))) {
1756  /* Check if the SYN/ACK packet ack's the earlier
1757  * received SYN packet. */
1758  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) {
1760  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1761  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1762  ssn->client.isn + 1);
1763  return -1;
1764  }
1765  } else {
1766  if (SEQ_EQ(TCP_GET_ACK(p), ssn->client.next_seq)) {
1767  SCLogDebug("ssn %p: (TFO) ACK matches next_seq, packet ACK %" PRIu32 " == "
1768  "%" PRIu32 " from stream",
1769  ssn, TCP_GET_ACK(p), ssn->client.next_seq);
1770  } else if (SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1)) {
1771  SCLogDebug("ssn %p: (TFO) ACK matches ISN+1, packet ACK %" PRIu32 " == "
1772  "%" PRIu32 " from stream",
1773  ssn, TCP_GET_ACK(p), ssn->client.isn + 1);
1774  ssn->client.next_seq = ssn->client.isn; // reset to ISN
1775  SCLogDebug("ssn %p: (TFO) next_seq reset to isn (%u)", ssn, ssn->client.next_seq);
1778  } else {
1780  SCLogDebug("ssn %p: (TFO) ACK mismatch, packet ACK %" PRIu32 " != "
1781  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1782  ssn->client.next_seq);
1783  return -1;
1784  }
1786  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1787  }
1788 
1789  const bool ts_mismatch = !StateSynSentValidateTimestamp(ssn, p);
1790  if (ts_mismatch) {
1791  SCLogDebug("ssn %p: ts_mismatch:%s", ssn, BOOL2STR(ts_mismatch));
1792  if (ssn->queue) {
1793  TcpStateQueue search;
1794  TcpStateQueueInitFromPktSynAck(p, &search);
1795 
1796  const TcpStateQueue *q = StreamTcp3whsFindSyn(ssn, &search);
1797  if (q == NULL) {
1798  SCLogDebug("not found: mismatch");
1800  return -1;
1801  }
1802  SCLogDebug("ssn %p: found queued SYN state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u",
1803  ssn, q, q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS),
1804  q->ts);
1805 
1806  StreamTcp3whsStoreSynApplyToSsn(ssn, q);
1807 
1808  } else {
1809  SCLogDebug("not found: no queue");
1811  return -1;
1812  }
1813  }
1814 
1815  /* clear ssn->queue on state change: TcpSession can be reused by SYN/ACK */
1816  StreamTcp3wsFreeQueue(ssn);
1817 
1818  StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
1819  return 0;
1820 
1821  } else if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOSERVER(p)) {
1822 
1823  if (!(ssn->flags & STREAMTCP_FLAG_4WHS)) {
1825  SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
1826  return -1;
1827  }
1828 
1829  SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
1830 
1831  /* Check if the SYN/ACK packet ack's the earlier
1832  * received SYN packet. */
1833  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->server.isn + 1))) {
1835 
1836  SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %" PRIu32 ""
1837  " != %" PRIu32 " from stream",
1838  ssn, TCP_GET_ACK(p), ssn->server.isn + 1);
1839  return -1;
1840  }
1841 
1842  /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
1843  * packet. */
1844  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
1846 
1847  SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %" PRIu32 ""
1848  " != %" PRIu32 " from *first* SYN pkt",
1849  ssn, TCP_GET_SEQ(p), ssn->client.isn);
1850  return -1;
1851  }
1852 
1853  /* update state */
1854  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1855  SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
1856 
1857  /* sequence number & window */
1858  ssn->client.isn = TCP_GET_SEQ(p);
1860  ssn->client.next_seq = ssn->client.isn + 1;
1861 
1862  ssn->server.window = TCP_GET_WINDOW(p);
1863  SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn, ssn->client.window);
1864 
1865  /* Set the timestamp values used to validate the timestamp of
1866  * received packets. */
1867  if ((TCP_HAS_TS(p)) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) {
1868  ssn->client.last_ts = TCP_GET_TSVAL(p);
1869  SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32 " "
1870  "ssn->server.last_ts %" PRIu32 "",
1871  ssn, ssn->client.last_ts, ssn->server.last_ts);
1873  ssn->client.last_pkt_ts = SCTIME_SECS(p->ts);
1874  if (ssn->client.last_ts == 0)
1876  } else {
1877  ssn->server.last_ts = 0;
1878  ssn->client.last_ts = 0;
1880  }
1881 
1882  ssn->server.last_ack = TCP_GET_ACK(p);
1883  ssn->client.last_ack = ssn->client.isn + 1;
1884 
1885  /** check for the presense of the ws ptr to determine if we
1886  * support wscale at all */
1887  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && (TCP_HAS_WSCALE(p))) {
1888  ssn->server.wscale = TCP_GET_WSCALE(p);
1889  } else {
1890  ssn->server.wscale = 0;
1891  }
1892 
1893  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) && TCP_GET_SACKOK(p) == 1) {
1894  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1895  SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
1896  }
1897 
1898  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1899  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1900  SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win);
1901  SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win);
1902  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
1903  "ssn->client.next_seq %" PRIu32 ", "
1904  "ssn->client.last_ack %" PRIu32 " "
1905  "(ssn->server.last_ack %" PRIu32 ")",
1906  ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack,
1907  ssn->server.last_ack);
1908 
1909  /* done here */
1910  return 0;
1911  }
1912 
1913  /* check for bad responses */
1914  if (StateSynSentValidateTimestamp(ssn, p) == false) {
1916  return -1;
1917  }
1918 
1919  /* RST */
1920  if (p->tcph->th_flags & TH_RST) {
1921 
1922  if (!StreamTcpValidateRst(ssn, p))
1923  return -1;
1924 
1925  if (PKT_IS_TOSERVER(p)) {
1926  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) && SEQ_EQ(TCP_GET_WINDOW(p), 0) &&
1927  SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) {
1928  SCLogDebug("ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
1930  StreamTcpCloseSsnWithReset(p, ssn);
1931  StreamTcp3wsFreeQueue(ssn);
1932  }
1933  } else {
1935  SCLogDebug("ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
1936  StreamTcpCloseSsnWithReset(p, ssn);
1937  StreamTcp3wsFreeQueue(ssn);
1938  }
1939 
1940  /* FIN */
1941  } else if (p->tcph->th_flags & TH_FIN) {
1942  /** \todo */
1943 
1944  } else if (p->tcph->th_flags & TH_SYN) {
1945  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
1946  if (ssn->flags & STREAMTCP_FLAG_4WHS) {
1947  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
1948  "4WHS SYN", ssn);
1949  }
1950 
1951  if (PKT_IS_TOCLIENT(p)) {
1952  /** a SYN only packet in the opposite direction could be:
1953  * http://www.breakingpointsystems.com/community/blog/tcp-
1954  * portals-the-three-way-handshake-is-a-lie
1955  *
1956  * \todo improve resetting the session */
1957 
1958  /* indicate that we're dealing with 4WHS here */
1959  ssn->flags |= STREAMTCP_FLAG_4WHS;
1960  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
1961 
1962  /* set the sequence numbers and window for server
1963  * We leave the ssn->client.isn in place as we will
1964  * check the SYN/ACK pkt with that.
1965  */
1966  ssn->server.isn = TCP_GET_SEQ(p);
1968  ssn->server.next_seq = ssn->server.isn + 1;
1969 
1970  /* Set the stream timestamp value, if packet has timestamp
1971  * option enabled. */
1972  if (TCP_HAS_TS(p)) {
1973  ssn->server.last_ts = TCP_GET_TSVAL(p);
1974  SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
1975 
1976  if (ssn->server.last_ts == 0)
1978  ssn->server.last_pkt_ts = SCTIME_SECS(p->ts);
1980  }
1981 
1982  ssn->server.window = TCP_GET_WINDOW(p);
1983  if (TCP_HAS_WSCALE(p)) {
1985  ssn->server.wscale = TCP_GET_WSCALE(p);
1986  } else {
1988  ssn->server.wscale = 0;
1989  }
1990 
1991  if (TCP_GET_SACKOK(p) == 1) {
1993  } else {
1995  }
1996 
1997  SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
1998  "ssn->server.next_seq %" PRIu32 ", "
1999  "ssn->server.last_ack %"PRIu32"", ssn,
2000  ssn->server.isn, ssn->server.next_seq,
2001  ssn->server.last_ack);
2002  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2003  "ssn->client.next_seq %" PRIu32 ", "
2004  "ssn->client.last_ack %"PRIu32"", ssn,
2005  ssn->client.isn, ssn->client.next_seq,
2006  ssn->client.last_ack);
2007  } else if (PKT_IS_TOSERVER(p)) {
2008  /* on a SYN resend we queue up the SYN's until a SYN/ACK moves the state
2009  * to SYN_RECV. We update the ssn to the most recent, as it is most likely
2010  * to be correct. */
2011 
2012  TcpStateQueue syn_pkt, syn_ssn;
2013  TcpStateQueueInitFromPktSyn(p, &syn_pkt);
2014  TcpStateQueueInitFromSsnSyn(ssn, &syn_ssn);
2015 
2016  if (memcmp(&syn_pkt, &syn_ssn, sizeof(TcpStateQueue)) != 0) {
2017  /* store the old session settings */
2018  StreamTcp3whsStoreSyn(ssn, p);
2019  SCLogDebug("ssn %p: Retransmitted SYN. Updating ssn from packet %" PRIu64
2020  ". Stored previous state",
2021  ssn, p->pcap_cnt);
2022  }
2023  StreamTcp3whsStoreSynApplyToSsn(ssn, &syn_pkt);
2024  }
2025  } else if (p->tcph->th_flags & TH_ACK) {
2026  /* Handle the asynchronous stream, when we receive a SYN packet
2027  and now instead of receiving a SYN/ACK we receive a ACK from the
2028  same host, which sent the SYN, this suggests the ASYNC streams.*/
2030  return 0;
2031 
2032  /* we are in ASYNC (one side) mode now. */
2033 
2034  /* one side async means we won't see a SYN/ACK, so we can
2035  * only check the SYN. */
2036  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) {
2038 
2039  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2040  "%" PRIu32 " from stream",ssn, TCP_GET_SEQ(p),
2041  ssn->client.next_seq);
2042  return -1;
2043  }
2044 
2045  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2046  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2047  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2048  StreamTcp3wsFreeQueue(ssn);
2049 
2050  ssn->client.window = TCP_GET_WINDOW(p);
2051  ssn->client.last_ack = TCP_GET_SEQ(p);
2052  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2053 
2054  /* Set the server side parameters */
2055  ssn->server.isn = TCP_GET_ACK(p) - 1;
2057  ssn->server.next_seq = ssn->server.isn + 1;
2058  ssn->server.last_ack = ssn->server.next_seq;
2059  ssn->server.next_win = ssn->server.last_ack;
2060 
2061  SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
2062  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2063  "ssn->client.next_seq %" PRIu32 ""
2064  ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
2065  + p->payload_len, ssn->client.next_seq);
2066 
2067  /* if SYN had wscale, assume it to be supported. Otherwise
2068  * we know it not to be supported. */
2069  if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
2070  ssn->client.wscale = TCP_WSCALE_MAX;
2071  }
2072 
2073  /* Set the timestamp values used to validate the timestamp of
2074  * received packets.*/
2075  if (TCP_HAS_TS(p) &&
2077  {
2080  ssn->client.last_pkt_ts = SCTIME_SECS(p->ts);
2081  } else {
2082  ssn->client.last_ts = 0;
2084  }
2085 
2086  if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
2087  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2088  }
2089 
2090  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2091 
2092  } else {
2093  SCLogDebug("ssn %p: default case", ssn);
2094  }
2095 
2096  return 0;
2097 }
2098 
2099 /**
2100  * \brief Function to handle the TCP_SYN_RECV state. The function handles
2101  * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
2102  * the connection state.
2103  *
2104  * \param tv Thread Variable containing input/output queue, cpu affinity
2105  * \param p Packet which has to be handled in this TCP state.
2106  * \param stt Stream Thread module registered to handle the stream handling
2107  *
2108  * \retval 0 ok
2109  * \retval -1 error
2110  */
2111 
2112 static int StreamTcpPacketStateSynRecv(
2113  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
2114 {
2115  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
2116 
2117  if (p->tcph->th_flags & TH_RST) {
2118  if (!StreamTcpValidateRst(ssn, p))
2119  return -1;
2120 
2121  bool reset = true;
2122  /* After receiving the RST in SYN_RECV state and if detection
2123  evasion flags has been set, then the following operating
2124  systems will not closed the connection. As they consider the
2125  packet as stray packet and not belonging to the current
2126  session, for more information check
2127  http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
2129  if (PKT_IS_TOSERVER(p)) {
2130  if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
2131  (ssn->server.os_policy == OS_POLICY_OLD_LINUX) ||
2133  {
2134  reset = false;
2135  SCLogDebug("Detection evasion has been attempted, so"
2136  " not resetting the connection !!");
2137  }
2138  } else {
2139  if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
2140  (ssn->client.os_policy == OS_POLICY_OLD_LINUX) ||
2142  {
2143  reset = false;
2144  SCLogDebug("Detection evasion has been attempted, so"
2145  " not resetting the connection !!");
2146  }
2147  }
2148  }
2149 
2150  if (reset) {
2151  StreamTcpCloseSsnWithReset(p, ssn);
2152 
2153  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2154  StreamTcpHandleTimestamp(ssn, p);
2155  }
2156  }
2157 
2158  } else if (p->tcph->th_flags & TH_FIN) {
2159  /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
2160  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2161  if (!StreamTcpValidateTimestamp(ssn, p))
2162  return -1;
2163  }
2164 
2165  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
2166  return -1;
2167 
2168  /* SYN/ACK */
2169  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
2170  SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
2171 
2172  if (PKT_IS_TOSERVER(p)) {
2173  SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
2174 
2176  return -1;
2177  }
2178 
2179  /* Check if the SYN/ACK packets ACK matches the earlier
2180  * received SYN/ACK packet. */
2181  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
2182  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
2183  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
2184  ssn->client.isn + 1);
2185 
2187  return -1;
2188  }
2189 
2190  /* Check if the SYN/ACK packet SEQ the earlier
2191  * received SYN/ACK packet, server resend with different ISN. */
2192  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
2193  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2194  "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
2195  ssn->client.isn);
2196 
2197  if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
2198  return -1;
2199  SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
2200  }
2201 
2202  } else if (p->tcph->th_flags & TH_SYN) {
2203  SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
2204 
2205  if (PKT_IS_TOCLIENT(p)) {
2206  SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
2207 
2209  return -1;
2210  }
2211 
2212  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
2213  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
2214 
2216  return -1;
2217  }
2218 
2219  } else if (p->tcph->th_flags & TH_ACK) {
2220  if (ssn->queue_len) {
2221  SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
2222  TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
2223  if (q != NULL) {
2224  SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
2225  StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
2226  } else {
2227  SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
2228  }
2229  }
2230 
2231 
2232  /* If the timestamp option is enabled for both the streams, then
2233  * validate the received packet timestamp value against the
2234  * stream->last_ts. If the timestamp is valid then process the
2235  * packet normally otherwise the drop the packet (RFC 1323)*/
2236  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2237  if (!(StreamTcpValidateTimestamp(ssn, p))) {
2238  return -1;
2239  }
2240  }
2241 
2242  if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) {
2243  SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
2244 
2245  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) {
2246  SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
2248  return -1;
2249  }
2250 
2251  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2252  SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
2254  return -1;
2255  }
2256 
2257  SCLogDebug("4WHS normal pkt");
2258  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2259  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2260  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2261 
2262  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2263  StreamTcpHandleTimestamp(ssn, p);
2264  }
2265 
2266  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2267  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2268  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2269  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2270 
2271  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2272  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2273 
2274  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2275 
2276  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
2277  "ssn->client.last_ack %"PRIu32"", ssn,
2278  ssn->client.next_win, ssn->client.last_ack);
2279  return 0;
2280  }
2281 
2282  bool ack_indicates_missed_3whs_ack_packet = false;
2283  /* Check if the ACK received is in right direction. But when we have
2284  * picked up a mid stream session after missing the initial SYN pkt,
2285  * in this case the ACK packet can arrive from either client (normal
2286  * case) or from server itself (asynchronous streams). Therefore
2287  * the check has been avoided in this case */
2288  if (PKT_IS_TOCLIENT(p)) {
2289  /* special case, handle 4WHS, so SYN/ACK in the opposite
2290  * direction */
2292  SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
2293  "pickup session",ssn);
2294  /* fall through */
2295  } else if (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) {
2296  SCLogDebug("ssn %p: ACK received on TFO session",ssn);
2297  /* fall through */
2298 
2299  } else {
2300  /* if we missed traffic between the S/SA and the current
2301  * 'wrong direction' ACK, we could end up here. In IPS
2302  * reject it. But in IDS mode we continue.
2303  *
2304  * IPS rejects as it should see all packets, so pktloss
2305  * should lead to retransmissions. As this can also be
2306  * pattern for MOTS/MITM injection attacks, we need to be
2307  * careful.
2308  */
2309  if (StreamTcpInlineMode()) {
2310  if (p->payload_len > 0 &&
2311  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) &&
2312  SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
2313  /* packet loss is possible but unlikely here */
2314  SCLogDebug("ssn %p: possible data injection", ssn);
2316  return -1;
2317  }
2318 
2319  SCLogDebug("ssn %p: ACK received in the wrong direction",
2320  ssn);
2322  return -1;
2323  }
2324  ack_indicates_missed_3whs_ack_packet = true;
2325  }
2326  }
2327 
2328  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
2329  ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
2330  TCP_GET_ACK(p));
2331 
2332  /* Check both seq and ack number before accepting the packet and
2333  changing to ESTABLISHED state */
2334  if ((SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) &&
2335  SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) {
2336  SCLogDebug("normal pkt");
2337 
2338  /* process the packet normal, No Async streams :) */
2339 
2340  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2341  StreamTcpHandleTimestamp(ssn, p);
2342  }
2343 
2344  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2345  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2346  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2347 
2348  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2349 
2350  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2351  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2352  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2353  ssn->server.next_win = ssn->server.last_ack +
2354  ssn->server.window;
2355  if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
2356  /* window scaling for midstream pickups, we can't do much
2357  * other than assume that it's set to the max value: 14 */
2358  ssn->server.wscale = TCP_WSCALE_MAX;
2359  ssn->client.wscale = TCP_WSCALE_MAX;
2360  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2361  }
2362  }
2363 
2364  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2365  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2366 
2367  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2368 
2369  /* If asynchronous stream handling is allowed then set the session,
2370  if packet's seq number is equal the expected seq no.*/
2371  } else if (stream_config.async_oneside && (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) {
2372  /*set the ASYNC flag used to indicate the session as async stream
2373  and helps in relaxing the windows checks.*/
2374  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2375  ssn->server.next_seq += p->payload_len;
2376  ssn->server.last_ack = TCP_GET_SEQ(p);
2377 
2378  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2379  ssn->client.last_ack = TCP_GET_ACK(p);
2380 
2381  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2382  StreamTcpHandleTimestamp(ssn, p);
2383  }
2384 
2385  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2386  ssn->server.window = TCP_GET_WINDOW(p);
2387  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2388  /* window scaling for midstream pickups, we can't do much
2389  * other than assume that it's set to the max value: 14 */
2390  ssn->server.wscale = TCP_WSCALE_MAX;
2391  ssn->client.wscale = TCP_WSCALE_MAX;
2392  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2393  }
2394 
2395  SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
2396  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2397  "ssn->server.next_seq %" PRIu32
2398  , ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
2399  + p->payload_len, ssn->server.next_seq);
2400 
2401  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2402  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2403 
2404  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2405  /* Upon receiving the packet with correct seq number and wrong
2406  ACK number, it causes the other end to send RST. But some target
2407  system (Linux & solaris) does not RST the connection, so it is
2408  likely to avoid the detection */
2409  } else if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {
2411  SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
2412  ssn);
2413 
2415  return -1;
2416 
2417  /* SYN/ACK followed by more TOCLIENT suggesting packet loss */
2418  } else if (PKT_IS_TOCLIENT(p) && !StreamTcpInlineMode() &&
2419  SEQ_GT(TCP_GET_SEQ(p), ssn->client.next_seq) &&
2420  SEQ_GT(TCP_GET_ACK(p), ssn->client.last_ack)) {
2421  SCLogDebug("ssn %p: ACK for missing data", ssn);
2422 
2423  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2424  StreamTcpHandleTimestamp(ssn, p);
2425  }
2426 
2427  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2428 
2429  ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2430  SCLogDebug("ssn %p: ACK for missing data: ssn->server.next_seq %u", ssn,
2431  ssn->server.next_seq);
2432  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2433 
2434  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2435 
2436  ssn->client.window = TCP_GET_WINDOW(p);
2437  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2438 
2439  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2440  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2441 
2442  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2443 
2444  /* if we get a packet with a proper ack, but a seq that is beyond
2445  * next_seq but in-window, we probably missed some packets */
2446  } else if (SEQ_GT(TCP_GET_SEQ(p), ssn->client.next_seq) &&
2447  SEQ_LEQ(TCP_GET_SEQ(p), ssn->client.next_win) &&
2448  SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) {
2449  SCLogDebug("ssn %p: ACK for missing data", ssn);
2450 
2451  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2452  StreamTcpHandleTimestamp(ssn, p);
2453  }
2454 
2455  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2456  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2457 
2458  SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
2459  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2460  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2461 
2462  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2463  ssn->client.window = TCP_GET_WINDOW(p);
2464  ssn->server.next_win = ssn->server.last_ack +
2465  ssn->server.window;
2466  /* window scaling for midstream pickups, we can't do much
2467  * other than assume that it's set to the max value: 14 */
2468  ssn->server.wscale = TCP_WSCALE_MAX;
2469  ssn->client.wscale = TCP_WSCALE_MAX;
2470  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2471  }
2472 
2473  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2474  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2475 
2476  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2477 
2478  /* toclient packet: after having missed the 3whs's final ACK */
2479  } else if ((ack_indicates_missed_3whs_ack_packet ||
2480  (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN)) &&
2481  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) &&
2482  SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
2483  if (ack_indicates_missed_3whs_ack_packet) {
2484  SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2485  } else {
2486  SCLogDebug("ssn %p: (TFO) expected packet fits perfectly after SYN/ACK", ssn);
2487  }
2488 
2489  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2490 
2491  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2492  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2493 
2494  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2495  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2496 
2497  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2498 
2499  } else {
2500  SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2501 
2503  return -1;
2504  }
2505 
2506  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2507  "ssn->server.last_ack %"PRIu32"", ssn,
2508  ssn->server.next_win, ssn->server.last_ack);
2509  } else {
2510  SCLogDebug("ssn %p: default case", ssn);
2511  }
2512 
2513  return 0;
2514 }
2515 
2516 /**
2517  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2518  * sent by the client to server. The function handles
2519  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2520  * the reassembly.
2521  *
2522  * Timestamp has already been checked at this point.
2523  *
2524  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2525  * \param ssn Pointer to the current TCP session
2526  * \param p Packet which has to be handled in this TCP state.
2527  * \param stt Stream Thread module registered to handle the stream handling
2528  */
2529 static int HandleEstablishedPacketToServer(
2530  ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt)
2531 {
2532  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2533  "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
2535 
2536  const bool has_ack = (p->tcph->th_flags & TH_ACK) != 0;
2537  if (has_ack) {
2538  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TC) && TCP_GET_ACK(p) == ssn->server.next_seq + 1) {
2539  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2541 
2542  } else if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2543  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2545  return -1;
2546  }
2547  }
2548 
2549  /* check for Keep Alive */
2550  if ((p->payload_len == 0 || p->payload_len == 1) &&
2551  (TCP_GET_SEQ(p) == (ssn->client.next_seq - 1))) {
2552  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2553 
2554  /* normal pkt */
2555  } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack))) {
2556  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2557  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2558  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2559  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2560  "%" PRIu32 "(%" PRIu32 ")",
2561  ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2562  ssn->client.last_ack, ssn->client.next_win,
2563  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2564 
2565  /* update the last_ack to current seq number as the session is
2566  * async and other stream is not updating it anymore :( */
2567  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2568 
2569  } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p)) && stream_config.async_oneside &&
2570  (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2571  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2572  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2573  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2574  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2575  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2576  ssn->client.last_ack, ssn->client.next_win,
2577  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2578 
2579  /* it seems we missed SYN and SYN/ACK packets of this session.
2580  * Update the last_ack to current seq number as the session
2581  * is async and other stream is not updating it anymore :( */
2582  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2583  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2584 
2585  } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2587  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2588  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2589  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2590  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2591  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2592  ssn->client.last_ack, ssn->client.next_win,
2593  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2594 
2595  /* it seems we missed SYN and SYN/ACK packets of this session.
2596  * Update the last_ack to current seq number as the session
2597  * is async and other stream is not updating it anymore :(*/
2598  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2599  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2600 
2601  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2602  * In this case we do accept the data before last_ack if it is (partly)
2603  * beyond next seq */
2604  } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
2605  SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), ssn->client.next_seq)) {
2606  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2607  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
2608  " acked data that we haven't seen before",
2609  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->client.last_ack,
2610  ssn->client.next_seq);
2611  } else {
2612  SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
2613  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2614  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2615  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2616  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2617  ssn->client.last_ack, ssn->client.next_win,
2618  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2619 
2620  SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
2622  return -1;
2623  }
2624  }
2625 
2626  int zerowindowprobe = 0;
2627  /* zero window probe */
2628  if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->client.next_seq && ssn->client.window == 0) {
2629  SCLogDebug("ssn %p: zero window probe", ssn);
2630  zerowindowprobe = 1;
2632  ssn->flags |= STREAMTCP_FLAG_ZWP_TS;
2633  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2634 
2635  } else if (SEQ_GEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_seq)) {
2636  StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
2637  }
2638 
2639  /* in window check */
2640  if (zerowindowprobe) {
2641  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2642  } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
2644  {
2645  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
2646  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
2647 
2648  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2649  SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
2650  ssn->server.window);
2651 
2652  /* Check if the ACK value is sane and inside the window limit */
2653  if (p->tcph->th_flags & TH_ACK) {
2654  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2655  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
2656  SEQ_GT(ssn->server.last_ack, ssn->server.next_seq)) {
2659  }
2660  }
2661 
2662  SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, ssn->server.next_seq);
2663 
2664  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2665  StreamTcpHandleTimestamp(ssn, p);
2666  }
2667 
2669 
2670  /* update next_win */
2671  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
2672 
2673  /* handle data (if any) */
2674  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2675 
2676  } else {
2677  SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
2678  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2679  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2680  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2681  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2682  ssn->client.last_ack, ssn->client.next_win,
2683  (TCP_GET_SEQ(p) + p->payload_len) - ssn->client.next_win);
2684  SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
2685  StreamTcpSackedSize(&ssn->client));
2687  return -1;
2688  }
2689  return 0;
2690 }
2691 
2692 /**
2693  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2694  * sent by the server to client. The function handles
2695  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2696  * the reassembly
2697  *
2698  * Timestamp has already been checked at this point.
2699  *
2700  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2701  * \param ssn Pointer to the current TCP session
2702  * \param p Packet which has to be handled in this TCP state.
2703  * \param stt Stream Thread module registered to handle the stream handling
2704  */
2705 static int HandleEstablishedPacketToClient(
2706  ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt)
2707 {
2708  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
2709  " ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
2711 
2712  const bool has_ack = (p->tcph->th_flags & TH_ACK) != 0;
2713  if (has_ack) {
2714  if ((ssn->flags & STREAMTCP_FLAG_ZWP_TS) && TCP_GET_ACK(p) == ssn->client.next_seq + 1) {
2715  SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2717 
2718  } else if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2719  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2721  return -1;
2722  }
2723  }
2724 
2725  /* To get the server window value from the servers packet, when connection
2726  is picked up as midstream */
2727  if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
2729  {
2730  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2731  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2733  SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
2734  "%" PRIu32 "", ssn, ssn->server.next_win);
2735  }
2736 
2737  /* check for Keep Alive */
2738  if ((p->payload_len == 0 || p->payload_len == 1) &&
2739  (TCP_GET_SEQ(p) == (ssn->server.next_seq - 1))) {
2740  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2741 
2742  /* normal pkt */
2743  } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->server.last_ack))) {
2744  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2745 
2746  SCLogDebug("ssn %p: client => Asynchronous stream, packet SEQ"
2747  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2748  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2749  " %" PRIu32 "(%" PRIu32 ")",
2750  ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2751  ssn->server.last_ack, ssn->server.next_win,
2752  TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
2753 
2754  ssn->server.last_ack = TCP_GET_SEQ(p);
2755 
2756  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2757  * In this case we do accept the data before last_ack if it is (partly)
2758  * beyond next seq */
2759  } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
2761  {
2762  SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2763  " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
2764  " acked data that we haven't seen before",
2765  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack,
2766  ssn->server.next_seq);
2767  } else {
2768  SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2769  " before last_ack %"PRIu32". next_seq %"PRIu32,
2770  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2772  return -1;
2773  }
2774  }
2775 
2776  int zerowindowprobe = 0;
2777  /* zero window probe */
2778  if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->server.next_seq && ssn->server.window == 0) {
2779  SCLogDebug("ssn %p: zero window probe", ssn);
2780  zerowindowprobe = 1;
2782  ssn->flags |= STREAMTCP_FLAG_ZWP_TC;
2783 
2784  /* accept the segment */
2785  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2786 
2787  } else if (SEQ_GEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_seq)) {
2788  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2789  }
2790 
2791  if (zerowindowprobe) {
2792  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2793  } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
2795  {
2796  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
2797  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
2798  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2799  SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
2800  ssn->client.window);
2801 
2802  if (p->tcph->th_flags & TH_ACK) {
2803  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2804  if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
2805  SEQ_GT(ssn->client.last_ack, ssn->client.next_seq)) {
2808  }
2809  }
2810 
2811  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2812  StreamTcpHandleTimestamp(ssn, p);
2813  }
2814 
2816 
2817  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
2818 
2819  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2820  } else {
2821  SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
2822  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2823  " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
2824  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2825  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2826  ssn->server.last_ack, ssn->server.next_win,
2827  TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
2829  return -1;
2830  }
2831  return 0;
2832 }
2833 
2834 /**
2835  * \internal
2836  *
2837  * \brief Find the highest sequence number needed to consider all segments as ACK'd
2838  *
2839  * Used to treat all segments as ACK'd upon receiving a valid RST.
2840  *
2841  * \param stream stream to inspect the segments from
2842  * \param seq sequence number to check against
2843  *
2844  * \retval ack highest ack we need to set
2845  */
2846 static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
2847 {
2848  uint32_t ack = seq;
2849 
2850  if (STREAM_HAS_SEEN_DATA(stream)) {
2851  const uint32_t tail_seq = STREAM_SEQ_RIGHT_EDGE(stream);
2852  if (SEQ_GT(tail_seq, ack)) {
2853  ack = tail_seq;
2854  }
2855  }
2856 
2857  SCReturnUInt(ack);
2858 }
2859 
2860 static bool StreamTcpPacketIsZeroWindowProbeAck(const TcpSession *ssn, const Packet *p)
2861 {
2862  if (ssn->state < TCP_ESTABLISHED)
2863  return false;
2864  if (p->payload_len != 0)
2865  return false;
2866  if ((p->tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
2867  return false;
2868 
2869  const TcpStream *snd, *rcv;
2870  if (PKT_IS_TOCLIENT(p)) {
2871  snd = &ssn->server;
2872  rcv = &ssn->client;
2873  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TS))
2874  return false;
2875  } else {
2876  snd = &ssn->client;
2877  rcv = &ssn->server;
2878  if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TC))
2879  return false;
2880  }
2881 
2882  const uint32_t pkt_win = TCP_GET_WINDOW(p) << snd->wscale;
2883  if (pkt_win != 0)
2884  return false;
2885  if (pkt_win != rcv->window)
2886  return false;
2887 
2888  if (TCP_GET_SEQ(p) != snd->next_seq)
2889  return false;
2890  if (TCP_GET_ACK(p) != rcv->last_ack)
2891  return false;
2892  SCLogDebug("ssn %p: packet %" PRIu64 " is a Zero Window Probe ACK", ssn, p->pcap_cnt);
2893  return true;
2894 }
2895 
2896 /** \internal
2897  * \brief check if an ACK packet is a dup-ACK
2898  */
2899 static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p)
2900 {
2901  if (ssn->state < TCP_ESTABLISHED)
2902  return false;
2903  if (p->payload_len != 0)
2904  return false;
2905  if ((p->tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
2906  return false;
2907 
2908  const TcpStream *snd, *rcv;
2909  if (PKT_IS_TOCLIENT(p)) {
2910  snd = &ssn->server;
2911  rcv = &ssn->client;
2912  } else {
2913  snd = &ssn->client;
2914  rcv = &ssn->server;
2915  }
2916 
2917  const uint32_t pkt_win = TCP_GET_WINDOW(p) << snd->wscale;
2918  if (pkt_win == 0 || rcv->window == 0)
2919  return false;
2920  if (pkt_win != rcv->window)
2921  return false;
2922 
2923  if (TCP_GET_SEQ(p) != snd->next_seq)
2924  return false;
2925  if (TCP_GET_ACK(p) != rcv->last_ack)
2926  return false;
2927 
2928  SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn,
2929  p->pcap_cnt, TCP_GET_SEQ(p), TCP_GET_ACK(p), pkt_win, snd->next_seq, snd->last_ack,
2930  rcv->window, snd->next_seq, rcv->last_ack, rcv->window);
2931  return true;
2932 }
2933 
2934 /** \internal
2935  * \brief check if a ACK packet is outdated so processing can be fast tracked
2936  *
2937  * Consider a packet outdated ack if:
2938  * - state is >= ESTABLISHED
2939  * - ACK < last_ACK
2940  * - SACK acks nothing new
2941  * - packet has no data
2942  * - SEQ == next_SEQ
2943  * - flags has ACK set but don't contain SYN/FIN/RST
2944  *
2945  * \todo the most likely explanation for this packet is that we already
2946  * accepted a "newer" ACK. We will not consider an outdated timestamp
2947  * option an issue for this packet, but we should probably still
2948  * check if the ts isn't too far off.
2949  */
2950 static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p)
2951 {
2952  if (ssn->state < TCP_ESTABLISHED)
2953  return false;
2954  if (p->payload_len != 0)
2955  return false;
2956  if ((p->tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
2957  return false;
2958 
2959  /* lets see if this is a packet that is entirely eclipsed by earlier ACKs */
2960  if (PKT_IS_TOSERVER(p)) {
2961  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq) &&
2962  SEQ_LT(TCP_GET_ACK(p), ssn->server.last_ack)) {
2963  if (!TCP_HAS_SACK(p)) {
2964  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_SEQ(p),
2965  ssn->client.next_seq);
2966  return true;
2967  }
2968 
2969  if (StreamTcpSackPacketIsOutdated(&ssn->server, p)) {
2970  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_SEQ(p),
2971  ssn->client.next_seq);
2972  return true;
2973  }
2974  }
2975  } else {
2976  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq) &&
2977  SEQ_LT(TCP_GET_ACK(p), ssn->client.last_ack)) {
2978  if (!TCP_HAS_SACK(p)) {
2979  SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_SEQ(p),
2980  ssn->client.next_seq);
2981  return true;
2982  }
2983 
2984  if (StreamTcpSackPacketIsOutdated(&ssn->client, p)) {
2985  SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_SEQ(p),
2986  ssn->client.next_seq);
2987  return true;
2988  }
2989  }
2990  }
2991  return false;
2992 }
2993 
2994 /** \internal
2995  * \brief check if packet is before ack'd windows
2996  * If packet is before last ack, we will not accept it
2997  *
2998  * \retval 0 not spurious retransmission
2999  * \retval 1 before last_ack, after base_seq
3000  * \retval 2 before last_ack and base_seq
3001  */
3002 static int StreamTcpPacketIsSpuriousRetransmission(const TcpSession *ssn, Packet *p)
3003 {
3004  const TcpStream *stream;
3005  if (PKT_IS_TOCLIENT(p)) {
3006  stream = &ssn->server;
3007  } else {
3008  stream = &ssn->client;
3009  }
3010  if (p->payload_len == 0)
3011  return 0;
3012 
3013  /* take base_seq into account to avoid edge cases where last_ack might be
3014  * too far ahead during heavy packet loss */
3015  if (!(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3016  if ((SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, stream->base_seq))) {
3017  SCLogDebug(
3018  "ssn %p: spurious retransmission; packet entirely before base_seq: SEQ %u(%u) "
3019  "last_ack %u base_seq %u",
3020  ssn, TCP_GET_SEQ(p), TCP_GET_SEQ(p) + p->payload_len, stream->last_ack,
3021  stream->base_seq);
3023  return 2;
3024  }
3025  }
3026 
3027  if ((SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, stream->last_ack))) {
3028  SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) "
3029  "last_ack %u",
3030  ssn, TCP_GET_SEQ(p), TCP_GET_SEQ(p) + p->payload_len, stream->last_ack);
3032  return 1;
3033  }
3034 
3035  SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ "
3036  "%u(%u) last_ack %u, base_seq %u",
3037  ssn, TCP_GET_SEQ(p), TCP_GET_SEQ(p) + p->payload_len, stream->last_ack,
3038  stream->base_seq);
3039  return 0;
3040 }
3041 
3042 /**
3043  * \brief Function to handle the TCP_ESTABLISHED state. The function handles
3044  * ACK, FIN, RST packets and correspondingly changes the connection
3045  * state. The function handles the data inside packets and call
3046  * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
3047  *
3048  * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3049  * \param p Packet which has to be handled in this TCP state.
3050  * \param stt Stream Thread module registered to handle the stream handling
3051  */
3052 
3053 static int StreamTcpPacketStateEstablished(
3054  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3055 {
3056  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3057 
3058  if (p->tcph->th_flags & TH_RST) {
3059  if (!StreamTcpValidateRst(ssn, p))
3060  return -1;
3061 
3062  if (PKT_IS_TOSERVER(p)) {
3063  StreamTcpCloseSsnWithReset(p, ssn);
3064 
3065  ssn->server.next_seq = TCP_GET_ACK(p);
3066  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
3067  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3068  ssn->server.next_seq);
3069  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3070 
3071  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3072  StreamTcpUpdateLastAck(ssn, &ssn->server,
3073  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3074 
3075  StreamTcpUpdateLastAck(ssn, &ssn->client,
3076  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3077 
3078  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3079  StreamTcpHandleTimestamp(ssn, p);
3080  }
3081 
3082  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3083  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3084  "%" PRIu32 "", ssn, ssn->client.next_seq,
3085  ssn->server.last_ack);
3086 
3087  /* don't return packets to pools here just yet, the pseudo
3088  * packet will take care, otherwise the normal session
3089  * cleanup. */
3090  } else {
3091  StreamTcpCloseSsnWithReset(p, ssn);
3092 
3093  ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1;
3094  ssn->client.next_seq = TCP_GET_ACK(p);
3095 
3096  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3097  ssn->server.next_seq);
3098  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3099 
3100  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3101  StreamTcpUpdateLastAck(ssn, &ssn->client,
3102  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3103 
3104  StreamTcpUpdateLastAck(ssn, &ssn->server,
3105  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3106 
3107  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3108  StreamTcpHandleTimestamp(ssn, p);
3109  }
3110 
3111  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3112  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3113  "%" PRIu32 "", ssn, ssn->server.next_seq,
3114  ssn->client.last_ack);
3115 
3116  /* don't return packets to pools here just yet, the pseudo
3117  * packet will take care, otherwise the normal session
3118  * cleanup. */
3119  }
3120 
3121  } else if (p->tcph->th_flags & TH_FIN) {
3122  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3123  if (!StreamTcpValidateTimestamp(ssn, p))
3124  return -1;
3125  }
3126 
3127  SCLogDebug("ssn (%p: FIN received SEQ"
3128  " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
3129  " win %" PRIu32 "", ssn, ssn->server.next_seq,
3130  ssn->client.last_ack, ssn->server.next_win,
3131  ssn->server.window);
3132 
3133  if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
3134  return -1;
3135 
3136  /* SYN/ACK */
3137  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
3138  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
3139  ssn);
3140 
3141  if (PKT_IS_TOSERVER(p)) {
3142  SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
3143 
3145  return -1;
3146  }
3147 
3148  /* Check if the SYN/ACK packets ACK matches the earlier
3149  * received SYN/ACK packet. */
3150  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
3151  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
3152  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
3153  ssn->client.isn + 1);
3154 
3156  return -1;
3157  }
3158 
3159  /* Check if the SYN/ACK packet SEQ the earlier
3160  * received SYN packet. */
3161  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
3162  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
3163  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
3164  ssn->client.isn + 1);
3165 
3167  return -1;
3168  }
3169 
3170  if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
3171  /* a resend of a SYN while we are established already -- fishy */
3173  return -1;
3174  }
3175 
3176  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
3177  "Likely due server not receiving final ACK in 3whs", ssn);
3178  return 0;
3179 
3180  } else if (p->tcph->th_flags & TH_SYN) {
3181  SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
3182  if (PKT_IS_TOCLIENT(p)) {
3183  SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
3184 
3186  return -1;
3187  }
3188 
3189  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
3190  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
3191 
3193  return -1;
3194  }
3195 
3196  /* a resend of a SYN while we are established already -- fishy */
3198  return -1;
3199 
3200  } else if (p->tcph->th_flags & TH_ACK) {
3201  /* Urgent pointer size can be more than the payload size, as it tells
3202  * the future coming data from the sender will be handled urgently
3203  * until data of size equal to urgent offset has been processed
3204  * (RFC 2147) */
3205 
3206  /* If the timestamp option is enabled for both the streams, then
3207  * validate the received packet timestamp value against the
3208  * stream->last_ts. If the timestamp is valid then process the
3209  * packet normally otherwise the drop the packet (RFC 1323) */
3210  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3211  if (!StreamTcpValidateTimestamp(ssn, p))
3212  return -1;
3213  }
3214 
3215  if (PKT_IS_TOSERVER(p)) {
3216  /* Process the received packet to server */
3217  HandleEstablishedPacketToServer(tv, ssn, p, stt);
3218 
3219  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3220  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3221  ssn->client.next_seq, ssn->server.last_ack
3222  ,ssn->client.next_win, ssn->client.window);
3223 
3224  } else { /* implied to client */
3225  if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
3227  SCLogDebug("3whs is now confirmed by server");
3228  }
3229 
3230  /* Process the received packet to client */
3231  HandleEstablishedPacketToClient(tv, ssn, p, stt);
3232 
3233  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3234  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3235  ssn->server.next_seq, ssn->client.last_ack,
3236  ssn->server.next_win, ssn->server.window);
3237  }
3238  } else {
3239  SCLogDebug("ssn %p: default case", ssn);
3240  }
3241 
3242  return 0;
3243 }
3244 
3245 /**
3246  * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
3247  * TCP_ESTABLISHED and changes to another TCP state as required.
3248  *
3249  * \param tv Thread Variable containing input/output queue, cpu affinity
3250  * \param p Packet which has to be handled in this TCP state.
3251  * \param stt Stream Thread module registered to handle the stream handling
3252  *
3253  * \retval 0 success
3254  * \retval -1 something wrong with the packet
3255  */
3256 
3257 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession *ssn, Packet *p)
3258 {
3259  if (PKT_IS_TOSERVER(p)) {
3260  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
3261  " ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
3262  TCP_GET_ACK(p));
3263 
3264  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3265  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3267  return -1;
3268  }
3269 
3270  const uint32_t pkt_re = TCP_GET_SEQ(p) + p->payload_len;
3271  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, TCP_GET_SEQ(p), pkt_re,
3272  ssn->client.last_ack, ssn->client.next_win);
3273  if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.last_ack) &&
3274  SEQ_LEQ(pkt_re, ssn->client.next_win)) {
3275  // within expectations
3276  } else {
3277  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3278  "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
3279  ssn->client.next_seq);
3280 
3282  return -1;
3283  }
3284 
3285  if (p->tcph->th_flags & TH_SYN) {
3286  SCLogDebug("ssn %p: FIN+SYN", ssn);
3288  return -1;
3289  }
3290  StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
3291  SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
3292 
3293  /* if we accept the FIN, next_seq needs to reflect the FIN */
3294  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
3295 
3296  SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
3297  ssn->client.next_seq);
3298  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3299 
3300  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3301  StreamTcpHandleTimestamp(ssn, p);
3302  }
3303 
3304  /* Update the next_seq, in case if we have missed the client packet
3305  and server has already received and acked it */
3306  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3307  ssn->server.next_seq = TCP_GET_ACK(p);
3308 
3309  if (p->tcph->th_flags & TH_ACK)
3310  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3311 
3312  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3313 
3314  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3315  ssn, ssn->client.next_seq, ssn->server.last_ack);
3316  } else { /* implied to client */
3317  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
3318  "ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
3319  TCP_GET_ACK(p));
3320 
3321  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3322  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3324  return -1;
3325  }
3326 
3327  const uint32_t pkt_re = TCP_GET_SEQ(p) + p->payload_len;
3328  SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, TCP_GET_SEQ(p), pkt_re,
3329  ssn->server.last_ack, ssn->server.next_win);
3330  if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.last_ack) &&
3331  SEQ_LEQ(pkt_re, ssn->server.next_win)) {
3332  // within expectations
3333  } else {
3334  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3335  "%" PRIu32 " from stream (last_ack %u win %u = %u)", ssn, TCP_GET_SEQ(p),
3336  ssn->server.next_seq, ssn->server.last_ack, ssn->server.window, (ssn->server.last_ack + ssn->server.window));
3337 
3339  return -1;
3340  }
3341 
3342  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
3343  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
3344 
3345  /* if we accept the FIN, next_seq needs to reflect the FIN */
3346  ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1;
3347  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 " updated", ssn, ssn->server.next_seq);
3348 
3349  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3350 
3351  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3352  StreamTcpHandleTimestamp(ssn, p);
3353  }
3354 
3355  /* Update the next_seq, in case if we have missed the client packet
3356  and server has already received and acked it */
3357  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3358  ssn->client.next_seq = TCP_GET_ACK(p);
3359 
3360  if (p->tcph->th_flags & TH_ACK)
3361  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3362 
3363  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3364 
3365  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3366  ssn, ssn->server.next_seq, ssn->client.last_ack);
3367  }
3368 
3369  return 0;
3370 }
3371 
3372 /**
3373  * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
3374  * ACK, FIN, RST packets and correspondingly changes the connection
3375  * state.
3376  *
3377  * \param tv Thread Variable containing input/output queue, cpu affinity
3378  * \param p Packet which has to be handled in this TCP state.
3379  * \param stt Stream Thread module registered to handle the stream handling
3380  *
3381  * \retval 0 success
3382  * \retval -1 something wrong with the packet
3383  */
3384 
3385 static int StreamTcpPacketStateFinWait1(
3386  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3387 {
3388  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3389 
3390  if (p->tcph->th_flags & TH_RST) {
3391  if (!StreamTcpValidateRst(ssn, p))
3392  return -1;
3393 
3394  StreamTcpCloseSsnWithReset(p, ssn);
3395 
3396  if (PKT_IS_TOSERVER(p)) {
3397  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3398  StreamTcpUpdateLastAck(ssn, &ssn->server,
3399  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3400 
3401  StreamTcpUpdateLastAck(ssn, &ssn->client,
3402  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3403 
3404  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3405  StreamTcpHandleTimestamp(ssn, p);
3406  }
3407 
3408  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3409  } else {
3410  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3411  StreamTcpUpdateLastAck(ssn, &ssn->client,
3412  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3413 
3414  StreamTcpUpdateLastAck(ssn, &ssn->server,
3415  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3416 
3417  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3418  StreamTcpHandleTimestamp(ssn, p);
3419  }
3420 
3421  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3422  }
3423 
3424  } else if ((p->tcph->th_flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) {
3425  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3426  if (!StreamTcpValidateTimestamp(ssn, p))
3427  return -1;
3428  }
3429 
3430  if (PKT_IS_TOSERVER(p)) {
3431  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3432  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3433  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3434  int retransmission = 0;
3435 
3436  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3437  SCLogDebug("ssn %p: packet is retransmission", ssn);
3438  retransmission = 1;
3440 
3441  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq - 1) ||
3442  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) {
3443  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3444  " != %" PRIu32 " from stream", ssn,
3445  TCP_GET_SEQ(p), ssn->client.next_seq);
3447  return -1;
3448  }
3449 
3450  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3451  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3453  return -1;
3454  }
3455 
3456  if (!retransmission) {
3457  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3458  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3459 
3460  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3461  }
3462 
3463  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3464  StreamTcpHandleTimestamp(ssn, p);
3465  }
3466 
3467  /* Update the next_seq, in case if we have missed the client
3468  packet and server has already received and acked it */
3469  if (SEQ_LT(ssn->server.next_seq - 1, TCP_GET_ACK(p)))
3470  ssn->server.next_seq = TCP_GET_ACK(p);
3471 
3472  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3473  StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
3474  }
3475 
3476  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3477 
3478  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3479 
3480  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3481  "%" PRIu32 "", ssn, ssn->client.next_seq,
3482  ssn->server.last_ack);
3483  } else { /* implied to client */
3484  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3485  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3486  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3487  int retransmission = 0;
3488 
3489  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3490  SCLogDebug("ssn %p: packet is retransmission", ssn);
3491  retransmission = 1;
3493 
3494  } else if (SEQ_EQ(ssn->server.next_seq - 1, TCP_GET_SEQ(p)) &&
3495  SEQ_EQ(ssn->client.last_ack, TCP_GET_ACK(p))) {
3496  SCLogDebug("ssn %p: packet is retransmission", ssn);
3497  retransmission = 1;
3499 
3500  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq - 1) ||
3501  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) {
3502  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3503  " != %" PRIu32 " from stream", ssn,
3504  TCP_GET_SEQ(p), ssn->server.next_seq);
3506  return -1;
3507  }
3508 
3509  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3510  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3512  return -1;
3513  }
3514 
3515  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3516  StreamTcpHandleTimestamp(ssn, p);
3517  }
3518 
3519  if (!retransmission) {
3520  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3521  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3522 
3523  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3524 
3525  /* Update the next_seq, in case if we have missed the client
3526  packet and server has already received and acked it */
3527  if (SEQ_LT(ssn->client.next_seq - 1, TCP_GET_ACK(p)))
3528  ssn->client.next_seq = TCP_GET_ACK(p);
3529 
3530  if (SEQ_EQ(ssn->server.next_seq - 1, TCP_GET_SEQ(p))) {
3531  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
3532  }
3533 
3534  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3535  }
3536 
3537  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3538 
3539  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3540  "%" PRIu32 "", ssn, ssn->server.next_seq,
3541  ssn->client.last_ack);
3542  }
3543 
3544  } else if (p->tcph->th_flags & TH_FIN) {
3545  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3546  if (!StreamTcpValidateTimestamp(ssn, p))
3547  return -1;
3548  }
3549 
3550  if (PKT_IS_TOSERVER(p)) {
3551  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3552  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3553  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3554  int retransmission = 0;
3555 
3556  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3557  SCLogDebug("ssn %p: packet is retransmission", ssn);
3558  retransmission = 1;
3560 
3561  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq - 1) ||
3562  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) {
3563  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3564  " != %" PRIu32 " from stream", ssn,
3565  TCP_GET_SEQ(p), ssn->client.next_seq);
3567  return -1;
3568  }
3569 
3570  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3571  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3573  return -1;
3574  }
3575 
3576  if (!retransmission) {
3577  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3578  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3579 
3580  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3581  }
3582 
3583  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3584  StreamTcpHandleTimestamp(ssn, p);
3585  }
3586 
3587  /* Update the next_seq, in case if we have missed the client
3588  packet and server has already received and acked it */
3589  if (SEQ_LT(ssn->server.next_seq - 1, TCP_GET_ACK(p)))
3590  ssn->server.next_seq = TCP_GET_ACK(p);
3591 
3592  if (SEQ_EQ(ssn->client.next_seq - 1, TCP_GET_SEQ(p))) {
3593  StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
3594  }
3595 
3596  if (p->tcph->th_flags & TH_ACK)
3597  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3598 
3599  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3600 
3601  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3602  "%" PRIu32 "", ssn, ssn->client.next_seq,
3603  ssn->server.last_ack);
3604  } else { /* implied to client */
3605  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3606  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3607  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3608 
3609  int retransmission = 0;
3610 
3611  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3612  SCLogDebug("ssn %p: packet is retransmission", ssn);
3613  retransmission = 1;
3615 
3616  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq - 1) ||
3617  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) {
3618  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3619  " != %" PRIu32 " from stream", ssn,
3620  TCP_GET_SEQ(p), ssn->server.next_seq);
3622  return -1;
3623  }
3624 
3625  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3626  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3628  return -1;
3629  }
3630 
3631  if (!retransmission) {
3632  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3633  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3634 
3635  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3636  }
3637 
3638  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3639  StreamTcpHandleTimestamp(ssn, p);
3640  }
3641 
3642  /* Update the next_seq, in case if we have missed the client
3643  packet and server has already received and acked it */
3644  if (SEQ_LT(ssn->client.next_seq - 1, TCP_GET_ACK(p)))
3645  ssn->client.next_seq = TCP_GET_ACK(p);
3646 
3647  if (SEQ_EQ(ssn->server.next_seq - 1, TCP_GET_SEQ(p))) {
3648  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
3649  }
3650 
3651  if (p->tcph->th_flags & TH_ACK)
3652  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3653 
3654  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3655 
3656  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3657  "%" PRIu32 "", ssn, ssn->server.next_seq,
3658  ssn->client.last_ack);
3659  }
3660  } else if (p->tcph->th_flags & TH_SYN) {
3661  SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
3663  return -1;
3664 
3665  } else if (p->tcph->th_flags & TH_ACK) {
3666  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3667  if (!StreamTcpValidateTimestamp(ssn, p))
3668  return -1;
3669  }
3670 
3671  if (PKT_IS_TOSERVER(p)) {
3672  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3673  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3674  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3675  int retransmission = 0;
3676 
3677  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3678  SCLogDebug("ssn %p: packet is retransmission", ssn);
3679  retransmission = 1;
3681  }
3682 
3683  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3684  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3686  return -1;
3687  }
3688 
3689  if (SEQ_LT(TCP_GET_ACK(p), ssn->server.next_seq)) {
3690  SCLogDebug("ssn %p: ACK's older segment as %u < %u", ssn, TCP_GET_ACK(p),
3691  ssn->server.next_seq);
3692  } else if (!retransmission) {
3693  if (SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) {
3694  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
3696  SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
3697  "%" PRIu32 "",
3698  ssn, TCP_GET_SEQ(p), ssn->client.next_win);
3699  SCLogDebug(
3700  "seq %u client.next_seq %u", TCP_GET_SEQ(p), ssn->client.next_seq);
3701  if (TCP_GET_SEQ(p) == ssn->client.next_seq) {
3702  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3703  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3704  }
3705  } else {
3706  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3707  " != %" PRIu32 " from stream",
3708  ssn, TCP_GET_SEQ(p), ssn->client.next_seq);
3709 
3711  return -1;
3712  }
3713 
3714  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3715  }
3716  }
3717 
3718  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3719  StreamTcpHandleTimestamp(ssn, p);
3720  }
3721 
3722  /* Update the next_seq, in case if we have missed the client
3723  packet and server has already received and acked it */
3724  if (SEQ_LT(ssn->server.next_seq - 1, TCP_GET_ACK(p)))
3725  ssn->server.next_seq = TCP_GET_ACK(p);
3726 
3727  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3728  StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
3729  }
3730 
3731  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3732 
3734 
3735  /* update next_win */
3736  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3737 
3738  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3739 
3740  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3741  "%" PRIu32 "", ssn, ssn->client.next_seq,
3742  ssn->server.last_ack);
3743 
3744  } else { /* implied to client */
3745 
3746  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3747  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3748  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3749 
3750  int retransmission = 0;
3751 
3752  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3753  SCLogDebug("ssn %p: packet is retransmission", ssn);
3754  retransmission = 1;
3756  }
3757 
3758  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3759  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3761  return -1;
3762  }
3763 
3764  if (!retransmission) {
3765  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
3767  {
3768  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
3769  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
3770 
3771  if (TCP_GET_SEQ(p) == ssn->server.next_seq - 1) {
3772  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3773  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3774  }
3775  } else {
3776  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3777  " != %" PRIu32 " from stream", ssn,
3778  TCP_GET_SEQ(p), ssn->server.next_seq);
3780  return -1;
3781  }
3782 
3783  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3784  }
3785 
3786  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3787  StreamTcpHandleTimestamp(ssn, p);
3788  }
3789 
3790  /* Update the next_seq, in case if we have missed the client
3791  packet and server has already received and acked it */
3792  if (SEQ_LT(ssn->client.next_seq - 1, TCP_GET_ACK(p)))
3793  ssn->client.next_seq = TCP_GET_ACK(p);
3794 
3795  if (SEQ_EQ(ssn->server.next_seq - 1, TCP_GET_SEQ(p))) {
3796  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
3797  }
3798 
3799  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3800 
3802 
3803  /* update next_win */
3804  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3805 
3806  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3807 
3808  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3809  "%" PRIu32 "", ssn, ssn->server.next_seq,
3810  ssn->client.last_ack);
3811  }
3812  } else {
3813  SCLogDebug("ssn (%p): default case", ssn);
3814  }
3815 
3816  return 0;
3817 }
3818 
3819 /**
3820  * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
3821  * ACK, RST, FIN packets and correspondingly changes the connection
3822  * state.
3823  *
3824  * \param tv Thread Variable containing input/output queue, cpu affinity
3825  * \param p Packet which has to be handled in this TCP state.
3826  * \param stt Stream Thread module registered to handle the stream handling
3827  */
3828 
3829 static int StreamTcpPacketStateFinWait2(
3830  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
3831 {
3832  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3833 
3834  if (p->tcph->th_flags & TH_RST) {
3835  if (!StreamTcpValidateRst(ssn, p))
3836  return -1;
3837 
3838  StreamTcpCloseSsnWithReset(p, ssn);
3839 
3840  if (PKT_IS_TOSERVER(p)) {
3841  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3842  StreamTcpUpdateLastAck(ssn, &ssn->server,
3843  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3844 
3845  StreamTcpUpdateLastAck(ssn, &ssn->client,
3846  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3847 
3848  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3849  StreamTcpHandleTimestamp(ssn, p);
3850  }
3851 
3852  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3853  } else {
3854  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3855  StreamTcpUpdateLastAck(ssn, &ssn->client,
3856  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3857 
3858  StreamTcpUpdateLastAck(ssn, &ssn->server,
3859  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3860 
3861  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3862  StreamTcpHandleTimestamp(ssn, p);
3863  }
3864 
3865  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3866  }
3867 
3868  } else if (p->tcph->th_flags & TH_FIN) {
3869  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3870  if (!StreamTcpValidateTimestamp(ssn, p))
3871  return -1;
3872  }
3873 
3874  if (PKT_IS_TOSERVER(p)) {
3875  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3876  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3877  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3878  int retransmission = 0;
3879 
3880  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq - 1) &&
3881  SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) {
3882  SCLogDebug("ssn %p: retransmission", ssn);
3883  retransmission = 1;
3885  } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3886  SCLogDebug("ssn %p: packet is retransmission", ssn);
3887  retransmission = 1;
3889 
3890  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
3891  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3892  {
3893  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
3894  "%" PRIu32 " != %" PRIu32 " from stream", ssn,
3895  TCP_GET_SEQ(p), ssn->client.next_seq);
3897  return -1;
3898  }
3899 
3900  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3901  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3903  return -1;
3904  }
3905 
3906  if (!retransmission) {
3907  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3908  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3909 
3910  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3912  ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3913  }
3914  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3915  }
3916 
3917  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3918  StreamTcpHandleTimestamp(ssn, p);
3919  }
3920 
3921  /* Update the next_seq, in case if we have missed the client
3922  packet and server has already received and acked it */
3923  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3924  ssn->server.next_seq = TCP_GET_ACK(p);
3925 
3926  if (p->tcph->th_flags & TH_ACK)
3927  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3928 
3929  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3930 
3931  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3932  "%" PRIu32 "", ssn, ssn->client.next_seq,
3933  ssn->server.last_ack);
3934  } else { /* implied to client */
3935  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3936  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3937  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3938  int retransmission = 0;
3939 
3940  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq - 1) &&
3941  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) {
3942  SCLogDebug("ssn %p: retransmission", ssn);
3943  retransmission = 1;
3945  } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3946  SCLogDebug("ssn %p: packet is retransmission", ssn);
3947  retransmission = 1;
3949 
3950  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
3951  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3952  {
3953  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
3954  "%" PRIu32 " != %" PRIu32 " from stream", ssn,
3955  TCP_GET_SEQ(p), ssn->server.next_seq);
3957  return -1;
3958  }
3959 
3960  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3961  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3963  return -1;
3964  }
3965 
3966  if (!retransmission) {
3967  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3968  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3969 
3970  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3971  }
3972 
3973  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3974  StreamTcpHandleTimestamp(ssn, p);
3975  }
3976 
3977  /* Update the next_seq, in case if we have missed the client
3978  packet and server has already received and acked it */
3979  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3980  ssn->client.next_seq = TCP_GET_ACK(p);
3981 
3982  if (p->tcph->th_flags & TH_ACK)
3983  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3984 
3985  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3986  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3987  "%" PRIu32 "", ssn, ssn->server.next_seq,
3988  ssn->client.last_ack);
3989  }
3990 
3991  } else if (p->tcph->th_flags & TH_SYN) {
3992  SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
3994  return -1;
3995 
3996  } else if (p->tcph->th_flags & TH_ACK) {
3997  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3998  if (!StreamTcpValidateTimestamp(ssn, p))
3999  return -1;
4000  }
4001 
4002  if (PKT_IS_TOSERVER(p)) {
4003  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4004  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4005  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4006  int retransmission = 0;
4007 
4008  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4009  SCLogDebug("ssn %p: packet is retransmission", ssn);
4010  retransmission = 1;
4012  }
4013 
4014  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4015  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4017  return -1;
4018  }
4019 
4020  if (!retransmission) {
4021  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
4023  {
4024  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
4025  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
4026 
4027  } else {
4028  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4029  " != %" PRIu32 " from stream", ssn,
4030  TCP_GET_SEQ(p), ssn->client.next_seq);
4032  return -1;
4033  }
4034 
4035  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
4036  }
4037 
4038  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4039  StreamTcpHandleTimestamp(ssn, p);
4040  }
4041 
4042  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
4043  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4044  }
4045 
4046  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4047 
4049 
4050  /* update next_win */
4051  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
4052 
4053  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4054 
4055  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4056  "%" PRIu32 "", ssn, ssn->client.next_seq,
4057  ssn->server.last_ack);
4058  } else { /* implied to client */
4059  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4060  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4061  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4062  int retransmission = 0;
4063 
4064  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4065  SCLogDebug("ssn %p: packet is retransmission", ssn);
4066  retransmission = 1;
4068  }
4069 
4070  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4071  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4073  return -1;
4074  }
4075 
4076  if (!retransmission) {
4077  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
4079  {
4080  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
4081  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
4082  } else {
4083  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4084  " != %" PRIu32 " from stream", ssn,
4085  TCP_GET_SEQ(p), ssn->server.next_seq);
4087  return -1;
4088  }
4089 
4090  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
4091  }
4092 
4093  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4094  StreamTcpHandleTimestamp(ssn, p);
4095  }
4096 
4097  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
4098  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4099  }
4100 
4101  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
4102 
4104 
4105  /* update next_win */
4106  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4107 
4108  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4109 
4110  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4111  "%" PRIu32 "", ssn, ssn->server.next_seq,
4112  ssn->client.last_ack);
4113  }
4114  } else {
4115  SCLogDebug("ssn %p: default case", ssn);
4116  }
4117 
4118  return 0;
4119 }
4120 
4121 /**
4122  * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
4123  * the connection goes to TCP_TIME_WAIT state. The state has been
4124  * reached as both end application has been closed.
4125  *
4126  * \param tv Thread Variable containing input/output queue, cpu affinity
4127  * \param p Packet which has to be handled in this TCP state.
4128  * \param stt Stream Thread module registered to handle the stream handling
4129  */
4130 
4131 static int StreamTcpPacketStateClosing(
4132  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4133 {
4134  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4135 
4136  if (p->tcph->th_flags & TH_RST) {
4137  if (!StreamTcpValidateRst(ssn, p))
4138  return -1;
4139 
4140  StreamTcpCloseSsnWithReset(p, ssn);
4141 
4142  if (PKT_IS_TOSERVER(p)) {
4143  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4144  StreamTcpUpdateLastAck(ssn, &ssn->server,
4145  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
4146 
4147  StreamTcpUpdateLastAck(ssn, &ssn->client,
4148  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
4149 
4150  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4151  StreamTcpHandleTimestamp(ssn, p);
4152  }
4153 
4154  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4155  } else {
4156  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4157  StreamTcpUpdateLastAck(ssn, &ssn->client,
4158  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
4159 
4160  StreamTcpUpdateLastAck(ssn, &ssn->server,
4161  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
4162 
4163  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4164  StreamTcpHandleTimestamp(ssn, p);
4165  }
4166 
4167  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4168  }
4169 
4170  } else if (p->tcph->th_flags & TH_SYN) {
4171  SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
4173  return -1;
4174 
4175  } else if (p->tcph->th_flags & TH_ACK) {
4176  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4177  if (!StreamTcpValidateTimestamp(ssn, p))
4178  return -1;
4179  }
4180 
4181  if (PKT_IS_TOSERVER(p)) {
4182  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4183  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4184  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4185  int retransmission = 0;
4186  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4187  SCLogDebug("ssn %p: packet is retransmission", ssn);
4188  retransmission = 1;
4190  }
4191 
4192  if (TCP_GET_SEQ(p) != ssn->client.next_seq) {
4193  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4194  " != %" PRIu32 " from stream", ssn,
4195  TCP_GET_SEQ(p), ssn->client.next_seq);
4197  return -1;
4198  }
4199 
4200  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4201  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4203  return -1;
4204  }
4205 
4206  if (!retransmission) {
4207  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4208  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4209 
4210  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
4211  }
4212 
4213  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4214  StreamTcpHandleTimestamp(ssn, p);
4215  }
4216  /* Update the next_seq, in case if we have missed the client
4217  packet and server has already received and acked it */
4218  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
4219  ssn->server.next_seq = TCP_GET_ACK(p);
4220 
4221  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4222 
4223  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4224  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4225  "%" PRIu32 "", ssn, ssn->client.next_seq,
4226  ssn->server.last_ack);
4227  } else { /* implied to client */
4228  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4229  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4230  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4231  int retransmission = 0;
4232  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4233  SCLogDebug("ssn %p: packet is retransmission", ssn);
4234  retransmission = 1;
4236  }
4237 
4238  if (TCP_GET_SEQ(p) != ssn->server.next_seq) {
4239  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4240  " != %" PRIu32 " from stream", ssn,
4241  TCP_GET_SEQ(p), ssn->server.next_seq);
4243  return -1;
4244  }
4245 
4246  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4247  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4249  return -1;
4250  }
4251 
4252  if (!retransmission) {
4253  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4254  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4255 
4256  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
4257  }
4258 
4259  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4260  StreamTcpHandleTimestamp(ssn, p);
4261  }
4262 
4263  /* Update the next_seq, in case if we have missed the client
4264  packet and server has already received and acked it */
4265  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
4266  ssn->client.next_seq = TCP_GET_ACK(p);
4267 
4268  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
4269 
4270  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4271  SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
4272  "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
4273  ssn->server.next_seq, ssn->client.last_ack);
4274  }
4275  } else {
4276  SCLogDebug("ssn %p: default case", ssn);
4277  }
4278 
4279  return 0;
4280 }
4281 
4282 /**
4283  * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
4284  * packet from server the connection goes to TCP_LAST_ACK state.
4285  * The state is possible only for server host.
4286  *
4287  * \param tv Thread Variable containing input/output queue, cpu affinity
4288  * \param p Packet which has to be handled in this TCP state.
4289  * \param stt Stream Thread module registered to handle the stream handling
4290  */
4291 
4292 static int StreamTcpPacketStateCloseWait(
4293  ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn)
4294 {
4295  SCEnter();
4296 
4297  DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4298 
4299  if (PKT_IS_TOCLIENT(p)) {
4300  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4301  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4302  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4303  } else {
4304  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4305  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4306  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4307  }
4308 
4309  if (p->tcph->th_flags & TH_RST) {
4310  if (!StreamTcpValidateRst(ssn, p))
4311  return -1;
4312 
4313  StreamTcpCloseSsnWithReset(p, ssn);
4314 
4315  if (PKT_IS_TOSERVER(p)) {
4316  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4317  StreamTcpUpdateLastAck(ssn, &ssn->server,
4318  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
4319 
4320  StreamTcpUpdateLastAck(ssn, &ssn->client,
4321  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
4322 
4323  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4324  StreamTcpHandleTimestamp(ssn, p);
4325  }
4326 
4327  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4328  } else {
4329  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4330  StreamTcpUpdateLastAck(ssn, &ssn->client,
4331  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
4332 
4333  StreamTcpUpdateLastAck(ssn, &ssn->server,
4334  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
4335 
4336  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4337  StreamTcpHandleTimestamp(ssn, p);
4338  }
4339 
4340  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4341  }
4342 
4343  } else if (p->tcph->th_flags & TH_FIN) {
4344  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4345  if (!StreamTcpValidateTimestamp(ssn, p))
4346  SCReturnInt(-1);
4347  }
4348 
4349  if (PKT_IS_TOSERVER(p)) {
4350  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4351  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4352  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4353 
4354  int retransmission = 0;
4355  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4356  SCLogDebug("ssn %p: packet is retransmission", ssn);
4357  retransmission = 1;
4359  }
4360 
4361  if (!retransmission) {
4362  if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
4363  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
4364  {
4365  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4366  " != %" PRIu32 " from stream", ssn,
4367  TCP_GET_SEQ(p), ssn->client.next_seq);
4369  SCReturnInt(-1);
4370  }
4371  }
4372 
4373  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4374  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4376  SCReturnInt(-1);
4377  }
4378 
4379  /* don't update to LAST_ACK here as we want a toclient FIN for that */
4380 
4381  if (!retransmission)
4382  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
4383 
4384  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4385  StreamTcpHandleTimestamp(ssn, p);
4386  }
4387 
4388  /* Update the next_seq, in case if we have missed the client
4389  packet and server has already received and acked it */
4390  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
4391  ssn->server.next_seq = TCP_GET_ACK(p);
4392 
4393  if (p->tcph->th_flags & TH_ACK)
4394  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4395 
4396  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4397  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4398  "%" PRIu32 "", ssn, ssn->client.next_seq,
4399  ssn->server.last_ack);
4400  } else {
4401  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4402  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4403  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4404 
4405  int retransmission = 0;
4406  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4407  SCLogDebug("ssn %p: packet is retransmission", ssn);
4408  retransmission = 1;
4410  }
4411 
4412  if (!retransmission) {
4413  if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
4414  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
4415  {
4416  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4417  " != %" PRIu32 " from stream", ssn,
4418  TCP_GET_SEQ(p), ssn->server.next_seq);
4420  SCReturnInt(-1);
4421  }
4422  }
4423 
4424  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4425  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4427  SCReturnInt(-1);
4428  }
4429 
4430  if (!retransmission) {
4431  StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
4432  SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
4433 
4434  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
4435  }
4436 
4437  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4438  StreamTcpHandleTimestamp(ssn, p);
4439  }
4440 
4441  /* Update the next_seq, in case if we have missed the client
4442  packet and server has already received and acked it */
4443  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
4444  ssn->client.next_seq = TCP_GET_ACK(p);
4445 
4446  if (p->tcph->th_flags & TH_ACK)
4447  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
4448 
4449  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4450  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4451  "%" PRIu32 "", ssn, ssn->server.next_seq,
4452  ssn->client.last_ack);
4453  }
4454 
4455  } else if (p->tcph->th_flags & TH_SYN) {
4456  SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
4458  SCReturnInt(-1);
4459 
4460  } else if (p->tcph->th_flags & TH_ACK) {
4461  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4462  if (!StreamTcpValidateTimestamp(ssn, p))
4463  SCReturnInt(-1);
4464  }
4465 
4466  if (PKT_IS_TOSERVER(p)) {
4467  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4468  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4469  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4470 
4471  int retransmission = 0;
4472  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4473  SCLogDebug("ssn %p: packet is retransmission", ssn);
4474  retransmission = 1;
4476  }
4477 
4478  if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) {
4479  SCLogDebug("ssn %p: -> retransmission", ssn);
4481  SCReturnInt(-1);
4482 
4483  } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
4484  {
4485  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4486  " != %" PRIu32 " from stream", ssn,
4487  TCP_GET_SEQ(p), ssn->client.next_seq);
4489  SCReturnInt(-1);
4490  }
4491 
4492  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4493  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4494  StreamTcpSetEvent(p, <