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 
931  /* reverse packet and flow */
932  SCLogDebug("reversing flow and packet");
933  PacketSwap(p);
934  FlowSwap(p->flow);
935 
936  /* set the state */
937  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
938  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
939  "TCP_SYN_RECV", ssn);
941  /* Flag used to change the direct in the later stage in the session */
944  SCLogDebug("ssn %p: =~ ASYNC", ssn);
945  ssn->flags |= STREAMTCP_FLAG_ASYNC;
946  }
947 
948  /* sequence number & window */
949  ssn->server.isn = TCP_GET_SEQ(p);
951  ssn->server.next_seq = ssn->server.isn + 1;
952  ssn->server.window = TCP_GET_WINDOW(p);
953  SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
954 
955  ssn->client.isn = TCP_GET_ACK(p) - 1;
957  ssn->client.next_seq = ssn->client.isn + 1;
958 
959  ssn->client.last_ack = TCP_GET_ACK(p);
960  ssn->server.last_ack = TCP_GET_SEQ(p);
961 
962  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
963 
964  /** If the client has a wscale option the server had it too,
965  * so set the wscale for the server to max. Otherwise none
966  * will have the wscale opt just like it should. */
967  if (TCP_HAS_WSCALE(p)) {
968  ssn->client.wscale = TCP_GET_WSCALE(p);
970  SCLogDebug("ssn %p: wscale enabled. client %u server %u",
971  ssn, ssn->client.wscale, ssn->server.wscale);
972  }
973 
974  SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
975  " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
976  ssn->client.isn, ssn->client.next_seq,
977  ssn->client.last_ack);
978  SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
979  " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
980  ssn->server.isn, ssn->server.next_seq,
981  ssn->server.last_ack);
982 
983  /* Set the timestamp value for both streams, if packet has timestamp
984  * option enabled.*/
985  if (TCP_HAS_TS(p)) {
986  ssn->server.last_ts = TCP_GET_TSVAL(p);
987  ssn->client.last_ts = TCP_GET_TSECR(p);
988  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
989  "ssn->client.last_ts %" PRIu32"", ssn,
990  ssn->server.last_ts, ssn->client.last_ts);
991 
993 
994  ssn->server.last_pkt_ts = p->ts.tv_sec;
995  if (ssn->server.last_ts == 0)
997  if (ssn->client.last_ts == 0)
999 
1000  } else {
1001  ssn->server.last_ts = 0;
1002  ssn->client.last_ts = 0;
1003  }
1004 
1005  if (TCP_GET_SACKOK(p) == 1) {
1006  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1007  SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
1008  "SACK permitted for both sides", ssn);
1009  }
1010  return 0;
1011 
1012  } else if (p->tcph->th_flags & TH_SYN) {
1013  if (ssn == NULL) {
1014  ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
1015  if (ssn == NULL) {
1017  return -1;
1018  }
1019 
1020  StatsIncr(tv, stt->counter_tcp_sessions);
1021  }
1022 
1023  /* set the state */
1024  StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
1025  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
1026 
1028  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1029  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1030  }
1031 
1032  /* set the sequence numbers and window */
1033  ssn->client.isn = TCP_GET_SEQ(p);
1035  ssn->client.next_seq = ssn->client.isn + 1;
1036 
1037  /* Set the stream timestamp value, if packet has timestamp option
1038  * enabled. */
1039  if (TCP_HAS_TS(p)) {
1040  ssn->client.last_ts = TCP_GET_TSVAL(p);
1041  SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
1042 
1043  if (ssn->client.last_ts == 0)
1045 
1046  ssn->client.last_pkt_ts = p->ts.tv_sec;
1048  }
1049 
1050  ssn->server.window = TCP_GET_WINDOW(p);
1051  if (TCP_HAS_WSCALE(p)) {
1053  ssn->server.wscale = TCP_GET_WSCALE(p);
1054  }
1055 
1056  if (TCP_GET_SACKOK(p) == 1) {
1058  SCLogDebug("ssn %p: SACK permited on SYN packet", ssn);
1059  }
1060 
1061  SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
1062  "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
1063  "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
1064  ssn->client.last_ack);
1065 
1066  } else if (p->tcph->th_flags & TH_ACK) {
1067  if (stream_config.midstream == FALSE)
1068  return 0;
1069 
1070  if (ssn == NULL) {
1071  ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
1072  if (ssn == NULL) {
1074  return -1;
1075  }
1076  StatsIncr(tv, stt->counter_tcp_sessions);
1078  }
1079  /* set the state */
1080  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1081  SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1082  "TCP_ESTABLISHED", ssn);
1083 
1087  SCLogDebug("ssn %p: =~ ASYNC", ssn);
1088  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1089  }
1090 
1091  /** window scaling for midstream pickups, we can't do much other
1092  * than assume that it's set to the max value: 14 */
1093  ssn->client.wscale = TCP_WSCALE_MAX;
1094  ssn->server.wscale = TCP_WSCALE_MAX;
1095 
1096  /* set the sequence numbers and window */
1097  ssn->client.isn = TCP_GET_SEQ(p) - 1;
1099  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
1100  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1101  ssn->client.last_ack = TCP_GET_SEQ(p);
1102  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1103  SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
1104  ssn, ssn->client.isn, ssn->client.next_seq);
1105 
1106  ssn->server.isn = TCP_GET_ACK(p) - 1;
1108  ssn->server.next_seq = ssn->server.isn + 1;
1109  ssn->server.last_ack = TCP_GET_ACK(p);
1110  ssn->server.next_win = ssn->server.last_ack;
1111 
1112  SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
1113  "ssn->server.next_win %"PRIu32"", ssn,
1114  ssn->client.next_win, ssn->server.next_win);
1115  SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
1116  "ssn->server.last_ack %"PRIu32"", ssn,
1117  ssn->client.last_ack, ssn->server.last_ack);
1118 
1119  /* Set the timestamp value for both streams, if packet has timestamp
1120  * option enabled.*/
1121  if (TCP_HAS_TS(p)) {
1122  ssn->client.last_ts = TCP_GET_TSVAL(p);
1123  ssn->server.last_ts = TCP_GET_TSECR(p);
1124  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1125  "ssn->client.last_ts %" PRIu32"", ssn,
1126  ssn->server.last_ts, ssn->client.last_ts);
1127 
1129 
1130  ssn->client.last_pkt_ts = p->ts.tv_sec;
1131  if (ssn->server.last_ts == 0)
1133  if (ssn->client.last_ts == 0)
1135 
1136  } else {
1137  ssn->server.last_ts = 0;
1138  ssn->client.last_ts = 0;
1139  }
1140 
1141  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
1142 
1143  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1144  SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1145 
1146  } else {
1147  SCLogDebug("default case");
1148  }
1149 
1150  return 0;
1151 }
1152 
1153 /** \internal
1154  * \brief Setup TcpStateQueue based on SYN/ACK packet
1155  */
1156 static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
1157 {
1158  q->flags = 0;
1159  q->wscale = 0;
1160  q->ts = 0;
1161  q->win = TCP_GET_WINDOW(p);
1162  q->seq = TCP_GET_SEQ(p);
1163  q->ack = TCP_GET_ACK(p);
1164  q->pkt_ts = p->ts.tv_sec;
1165 
1166  if (TCP_GET_SACKOK(p) == 1)
1168 
1169  if (TCP_HAS_WSCALE(p)) {
1171  q->wscale = TCP_GET_WSCALE(p);
1172  }
1173  if (TCP_HAS_TS(p)) {
1175  q->ts = TCP_GET_TSVAL(p);
1176  }
1177 }
1178 
1179 /** \internal
1180  * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
1181  * \retval q or NULL */
1182 static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
1183 {
1184  TcpStateQueue *q = ssn->queue;
1185  TcpStateQueue search;
1186 
1187  StreamTcp3whsSynAckToStateQueue(p, &search);
1188 
1189  while (q != NULL) {
1190  if (search.flags == q->flags &&
1191  search.wscale == q->wscale &&
1192  search.win == q->win &&
1193  search.seq == q->seq &&
1194  search.ack == q->ack &&
1195  search.ts == q->ts) {
1196  return q;
1197  }
1198 
1199  q = q->next;
1200  }
1201 
1202  return q;
1203 }
1204 
1205 static int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
1206 {
1207  /* first see if this is already in our list */
1208  if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
1209  return 0;
1210 
1212  SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
1214  return -1;
1215  }
1216 
1217  if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1218  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
1219  return -1;
1220  }
1221 
1222  TcpStateQueue *q = SCMalloc(sizeof(*q));
1223  if (unlikely(q == NULL)) {
1224  SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
1225  return -1;
1226  }
1227  memset(q, 0x00, sizeof(*q));
1228  StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1229 
1230  StreamTcp3whsSynAckToStateQueue(p, q);
1231 
1232  /* put in list */
1233  q->next = ssn->queue;
1234  ssn->queue = q;
1235  ssn->queue_len++;
1236  return 0;
1237 }
1238 
1239 /** \internal
1240  * \brief Find the Queued SYN/ACK that goes with this ACK
1241  * \retval q or NULL */
1242 static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
1243 {
1244  uint32_t ack = TCP_GET_SEQ(p);
1245  uint32_t seq = TCP_GET_ACK(p) - 1;
1246  TcpStateQueue *q = ssn->queue;
1247 
1248  while (q != NULL) {
1249  if (seq == q->seq &&
1250  ack == q->ack) {
1251  return q;
1252  }
1253 
1254  q = q->next;
1255  }
1256 
1257  return NULL;
1258 }
1259 
1260 /** \internal
1261  * \brief Update SSN after receiving a valid SYN/ACK
1262  *
1263  * Normally we update the SSN from the SYN/ACK packet. But in case
1264  * of queued SYN/ACKs, we can use one of those.
1265  *
1266  * \param ssn TCP session
1267  * \param p Packet
1268  * \param q queued state if used, NULL otherwise
1269  *
1270  * To make sure all SYN/ACK based state updates are in one place,
1271  * this function can updated based on Packet or TcpStateQueue, where
1272  * the latter takes precedence.
1273  */
1274 static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
1275 {
1276  TcpStateQueue update;
1277  if (likely(q == NULL)) {
1278  StreamTcp3whsSynAckToStateQueue(p, &update);
1279  q = &update;
1280  }
1281 
1282  if (ssn->state != TCP_SYN_RECV) {
1283  /* update state */
1284  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1285  SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
1286  }
1287  /* sequence number & window */
1288  ssn->server.isn = q->seq;
1290  ssn->server.next_seq = ssn->server.isn + 1;
1291 
1292  ssn->client.window = q->win;
1293  SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
1294 
1295  /* Set the timestamp values used to validate the timestamp of
1296  * received packets.*/
1297  if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
1299  {
1300  ssn->server.last_ts = q->ts;
1301  SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1302  "ssn->client.last_ts %" PRIu32"", ssn,
1303  ssn->server.last_ts, ssn->client.last_ts);
1305  ssn->server.last_pkt_ts = q->pkt_ts;
1306  if (ssn->server.last_ts == 0)
1308  } else {
1309  ssn->client.last_ts = 0;
1310  ssn->server.last_ts = 0;
1312  }
1313 
1314  ssn->client.last_ack = q->ack;
1315  ssn->server.last_ack = ssn->server.isn + 1;
1316 
1317  /** check for the presense of the ws ptr to determine if we
1318  * support wscale at all */
1319  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1321  {
1322  ssn->client.wscale = q->wscale;
1323  } else {
1324  ssn->client.wscale = 0;
1325  }
1326 
1327  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1329  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1330  SCLogDebug("ssn %p: SACK permitted for session", ssn);
1331  } else {
1332  ssn->flags &= ~STREAMTCP_FLAG_SACKOK;
1333  }
1334 
1335  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1336  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1337  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
1338  ssn->server.next_win);
1339  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
1340  ssn->client.next_win);
1341  SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
1342  "ssn->server.next_seq %" PRIu32 ", "
1343  "ssn->server.last_ack %" PRIu32 " "
1344  "(ssn->client.last_ack %" PRIu32 ")", ssn,
1345  ssn->server.isn, ssn->server.next_seq,
1346  ssn->server.last_ack, ssn->client.last_ack);
1347 
1348  /* unset the 4WHS flag as we received this SYN/ACK as part of a
1349  * (so far) valid 3WHS */
1350  if (ssn->flags & STREAMTCP_FLAG_4WHS)
1351  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
1352  " so considering 3WHS", ssn);
1353 
1354  ssn->flags &=~ STREAMTCP_FLAG_4WHS;
1355 }
1356 
1357 /**
1358  * \brief Function to handle the TCP_SYN_SENT state. The function handles
1359  * SYN, SYN/ACK, RST packets and correspondingly changes the connection
1360  * state.
1361  *
1362  * \param tv Thread Variable containig input/output queue, cpu affinity
1363  * \param p Packet which has to be handled in this TCP state.
1364  * \param stt Strean Thread module registered to handle the stream handling
1365  */
1366 
1367 static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p,
1368  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
1369 {
1370  if (ssn == NULL)
1371  return -1;
1372 
1373  SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ?
1374  "toclient":"toserver");
1375 
1376  /* RST */
1377  if (p->tcph->th_flags & TH_RST) {
1378  if (!StreamTcpValidateRst(ssn, p))
1379  return -1;
1380 
1381  if (PKT_IS_TOSERVER(p)) {
1382  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) &&
1383  SEQ_EQ(TCP_GET_WINDOW(p), 0) &&
1384  SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1)))
1385  {
1386  SCLogDebug("ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
1388 
1389  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1390  SCLogDebug("ssn %p: Reset received and state changed to "
1391  "TCP_CLOSED", ssn);
1392  }
1393  } else {
1395  SCLogDebug("ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
1396  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1397  SCLogDebug("ssn %p: Reset received and state changed to "
1398  "TCP_CLOSED", ssn);
1399  }
1400 
1401  /* FIN */
1402  } else if (p->tcph->th_flags & TH_FIN) {
1403  /** \todo */
1404 
1405  /* SYN/ACK */
1406  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
1407  if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOSERVER(p)) {
1408  SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
1409 
1410  /* Check if the SYN/ACK packet ack's the earlier
1411  * received SYN packet. */
1412  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->server.isn + 1))) {
1414 
1415  SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %"PRIu32""
1416  " != %" PRIu32 " from stream", ssn,
1417  TCP_GET_ACK(p), ssn->server.isn + 1);
1418  return -1;
1419  }
1420 
1421  /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
1422  * packet. */
1423  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
1425 
1426  SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %"PRIu32""
1427  " != %" PRIu32 " from *first* SYN pkt", ssn,
1428  TCP_GET_SEQ(p), ssn->client.isn);
1429  return -1;
1430  }
1431 
1432 
1433  /* update state */
1434  StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1435  SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
1436 
1437  /* sequence number & window */
1438  ssn->client.isn = TCP_GET_SEQ(p);
1440  ssn->client.next_seq = ssn->client.isn + 1;
1441 
1442  ssn->server.window = TCP_GET_WINDOW(p);
1443  SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn,
1444  ssn->client.window);
1445 
1446  /* Set the timestamp values used to validate the timestamp of
1447  * received packets. */
1448  if ((TCP_HAS_TS(p)) &&
1450  {
1451  ssn->client.last_ts = TCP_GET_TSVAL(p);
1452  SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32" "
1453  "ssn->server.last_ts %" PRIu32"", ssn,
1454  ssn->client.last_ts, ssn->server.last_ts);
1456  ssn->client.last_pkt_ts = p->ts.tv_sec;
1457  if (ssn->client.last_ts == 0)
1459  } else {
1460  ssn->server.last_ts = 0;
1461  ssn->client.last_ts = 0;
1463  }
1464 
1465  ssn->server.last_ack = TCP_GET_ACK(p);
1466  ssn->client.last_ack = ssn->client.isn + 1;
1467 
1468  /** check for the presense of the ws ptr to determine if we
1469  * support wscale at all */
1470  if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1471  (TCP_HAS_WSCALE(p)))
1472  {
1473  ssn->server.wscale = TCP_GET_WSCALE(p);
1474  } else {
1475  ssn->server.wscale = 0;
1476  }
1477 
1478  if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1479  TCP_GET_SACKOK(p) == 1) {
1480  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1481  SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
1482  }
1483 
1484  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1485  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1486  SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn,
1487  ssn->client.next_win);
1488  SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn,
1489  ssn->server.next_win);
1490  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
1491  "ssn->client.next_seq %" PRIu32 ", "
1492  "ssn->client.last_ack %" PRIu32 " "
1493  "(ssn->server.last_ack %" PRIu32 ")", ssn,
1494  ssn->client.isn, ssn->client.next_seq,
1495  ssn->client.last_ack, ssn->server.last_ack);
1496 
1497  /* done here */
1498  return 0;
1499  }
1500 
1501  if (PKT_IS_TOSERVER(p)) {
1503  SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
1504  return -1;
1505  }
1506 
1507  /* Check if the SYN/ACK packet ack's the earlier
1508  * received SYN packet. */
1509  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) {
1511  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1512  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1513  ssn->client.isn + 1);
1514  return -1;
1515  }
1516 
1517  StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
1518 
1519  } else if (p->tcph->th_flags & TH_SYN) {
1520  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
1521  if (ssn->flags & STREAMTCP_FLAG_4WHS) {
1522  SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
1523  "4WHS SYN", ssn);
1524  }
1525 
1526  if (PKT_IS_TOCLIENT(p)) {
1527  /** a SYN only packet in the opposite direction could be:
1528  * http://www.breakingpointsystems.com/community/blog/tcp-
1529  * portals-the-three-way-handshake-is-a-lie
1530  *
1531  * \todo improve resetting the session */
1532 
1533  /* indicate that we're dealing with 4WHS here */
1534  ssn->flags |= STREAMTCP_FLAG_4WHS;
1535  SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
1536 
1537  /* set the sequence numbers and window for server
1538  * We leave the ssn->client.isn in place as we will
1539  * check the SYN/ACK pkt with that.
1540  */
1541  ssn->server.isn = TCP_GET_SEQ(p);
1543  ssn->server.next_seq = ssn->server.isn + 1;
1544 
1545  /* Set the stream timestamp value, if packet has timestamp
1546  * option enabled. */
1547  if (TCP_HAS_TS(p)) {
1548  ssn->server.last_ts = TCP_GET_TSVAL(p);
1549  SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
1550 
1551  if (ssn->server.last_ts == 0)
1553  ssn->server.last_pkt_ts = p->ts.tv_sec;
1555  }
1556 
1557  ssn->server.window = TCP_GET_WINDOW(p);
1558  if (TCP_HAS_WSCALE(p)) {
1560  ssn->server.wscale = TCP_GET_WSCALE(p);
1561  } else {
1563  ssn->server.wscale = 0;
1564  }
1565 
1566  if (TCP_GET_SACKOK(p) == 1) {
1568  } else {
1570  }
1571 
1572  SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
1573  "ssn->server.next_seq %" PRIu32 ", "
1574  "ssn->server.last_ack %"PRIu32"", ssn,
1575  ssn->server.isn, ssn->server.next_seq,
1576  ssn->server.last_ack);
1577  SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
1578  "ssn->client.next_seq %" PRIu32 ", "
1579  "ssn->client.last_ack %"PRIu32"", ssn,
1580  ssn->client.isn, ssn->client.next_seq,
1581  ssn->client.last_ack);
1582  }
1583 
1584  /** \todo check if it's correct or set event */
1585 
1586  } else if (p->tcph->th_flags & TH_ACK) {
1587  /* Handle the asynchronous stream, when we receive a SYN packet
1588  and now istead of receving a SYN/ACK we receive a ACK from the
1589  same host, which sent the SYN, this suggests the ASNYC streams.*/
1591  return 0;
1592 
1593  /* we are in AYNC (one side) mode now. */
1594 
1595  /* one side async means we won't see a SYN/ACK, so we can
1596  * only check the SYN. */
1597  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) {
1599 
1600  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
1601  "%" PRIu32 " from stream",ssn, TCP_GET_SEQ(p),
1602  ssn->client.next_seq);
1603  return -1;
1604  }
1605 
1606  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1607  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1608  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1609 
1610  ssn->client.window = TCP_GET_WINDOW(p);
1611  ssn->client.last_ack = TCP_GET_SEQ(p);
1612  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1613 
1614  /* Set the server side parameters */
1615  ssn->server.isn = TCP_GET_ACK(p) - 1;
1617  ssn->server.next_seq = ssn->server.isn + 1;
1618  ssn->server.last_ack = ssn->server.next_seq;
1619  ssn->server.next_win = ssn->server.last_ack;
1620 
1621  SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
1622  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
1623  "ssn->client.next_seq %" PRIu32 ""
1624  ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
1625  + p->payload_len, ssn->client.next_seq);
1626 
1627  /* if SYN had wscale, assume it to be supported. Otherwise
1628  * we know it not to be supported. */
1629  if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
1630  ssn->client.wscale = TCP_WSCALE_MAX;
1631  }
1632 
1633  /* Set the timestamp values used to validate the timestamp of
1634  * received packets.*/
1635  if (TCP_HAS_TS(p) &&
1637  {
1640  ssn->client.last_pkt_ts = p->ts.tv_sec;
1641  } else {
1642  ssn->client.last_ts = 0;
1644  }
1645 
1646  if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
1647  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1648  }
1649 
1651  &ssn->client, p, pq);
1652 
1653  } else {
1654  SCLogDebug("ssn %p: default case", ssn);
1655  }
1656 
1657  return 0;
1658 }
1659 
1660 /**
1661  * \brief Function to handle the TCP_SYN_RECV state. The function handles
1662  * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
1663  * the connection state.
1664  *
1665  * \param tv Thread Variable containig input/output queue, cpu affinity
1666  * \param p Packet which has to be handled in this TCP state.
1667  * \param stt Strean Thread module registered to handle the stream handling
1668  *
1669  * \retval 0 ok
1670  * \retval -1 error
1671  */
1672 
1673 static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p,
1674  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
1675 {
1676  if (ssn == NULL)
1677  return -1;
1678 
1679  if (p->tcph->th_flags & TH_RST) {
1680  if (!StreamTcpValidateRst(ssn, p))
1681  return -1;
1682 
1683  uint8_t reset = TRUE;
1684  /* After receiveing the RST in SYN_RECV state and if detection
1685  evasion flags has been set, then the following operating
1686  systems will not closed the connection. As they consider the
1687  packet as stray packet and not belonging to the current
1688  session, for more information check
1689  http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
1691  if (PKT_IS_TOSERVER(p)) {
1692  if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
1693  (ssn->server.os_policy == OS_POLICY_OLD_LINUX) ||
1695  {
1696  reset = FALSE;
1697  SCLogDebug("Detection evasion has been attempted, so"
1698  " not resetting the connection !!");
1699  }
1700  } else {
1701  if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
1702  (ssn->client.os_policy == OS_POLICY_OLD_LINUX) ||
1704  {
1705  reset = FALSE;
1706  SCLogDebug("Detection evasion has been attempted, so"
1707  " not resetting the connection !!");
1708  }
1709  }
1710  }
1711 
1712  if (reset == TRUE) {
1713  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1714  SCLogDebug("ssn %p: Reset received and state changed to "
1715  "TCP_CLOSED", ssn);
1716 
1717  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1718  StreamTcpHandleTimestamp(ssn, p);
1719  }
1720  }
1721 
1722  } else if (p->tcph->th_flags & TH_FIN) {
1723  /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
1724  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1725  if (!StreamTcpValidateTimestamp(ssn, p))
1726  return -1;
1727  }
1728 
1729  if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1)
1730  return -1;
1731 
1732  /* SYN/ACK */
1733  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
1734  SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
1735 
1736  if (PKT_IS_TOSERVER(p)) {
1737  SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
1738 
1740  return -1;
1741  }
1742 
1743  /* Check if the SYN/ACK packets ACK matches the earlier
1744  * received SYN/ACK packet. */
1745  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
1746  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1747  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1748  ssn->client.isn + 1);
1749 
1751  return -1;
1752  }
1753 
1754  /* Check if the SYN/ACK packet SEQ the earlier
1755  * received SYN/ACK packet, server resend with different ISN. */
1756  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
1757  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
1758  "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
1759  ssn->client.isn);
1760 
1761  if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
1762  return -1;
1763  SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
1764  }
1765 
1766  } else if (p->tcph->th_flags & TH_SYN) {
1767  SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
1768 
1769  if (PKT_IS_TOCLIENT(p)) {
1770  SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
1771 
1773  return -1;
1774  }
1775 
1776  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
1777  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
1778 
1780  return -1;
1781  }
1782 
1783  } else if (p->tcph->th_flags & TH_ACK) {
1784  if (ssn->queue_len) {
1785  SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
1786  TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
1787  if (q != NULL) {
1788  SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
1789  StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
1790  } else {
1791  SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
1792  }
1793  }
1794 
1795 
1796  /* If the timestamp option is enabled for both the streams, then
1797  * validate the received packet timestamp value against the
1798  * stream->last_ts. If the timestamp is valid then process the
1799  * packet normally otherwise the drop the packet (RFC 1323)*/
1800  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1801  if (!(StreamTcpValidateTimestamp(ssn, p))) {
1802  return -1;
1803  }
1804  }
1805 
1806  if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) {
1807  SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
1808 
1809  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) {
1810  SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
1812  return -1;
1813  }
1814 
1815  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
1816  SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
1818  return -1;
1819  }
1820 
1821  SCLogDebug("4WHS normal pkt");
1822  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
1823  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
1824  TCP_GET_SEQ(p), TCP_GET_ACK(p));
1825 
1826  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1827  StreamTcpHandleTimestamp(ssn, p);
1828  }
1829 
1830  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
1831  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
1832  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1833  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1834 
1835  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1836  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1837 
1839  &ssn->server, p, pq);
1840 
1841  SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
1842  "ssn->client.last_ack %"PRIu32"", ssn,
1843  ssn->client.next_win, ssn->client.last_ack);
1844  return 0;
1845  }
1846 
1847  bool ack_indicates_missed_3whs_ack_packet = false;
1848  /* Check if the ACK received is in right direction. But when we have
1849  * picked up a mid stream session after missing the initial SYN pkt,
1850  * in this case the ACK packet can arrive from either client (normal
1851  * case) or from server itself (asynchronous streams). Therefore
1852  * the check has been avoided in this case */
1853  if (PKT_IS_TOCLIENT(p)) {
1854  /* special case, handle 4WHS, so SYN/ACK in the opposite
1855  * direction */
1857  SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
1858  "pickup session",ssn);
1859  /* fall through */
1860 
1861  } else {
1862  /* if we missed traffic between the S/SA and the current
1863  * 'wrong direction' ACK, we could end up here. In IPS
1864  * reject it. But in IDS mode we continue.
1865  *
1866  * IPS rejects as it should see all packets, so pktloss
1867  * should lead to retransmissions. As this can also be
1868  * pattern for MOTS/MITM injection attacks, we need to be
1869  * careful.
1870  */
1871  if (StreamTcpInlineMode()) {
1872  if (p->payload_len > 0 &&
1873  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) &&
1874  SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
1875  /* packet loss is possible but unlikely here */
1876  SCLogDebug("ssn %p: possible data injection", ssn);
1878  return -1;
1879  }
1880 
1881  SCLogDebug("ssn %p: ACK received in the wrong direction",
1882  ssn);
1884  return -1;
1885  }
1886  ack_indicates_missed_3whs_ack_packet = true;
1887  }
1888  }
1889 
1890  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
1891  ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
1892  TCP_GET_ACK(p));
1893 
1894  /* Check both seq and ack number before accepting the packet and
1895  changing to ESTABLISHED state */
1896  if ((SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) &&
1897  SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) {
1898  SCLogDebug("normal pkt");
1899 
1900  /* process the packet normal, No Async streams :) */
1901 
1902  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1903  StreamTcpHandleTimestamp(ssn, p);
1904  }
1905 
1906  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
1907  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
1908  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
1909 
1910  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1911 
1912  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
1913  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1914  ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1915  ssn->server.next_win = ssn->server.last_ack +
1916  ssn->server.window;
1917  if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
1918  /* window scaling for midstream pickups, we can't do much
1919  * other than assume that it's set to the max value: 14 */
1920  ssn->server.wscale = TCP_WSCALE_MAX;
1921  ssn->client.wscale = TCP_WSCALE_MAX;
1922  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1923  }
1924  }
1925 
1926  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1927  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1928 
1930  &ssn->client, p, pq);
1931 
1932  /* If asynchronous stream handling is allowed then set the session,
1933  if packet's seq number is equal the expected seq no.*/
1934  } else if (stream_config.async_oneside == TRUE &&
1935  (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)))
1936  {
1937  /*set the ASYNC flag used to indicate the session as async stream
1938  and helps in relaxing the windows checks.*/
1939  ssn->flags |= STREAMTCP_FLAG_ASYNC;
1940  ssn->server.next_seq += p->payload_len;
1941  ssn->server.last_ack = TCP_GET_SEQ(p);
1942 
1943  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1944  ssn->client.last_ack = TCP_GET_ACK(p);
1945 
1946  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1947  StreamTcpHandleTimestamp(ssn, p);
1948  }
1949 
1950  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
1951  ssn->server.window = TCP_GET_WINDOW(p);
1952  ssn->client.next_win = ssn->server.last_ack +
1953  ssn->server.window;
1954  /* window scaling for midstream pickups, we can't do much
1955  * other than assume that it's set to the max value: 14 */
1956  ssn->server.wscale = TCP_WSCALE_MAX;
1957  ssn->client.wscale = TCP_WSCALE_MAX;
1958  ssn->flags |= STREAMTCP_FLAG_SACKOK;
1959  }
1960 
1961  SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
1962  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
1963  "ssn->server.next_seq %" PRIu32 "\n"
1964  , ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
1965  + p->payload_len, ssn->server.next_seq);
1966 
1967  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1968  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1969 
1971  &ssn->server, p, pq);
1972  /* Upon receiving the packet with correct seq number and wrong
1973  ACK number, it causes the other end to send RST. But some target
1974  system (Linux & solaris) does not RST the connection, so it is
1975  likely to avoid the detection */
1976  } else if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)){
1978  SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
1979  ssn);
1980 
1982  return -1;
1983 
1984  /* if we get a packet with a proper ack, but a seq that is beyond
1985  * next_seq but in-window, we probably missed some packets */
1986  } else if (SEQ_GT(TCP_GET_SEQ(p), ssn->client.next_seq) &&
1987  SEQ_LEQ(TCP_GET_SEQ(p),ssn->client.next_win) &&
1988  SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq))
1989  {
1990  SCLogDebug("ssn %p: ACK for missing data", ssn);
1991 
1992  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1993  StreamTcpHandleTimestamp(ssn, p);
1994  }
1995 
1996  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
1997 
1998  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
1999  SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
2000  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2001 
2002  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2003 
2004  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2005  ssn->client.window = TCP_GET_WINDOW(p);
2006  ssn->server.next_win = ssn->server.last_ack +
2007  ssn->server.window;
2008  /* window scaling for midstream pickups, we can't do much
2009  * other than assume that it's set to the max value: 14 */
2010  ssn->server.wscale = TCP_WSCALE_MAX;
2011  ssn->client.wscale = TCP_WSCALE_MAX;
2012  ssn->flags |= STREAMTCP_FLAG_SACKOK;
2013  }
2014 
2015  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2016  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2017 
2019  &ssn->client, p, pq);
2020 
2021  /* toclient packet: after having missed the 3whs's final ACK */
2022  } else if (ack_indicates_missed_3whs_ack_packet &&
2023  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) &&
2024  SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))
2025  {
2026  SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2027 
2028  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2029 
2030  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2031  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2032 
2033  StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2034  SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2035 
2037  &ssn->server, p, pq);
2038 
2039  } else {
2040  SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2041 
2043  return -1;
2044  }
2045 
2046  SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2047  "ssn->server.last_ack %"PRIu32"", ssn,
2048  ssn->server.next_win, ssn->server.last_ack);
2049  } else {
2050  SCLogDebug("ssn %p: default case", ssn);
2051  }
2052 
2053  return 0;
2054 }
2055 
2056 /**
2057  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2058  * sent by the client to server. The function handles
2059  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2060  * the reassembly.
2061  *
2062  * Timestamp has already been checked at this point.
2063  *
2064  * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2065  * \param ssn Pointer to the current TCP session
2066  * \param p Packet which has to be handled in this TCP state.
2067  * \param stt Strean Thread module registered to handle the stream handling
2068  */
2069 static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Packet *p,
2070  StreamTcpThread *stt, PacketQueue *pq)
2071 {
2072  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2073  "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
2075 
2076  if (StreamTcpValidateAck(ssn, &(ssn->server), p) == -1) {
2077  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2079  return -1;
2080  }
2081 
2082  /* check for Keep Alive */
2083  if ((p->payload_len == 0 || p->payload_len == 1) &&
2084  (TCP_GET_SEQ(p) == (ssn->client.next_seq - 1))) {
2085  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2086 
2087  /* normal pkt */
2088  } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack))) {
2089  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2090  SCLogDebug("ssn %p: server => Asynchrouns stream, packet SEQ"
2091  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2092  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2093  "%" PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2094  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2095  ssn->client.last_ack, ssn->client.next_win,
2096  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2097 
2098  /* update the last_ack to current seq number as the session is
2099  * async and other stream is not updating it anymore :( */
2100  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2101 
2102  } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p)) &&
2104  (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2105  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2106  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2107  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2108  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2109  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2110  ssn->client.last_ack, ssn->client.next_win,
2111  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2112 
2113  /* it seems we missed SYN and SYN/ACK packets of this session.
2114  * Update the last_ack to current seq number as the session
2115  * is async and other stream is not updating it anymore :( */
2116  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2117  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2118 
2119  } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2121  (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2122  SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2123  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2124  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2125  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2126  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2127  ssn->client.last_ack, ssn->client.next_win,
2128  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2129 
2130  /* it seems we missed SYN and SYN/ACK packets of this session.
2131  * Update the last_ack to current seq number as the session
2132  * is async and other stream is not updating it anymore :(*/
2133  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2134  ssn->flags |= STREAMTCP_FLAG_ASYNC;
2135 
2136  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2137  * In this case we do accept the data before last_ack if it is (partly)
2138  * beyond next seq */
2139  } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
2141  {
2142  SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2143  " before last_ack %"PRIu32", after next_seq %"PRIu32":"
2144  " acked data that we haven't seen before",
2145  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->client.last_ack, ssn->client.next_seq);
2146  if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq)) {
2147  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2148  }
2149  } else {
2150  SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
2151  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2152  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2153  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2154  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2155  ssn->client.last_ack, ssn->client.next_win,
2156  TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2157 
2158  SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
2160  return -1;
2161  }
2162  }
2163 
2164  int zerowindowprobe = 0;
2165  /* zero window probe */
2166  if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->client.next_seq && ssn->client.window == 0) {
2167  SCLogDebug("ssn %p: zero window probe", ssn);
2168  zerowindowprobe = 1;
2169 
2170  /* expected packet */
2171  } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2172  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2173 
2174  /* not completely as expected, but valid */
2175  } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->client.next_seq) &&
2176  SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->client.next_seq))
2177  {
2178  StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
2179  SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32
2180  " (started before next_seq, ended after)",
2181  ssn, ssn->client.next_seq);
2182 
2183  /* if next_seq has fallen behind last_ack, we got some catching up to do */
2184  } else if (SEQ_LT(ssn->client.next_seq, ssn->client.last_ack)) {
2185  StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
2186  SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32
2187  " (next_seq had fallen behind last_ack)",
2188  ssn, ssn->client.next_seq);
2189 
2190  } else {
2191  SCLogDebug("ssn %p: no update to ssn->client.next_seq %"PRIu32
2192  " SEQ %u SEQ+ %u last_ack %u",
2193  ssn, ssn->client.next_seq,
2195  }
2196 
2197  /* in window check */
2198  if (zerowindowprobe) {
2199  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2200  } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
2202  {
2203  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
2204  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
2205 
2206  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2207  SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
2208  ssn->server.window);
2209 
2210  /* Check if the ACK value is sane and inside the window limit */
2211  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2212  SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, ssn->server.next_seq);
2213 
2214  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2215  StreamTcpHandleTimestamp(ssn, p);
2216  }
2217 
2219 
2220  /* update next_win */
2221  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
2222 
2223  /* handle data (if any) */
2224  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
2225 
2226  } else {
2227  SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
2228  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2229  "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2230  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2231  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2232  ssn->client.last_ack, ssn->client.next_win,
2233  (TCP_GET_SEQ(p) + p->payload_len) - ssn->client.next_win);
2234  SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
2235  StreamTcpSackedSize(&ssn->client));
2237  return -1;
2238  }
2239  return 0;
2240 }
2241 
2242 /**
2243  * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2244  * sent by the server to client. The function handles
2245  * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2246  * the reassembly
2247  *
2248  * Timestamp has already been checked at this point.
2249  *
2250  * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2251  * \param ssn Pointer to the current TCP session
2252  * \param p Packet which has to be handled in this TCP state.
2253  * \param stt Strean Thread module registered to handle the stream handling
2254  */
2255 static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Packet *p,
2256  StreamTcpThread *stt, PacketQueue *pq)
2257 {
2258  SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
2259  " ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
2261 
2262  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2263  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2265  return -1;
2266  }
2267 
2268  /* To get the server window value from the servers packet, when connection
2269  is picked up as midstream */
2270  if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
2272  {
2273  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2274  ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2276  SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
2277  "%" PRIu32 "", ssn, ssn->server.next_win);
2278  }
2279 
2280  /* check for Keep Alive */
2281  if ((p->payload_len == 0 || p->payload_len == 1) &&
2282  (TCP_GET_SEQ(p) == (ssn->server.next_seq - 1))) {
2283  SCLogDebug("ssn %p: pkt is keep alive", ssn);
2284 
2285  /* normal pkt */
2286  } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->server.last_ack))) {
2287  if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2288 
2289  SCLogDebug("ssn %p: client => Asynchrouns stream, packet SEQ"
2290  " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2291  " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2292  " %"PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2293  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2294  ssn->server.last_ack, ssn->server.next_win,
2295  TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
2296 
2297  ssn->server.last_ack = TCP_GET_SEQ(p);
2298 
2299  /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2300  * In this case we do accept the data before last_ack if it is (partly)
2301  * beyond next seq */
2302  } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
2304  {
2305  SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2306  " before last_ack %"PRIu32", after next_seq %"PRIu32":"
2307  " acked data that we haven't seen before",
2308  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2309  if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq)) {
2310  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2311  }
2312  } else {
2313  SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2314  " before last_ack %"PRIu32". next_seq %"PRIu32,
2315  ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2317  return -1;
2318  }
2319  }
2320 
2321  int zerowindowprobe = 0;
2322  /* zero window probe */
2323  if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->server.next_seq && ssn->server.window == 0) {
2324  SCLogDebug("ssn %p: zero window probe", ssn);
2325  zerowindowprobe = 1;
2326 
2327  /* expected packet */
2328  } else if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
2329  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2330 
2331  /* not completely as expected, but valid */
2332  } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->server.next_seq) &&
2333  SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->server.next_seq))
2334  {
2335  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2336  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32
2337  " (started before next_seq, ended after)",
2338  ssn, ssn->server.next_seq);
2339 
2340  /* if next_seq has fallen behind last_ack, we got some catching up to do */
2341  } else if (SEQ_LT(ssn->server.next_seq, ssn->server.last_ack)) {
2342  StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2343  SCLogDebug("ssn %p: ssn->server.next_seq %"PRIu32
2344  " (next_seq had fallen behind last_ack)",
2345  ssn, ssn->server.next_seq);
2346 
2347  } else {
2348  SCLogDebug("ssn %p: no update to ssn->server.next_seq %"PRIu32
2349  " SEQ %u SEQ+ %u last_ack %u",
2350  ssn, ssn->server.next_seq,
2352  }
2353 
2354  if (zerowindowprobe) {
2355  SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2356  } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
2358  {
2359  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
2360  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
2361  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2362  SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
2363  ssn->client.window);
2364 
2365  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2366 
2367  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2368  StreamTcpHandleTimestamp(ssn, p);
2369  }
2370 
2372 
2373  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
2374 
2375  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
2376  } else {
2377  SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
2378  "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2379  " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
2380  "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2381  p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2382  ssn->server.last_ack, ssn->server.next_win,
2383  TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
2385  return -1;
2386  }
2387  return 0;
2388 }
2389 
2390 /**
2391  * \internal
2392  *
2393  * \brief Find the highest sequence number needed to consider all segments as ACK'd
2394  *
2395  * Used to treat all segments as ACK'd upon receiving a valid RST.
2396  *
2397  * \param stream stream to inspect the segments from
2398  * \param seq sequence number to check against
2399  *
2400  * \retval ack highest ack we need to set
2401  */
2402 static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
2403 {
2404  uint32_t ack = seq;
2405 
2406  if (STREAM_HAS_SEEN_DATA(stream)) {
2407  const uint32_t tail_seq = STREAM_SEQ_RIGHT_EDGE(stream);
2408  if (SEQ_GT(tail_seq, ack)) {
2409  ack = tail_seq;
2410  }
2411  }
2412 
2413  SCReturnUInt(ack);
2414 }
2415 
2416 /**
2417  * \brief Function to handle the TCP_ESTABLISHED state. The function handles
2418  * ACK, FIN, RST packets and correspondingly changes the connection
2419  * state. The function handles the data inside packets and call
2420  * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
2421  *
2422  * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2423  * \param p Packet which has to be handled in this TCP state.
2424  * \param stt Strean Thread module registered to handle the stream handling
2425  */
2426 
2427 static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p,
2428  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
2429 {
2430  if (ssn == NULL)
2431  return -1;
2432 
2433  if (p->tcph->th_flags & TH_RST) {
2434  if (!StreamTcpValidateRst(ssn, p))
2435  return -1;
2436 
2437  if (PKT_IS_TOSERVER(p)) {
2438  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
2439  SCLogDebug("ssn %p: Reset received and state changed to "
2440  "TCP_CLOSED", ssn);
2441 
2442  ssn->server.next_seq = TCP_GET_ACK(p);
2443  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2444  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2445  ssn->server.next_seq);
2446  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2447 
2448  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
2449  StreamTcpUpdateLastAck(ssn, &ssn->server,
2450  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
2451 
2452  StreamTcpUpdateLastAck(ssn, &ssn->client,
2453  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
2454 
2455  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2456  StreamTcpHandleTimestamp(ssn, p);
2457  }
2458 
2460  &ssn->client, p, pq);
2461  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2462  "%" PRIu32 "", ssn, ssn->client.next_seq,
2463  ssn->server.last_ack);
2464 
2465  /* don't return packets to pools here just yet, the pseudo
2466  * packet will take care, otherwise the normal session
2467  * cleanup. */
2468  } else {
2469  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
2470  SCLogDebug("ssn %p: Reset received and state changed to "
2471  "TCP_CLOSED", ssn);
2472 
2473  ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1;
2474  ssn->client.next_seq = TCP_GET_ACK(p);
2475 
2476  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2477  ssn->server.next_seq);
2478  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2479 
2480  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
2481  StreamTcpUpdateLastAck(ssn, &ssn->client,
2482  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
2483 
2484  StreamTcpUpdateLastAck(ssn, &ssn->server,
2485  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
2486 
2487  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2488  StreamTcpHandleTimestamp(ssn, p);
2489  }
2490 
2492  &ssn->server, p, pq);
2493  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2494  "%" PRIu32 "", ssn, ssn->server.next_seq,
2495  ssn->client.last_ack);
2496 
2497  /* don't return packets to pools here just yet, the pseudo
2498  * packet will take care, otherwise the normal session
2499  * cleanup. */
2500  }
2501 
2502  } else if (p->tcph->th_flags & TH_FIN) {
2503  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2504  if (!StreamTcpValidateTimestamp(ssn, p))
2505  return -1;
2506  }
2507 
2508  SCLogDebug("ssn (%p: FIN received SEQ"
2509  " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
2510  " win %" PRIu32 "", ssn, ssn->server.next_seq,
2511  ssn->client.last_ack, ssn->server.next_win,
2512  ssn->server.window);
2513 
2514  if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1)
2515  return -1;
2516 
2517  /* SYN/ACK */
2518  } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
2519  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
2520  ssn);
2521 
2522  if (PKT_IS_TOSERVER(p)) {
2523  SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
2524 
2526  return -1;
2527  }
2528 
2529  /* Check if the SYN/ACK packets ACK matches the earlier
2530  * received SYN/ACK packet. */
2531  if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
2532  SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
2533  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
2534  ssn->client.isn + 1);
2535 
2537  return -1;
2538  }
2539 
2540  /* Check if the SYN/ACK packet SEQ the earlier
2541  * received SYN packet. */
2542  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
2543  SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2544  "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
2545  ssn->client.isn + 1);
2546 
2548  return -1;
2549  }
2550 
2551  if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
2552  /* a resend of a SYN while we are established already -- fishy */
2554  return -1;
2555  }
2556 
2557  SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
2558  "Likely due server not receiving final ACK in 3whs", ssn);
2559  return 0;
2560 
2561  } else if (p->tcph->th_flags & TH_SYN) {
2562  SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
2563  if (PKT_IS_TOCLIENT(p)) {
2564  SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
2565 
2567  return -1;
2568  }
2569 
2570  if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
2571  SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
2572 
2574  return -1;
2575  }
2576 
2577  /* a resend of a SYN while we are established already -- fishy */
2579  return -1;
2580 
2581  } else if (p->tcph->th_flags & TH_ACK) {
2582  /* Urgent pointer size can be more than the payload size, as it tells
2583  * the future coming data from the sender will be handled urgently
2584  * until data of size equal to urgent offset has been processed
2585  * (RFC 2147) */
2586 
2587  /* If the timestamp option is enabled for both the streams, then
2588  * validate the received packet timestamp value against the
2589  * stream->last_ts. If the timestamp is valid then process the
2590  * packet normally otherwise the drop the packet (RFC 1323) */
2591  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2592  if (!StreamTcpValidateTimestamp(ssn, p))
2593  return -1;
2594  }
2595 
2596  if (PKT_IS_TOSERVER(p)) {
2597  /* Process the received packet to server */
2598  HandleEstablishedPacketToServer(tv, ssn, p, stt, pq);
2599 
2600  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
2601  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
2602  ssn->client.next_seq, ssn->server.last_ack
2603  ,ssn->client.next_win, ssn->client.window);
2604 
2605  } else { /* implied to client */
2606  if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
2608  SCLogDebug("3whs is now confirmed by server");
2609  }
2610 
2611  /* Process the received packet to client */
2612  HandleEstablishedPacketToClient(tv, ssn, p, stt, pq);
2613 
2614  SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
2615  " next win %" PRIu32 ", win %" PRIu32 "", ssn,
2616  ssn->server.next_seq, ssn->client.last_ack,
2617  ssn->server.next_win, ssn->server.window);
2618  }
2619  } else {
2620  SCLogDebug("ssn %p: default case", ssn);
2621  }
2622 
2623  return 0;
2624 }
2625 
2626 /**
2627  * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
2628  * TCP_ESTABLISHED and changes to another TCP state as required.
2629  *
2630  * \param tv Thread Variable containig input/output queue, cpu affinity
2631  * \param p Packet which has to be handled in this TCP state.
2632  * \param stt Strean Thread module registered to handle the stream handling
2633  *
2634  * \retval 0 success
2635  * \retval -1 something wrong with the packet
2636  */
2637 
2638 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt,
2639  TcpSession *ssn, Packet *p, PacketQueue *pq)
2640 {
2641  if (PKT_IS_TOSERVER(p)) {
2642  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2643  " ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
2644  TCP_GET_ACK(p));
2645 
2646  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2647  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2649  return -1;
2650  }
2651 
2652  if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
2653  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
2654  {
2655  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
2656  "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
2657  ssn->client.next_seq);
2658 
2660  return -1;
2661  }
2662 
2663  StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
2664  SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
2665 
2666  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))
2667  ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2668 
2669  SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
2670  ssn->client.next_seq);
2671  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2672 
2673  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2674 
2675  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2676  StreamTcpHandleTimestamp(ssn, p);
2677  }
2678 
2679  /* Update the next_seq, in case if we have missed the client packet
2680  and server has already received and acked it */
2681  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
2682  ssn->server.next_seq = TCP_GET_ACK(p);
2683 
2684  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
2685 
2686  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
2687  ssn, ssn->client.next_seq, ssn->server.last_ack);
2688  } else { /* implied to client */
2689  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
2690  "ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
2691  TCP_GET_ACK(p));
2692 
2693  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2694  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2696  return -1;
2697  }
2698 
2699  if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
2700  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
2701  {
2702  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
2703  "%" PRIu32 " from stream (last_ack %u win %u = %u)", ssn, TCP_GET_SEQ(p),
2704  ssn->server.next_seq, ssn->server.last_ack, ssn->server.window, (ssn->server.last_ack + ssn->server.window));
2705 
2707  return -1;
2708  }
2709 
2710  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
2711  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
2712 
2713  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))
2714  ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2715 
2716  SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2717  ssn->server.next_seq);
2718  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2719 
2720  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2721 
2722  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2723  StreamTcpHandleTimestamp(ssn, p);
2724  }
2725 
2726  /* Update the next_seq, in case if we have missed the client packet
2727  and server has already received and acked it */
2728  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
2729  ssn->client.next_seq = TCP_GET_ACK(p);
2730 
2731  StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
2732 
2733  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
2734  ssn, ssn->server.next_seq, ssn->client.last_ack);
2735  }
2736 
2737  return 0;
2738 }
2739 
2740 /**
2741  * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
2742  * ACK, FIN, RST packets and correspondingly changes the connection
2743  * state.
2744  *
2745  * \param tv Thread Variable containig input/output queue, cpu affinity
2746  * \param p Packet which has to be handled in this TCP state.
2747  * \param stt Strean Thread module registered to handle the stream handling
2748  *
2749  * \retval 0 success
2750  * \retval -1 something wrong with the packet
2751  */
2752 
2753 static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p,
2754  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
2755 {
2756  if (ssn == NULL)
2757  return -1;
2758 
2759  if (p->tcph->th_flags & TH_RST) {
2760  if (!StreamTcpValidateRst(ssn, p))
2761  return -1;
2762 
2763  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
2764  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
2765  ssn);
2766 
2767  if (PKT_IS_TOSERVER(p)) {
2768  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
2769  StreamTcpUpdateLastAck(ssn, &ssn->server,
2770  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
2771 
2772  StreamTcpUpdateLastAck(ssn, &ssn->client,
2773  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
2774 
2775  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2776  StreamTcpHandleTimestamp(ssn, p);
2777  }
2778 
2780  &ssn->client, p, pq);
2781  } else {
2782  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
2783  StreamTcpUpdateLastAck(ssn, &ssn->client,
2784  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
2785 
2786  StreamTcpUpdateLastAck(ssn, &ssn->server,
2787  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
2788 
2789  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2790  StreamTcpHandleTimestamp(ssn, p);
2791  }
2792 
2794  &ssn->server, p, pq);
2795  }
2796 
2797  } else if ((p->tcph->th_flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) {
2798  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2799  if (!StreamTcpValidateTimestamp(ssn, p))
2800  return -1;
2801  }
2802 
2803  if (PKT_IS_TOSERVER(p)) {
2804  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
2805  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2806  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2807  int retransmission = 0;
2808 
2809  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
2810  SCLogDebug("ssn %p: packet is retransmission", ssn);
2811  retransmission = 1;
2812 
2813  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
2814  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
2815  {
2816  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2817  " != %" PRIu32 " from stream", ssn,
2818  TCP_GET_SEQ(p), ssn->client.next_seq);
2820  return -1;
2821  }
2822 
2823  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2824  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2826  return -1;
2827  }
2828 
2829  if (!retransmission) {
2830  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
2831  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
2832 
2833  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2834  }
2835 
2836  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2837 
2838  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2839  StreamTcpHandleTimestamp(ssn, p);
2840  }
2841 
2842  /* Update the next_seq, in case if we have missed the client
2843  packet and server has already received and acked it */
2844  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
2845  ssn->server.next_seq = TCP_GET_ACK(p);
2846 
2847  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2848  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2849  }
2850 
2852  &ssn->client, p, pq);
2853 
2854  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2855  "%" PRIu32 "", ssn, ssn->client.next_seq,
2856  ssn->server.last_ack);
2857  } else { /* implied to client */
2858  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2859  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2860  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2861  int retransmission = 0;
2862 
2863  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
2864  SCLogDebug("ssn %p: packet is retransmission", ssn);
2865  retransmission = 1;
2866 
2867  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
2868  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
2869  {
2870  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2871  " != %" PRIu32 " from stream", ssn,
2872  TCP_GET_SEQ(p), ssn->server.next_seq);
2874  return -1;
2875  }
2876 
2877  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2878  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2880  return -1;
2881  }
2882 
2883  if (!retransmission) {
2884  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
2885  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
2886 
2887  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2888  }
2889 
2890  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2891 
2892  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2893  StreamTcpHandleTimestamp(ssn, p);
2894  }
2895 
2896  /* Update the next_seq, in case if we have missed the client
2897  packet and server has already received and acked it */
2898  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
2899  ssn->client.next_seq = TCP_GET_ACK(p);
2900 
2901  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
2902  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2903  }
2904 
2906  &ssn->server, p, pq);
2907 
2908  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2909  "%" PRIu32 "", ssn, ssn->server.next_seq,
2910  ssn->client.last_ack);
2911  }
2912 
2913  } else if (p->tcph->th_flags & TH_FIN) {
2914  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2915  if (!StreamTcpValidateTimestamp(ssn, p))
2916  return -1;
2917  }
2918 
2919  if (PKT_IS_TOSERVER(p)) {
2920  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
2921  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2922  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2923  int retransmission = 0;
2924 
2925  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
2926  SCLogDebug("ssn %p: packet is retransmission", ssn);
2927  retransmission = 1;
2928 
2929  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
2930  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
2931  {
2932  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2933  " != %" PRIu32 " from stream", ssn,
2934  TCP_GET_SEQ(p), ssn->client.next_seq);
2936  return -1;
2937  }
2938 
2939  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2940  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2942  return -1;
2943  }
2944 
2945  if (!retransmission) {
2946  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
2947  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
2948 
2949  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2950  }
2951 
2952  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2953 
2954  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2955  StreamTcpHandleTimestamp(ssn, p);
2956  }
2957 
2958  /* Update the next_seq, in case if we have missed the client
2959  packet and server has already received and acked it */
2960  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
2961  ssn->server.next_seq = TCP_GET_ACK(p);
2962 
2963  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2964  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2965  }
2966 
2968  &ssn->client, p, pq);
2969 
2970  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2971  "%" PRIu32 "", ssn, ssn->client.next_seq,
2972  ssn->server.last_ack);
2973  } else { /* implied to client */
2974  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2975  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2976  TCP_GET_SEQ(p), TCP_GET_ACK(p));
2977 
2978  int retransmission = 0;
2979 
2980  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
2981  SCLogDebug("ssn %p: packet is retransmission", ssn);
2982  retransmission = 1;
2983 
2984  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
2985  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
2986  {
2987  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2988  " != %" PRIu32 " from stream", ssn,
2989  TCP_GET_SEQ(p), ssn->server.next_seq);
2991  return -1;
2992  }
2993 
2994  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2995  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2997  return -1;
2998  }
2999 
3000  if (!retransmission) {
3001  StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3002  SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3003 
3004  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3005  }
3006 
3007  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3008 
3009  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3010  StreamTcpHandleTimestamp(ssn, p);
3011  }
3012 
3013  /* Update the next_seq, in case if we have missed the client
3014  packet and server has already received and acked it */
3015  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3016  ssn->client.next_seq = TCP_GET_ACK(p);
3017 
3018  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3019  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3020  }
3021 
3023  &ssn->server, p, pq);
3024 
3025  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3026  "%" PRIu32 "", ssn, ssn->server.next_seq,
3027  ssn->client.last_ack);
3028  }
3029  } else if (p->tcph->th_flags & TH_SYN) {
3030  SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
3032  return -1;
3033 
3034  } else if (p->tcph->th_flags & TH_ACK) {
3035  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3036  if (!StreamTcpValidateTimestamp(ssn, p))
3037  return -1;
3038  }
3039 
3040  if (PKT_IS_TOSERVER(p)) {
3041  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3042  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3043  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3044  int retransmission = 0;
3045 
3046  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3047  SCLogDebug("ssn %p: packet is retransmission", ssn);
3048  retransmission = 1;
3049  }
3050 
3051  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3052  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3054  return -1;
3055  }
3056 
3057  if (!retransmission) {
3058  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
3060  {
3061  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
3062  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
3063 
3064  if (TCP_GET_SEQ(p) == ssn->client.next_seq) {
3065  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3066  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3067  }
3068  } else {
3069  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3070  " != %" PRIu32 " from stream", ssn,
3071  TCP_GET_SEQ(p), ssn->client.next_seq);
3072 
3074  return -1;
3075  }
3076 
3077  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3078  }
3079 
3080  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3081 
3082  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3083  StreamTcpHandleTimestamp(ssn, p);
3084  }
3085 
3086  /* Update the next_seq, in case if we have missed the client
3087  packet and server has already received and acked it */
3088  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3089  ssn->server.next_seq = TCP_GET_ACK(p);
3090 
3091  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3092  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3093  }
3094 
3096 
3097  /* update next_win */
3098  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3099 
3101  &ssn->client, p, pq);
3102 
3103  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3104  "%" PRIu32 "", ssn, ssn->client.next_seq,
3105  ssn->server.last_ack);
3106 
3107  } else { /* implied to client */
3108 
3109  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3110  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3111  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3112 
3113  int retransmission = 0;
3114 
3115  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3116  SCLogDebug("ssn %p: packet is retransmission", ssn);
3117  retransmission = 1;
3118  }
3119 
3120  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3121  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3123  return -1;
3124  }
3125 
3126  if (!retransmission) {
3127  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
3129  {
3130  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
3131  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
3132 
3133  if (TCP_GET_SEQ(p) == ssn->server.next_seq) {
3134  StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3135  SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3136  }
3137  } else {
3138  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3139  " != %" PRIu32 " from stream", ssn,
3140  TCP_GET_SEQ(p), ssn->server.next_seq);
3142  return -1;
3143  }
3144 
3145  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3146  }
3147 
3148  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3149 
3150  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3151  StreamTcpHandleTimestamp(ssn, p);
3152  }
3153 
3154  /* Update the next_seq, in case if we have missed the client
3155  packet and server has already received and acked it */
3156  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3157  ssn->client.next_seq = TCP_GET_ACK(p);
3158 
3159  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3160  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3161  }
3162 
3164 
3165  /* update next_win */
3166  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3167 
3169  &ssn->server, p, pq);
3170 
3171  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3172  "%" PRIu32 "", ssn, ssn->server.next_seq,
3173  ssn->client.last_ack);
3174  }
3175  } else {
3176  SCLogDebug("ssn (%p): default case", ssn);
3177  }
3178 
3179  return 0;
3180 }
3181 
3182 /**
3183  * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
3184  * ACK, RST, FIN packets and correspondingly changes the connection
3185  * state.
3186  *
3187  * \param tv Thread Variable containig input/output queue, cpu affinity
3188  * \param p Packet which has to be handled in this TCP state.
3189  * \param stt Strean Thread module registered to handle the stream handling
3190  */
3191 
3192 static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p,
3193  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
3194 {
3195  if (ssn == NULL)
3196  return -1;
3197 
3198  if (p->tcph->th_flags & TH_RST) {
3199  if (!StreamTcpValidateRst(ssn, p))
3200  return -1;
3201 
3202  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
3203  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
3204  ssn);
3205 
3206  if (PKT_IS_TOSERVER(p)) {
3207  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3208  StreamTcpUpdateLastAck(ssn, &ssn->server,
3209  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3210 
3211  StreamTcpUpdateLastAck(ssn, &ssn->client,
3212  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3213 
3214  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3215  StreamTcpHandleTimestamp(ssn, p);
3216  }
3217 
3219  &ssn->client, p, pq);
3220  } else {
3221  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3222  StreamTcpUpdateLastAck(ssn, &ssn->client,
3223  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3224 
3225  StreamTcpUpdateLastAck(ssn, &ssn->server,
3226  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3227 
3228  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3229  StreamTcpHandleTimestamp(ssn, p);
3230  }
3231 
3233  &ssn->server, p, pq);
3234  }
3235 
3236  } else if (p->tcph->th_flags & TH_FIN) {
3237  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3238  if (!StreamTcpValidateTimestamp(ssn, p))
3239  return -1;
3240  }
3241 
3242  if (PKT_IS_TOSERVER(p)) {
3243  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3244  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3245  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3246  int retransmission = 0;
3247 
3248  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq - 1) &&
3249  SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) {
3250  SCLogDebug("ssn %p: retransmission", ssn);
3251  retransmission = 1;
3252  } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3253  SCLogDebug("ssn %p: packet is retransmission", ssn);
3254  retransmission = 1;
3255 
3256  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
3257  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3258  {
3259  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
3260  "%" PRIu32 " != %" PRIu32 " from stream", ssn,
3261  TCP_GET_SEQ(p), ssn->client.next_seq);
3263  return -1;
3264  }
3265 
3266  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3267  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3269  return -1;
3270  }
3271 
3272  if (!retransmission) {
3273  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3274  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3275 
3276  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3277  }
3278 
3279  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3280 
3281  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3282  StreamTcpHandleTimestamp(ssn, p);
3283  }
3284 
3285  /* Update the next_seq, in case if we have missed the client
3286  packet and server has already received and acked it */
3287  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3288  ssn->server.next_seq = TCP_GET_ACK(p);
3289 
3291  &ssn->client, p, pq);
3292 
3293  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3294  "%" PRIu32 "", ssn, ssn->client.next_seq,
3295  ssn->server.last_ack);
3296  } else { /* implied to client */
3297  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3298  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3299  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3300  int retransmission = 0;
3301 
3302  if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq - 1) &&
3303  SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) {
3304  SCLogDebug("ssn %p: retransmission", ssn);
3305  retransmission = 1;
3306  } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3307  SCLogDebug("ssn %p: packet is retransmission", ssn);
3308  retransmission = 1;
3309 
3310  } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
3311  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3312  {
3313  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
3314  "%" PRIu32 " != %" PRIu32 " from stream", ssn,
3315  TCP_GET_SEQ(p), ssn->server.next_seq);
3317  return -1;
3318  }
3319 
3320  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3321  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3323  return -1;
3324  }
3325 
3326  if (!retransmission) {
3327  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3328  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3329 
3330  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3331  }
3332 
3333  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3334 
3335  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3336  StreamTcpHandleTimestamp(ssn, p);
3337  }
3338 
3339  /* Update the next_seq, in case if we have missed the client
3340  packet and server has already received and acked it */
3341  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3342  ssn->client.next_seq = TCP_GET_ACK(p);
3343 
3345  &ssn->server, p, pq);
3346  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3347  "%" PRIu32 "", ssn, ssn->server.next_seq,
3348  ssn->client.last_ack);
3349  }
3350 
3351  } else if (p->tcph->th_flags & TH_SYN) {
3352  SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
3354  return -1;
3355 
3356  } else if (p->tcph->th_flags & TH_ACK) {
3357  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3358  if (!StreamTcpValidateTimestamp(ssn, p))
3359  return -1;
3360  }
3361 
3362  if (PKT_IS_TOSERVER(p)) {
3363  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3364  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3365  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3366  int retransmission = 0;
3367 
3368  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3369  SCLogDebug("ssn %p: packet is retransmission", ssn);
3370  retransmission = 1;
3371  }
3372 
3373  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3374  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3376  return -1;
3377  }
3378 
3379  if (!retransmission) {
3380  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
3382  {
3383  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
3384  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
3385 
3386  } else {
3387  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3388  " != %" PRIu32 " from stream", ssn,
3389  TCP_GET_SEQ(p), ssn->client.next_seq);
3391  return -1;
3392  }
3393 
3394  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3395  }
3396 
3397  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3398 
3399  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3400  StreamTcpHandleTimestamp(ssn, p);
3401  }
3402 
3403  if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3404  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3405  }
3406 
3408 
3409  /* update next_win */
3410  StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3411 
3413  &ssn->client, p, pq);
3414 
3415  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3416  "%" PRIu32 "", ssn, ssn->client.next_seq,
3417  ssn->server.last_ack);
3418  } else { /* implied to client */
3419  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3420  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3421  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3422  int retransmission = 0;
3423 
3424  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3425  SCLogDebug("ssn %p: packet is retransmission", ssn);
3426  retransmission = 1;
3427  }
3428 
3429  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3430  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3432  return -1;
3433  }
3434 
3435  if (!retransmission) {
3436  if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
3438  {
3439  SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
3440  "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
3441  } else {
3442  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3443  " != %" PRIu32 " from stream", ssn,
3444  TCP_GET_SEQ(p), ssn->server.next_seq);
3446  return -1;
3447  }
3448 
3449  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3450  }
3451 
3452  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3453 
3454  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3455  StreamTcpHandleTimestamp(ssn, p);
3456  }
3457 
3458  if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3459  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3460  }
3461 
3463 
3464  /* update next_win */
3465  StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3466 
3468  &ssn->server, p, pq);
3469 
3470  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3471  "%" PRIu32 "", ssn, ssn->server.next_seq,
3472  ssn->client.last_ack);
3473  }
3474  } else {
3475  SCLogDebug("ssn %p: default case", ssn);
3476  }
3477 
3478  return 0;
3479 }
3480 
3481 /**
3482  * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
3483  * the connection goes to TCP_TIME_WAIT state. The state has been
3484  * reached as both end application has been closed.
3485  *
3486  * \param tv Thread Variable containig input/output queue, cpu affinity
3487  * \param p Packet which has to be handled in this TCP state.
3488  * \param stt Strean Thread module registered to handle the stream handling
3489  */
3490 
3491 static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p,
3492  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
3493 {
3494  if (ssn == NULL)
3495  return -1;
3496 
3497  if (p->tcph->th_flags & TH_RST) {
3498  if (!StreamTcpValidateRst(ssn, p))
3499  return -1;
3500 
3501  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
3502  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
3503  ssn);
3504 
3505  if (PKT_IS_TOSERVER(p)) {
3506  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3507  StreamTcpUpdateLastAck(ssn, &ssn->server,
3508  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3509 
3510  StreamTcpUpdateLastAck(ssn, &ssn->client,
3511  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3512 
3513  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3514  StreamTcpHandleTimestamp(ssn, p);
3515  }
3516 
3518  &ssn->client, p, pq);
3519  } else {
3520  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3521  StreamTcpUpdateLastAck(ssn, &ssn->client,
3522  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3523 
3524  StreamTcpUpdateLastAck(ssn, &ssn->server,
3525  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3526 
3527  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3528  StreamTcpHandleTimestamp(ssn, p);
3529  }
3530 
3532  &ssn->server, p, pq);
3533  }
3534 
3535  } else if (p->tcph->th_flags & TH_SYN) {
3536  SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
3538  return -1;
3539 
3540  } else if (p->tcph->th_flags & TH_ACK) {
3541  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3542  if (!StreamTcpValidateTimestamp(ssn, p))
3543  return -1;
3544  }
3545 
3546  if (PKT_IS_TOSERVER(p)) {
3547  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3548  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3549  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3550  int retransmission = 0;
3551  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3552  SCLogDebug("ssn %p: packet is retransmission", ssn);
3553  retransmission = 1;
3554  }
3555 
3556  if (TCP_GET_SEQ(p) != ssn->client.next_seq) {
3557  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3558  " != %" PRIu32 " from stream", ssn,
3559  TCP_GET_SEQ(p), ssn->client.next_seq);
3561  return -1;
3562  }
3563 
3564  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3565  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3567  return -1;
3568  }
3569 
3570  if (!retransmission) {
3571  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3572  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3573 
3574  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3575  }
3576 
3577  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3578 
3579  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3580  StreamTcpHandleTimestamp(ssn, p);
3581  }
3582  /* Update the next_seq, in case if we have missed the client
3583  packet and server has already received and acked it */
3584  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3585  ssn->server.next_seq = TCP_GET_ACK(p);
3586 
3588  &ssn->client, p, pq);
3589  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3590  "%" PRIu32 "", ssn, ssn->client.next_seq,
3591  ssn->server.last_ack);
3592  } else { /* implied to client */
3593  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3594  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3595  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3596  int retransmission = 0;
3597  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3598  SCLogDebug("ssn %p: packet is retransmission", ssn);
3599  retransmission = 1;
3600  }
3601 
3602  if (TCP_GET_SEQ(p) != ssn->server.next_seq) {
3603  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3604  " != %" PRIu32 " from stream", ssn,
3605  TCP_GET_SEQ(p), ssn->server.next_seq);
3607  return -1;
3608  }
3609 
3610  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3611  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3613  return -1;
3614  }
3615 
3616  if (!retransmission) {
3617  StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3618  SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3619 
3620  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3621  }
3622 
3623  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3624 
3625  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3626  StreamTcpHandleTimestamp(ssn, p);
3627  }
3628 
3629  /* Update the next_seq, in case if we have missed the client
3630  packet and server has already received and acked it */
3631  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3632  ssn->client.next_seq = TCP_GET_ACK(p);
3633 
3635  &ssn->server, p, pq);
3636  SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
3637  "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
3638  ssn->server.next_seq, ssn->client.last_ack);
3639  }
3640  } else {
3641  SCLogDebug("ssn %p: default case", ssn);
3642  }
3643 
3644  return 0;
3645 }
3646 
3647 /**
3648  * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
3649  * packet from server the connection goes to TCP_LAST_ACK state.
3650  * The state is possible only for server host.
3651  *
3652  * \param tv Thread Variable containig input/output queue, cpu affinity
3653  * \param p Packet which has to be handled in this TCP state.
3654  * \param stt Strean Thread module registered to handle the stream handling
3655  */
3656 
3657 static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p,
3658  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
3659 {
3660  SCEnter();
3661 
3662  if (ssn == NULL) {
3663  SCReturnInt(-1);
3664  }
3665 
3666  if (PKT_IS_TOCLIENT(p)) {
3667  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3668  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3669  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3670  } else {
3671  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3672  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3673  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3674  }
3675 
3676  if (p->tcph->th_flags & TH_RST) {
3677  if (!StreamTcpValidateRst(ssn, p))
3678  return -1;
3679 
3680  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
3681  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
3682  ssn);
3683 
3684  if (PKT_IS_TOSERVER(p)) {
3685  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3686  StreamTcpUpdateLastAck(ssn, &ssn->server,
3687  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3688 
3689  StreamTcpUpdateLastAck(ssn, &ssn->client,
3690  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3691 
3692  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3693  StreamTcpHandleTimestamp(ssn, p);
3694  }
3695 
3697  &ssn->client, p, pq);
3698  } else {
3699  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3700  StreamTcpUpdateLastAck(ssn, &ssn->client,
3701  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3702 
3703  StreamTcpUpdateLastAck(ssn, &ssn->server,
3704  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3705 
3706  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3707  StreamTcpHandleTimestamp(ssn, p);
3708  }
3709 
3711  &ssn->server, p, pq);
3712  }
3713 
3714  } else if (p->tcph->th_flags & TH_FIN) {
3715  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3716  if (!StreamTcpValidateTimestamp(ssn, p))
3717  SCReturnInt(-1);
3718  }
3719 
3720  if (PKT_IS_TOSERVER(p)) {
3721  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3722  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3723  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3724 
3725  int retransmission = 0;
3726  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3727  SCLogDebug("ssn %p: packet is retransmission", ssn);
3728  retransmission = 1;
3729  }
3730 
3731  if (!retransmission) {
3732  if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
3733  SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3734  {
3735  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3736  " != %" PRIu32 " from stream", ssn,
3737  TCP_GET_SEQ(p), ssn->client.next_seq);
3739  SCReturnInt(-1);
3740  }
3741  }
3742 
3743  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3744  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3746  SCReturnInt(-1);
3747  }
3748 
3749  /* don't update to LAST_ACK here as we want a toclient FIN for that */
3750 
3751  if (!retransmission)
3752  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3753 
3754  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3755 
3756  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3757  StreamTcpHandleTimestamp(ssn, p);
3758  }
3759 
3760  /* Update the next_seq, in case if we have missed the client
3761  packet and server has already received and acked it */
3762  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3763  ssn->server.next_seq = TCP_GET_ACK(p);
3764 
3766  &ssn->client, p, pq);
3767  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3768  "%" PRIu32 "", ssn, ssn->client.next_seq,
3769  ssn->server.last_ack);
3770  } else {
3771  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3772  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3773  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3774 
3775  int retransmission = 0;
3776  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3777  SCLogDebug("ssn %p: packet is retransmission", ssn);
3778  retransmission = 1;
3779  }
3780 
3781  if (!retransmission) {
3782  if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
3783  SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3784  {
3785  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3786  " != %" PRIu32 " from stream", ssn,
3787  TCP_GET_SEQ(p), ssn->server.next_seq);
3789  SCReturnInt(-1);
3790  }
3791  }
3792 
3793  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3794  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3796  SCReturnInt(-1);
3797  }
3798 
3799  if (!retransmission) {
3800  StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
3801  SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
3802 
3803  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3804  }
3805 
3806  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3807 
3808  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3809  StreamTcpHandleTimestamp(ssn, p);
3810  }
3811 
3812  /* Update the next_seq, in case if we have missed the client
3813  packet and server has already received and acked it */
3814  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3815  ssn->client.next_seq = TCP_GET_ACK(p);
3816 
3818  &ssn->server, p, pq);
3819  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3820  "%" PRIu32 "", ssn, ssn->server.next_seq,
3821  ssn->client.last_ack);
3822  }
3823 
3824  } else if (p->tcph->th_flags & TH_SYN) {
3825  SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
3827  SCReturnInt(-1);
3828 
3829  } else if (p->tcph->th_flags & TH_ACK) {
3830  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3831  if (!StreamTcpValidateTimestamp(ssn, p))
3832  SCReturnInt(-1);
3833  }
3834 
3835  if (PKT_IS_TOSERVER(p)) {
3836  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3837  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3838  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3839 
3840  int retransmission = 0;
3841  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3842  SCLogDebug("ssn %p: packet is retransmission", ssn);
3843  retransmission = 1;
3844  }
3845 
3846  if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) {
3847  SCLogDebug("ssn %p: -> retransmission", ssn);
3849  SCReturnInt(-1);
3850 
3851  } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3852  {
3853  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3854  " != %" PRIu32 " from stream", ssn,
3855  TCP_GET_SEQ(p), ssn->client.next_seq);
3857  SCReturnInt(-1);
3858  }
3859 
3860  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3861  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3863  SCReturnInt(-1);
3864  }
3865 
3866  if (!retransmission) {
3867  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3868  }
3869 
3870  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3871 
3872  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3873  StreamTcpHandleTimestamp(ssn, p);
3874  }
3875 
3876  /* Update the next_seq, in case if we have missed the client
3877  packet and server has already received and acked it */
3878  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3879  ssn->server.next_seq = TCP_GET_ACK(p);
3880 
3881  if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq))
3882  StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3883 
3885  &ssn->client, p, pq);
3886  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3887  "%" PRIu32 "", ssn, ssn->client.next_seq,
3888  ssn->server.last_ack);
3889  } else {
3890  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3891  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3892  TCP_GET_SEQ(p), TCP_GET_ACK(p));
3893  int retransmission = 0;
3894  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3895  SCLogDebug("ssn %p: packet is retransmission", ssn);
3896  retransmission = 1;
3897  }
3898 
3899  if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) {
3900  SCLogDebug("ssn %p: -> retransmission", ssn);
3902  SCReturnInt(-1);
3903 
3904  } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3905  {
3906  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3907  " != %" PRIu32 " from stream", ssn,
3908  TCP_GET_SEQ(p), ssn->server.next_seq);
3910  SCReturnInt(-1);
3911  }
3912 
3913  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3914  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3916  SCReturnInt(-1);
3917  }
3918 
3919  if (!retransmission) {
3920  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3921  }
3922 
3923  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3924 
3925  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3926  StreamTcpHandleTimestamp(ssn, p);
3927  }
3928 
3929  /* Update the next_seq, in case if we have missed the client
3930  packet and server has already received and acked it */
3931  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3932  ssn->client.next_seq = TCP_GET_ACK(p);
3933 
3934  if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq))
3935  StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3936 
3938  &ssn->server, p, pq);
3939  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3940  "%" PRIu32 "", ssn, ssn->server.next_seq,
3941  ssn->client.last_ack);
3942  }
3943 
3944  } else {
3945  SCLogDebug("ssn %p: default case", ssn);
3946  }
3947  SCReturnInt(0);
3948 }
3949 
3950 /**
3951  * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
3952  * the connection goes to TCP_CLOSED state and stream memory is
3953  * returned back to pool. The state is possible only for server host.
3954  *
3955  * \param tv Thread Variable containig input/output queue, cpu affinity
3956  * \param p Packet which has to be handled in this TCP state.
3957  * \param stt Strean Thread module registered to handle the stream handling
3958  */
3959 
3960 static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p,
3961  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
3962 {
3963  if (ssn == NULL)
3964  return -1;
3965 
3966  if (p->tcph->th_flags & TH_RST) {
3967  if (!StreamTcpValidateRst(ssn, p))
3968  return -1;
3969 
3970  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
3971  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
3972  ssn);
3973 
3974  if (PKT_IS_TOSERVER(p)) {
3975  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3976  StreamTcpUpdateLastAck(ssn, &ssn->server,
3977  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3978 
3979  StreamTcpUpdateLastAck(ssn, &ssn->client,
3980  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3981 
3982  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3983  StreamTcpHandleTimestamp(ssn, p);
3984  }
3985 
3987  &ssn->client, p, pq);
3988  } else {
3989  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3990  StreamTcpUpdateLastAck(ssn, &ssn->client,
3991  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3992 
3993  StreamTcpUpdateLastAck(ssn, &ssn->server,
3994  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3995 
3996  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3997  StreamTcpHandleTimestamp(ssn, p);
3998  }
3999 
4001  &ssn->server, p, pq);
4002  }
4003 
4004  } else if (p->tcph->th_flags & TH_FIN) {
4005  /** \todo */
4006  SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
4007 
4008  } else if (p->tcph->th_flags & TH_SYN) {
4009  SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
4011  return -1;
4012 
4013  } else if (p->tcph->th_flags & TH_ACK) {
4014  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4015  if (!StreamTcpValidateTimestamp(ssn, p))
4016  return -1;
4017  }
4018 
4019  if (PKT_IS_TOSERVER(p)) {
4020  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4021  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4022  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4023 
4024  int retransmission = 0;
4025  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4026  SCLogDebug("ssn %p: packet is retransmission", ssn);
4027  retransmission = 1;
4028  }
4029 
4030  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4031  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4033  SCReturnInt(-1);
4034  }
4035 
4036  if (!retransmission) {
4037  if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq)) {
4038  SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
4039  } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq + 1) {
4040  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4041  " != %" PRIu32 " from stream", ssn,
4042  TCP_GET_SEQ(p), ssn->client.next_seq);
4044  return -1;
4045  } else {
4046  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4047  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4048 
4049  }
4050  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
4051  }
4052 
4053  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4054 
4055  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4056  StreamTcpHandleTimestamp(ssn, p);
4057  }
4058 
4059  /* Update the next_seq, in case if we have missed the client
4060  packet and server has already received and acked it */
4061  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
4062  ssn->server.next_seq = TCP_GET_ACK(p);
4063 
4065  &ssn->client, p, pq);
4066  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4067  "%" PRIu32 "", ssn, ssn->client.next_seq,
4068  ssn->server.last_ack);
4069  }
4070  } else {
4071  SCLogDebug("ssn %p: default case", ssn);
4072  }
4073 
4074  return 0;
4075 }
4076 
4077 /**
4078  * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
4079  * the connection goes to TCP_CLOSED state and stream memory is
4080  * returned back to pool.
4081  *
4082  * \param tv Thread Variable containig input/output queue, cpu affinity
4083  * \param p Packet which has to be handled in this TCP state.
4084  * \param stt Strean Thread module registered to handle the stream handling
4085  */
4086 
4087 static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p,
4088  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
4089 {
4090  if (ssn == NULL)
4091  return -1;
4092 
4093  if (p->tcph->th_flags & TH_RST) {
4094  if (!StreamTcpValidateRst(ssn, p))
4095  return -1;
4096 
4097  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4098  SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
4099  ssn);
4100 
4101  if (PKT_IS_TOSERVER(p)) {
4102  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4103  StreamTcpUpdateLastAck(ssn, &ssn->server,
4104  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
4105 
4106  StreamTcpUpdateLastAck(ssn, &ssn->client,
4107  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
4108 
4109  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4110  StreamTcpHandleTimestamp(ssn, p);
4111  }
4112 
4114  &ssn->client, p, pq);
4115  } else {
4116  if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4117  StreamTcpUpdateLastAck(ssn, &ssn->client,
4118  StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
4119 
4120  StreamTcpUpdateLastAck(ssn, &ssn->server,
4121  StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
4122 
4123  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4124  StreamTcpHandleTimestamp(ssn, p);
4125  }
4126 
4128  &ssn->server, p, pq);
4129  }
4130 
4131  } else if (p->tcph->th_flags & TH_FIN) {
4132  /** \todo */
4133 
4134  } else if (p->tcph->th_flags & TH_SYN) {
4135  SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
4137  return -1;
4138 
4139  } else if (p->tcph->th_flags & TH_ACK) {
4140  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4141  if (!StreamTcpValidateTimestamp(ssn, p))
4142  return -1;
4143  }
4144 
4145  if (PKT_IS_TOSERVER(p)) {
4146  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4147  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4148  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4149  int retransmission = 0;
4150  if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4151  SCLogDebug("ssn %p: packet is retransmission", ssn);
4152  retransmission = 1;
4153 
4154  } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq+1) {
4155  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4156  " != %" PRIu32 " from stream", ssn,
4157  TCP_GET_SEQ(p), ssn->client.next_seq);
4159  return -1;
4160  }
4161 
4162  if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4163  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4165  SCReturnInt(-1);
4166  }
4167 
4168  if (!retransmission) {
4169  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4170  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4171 
4172  ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
4173  }
4174 
4175  StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4176 
4177  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4178  StreamTcpHandleTimestamp(ssn, p);
4179  }
4180 
4181  /* Update the next_seq, in case if we have missed the client
4182  packet and server has already received and acked it */
4183  if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
4184  ssn->server.next_seq = TCP_GET_ACK(p);
4185 
4187  &ssn->client, p, pq);
4188  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4189  "%" PRIu32 "", ssn, ssn->client.next_seq,
4190  ssn->server.last_ack);
4191  } else {
4192  SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4193  "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4194  TCP_GET_SEQ(p), TCP_GET_ACK(p));
4195  int retransmission = 0;
4196  if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4197  SCLogDebug("ssn %p: packet is retransmission", ssn);
4198  retransmission = 1;
4199  } else if (TCP_GET_SEQ(p) != ssn->server.next_seq && TCP_GET_SEQ(p) != ssn->server.next_seq+1) {
4200  if (p->payload_len > 0 && TCP_GET_SEQ(p) == ssn->server.last_ack) {
4201  SCLogDebug("ssn %p: -> retransmission", ssn);
4202  SCReturnInt(0);
4203  } else {
4204  SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4205  " != %" PRIu32 " from stream", ssn,
4206  TCP_GET_SEQ(p), ssn->server.next_seq);
4208  return -1;
4209  }
4210  }
4211 
4212  if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4213  SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4215  SCReturnInt(-1);
4216  }
4217 
4218  if (!retransmission) {
4219  StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4220  SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4221 
4222  ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
4223  }
4224 
4225  StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
4226 
4227  if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4228  StreamTcpHandleTimestamp(ssn, p);
4229  }
4230 
4231  /* Update the next_seq, in case if we have missed the client
4232  packet and server has already received and acked it */
4233  if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
4234  ssn->client.next_seq = TCP_GET_ACK(p);
4235 
4237  &ssn->server, p, pq);
4238  SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4239  "%" PRIu32 "", ssn, ssn->server.next_seq,
4240  ssn->client.last_ack);
4241  }
4242 
4243  } else {
4244  SCLogDebug("ssn %p: default case", ssn);
4245  }
4246 
4247  return 0;
4248 }
4249 
4250 static int StreamTcpPacketStateClosed(ThreadVars *tv, Packet *p,
4251  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
4252 {
4253  if (ssn == NULL)
4254  return -1;
4255 
4256  if (p->tcph->th_flags & TH_RST) {
4257  SCLogDebug("RST on closed state");
4258  return 0;
4259  }
4260 
4261  TcpStream *stream = NULL, *ostream = NULL;
4262  if (PKT_IS_TOSERVER(p)) {
4263  stream = &ssn->client;
4264  ostream = &ssn->server;
4265  } else {
4266  stream = &ssn->server;
4267  ostream = &ssn->client;
4268  }
4269 
4270  SCLogDebug("stream %s ostream %s",
4271  stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
4272  ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
4273 
4274  /* if we've seen a RST on our direction, but not on the other
4275  * see if we perhaps need to continue processing anyway. */
4276  if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
4277  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
4278  if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->pstate) < 0)
4279  return -1;
4280  }
4281  }
4282  return 0;
4283 }
4284 
4285 static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
4286 {
4287  if (p->flags & PKT_PSEUDO_STREAM_END) {
4288  return;
4289  }
4290  /* more RSTs are not unusual */
4291  if ((p->tcph->th_flags & (TH_RST)) != 0) {
4292  return;
4293  }
4294 
4295  TcpStream *ostream = NULL;
4296  if (PKT_IS_TOSERVER(p)) {
4297  ostream = &ssn->server;
4298  } else {
4299  ostream = &ssn->client;
4300  }
4301 
4302  if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
4303  SCLogDebug("regular packet %"PRIu64" from same sender as "
4304  "the previous RST. Looks like it injected!", p->pcap_cnt);
4307  return;
4308  }
4309  return;
4310 }
4311 
4312 /**
4313  * \retval 1 packet is a keep alive pkt
4314  * \retval 0 packet is not a keep alive pkt
4315  */
4316 static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
4317 {
4318  TcpStream *stream = NULL, *ostream = NULL;
4319  uint32_t seq;
4320  uint32_t ack;
4321 
4322  if (p->flags & PKT_PSEUDO_STREAM_END)
4323  return 0;
4324 
4325  /*
4326  rfc 1122:
4327  An implementation SHOULD send a keep-alive segment with no
4328  data; however, it MAY be configurable to send a keep-alive
4329  segment containing one garbage octet, for compatibility with
4330  erroneous TCP implementations.
4331  */
4332  if (p->payload_len > 1)
4333  return 0;
4334 
4335  if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) {
4336  return 0;
4337  }
4338 
4339  if (PKT_IS_TOSERVER(p)) {
4340  stream = &ssn->client;
4341  ostream = &ssn->server;
4342  } else {
4343  stream = &ssn->server;
4344  ostream = &ssn->client;
4345  }
4346 
4347  seq = TCP_GET_SEQ(p);
4348  ack = TCP_GET_ACK(p);
4349 
4350  if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
4351  SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
4353  return 1;
4354  }
4355  SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
4356  return 0;
4357 }
4358 
4359 /**
4360  * \retval 1 packet is a keep alive ACK pkt
4361  * \retval 0 packet is not a keep alive ACK pkt
4362  */
4363 static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
4364 {
4365  TcpStream *stream = NULL, *ostream = NULL;
4366  uint32_t seq;
4367  uint32_t ack;
4368  uint32_t pkt_win;
4369 
4370  if (p->flags & PKT_PSEUDO_STREAM_END)
4371  return 0;
4372  /* should get a normal ACK to a Keep Alive */
4373  if (p->payload_len > 0)
4374  return 0;
4375 
4376  if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4377  return 0;
4378 
4379  if (TCP_GET_WINDOW(p) == 0)
4380  return 0;
4381 
4382  if (PKT_IS_TOSERVER(p)) {
4383  stream = &ssn->client;
4384  ostream = &ssn->server;
4385  } else {
4386  stream = &ssn->server;
4387  ostream = &ssn->client;
4388  }
4389 
4390  seq = TCP_GET_SEQ(p);
4391  ack = TCP_GET_ACK(p);
4392 
4393  pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4394  if (pkt_win != ostream->window)
4395  return 0;
4396 
4397  if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
4398  SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
4399  ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
4400  return 1;
4401  }
4402  SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
4403  ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
4404  return 0;
4405 }
4406 
4407 static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
4408 {
4409  TcpStream *stream = NULL;
4410 
4411  if (p->flags & PKT_PSEUDO_STREAM_END)
4412  return;
4413 
4414  if (PKT_IS_TOSERVER(p)) {
4415  stream = &ssn->client;
4416  } else {
4417  stream = &ssn->server;
4418  }
4419 
4420  if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
4422  SCLogDebug("FLAG_KEEPALIVE cleared");
4423  }
4424 }
4425 
4426 /**
4427  * \retval 1 packet is a window update pkt
4428  * \retval 0 packet is not a window update pkt
4429  */
4430 static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
4431 {
4432  TcpStream *stream = NULL, *ostream = NULL;
4433  uint32_t seq;
4434  uint32_t ack;
4435  uint32_t pkt_win;
4436 
4437  if (p->flags & PKT_PSEUDO_STREAM_END)
4438  return 0;
4439 
4440  if (ssn->state < TCP_ESTABLISHED)
4441  return 0;
4442 
4443  if (p->payload_len > 0)
4444  return 0;
4445 
4446  if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4447  return 0;
4448 
4449  if (TCP_GET_WINDOW(p) == 0)
4450  return 0;
4451 
4452  if (PKT_IS_TOSERVER(p)) {
4453  stream = &ssn->client;
4454  ostream = &ssn->server;
4455  } else {
4456  stream = &ssn->server;
4457  ostream = &ssn->client;
4458  }
4459 
4460  seq = TCP_GET_SEQ(p);
4461  ack = TCP_GET_ACK(p);
4462 
4463  pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4464  if (pkt_win == ostream->window)
4465  return 0;
4466 
4467  if (ack == ostream->last_ack && seq == stream->next_seq) {
4468  SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
4469  return 1;
4470  }
4471  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
4472  return 0;
4473 }
4474 
4475 /**
4476  * Try to detect whether a packet is a valid FIN 4whs final ack.
4477  *
4478  */
4479 static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
4480 {
4481  TcpStream *stream = NULL, *ostream = NULL;
4482  uint32_t seq;
4483  uint32_t ack;
4484 
4485  if (p->flags & PKT_PSEUDO_STREAM_END)
4486  return 0;
4487  if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
4488  return 0;
4489  if (p->tcph->th_flags != TH_ACK)
4490  return 0;
4491  if (p->payload_len != 0)
4492  return 0;
4493 
4494  if (PKT_IS_TOSERVER(p)) {
4495  stream = &ssn->client;
4496  ostream = &ssn->server;
4497  } else {
4498  stream = &ssn->server;
4499  ostream = &ssn->client;
4500  }
4501 
4502  seq = TCP_GET_SEQ(p);
4503  ack = TCP_GET_ACK(p);
4504 
4505  SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
4506  p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
4507 
4508  if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
4509  return 1;
4510  }
4511  return 0;
4512 }
4513 
4514 /**
4515  * Try to detect packets doing bad window updates
4516  *
4517  * See bug 1238.
4518  *
4519  * Find packets that are unexpected, and shrink the window to the point
4520  * where the packets we do expect are rejected for being out of window.
4521  *
4522  * The logic we use here is:
4523  * - packet seq > next_seq
4524  * - packet ack > next_seq (packet acks unseen data)
4525  * - packet shrinks window more than it's own data size
4526  * - packet shrinks window more than the diff between it's ack and the
4527  * last_ack value
4528  *
4529  * Packets coming in after packet loss can look quite a bit like this.
4530  */
4531 static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
4532 {
4533  TcpStream *stream = NULL, *ostream = NULL;
4534  uint32_t seq;
4535  uint32_t ack;
4536  uint32_t pkt_win;
4537 
4538  if (p->flags & PKT_PSEUDO_STREAM_END)
4539  return 0;
4540 
4541  if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
4542  return 0;
4543 
4544  if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4545  return 0;
4546 
4547  if (PKT_IS_TOSERVER(p)) {
4548  stream = &ssn->client;
4549  ostream = &ssn->server;
4550  } else {
4551  stream = &ssn->server;
4552  ostream = &ssn->client;
4553  }
4554 
4555  seq = TCP_GET_SEQ(p);
4556  ack = TCP_GET_ACK(p);
4557 
4558  pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4559 
4560  if (pkt_win < ostream->window) {
4561  uint32_t diff = ostream->window - pkt_win;
4562  if (diff > p->payload_len &&
4563  SEQ_GT(ack, ostream->next_seq) &&
4564  SEQ_GT(seq, stream->next_seq))
4565  {
4566  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
4567  p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
4568  SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
4569  p->pcap_cnt, pkt_win, ostream->window);
4570  SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
4571  p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
4572  ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
4573 
4574  /* get the expected window shrinking from looking at ack vs last_ack.
4575  * Observed a lot of just a little overrunning that value. So added some
4576  * margin that is still ok. To make sure this isn't a loophole to still
4577  * close the window, this is limited to windows above 1024. Both values
4578  * are rather arbitrary. */
4579  uint32_t adiff = ack - ostream->last_ack;
4580  if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
4581  ((pkt_win <= 1024) && (diff > adiff)))
4582  {
4583  SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
4584  "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
4585  SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
4587  return 1;
4588  }
4589  }
4590 
4591  }
4592  SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
4593  return 0;
4594 }
4595 
4596 /** \internal
4597  * \brief call packet handling function for 'state'
4598  * \param state current TCP state
4599  */
4600 static inline int StreamTcpStateDispatch(ThreadVars *tv, Packet *p,
4601  StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq,
4602  const uint8_t state)
4603 {
4604  SCLogDebug("ssn: %p", ssn);
4605  switch (state) {
4606  case TCP_SYN_SENT:
4607  if (StreamTcpPacketStateSynSent(tv, p, stt, ssn, pq)) {
4608  return -1;
4609  }
4610  break;
4611  case TCP_SYN_RECV:
4612  if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn, pq)) {
4613  return -1;
4614  }
4615  break;
4616  case TCP_ESTABLISHED:
4617  if (StreamTcpPacketStateEstablished(tv, p, stt, ssn, pq)) {
4618  return -1;
4619  }
4620  break;
4621  case TCP_FIN_WAIT1:
4622  SCLogDebug("packet received on TCP_FIN_WAIT1 state");
4623  if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn, pq)) {
4624  return -1;
4625  }
4626  break;
4627  case TCP_FIN_WAIT2:
4628  SCLogDebug("packet received on TCP_FIN_WAIT2 state");
4629  if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn, pq)) {
4630  return -1;
4631  }
4632  break;
4633  case TCP_CLOSING:
4634  SCLogDebug("packet received on TCP_CLOSING state");
4635  if (StreamTcpPacketStateClosing(tv, p, stt, ssn, pq)) {
4636  return -1;
4637  }
4638  break;
4639  case TCP_CLOSE_WAIT:
4640  SCLogDebug("packet received on TCP_CLOSE_WAIT state");
4641  if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn, pq)) {
4642  return -1;
4643  }
4644  break;
4645  case TCP_LAST_ACK:
4646  SCLogDebug("packet received on TCP_LAST_ACK state");
4647  if (StreamTcpPacketStateLastAck(tv, p, stt, ssn, pq)) {
4648  return -1;
4649  }
4650  break;
4651  case TCP_TIME_WAIT:
4652  SCLogDebug("packet received on TCP_TIME_WAIT state");
4653  if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn, pq)) {
4654  return -1;
4655  }
4656  break;
4657  case TCP_CLOSED:
4658  /* TCP session memory is not returned to pool until timeout. */
4659  SCLogDebug("packet received on closed state");
4660 
4661  if (StreamTcpPacketStateClosed(tv, p, stt, ssn, pq)) {
4662  return -1;
4663  }
4664 
4665  break;
4666  default:
4667  SCLogDebug("packet received on default state");
4668  break;
4669  }
4670  return 0;
4671 }
4672 
4673 /* flow is and stays locked */
4675  PacketQueue *pq)
4676 {
4677  SCEnter();
4678 
4680 
4681  SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
4682 
4683  /* assign the thread id to the flow */
4684  if (unlikely(p->flow->thread_id == 0)) {
4685  p->flow->thread_id = (FlowThreadId)tv->id;
4686  } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id)) {
4687  SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id, tv->id);
4688  if (p->pkt_src == PKT_SRC_WIRE) {
4690  if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
4691  p->flow->flags |= FLOW_WRONG_THREAD;
4693  }
4694  }
4695  }
4696 
4697  TcpSession *ssn = (TcpSession *)p->flow->protoctx;
4698 
4699  /* track TCP flags */
4700  if (ssn != NULL) {
4701  ssn->tcp_packet_flags |= p->tcph->th_flags;
4702  if (PKT_IS_TOSERVER(p))
4703  ssn->client.tcp_flags |= p->tcph->th_flags;
4704  else if (PKT_IS_TOCLIENT(p))