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