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