suricata
stream-tcp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 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 
32 #include "decode.h"
33 #include "debug.h"
34 #include "detect.h"
35 
36 #include "flow.h"
37 #include "flow-util.h"
38 
39 #include "conf.h"
40 #include "conf-yaml-loader.h"
41 
42 #include "threads.h"
43 #include "threadvars.h"
44 #include "tm-threads.h"
45 
46 #include "util-pool.h"
47 #include "util-pool-thread.h"
48 #include "util-checksum.h"
49 #include "util-unittest.h"
50 #include "util-print.h"
51 #include "util-debug.h"
52 #include "util-device.h"
53 
54 #include "stream-tcp-private.h"
55 #include "stream-tcp-reassemble.h"
56 #include "stream-tcp.h"
57 #include "stream-tcp-inline.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 
78 #include "source-pcap-file.h"
79 
80 //#define DEBUG
81 
82 #define STREAMTCP_DEFAULT_PREALLOC 2048
83 #define STREAMTCP_DEFAULT_MEMCAP (32 * 1024 * 1024) /* 32mb */
84 #define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP (64 * 1024 * 1024) /* 64mb */
85 #define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE 2560
86 #define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE 2560
87 #define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED 5
88 
89 #define STREAMTCP_NEW_TIMEOUT 60
90 #define STREAMTCP_EST_TIMEOUT 3600
91 #define STREAMTCP_CLOSED_TIMEOUT 120
92 
93 #define STREAMTCP_EMERG_NEW_TIMEOUT 10
94 #define STREAMTCP_EMERG_EST_TIMEOUT 300
95 #define STREAMTCP_EMERG_CLOSED_TIMEOUT 20
96 
97 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *, PacketQueue *);
99 void StreamTcpInitConfig(char);
100 int StreamTcpGetFlowState(void *);
103 
104 static int StreamTcpValidateTimestamp(TcpSession * , Packet *);
105 static int StreamTcpHandleTimestamp(TcpSession * , Packet *);
106 static int StreamTcpValidateRst(TcpSession * , Packet *);
107 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *, Packet *);
108 static int StreamTcpStateDispatch(ThreadVars *tv, Packet *p,
109  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq,
110  uint8_t state);
111 
112 extern int g_detect_disabled;
113 
114 static PoolThread *ssn_pool = NULL;
115 static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect initializing and growing pool */
116 #ifdef DEBUG
117 static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */
118 #endif
119 
121 SC_ATOMIC_DECLARE(uint64_t, st_memuse);
122 
124 {
125  SC_ATOMIC_INIT(st_memuse);
126 }
127 
128 void StreamTcpIncrMemuse(uint64_t size)
129 {
130  (void) SC_ATOMIC_ADD(st_memuse, size);
131  SCLogDebug("STREAM %"PRIu64", incr %"PRIu64, StreamTcpMemuseCounter(), size);
132  return;
133 }
134 
135 void StreamTcpDecrMemuse(uint64_t size)
136 {
137 #ifdef DEBUG_VALIDATION
138  uint64_t presize = SC_ATOMIC_GET(st_memuse);
139  if (RunmodeIsUnittests()) {
140  BUG_ON(presize > UINT_MAX);
141  }
142 #endif
143 
144  (void) SC_ATOMIC_SUB(st_memuse, size);
145 
146 #ifdef DEBUG_VALIDATION
147  if (RunmodeIsUnittests()) {
148  uint64_t postsize = SC_ATOMIC_GET(st_memuse);
149  BUG_ON(postsize > presize);
150  }
151 #endif
152  SCLogDebug("STREAM %"PRIu64", decr %"PRIu64, StreamTcpMemuseCounter(), size);
153  return;
154 }
155 
157 {
158  uint64_t memusecopy = SC_ATOMIC_GET(st_memuse);
159  return memusecopy;
160 }
161 
162 /**
163  * \brief Check if alloc'ing "size" would mean we're over memcap
164  *
165  * \retval 1 if in bounds
166  * \retval 0 if not in bounds
167  */
168 int StreamTcpCheckMemcap(uint64_t size)
169 {
170  uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.memcap);
171  if (memcapcopy == 0 || size + SC_ATOMIC_GET(st_memuse) <= memcapcopy)
172  return 1;
173  return 0;
174 }
175 
176 /**
177  * \brief Update memcap value
178  *
179  * \param size new memcap value
180  */
181 int StreamTcpSetMemcap(uint64_t size)
182 {
183  if (size == 0 || (uint64_t)SC_ATOMIC_GET(st_memuse) < size) {
184  SC_ATOMIC_SET(stream_config.memcap, size);
185  return 1;
186  }
187 
188  return 0;
189 }
190 
191 /**
192  * \brief Return memcap value
193  *
194  * \param memcap memcap value
195  */
196 uint64_t StreamTcpGetMemcap(void)
197 {
198  uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.memcap);
199  return memcapcopy;
200 }
201 
203 {
204  if (stream != NULL) {
205  StreamTcpSackFreeList(stream);
207  StreamingBufferClear(&stream->sb);
208  }
209 }
210 
211 /**
212  * \brief Session cleanup function. Does not free the ssn.
213  * \param ssn tcp session
214  */
216 {
217  SCEnter();
218  TcpStateQueue *q, *q_next;
219 
220  if (ssn == NULL)
221  return;
222 
225 
226  q = ssn->queue;
227  while (q != NULL) {
228  q_next = q->next;
229  SCFree(q);
230  q = q_next;
231  StreamTcpDecrMemuse((uint64_t)sizeof(TcpStateQueue));
232  }
233  ssn->queue = NULL;
234  ssn->queue_len = 0;
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. We are guaranteed to only get here when the flow's use_cnt is 0.
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 */
259  PoolThreadReserved a = ssn->res;
260  memset(ssn, 0, sizeof(TcpSession));
261  ssn->res = a;
262 
263  PoolThreadReturn(ssn_pool, ssn);
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  * We don't clear out the app layer storage here as that is under protection
277  * of the "use_cnt" reference counter in the flow. This function is called
278  * when the use_cnt is always at least 1 (this pkt has incremented the flow
279  * use_cnt itself), so we don't bother.
280  *
281  * \param p Packet used to identify the stream.
282  */
284 {
285  SCEnter();
286 
287  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
288  if (ssn == NULL)
289  SCReturn;
290 
293 
294  SCReturn;
295 }
296 
297 /** \brief Stream alloc function for the Pool
298  * \retval ptr void ptr to TcpSession structure with all vars set to 0/NULL
299  */
300 static void *StreamTcpSessionPoolAlloc(void)
301 {
302  void *ptr = NULL;
303 
304  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpSession)) == 0)
305  return NULL;
306 
307  ptr = SCMalloc(sizeof(TcpSession));
308  if (unlikely(ptr == NULL))
309  return NULL;
310 
311  return ptr;
312 }
313 
314 static int StreamTcpSessionPoolInit(void *data, void* initdata)
315 {
316  memset(data, 0, sizeof(TcpSession));
317  StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession));
318 
319  return 1;
320 }
321 
322 /** \brief Pool cleanup function
323  * \param s Void ptr to TcpSession memory */
324 static void StreamTcpSessionPoolCleanup(void *s)
325 {
326  if (s != NULL) {
328  /** \todo not very clean, as the memory is not freed here */
329  StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession));
330  }
331 }
332 
333 /**
334  * \brief See if stream engine is dropping invalid packet in inline mode
335  *
336  * \retval 0 no
337  * \retval 1 yes
338  */
340 {
343 }
344 
345 /* hack: stream random range code expects random values in range of 0-RAND_MAX,
346  * but we can get both <0 and >RAND_MAX values from RandomGet
347  */
348 static int RandomGetWrap(void)
349 {
350  unsigned long r;
351 
352  do {
353  r = RandomGet();
354  } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
355 
356  return r % RAND_MAX;
357 }
358 
359 /** \brief To initialize the stream global configuration data
360  *
361  * \param quiet It tells the mode of operation, if it is TRUE nothing will
362  * be get printed.
363  */
364 
365 void StreamTcpInitConfig(char quiet)
366 {
367  intmax_t value = 0;
368  uint16_t rdrange = 10;
369 
370  SCLogDebug("Initializing Stream");
371 
372  memset(&stream_config, 0, sizeof(stream_config));
373 
375  SC_ATOMIC_INIT(stream_config.reassembly_memcap);
376 
377  if ((ConfGetInt("stream.max-sessions", &value)) == 1) {
378  SCLogWarning(SC_WARN_OPTION_OBSOLETE, "max-sessions is obsolete. "
379  "Number of concurrent sessions is now only limited by Flow and "
380  "TCP stream engine memcaps.");
381  }
382 
383  if ((ConfGetInt("stream.prealloc-sessions", &value)) == 1) {
384  stream_config.prealloc_sessions = (uint32_t)value;
385  } else {
386  if (RunmodeIsUnittests()) {
388  } else {
390  if (ConfGetNode("stream.prealloc-sessions") != NULL) {
391  WarnInvalidConfEntry("stream.prealloc_sessions",
392  "%"PRIu32,
394  }
395  }
396  }
397  if (!quiet) {
398  SCLogConfig("stream \"prealloc-sessions\": %"PRIu32" (per thread)",
400  }
401 
402  const char *temp_stream_memcap_str;
403  if (ConfGetValue("stream.memcap", &temp_stream_memcap_str) == 1) {
404  uint64_t stream_memcap_copy;
405  if (ParseSizeStringU64(temp_stream_memcap_str, &stream_memcap_copy) < 0) {
406  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing stream.memcap "
407  "from conf file - %s. Killing engine",
408  temp_stream_memcap_str);
409  exit(EXIT_FAILURE);
410  } else {
411  SC_ATOMIC_SET(stream_config.memcap, stream_memcap_copy);
412  }
413  } else {
415  }
416 
417  if (!quiet) {
418  SCLogConfig("stream \"memcap\": %"PRIu64, SC_ATOMIC_GET(stream_config.memcap));
419  }
420 
421  ConfGetBool("stream.midstream", &stream_config.midstream);
422 
423  if (!quiet) {
424  SCLogConfig("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled");
425  }
426 
427  ConfGetBool("stream.async-oneside", &stream_config.async_oneside);
428 
429  if (!quiet) {
430  SCLogConfig("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled");
431  }
432 
433  int csum = 0;
434 
435  if ((ConfGetBool("stream.checksum-validation", &csum)) == 1) {
436  if (csum == 1) {
438  }
439  /* Default is that we validate the checksum of all the packets */
440  } else {
442  }
443 
444  if (!quiet) {
445  SCLogConfig("stream \"checksum-validation\": %s",
447  "enabled" : "disabled");
448  }
449 
450  const char *temp_stream_inline_str;
451  if (ConfGetValue("stream.inline", &temp_stream_inline_str) == 1) {
452  int inl = 0;
453 
454  /* checking for "auto" and falling back to boolean to provide
455  * backward compatibility */
456  if (strcmp(temp_stream_inline_str, "auto") == 0) {
457  if (EngineModeIsIPS()) {
459  }
460  } else if (ConfGetBool("stream.inline", &inl) == 1) {
461  if (inl) {
463  }
464  }
465  } else {
466  /* default to 'auto' */
467  if (EngineModeIsIPS()) {
469  }
470  }
471 
472  if (!quiet) {
473  SCLogConfig("stream.\"inline\": %s",
475  ? "enabled" : "disabled");
476  }
477 
478  int bypass = 0;
479  if ((ConfGetBool("stream.bypass", &bypass)) == 1) {
480  if (bypass == 1) {
482  }
483  }
484 
485  if (!quiet) {
486  SCLogConfig("stream \"bypass\": %s",
488  ? "enabled" : "disabled");
489  }
490 
491  int drop_invalid = 0;
492  if ((ConfGetBool("stream.drop-invalid", &drop_invalid)) == 1) {
493  if (drop_invalid == 1) {
495  }
496  } else {
498  }
499 
500  if ((ConfGetInt("stream.max-synack-queued", &value)) == 1) {
501  if (value >= 0 && value <= 255) {
502  stream_config.max_synack_queued = (uint8_t)value;
503  } else {
505  }
506  } else {
508  }
509  if (!quiet) {
510  SCLogConfig("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued);
511  }
512 
513  const char *temp_stream_reassembly_memcap_str;
514  if (ConfGetValue("stream.reassembly.memcap", &temp_stream_reassembly_memcap_str) == 1) {
515  uint64_t stream_reassembly_memcap_copy;
516  if (ParseSizeStringU64(temp_stream_reassembly_memcap_str,
517  &stream_reassembly_memcap_copy) < 0) {
518  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
519  "stream.reassembly.memcap "
520  "from conf file - %s. Killing engine",
521  temp_stream_reassembly_memcap_str);
522  exit(EXIT_FAILURE);
523  } else {
524  SC_ATOMIC_SET(stream_config.reassembly_memcap, stream_reassembly_memcap_copy);
525  }
526  } else {
528  }
529 
530  if (!quiet) {
531  SCLogConfig("stream.reassembly \"memcap\": %"PRIu64"",
532  SC_ATOMIC_GET(stream_config.reassembly_memcap));
533  }
534 
535  const char *temp_stream_reassembly_depth_str;
536  if (ConfGetValue("stream.reassembly.depth", &temp_stream_reassembly_depth_str) == 1) {
537  if (ParseSizeStringU32(temp_stream_reassembly_depth_str,
539  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
540  "stream.reassembly.depth "
541  "from conf file - %s. Killing engine",
542  temp_stream_reassembly_depth_str);
543  exit(EXIT_FAILURE);
544  }
545  } else {
547  }
548 
549  if (!quiet) {
550  SCLogConfig("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth);
551  }
552 
553  int randomize = 0;
554  if ((ConfGetBool("stream.reassembly.randomize-chunk-size", &randomize)) == 0) {
555  /* randomize by default if value not set
556  * In ut mode we disable, to get predictible test results */
557  if (!(RunmodeIsUnittests()))
558  randomize = 1;
559  }
560 
561  if (randomize) {
562  const char *temp_rdrange;
563  if (ConfGetValue("stream.reassembly.randomize-chunk-range",
564  &temp_rdrange) == 1) {
565  if (ParseSizeStringU16(temp_rdrange, &rdrange) < 0) {
566  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
567  "stream.reassembly.randomize-chunk-range "
568  "from conf file - %s. Killing engine",
569  temp_rdrange);
570  exit(EXIT_FAILURE);
571  } else if (rdrange >= 100) {
573  "stream.reassembly.randomize-chunk-range "
574  "must be lower than 100");
575  exit(EXIT_FAILURE);
576  }
577  }
578  }
579 
580  const char *temp_stream_reassembly_toserver_chunk_size_str;
581  if (ConfGetValue("stream.reassembly.toserver-chunk-size",
582  &temp_stream_reassembly_toserver_chunk_size_str) == 1) {
583  if (ParseSizeStringU16(temp_stream_reassembly_toserver_chunk_size_str,
585  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
586  "stream.reassembly.toserver-chunk-size "
587  "from conf file - %s. Killing engine",
588  temp_stream_reassembly_toserver_chunk_size_str);
589  exit(EXIT_FAILURE);
590  }
591  } else {
594  }
595 
596  if (randomize) {
597  long int r = RandomGetWrap();
600  (r * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
601  }
602  const char *temp_stream_reassembly_toclient_chunk_size_str;
603  if (ConfGetValue("stream.reassembly.toclient-chunk-size",
604  &temp_stream_reassembly_toclient_chunk_size_str) == 1) {
605  if (ParseSizeStringU16(temp_stream_reassembly_toclient_chunk_size_str,
607  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
608  "stream.reassembly.toclient-chunk-size "
609  "from conf file - %s. Killing engine",
610  temp_stream_reassembly_toclient_chunk_size_str);
611  exit(EXIT_FAILURE);
612  }
613  } else {
616  }
617 
618  if (randomize) {
619  long int r = RandomGetWrap();
622  (r * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
623  }
624  if (!quiet) {
625  SCLogConfig("stream.reassembly \"toserver-chunk-size\": %"PRIu16,
627  SCLogConfig("stream.reassembly \"toclient-chunk-size\": %"PRIu16,
629  }
630 
631  int enable_raw = 1;
632  if (ConfGetBool("stream.reassembly.raw", &enable_raw) == 1) {
633  if (!enable_raw) {
635  }
636  } else {
637  enable_raw = 1;
638  }
639  if (!quiet)
640  SCLogConfig("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled");
641 
642  /* init the memcap/use tracking */
645 
647 
648  /* set the default free function and flow state function
649  * values. */
651 
652 #ifdef UNITTESTS
653  if (RunmodeIsUnittests()) {
654  SCMutexLock(&ssn_pool_mutex);
655  if (ssn_pool == NULL) {
656  ssn_pool = PoolThreadInit(1, /* thread */
657  0, /* unlimited */
659  sizeof(TcpSession),
660  StreamTcpSessionPoolAlloc,
661  StreamTcpSessionPoolInit, NULL,
662  StreamTcpSessionPoolCleanup, NULL);
663  }
664  SCMutexUnlock(&ssn_pool_mutex);
665  }
666 #endif
667 }
668 
669 void StreamTcpFreeConfig(char quiet)
670 {
672  SC_ATOMIC_DESTROY(stream_config.reassembly_memcap);
673 
675 
676  SCMutexLock(&ssn_pool_mutex);
677  if (ssn_pool != NULL) {
678  PoolThreadFree(ssn_pool);
679  ssn_pool = NULL;
680  }
681  SCMutexUnlock(&ssn_pool_mutex);
682  SCMutexDestroy(&ssn_pool_mutex);
683 
684  SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt);
685 }
686 
687 /** \internal
688  * \brief The function is used to to fetch a TCP session from the
689  * ssn_pool, when a TCP SYN is received.
690  *
691  * \param p packet starting the new TCP session.
692  * \param id thread pool id
693  *
694  * \retval ssn new TCP session.
695  */
696 static TcpSession *StreamTcpNewSession (Packet *p, int id)
697 {
698  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
699 
700  if (ssn == NULL) {
701  p->flow->protoctx = PoolThreadGetById(ssn_pool, id);
702 #ifdef DEBUG
703  SCMutexLock(&ssn_pool_mutex);
704  if (p->flow->protoctx != NULL)
705  ssn_pool_cnt++;
706  SCMutexUnlock(&ssn_pool_mutex);
707 #endif
708 
709  ssn = (TcpSession *)p->flow->protoctx;
710  if (ssn == NULL) {
711  SCLogDebug("ssn_pool is empty");
712  return NULL;
713  }
714 
715  ssn->state = TCP_NONE;
717  ssn->tcp_packet_flags = p->tcph ? p->tcph->th_flags : 0;
720 
722  ssn->client.sb = x;
723  ssn->server.sb = x;
724 
725  if (PKT_IS_TOSERVER(p)) {
726  ssn->client.tcp_flags = p->tcph ? p->tcph->th_flags : 0;
727  ssn->server.tcp_flags = 0;
728  } else if (PKT_IS_TOCLIENT(p)) {
729  ssn->server.tcp_flags = p->tcph ? p->tcph->th_flags : 0;
730  ssn->client.tcp_flags = 0;
731  }
732  }
733 
734  return ssn;
735 }
736 
737 static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn,
738  uint8_t state)
739 {
740  if (state == ssn->state || PKT_IS_PSEUDOPKT(p))
741  return;
742 
743  ssn->pstate = ssn->state;
744  ssn->state = state;
745 
746  /* update the flow state */
747  switch(ssn->state) {
748  case TCP_ESTABLISHED:
749  case TCP_FIN_WAIT1:
750  case TCP_FIN_WAIT2:
751  case TCP_CLOSING:
752  case TCP_CLOSE_WAIT:
754  break;
755  case TCP_LAST_ACK:
756  case TCP_TIME_WAIT:
757  case TCP_CLOSED:
759  break;
760  }
761 }
762 
763 /**
764  * \brief Function to set the OS policy for the given stream based on the
765  * destination of the received packet.
766  *
767  * \param stream TcpStream of which os_policy needs to set
768  * \param p Packet which is used to set the os policy
769  */
771 {
772  int ret = 0;
773 
774  if (PKT_IS_IPV4(p)) {
775  /* Get the OS policy based on destination IP address, as destination
776  OS will decide how to react on the anomalies of newly received
777  packets */
779  if (ret > 0)
780  stream->os_policy = ret;
781  else
782  stream->os_policy = OS_POLICY_DEFAULT;
783 
784  } else if (PKT_IS_IPV6(p)) {
785  /* Get the OS policy based on destination IP address, as destination
786  OS will decide how to react on the anomalies of newly received
787  packets */
788  ret = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
789  if (ret > 0)
790  stream->os_policy = ret;
791  else
792  stream->os_policy = OS_POLICY_DEFAULT;
793  }
794 
795  if (stream->os_policy == OS_POLICY_BSD_RIGHT)
796  stream->os_policy = OS_POLICY_BSD;
797  else if (stream->os_policy == OS_POLICY_OLD_SOLARIS)
798  stream->os_policy = OS_POLICY_SOLARIS;
799 
800  SCLogDebug("Policy is %"PRIu8"", stream->os_policy);
801 
802 }
803 
804 /**
805  * \brief macro to update last_ack only if the new value is higher
806  *
807  * \param ssn session
808  * \param stream stream to update
809  * \param ack ACK value to test and set
810  */
811 #define StreamTcpUpdateLastAck(ssn, stream, ack) { \
812  if (SEQ_GT((ack), (stream)->last_ack)) \
813  { \
814  SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \
815  if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \
816  SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \
817  } else { \
818  SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \
819  }\
820  (stream)->last_ack = (ack); \
821  StreamTcpSackPruneList((stream)); \
822  } else { \
823  SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \
824  (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \
825  }\
826 }
827 
828 #define StreamTcpAsyncLastAckUpdate(ssn, stream) { \
829  if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \
830  if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \
831  uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \
832  (stream)->last_ack += ack_diff; \
833  SCLogDebug("ssn %p: ASYNC last_ack set to %"PRIu32", moved %u forward", \
834  (ssn), (stream)->next_seq, ack_diff); \
835  } \
836  } \
837 }
838 
839 #define StreamTcpUpdateNextSeq(ssn, stream, seq) { \
840  (stream)->next_seq = seq; \
841  SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \
842  StreamTcpAsyncLastAckUpdate((ssn), (stream)); \
843 }
844 
845 /**
846  * \brief macro to update next_win only if the new value is higher
847  *
848  * \param ssn session
849  * \param stream stream to update
850  * \param win window value to test and set
851  */
852 #define StreamTcpUpdateNextWin(ssn, stream, win) { \
853  uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \
854  if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \
855  (stream)->next_win = ((win) + sacked_size__); \
856  SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \
857  } \
858 }
859 
860 static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p)
861 {
862  if (p->payload_len == 0)
863  SCReturnInt(0);
864 
865  /* retransmission of already partially ack'd data */
866  if (SEQ_LT(TCP_GET_SEQ(p), stream->last_ack) && SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack))
867  {
869  SCReturnInt(1);
870  }
871 
872  /* retransmission of already ack'd data */
873  if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) {
875  SCReturnInt(1);
876  }
877 
878  /* retransmission of in flight data */
879  if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->next_seq)) {
881  SCReturnInt(2);
882  }
883 
884  SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", TCP_GET_SEQ(p),
885  p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack, stream->next_seq);
886  SCReturnInt(0);
887 }
888 
889 /**
890  * \internal
891  * \brief Function to handle the TCP_CLOSED or NONE state. The function handles
892  * packets while the session state is None which means a newly
893  * initialized structure, or a fully closed session.
894  *
895  * \param tv Thread Variable containig input/output queue, cpu affinity
896  * \param p Packet which has to be handled in this TCP state.
897  * \param stt Strean Thread module registered to handle the stream handling
898  *
899  * \retval 0 ok
900  * \retval -1 error
901  */
902 static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p,
903  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
904 {
905  if (p->tcph->th_flags & TH_RST) {
907  SCLogDebug("RST packet received, no session setup");
908  return -1;
909 
910  } else if (p->tcph->th_flags & TH_FIN) {
912  SCLogDebug("FIN packet received, no session setup");
913  return -1;
914 
915  /* SYN/ACK */
916  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
917  if (stream_config.midstream == FALSE &&
919  return 0;
920 
921  if (ssn == NULL) {
922  ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
923  if (ssn == NULL) {
925  return -1;
926  }
929  }
930  /* set the state */
931  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
932  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
933  "TCP_SYN_RECV", ssn);
935  /* Flag used to change the direct in the later stage in the session */
938  SCLogDebug("ssn %p: =~ ASYNC", ssn);
939  ssn->flags |= STREAMTCP_FLAG_ASYNC;
940  }
941 
942  /* sequence number & window */
943  ssn->server.isn = TCP_GET_SEQ(p);
945  ssn->server.next_seq = ssn->server.isn + 1;
946  ssn->server.window = TCP_GET_WINDOW(p);
947  SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
948 
949  ssn->client.isn = TCP_GET_ACK(p) - 1;
951  ssn->client.next_seq = ssn->client.isn + 1;
952 
953  ssn->client.last_ack = TCP_GET_ACK(p);
954  ssn->server.last_ack = TCP_GET_SEQ(p);
955 
956  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
957 
958  /** If the client has a wscale option the server had it too,
959  * so set the wscale for the server to max. Otherwise none
960  * will have the wscale opt just like it should. */
961  if (TCP_HAS_WSCALE(p)) {
962  ssn->client.wscale = TCP_GET_WSCALE(p);
964  SCLogDebug("ssn %p: wscale enabled. client %u server %u",
965  ssn, ssn->client.wscale, ssn->server.wscale);
966  }
967 
968  SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
969  " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
970  ssn->client.isn, ssn->client.next_seq,
971  ssn->client.last_ack);
972  SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
973  " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
974  ssn->server.isn, ssn->server.next_seq,
975  ssn->server.last_ack);
976 
977  /* Set the timestamp value for both streams, if packet has timestamp
978  * option enabled.*/
979  if (TCP_HAS_TS(p)) {
980  ssn->server.last_ts = TCP_GET_TSVAL(p);
981  ssn->client.last_ts = TCP_GET_TSECR(p);
982  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
983  "ssn->client.last_ts %" PRIu32"", ssn,
984  ssn->server.last_ts, ssn->client.last_ts);
985 
987 
988  ssn->server.last_pkt_ts = p->ts.tv_sec;
989  if (ssn->server.last_ts == 0)
991  if (ssn->client.last_ts == 0)
993 
994  } else {
995  ssn->server.last_ts = 0;
996  ssn->client.last_ts = 0;
997  }
998 
999  if (TCP_GET_SACKOK(p) == 1) {
1000  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1001  SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
1002  "SACK permitted for both sides", ssn);
1003  }
1004 
1005  /* packet thinks it is in the wrong direction, flip it */
1006  StreamTcpPacketSwitchDir(ssn, p);
1007 
1008  } else if (p->tcph->th_flags & TH_SYN) {
1009  if (ssn == NULL) {
1010  ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
1011  if (ssn == NULL) {
1013  return -1;
1014  }
1015 
1016  StatsIncr(tv, stt->counter_tcp_sessions);
1017  }
1018 
1019  /* set the state */
1020  StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
1021  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
1022 
1024  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1025  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1026  }
1027 
1028  /* set the sequence numbers and window */
1029  ssn->client.isn = TCP_GET_SEQ(p);
1031  ssn->client.next_seq = ssn->client.isn + 1;
1032 
1033  /* Set the stream timestamp value, if packet has timestamp option
1034  * enabled. */
1035  if (TCP_HAS_TS(p)) {
1036  ssn->client.last_ts = TCP_GET_TSVAL(p);
1037  SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
1038 
1039  if (ssn->client.last_ts == 0)
1041 
1042  ssn->client.last_pkt_ts = p->ts.tv_sec;
1044  }
1045 
1046  ssn->server.window = TCP_GET_WINDOW(p);
1047  if (TCP_HAS_WSCALE(p)) {
1049  ssn->server.wscale = TCP_GET_WSCALE(p);
1050  }
1051 
1052  if (TCP_GET_SACKOK(p) == 1) {
1054  SCLogDebug("ssn %p: SACK permited on SYN packet", ssn);
1055  }
1056 
1057  SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
1058  "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
1059  "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
1060  ssn->client.last_ack);
1061 
1062  } else if (p->tcph->th_flags & TH_ACK) {
1063  if (stream_config.midstream == FALSE)
1064  return 0;
1065 
1066  if (ssn == NULL) {
1067  ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
1068  if (ssn == NULL) {
1070  return -1;
1071  }
1072  StatsIncr(tv, stt->counter_tcp_sessions);
1074  }
1075  /* set the state */
1076  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1077  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1078  "TCP_ESTABLISHED", ssn);
1079 
1083  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1084  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1085  }
1086 
1087  /** window scaling for midstream pickups, we can't do much other
1088  * than assume that it's set to the max value: 14 */
1089  ssn->client.wscale = TCP_WSCALE_MAX;
1090  ssn->server.wscale = TCP_WSCALE_MAX;
1091 
1092  /* set the sequence numbers and window */
1093  ssn->client.isn = TCP_GET_SEQ(p) - 1;
1095  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
1096  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1097  ssn->client.last_ack = TCP_GET_SEQ(p);
1098  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1099  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
1100  ssn, ssn->client.isn, ssn->client.next_seq);
1101 
1102  ssn->server.isn = TCP_GET_ACK(p) - 1;
1104  ssn->server.next_seq = ssn->server.isn + 1;
1105  ssn->server.last_ack = TCP_GET_ACK(p);
1106  ssn->server.next_win = ssn->server.last_ack;
1107 
1108  SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
1109  "ssn->server.next_win %"PRIu32"", ssn,
1110  ssn->client.next_win, ssn->server.next_win);
1111  SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
1112  "ssn->server.last_ack %"PRIu32"", ssn,
1113  ssn->client.last_ack, ssn->server.last_ack);
1114 
1115  /* Set the timestamp value for both streams, if packet has timestamp
1116  * option enabled.*/
1117  if (TCP_HAS_TS(p)) {
1118  ssn->client.last_ts = TCP_GET_TSVAL(p);
1119  ssn->server.last_ts = TCP_GET_TSECR(p);
1120  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1121  "ssn->client.last_ts %" PRIu32"", ssn,
1122  ssn->server.last_ts, ssn->client.last_ts);
1123 
1125 
1126  ssn->client.last_pkt_ts = p->ts.tv_sec;
1127  if (ssn->server.last_ts == 0)
1129  if (ssn->client.last_ts == 0)
1131 
1132  } else {
1133  ssn->server.last_ts = 0;
1134  ssn->client.last_ts = 0;
1135  }
1136 
1137  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
1138 
1139  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1140  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1141 
1142  } else {
1143  SCLogDebug("default case");
1144  }
1145 
1146  return 0;
1147 }
1148 
1149 /** \internal
1150  * \brief Setup TcpStateQueue based on SYN/ACK packet
1151  */
1152 static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
1153 {
1154  q->flags = 0;
1155  q->wscale = 0;
1156  q->ts = 0;
1157  q->win = TCP_GET_WINDOW(p);
1158  q->seq = TCP_GET_SEQ(p);
1159  q->ack = TCP_GET_ACK(p);
1160  q->pkt_ts = p->ts.tv_sec;
1161 
1162  if (TCP_GET_SACKOK(p) == 1)
1164 
1165  if (TCP_HAS_WSCALE(p)) {
1167  q->wscale = TCP_GET_WSCALE(p);
1168  }
1169  if (TCP_HAS_TS(p)) {
1171  q->ts = TCP_GET_TSVAL(p);
1172  }
1173 }
1174 
1175 /** \internal
1176  * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
1177  * \retval q or NULL */
1178 static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
1179 {
1180  TcpStateQueue *q = ssn->queue;
1181  TcpStateQueue search;
1182 
1183  StreamTcp3whsSynAckToStateQueue(p, &search);
1184 
1185  while (q != NULL) {
1186  if (search.flags == q->flags &&
1187  search.wscale == q->wscale &&
1188  search.win == q->win &&
1189  search.seq == q->seq &&
1190  search.ack == q->ack &&
1191  search.ts == q->ts) {
1192  return q;
1193  }
1194 
1195  q = q->next;
1196  }
1197 
1198  return q;
1199 }
1200 
1201 static int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
1202 {
1203  /* first see if this is already in our list */
1204  if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
1205  return 0;
1206 
1208  SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
1210  return -1;
1211  }
1212 
1213  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1214  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
1215  return -1;
1216  }
1217 
1218  TcpStateQueue *q = SCMalloc(sizeof(*q));
1219  if (unlikely(q == NULL)) {
1220  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
1221  return -1;
1222  }
1223  memset(q, 0x00, sizeof(*q));
1224  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1225 
1226  StreamTcp3whsSynAckToStateQueue(p, q);
1227 
1228  /* put in list */
1229  q->next = ssn->queue;
1230  ssn->queue = q;
1231  ssn->queue_len++;
1232  return 0;
1233 }
1234 
1235 /** \internal
1236  * \brief Find the Queued SYN/ACK that goes with this ACK
1237  * \retval q or NULL */
1238 static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
1239 {
1240  uint32_t ack = TCP_GET_SEQ(p);
1241  uint32_t seq = TCP_GET_ACK(p) - 1;
1242  TcpStateQueue *q = ssn->queue;
1243 
1244  while (q != NULL) {
1245  if (seq == q->seq &&
1246  ack == q->ack) {
1247  return q;
1248  }
1249 
1250  q = q->next;
1251  }
1252 
1253  return NULL;
1254 }
1255 
1256 /** \internal
1257  * \brief Update SSN after receiving a valid SYN/ACK
1258  *
1259  * Normally we update the SSN from the SYN/ACK packet. But in case
1260  * of queued SYN/ACKs, we can use one of those.
1261  *
1262  * \param ssn TCP session
1263  * \param p Packet
1264  * \param q queued state if used, NULL otherwise
1265  *
1266  * To make sure all SYN/ACK based state updates are in one place,
1267  * this function can updated based on Packet or TcpStateQueue, where
1268  * the latter takes precedence.
1269  */
1270 static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
1271 {
1272  TcpStateQueue update;
1273  if (likely(q == NULL)) {
1274  StreamTcp3whsSynAckToStateQueue(p, &update);
1275  q = &update;
1276  }
1277 
1278  if (ssn->state != TCP_SYN_RECV) {
1279  /* update state */
1280  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1281  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
1282  }
1283  /* sequence number & window */
1284  ssn->server.isn = q->seq;
1286  ssn->server.next_seq = ssn->server.isn + 1;
1287 
1288  ssn->client.window = q->win;
1289  SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
1290 
1291  /* Set the timestamp values used to validate the timestamp of
1292  * received packets.*/
1293  if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
1295  {
1296  ssn->server.last_ts = q->ts;
1297  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1298  "ssn->client.last_ts %" PRIu32"", ssn,
1299  ssn->server.last_ts, ssn->client.last_ts);
1301  ssn->server.last_pkt_ts = q->pkt_ts;
1302  if (ssn->server.last_ts == 0)
1304  } else {
1305  ssn->client.last_ts = 0;
1306  ssn->server.last_ts = 0;
1308  }
1309 
1310  ssn->client.last_ack = q->ack;
1311  ssn->server.last_ack = ssn->server.isn + 1;
1312 
1313  /** check for the presense of the ws ptr to determine if we
1314  * support wscale at all */
1315  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1317  {
1318  ssn->client.wscale = q->wscale;
1319  } else {
1320  ssn->client.wscale = 0;
1321  }
1322 
1323  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1325  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1326  SCLogDebug("ssn %p: SACK permitted for session", ssn);
1327  } else {
1328  ssn->flags &= ~STREAMTCP_FLAG_SACKOK;
1329  }
1330 
1331  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1332  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1333  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
1334  ssn->server.next_win);
1335  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
1336  ssn->client.next_win);
1337  SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
1338  "ssn->server.next_seq %" PRIu32 ", "
1339  "ssn->server.last_ack %" PRIu32 " "
1340  "(ssn->client.last_ack %" PRIu32 ")", ssn,
1341  ssn->server.isn, ssn->server.next_seq,
1342  ssn->server.last_ack, ssn->client.last_ack);
1343 
1344  /* unset the 4WHS flag as we received this SYN/ACK as part of a
1345  * (so far) valid 3WHS */
1346  if (ssn->flags & STREAMTCP_FLAG_4WHS)
1347  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
1348  " so considering 3WHS", ssn);
1349 
1350  ssn->flags &=~ STREAMTCP_FLAG_4WHS;
1351 }
1352 
1353 /**
1354  * \brief Function to handle the TCP_SYN_SENT state. The function handles
1355  * SYN, SYN/ACK, RST packets and correspondingly changes the connection
1356  * state.
1357  *
1358  * \param tv Thread Variable containig input/output queue, cpu affinity
1359  * \param p Packet which has to be handled in this TCP state.
1360  * \param stt Strean Thread module registered to handle the stream handling
1361  */
1362 
1363 static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p,
1364  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
1365 {
1366  if (ssn == NULL)
1367  return -1;
1368 
1369  SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ?
1370  "toclient":"toserver");
1371 
1372  /* RST */
1373  if (p->tcph->th_flags & TH_RST) {
1374  if (!StreamTcpValidateRst(ssn, p))
1375  return -1;
1376 
1377  if (PKT_IS_TOSERVER(p)) {
1378  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) &&
1379  SEQ_EQ(TCP_GET_WINDOW(p), 0) &&
1380  SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1)))
1381  {
1382  SCLogDebug("ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
1384 
1385  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1386  SCLogDebug("ssn %p: Reset received and state changed to "
1387  "TCP_CLOSED", ssn);
1388  }
1389  } else {
1391  SCLogDebug("ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
1392  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1393  SCLogDebug("ssn %p: Reset received and state changed to "
1394  "TCP_CLOSED", ssn);
1395  }
1396 
1397  /* FIN */
1398  } else if (p->tcph->th_flags & TH_FIN) {
1399  /** \todo */
1400 
1401  /* SYN/ACK */
1402  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
1403  if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOSERVER(p)) {
1404  SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
1405 
1406  /* Check if the SYN/ACK packet ack's the earlier
1407  * received SYN packet. */
1408  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->server.isn + 1))) {
1410 
1411  SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %"PRIu32""
1412  " != %" PRIu32 " from stream", ssn,
1413  TCP_GET_ACK(p), ssn->server.isn + 1);
1414  return -1;
1415  }
1416 
1417  /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
1418  * packet. */
1419  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
1421 
1422  SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %"PRIu32""
1423  " != %" PRIu32 " from *first* SYN pkt", ssn,
1424  TCP_GET_SEQ(p), ssn->client.isn);
1425  return -1;
1426  }
1427 
1428 
1429  /* update state */
1430  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1431  SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
1432 
1433  /* sequence number & window */
1434  ssn->client.isn = TCP_GET_SEQ(p);
1436  ssn->client.next_seq = ssn->client.isn + 1;
1437 
1438  ssn->server.window = TCP_GET_WINDOW(p);
1439  SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn,
1440  ssn->client.window);
1441 
1442  /* Set the timestamp values used to validate the timestamp of
1443  * received packets. */
1444  if ((TCP_HAS_TS(p)) &&
1446  {
1447  ssn->client.last_ts = TCP_GET_TSVAL(p);
1448  SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32" "
1449  "ssn->server.last_ts %" PRIu32"", ssn,
1450  ssn->client.last_ts, ssn->server.last_ts);
1452  ssn->client.last_pkt_ts = p->ts.tv_sec;
1453  if (ssn->client.last_ts == 0)
1455  } else {
1456  ssn->server.last_ts = 0;
1457  ssn->client.last_ts = 0;
1459  }
1460 
1461  ssn->server.last_ack = TCP_GET_ACK(p);
1462  ssn->client.last_ack = ssn->client.isn + 1;
1463 
1464  /** check for the presense of the ws ptr to determine if we
1465  * support wscale at all */
1466  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1467  (TCP_HAS_WSCALE(p)))
1468  {
1469  ssn->server.wscale = TCP_GET_WSCALE(p);
1470  } else {
1471  ssn->server.wscale = 0;
1472  }
1473 
1474  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1475  TCP_GET_SACKOK(p) == 1) {
1476  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1477  SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
1478  }
1479 
1480  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1481  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1482  SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn,
1483  ssn->client.next_win);
1484  SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn,
1485  ssn->server.next_win);
1486  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
1487  "ssn->client.next_seq %" PRIu32 ", "
1488  "ssn->client.last_ack %" PRIu32 " "
1489  "(ssn->server.last_ack %" PRIu32 ")", ssn,
1490  ssn->client.isn, ssn->client.next_seq,
1491  ssn->client.last_ack, ssn->server.last_ack);
1492 
1493  /* done here */
1494  return 0;
1495  }
1496 
1497  if (PKT_IS_TOSERVER(p)) {
1499  SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
1500  return -1;
1501  }
1502 
1503  /* Check if the SYN/ACK packet ack's the earlier
1504  * received SYN packet. */
1505  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) {
1507  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1508  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1509  ssn->client.isn + 1);
1510  return -1;
1511  }
1512 
1513  StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
1514 
1515  } else if (p->tcph->th_flags & TH_SYN) {
1516  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
1517  if (ssn->flags & STREAMTCP_FLAG_4WHS) {
1518  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
1519  "4WHS SYN", ssn);
1520  }
1521 
1522  if (PKT_IS_TOCLIENT(p)) {
1523  /** a SYN only packet in the opposite direction could be:
1524  * http://www.breakingpointsystems.com/community/blog/tcp-
1525  * portals-the-three-way-handshake-is-a-lie
1526  *
1527  * \todo improve resetting the session */
1528 
1529  /* indicate that we're dealing with 4WHS here */
1530  ssn->flags |= STREAMTCP_FLAG_4WHS;
1531  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
1532 
1533  /* set the sequence numbers and window for server
1534  * We leave the ssn->client.isn in place as we will
1535  * check the SYN/ACK pkt with that.
1536  */
1537  ssn->server.isn = TCP_GET_SEQ(p);
1539  ssn->server.next_seq = ssn->server.isn + 1;
1540 
1541  /* Set the stream timestamp value, if packet has timestamp
1542  * option enabled. */
1543  if (TCP_HAS_TS(p)) {
1544  ssn->server.last_ts = TCP_GET_TSVAL(p);
1545  SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
1546 
1547  if (ssn->server.last_ts == 0)
1549  ssn->server.last_pkt_ts = p->ts.tv_sec;
1551  }
1552 
1553  ssn->server.window = TCP_GET_WINDOW(p);
1554  if (TCP_HAS_WSCALE(p)) {
1556  ssn->server.wscale = TCP_GET_WSCALE(p);
1557  } else {
1559  ssn->server.wscale = 0;
1560  }
1561 
1562  if (TCP_GET_SACKOK(p) == 1) {
1564  } else {
1566  }
1567 
1568  SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
1569  "ssn->server.next_seq %" PRIu32 ", "
1570  "ssn->server.last_ack %"PRIu32"", ssn,
1571  ssn->server.isn, ssn->server.next_seq,
1572  ssn->server.last_ack);
1573  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
1574  "ssn->client.next_seq %" PRIu32 ", "
1575  "ssn->client.last_ack %"PRIu32"", ssn,
1576  ssn->client.isn, ssn->client.next_seq,
1577  ssn->client.last_ack);
1578  }
1579 
1580  /** \todo check if it's correct or set event */
1581 
1582  } else if (p->tcph->th_flags & TH_ACK) {
1583  /* Handle the asynchronous stream, when we receive a SYN packet
1584  and now istead of receving a SYN/ACK we receive a ACK from the
1585  same host, which sent the SYN, this suggests the ASNYC streams.*/
1587  return 0;
1588 
1589  /* we are in AYNC (one side) mode now. */
1590 
1591  /* one side async means we won't see a SYN/ACK, so we can
1592  * only check the SYN. */
1593  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) {
1595 
1596  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
1597  "%" PRIu32 " from stream",ssn, TCP_GET_SEQ(p),
1598  ssn->client.next_seq);
1599  return -1;
1600  }
1601 
1602  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1603  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1604  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1605 
1606  ssn->client.window = TCP_GET_WINDOW(p);
1607  ssn->client.last_ack = TCP_GET_SEQ(p);
1608  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1609 
1610  /* Set the server side parameters */
1611  ssn->server.isn = TCP_GET_ACK(p) - 1;
1613  ssn->server.next_seq = ssn->server.isn + 1;
1614  ssn->server.last_ack = ssn->server.next_seq;
1615  ssn->server.next_win = ssn->server.last_ack;
1616 
1617  SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
1618  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
1619  "ssn->client.next_seq %" PRIu32 ""
1620  ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
1621  + p->payload_len, ssn->client.next_seq);
1622 
1623  /* if SYN had wscale, assume it to be supported. Otherwise
1624  * we know it not to be supported. */
1625  if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
1626  ssn->client.wscale = TCP_WSCALE_MAX;
1627  }
1628 
1629  /* Set the timestamp values used to validate the timestamp of
1630  * received packets.*/
1631  if (TCP_HAS_TS(p) &&
1633  {
1636  ssn->client.last_pkt_ts = p->ts.tv_sec;
1637  } else {
1638  ssn->client.last_ts = 0;
1640  }
1641 
1642  if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
1643  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1644  }
1645 
1647  &ssn->client, p, pq);
1648 
1649  } else {
1650  SCLogDebug("ssn %p: default case", ssn);
1651  }
1652 
1653  return 0;
1654 }
1655 
1656 /**
1657  * \brief Function to handle the TCP_SYN_RECV state. The function handles
1658  * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
1659  * the connection state.
1660  *
1661  * \param tv Thread Variable containig input/output queue, cpu affinity
1662  * \param p Packet which has to be handled in this TCP state.
1663  * \param stt Strean Thread module registered to handle the stream handling
1664  *
1665  * \retval 0 ok
1666  * \retval -1 error
1667  */
1668 
1669 static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p,
1670  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
1671 {
1672  if (ssn == NULL)
1673  return -1;
1674 
1675  if (p->tcph->th_flags & TH_RST) {
1676  if (!StreamTcpValidateRst(ssn, p))
1677  return -1;
1678 
1679  uint8_t reset = TRUE;
1680  /* After receiveing the RST in SYN_RECV state and if detection
1681  evasion flags has been set, then the following operating
1682  systems will not closed the connection. As they consider the
1683  packet as stray packet and not belonging to the current
1684  session, for more information check
1685  http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
1687  if (PKT_IS_TOSERVER(p)) {
1688  if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
1689  (ssn->server.os_policy == OS_POLICY_OLD_LINUX) ||
1691  {
1692  reset = FALSE;
1693  SCLogDebug("Detection evasion has been attempted, so"
1694  " not resetting the connection !!");
1695  }
1696  } else {
1697  if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
1698  (ssn->client.os_policy == OS_POLICY_OLD_LINUX) ||
1700  {
1701  reset = FALSE;
1702  SCLogDebug("Detection evasion has been attempted, so"
1703  " not resetting the connection !!");
1704  }
1705  }
1706  }
1707 
1708  if (reset == TRUE) {
1709  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1710  SCLogDebug("ssn %p: Reset received and state changed to "
1711  "TCP_CLOSED", ssn);
1712 
1713  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1714  StreamTcpHandleTimestamp(ssn, p);
1715  }
1716  }
1717 
1718  } else if (p->tcph->th_flags & TH_FIN) {
1719  /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
1720  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1721  if (!StreamTcpValidateTimestamp(ssn, p))
1722  return -1;
1723  }
1724 
1725  if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1)
1726  return -1;
1727 
1728  /* SYN/ACK */
1729  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
1730  SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
1731 
1732  if (PKT_IS_TOSERVER(p)) {
1733  SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
1734 
1736  return -1;
1737  }
1738 
1739  /* Check if the SYN/ACK packets ACK matches the earlier
1740  * received SYN/ACK packet. */
1741  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
1742  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1743  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1744  ssn->client.isn + 1);
1745 
1747  return -1;
1748  }
1749 
1750  /* Check if the SYN/ACK packet SEQ the earlier
1751  * received SYN/ACK packet, server resend with different ISN. */
1752  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
1753  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
1754  "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
1755  ssn->client.isn);
1756 
1757  if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
1758  return -1;
1759  SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
1760  }
1761 
1762  } else if (p->tcph->th_flags & TH_SYN) {
1763  SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
1764 
1765  if (PKT_IS_TOCLIENT(p)) {
1766  SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
1767 
1769  return -1;
1770  }
1771 
1772  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
1773  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
1774 
1776  return -1;
1777  }
1778 
1779  } else if (p->tcph->th_flags & TH_ACK) {
1780  if (ssn->queue_len) {
1781  SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
1782  TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
1783  if (q != NULL) {
1784  SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
1785  StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
1786  } else {
1787  SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
1788  }
1789  }
1790 
1791 
1792  /* If the timestamp option is enabled for both the streams, then
1793  * validate the received packet timestamp value against the
1794  * stream->last_ts. If the timestamp is valid then process the
1795  * packet normally otherwise the drop the packet (RFC 1323)*/
1796  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1797  if (!(StreamTcpValidateTimestamp(ssn, p))) {
1798  return -1;
1799  }
1800  }
1801 
1802  if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) {
1803  SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
1804 
1805  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) {
1806  SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
1808  return -1;
1809  }
1810 
1811  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
1812  SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
1814  return -1;
1815  }
1816 
1817  SCLogDebug("4WHS normal pkt");
1818  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
1819  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
1820  TCP_GET_SEQ(p), TCP_GET_ACK(p));
1821 
1822  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1823  StreamTcpHandleTimestamp(ssn, p);
1824  }
1825 
1826  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
1827  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
1828  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1829  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1830 
1831  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1832  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1833 
1835  &ssn->server, p, pq);
1836 
1837  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
1838  "ssn->client.last_ack %"PRIu32"", ssn,
1839  ssn->client.next_win, ssn->client.last_ack);
1840  return 0;
1841  }
1842 
1843  bool ack_indicates_missed_3whs_ack_packet = false;
1844  /* Check if the ACK received is in right direction. But when we have
1845  * picked up a mid stream session after missing the initial SYN pkt,
1846  * in this case the ACK packet can arrive from either client (normal
1847  * case) or from server itself (asynchronous streams). Therefore
1848  * the check has been avoided in this case */
1849  if (PKT_IS_TOCLIENT(p)) {
1850  /* special case, handle 4WHS, so SYN/ACK in the opposite
1851  * direction */
1853  SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
1854  "pickup session",ssn);
1855  /* fall through */
1856 
1857  } else {
1858  /* if we missed traffic between the S/SA and the current
1859  * 'wrong direction' ACK, we could end up here. In IPS
1860  * reject it. But in IDS mode we continue.
1861  *
1862  * IPS rejects as it should see all packets, so pktloss
1863  * should lead to retransmissions. As this can also be
1864  * pattern for MOTS/MITM injection attacks, we need to be
1865  * careful.
1866  */
1867  if (StreamTcpInlineMode()) {
1868  if (p->payload_len > 0 &&
1869  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) &&
1870  SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
1871  /* packet loss is possible but unlikely here */
1872  SCLogDebug("ssn %p: possible data injection", ssn);
1874  return -1;
1875  }
1876 
1877  SCLogDebug("ssn %p: ACK received in the wrong direction",
1878  ssn);
1880  return -1;
1881  }
1882  ack_indicates_missed_3whs_ack_packet = true;
1883  }
1884  }
1885 
1886  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
1887  ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
1888  TCP_GET_ACK(p));
1889 
1890  /* Check both seq and ack number before accepting the packet and
1891  changing to ESTABLISHED state */
1892  if ((SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) &&
1893  SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) {
1894  SCLogDebug("normal pkt");
1895 
1896  /* process the packet normal, No Async streams :) */
1897 
1898  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1899  StreamTcpHandleTimestamp(ssn, p);
1900  }
1901 
1902  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
1903  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
1904  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
1905 
1906  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1907 
1908  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
1909  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1910  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1911  ssn->server.next_win = ssn->server.last_ack +
1912  ssn->server.window;
1913  if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
1914  /* window scaling for midstream pickups, we can't do much
1915  * other than assume that it's set to the max value: 14 */
1916  ssn->server.wscale = TCP_WSCALE_MAX;
1917  ssn->client.wscale = TCP_WSCALE_MAX;
1918  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1919  }
1920  }
1921 
1922  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1923  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1924 
1926  &ssn->client, p, pq);
1927 
1928  /* If asynchronous stream handling is allowed then set the session,
1929  if packet's seq number is equal the expected seq no.*/
1930  } else if (stream_config.async_oneside == TRUE &&
1931  (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)))
1932  {
1933  /*set the ASYNC flag used to indicate the session as async stream
1934  and helps in relaxing the windows checks.*/
1935  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1936  ssn->server.next_seq += p->payload_len;
1937  ssn->server.last_ack = TCP_GET_SEQ(p);
1938 
1939  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1940  ssn->client.last_ack = TCP_GET_ACK(p);
1941 
1942  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1943  StreamTcpHandleTimestamp(ssn, p);
1944  }
1945 
1946  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
1947  ssn->server.window = TCP_GET_WINDOW(p);
1948  ssn->client.next_win = ssn->server.last_ack +
1949  ssn->server.window;
1950  /* window scaling for midstream pickups, we can't do much
1951  * other than assume that it's set to the max value: 14 */
1952  ssn->server.wscale = TCP_WSCALE_MAX;
1953  ssn->client.wscale = TCP_WSCALE_MAX;
1954  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1955  }
1956 
1957  SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
1958  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
1959  "ssn->server.next_seq %" PRIu32 "\n"
1960  , ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
1961  + p->payload_len, ssn->server.next_seq);
1962 
1963  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1964  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1965 
1967  &ssn->server, p, pq);
1968  /* Upon receiving the packet with correct seq number and wrong
1969  ACK number, it causes the other end to send RST. But some target
1970  system (Linux & solaris) does not RST the connection, so it is
1971  likely to avoid the detection */
1972  } else if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)){
1974  SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
1975  ssn);
1976 
1978  return -1;
1979 
1980  /* if we get a packet with a proper ack, but a seq that is beyond
1981  * next_seq but in-window, we probably missed some packets */
1982  } else if (SEQ_GT(TCP_GET_SEQ(p), ssn->client.next_seq) &&
1983  SEQ_LEQ(TCP_GET_SEQ(p),ssn->client.next_win) &&
1984  SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq))
1985  {
1986  SCLogDebug("ssn %p: ACK for missing data", ssn);
1987 
1988  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1989  StreamTcpHandleTimestamp(ssn, p);
1990  }
1991 
1992  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
1993 
1994  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
1995  SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
1996  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
1997 
1998  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1999 
2000  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2001  ssn->client.window = TCP_GET_WINDOW(p);
2002  ssn->server.next_win = ssn->server.last_ack +
2003  ssn->server.window;
2004  /* window scaling for midstream pickups, we can't do much
2005  * other than assume that it's set to the max value: 14 */
2006  ssn->server.wscale = TCP_WSCALE_MAX;
2007  ssn->client.wscale = TCP_WSCALE_MAX;
2008  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2009  }
2010 
2011  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2012  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2013 
2015  &ssn->client, p, pq);
2016 
2017  /* toclient packet: after having missed the 3whs's final ACK */
2018  } else if (ack_indicates_missed_3whs_ack_packet &&
2019  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) &&
2020  SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))
2021  {
2022  SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2023 
2024  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2025 
2026  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2027  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2028 
2029  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2030  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2031 
2033  &ssn->server, p, pq);
2034 
2035  } else {
2036  SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2037 
2039  return -1;
2040  }
2041 
2042  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2043  "ssn->server.last_ack %"PRIu32"", ssn,
2044  ssn->server.next_win, ssn->server.last_ack);
2045  } else {
2046  SCLogDebug("ssn %p: default case", ssn);
2047  }
2048 
2049  return 0;
2050 }
2051 
2052 /**
2053  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2054  * sent by the client to server. The function handles
2055  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2056  * the reassembly.
2057  *
2058  * Timestamp has already been checked at this point.
2059  *
2060  * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2061  * \param ssn Pointer to the current TCP session
2062  * \param p Packet which has to be handled in this TCP state.
2063  * \param stt Strean Thread module registered to handle the stream handling
2064  */
2065 static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Packet *p,
2066  StreamTcpThread *stt, PacketQueue *pq)
2067 {
2068  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2069  "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
2071 
2072  if (StreamTcpValidateAck(ssn, &(ssn->server), p) == -1) {
2073  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2075  return -1;
2076  }
2077 
2078  /* check for Keep Alive */
2079  if ((p->payload_len == 0 || p->payload_len == 1) &&
2080  (TCP_GET_SEQ(p) == (ssn->client.next_seq - 1))) {
2081  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2082 
2083  /* normal pkt */
2084  } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack))) {
2085  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2086  SCLogDebug("ssn %p: server => Asynchrouns stream, packet SEQ"
2087  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2088  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2089  "%" PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2090  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2091  ssn->client.last_ack, ssn->client.next_win,
2092  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2093 
2094  /* update the last_ack to current seq number as the session is
2095  * async and other stream is not updating it anymore :( */
2096  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2097 
2098  } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p)) &&
2100  (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2101  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2102  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2103  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2104  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2105  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2106  ssn->client.last_ack, ssn->client.next_win,
2107  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2108 
2109  /* it seems we missed SYN and SYN/ACK packets of this session.
2110  * Update the last_ack to current seq number as the session
2111  * is async and other stream is not updating it anymore :( */
2112  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2113  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2114 
2115  } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2117  (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2118  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2119  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2120  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2121  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2122  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2123  ssn->client.last_ack, ssn->client.next_win,
2124  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2125 
2126  /* it seems we missed SYN and SYN/ACK packets of this session.
2127  * Update the last_ack to current seq number as the session
2128  * is async and other stream is not updating it anymore :(*/
2129  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2130  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2131 
2132  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2133  * In this case we do accept the data before last_ack if it is (partly)
2134  * beyond next seq */
2135  } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
2137  {
2138  SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2139  " before last_ack %"PRIu32", after next_seq %"PRIu32":"
2140  " acked data that we haven't seen before",
2141  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->client.last_ack, ssn->client.next_seq);
2142  if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq)) {
2143  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2144  }
2145  } else {
2146  SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
2147  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2148  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2149  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2150  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2151  ssn->client.last_ack, ssn->client.next_win,
2152  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2153 
2154  SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
2156  return -1;
2157  }
2158  }
2159 
2160  int zerowindowprobe = 0;
2161  /* zero window probe */
2162  if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->client.next_seq && ssn->client.window == 0) {
2163  SCLogDebug("ssn %p: zero window probe", ssn);
2164  zerowindowprobe = 1;
2165 
2166  /* expected packet */
2167  } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2168  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2169 
2170  /* not completely as expected, but valid */
2171  } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->client.next_seq) &&
2172  SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->client.next_seq))
2173  {
2174  StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
2175  SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32
2176  " (started before next_seq, ended after)",
2177  ssn, ssn->client.next_seq);
2178 
2179  /* if next_seq has fallen behind last_ack, we got some catching up to do */
2180  } else if (SEQ_LT(ssn->client.next_seq, ssn->client.last_ack)) {
2181  StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
2182  SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32
2183  " (next_seq had fallen behind last_ack)",
2184  ssn, ssn->client.next_seq);
2185 
2186  } else {
2187  SCLogDebug("ssn %p: no update to ssn->client.next_seq %"PRIu32
2188  " SEQ %u SEQ+ %u last_ack %u",
2189  ssn, ssn->client.next_seq,
2191  }
2192 
2193  /* in window check */
2194  if (zerowindowprobe) {
2195  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2196  } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
2198  {
2199  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
2200  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
2201 
2202  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2203  SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
2204  ssn->server.window);
2205 
2206  /* Check if the ACK value is sane and inside the window limit */
2207  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2208  SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, ssn->server.next_seq);
2209 
2210  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2211  StreamTcpHandleTimestamp(ssn, p);
2212  }
2213 
2215 
2216  /* update next_win */
2217  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
2218 
2219  /* handle data (if any) */
2220  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
2221 
2222  } else {
2223  SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
2224  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2225  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2226  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2227  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2228  ssn->client.last_ack, ssn->client.next_win,
2229  (TCP_GET_SEQ(p) + p->payload_len) - ssn->client.next_win);
2230  SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
2231  StreamTcpSackedSize(&ssn->client));
2233  return -1;
2234  }
2235  return 0;
2236 }
2237 
2238 /**
2239  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2240  * sent by the server to client. The function handles
2241  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2242  * the reassembly
2243  *
2244  * Timestamp has already been checked at this point.
2245  *
2246  * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2247  * \param ssn Pointer to the current TCP session
2248  * \param p Packet which has to be handled in this TCP state.
2249  * \param stt Strean Thread module registered to handle the stream handling
2250  */
2251 static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Packet *p,
2252  StreamTcpThread *stt, PacketQueue *pq)
2253 {
2254  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
2255  " ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
2257 
2258  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2259  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2261  return -1;
2262  }
2263 
2264  /* To get the server window value from the servers packet, when connection
2265  is picked up as midstream */
2266  if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
2268  {
2269  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2270  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2272  SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
2273  "%" PRIu32 "", ssn, ssn->server.next_win);
2274  }
2275 
2276  /* check for Keep Alive */
2277  if ((p->payload_len == 0 || p->payload_len == 1) &&
2278  (TCP_GET_SEQ(p) == (ssn->server.next_seq - 1))) {
2279  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2280 
2281  /* normal pkt */
2282  } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->server.last_ack))) {
2283  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2284 
2285  SCLogDebug("ssn %p: client => Asynchrouns stream, packet SEQ"
2286  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2287  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2288  " %"PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2289  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2290  ssn->server.last_ack, ssn->server.next_win,
2291  TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
2292 
2293  ssn->server.last_ack = TCP_GET_SEQ(p);
2294 
2295  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2296  * In this case we do accept the data before last_ack if it is (partly)
2297  * beyond next seq */
2298  } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
2300  {
2301  SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2302  " before last_ack %"PRIu32", after next_seq %"PRIu32":"
2303  " acked data that we haven't seen before",
2304  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2305  if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq)) {
2306  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2307  }
2308  } else {
2309  SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2310  " before last_ack %"PRIu32". next_seq %"PRIu32,
2311  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2313  return -1;
2314  }
2315  }
2316 
2317  int zerowindowprobe = 0;
2318  /* zero window probe */
2319  if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->server.next_seq && ssn->server.window == 0) {
2320  SCLogDebug("ssn %p: zero window probe", ssn);
2321  zerowindowprobe = 1;
2322 
2323  /* expected packet */
2324  } else if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
2325  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2326 
2327  /* not completely as expected, but valid */
2328  } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->server.next_seq) &&
2329  SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->server.next_seq))
2330  {
2331  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2332  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32
2333  " (started before next_seq, ended after)",
2334  ssn, ssn->server.next_seq);
2335 
2336  /* if next_seq has fallen behind last_ack, we got some catching up to do */
2337  } else if (SEQ_LT(ssn->server.next_seq, ssn->server.last_ack)) {
2338  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2339  SCLogDebug("ssn %p: ssn->server.next_seq %"PRIu32
2340  " (next_seq had fallen behind last_ack)",
2341  ssn, ssn->server.next_seq);
2342 
2343  } else {
2344  SCLogDebug("ssn %p: no update to ssn->server.next_seq %"PRIu32
2345  " SEQ %u SEQ+ %u last_ack %u",
2346  ssn, ssn->server.next_seq,
2348  }
2349 
2350  if (zerowindowprobe) {
2351  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2352  } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
2354  {
2355  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
2356  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
2357  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2358  SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
2359  ssn->client.window);
2360 
2361  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2362 
2363  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2364  StreamTcpHandleTimestamp(ssn, p);
2365  }
2366 
2368 
2369  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
2370 
2371  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
2372  } else {
2373  SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
2374  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2375  " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
2376  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2377  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2378  ssn->server.last_ack, ssn->server.next_win,
2379  TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
2381  return -1;
2382  }
2383  return 0;
2384 }
2385 
2386 /**
2387  * \internal
2388  *
2389  * \brief Find the highest sequence number needed to consider all segments as ACK'd
2390  *
2391  * Used to treat all segments as ACK'd upon receiving a valid RST.
2392  *
2393  * \param stream stream to inspect the segments from
2394  * \param seq sequence number to check against
2395  *
2396  * \retval ack highest ack we need to set
2397  */
2398 static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
2399 {
2400  uint32_t ack = seq;
2401 
2402  if (STREAM_HAS_SEEN_DATA(stream)) {
2403  const uint32_t tail_seq = STREAM_SEQ_RIGHT_EDGE(stream);
2404  if (SEQ_GT(tail_seq, ack)) {
2405  ack = tail_seq;
2406  }
2407  }
2408 
2409  SCReturnUInt(ack);
2410 }
2411 
2412 /**
2413  * \brief Function to handle the TCP_ESTABLISHED state. The function handles
2414  * ACK, FIN, RST packets and correspondingly changes the connection
2415  * state. The function handles the data inside packets and call
2416  * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
2417  *
2418  * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2419  * \param p Packet which has to be handled in this TCP state.
2420  * \param stt Strean Thread module registered to handle the stream handling
2421  */
2422 
2423 static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p,
2424  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
2425 {
2426  if (ssn == NULL)
2427  return -1;
2428 
2429  if (p->tcph->th_flags & TH_RST) {
2430  if (!StreamTcpValidateRst(ssn, p))
2431  return -1;
2432 
2433  if (PKT_IS_TOSERVER(p)) {
2434  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
2435  SCLogDebug("ssn %p: Reset received and state changed to "
2436  "TCP_CLOSED", ssn);
2437 
2438  ssn->server.next_seq = TCP_GET_ACK(p);
2439  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2440  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2441  ssn->server.next_seq);
2442  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2443 
2444  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
2445  StreamTcpUpdateLastAck(ssn, &ssn->server,
2446  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
2447 
2448  StreamTcpUpdateLastAck(ssn, &ssn->client,
2449  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
2450 
2451  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2452  StreamTcpHandleTimestamp(ssn, p);
2453  }
2454 
2456  &ssn->client, p, pq);
2457  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2458  "%" PRIu32 "", ssn, ssn->client.next_seq,
2459  ssn->server.last_ack);
2460 
2461  /* don't return packets to pools here just yet, the pseudo
2462  * packet will take care, otherwise the normal session
2463  * cleanup. */
2464  } else {
2465  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
2466  SCLogDebug("ssn %p: Reset received and state changed to "
2467  "TCP_CLOSED", ssn);
2468 
2469  ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1;
2470  ssn->client.next_seq = TCP_GET_ACK(p);
2471 
2472  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2473  ssn->server.next_seq);
2474  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2475 
2476  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
2477  StreamTcpUpdateLastAck(ssn, &ssn->client,
2478  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
2479 
2480  StreamTcpUpdateLastAck(ssn, &ssn->server,
2481  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
2482 
2483  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2484  StreamTcpHandleTimestamp(ssn, p);
2485  }
2486 
2488  &ssn->server, p, pq);
2489  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2490  "%" PRIu32 "", ssn, ssn->server.next_seq,
2491  ssn->client.last_ack);
2492 
2493  /* don't return packets to pools here just yet, the pseudo
2494  * packet will take care, otherwise the normal session
2495  * cleanup. */
2496  }
2497 
2498  } else if (p->tcph->th_flags & TH_FIN) {
2499  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2500  if (!StreamTcpValidateTimestamp(ssn, p))
2501  return -1;
2502  }
2503 
2504  SCLogDebug("ssn (%p: FIN received SEQ"
2505  " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
2506  " win %" PRIu32 "", ssn, ssn->server.next_seq,
2507  ssn->client.last_ack, ssn->server.next_win,
2508  ssn->server.window);
2509 
2510  if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1)
2511  return -1;
2512 
2513  /* SYN/ACK */
2514  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
2515  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
2516  ssn);
2517 
2518  if (PKT_IS_TOSERVER(p)) {
2519  SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
2520 
2522  return -1;
2523  }
2524 
2525  /* Check if the SYN/ACK packets ACK matches the earlier
2526  * received SYN/ACK packet. */
2527  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
2528  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
2529  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
2530  ssn->client.isn + 1);
2531 
2533  return -1;
2534  }
2535 
2536  /* Check if the SYN/ACK packet SEQ the earlier
2537  * received SYN packet. */
2538  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
2539  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2540  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
2541  ssn->client.isn + 1);
2542 
2544  return -1;
2545  }
2546 
2547  if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
2548  /* a resend of a SYN while we are established already -- fishy */
2550  return -1;
2551  }
2552 
2553  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
2554  "Likely due server not receiving final ACK in 3whs", ssn);
2555  return 0;
2556 
2557  } else if (p->tcph->th_flags & TH_SYN) {
2558  SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
2559  if (PKT_IS_TOCLIENT(p)) {
2560  SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
2561 
2563  return -1;
2564  }
2565 
2566  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
2567  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
2568 
2570  return -1;
2571  }
2572 
2573  /* a resend of a SYN while we are established already -- fishy */
2575  return -1;
2576 
2577  } else if (p->tcph->th_flags & TH_ACK) {
2578  /* Urgent pointer size can be more than the payload size, as it tells
2579  * the future coming data from the sender will be handled urgently
2580  * until data of size equal to urgent offset has been processed
2581  * (RFC 2147) */
2582 
2583  /* If the timestamp option is enabled for both the streams, then
2584  * validate the received packet timestamp value against the
2585  * stream->last_ts. If the timestamp is valid then process the
2586  * packet normally otherwise the drop the packet (RFC 1323) */
2587  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2588  if (!StreamTcpValidateTimestamp(ssn, p))
2589  return -1;
2590  }
2591 
2592  if (PKT_IS_TOSERVER(p)) {
2593  /* Process the received packet to server */
2594  HandleEstablishedPacketToServer(tv, ssn, p, stt, pq);
2595 
2596  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
2597  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
2598  ssn->client.next_seq, ssn->server.last_ack
2599  ,ssn->client.next_win, ssn->client.window);
2600 
2601  } else { /* implied to client */
2602  if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
2604  SCLogDebug("3whs is now confirmed by server");
2605  }
2606 
2607  /* Process the received packet to client */
2608  HandleEstablishedPacketToClient(tv, ssn, p, stt, pq);
2609 
2610  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
2611  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
2612  ssn->server.next_seq, ssn->client.last_ack,
2613  ssn->server.next_win, ssn->server.window);
2614  }
2615  } else {
2616  SCLogDebug("ssn %p: default case", ssn);
2617  }
2618 
2619  return 0;
2620 }
2621 
2622 /**
2623  * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
2624  * TCP_ESTABLISHED and changes to another TCP state as required.
2625  *
2626  * \param tv Thread Variable containig input/output queue, cpu affinity
2627  * \param p Packet which has to be handled in this TCP state.
2628  * \param stt Strean Thread module registered to handle the stream handling
2629  *
2630  * \retval 0 success
2631  * \retval -1 something wrong with the packet
2632  */
2633 
2634 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt,
2635  TcpSession *ssn, Packet *p, PacketQueue *pq)
2636 {
2637  if (PKT_IS_TOSERVER(p)) {
2638  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2639  " ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
2640  TCP_GET_ACK(p));
2641 
2642  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2643  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2645  return -1;
2646  }
2647 
2648  if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
2649  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
2650  {
2651  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
2652  "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
2653  ssn->client.next_seq);
2654 
2656  return -1;
2657  }
2658 
2659  StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
2660  SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
2661 
2662  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))
2663  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2664 
2665  SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
2666  ssn->client.next_seq);
2667  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2668 
2669  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2670 
2671  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2672  StreamTcpHandleTimestamp(ssn, p);
2673  }
2674 
2675  /* Update the next_seq, in case if we have missed the client packet
2676  and server has already received and acked it */
2677  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
2678  ssn->server.next_seq = TCP_GET_ACK(p);
2679 
2680  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
2681 
2682  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
2683  ssn, ssn->client.next_seq, ssn->server.last_ack);
2684  } else { /* implied to client */
2685  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
2686  "ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
2687  TCP_GET_ACK(p));
2688 
2689  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2690  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2692  return -1;
2693  }
2694 
2695  if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
2696  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
2697  {
2698  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
2699  "%" PRIu32 " from stream (last_ack %u win %u = %u)", ssn, TCP_GET_SEQ(p),
2700  ssn->server.next_seq, ssn->server.last_ack, ssn->server.window, (ssn->server.last_ack + ssn->server.window));
2701 
2703  return -1;
2704  }
2705 
2706  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
2707  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
2708 
2709  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))
2710  ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2711 
2712  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2713  ssn->server.next_seq);
2714  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2715 
2716  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2717 
2718  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2719  StreamTcpHandleTimestamp(ssn, p);
2720  }
2721 
2722  /* Update the next_seq, in case if we have missed the client packet
2723  and server has already received and acked it */
2724  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
2725  ssn->client.next_seq = TCP_GET_ACK(p);
2726 
2727  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
2728 
2729  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
2730  ssn, ssn->server.next_seq, ssn->client.last_ack);
2731  }
2732 
2733  return 0;
2734 }
2735 
2736 /**
2737  * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
2738  * ACK, FIN, RST packets and correspondingly changes the connection
2739  * state.
2740  *
2741  * \param tv Thread Variable containig input/output queue, cpu affinity
2742  * \param p Packet which has to be handled in this TCP state.
2743  * \param stt Strean Thread module registered to handle the stream handling
2744  *
2745  * \retval 0 success
2746  * \retval -1 something wrong with the packet
2747  */
2748 
2749 static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p,
2750  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
2751 {
2752  if (ssn == NULL)
2753  return -1;
2754 
2755  if (p->tcph->th_flags & TH_RST) {
2756  if (!StreamTcpValidateRst(ssn, p))
2757  return -1;
2758 
2759  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
2760  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
2761  ssn);
2762 
2763  if (PKT_IS_TOSERVER(p)) {
2764  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
2765  StreamTcpUpdateLastAck(ssn, &ssn->server,
2766  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
2767 
2768  StreamTcpUpdateLastAck(ssn, &ssn->client,
2769  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
2770 
2771  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2772  StreamTcpHandleTimestamp(ssn, p);
2773  }
2774 
2776  &ssn->client, p, pq);
2777  } else {
2778  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
2779  StreamTcpUpdateLastAck(ssn, &ssn->client,
2780  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
2781 
2782  StreamTcpUpdateLastAck(ssn, &ssn->server,
2783  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
2784 
2785  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2786  StreamTcpHandleTimestamp(ssn, p);
2787  }
2788 
2790  &ssn->server, p, pq);
2791  }
2792 
2793  } else if ((p->tcph->th_flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) {
2794  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2795  if (!StreamTcpValidateTimestamp(ssn, p))
2796  return -1;
2797  }
2798 
2799  if (PKT_IS_TOSERVER(p)) {
2800  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
2801  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2802  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2803  int retransmission = 0;
2804 
2805  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
2806  SCLogDebug("ssn %p: packet is retransmission", ssn);
2807  retransmission = 1;
2808 
2809  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
2810  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
2811  {
2812  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2813  " != %" PRIu32 " from stream", ssn,
2814  TCP_GET_SEQ(p), ssn->client.next_seq);
2816  return -1;
2817  }
2818 
2819  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2820  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2822  return -1;
2823  }
2824 
2825  if (!retransmission) {
2826  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
2827  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
2828 
2829  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2830  }
2831 
2832  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2833 
2834  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2835  StreamTcpHandleTimestamp(ssn, p);
2836  }
2837 
2838  /* Update the next_seq, in case if we have missed the client
2839  packet and server has already received and acked it */
2840  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
2841  ssn->server.next_seq = TCP_GET_ACK(p);
2842 
2843  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2844  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2845  }
2846 
2848  &ssn->client, p, pq);
2849 
2850  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2851  "%" PRIu32 "", ssn, ssn->client.next_seq,
2852  ssn->server.last_ack);
2853  } else { /* implied to client */
2854  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2855  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2856  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2857  int retransmission = 0;
2858 
2859  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
2860  SCLogDebug("ssn %p: packet is retransmission", ssn);
2861  retransmission = 1;
2862 
2863  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
2864  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
2865  {
2866  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2867  " != %" PRIu32 " from stream", ssn,
2868  TCP_GET_SEQ(p), ssn->server.next_seq);
2870  return -1;
2871  }
2872 
2873  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2874  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2876  return -1;
2877  }
2878 
2879  if (!retransmission) {
2880  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
2881  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
2882 
2883  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2884  }
2885 
2886  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2887 
2888  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2889  StreamTcpHandleTimestamp(ssn, p);
2890  }
2891 
2892  /* Update the next_seq, in case if we have missed the client
2893  packet and server has already received and acked it */
2894  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
2895  ssn->client.next_seq = TCP_GET_ACK(p);
2896 
2897  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
2898  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2899  }
2900 
2902  &ssn->server, p, pq);
2903 
2904  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2905  "%" PRIu32 "", ssn, ssn->server.next_seq,
2906  ssn->client.last_ack);
2907  }
2908 
2909  } else if (p->tcph->th_flags & TH_FIN) {
2910  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2911  if (!StreamTcpValidateTimestamp(ssn, p))
2912  return -1;
2913  }
2914 
2915  if (PKT_IS_TOSERVER(p)) {
2916  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
2917  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2918  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2919  int retransmission = 0;
2920 
2921  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
2922  SCLogDebug("ssn %p: packet is retransmission", ssn);
2923  retransmission = 1;
2924 
2925  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
2926  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
2927  {
2928  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2929  " != %" PRIu32 " from stream", ssn,
2930  TCP_GET_SEQ(p), ssn->client.next_seq);
2932  return -1;
2933  }
2934 
2935  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2936  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2938  return -1;
2939  }
2940 
2941  if (!retransmission) {
2942  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
2943  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
2944 
2945  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2946  }
2947 
2948  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2949 
2950  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2951  StreamTcpHandleTimestamp(ssn, p);
2952  }
2953 
2954  /* Update the next_seq, in case if we have missed the client
2955  packet and server has already received and acked it */
2956  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
2957  ssn->server.next_seq = TCP_GET_ACK(p);
2958 
2959  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2960  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2961  }
2962 
2964  &ssn->client, p, pq);
2965 
2966  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2967  "%" PRIu32 "", ssn, ssn->client.next_seq,
2968  ssn->server.last_ack);
2969  } else { /* implied to client */
2970  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2971  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2972  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2973 
2974  int retransmission = 0;
2975 
2976  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
2977  SCLogDebug("ssn %p: packet is retransmission", ssn);
2978  retransmission = 1;
2979 
2980  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
2981  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
2982  {
2983  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2984  " != %" PRIu32 " from stream", ssn,
2985  TCP_GET_SEQ(p), ssn->server.next_seq);
2987  return -1;
2988  }
2989 
2990  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2991  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2993  return -1;
2994  }
2995 
2996  if (!retransmission) {
2997  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
2998  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
2999 
3000  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3001  }
3002 
3003  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3004 
3005  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3006  StreamTcpHandleTimestamp(ssn, p);
3007  }
3008 
3009  /* Update the next_seq, in case if we have missed the client
3010  packet and server has already received and acked it */
3011  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3012  ssn->client.next_seq = TCP_GET_ACK(p);
3013 
3014  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3015  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3016  }
3017 
3019  &ssn->server, p, pq);
3020 
3021  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3022  "%" PRIu32 "", ssn, ssn->server.next_seq,
3023  ssn->client.last_ack);
3024  }
3025  } else if (p->tcph->th_flags & TH_SYN) {
3026  SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
3028  return -1;
3029 
3030  } else if (p->tcph->th_flags & TH_ACK) {
3031  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3032  if (!StreamTcpValidateTimestamp(ssn, p))
3033  return -1;
3034  }
3035 
3036  if (PKT_IS_TOSERVER(p)) {
3037  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3038  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3039  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3040  int retransmission = 0;
3041 
3042  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3043  SCLogDebug("ssn %p: packet is retransmission", ssn);
3044  retransmission = 1;
3045  }
3046 
3047  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3048  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3050  return -1;
3051  }
3052 
3053  if (!retransmission) {
3054  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
3056  {
3057  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
3058  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
3059 
3060  if (TCP_GET_SEQ(p) == ssn->client.next_seq) {
3061  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3062  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3063  }
3064  } else {
3065  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3066  " != %" PRIu32 " from stream", ssn,
3067  TCP_GET_SEQ(p), ssn->client.next_seq);
3068 
3070  return -1;
3071  }
3072 
3073  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3074  }
3075 
3076  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3077 
3078  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3079  StreamTcpHandleTimestamp(ssn, p);
3080  }
3081 
3082  /* Update the next_seq, in case if we have missed the client
3083  packet and server has already received and acked it */
3084  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3085  ssn->server.next_seq = TCP_GET_ACK(p);
3086 
3087  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3088  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3089  }
3090 
3092 
3093  /* update next_win */
3094  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3095 
3097  &ssn->client, p, pq);
3098 
3099  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3100  "%" PRIu32 "", ssn, ssn->client.next_seq,
3101  ssn->server.last_ack);
3102 
3103  } else { /* implied to client */
3104 
3105  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3106  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3107  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3108 
3109  int retransmission = 0;
3110 
3111  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3112  SCLogDebug("ssn %p: packet is retransmission", ssn);
3113  retransmission = 1;
3114  }
3115 
3116  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3117  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3119  return -1;
3120  }
3121 
3122  if (!retransmission) {
3123  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
3125  {
3126  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
3127  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
3128 
3129  if (TCP_GET_SEQ(p) == ssn->server.next_seq) {
3130  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3131  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3132  }
3133  } else {
3134  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3135  " != %" PRIu32 " from stream", ssn,
3136  TCP_GET_SEQ(p), ssn->server.next_seq);
3138  return -1;
3139  }
3140 
3141  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3142  }
3143 
3144  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3145 
3146  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3147  StreamTcpHandleTimestamp(ssn, p);
3148  }
3149 
3150  /* Update the next_seq, in case if we have missed the client
3151  packet and server has already received and acked it */
3152  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3153  ssn->client.next_seq = TCP_GET_ACK(p);
3154 
3155  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3156  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3157  }
3158 
3160 
3161  /* update next_win */
3162  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3163 
3165  &ssn->server, p, pq);
3166 
3167  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3168  "%" PRIu32 "", ssn, ssn->server.next_seq,
3169  ssn->client.last_ack);
3170  }
3171  } else {
3172  SCLogDebug("ssn (%p): default case", ssn);
3173  }
3174 
3175  return 0;
3176 }
3177 
3178 /**
3179  * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
3180  * ACK, RST, FIN packets and correspondingly changes the connection
3181  * state.
3182  *
3183  * \param tv Thread Variable containig input/output queue, cpu affinity
3184  * \param p Packet which has to be handled in this TCP state.
3185  * \param stt Strean Thread module registered to handle the stream handling
3186  */
3187 
3188 static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p,
3189  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
3190 {
3191  if (ssn == NULL)
3192  return -1;
3193 
3194  if (p->tcph->th_flags & TH_RST) {
3195  if (!StreamTcpValidateRst(ssn, p))
3196  return -1;
3197 
3198  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
3199  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
3200  ssn);
3201 
3202  if (PKT_IS_TOSERVER(p)) {
3203  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3204  StreamTcpUpdateLastAck(ssn, &ssn->server,
3205  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3206 
3207  StreamTcpUpdateLastAck(ssn, &ssn->client,
3208  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3209 
3210  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3211  StreamTcpHandleTimestamp(ssn, p);
3212  }
3213 
3215  &ssn->client, p, pq);
3216  } else {
3217  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3218  StreamTcpUpdateLastAck(ssn, &ssn->client,
3219  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3220 
3221  StreamTcpUpdateLastAck(ssn, &ssn->server,
3222  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3223 
3224  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3225  StreamTcpHandleTimestamp(ssn, p);
3226  }
3227 
3229  &ssn->server, p, pq);
3230  }
3231 
3232  } else if (p->tcph->th_flags & TH_FIN) {
3233  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3234  if (!StreamTcpValidateTimestamp(ssn, p))
3235  return -1;
3236  }
3237 
3238  if (PKT_IS_TOSERVER(p)) {
3239  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3240  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3241  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3242  int retransmission = 0;
3243 
3244  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq - 1) &&
3245  SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) {
3246  SCLogDebug("ssn %p: retransmission", ssn);
3247  retransmission = 1;
3248  } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3249  SCLogDebug("ssn %p: packet is retransmission", ssn);
3250  retransmission = 1;
3251 
3252  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
3253  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3254  {
3255  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
3256  "%" PRIu32 " != %" PRIu32 " from stream", ssn,
3257  TCP_GET_SEQ(p), ssn->client.next_seq);
3259  return -1;
3260  }
3261 
3262  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3263  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3265  return -1;
3266  }
3267 
3268  if (!retransmission) {
3269  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3270  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3271 
3272  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3273  }
3274 
3275  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3276 
3277  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3278  StreamTcpHandleTimestamp(ssn, p);
3279  }
3280 
3281  /* Update the next_seq, in case if we have missed the client
3282  packet and server has already received and acked it */
3283  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3284  ssn->server.next_seq = TCP_GET_ACK(p);
3285 
3287  &ssn->client, p, pq);
3288 
3289  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3290  "%" PRIu32 "", ssn, ssn->client.next_seq,
3291  ssn->server.last_ack);
3292  } else { /* implied to client */
3293  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3294  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3295  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3296  int retransmission = 0;
3297 
3298  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq - 1) &&
3299  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) {
3300  SCLogDebug("ssn %p: retransmission", ssn);
3301  retransmission = 1;
3302  } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3303  SCLogDebug("ssn %p: packet is retransmission", ssn);
3304  retransmission = 1;
3305 
3306  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
3307  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3308  {
3309  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
3310  "%" PRIu32 " != %" PRIu32 " from stream", ssn,
3311  TCP_GET_SEQ(p), ssn->server.next_seq);
3313  return -1;
3314  }
3315 
3316  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3317  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3319  return -1;
3320  }
3321 
3322  if (!retransmission) {
3323  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3324  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3325 
3326  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3327  }
3328 
3329  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3330 
3331  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3332  StreamTcpHandleTimestamp(ssn, p);
3333  }
3334 
3335  /* Update the next_seq, in case if we have missed the client
3336  packet and server has already received and acked it */
3337  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3338  ssn->client.next_seq = TCP_GET_ACK(p);
3339 
3341  &ssn->server, p, pq);
3342  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3343  "%" PRIu32 "", ssn, ssn->server.next_seq,
3344  ssn->client.last_ack);
3345  }
3346 
3347  } else if (p->tcph->th_flags & TH_SYN) {
3348  SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
3350  return -1;
3351 
3352  } else if (p->tcph->th_flags & TH_ACK) {
3353  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3354  if (!StreamTcpValidateTimestamp(ssn, p))
3355  return -1;
3356  }
3357 
3358  if (PKT_IS_TOSERVER(p)) {
3359  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3360  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3361  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3362  int retransmission = 0;
3363 
3364  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3365  SCLogDebug("ssn %p: packet is retransmission", ssn);
3366  retransmission = 1;
3367  }
3368 
3369  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3370  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3372  return -1;
3373  }
3374 
3375  if (!retransmission) {
3376  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
3378  {
3379  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
3380  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
3381 
3382  } else {
3383  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3384  " != %" PRIu32 " from stream", ssn,
3385  TCP_GET_SEQ(p), ssn->client.next_seq);
3387  return -1;
3388  }
3389 
3390  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3391  }
3392 
3393  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3394 
3395  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3396  StreamTcpHandleTimestamp(ssn, p);
3397  }
3398 
3399  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3400  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3401  }
3402 
3404 
3405  /* update next_win */
3406  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3407 
3409  &ssn->client, p, pq);
3410 
3411  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3412  "%" PRIu32 "", ssn, ssn->client.next_seq,
3413  ssn->server.last_ack);
3414  } else { /* implied to client */
3415  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3416  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3417  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3418  int retransmission = 0;
3419 
3420  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3421  SCLogDebug("ssn %p: packet is retransmission", ssn);
3422  retransmission = 1;
3423  }
3424 
3425  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3426  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3428  return -1;
3429  }
3430 
3431  if (!retransmission) {
3432  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
3434  {
3435  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
3436  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
3437  } else {
3438  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3439  " != %" PRIu32 " from stream", ssn,
3440  TCP_GET_SEQ(p), ssn->server.next_seq);
3442  return -1;
3443  }
3444 
3445  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3446  }
3447 
3448  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3449 
3450  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3451  StreamTcpHandleTimestamp(ssn, p);
3452  }
3453 
3454  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3455  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3456  }
3457 
3459 
3460  /* update next_win */
3461  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3462 
3464  &ssn->server, p, pq);
3465 
3466  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3467  "%" PRIu32 "", ssn, ssn->server.next_seq,
3468  ssn->client.last_ack);
3469  }
3470  } else {
3471  SCLogDebug("ssn %p: default case", ssn);
3472  }
3473 
3474  return 0;
3475 }
3476 
3477 /**
3478  * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
3479  * the connection goes to TCP_TIME_WAIT state. The state has been
3480  * reached as both end application has been closed.
3481  *
3482  * \param tv Thread Variable containig input/output queue, cpu affinity
3483  * \param p Packet which has to be handled in this TCP state.
3484  * \param stt Strean Thread module registered to handle the stream handling
3485  */
3486 
3487 static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p,
3488  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
3489 {
3490  if (ssn == NULL)
3491  return -1;
3492 
3493  if (p->tcph->th_flags & TH_RST) {
3494  if (!StreamTcpValidateRst(ssn, p))
3495  return -1;
3496 
3497  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
3498  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
3499  ssn);
3500 
3501  if (PKT_IS_TOSERVER(p)) {
3502  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3503  StreamTcpUpdateLastAck(ssn, &ssn->server,
3504  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3505 
3506  StreamTcpUpdateLastAck(ssn, &ssn->client,
3507  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3508 
3509  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3510  StreamTcpHandleTimestamp(ssn, p);
3511  }
3512 
3514  &ssn->client, p, pq);
3515  } else {
3516  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3517  StreamTcpUpdateLastAck(ssn, &ssn->client,
3518  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3519 
3520  StreamTcpUpdateLastAck(ssn, &ssn->server,
3521  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3522 
3523  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3524  StreamTcpHandleTimestamp(ssn, p);
3525  }
3526 
3528  &ssn->server, p, pq);
3529  }
3530 
3531  } else if (p->tcph->th_flags & TH_SYN) {
3532  SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
3534  return -1;
3535 
3536  } else if (p->tcph->th_flags & TH_ACK) {
3537  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3538  if (!StreamTcpValidateTimestamp(ssn, p))
3539  return -1;
3540  }
3541 
3542  if (PKT_IS_TOSERVER(p)) {
3543  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3544  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3545  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3546  int retransmission = 0;
3547  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3548  SCLogDebug("ssn %p: packet is retransmission", ssn);
3549  retransmission = 1;
3550  }
3551 
3552  if (TCP_GET_SEQ(p) != ssn->client.next_seq) {
3553  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3554  " != %" PRIu32 " from stream", ssn,
3555  TCP_GET_SEQ(p), ssn->client.next_seq);
3557  return -1;
3558  }
3559 
3560  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3561  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3563  return -1;
3564  }
3565 
3566  if (!retransmission) {
3567  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3568  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3569 
3570  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3571  }
3572 
3573  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3574 
3575  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3576  StreamTcpHandleTimestamp(ssn, p);
3577  }
3578  /* Update the next_seq, in case if we have missed the client
3579  packet and server has already received and acked it */
3580  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3581  ssn->server.next_seq = TCP_GET_ACK(p);
3582 
3584  &ssn->client, p, pq);
3585  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3586  "%" PRIu32 "", ssn, ssn->client.next_seq,
3587  ssn->server.last_ack);
3588  } else { /* implied to client */
3589  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3590  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3591  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3592  int retransmission = 0;
3593  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3594  SCLogDebug("ssn %p: packet is retransmission", ssn);
3595  retransmission = 1;
3596  }
3597 
3598  if (TCP_GET_SEQ(p) != ssn->server.next_seq) {
3599  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3600  " != %" PRIu32 " from stream", ssn,
3601  TCP_GET_SEQ(p), ssn->server.next_seq);
3603  return -1;
3604  }
3605 
3606  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3607  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3609  return -1;
3610  }
3611 
3612  if (!retransmission) {
3613  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3614  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3615 
3616  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3617  }
3618 
3619  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3620 
3621  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3622  StreamTcpHandleTimestamp(ssn, p);
3623  }
3624 
3625  /* Update the next_seq, in case if we have missed the client
3626  packet and server has already received and acked it */
3627  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3628  ssn->client.next_seq = TCP_GET_ACK(p);
3629 
3631  &ssn->server, p, pq);
3632  SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
3633  "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
3634  ssn->server.next_seq, ssn->client.last_ack);
3635  }
3636  } else {
3637  SCLogDebug("ssn %p: default case", ssn);
3638  }
3639 
3640  return 0;
3641 }
3642 
3643 /**
3644  * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
3645  * packet from server the connection goes to TCP_LAST_ACK state.
3646  * The state is possible only for server host.
3647  *
3648  * \param tv Thread Variable containig input/output queue, cpu affinity
3649  * \param p Packet which has to be handled in this TCP state.
3650  * \param stt Strean Thread module registered to handle the stream handling
3651  */
3652 
3653 static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p,
3654  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
3655 {
3656  SCEnter();
3657 
3658  if (ssn == NULL) {
3659  SCReturnInt(-1);
3660  }
3661 
3662  if (PKT_IS_TOCLIENT(p)) {
3663  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3664  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3665  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3666  } else {
3667  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3668  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3669  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3670  }
3671 
3672  if (p->tcph->th_flags & TH_RST) {
3673  if (!StreamTcpValidateRst(ssn, p))
3674  return -1;
3675 
3676  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
3677  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
3678  ssn);
3679 
3680  if (PKT_IS_TOSERVER(p)) {
3681  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3682  StreamTcpUpdateLastAck(ssn, &ssn->server,
3683  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3684 
3685  StreamTcpUpdateLastAck(ssn, &ssn->client,
3686  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3687 
3688  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3689  StreamTcpHandleTimestamp(ssn, p);
3690  }
3691 
3693  &ssn->client, p, pq);
3694  } else {
3695  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3696  StreamTcpUpdateLastAck(ssn, &ssn->client,
3697  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3698 
3699  StreamTcpUpdateLastAck(ssn, &ssn->server,
3700  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3701 
3702  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3703  StreamTcpHandleTimestamp(ssn, p);
3704  }
3705 
3707  &ssn->server, p, pq);
3708  }
3709 
3710  } else if (p->tcph->th_flags & TH_FIN) {
3711  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3712  if (!StreamTcpValidateTimestamp(ssn, p))
3713  SCReturnInt(-1);
3714  }
3715 
3716  if (PKT_IS_TOSERVER(p)) {
3717  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3718  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3719  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3720 
3721  int retransmission = 0;
3722  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3723  SCLogDebug("ssn %p: packet is retransmission", ssn);
3724  retransmission = 1;
3725  }
3726 
3727  if (!retransmission) {
3728  if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
3729  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3730  {
3731  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3732  " != %" PRIu32 " from stream", ssn,
3733  TCP_GET_SEQ(p), ssn->client.next_seq);
3735  SCReturnInt(-1);
3736  }
3737  }
3738 
3739  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3740  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3742  SCReturnInt(-1);
3743  }
3744 
3745  /* don't update to LAST_ACK here as we want a toclient FIN for that */
3746 
3747  if (!retransmission)
3748  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3749 
3750  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3751 
3752  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3753  StreamTcpHandleTimestamp(ssn, p);
3754  }
3755 
3756  /* Update the next_seq, in case if we have missed the client
3757  packet and server has already received and acked it */
3758  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3759  ssn->server.next_seq = TCP_GET_ACK(p);
3760 
3762  &ssn->client, p, pq);
3763  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3764  "%" PRIu32 "", ssn, ssn->client.next_seq,
3765  ssn->server.last_ack);
3766  } else {
3767  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3768  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3769  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3770 
3771  int retransmission = 0;
3772  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3773  SCLogDebug("ssn %p: packet is retransmission", ssn);
3774  retransmission = 1;
3775  }
3776 
3777  if (!retransmission) {
3778  if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
3779  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3780  {
3781  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3782  " != %" PRIu32 " from stream", ssn,
3783  TCP_GET_SEQ(p), ssn->server.next_seq);
3785  SCReturnInt(-1);
3786  }
3787  }
3788 
3789  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3790  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3792  SCReturnInt(-1);
3793  }
3794 
3795  if (!retransmission) {
3796  StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
3797  SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
3798 
3799  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3800  }
3801 
3802  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3803 
3804  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3805  StreamTcpHandleTimestamp(ssn, p);
3806  }
3807 
3808  /* Update the next_seq, in case if we have missed the client
3809  packet and server has already received and acked it */
3810  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3811  ssn->client.next_seq = TCP_GET_ACK(p);
3812 
3814  &ssn->server, p, pq);
3815  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3816  "%" PRIu32 "", ssn, ssn->server.next_seq,
3817  ssn->client.last_ack);
3818  }
3819 
3820  } else if (p->tcph->th_flags & TH_SYN) {
3821  SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
3823  SCReturnInt(-1);
3824 
3825  } else if (p->tcph->th_flags & TH_ACK) {
3826  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3827  if (!StreamTcpValidateTimestamp(ssn, p))
3828  SCReturnInt(-1);
3829  }
3830 
3831  if (PKT_IS_TOSERVER(p)) {
3832  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3833  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3834  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3835 
3836  int retransmission = 0;
3837  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3838  SCLogDebug("ssn %p: packet is retransmission", ssn);
3839  retransmission = 1;
3840  }
3841 
3842  if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) {
3843  SCLogDebug("ssn %p: -> retransmission", ssn);
3845  SCReturnInt(-1);
3846 
3847  } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3848  {
3849  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3850  " != %" PRIu32 " from stream", ssn,
3851  TCP_GET_SEQ(p), ssn->client.next_seq);
3853  SCReturnInt(-1);
3854  }
3855 
3856  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3857  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3859  SCReturnInt(-1);
3860  }
3861 
3862  if (!retransmission) {
3863  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3864  }
3865 
3866  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3867 
3868  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3869  StreamTcpHandleTimestamp(ssn, p);
3870  }
3871 
3872  /* Update the next_seq, in case if we have missed the client
3873  packet and server has already received and acked it */
3874  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3875  ssn->server.next_seq = TCP_GET_ACK(p);
3876 
3877  if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq))
3878  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3879 
3881  &ssn->client, p, pq);
3882  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3883  "%" PRIu32 "", ssn, ssn->client.next_seq,
3884  ssn->server.last_ack);
3885  } else {
3886  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3887  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3888  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3889  int retransmission = 0;
3890  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3891  SCLogDebug("ssn %p: packet is retransmission", ssn);
3892  retransmission = 1;
3893  }
3894 
3895  if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) {
3896  SCLogDebug("ssn %p: -> retransmission", ssn);
3898  SCReturnInt(-1);
3899 
3900  } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3901  {
3902  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3903  " != %" PRIu32 " from stream", ssn,
3904  TCP_GET_SEQ(p), ssn->server.next_seq);
3906  SCReturnInt(-1);
3907  }
3908 
3909  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3910  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3912  SCReturnInt(-1);
3913  }
3914 
3915  if (!retransmission) {
3916  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3917  }
3918 
3919  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3920 
3921  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3922  StreamTcpHandleTimestamp(ssn, p);
3923  }
3924 
3925  /* Update the next_seq, in case if we have missed the client
3926  packet and server has already received and acked it */
3927  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3928  ssn->client.next_seq = TCP_GET_ACK(p);
3929 
3930  if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq))
3931  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3932 
3934  &ssn->server, p, pq);
3935  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3936  "%" PRIu32 "", ssn, ssn->server.next_seq,
3937  ssn->client.last_ack);
3938  }
3939 
3940  } else {
3941  SCLogDebug("ssn %p: default case", ssn);
3942  }
3943  SCReturnInt(0);
3944 }
3945 
3946 /**
3947  * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
3948  * the connection goes to TCP_CLOSED state and stream memory is
3949  * returned back to pool. The state is possible only for server host.
3950  *
3951  * \param tv Thread Variable containig input/output queue, cpu affinity
3952  * \param p Packet which has to be handled in this TCP state.
3953  * \param stt Strean Thread module registered to handle the stream handling
3954  */
3955 
3956 static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p,
3957  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
3958 {
3959  if (ssn == NULL)
3960  return -1;
3961 
3962  if (p->tcph->th_flags & TH_RST) {
3963  if (!StreamTcpValidateRst(ssn, p))
3964  return -1;
3965 
3966  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
3967  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
3968  ssn);
3969 
3970  if (PKT_IS_TOSERVER(p)) {
3971  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3972  StreamTcpUpdateLastAck(ssn, &ssn->server,
3973  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3974 
3975  StreamTcpUpdateLastAck(ssn, &ssn->client,
3976  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3977 
3978  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3979  StreamTcpHandleTimestamp(ssn, p);
3980  }
3981 
3983  &ssn->client, p, pq);
3984  } else {
3985  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3986  StreamTcpUpdateLastAck(ssn, &ssn->client,
3987  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3988 
3989  StreamTcpUpdateLastAck(ssn, &ssn->server,
3990  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3991 
3992  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3993  StreamTcpHandleTimestamp(ssn, p);
3994  }
3995 
3997  &ssn->server, p, pq);
3998  }
3999 
4000  } else if (p->tcph->th_flags & TH_FIN) {
4001  /** \todo */
4002  SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
4003 
4004  } else if (p->tcph->th_flags & TH_SYN) {
4005  SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
4007  return -1;
4008 
4009  } else if (p->tcph->th_flags & TH_ACK) {
4010  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4011  if (!StreamTcpValidateTimestamp(ssn, p))
4012  return -1;
4013  }
4014 
4015  if (PKT_IS_TOSERVER(p)) {
4016  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4017  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4018  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4019 
4020  int retransmission = 0;
4021  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4022  SCLogDebug("ssn %p: packet is retransmission", ssn);
4023  retransmission = 1;
4024  }
4025 
4026  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4027  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4029  SCReturnInt(-1);
4030  }
4031 
4032  if (!retransmission) {
4033  if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq)) {
4034  SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
4035  } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq + 1) {
4036  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4037  " != %" PRIu32 " from stream", ssn,
4038  TCP_GET_SEQ(p), ssn->client.next_seq);
4040  return -1;
4041  } else {
4042  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4043  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4044 
4045  }
4046  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
4047  }
4048 
4049  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4050 
4051  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4052  StreamTcpHandleTimestamp(ssn, p);
4053  }
4054 
4055  /* Update the next_seq, in case if we have missed the client
4056  packet and server has already received and acked it */
4057  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
4058  ssn->server.next_seq = TCP_GET_ACK(p);
4059 
4061  &ssn->client, p, pq);
4062  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4063  "%" PRIu32 "", ssn, ssn->client.next_seq,
4064  ssn->server.last_ack);
4065  }
4066  } else {
4067  SCLogDebug("ssn %p: default case", ssn);
4068  }
4069 
4070  return 0;
4071 }
4072 
4073 /**
4074  * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
4075  * the connection goes to TCP_CLOSED state and stream memory is
4076  * returned back to pool.
4077  *
4078  * \param tv Thread Variable containig input/output queue, cpu affinity
4079  * \param p Packet which has to be handled in this TCP state.
4080  * \param stt Strean Thread module registered to handle the stream handling
4081  */
4082 
4083 static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p,
4084  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
4085 {
4086  if (ssn == NULL)
4087  return -1;
4088 
4089  if (p->tcph->th_flags & TH_RST) {
4090  if (!StreamTcpValidateRst(ssn, p))
4091  return -1;
4092 
4093  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4094  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
4095  ssn);
4096 
4097  if (PKT_IS_TOSERVER(p)) {
4098  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4099  StreamTcpUpdateLastAck(ssn, &ssn->server,
4100  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
4101 
4102  StreamTcpUpdateLastAck(ssn, &ssn->client,
4103  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
4104 
4105  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4106  StreamTcpHandleTimestamp(ssn, p);
4107  }
4108 
4110  &ssn->client, p, pq);
4111  } else {
4112  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4113  StreamTcpUpdateLastAck(ssn, &ssn->client,
4114  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
4115 
4116  StreamTcpUpdateLastAck(ssn, &ssn->server,
4117  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
4118 
4119  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4120  StreamTcpHandleTimestamp(ssn, p);
4121  }
4122 
4124  &ssn->server, p, pq);
4125  }
4126 
4127  } else if (p->tcph->th_flags & TH_FIN) {
4128  /** \todo */
4129 
4130  } else if (p->tcph->th_flags & TH_SYN) {
4131  SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
4133  return -1;
4134 
4135  } else if (p->tcph->th_flags & TH_ACK) {
4136  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4137  if (!StreamTcpValidateTimestamp(ssn, p))
4138  return -1;
4139  }
4140 
4141  if (PKT_IS_TOSERVER(p)) {
4142  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4143  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4144  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4145  int retransmission = 0;
4146  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4147  SCLogDebug("ssn %p: packet is retransmission", ssn);
4148  retransmission = 1;
4149 
4150  } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq+1) {
4151  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4152  " != %" PRIu32 " from stream", ssn,
4153  TCP_GET_SEQ(p), ssn->client.next_seq);
4155  return -1;
4156  }
4157 
4158  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4159  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4161  SCReturnInt(-1);
4162  }
4163 
4164  if (!retransmission) {
4165  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4166  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4167 
4168  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
4169  }
4170 
4171  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4172 
4173  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4174  StreamTcpHandleTimestamp(ssn, p);
4175  }
4176 
4177  /* Update the next_seq, in case if we have missed the client
4178  packet and server has already received and acked it */
4179  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
4180  ssn->server.next_seq = TCP_GET_ACK(p);
4181 
4183  &ssn->client, p, pq);
4184  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4185  "%" PRIu32 "", ssn, ssn->client.next_seq,
4186  ssn->server.last_ack);
4187  } else {
4188  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4189  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4190  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4191  int retransmission = 0;
4192  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4193  SCLogDebug("ssn %p: packet is retransmission", ssn);
4194  retransmission = 1;
4195  } else if (TCP_GET_SEQ(p) != ssn->server.next_seq && TCP_GET_SEQ(p) != ssn->server.next_seq+1) {
4196  if (p->payload_len > 0 && TCP_GET_SEQ(p) == ssn->server.last_ack) {
4197  SCLogDebug("ssn %p: -> retransmission", ssn);
4198  SCReturnInt(0);
4199  } else {
4200  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4201  " != %" PRIu32 " from stream", ssn,
4202  TCP_GET_SEQ(p), ssn->server.next_seq);
4204  return -1;
4205  }
4206  }
4207 
4208  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4209  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4211  SCReturnInt(-1);
4212  }
4213 
4214  if (!retransmission) {
4215  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4216  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4217 
4218  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
4219  }
4220 
4221  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
4222 
4223  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4224  StreamTcpHandleTimestamp(ssn, p);
4225  }
4226 
4227  /* Update the next_seq, in case if we have missed the client
4228  packet and server has already received and acked it */
4229  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
4230  ssn->client.next_seq = TCP_GET_ACK(p);
4231 
4233  &ssn->server, p, pq);
4234  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4235  "%" PRIu32 "", ssn, ssn->server.next_seq,
4236  ssn->client.last_ack);
4237  }
4238 
4239  } else {
4240  SCLogDebug("ssn %p: default case", ssn);
4241  }
4242 
4243  return 0;
4244 }
4245 
4246 static int StreamTcpPacketStateClosed(ThreadVars *tv, Packet *p,
4247  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
4248 {
4249  if (ssn == NULL)
4250  return -1;
4251 
4252  if (p->tcph->th_flags & TH_RST) {
4253  SCLogDebug("RST on closed state");
4254  return 0;
4255  }
4256 
4257  TcpStream *stream = NULL, *ostream = NULL;
4258  if (PKT_IS_TOSERVER(p)) {
4259  stream = &ssn->client;
4260  ostream = &ssn->server;
4261  } else {
4262  stream = &ssn->server;
4263  ostream = &ssn->client;
4264  }
4265 
4266  SCLogDebug("stream %s ostream %s",
4267  stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
4268  ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
4269 
4270  /* if we've seen a RST on our direction, but not on the other
4271  * see if we perhaps need to continue processing anyway. */
4272  if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
4273  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
4274  if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->pstate) < 0)
4275  return -1;
4276  }
4277  }
4278  return 0;
4279 }
4280 
4281 static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
4282 {
4283  if (p->flags & PKT_PSEUDO_STREAM_END) {
4284  return;
4285  }
4286  /* more RSTs are not unusual */
4287  if ((p->tcph->th_flags & (TH_RST)) != 0) {
4288  return;
4289  }
4290 
4291  TcpStream *ostream = NULL;
4292  if (PKT_IS_TOSERVER(p)) {
4293  ostream = &ssn->server;
4294  } else {
4295  ostream = &ssn->client;
4296  }
4297 
4298  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
4299  SCLogDebug("regular packet %"PRIu64" from same sender as "
4300  "the previous RST. Looks like it injected!", p->pcap_cnt);
4303  return;
4304  }
4305  return;
4306 }
4307 
4308 /**
4309  * \retval 1 packet is a keep alive pkt
4310  * \retval 0 packet is not a keep alive pkt
4311  */
4312 static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
4313 {
4314  TcpStream *stream = NULL, *ostream = NULL;
4315  uint32_t seq;
4316  uint32_t ack;
4317 
4318  if (p->flags & PKT_PSEUDO_STREAM_END)
4319  return 0;
4320 
4321  /*
4322  rfc 1122:
4323  An implementation SHOULD send a keep-alive segment with no
4324  data; however, it MAY be configurable to send a keep-alive
4325  segment containing one garbage octet, for compatibility with
4326  erroneous TCP implementations.
4327  */
4328  if (p->payload_len > 1)
4329  return 0;
4330 
4331  if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) {
4332  return 0;
4333  }
4334 
4335  if (PKT_IS_TOSERVER(p)) {
4336  stream = &ssn->client;
4337  ostream = &ssn->server;
4338  } else {
4339  stream = &ssn->server;
4340  ostream = &ssn->client;
4341  }
4342 
4343  seq = TCP_GET_SEQ(p);
4344  ack = TCP_GET_ACK(p);
4345 
4346  if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
4347  SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
4349  return 1;
4350  }
4351  SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
4352  return 0;
4353 }
4354 
4355 /**
4356  * \retval 1 packet is a keep alive ACK pkt
4357  * \retval 0 packet is not a keep alive ACK pkt
4358  */
4359 static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
4360 {
4361  TcpStream *stream = NULL, *ostream = NULL;
4362  uint32_t seq;
4363  uint32_t ack;
4364  uint32_t pkt_win;
4365 
4366  if (p->flags & PKT_PSEUDO_STREAM_END)
4367  return 0;
4368  /* should get a normal ACK to a Keep Alive */
4369  if (p->payload_len > 0)
4370  return 0;
4371 
4372  if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4373  return 0;
4374 
4375  if (TCP_GET_WINDOW(p) == 0)
4376  return 0;
4377 
4378  if (PKT_IS_TOSERVER(p)) {
4379  stream = &ssn->client;
4380  ostream = &ssn->server;
4381  } else {
4382  stream = &ssn->server;
4383  ostream = &ssn->client;
4384  }
4385 
4386  seq = TCP_GET_SEQ(p);
4387  ack = TCP_GET_ACK(p);
4388 
4389  pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4390  if (pkt_win != ostream->window)
4391  return 0;
4392 
4393  if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
4394  SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
4395  ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
4396  return 1;
4397  }
4398  SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
4399  ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
4400  return 0;
4401 }
4402 
4403 static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
4404 {
4405  TcpStream *stream = NULL;
4406 
4407  if (p->flags & PKT_PSEUDO_STREAM_END)
4408  return;
4409 
4410  if (PKT_IS_TOSERVER(p)) {
4411  stream = &ssn->client;
4412  } else {
4413  stream = &ssn->server;
4414  }
4415 
4416  if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
4418  SCLogDebug("FLAG_KEEPALIVE cleared");
4419  }
4420 }
4421 
4422 /**
4423  * \retval 1 packet is a window update pkt
4424  * \retval 0 packet is not a window update pkt
4425  */
4426 static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
4427 {
4428  TcpStream *stream = NULL, *ostream = NULL;
4429  uint32_t seq;
4430  uint32_t ack;
4431  uint32_t pkt_win;
4432 
4433  if (p->flags & PKT_PSEUDO_STREAM_END)
4434  return 0;
4435 
4436  if (ssn->state < TCP_ESTABLISHED)
4437  return 0;
4438 
4439  if (p->payload_len > 0)
4440  return 0;
4441 
4442  if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4443  return 0;
4444 
4445  if (TCP_GET_WINDOW(p) == 0)
4446  return 0;
4447 
4448  if (PKT_IS_TOSERVER(p)) {
4449  stream = &ssn->client;
4450  ostream = &ssn->server;
4451  } else {
4452  stream = &ssn->server;
4453  ostream = &ssn->client;
4454  }
4455 
4456  seq = TCP_GET_SEQ(p);
4457  ack = TCP_GET_ACK(p);
4458 
4459  pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4460  if (pkt_win == ostream->window)
4461  return 0;
4462 
4463  if (ack == ostream->last_ack && seq == stream->next_seq) {
4464  SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
4465  return 1;
4466  }
4467  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
4468  return 0;
4469 }
4470 
4471 /**
4472  * Try to detect whether a packet is a valid FIN 4whs final ack.
4473  *
4474  */
4475 static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
4476 {
4477  TcpStream *stream = NULL, *ostream = NULL;
4478  uint32_t seq;
4479  uint32_t ack;
4480 
4481  if (p->flags & PKT_PSEUDO_STREAM_END)
4482  return 0;
4483  if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
4484  return 0;
4485  if (p->tcph->th_flags != TH_ACK)
4486  return 0;
4487  if (p->payload_len != 0)
4488  return 0;
4489 
4490  if (PKT_IS_TOSERVER(p)) {
4491  stream = &ssn->client;
4492  ostream = &ssn->server;
4493  } else {
4494  stream = &ssn->server;
4495  ostream = &ssn->client;
4496  }
4497 
4498  seq = TCP_GET_SEQ(p);
4499  ack = TCP_GET_ACK(p);
4500 
4501  SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
4502  p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
4503 
4504  if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
4505  return 1;
4506  }
4507  return 0;
4508 }
4509 
4510 /**
4511  * Try to detect packets doing bad window updates
4512  *
4513  * See bug 1238.
4514  *
4515  * Find packets that are unexpected, and shrink the window to the point
4516  * where the packets we do expect are rejected for being out of window.
4517  *
4518  * The logic we use here is:
4519  * - packet seq > next_seq
4520  * - packet ack > next_seq (packet acks unseen data)
4521  * - packet shrinks window more than it's own data size
4522  * - packet shrinks window more than the diff between it's ack and the
4523  * last_ack value
4524  *
4525  * Packets coming in after packet loss can look quite a bit like this.
4526  */
4527 static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
4528 {
4529  TcpStream *stream = NULL, *ostream = NULL;
4530  uint32_t seq;
4531  uint32_t ack;
4532  uint32_t pkt_win;
4533 
4534  if (p->flags & PKT_PSEUDO_STREAM_END)
4535  return 0;
4536 
4537  if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
4538  return 0;
4539 
4540  if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4541  return 0;
4542 
4543  if (PKT_IS_TOSERVER(p)) {
4544  stream = &ssn->client;
4545  ostream = &ssn->server;
4546  } else {
4547  stream = &ssn->server;
4548  ostream = &ssn->client;
4549  }
4550 
4551  seq = TCP_GET_SEQ(p);
4552  ack = TCP_GET_ACK(p);
4553 
4554  pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4555 
4556  if (pkt_win < ostream->window) {
4557  uint32_t diff = ostream->window - pkt_win;
4558  if (diff > p->payload_len &&
4559  SEQ_GT(ack, ostream->next_seq) &&
4560  SEQ_GT(seq, stream->next_seq))
4561  {
4562  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
4563  p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
4564  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
4565  p->pcap_cnt, pkt_win, ostream->window);
4566  SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
4567  p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
4568  ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
4569 
4570  /* get the expected window shrinking from looking at ack vs last_ack.
4571  * Observed a lot of just a little overrunning that value. So added some
4572  * margin that is still ok. To make sure this isn't a loophole to still
4573  * close the window, this is limited to windows above 1024. Both values
4574  * are rather arbitrary. */
4575  uint32_t adiff = ack - ostream->last_ack;
4576  if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
4577  ((pkt_win <= 1024) && (diff > adiff)))
4578  {
4579  SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
4580  "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
4581  SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
4583  return 1;
4584  }
4585  }
4586 
4587  }
4588  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
4589  return 0;
4590 }
4591 
4592 /** \internal
4593  * \brief call packet handling function for 'state'
4594  * \param state current TCP state
4595  */
4596 static inline int StreamTcpStateDispatch(ThreadVars *tv, Packet *p,
4597  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq,
4598  const uint8_t state)
4599 {
4600  SCLogDebug("ssn: %p", ssn);
4601  switch (state) {
4602  case TCP_SYN_SENT:
4603  if (StreamTcpPacketStateSynSent(tv, p, stt, ssn, pq)) {
4604  return -1;
4605  }
4606  break;
4607  case TCP_SYN_RECV:
4608  if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn, pq)) {
4609  return -1;
4610  }
4611  break;
4612  case TCP_ESTABLISHED:
4613  if (StreamTcpPacketStateEstablished(tv, p, stt, ssn, pq)) {
4614  return -1;
4615  }
4616  break;
4617  case TCP_FIN_WAIT1:
4618  SCLogDebug("packet received on TCP_FIN_WAIT1 state");
4619  if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn, pq)) {
4620  return -1;
4621  }
4622  break;
4623  case TCP_FIN_WAIT2:
4624  SCLogDebug("packet received on TCP_FIN_WAIT2 state");
4625  if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn, pq)) {
4626  return -1;
4627  }
4628  break;
4629  case TCP_CLOSING:
4630  SCLogDebug("packet received on TCP_CLOSING state");
4631  if (StreamTcpPacketStateClosing(tv, p, stt, ssn, pq)) {
4632  return -1;
4633  }
4634  break;
4635  case TCP_CLOSE_WAIT:
4636  SCLogDebug("packet received on TCP_CLOSE_WAIT state");
4637  if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn, pq)) {
4638  return -1;
4639  }
4640  break;
4641  case TCP_LAST_ACK:
4642  SCLogDebug("packet received on TCP_LAST_ACK state");
4643  if (StreamTcpPacketStateLastAck(tv, p, stt, ssn, pq)) {
4644  return -1;
4645  }
4646  break;
4647  case TCP_TIME_WAIT:
4648  SCLogDebug("packet received on TCP_TIME_WAIT state");
4649  if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn, pq)) {
4650  return -1;
4651  }
4652  break;
4653  case TCP_CLOSED:
4654  /* TCP session memory is not returned to pool until timeout. */
4655  SCLogDebug("packet received on closed state");
4656 
4657  if (StreamTcpPacketStateClosed(tv, p, stt, ssn, pq)) {
4658  return -1;
4659  }
4660 
4661  break;
4662  default:
4663  SCLogDebug("packet received on default state");
4664  break;
4665  }
4666  return 0;
4667 }
4668 
4669 /* flow is and stays locked */
4671  PacketQueue *pq)
4672 {
4673  SCEnter();
4674 
4676 
4677  SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
4678 
4679  /* assign the thread id to the flow */
4680  if (unlikely(p->flow->thread_id == 0)) {
4681  p->flow->thread_id = (FlowThreadId)tv->id;
4682  } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id)) {
4683  SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id, tv->id);
4684  if (p->pkt_src == PKT_SRC_WIRE) {
4686  if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
4687  p->flow->flags |= FLOW_WRONG_THREAD;
4689  }
4690  }
4691  }
4692 
4693  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
4694 
4695  /* track TCP flags */
4696  if (ssn != NULL) {
4697  ssn->tcp_packet_flags |= p->tcph->th_flags;
4698  if (PKT_IS_TOSERVER(p))
4699  ssn->client.tcp_flags |= p->tcph->th_flags;
4700  else if (PKT_IS_TOCLIENT(p))
4701  ssn->server.tcp_flags |= p->tcph->th_flags;
4702 
4703  /* check if we need to unset the ASYNC flag */
4704  if (ssn->