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