suricata
stream-tcp.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2025 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-private.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"
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"
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_SYN_QUEUED 10
91#define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED 5
92
93/* Settings order as in the enum */
94// clang-format off
97 /* EXCEPTION_POLICY_NOT_SET */ false,
98 /* EXCEPTION_POLICY_AUTO */ false,
99 /* EXCEPTION_POLICY_PASS_PACKET */ true,
100 /* EXCEPTION_POLICY_PASS_FLOW */ true,
101 /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
102 /* EXCEPTION_POLICY_DROP_PACKET */ false,
103 /* EXCEPTION_POLICY_DROP_FLOW */ false,
104 /* EXCEPTION_POLICY_REJECT */ true,
105 },
106 .valid_settings_ips = {
107 /* EXCEPTION_POLICY_NOT_SET */ false,
108 /* EXCEPTION_POLICY_AUTO */ false,
109 /* EXCEPTION_POLICY_PASS_PACKET */ true,
110 /* EXCEPTION_POLICY_PASS_FLOW */ true,
111 /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
112 /* EXCEPTION_POLICY_DROP_PACKET */ true,
113 /* EXCEPTION_POLICY_DROP_FLOW */ true,
114 /* EXCEPTION_POLICY_REJECT */ true,
115 },
116};
117// clang-format on
118
119/* Settings order as in the enum */
120// clang-format off
123 /* EXCEPTION_POLICY_NOT_SET */ false,
124 /* EXCEPTION_POLICY_AUTO */ false,
125 /* EXCEPTION_POLICY_PASS_PACKET */ true,
126 /* EXCEPTION_POLICY_PASS_FLOW */ true,
127 /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
128 /* EXCEPTION_POLICY_DROP_PACKET */ false,
129 /* EXCEPTION_POLICY_DROP_FLOW */ false,
130 /* EXCEPTION_POLICY_REJECT */ true,
131 },
132 .valid_settings_ips = {
133 /* EXCEPTION_POLICY_NOT_SET */ false,
134 /* EXCEPTION_POLICY_AUTO */ false,
135 /* EXCEPTION_POLICY_PASS_PACKET */ true,
136 /* EXCEPTION_POLICY_PASS_FLOW */ true,
137 /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
138 /* EXCEPTION_POLICY_DROP_PACKET */ true,
139 /* EXCEPTION_POLICY_DROP_FLOW */ true,
140 /* EXCEPTION_POLICY_REJECT */ true,
141 },
142};
143// clang-format on
144
145/* Settings order as in the enum */
146// clang-format off
149 /* EXCEPTION_POLICY_NOT_SET */ false,
150 /* EXCEPTION_POLICY_AUTO */ false,
151 /* EXCEPTION_POLICY_PASS_PACKET */ false,
152 /* EXCEPTION_POLICY_PASS_FLOW */ true,
153 /* EXCEPTION_POLICY_BYPASS_FLOW */ false,
154 /* EXCEPTION_POLICY_DROP_PACKET */ false,
155 /* EXCEPTION_POLICY_DROP_FLOW */ false,
156 /* EXCEPTION_POLICY_REJECT */ false,
157 },
158 .valid_settings_ips = {
159 /* EXCEPTION_POLICY_NOT_SET */ false,
160 /* EXCEPTION_POLICY_AUTO */ false,
161 /* EXCEPTION_POLICY_PASS_PACKET */ false,
162 /* EXCEPTION_POLICY_PASS_FLOW */ true,
163 /* EXCEPTION_POLICY_BYPASS_FLOW */ false,
164 /* EXCEPTION_POLICY_DROP_PACKET */ false,
165 /* EXCEPTION_POLICY_DROP_FLOW */ false,
166 /* EXCEPTION_POLICY_REJECT */ false,
167 },
168};
169// clang-format on
170
171/* Settings order as in the enum */
172// clang-format off
175 /* EXCEPTION_POLICY_NOT_SET */ false,
176 /* EXCEPTION_POLICY_AUTO */ false,
177 /* EXCEPTION_POLICY_PASS_PACKET */ false,
178 /* EXCEPTION_POLICY_PASS_FLOW */ true,
179 /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
180 /* EXCEPTION_POLICY_DROP_PACKET */ false,
181 /* EXCEPTION_POLICY_DROP_FLOW */ false,
182 /* EXCEPTION_POLICY_REJECT */ true,
183 },
184 .valid_settings_ips = {
185 /* EXCEPTION_POLICY_NOT_SET */ false,
186 /* EXCEPTION_POLICY_AUTO */ false,
187 /* EXCEPTION_POLICY_PASS_PACKET */ false,
188 /* EXCEPTION_POLICY_PASS_FLOW */ true,
189 /* EXCEPTION_POLICY_BYPASS_FLOW */ true,
190 /* EXCEPTION_POLICY_DROP_PACKET */ false,
191 /* EXCEPTION_POLICY_DROP_FLOW */ true,
192 /* EXCEPTION_POLICY_REJECT */ true,
193 },
194};
195// clang-format on
196
197static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *);
199void StreamTcpInitConfig(bool);
202
203static int StreamTcpValidateTimestamp(TcpSession * , Packet *);
204static int StreamTcpHandleTimestamp(TcpSession * , Packet *);
205static int StreamTcpValidateRst(TcpSession * , Packet *);
206static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *, Packet *);
207static int StreamTcpStateDispatch(
208 ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state);
209
210extern thread_local uint64_t t_pcapcnt;
211extern int g_detect_disabled;
212
214static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect initializing and growing pool */
215#ifdef DEBUG
216static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */
217#endif
218
221SC_ATOMIC_DECLARE(uint64_t, st_memuse);
222
224{
225 SC_ATOMIC_INIT(st_memuse);
226}
227
228void StreamTcpIncrMemuse(uint64_t size)
229{
230 (void) SC_ATOMIC_ADD(st_memuse, size);
231 SCLogDebug("STREAM %" PRIu64 ", incr %" PRIu64, StreamTcpMemuseCounter(), size);
232}
233
234void StreamTcpDecrMemuse(uint64_t size)
235{
236#if defined(DEBUG_VALIDATION) && defined(UNITTESTS)
237 uint64_t presize = SC_ATOMIC_GET(st_memuse);
238 if (RunmodeIsUnittests()) {
239 BUG_ON(presize > UINT_MAX);
240 }
241#endif
242
243 (void) SC_ATOMIC_SUB(st_memuse, size);
244
245#if defined(DEBUG_VALIDATION) && defined(UNITTESTS)
246 if (RunmodeIsUnittests()) {
247 uint64_t postsize = SC_ATOMIC_GET(st_memuse);
248 BUG_ON(postsize > presize);
249 }
250#endif
251 SCLogDebug("STREAM %" PRIu64 ", decr %" PRIu64, StreamTcpMemuseCounter(), size);
252}
253
255{
256 uint64_t memusecopy = SC_ATOMIC_GET(st_memuse);
257 return memusecopy;
258}
259
260/**
261 * \brief Check if alloc'ing "size" would mean we're over memcap
262 *
263 * \retval 1 if in bounds
264 * \retval 0 if not in bounds
265 */
266int StreamTcpCheckMemcap(uint64_t size)
267{
268 uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.memcap);
269 if (memcapcopy == 0 || size + SC_ATOMIC_GET(st_memuse) <= memcapcopy)
270 return 1;
271 return 0;
272}
273
274/**
275 * \brief Update memcap value
276 *
277 * \param size new memcap value
278 */
279int StreamTcpSetMemcap(uint64_t size)
280{
281 if (size == 0 || (uint64_t)SC_ATOMIC_GET(st_memuse) < size) {
282 SC_ATOMIC_SET(stream_config.memcap, size);
283 return 1;
284 }
285
286 return 0;
287}
288
289/**
290 * \brief Return memcap value
291 *
292 * \param memcap memcap value
293 */
294uint64_t StreamTcpGetMemcap(void)
295{
296 uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.memcap);
297 return memcapcopy;
298}
299
301{
302 if (stream != NULL) {
303 StreamTcpSackFreeList(stream);
306 }
307}
308
309static void StreamTcp3wsFreeQueue(TcpSession *ssn)
310{
311 TcpStateQueue *q, *q_next;
312 q = ssn->queue;
313 while (q != NULL) {
314 q_next = q->next;
315 SCFree(q);
316 q = q_next;
317 StreamTcpDecrMemuse((uint64_t)sizeof(TcpStateQueue));
318 }
319 ssn->queue = NULL;
320 ssn->queue_len = 0;
321}
322
323/**
324 * \brief Session cleanup function. Does not free the ssn.
325 * \param ssn tcp session
326 */
328{
329 SCEnter();
330
331 if (ssn == NULL)
332 return;
333
336 StreamTcp3wsFreeQueue(ssn);
337
338 SCReturn;
339}
340
341/**
342 * \brief Function to return the stream back to the pool. It returns the
343 * segments in the stream to the segment pool.
344 *
345 * This function is called when the flow is destroyed, so it should free
346 * *everything* related to the tcp session. So including the app layer
347 * data.
348 *
349 * \param ssn Void ptr to the ssn.
350 */
351void StreamTcpSessionClear(void *ssnptr)
352{
353 SCEnter();
354 TcpSession *ssn = (TcpSession *)ssnptr;
355 if (ssn == NULL)
356 return;
357
359
360 /* HACK: don't loose track of thread id */
362 memset(ssn, 0, sizeof(TcpSession));
363 ssn->pool_id = pool_id;
364
366#ifdef DEBUG
367 SCMutexLock(&ssn_pool_mutex);
368 ssn_pool_cnt--;
369 SCMutexUnlock(&ssn_pool_mutex);
370#endif
371
372 SCReturn;
373}
374
375/**
376 * \brief Function to return the stream segments back to the pool.
377 *
378 * \param p Packet used to identify the stream.
379 */
381{
382 SCEnter();
383
384 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
385 if (ssn == NULL)
386 SCReturn;
387
390
391 SCReturn;
392}
393
394/** \brief Stream alloc function for the Pool
395 * \retval ptr void ptr to TcpSession structure with all vars set to 0/NULL
396 */
397static void *StreamTcpSessionPoolAlloc(void)
398{
399 void *ptr = NULL;
400
401 if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpSession)) == 0)
402 return NULL;
403
404 ptr = SCMalloc(sizeof(TcpSession));
405 if (unlikely(ptr == NULL))
406 return NULL;
407
408 return ptr;
409}
410
411static int StreamTcpSessionPoolInit(void *data, void* initdata)
412{
413 memset(data, 0, sizeof(TcpSession));
414 StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession));
415
416 return 1;
417}
418
419/** \brief Pool cleanup function
420 * \param s Void ptr to TcpSession memory */
421static void StreamTcpSessionPoolCleanup(void *s)
422{
423 if (s != NULL) {
425 /** \todo not very clean, as the memory is not freed here */
426 StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession));
427 }
428}
429
430/** \internal
431 * \brief See if stream engine is dropping invalid packet in inline mode
432 * \retval false no
433 * \retval true yes
434 */
435static inline bool StreamTcpInlineDropInvalid(void)
436{
439}
440
441/** \internal
442 * \brief See if stream engine is dropping URG packets in inline mode
443 * \retval false no
444 * \retval true yes
445 */
446static inline bool StreamTcpInlineDropUrg(void)
447{
450}
451
452/* hack: stream random range code expects random values in range of 0-RAND_MAX,
453 * but we can get both <0 and >RAND_MAX values from RandomGet
454 */
455static int RandomGetWrap(void)
456{
457 unsigned long r;
458
459 do {
460 r = RandomGet();
461 } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
462
463 return r % RAND_MAX;
464}
465
466static const char *UrgentPolicyToString(enum TcpStreamUrgentHandling pol)
467{
468 switch (pol) {
470 return "oob";
472 return "inline";
474 return "drop";
476 return "gap";
477 }
478 return NULL;
479}
480
481
482/** \brief To initialize the stream global configuration data
483 *
484 * \param quiet It tells the mode of operation, if it is true nothing will
485 * be get printed.
486 */
487
488void StreamTcpInitConfig(bool quiet)
489{
490 intmax_t value = 0;
491 uint16_t rdrange = 10;
492
493 SCLogDebug("Initializing Stream");
494
495 memset(&stream_config, 0, sizeof(stream_config));
496
498 SC_ATOMIC_INIT(stream_config.reassembly_memcap);
499
500 if ((SCConfGetInt("stream.max-sessions", &value)) == 1) {
501 SCLogWarning("max-sessions is obsolete. "
502 "Number of concurrent sessions is now only limited by Flow and "
503 "TCP stream engine memcaps.");
504 }
505
506 if ((SCConfGetInt("stream.prealloc-sessions", &value)) == 1) {
507 stream_config.prealloc_sessions = (uint32_t)value;
508 } else {
509 if (RunmodeIsUnittests()) {
511 } else {
513 if (SCConfGetNode("stream.prealloc-sessions") != NULL) {
514 WarnInvalidConfEntry("stream.prealloc_sessions",
515 "%"PRIu32,
517 }
518 }
519 }
520 if (!quiet) {
521 SCLogConfig("stream \"prealloc-sessions\": %"PRIu32" (per thread)",
523 }
524
525 const char *temp_stream_memcap_str;
526 if (SCConfGet("stream.memcap", &temp_stream_memcap_str) == 1) {
527 uint64_t stream_memcap_copy;
528 if (ParseSizeStringU64(temp_stream_memcap_str, &stream_memcap_copy) < 0) {
529 SCLogError("Error parsing stream.memcap "
530 "from conf file - %s. Killing engine",
531 temp_stream_memcap_str);
532 exit(EXIT_FAILURE);
533 } else {
534 SC_ATOMIC_SET(stream_config.memcap, stream_memcap_copy);
535 }
536 } else {
538 }
539
540 if (!quiet) {
541 SCLogConfig("stream \"memcap\": %"PRIu64, SC_ATOMIC_GET(stream_config.memcap));
542 }
543
544 int imidstream;
545 (void)SCConfGetBool("stream.midstream", &imidstream);
546 stream_config.midstream = imidstream != 0;
547
548 if (!quiet) {
549 SCLogConfig("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled");
550 }
551
552 int async_oneside;
553 (void)SCConfGetBool("stream.async-oneside", &async_oneside);
554 stream_config.async_oneside = async_oneside != 0;
555
556 if (!quiet) {
557 SCLogConfig("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled");
558 }
559
560 int csum = 0;
561
562 if ((SCConfGetBool("stream.checksum-validation", &csum)) == 1) {
563 if (csum == 1) {
565 }
566 /* Default is that we validate the checksum of all the packets */
567 } else {
569 }
570
571 if (!quiet) {
572 SCLogConfig("stream \"checksum-validation\": %s",
574 "enabled" : "disabled");
575 }
576
577 const char *temp_stream_inline_str;
578 if (SCConfGet("stream.inline", &temp_stream_inline_str) == 1) {
579 int inl = 0;
580
581 /* checking for "auto" and falling back to boolean to provide
582 * backward compatibility */
583 if (strcmp(temp_stream_inline_str, "auto") == 0) {
584 if (EngineModeIsIPS()) {
586 }
587 } else if (SCConfGetBool("stream.inline", &inl) == 1) {
588 if (inl) {
590 }
591 }
592 } else {
593 /* default to 'auto' */
594 if (EngineModeIsIPS()) {
596 }
597 }
598 stream_config.ssn_memcap_policy = ExceptionPolicyParse("stream.memcap-policy", true);
600 ExceptionPolicyParse("stream.reassembly.memcap-policy", true);
602
603 if (!quiet) {
604 SCLogConfig("stream.\"inline\": %s",
606 ? "enabled" : "disabled");
607 }
608
609 int bypass = 0;
610 if ((SCConfGetBool("stream.bypass", &bypass)) == 1) {
611 if (bypass == 1) {
613 }
614 }
615
616 if (!quiet) {
617 SCLogConfig("stream \"bypass\": %s",
619 ? "enabled" : "disabled");
620 }
621
622 int drop_invalid = 0;
623 if ((SCConfGetBool("stream.drop-invalid", &drop_invalid)) == 1) {
624 if (drop_invalid == 1) {
626 }
627 } else {
629 }
630
631 const char *temp_urgpol = NULL;
632 if (SCConfGet("stream.reassembly.urgent.policy", &temp_urgpol) == 1 && temp_urgpol != NULL) {
633 if (strcmp(temp_urgpol, "inline") == 0) {
635 } else if (strcmp(temp_urgpol, "drop") == 0) {
637 } else if (strcmp(temp_urgpol, "oob") == 0) {
639 } else if (strcmp(temp_urgpol, "gap") == 0) {
641 } else {
642 FatalError("stream.reassembly.urgent.policy: invalid value '%s'", temp_urgpol);
643 }
644 } else {
646 }
647 if (!quiet) {
648 SCLogConfig("stream.reassembly.urgent.policy\": %s", UrgentPolicyToString(stream_config.urgent_policy));
649 }
651 const char *temp_urgoobpol = NULL;
652 if (SCConfGet("stream.reassembly.urgent.oob-limit-policy", &temp_urgoobpol) == 1 &&
653 temp_urgoobpol != NULL) {
654 if (strcmp(temp_urgoobpol, "inline") == 0) {
656 } else if (strcmp(temp_urgoobpol, "drop") == 0) {
658 } else if (strcmp(temp_urgoobpol, "gap") == 0) {
660 } else {
661 FatalError("stream.reassembly.urgent.oob-limit-policy: invalid value '%s'", temp_urgoobpol);
662 }
663 } else {
665 }
666 if (!quiet) {
667 SCLogConfig("stream.reassembly.urgent.oob-limit-policy\": %s", UrgentPolicyToString(stream_config.urgent_oob_limit_policy));
668 }
669 }
670
671 if ((SCConfGetInt("stream.max-syn-queued", &value)) == 1) {
672 if (value >= 0 && value <= 255) {
673 stream_config.max_syn_queued = (uint8_t)value;
674 } else {
676 }
677 } else {
679 }
680 if (!quiet) {
681 SCLogConfig("stream \"max-syn-queued\": %" PRIu8, stream_config.max_syn_queued);
682 }
683
684 if ((SCConfGetInt("stream.max-synack-queued", &value)) == 1) {
685 if (value >= 0 && value <= 255) {
686 stream_config.max_synack_queued = (uint8_t)value;
687 } else {
689 }
690 } else {
692 }
693 if (!quiet) {
694 SCLogConfig("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued);
695 }
696
697 const char *temp_stream_reassembly_memcap_str;
698 if (SCConfGet("stream.reassembly.memcap", &temp_stream_reassembly_memcap_str) == 1) {
699 uint64_t stream_reassembly_memcap_copy;
700 if (ParseSizeStringU64(temp_stream_reassembly_memcap_str,
701 &stream_reassembly_memcap_copy) < 0) {
702 SCLogError("Error parsing "
703 "stream.reassembly.memcap "
704 "from conf file - %s. Killing engine",
705 temp_stream_reassembly_memcap_str);
706 exit(EXIT_FAILURE);
707 } else {
708 SC_ATOMIC_SET(stream_config.reassembly_memcap, stream_reassembly_memcap_copy);
709 }
710 } else {
712 }
713
714 if (!quiet) {
715 SCLogConfig("stream.reassembly \"memcap\": %"PRIu64"",
716 SC_ATOMIC_GET(stream_config.reassembly_memcap));
717 }
718
719 const char *temp_stream_reassembly_depth_str;
720 if (SCConfGet("stream.reassembly.depth", &temp_stream_reassembly_depth_str) == 1) {
721 if (ParseSizeStringU32(temp_stream_reassembly_depth_str,
723 SCLogError("Error parsing "
724 "stream.reassembly.depth "
725 "from conf file - %s. Killing engine",
726 temp_stream_reassembly_depth_str);
727 exit(EXIT_FAILURE);
728 }
729 } else {
731 }
732
733 if (!quiet) {
734 SCLogConfig("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth);
735 }
736
737 int randomize = 0;
738 if ((SCConfGetBool("stream.reassembly.randomize-chunk-size", &randomize)) == 0) {
739 /* randomize by default if value not set
740 * In ut mode we disable, to get predictable test results */
741 if (!(RunmodeIsUnittests()))
742 randomize = 1;
743 }
744
745 if (randomize) {
746 const char *temp_rdrange;
747 if (SCConfGet("stream.reassembly.randomize-chunk-range", &temp_rdrange) == 1) {
748 if (ParseSizeStringU16(temp_rdrange, &rdrange) < 0) {
749 SCLogError("Error parsing "
750 "stream.reassembly.randomize-chunk-range "
751 "from conf file - %s. Killing engine",
752 temp_rdrange);
753 exit(EXIT_FAILURE);
754 } else if (rdrange >= 100) {
755 FatalError("stream.reassembly.randomize-chunk-range "
756 "must be lower than 100");
757 }
758 }
759 }
760
761 const char *temp_stream_reassembly_toserver_chunk_size_str;
762 if (SCConfGet("stream.reassembly.toserver-chunk-size",
763 &temp_stream_reassembly_toserver_chunk_size_str) == 1) {
764 if (ParseSizeStringU16(temp_stream_reassembly_toserver_chunk_size_str,
766 SCLogError("Error parsing "
767 "stream.reassembly.toserver-chunk-size "
768 "from conf file - %s. Killing engine",
769 temp_stream_reassembly_toserver_chunk_size_str);
770 exit(EXIT_FAILURE);
771 }
772 } else {
775 }
776
777 if (randomize) {
778 long int r = RandomGetWrap();
780 (int)(stream_config.reassembly_toserver_chunk_size * ((double)r / RAND_MAX - 0.5) *
781 rdrange / 100);
782 }
783 const char *temp_stream_reassembly_toclient_chunk_size_str;
784 if (SCConfGet("stream.reassembly.toclient-chunk-size",
785 &temp_stream_reassembly_toclient_chunk_size_str) == 1) {
786 if (ParseSizeStringU16(temp_stream_reassembly_toclient_chunk_size_str,
788 SCLogError("Error parsing "
789 "stream.reassembly.toclient-chunk-size "
790 "from conf file - %s. Killing engine",
791 temp_stream_reassembly_toclient_chunk_size_str);
792 exit(EXIT_FAILURE);
793 }
794 } else {
797 }
798
799 if (randomize) {
800 long int r = RandomGetWrap();
802 (int)(stream_config.reassembly_toclient_chunk_size * ((double)r / RAND_MAX - 0.5) *
803 rdrange / 100);
804 }
805 if (!quiet) {
806 SCLogConfig("stream.reassembly \"toserver-chunk-size\": %"PRIu16,
808 SCLogConfig("stream.reassembly \"toclient-chunk-size\": %"PRIu16,
810 }
811
812 int enable_raw = 1;
813 if (SCConfGetBool("stream.reassembly.raw", &enable_raw) == 1) {
814 if (!enable_raw) {
816 }
817 } else {
818 enable_raw = 1;
819 }
820 if (!quiet)
821 SCLogConfig("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled");
822
823 /* default to true. Not many ppl (correctly) set up host-os policies, so be permissive. */
825 int liberal_timestamps = 0;
826 if (SCConfGetBool("stream.liberal-timestamps", &liberal_timestamps) == 1) {
827 stream_config.liberal_timestamps = liberal_timestamps;
828 }
829 if (!quiet)
830 SCLogConfig("stream.liberal-timestamps: %s", liberal_timestamps ? "enabled" : "disabled");
831
832 /* init the memcap/use tracking */
835
837
838 /* set the default free function and flow state function
839 * values. */
841
842#ifdef UNITTESTS
843 if (RunmodeIsUnittests()) {
844 SCMutexLock(&ssn_pool_mutex);
845 if (ssn_pool == NULL) {
846 ssn_pool = PoolThreadInit(1, /* thread */
847 0, /* unlimited */
849 sizeof(TcpSession),
850 StreamTcpSessionPoolAlloc,
851 StreamTcpSessionPoolInit, NULL,
852 StreamTcpSessionPoolCleanup, NULL);
853 }
854 SCMutexUnlock(&ssn_pool_mutex);
855 }
856#endif
857}
858
859void StreamTcpFreeConfig(bool quiet)
860{
862
863 SCMutexLock(&ssn_pool_mutex);
864 if (ssn_pool != NULL) {
866 ssn_pool = NULL;
867 }
868 SCMutexUnlock(&ssn_pool_mutex);
869 SCMutexDestroy(&ssn_pool_mutex);
870
871 SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt);
872}
873
874static bool IsReassemblyMemcapExceptionPolicyStatsValid(enum ExceptionPolicy exception_policy)
875{
876 if (EngineModeIsIPS()) {
878 }
880}
881
882static bool IsStreamTcpSessionMemcapExceptionPolicyStatsValid(enum ExceptionPolicy policy)
883{
884 if (EngineModeIsIPS()) {
886 }
888}
889
890static void StreamTcpSsnMemcapExceptionPolicyStatsIncr(
891 ThreadVars *tv, StreamTcpThread *stt, enum ExceptionPolicy policy)
892{
893 const uint16_t id = stt->counter_tcp_ssn_memcap_eps.eps_id[policy];
894 if (likely(tv && id > 0)) {
895 StatsIncr(tv, id);
896 }
897}
898
903
908
913
914/** \internal
915 * \brief The function is used to fetch a TCP session from the
916 * ssn_pool, when a TCP SYN is received.
917 *
918 * \param p packet starting the new TCP session.
919 * \param id thread pool id
920 *
921 * \retval ssn new TCP session.
922 */
923static TcpSession *StreamTcpNewSession(ThreadVars *tv, StreamTcpThread *stt, Packet *p, int id)
924{
925 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
926
927 if (ssn == NULL) {
928 DEBUG_VALIDATE_BUG_ON(id < 0 || id > UINT16_MAX);
929 p->flow->protoctx = StreamTcpThreadCacheGetSession();
930 if (p->flow->protoctx != NULL) {
931#ifdef UNITTESTS
932 if (tv)
933#endif
935 } else {
936 p->flow->protoctx = PoolThreadGetById(ssn_pool, (uint16_t)id);
937 if (p->flow->protoctx != NULL)
938#ifdef UNITTESTS
939 if (tv)
940#endif
942 }
943#ifdef DEBUG
944 SCMutexLock(&ssn_pool_mutex);
945 if (p->flow->protoctx != NULL)
946 ssn_pool_cnt++;
947 SCMutexUnlock(&ssn_pool_mutex);
948
949 if (unlikely((g_eps_stream_ssn_memcap != UINT64_MAX &&
950 g_eps_stream_ssn_memcap == t_pcapcnt))) {
951 SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt);
953 StreamTcpSsnMemcapExceptionPolicyStatsIncr(tv, stt, stream_config.ssn_memcap_policy);
954 return NULL;
955 }
956#endif
957 ssn = (TcpSession *)p->flow->protoctx;
958 if (ssn == NULL) {
959 SCLogDebug("ssn_pool is empty");
961 StreamTcpSsnMemcapExceptionPolicyStatsIncr(tv, stt, stream_config.ssn_memcap_policy);
962 return NULL;
963 }
964
965 const TCPHdr *tcph = PacketGetTCP(p);
966 ssn->state = TCP_NONE;
968 ssn->tcp_packet_flags = tcph->th_flags;
971
973 ssn->client.sb = x;
974 ssn->server.sb = x;
975
976 if (PKT_IS_TOSERVER(p)) {
977 ssn->client.tcp_flags = tcph->th_flags;
978 ssn->server.tcp_flags = 0;
979 } else if (PKT_IS_TOCLIENT(p)) {
980 ssn->server.tcp_flags = tcph->th_flags;
981 ssn->client.tcp_flags = 0;
982 }
983 }
984
985 return ssn;
986}
987
988static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn,
989 uint8_t state)
990{
991 if (state == ssn->state || PKT_IS_PSEUDOPKT(p))
992 return;
993
994 ssn->pstate = ssn->state;
995 ssn->state = state;
997
998 /* update the flow state */
999 switch(ssn->state) {
1000 case TCP_ESTABLISHED:
1001 case TCP_FIN_WAIT1:
1002 case TCP_FIN_WAIT2:
1003 case TCP_CLOSING:
1004 case TCP_CLOSE_WAIT:
1006 break;
1007 case TCP_LAST_ACK:
1008 case TCP_TIME_WAIT:
1009 case TCP_CLOSED:
1011 break;
1012 }
1013}
1014
1015/**
1016 * \brief Function to set the OS policy for the given stream based on the
1017 * destination of the received packet.
1018 *
1019 * \param stream TcpStream of which os_policy needs to set
1020 * \param p Packet which is used to set the os policy
1021 */
1023{
1024 if (PacketIsIPv4(p)) {
1025 /* Get the OS policy based on destination IP address, as destination
1026 OS will decide how to react on the anomalies of newly received
1027 packets */
1028 int ret = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
1029 if (ret > 0)
1030 stream->os_policy = (uint8_t)ret;
1031 else
1032 stream->os_policy = OS_POLICY_DEFAULT;
1033
1034 } else if (PacketIsIPv6(p)) {
1035 /* Get the OS policy based on destination IP address, as destination
1036 OS will decide how to react on the anomalies of newly received
1037 packets */
1038 int ret = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
1039 if (ret > 0)
1040 stream->os_policy = (uint8_t)ret;
1041 else
1042 stream->os_policy = OS_POLICY_DEFAULT;
1043 }
1044
1045 if (stream->os_policy == OS_POLICY_BSD_RIGHT)
1046 stream->os_policy = OS_POLICY_BSD;
1047 else if (stream->os_policy == OS_POLICY_OLD_SOLARIS)
1048 stream->os_policy = OS_POLICY_SOLARIS;
1049
1050 SCLogDebug("Policy is %" PRIu8 "", stream->os_policy);
1051}
1052
1053/**
1054 * \brief macro to update last_ack only if the new value is higher
1055 *
1056 * \param ssn session
1057 * \param stream stream to update
1058 * \param ack ACK value to test and set
1059 */
1060#define StreamTcpUpdateLastAck(ssn, stream, ack) { \
1061 if (SEQ_GT((ack), (stream)->last_ack)) \
1062 { \
1063 SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \
1064 if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \
1065 SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \
1066 } else { \
1067 SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \
1068 }\
1069 (stream)->last_ack = (ack); \
1070 StreamTcpSackPruneList((stream)); \
1071 } else { \
1072 SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \
1073 (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \
1074 }\
1075}
1076
1077#define StreamTcpAsyncLastAckUpdate(ssn, stream) { \
1078 if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \
1079 if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \
1080 uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \
1081 (stream)->last_ack += ack_diff; \
1082 SCLogDebug("ssn %p: ASYNC last_ack set to %"PRIu32", moved %u forward", \
1083 (ssn), (stream)->next_seq, ack_diff); \
1084 } \
1085 } \
1086}
1087
1088#define StreamTcpUpdateNextSeq(ssn, stream, seq) { \
1089 (stream)->next_seq = seq; \
1090 SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \
1091 StreamTcpAsyncLastAckUpdate((ssn), (stream)); \
1092}
1093
1094/**
1095 * \brief macro to update next_win only if the new value is higher
1096 *
1097 * \param ssn session
1098 * \param stream stream to update
1099 * \param win window value to test and set
1100 */
1101#define StreamTcpUpdateNextWin(ssn, stream, win) { \
1102 uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \
1103 if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \
1104 (stream)->next_win = ((win) + sacked_size__); \
1105 SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \
1106 } \
1107}
1108
1109static inline void StreamTcpCloseSsnWithReset(Packet *p, TcpSession *ssn)
1110{
1112 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1113 SCLogDebug("ssn %p: (state: %s) Reset received and state changed to "
1114 "TCP_CLOSED", ssn, StreamTcpStateAsString(ssn->state));
1115}
1116
1117static bool IsMidstreamExceptionPolicyStatsValid(enum ExceptionPolicy policy)
1118{
1119 if (EngineModeIsIPS()) {
1122 }
1124 }
1127 }
1129}
1130
1131static void StreamTcpMidstreamExceptionPolicyStatsIncr(
1132 ThreadVars *tv, StreamTcpThread *stt, enum ExceptionPolicy policy)
1133{
1134 const uint16_t id = stt->counter_tcp_midstream_eps.eps_id[policy];
1135 if (likely(tv && id > 0)) {
1136 StatsIncr(tv, id);
1137 }
1138}
1139
1140static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p)
1141{
1142 if (p->payload_len == 0)
1143 SCReturnInt(0);
1144
1145 const TCPHdr *tcph = PacketGetTCP(p);
1146 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
1147 /* retransmission of already partially ack'd data */
1148 if (SEQ_LT(seq, stream->last_ack) && SEQ_GT((seq + p->payload_len), stream->last_ack)) {
1150 SCReturnInt(1);
1151 }
1152
1153 /* retransmission of already ack'd data */
1154 if (SEQ_LEQ((seq + p->payload_len), stream->last_ack)) {
1156 SCReturnInt(1);
1157 }
1158
1159 /* retransmission of in flight data */
1160 if (SEQ_LEQ((seq + p->payload_len), stream->next_seq)) {
1162 SCReturnInt(2);
1163 }
1164
1165 SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", seq, p->payload_len,
1166 (seq + p->payload_len), stream->last_ack, stream->next_seq);
1167 SCReturnInt(0);
1168}
1169
1170/**
1171 * \internal
1172 * \brief Function to handle the TCP_CLOSED or NONE state. The function handles
1173 * packets while the session state is None which means a newly
1174 * initialized structure, or a fully closed session.
1175 *
1176 * \param tv Thread Variable containing input/output queue, cpu affinity
1177 * \param p Packet which has to be handled in this TCP state.
1178 * \param stt Stream Thread module registered to handle the stream handling
1179 *
1180 * \retval 0 ok
1181 * \retval -1 error
1182 */
1183static int StreamTcpPacketStateNone(
1185{
1186 const TCPHdr *tcph = PacketGetTCP(p);
1187 if (tcph->th_flags & TH_RST) {
1189 SCLogDebug("RST packet received, no session setup");
1190 return -1;
1191
1192 } else if (tcph->th_flags & TH_FIN) {
1193 /* Drop reason will only be used if midstream policy is set to fail closed */
1195 StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1196
1197 if (!stream_config.midstream || p->payload_len == 0) {
1199 SCLogDebug("FIN packet received, no session setup");
1200 return -1;
1201 }
1205 SCLogDebug("FIN packet received, no session setup");
1206 return -1;
1207 }
1208 SCLogDebug("midstream picked up");
1209
1210 if (ssn == NULL) {
1211 ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1212 if (ssn == NULL) {
1214 return -1;
1215 }
1219 }
1220 /* set the state */
1221 StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
1222 SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1223 "TCP_FIN_WAIT1",
1224 ssn);
1225
1229 SCLogDebug("ssn %p: =~ ASYNC", ssn);
1231 }
1232
1233 /** window scaling for midstream pickups, we can't do much other
1234 * than assume that it's set to the max value: 14 */
1237
1238 /* set the sequence numbers and window */
1239 ssn->client.isn = TCP_GET_RAW_SEQ(tcph) - 1;
1241 ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len + 1;
1242 ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
1243 ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
1244 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1245 SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", ssn, ssn->client.isn,
1246 ssn->client.next_seq);
1247
1248 ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
1250 ssn->server.next_seq = ssn->server.isn + 1;
1251 ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
1252 ssn->server.next_win = ssn->server.last_ack;
1253
1254 SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
1255 "ssn->server.next_win %" PRIu32 "",
1256 ssn, ssn->client.next_win, ssn->server.next_win);
1257 SCLogDebug("ssn %p: ssn->client.last_ack %" PRIu32 ", "
1258 "ssn->server.last_ack %" PRIu32 "",
1259 ssn, ssn->client.last_ack, ssn->server.last_ack);
1260
1261 /* Set the timestamp value for both streams, if packet has timestamp
1262 * option enabled.*/
1263 if (TCP_HAS_TS(p)) {
1264 ssn->client.last_ts = TCP_GET_TSVAL(p);
1265 ssn->server.last_ts = TCP_GET_TSECR(p);
1266 SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " "
1267 "ssn->client.last_ts %" PRIu32 "",
1268 ssn, ssn->server.last_ts, ssn->client.last_ts);
1269
1271
1272 ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1273 if (ssn->server.last_ts == 0)
1275 if (ssn->client.last_ts == 0)
1277
1278 } else {
1279 ssn->server.last_ts = 0;
1280 ssn->client.last_ts = 0;
1281 }
1282
1283 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1284
1286 SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1287
1288 /* SYN/ACK */
1289 } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
1290 /* Drop reason will only be used if midstream policy is set to fail closed */
1292 StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1293
1295 SCLogDebug("Midstream not enabled, so won't pick up a session");
1296 return 0;
1297 }
1300 SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1301 return 0;
1302 }
1303 SCLogDebug("midstream picked up");
1304
1305 if (ssn == NULL) {
1306 ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1307 if (ssn == NULL) {
1309 return -1;
1310 }
1314 }
1315
1316 /* reverse packet and flow */
1317 SCLogDebug("reversing flow and packet");
1318 PacketSwap(p);
1319 FlowSwap(p->flow);
1320
1321 /* set the state */
1322 StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1323 SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1324 "TCP_SYN_RECV", ssn);
1326 /* Flag used to change the direct in the later stage in the session */
1329 SCLogDebug("ssn %p: =~ ASYNC", ssn);
1331 }
1332
1333 /* sequence number & window */
1334 ssn->server.isn = TCP_GET_RAW_SEQ(tcph);
1336 ssn->server.next_seq = ssn->server.isn + 1;
1337 ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
1338 SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
1339
1340 ssn->client.isn = TCP_GET_RAW_ACK(tcph) - 1;
1342 ssn->client.next_seq = ssn->client.isn + 1;
1343
1344 ssn->client.last_ack = TCP_GET_RAW_ACK(tcph);
1345 ssn->server.last_ack = TCP_GET_RAW_SEQ(tcph);
1346
1347 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1348
1349 /** If the client has a wscale option the server had it too,
1350 * so set the wscale for the server to max. Otherwise none
1351 * will have the wscale opt just like it should. */
1352 if (TCP_HAS_WSCALE(p)) {
1353 ssn->client.wscale = TCP_GET_WSCALE(p);
1355 SCLogDebug("ssn %p: wscale enabled. client %u server %u",
1356 ssn, ssn->client.wscale, ssn->server.wscale);
1357 }
1358
1359 SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
1360 " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
1361 ssn->client.isn, ssn->client.next_seq,
1362 ssn->client.last_ack);
1363 SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
1364 " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
1365 ssn->server.isn, ssn->server.next_seq,
1366 ssn->server.last_ack);
1367
1368 /* Set the timestamp value for both streams, if packet has timestamp
1369 * option enabled.*/
1370 if (TCP_HAS_TS(p)) {
1371 ssn->server.last_ts = TCP_GET_TSVAL(p);
1372 ssn->client.last_ts = TCP_GET_TSECR(p);
1373 SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1374 "ssn->client.last_ts %" PRIu32"", ssn,
1375 ssn->server.last_ts, ssn->client.last_ts);
1376
1378
1379 ssn->server.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1380 if (ssn->server.last_ts == 0)
1382 if (ssn->client.last_ts == 0)
1384
1385 } else {
1386 ssn->server.last_ts = 0;
1387 ssn->client.last_ts = 0;
1388 }
1389
1390 if (TCP_GET_SACKOK(p)) {
1392 SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
1393 "SACK permitted for both sides", ssn);
1394 }
1395 return 0;
1396
1397 } else if (tcph->th_flags & TH_SYN) {
1398 if (ssn == NULL) {
1399 ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1400 if (ssn == NULL) {
1402 return -1;
1403 }
1404
1407 }
1408
1409 /* set the state */
1410 StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
1411 SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
1412
1414 SCLogDebug("ssn %p: =~ ASYNC", ssn);
1416 }
1417
1418 /* set the sequence numbers and window */
1419 ssn->client.isn = TCP_GET_RAW_SEQ(tcph);
1421 ssn->client.next_seq = ssn->client.isn + 1;
1422
1423 /* Set the stream timestamp value, if packet has timestamp option
1424 * enabled. */
1425 if (TCP_HAS_TS(p)) {
1426 ssn->client.last_ts = TCP_GET_TSVAL(p);
1427 SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
1428
1429 if (ssn->client.last_ts == 0)
1431
1432 ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1434 }
1435
1436 ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
1437 if (TCP_HAS_WSCALE(p)) {
1439 ssn->server.wscale = TCP_GET_WSCALE(p);
1440 }
1441
1442 if (TCP_GET_SACKOK(p)) {
1444 SCLogDebug("ssn %p: SACK permitted on SYN packet", ssn);
1445 }
1446
1447 if (TCP_HAS_TFO(p)) {
1449 if (p->payload_len) {
1450 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
1451 SCLogDebug("ssn: %p (TFO) isn %u base_seq %u next_seq %u payload len %u", ssn,
1452 ssn->client.isn, ssn->client.base_seq, ssn->client.next_seq,
1453 p->payload_len);
1454 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1455 }
1456 }
1457
1458 SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
1459 "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
1460 "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
1461 ssn->client.last_ack);
1462
1463 } else if (tcph->th_flags & TH_ACK) {
1464 /* Drop reason will only be used if midstream policy is set to fail closed */
1466 StreamTcpMidstreamExceptionPolicyStatsIncr(tv, stt, stream_config.midstream_policy);
1467
1468 if (!stream_config.midstream) {
1469 SCLogDebug("Midstream not enabled, so won't pick up a session");
1470 return 0;
1471 }
1474 SCLogDebug("Midstream policy not permissive, so won't pick up a session");
1475 return 0;
1476 }
1477 SCLogDebug("midstream picked up");
1478
1479 if (ssn == NULL) {
1480 ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
1481 if (ssn == NULL) {
1483 return -1;
1484 }
1488 }
1489 /* set the state */
1490 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1491 SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1492 "TCP_ESTABLISHED", ssn);
1493
1497 SCLogDebug("ssn %p: =~ ASYNC", ssn);
1499 }
1500
1501 /** window scaling for midstream pickups, we can't do much other
1502 * than assume that it's set to the max value: 14 */
1505
1506 /* set the sequence numbers and window */
1507 ssn->client.isn = TCP_GET_RAW_SEQ(tcph) - 1;
1509 ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
1510 ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
1511 ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
1512 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1513 SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
1514 ssn, ssn->client.isn, ssn->client.next_seq);
1515
1516 ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
1518 ssn->server.next_seq = ssn->server.isn + 1;
1519 ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
1520 ssn->server.next_win = ssn->server.last_ack;
1521
1522 SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
1523 "ssn->server.next_win %"PRIu32"", ssn,
1524 ssn->client.next_win, ssn->server.next_win);
1525 SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
1526 "ssn->server.last_ack %"PRIu32"", ssn,
1527 ssn->client.last_ack, ssn->server.last_ack);
1528
1529 /* Set the timestamp value for both streams, if packet has timestamp
1530 * option enabled.*/
1531 if (TCP_HAS_TS(p)) {
1532 ssn->client.last_ts = TCP_GET_TSVAL(p);
1533 ssn->server.last_ts = TCP_GET_TSECR(p);
1534 SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1535 "ssn->client.last_ts %" PRIu32"", ssn,
1536 ssn->server.last_ts, ssn->client.last_ts);
1537
1539
1540 ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1541 if (ssn->server.last_ts == 0)
1543 if (ssn->client.last_ts == 0)
1545
1546 } else {
1547 ssn->server.last_ts = 0;
1548 ssn->client.last_ts = 0;
1549 }
1550
1551 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
1552
1554 SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1555
1556 } else {
1557 SCLogDebug("default case");
1558 }
1559
1560 return 0;
1561}
1562
1563/** \internal
1564 * \brief Setup TcpStateQueue based on SYN/ACK packet
1565 */
1566static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
1567{
1568 const TCPHdr *tcph = PacketGetTCP(p);
1569 q->flags = 0;
1570 q->wscale = 0;
1571 q->ts = 0;
1572 q->win = TCP_GET_RAW_WINDOW(tcph);
1573 q->seq = TCP_GET_RAW_SEQ(tcph);
1574 q->ack = TCP_GET_RAW_ACK(tcph);
1575 q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1576
1577 if (TCP_GET_SACKOK(p))
1579
1580 if (TCP_HAS_WSCALE(p)) {
1582 q->wscale = TCP_GET_WSCALE(p);
1583 }
1584 if (TCP_HAS_TS(p)) {
1586 q->ts = TCP_GET_TSVAL(p);
1587 }
1588}
1589
1590/** \internal
1591 * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
1592 * \retval q or NULL */
1593static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
1594{
1595 TcpStateQueue *q = ssn->queue;
1596 TcpStateQueue search;
1597
1598 StreamTcp3whsSynAckToStateQueue(p, &search);
1599
1600 while (q != NULL) {
1601 if (search.flags == q->flags &&
1602 search.wscale == q->wscale &&
1603 search.win == q->win &&
1604 search.seq == q->seq &&
1605 search.ack == q->ack &&
1606 search.ts == q->ts) {
1607 return q;
1608 }
1609
1610 q = q->next;
1611 }
1612
1613 return q;
1614}
1615
1616static int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
1617{
1618 /* first see if this is already in our list */
1619 if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
1620 return 0;
1621
1623 SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
1625 return -1;
1626 }
1627
1628 if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1629 SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
1630 return -1;
1631 }
1632
1633 TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1634 if (unlikely(q == NULL)) {
1635 SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
1636 return -1;
1637 }
1638 StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1639
1640 StreamTcp3whsSynAckToStateQueue(p, q);
1641
1642 /* put in list */
1643 q->next = ssn->queue;
1644 ssn->queue = q;
1645 ssn->queue_len++;
1646 return 0;
1647}
1648
1649/** \internal
1650 * \brief Find the Queued SYN/ACK that goes with this ACK
1651 * \retval q or NULL */
1652static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
1653{
1654 const TCPHdr *tcph = PacketGetTCP(p);
1655 const uint32_t ack = TCP_GET_RAW_SEQ(tcph);
1656 const uint32_t seq = TCP_GET_RAW_ACK(tcph) - 1;
1657 TcpStateQueue *q = ssn->queue;
1658
1659 while (q != NULL) {
1660 if (seq == q->seq &&
1661 ack == q->ack) {
1662 return q;
1663 }
1664
1665 q = q->next;
1666 }
1667
1668 return NULL;
1669}
1670
1671/** \internal
1672 * \brief Update SSN after receiving a valid SYN/ACK
1673 *
1674 * Normally we update the SSN from the SYN/ACK packet. But in case
1675 * of queued SYN/ACKs, we can use one of those.
1676 *
1677 * \param ssn TCP session
1678 * \param p Packet
1679 * \param q queued state if used, NULL otherwise
1680 *
1681 * To make sure all SYN/ACK based state updates are in one place,
1682 * this function can updated based on Packet or TcpStateQueue, where
1683 * the latter takes precedence.
1684 */
1685static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
1686{
1687 TcpStateQueue update;
1688 if (likely(q == NULL)) {
1689 StreamTcp3whsSynAckToStateQueue(p, &update);
1690 q = &update;
1691 }
1692
1693 if (ssn->state != TCP_SYN_RECV) {
1694 /* update state */
1695 StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1696 SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
1697 }
1698 /* sequence number & window */
1699 ssn->server.isn = q->seq;
1701 ssn->server.next_seq = ssn->server.isn + 1;
1702
1703 ssn->client.window = q->win;
1704 SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
1705
1706 /* Set the timestamp values used to validate the timestamp of
1707 * received packets.*/
1708 if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
1710 {
1711 ssn->server.last_ts = q->ts;
1712 SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1713 "ssn->client.last_ts %" PRIu32"", ssn,
1714 ssn->server.last_ts, ssn->client.last_ts);
1716 ssn->server.last_pkt_ts = q->pkt_ts;
1717 if (ssn->server.last_ts == 0)
1719 } else {
1720 ssn->client.last_ts = 0;
1721 ssn->server.last_ts = 0;
1722 ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1723 }
1724
1725 ssn->client.last_ack = q->ack;
1726 ssn->server.last_ack = ssn->server.isn + 1;
1727
1728 /** check for the presence of the ws ptr to determine if we
1729 * support wscale at all */
1730 if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1732 {
1733 ssn->client.wscale = q->wscale;
1734 } else {
1735 ssn->client.wscale = 0;
1736 }
1737
1738 if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1741 SCLogDebug("ssn %p: SACK permitted for session", ssn);
1742 } else {
1743 ssn->flags &= ~STREAMTCP_FLAG_SACKOK;
1744 }
1745
1746 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1747 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1748 SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
1749 ssn->server.next_win);
1750 SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
1751 ssn->client.next_win);
1752 SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
1753 "ssn->server.next_seq %" PRIu32 ", "
1754 "ssn->server.last_ack %" PRIu32 " "
1755 "(ssn->client.last_ack %" PRIu32 ")", ssn,
1756 ssn->server.isn, ssn->server.next_seq,
1757 ssn->server.last_ack, ssn->client.last_ack);
1758
1759 /* unset the 4WHS flag as we received this SYN/ACK as part of a
1760 * (so far) valid 3WHS */
1761 if (ssn->flags & STREAMTCP_FLAG_4WHS)
1762 SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
1763 " so considering 3WHS", ssn);
1764
1765 ssn->flags &=~ STREAMTCP_FLAG_4WHS;
1766}
1767
1768/** \internal
1769 * \brief detect timestamp anomalies when processing responses to the
1770 * SYN packet.
1771 * \retval true packet is ok
1772 * \retval false packet is bad
1773 */
1774static inline bool StateSynSentValidateTimestamp(TcpSession *ssn, Packet *p)
1775{
1776 /* we only care about evil server here, so skip TS packets */
1777 if (PKT_IS_TOSERVER(p) || !(TCP_HAS_TS(p))) {
1778 return true;
1779 }
1780
1781 TcpStream *receiver_stream = &ssn->client;
1782 const uint32_t ts_echo = TCP_GET_TSECR(p);
1783 if ((receiver_stream->flags & STREAMTCP_STREAM_FLAG_TIMESTAMP) != 0) {
1784 if (receiver_stream->last_ts != 0 && ts_echo != 0 &&
1785 ts_echo != receiver_stream->last_ts)
1786 {
1787 SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn,
1788 ts_echo, receiver_stream->last_ts);
1789 return false;
1790 }
1791 } else {
1792 if (receiver_stream->last_ts == 0 && ts_echo != 0) {
1793 SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn,
1794 ts_echo, receiver_stream->last_ts);
1795 return false;
1796 }
1797 }
1798 return true;
1799}
1800
1801static void TcpStateQueueInitFromSsnSyn(const TcpSession *ssn, TcpStateQueue *q)
1802{
1803 DEBUG_VALIDATE_BUG_ON(ssn->state != TCP_SYN_SENT); // TODO
1804 memset(q, 0, sizeof(*q));
1805
1806 /* SYN won't use wscale yet. So window should be limited to 16 bits. */
1807 DEBUG_VALIDATE_BUG_ON(ssn->server.window > UINT16_MAX);
1808 q->win = (uint16_t)ssn->server.window;
1809
1810 q->pkt_ts = ssn->client.last_pkt_ts;
1811
1814 }
1817 q->wscale = ssn->server.wscale;
1818 }
1821 q->ts = ssn->client.last_ts;
1822 }
1823
1824 SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1826}
1827
1828static void TcpStateQueueInitFromPktSyn(const Packet *p, TcpStateQueue *q)
1829{
1830#if defined(DEBUG_VALIDATION) || defined(DEBUG)
1831 const TcpSession *ssn = p->flow->protoctx;
1832 BUG_ON(ssn->state != TCP_SYN_SENT);
1833#endif
1834 memset(q, 0, sizeof(*q));
1835 const TCPHdr *tcph = PacketGetTCP(p);
1836
1837 q->win = TCP_GET_RAW_WINDOW(tcph);
1838 q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1839
1840 if (TCP_GET_SACKOK(p)) {
1842 }
1843 if (TCP_HAS_WSCALE(p)) {
1845 q->wscale = TCP_GET_WSCALE(p);
1846 }
1847 if (TCP_HAS_TS(p)) {
1849 q->ts = TCP_GET_TSVAL(p);
1850 }
1851
1852#if defined(DEBUG)
1853 SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1855#endif
1856}
1857
1858static void TcpStateQueueInitFromPktSynAck(const Packet *p, TcpStateQueue *q)
1859{
1860#if defined(DEBUG_VALIDATION) || defined(DEBUG)
1861 const TcpSession *ssn = p->flow->protoctx;
1862 if ((ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) == 0)
1863 BUG_ON(ssn->state != TCP_SYN_SENT);
1864 else
1865 BUG_ON(ssn->state != TCP_ESTABLISHED);
1866#endif
1867 memset(q, 0, sizeof(*q));
1868
1869 const TCPHdr *tcph = PacketGetTCP(p);
1870 q->win = TCP_GET_RAW_WINDOW(tcph);
1871 q->pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
1872
1873 if (TCP_GET_SACKOK(p)) {
1875 }
1876 if (TCP_HAS_WSCALE(p)) {
1878 q->wscale = TCP_GET_WSCALE(p);
1879 }
1880 if (TCP_HAS_TS(p)) {
1882 q->ts = TCP_GET_TSECR(p);
1883 }
1884
1885#if defined(DEBUG)
1886 SCLogDebug("ssn %p: state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq, q->win,
1888#endif
1889}
1890
1891/** \internal
1892 * \brief Find the Queued SYN that is the same as this SYN/ACK
1893 * \retval q or NULL */
1894static const TcpStateQueue *StreamTcp3whsFindSyn(const TcpSession *ssn, TcpStateQueue *s)
1895{
1896 SCLogDebug("ssn %p: search state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, s, s->seq, s->win,
1898
1899 for (const TcpStateQueue *q = ssn->queue; q != NULL; q = q->next) {
1900 SCLogDebug("ssn %p: queue state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u", ssn, q, q->seq,
1903 s->ts == q->ts) {
1904 return q;
1905 }
1906 }
1907 return NULL;
1908}
1909
1910/** \note the SEQ values *must* be the same */
1911static int StreamTcp3whsStoreSyn(TcpSession *ssn, Packet *p)
1912{
1913 TcpStateQueue search;
1914 TcpStateQueueInitFromSsnSyn(ssn, &search);
1915
1916 /* first see if this is already in our list */
1917 if (ssn->queue != NULL && StreamTcp3whsFindSyn(ssn, &search) != NULL)
1918 return 0;
1919
1921 SCLogDebug("ssn %p: =~ SYN queue limit reached", ssn);
1923 return -1;
1924 }
1925
1926 if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1927 SCLogDebug("ssn %p: =~ SYN queue failed: stream memcap reached", ssn);
1928 return -1;
1929 }
1930
1931 TcpStateQueue *q = SCCalloc(1, sizeof(*q));
1932 if (unlikely(q == NULL)) {
1933 SCLogDebug("ssn %p: =~ SYN queue failed: alloc failed", ssn);
1934 return -1;
1935 }
1936 StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1937
1938 *q = search;
1939 /* put in list */
1940 q->next = ssn->queue;
1941 ssn->queue = q;
1942 ssn->queue_len++;
1943 return 0;
1944}
1945
1946static inline void StreamTcp3whsStoreSynApplyToSsn(TcpSession *ssn, const TcpStateQueue *q)
1947{
1948 if (q->flags & STREAMTCP_QUEUE_FLAG_TS) {
1949 ssn->client.last_pkt_ts = q->pkt_ts;
1950 ssn->client.last_ts = q->ts;
1952 SCLogDebug("ssn: %p client.last_ts updated to %u", ssn, ssn->client.last_ts);
1953 }
1954 if (q->flags & STREAMTCP_QUEUE_FLAG_WS) {
1956 ssn->server.wscale = q->wscale;
1957 } else {
1959 ssn->server.wscale = 0;
1960 }
1961 ssn->server.window = q->win;
1962
1965 } else {
1966 ssn->flags &= ~STREAMTCP_FLAG_CLIENT_SACKOK;
1967 }
1968}
1969
1970/**
1971 * \brief Function to handle the TCP_SYN_SENT state. The function handles
1972 * SYN, SYN/ACK, RST packets and correspondingly changes the connection
1973 * state.
1974 *
1975 * \param tv Thread Variable containing input/output queue, cpu affinity
1976 * \param p Packet which has to be handled in this TCP state.
1977 * \param stt Stream Thread module registered to handle the stream handling
1978 */
1979
1980static int StreamTcpPacketStateSynSent(
1982{
1983 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
1984 const TCPHdr *tcph = PacketGetTCP(p);
1985
1986 SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ? "toclient" : "toserver");
1987
1988 /* common case: SYN/ACK from server to client */
1989 if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOCLIENT(p)) {
1990 SCLogDebug("ssn %p: SYN/ACK on SYN_SENT state for packet %" PRIu64, ssn, p->pcap_cnt);
1991
1992 if (!(TCP_HAS_TFO(p) || (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN))) {
1993 /* Check if the SYN/ACK packet ack's the earlier
1994 * received SYN packet. */
1995 if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1))) {
1997 SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1998 "%" PRIu32 " from stream",
1999 ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2000 return -1;
2001 }
2002 } else {
2003 if (SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.next_seq)) {
2004 SCLogDebug("ssn %p: (TFO) ACK matches next_seq, packet ACK %" PRIu32 " == "
2005 "%" PRIu32 " from stream",
2006 ssn, TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
2007 } else if (SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1)) {
2008 SCLogDebug("ssn %p: (TFO) ACK matches ISN+1, packet ACK %" PRIu32 " == "
2009 "%" PRIu32 " from stream",
2010 ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2011 ssn->client.next_seq = ssn->client.isn; // reset to ISN
2012 SCLogDebug("ssn %p: (TFO) next_seq reset to isn (%u)", ssn, ssn->client.next_seq);
2015 } else {
2017 SCLogDebug("ssn %p: (TFO) ACK mismatch, packet ACK %" PRIu32 " != "
2018 "%" PRIu32 " from stream",
2019 ssn, TCP_GET_RAW_ACK(tcph), ssn->client.next_seq);
2020 return -1;
2021 }
2023 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2024 }
2025
2026 const bool ts_mismatch = !StateSynSentValidateTimestamp(ssn, p);
2027 if (ts_mismatch) {
2028 SCLogDebug("ssn %p: ts_mismatch:%s", ssn, BOOL2STR(ts_mismatch));
2029 if (ssn->queue) {
2030 TcpStateQueue search;
2031 TcpStateQueueInitFromPktSynAck(p, &search);
2032
2033 const TcpStateQueue *q = StreamTcp3whsFindSyn(ssn, &search);
2034 if (q == NULL) {
2035 SCLogDebug("not found: mismatch");
2037 return -1;
2038 }
2039 SCLogDebug("ssn %p: found queued SYN state:%p, isn:%u/win:%u/has_ts:%s/tsval:%u",
2040 ssn, q, q->seq, q->win, BOOL2STR(q->flags & STREAMTCP_QUEUE_FLAG_TS),
2041 q->ts);
2042
2043 StreamTcp3whsStoreSynApplyToSsn(ssn, q);
2044
2045 } else {
2046 SCLogDebug("not found: no queue");
2048 return -1;
2049 }
2050 }
2051
2052 /* clear ssn->queue on state change: TcpSession can be reused by SYN/ACK */
2053 StreamTcp3wsFreeQueue(ssn);
2054
2055 StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
2056 return 0;
2057
2058 } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOSERVER(p)) {
2059
2060 if (!(ssn->flags & STREAMTCP_FLAG_4WHS)) {
2062 SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
2063 return -1;
2064 }
2065
2066 SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
2067
2068 /* Check if the SYN/ACK packet ack's the earlier
2069 * received SYN packet. */
2070 if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.isn + 1))) {
2072
2073 SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %" PRIu32 ""
2074 " != %" PRIu32 " from stream",
2075 ssn, TCP_GET_RAW_ACK(tcph), ssn->server.isn + 1);
2076 return -1;
2077 }
2078
2079 /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
2080 * packet. */
2081 if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn))) {
2083
2084 SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %" PRIu32 ""
2085 " != %" PRIu32 " from *first* SYN pkt",
2086 ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.isn);
2087 return -1;
2088 }
2089
2090 /* update state */
2091 StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
2092 SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
2093
2094 /* sequence number & window */
2095 ssn->client.isn = TCP_GET_RAW_SEQ(tcph);
2097 ssn->client.next_seq = ssn->client.isn + 1;
2098
2099 ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2100 SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn, ssn->client.window);
2101
2102 /* Set the timestamp values used to validate the timestamp of
2103 * received packets. */
2105 ssn->client.last_ts = TCP_GET_TSVAL(p);
2106 SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32 " "
2107 "ssn->server.last_ts %" PRIu32 "",
2108 ssn, ssn->client.last_ts, ssn->server.last_ts);
2110 ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2111 if (ssn->client.last_ts == 0)
2113 } else {
2114 ssn->server.last_ts = 0;
2115 ssn->client.last_ts = 0;
2116 ssn->server.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
2117 }
2118
2119 ssn->server.last_ack = TCP_GET_RAW_ACK(tcph);
2120 ssn->client.last_ack = ssn->client.isn + 1;
2121
2122 /** check for the presense of the ws ptr to determine if we
2123 * support wscale at all */
2124 if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && (TCP_HAS_WSCALE(p))) {
2125 ssn->server.wscale = TCP_GET_WSCALE(p);
2126 } else {
2127 ssn->server.wscale = 0;
2128 }
2129
2132 SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
2133 }
2134
2135 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2136 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2137 SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win);
2138 SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win);
2139 SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2140 "ssn->client.next_seq %" PRIu32 ", "
2141 "ssn->client.last_ack %" PRIu32 " "
2142 "(ssn->server.last_ack %" PRIu32 ")",
2143 ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack,
2144 ssn->server.last_ack);
2145
2146 /* done here */
2147 return 0;
2148 }
2149
2150 /* check for bad responses */
2151 if (!StateSynSentValidateTimestamp(ssn, p)) {
2153 return -1;
2154 }
2155
2156 /* RST */
2157 if (tcph->th_flags & TH_RST) {
2158
2159 if (!StreamTcpValidateRst(ssn, p))
2160 return -1;
2161
2162 if (PKT_IS_TOSERVER(p)) {
2163 if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn) &&
2164 SEQ_EQ(TCP_GET_RAW_WINDOW(tcph), 0) &&
2165 SEQ_EQ(TCP_GET_RAW_ACK(tcph), (ssn->client.isn + 1))) {
2166 SCLogDebug("ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
2168 StreamTcpCloseSsnWithReset(p, ssn);
2169 StreamTcp3wsFreeQueue(ssn);
2170 }
2171 } else {
2173 SCLogDebug("ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
2174 StreamTcpCloseSsnWithReset(p, ssn);
2175 StreamTcp3wsFreeQueue(ssn);
2176 }
2177
2178 /* FIN */
2179 } else if (tcph->th_flags & TH_FIN) {
2180 /** \todo */
2181
2182 } else if (tcph->th_flags & TH_SYN) {
2183 SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
2184 if (ssn->flags & STREAMTCP_FLAG_4WHS) {
2185 SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
2186 "4WHS SYN", ssn);
2187 }
2188
2189 if (PKT_IS_TOCLIENT(p)) {
2190 /** a SYN only packet in the opposite direction could be:
2191 * http://www.breakingpointsystems.com/community/blog/tcp-
2192 * portals-the-three-way-handshake-is-a-lie
2193 *
2194 * \todo improve resetting the session */
2195
2196 /* indicate that we're dealing with 4WHS here */
2197 ssn->flags |= STREAMTCP_FLAG_4WHS;
2198 SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
2199
2200 /* set the sequence numbers and window for server
2201 * We leave the ssn->client.isn in place as we will
2202 * check the SYN/ACK pkt with that.
2203 */
2204 ssn->server.isn = TCP_GET_RAW_SEQ(tcph);
2206 ssn->server.next_seq = ssn->server.isn + 1;
2207
2208 /* Set the stream timestamp value, if packet has timestamp
2209 * option enabled. */
2210 if (TCP_HAS_TS(p)) {
2211 ssn->server.last_ts = TCP_GET_TSVAL(p);
2212 SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
2213
2214 if (ssn->server.last_ts == 0)
2216 ssn->server.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2218 }
2219
2220 ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2221 if (TCP_HAS_WSCALE(p)) {
2223 ssn->server.wscale = TCP_GET_WSCALE(p);
2224 } else {
2225 ssn->flags &= ~STREAMTCP_FLAG_SERVER_WSCALE;
2226 ssn->server.wscale = 0;
2227 }
2228
2229 if (TCP_GET_SACKOK(p)) {
2231 } else {
2232 ssn->flags &= ~STREAMTCP_FLAG_CLIENT_SACKOK;
2233 }
2234
2235 SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
2236 "ssn->server.next_seq %" PRIu32 ", "
2237 "ssn->server.last_ack %"PRIu32"", ssn,
2238 ssn->server.isn, ssn->server.next_seq,
2239 ssn->server.last_ack);
2240 SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
2241 "ssn->client.next_seq %" PRIu32 ", "
2242 "ssn->client.last_ack %"PRIu32"", ssn,
2243 ssn->client.isn, ssn->client.next_seq,
2244 ssn->client.last_ack);
2245 } else if (PKT_IS_TOSERVER(p)) {
2246 /* on a SYN resend we queue up the SYN's until a SYN/ACK moves the state
2247 * to SYN_RECV. We update the ssn to the most recent, as it is most likely
2248 * to be correct. */
2249
2250 TcpStateQueue syn_pkt, syn_ssn;
2251 TcpStateQueueInitFromPktSyn(p, &syn_pkt);
2252 TcpStateQueueInitFromSsnSyn(ssn, &syn_ssn);
2253
2254 if (memcmp(&syn_pkt, &syn_ssn, sizeof(TcpStateQueue)) != 0) {
2255 /* store the old session settings */
2256 StreamTcp3whsStoreSyn(ssn, p);
2257 SCLogDebug("ssn %p: Retransmitted SYN. Updating ssn from packet %" PRIu64
2258 ". Stored previous state",
2259 ssn, p->pcap_cnt);
2260 }
2261 StreamTcp3whsStoreSynApplyToSsn(ssn, &syn_pkt);
2262 }
2263 } else if (tcph->th_flags & TH_ACK) {
2264 /* Handle the asynchronous stream, when we receive a SYN packet
2265 and now instead of receiving a SYN/ACK we receive a ACK from the
2266 same host, which sent the SYN, this suggests the ASYNC streams.*/
2268 return 0;
2269
2270 /* we are in ASYNC (one side) mode now. */
2271
2272 /* one side async means we won't see a SYN/ACK, so we can
2273 * only check the SYN. */
2274 if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq))) {
2276
2277 SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2278 "%" PRIu32 " from stream",
2279 ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq);
2280 return -1;
2281 }
2282
2284 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2285 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2286 StreamTcp3wsFreeQueue(ssn);
2287
2288 ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2289 ssn->client.last_ack = TCP_GET_RAW_SEQ(tcph);
2290 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2291
2292 /* Set the server side parameters */
2293 ssn->server.isn = TCP_GET_RAW_ACK(tcph) - 1;
2295 ssn->server.next_seq = ssn->server.isn + 1;
2296 ssn->server.last_ack = ssn->server.next_seq;
2297 ssn->server.next_win = ssn->server.last_ack;
2298
2299 SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
2300 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2301 "ssn->client.next_seq %" PRIu32 "",
2302 ssn, TCP_GET_RAW_SEQ(tcph), p->payload_len, TCP_GET_RAW_SEQ(tcph) + p->payload_len,
2303 ssn->client.next_seq);
2304
2305 /* if SYN had wscale, assume it to be supported. Otherwise
2306 * we know it not to be supported. */
2309 }
2310
2311 /* Set the timestamp values used to validate the timestamp of
2312 * received packets.*/
2313 if (TCP_HAS_TS(p) &&
2315 {
2317 ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_TIMESTAMP;
2318 ssn->client.last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
2319 } else {
2320 ssn->client.last_ts = 0;
2321 ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
2322 }
2323
2326 }
2327
2328 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2329
2330 } else {
2331 SCLogDebug("ssn %p: default case", ssn);
2332 }
2333
2334 return 0;
2335}
2336
2337/**
2338 * \brief Function to handle the TCP_SYN_RECV state. The function handles
2339 * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
2340 * the connection state.
2341 *
2342 * \param tv Thread Variable containing input/output queue, cpu affinity
2343 * \param p Packet which has to be handled in this TCP state.
2344 * \param stt Stream Thread module registered to handle the stream handling
2345 *
2346 * \retval 0 ok
2347 * \retval -1 error
2348 */
2349
2350static int StreamTcpPacketStateSynRecv(
2352{
2353 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
2354 const TCPHdr *tcph = PacketGetTCP(p);
2355
2356 if (tcph->th_flags & TH_RST) {
2357 if (!StreamTcpValidateRst(ssn, p))
2358 return -1;
2359
2360 bool reset = true;
2361 /* After receiving the RST in SYN_RECV state and if detection
2362 evasion flags has been set, then the following operating
2363 systems will not closed the connection. As they consider the
2364 packet as stray packet and not belonging to the current
2365 session, for more information check
2366 http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
2368 if (PKT_IS_TOSERVER(p)) {
2369 if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
2372 {
2373 reset = false;
2374 SCLogDebug("Detection evasion has been attempted, so"
2375 " not resetting the connection !!");
2376 }
2377 } else {
2378 if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
2381 {
2382 reset = false;
2383 SCLogDebug("Detection evasion has been attempted, so"
2384 " not resetting the connection !!");
2385 }
2386 }
2387 }
2388
2389 if (reset) {
2390 StreamTcpCloseSsnWithReset(p, ssn);
2391
2392 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2393 StreamTcpHandleTimestamp(ssn, p);
2394 }
2395 }
2396
2397 } else if (tcph->th_flags & TH_FIN) {
2398 /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
2399 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2400 if (!StreamTcpValidateTimestamp(ssn, p))
2401 return -1;
2402 }
2403
2404 if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
2405 return -1;
2406
2407 /* SYN/ACK */
2408 } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
2409 SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
2410
2411 if (PKT_IS_TOSERVER(p)) {
2412 SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
2413
2415 return -1;
2416 }
2417
2418 /* Check if the SYN/ACK packets ACK matches the earlier
2419 * received SYN/ACK packet. */
2420 if (!(SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack))) {
2421 SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
2422 "%" PRIu32 " from stream",
2423 ssn, TCP_GET_RAW_ACK(tcph), ssn->client.isn + 1);
2424
2426 return -1;
2427 }
2428
2429 /* Check if the SYN/ACK packet SEQ the earlier
2430 * received SYN/ACK packet, server resend with different ISN. */
2431 if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.isn))) {
2432 SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2433 "%" PRIu32 " from stream",
2434 ssn, TCP_GET_RAW_SEQ(tcph), ssn->client.isn);
2435
2436 if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
2437 return -1;
2438 SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
2439 }
2440
2441 } else if (tcph->th_flags & TH_SYN) {
2442 SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
2443
2444 if (PKT_IS_TOCLIENT(p)) {
2445 SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
2446
2448 return -1;
2449 }
2450
2451 if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.isn))) {
2452 SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
2453
2455 return -1;
2456 }
2457
2458 } else if (tcph->th_flags & TH_ACK) {
2459 if (ssn->queue_len) {
2460 SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
2461 TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
2462 if (q != NULL) {
2463 SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
2464 StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
2465 } else {
2466 SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
2467 }
2468 }
2469
2470
2471 /* If the timestamp option is enabled for both the streams, then
2472 * validate the received packet timestamp value against the
2473 * stream->last_ts. If the timestamp is valid then process the
2474 * packet normally otherwise the drop the packet (RFC 1323)*/
2475 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2476 if (!(StreamTcpValidateTimestamp(ssn, p))) {
2477 return -1;
2478 }
2479 }
2480
2481 if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) {
2482 SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
2483
2484 if (!(SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2485 SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
2487 return -1;
2488 }
2489
2490 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2491 SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
2493 return -1;
2494 }
2495
2496 SCLogDebug("4WHS normal pkt");
2497 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2498 "%" PRIu32 ", ACK %" PRIu32 "",
2499 ssn, p->payload_len, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph));
2500
2501 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2502 StreamTcpHandleTimestamp(ssn, p);
2503 }
2504
2506 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2507 ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2508 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2509
2510 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2511 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2512
2513 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2514
2515 SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
2516 "ssn->client.last_ack %"PRIu32"", ssn,
2517 ssn->client.next_win, ssn->client.last_ack);
2518 return 0;
2519 }
2520
2521 bool ack_indicates_missed_3whs_ack_packet = false;
2522 /* Check if the ACK received is in right direction. But when we have
2523 * picked up a mid stream session after missing the initial SYN pkt,
2524 * in this case the ACK packet can arrive from either client (normal
2525 * case) or from server itself (asynchronous streams). Therefore
2526 * the check has been avoided in this case */
2527 if (PKT_IS_TOCLIENT(p)) {
2528 /* special case, handle 4WHS, so SYN/ACK in the opposite
2529 * direction */
2531 SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
2532 "pickup session",ssn);
2533 /* fall through */
2534 } else if (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) {
2535 SCLogDebug("ssn %p: ACK received on TFO session",ssn);
2536 /* fall through */
2537
2538 } else {
2539 /* if we missed traffic between the S/SA and the current
2540 * 'wrong direction' ACK, we could end up here. In IPS
2541 * reject it. But in IDS mode we continue.
2542 *
2543 * IPS rejects as it should see all packets, so pktloss
2544 * should lead to retransmissions. As this can also be
2545 * pattern for MOTS/MITM injection attacks, we need to be
2546 * careful.
2547 */
2548 if (StreamTcpInlineMode()) {
2549 if (p->payload_len > 0 && SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack) &&
2550 SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq)) {
2551 /* packet loss is possible but unlikely here */
2552 SCLogDebug("ssn %p: possible data injection", ssn);
2554 return -1;
2555 }
2556
2557 SCLogDebug("ssn %p: ACK received in the wrong direction",
2558 ssn);
2560 return -1;
2561 }
2562 ack_indicates_missed_3whs_ack_packet = true;
2563 }
2564 }
2565
2566 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
2567 ", ACK %" PRIu32 "",
2568 ssn, p->payload_len, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph));
2569
2570 /* Check both seq and ack number before accepting the packet and
2571 changing to ESTABLISHED state */
2572 if ((SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) &&
2573 SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.next_seq)) {
2574 SCLogDebug("normal pkt");
2575
2576 /* process the packet normal, No Async streams :) */
2577
2578 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2579 StreamTcpHandleTimestamp(ssn, p);
2580 }
2581
2583 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2584 ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2585
2586 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2587
2588 if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2589 ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2590 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2591 ssn->server.next_win = ssn->server.last_ack +
2592 ssn->server.window;
2593 if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
2594 /* window scaling for midstream pickups, we can't do much
2595 * other than assume that it's set to the max value: 14 */
2599 }
2600 }
2601
2602 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2603 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2604
2605 /* special case: normally the packet following the 3whs is
2606 * considered flow established, but with data we need it to
2607 * be established now. This can happen if the original ACK was
2608 * lost. */
2609 if (p->payload_len) {
2611 }
2612
2613 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2614
2615 /* If asynchronous stream handling is allowed then set the session,
2616 if packet's seq number is equal the expected seq no.*/
2617 } else if (stream_config.async_oneside &&
2618 (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq))) {
2619 /*set the ASYNC flag used to indicate the session as async stream
2620 and helps in relaxing the windows checks.*/
2622 ssn->server.next_seq += p->payload_len;
2623 ssn->server.last_ack = TCP_GET_RAW_SEQ(tcph);
2624
2625 ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2626 ssn->client.last_ack = TCP_GET_RAW_ACK(tcph);
2627
2628 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2629 StreamTcpHandleTimestamp(ssn, p);
2630 }
2631
2632 if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2633 ssn->server.window = TCP_GET_RAW_WINDOW(tcph);
2634 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2635 /* window scaling for midstream pickups, we can't do much
2636 * other than assume that it's set to the max value: 14 */
2640 }
2641
2642 SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
2643 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2644 "ssn->server.next_seq %" PRIu32,
2645 ssn, TCP_GET_RAW_SEQ(tcph), p->payload_len,
2646 TCP_GET_RAW_SEQ(tcph) + p->payload_len, ssn->server.next_seq);
2647
2648 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2649 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2650
2651 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2652 /* Upon receiving the packet with correct seq number and wrong
2653 ACK number, it causes the other end to send RST. But some target
2654 system (Linux & solaris) does not RST the connection, so it is
2655 likely to avoid the detection */
2656 } else if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq)) {
2658 SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
2659 ssn);
2660
2662 return -1;
2663
2664 /* SYN/ACK followed by more TOCLIENT suggesting packet loss */
2665 } else if (PKT_IS_TOCLIENT(p) && !StreamTcpInlineMode() &&
2666 SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2667 SEQ_GT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
2668 SCLogDebug("ssn %p: ACK for missing data", ssn);
2669
2670 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2671 StreamTcpHandleTimestamp(ssn, p);
2672 }
2673
2675
2676 ssn->server.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
2677 SCLogDebug("ssn %p: ACK for missing data: ssn->server.next_seq %u", ssn,
2678 ssn->server.next_seq);
2679 ssn->client.window = TCP_GET_RAW_WINDOW(tcph) << ssn->client.wscale;
2680
2681 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2682
2683 ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2684 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2685
2686 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2687 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2688
2689 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2690
2691 /* if we get a packet with a proper ack, but a seq that is beyond
2692 * next_seq but in-window, we probably missed some packets */
2693 } else if (SEQ_GT(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
2694 SEQ_LEQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_win) &&
2695 SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->server.next_seq)) {
2696 SCLogDebug("ssn %p: ACK for missing data", ssn);
2697
2698 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2699 StreamTcpHandleTimestamp(ssn, p);
2700 }
2701
2702 ssn->client.next_seq = TCP_GET_RAW_SEQ(tcph) + p->payload_len;
2704
2705 SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
2706 ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2707 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2708
2709 if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2710 ssn->client.window = TCP_GET_RAW_WINDOW(tcph);
2711 ssn->server.next_win = ssn->server.last_ack +
2712 ssn->server.window;
2713 /* window scaling for midstream pickups, we can't do much
2714 * other than assume that it's set to the max value: 14 */
2718 }
2719
2720 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2721 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2722
2723 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2724
2725 /* toclient packet: after having missed the 3whs's final ACK */
2726 } else if ((ack_indicates_missed_3whs_ack_packet ||
2728 SEQ_EQ(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack) &&
2729 SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq)) {
2730 if (ack_indicates_missed_3whs_ack_packet) {
2731 SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2732 } else {
2733 SCLogDebug("ssn %p: (TFO) expected packet fits perfectly after SYN/ACK", ssn);
2734 }
2735
2736 StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_RAW_SEQ(tcph) + p->payload_len));
2737
2738 ssn->server.window = TCP_GET_RAW_WINDOW(tcph) << ssn->server.wscale;
2739 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2740
2741 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2742 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2743
2744 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
2745
2746 } else {
2747 SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2748
2750 return -1;
2751 }
2752
2753 SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2754 "ssn->server.last_ack %"PRIu32"", ssn,
2755 ssn->server.next_win, ssn->server.last_ack);
2756 } else {
2757 SCLogDebug("ssn %p: default case", ssn);
2758 }
2759
2760 return 0;
2761}
2762
2763/**
2764 * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2765 * sent by the client to server. The function handles
2766 * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2767 * the reassembly.
2768 *
2769 * Timestamp has already been checked at this point.
2770 *
2771 * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2772 * \param ssn Pointer to the current TCP session
2773 * \param p Packet which has to be handled in this TCP state.
2774 * \param stt Stream Thread module registered to handle the stream handling
2775 */
2776static int HandleEstablishedPacketToServer(
2778{
2779 const TCPHdr *tcph = PacketGetTCP(p);
2780 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
2781 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
2782 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
2783
2784 SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2785 "ACK %" PRIu32 ", WIN %" PRIu16 "",
2786 ssn, p->payload_len, seq, ack, window);
2787
2788 const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
2789 if (has_ack) {
2790 if ((ssn->flags & STREAMTCP_FLAG_ZWP_TC) && ack == ssn->server.next_seq + 1) {
2791 SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2793
2794 } else if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2795 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2797 return -1;
2798 }
2799 }
2800
2801 /* check for Keep Alive */
2802 if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->client.next_seq - 1))) {
2803 SCLogDebug("ssn %p: pkt is keep alive", ssn);
2804
2805 /* normal pkt */
2806 } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->client.last_ack))) {
2807 if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2808 SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2809 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2810 " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2811 "%" PRIu32 "(%" PRIu32 ")",
2812 ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2813 ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2814
2815 /* update the last_ack to current seq number as the session is
2816 * async and other stream is not updating it anymore :( */
2817 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2818
2819 } else if (SEQ_EQ(ssn->client.next_seq, seq) && stream_config.async_oneside &&
2821 SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2822 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2823 "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2824 "%" PRIu32 "(%" PRIu32 ")",
2825 ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2826 ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2827
2828 /* it seems we missed SYN and SYN/ACK packets of this session.
2829 * Update the last_ack to current seq number as the session
2830 * is async and other stream is not updating it anymore :( */
2831 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2833
2834 } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2836 SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2837 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2838 "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2839 "%" PRIu32 "(%" PRIu32 ")",
2840 ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2841 ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2842
2843 /* it seems we missed SYN and SYN/ACK packets of this session.
2844 * Update the last_ack to current seq number as the session
2845 * is async and other stream is not updating it anymore :(*/
2846 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
2848
2849 /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2850 * In this case we do accept the data before last_ack if it is (partly)
2851 * beyond next seq */
2852 } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
2853 SEQ_GT((seq + p->payload_len), ssn->client.next_seq)) {
2854 SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
2855 " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
2856 " acked data that we haven't seen before",
2857 ssn, seq, p->payload_len, ssn->client.last_ack, ssn->client.next_seq);
2858 } else {
2859 SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
2860 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2861 "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2862 "%" PRIu32 "(%" PRIu32 ")",
2863 ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2864 ssn->client.next_win, seq + p->payload_len - ssn->client.next_win);
2865
2866 SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
2868 return -1;
2869 }
2870 }
2871
2872 int zerowindowprobe = 0;
2873 /* zero window probe */
2874 if (p->payload_len == 1 && seq == ssn->client.next_seq && ssn->client.window == 0) {
2875 SCLogDebug("ssn %p: zero window probe", ssn);
2876 zerowindowprobe = 1;
2879 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2880
2881 } else if (SEQ_GEQ(seq + p->payload_len, ssn->client.next_seq)) {
2882 StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
2883 }
2884
2885 /* in window check */
2886 if (zerowindowprobe) {
2887 SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2888 } else if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
2890 SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
2891 "%" PRIu32 "",
2892 ssn, seq, ssn->client.next_win);
2893
2894 ssn->server.window = window << ssn->server.wscale;
2895 SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
2896 ssn->server.window);
2897
2898 /* Check if the ACK value is sane and inside the window limit */
2899 if (tcph->th_flags & TH_ACK) {
2900 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
2901 if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
2902 SEQ_GT(ssn->server.last_ack, ssn->server.next_seq)) {
2905 }
2906 }
2907
2908 SCLogDebug(
2909 "ack %u last_ack %u next_seq %u", ack, ssn->server.last_ack, ssn->server.next_seq);
2910
2911 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2912 StreamTcpHandleTimestamp(ssn, p);
2913 }
2914
2916
2917 /* update next_win */
2918 StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
2919
2920 /* handle data (if any) */
2921 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
2922
2923 } else {
2924 SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
2925 "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2926 "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2927 "%" PRIu32 "(%" PRIu32 ")",
2928 ssn, seq, p->payload_len, seq + p->payload_len, ssn->client.last_ack,
2929 ssn->client.next_win, (seq + p->payload_len) - ssn->client.next_win);
2930 SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
2931 StreamTcpSackedSize(&ssn->client));
2933 return -1;
2934 }
2935 return 0;
2936}
2937
2938/**
2939 * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2940 * sent by the server to client. The function handles
2941 * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2942 * the reassembly
2943 *
2944 * Timestamp has already been checked at this point.
2945 *
2946 * \param tv Thread Variable containing input/output queue, cpu affinity etc.
2947 * \param ssn Pointer to the current TCP session
2948 * \param p Packet which has to be handled in this TCP state.
2949 * \param stt Stream Thread module registered to handle the stream handling
2950 */
2951static int HandleEstablishedPacketToClient(
2953{
2954 const TCPHdr *tcph = PacketGetTCP(p);
2955 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
2956 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
2957 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
2958
2959 SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
2960 " ACK %" PRIu32 ", WIN %" PRIu16 "",
2961 ssn, p->payload_len, seq, ack, window);
2962
2963 const bool has_ack = (tcph->th_flags & TH_ACK) != 0;
2964 if (has_ack) {
2965 if ((ssn->flags & STREAMTCP_FLAG_ZWP_TS) && ack == ssn->client.next_seq + 1) {
2966 SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
2968
2969 } else if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2970 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2972 return -1;
2973 }
2974 }
2975
2976 /* To get the server window value from the servers packet, when connection
2977 is picked up as midstream */
2978 if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
2980 {
2981 ssn->server.window = window << ssn->server.wscale;
2982 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2983 ssn->flags &= ~STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED;
2984 SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
2985 "%" PRIu32 "", ssn, ssn->server.next_win);
2986 }
2987
2988 /* check for Keep Alive */
2989 if ((p->payload_len == 0 || p->payload_len == 1) && (seq == (ssn->server.next_seq - 1))) {
2990 SCLogDebug("ssn %p: pkt is keep alive", ssn);
2991
2992 /* normal pkt */
2993 } else if (!(SEQ_GEQ((seq + p->payload_len), ssn->server.last_ack))) {
2994 if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2995
2996 SCLogDebug("ssn %p: client => Asynchronous stream, packet SEQ"
2997 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2998 " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2999 " %" PRIu32 "(%" PRIu32 ")",
3000 ssn, seq, p->payload_len, seq + p->payload_len, ssn->server.last_ack,
3001 ssn->server.next_win, seq + p->payload_len - ssn->server.next_win);
3002
3003 ssn->server.last_ack = seq;
3004
3005 /* if last ack is beyond next_seq, we have accepted ack's for missing data.
3006 * In this case we do accept the data before last_ack if it is (partly)
3007 * beyond next seq */
3008 } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
3009 SEQ_GT((seq + p->payload_len), ssn->server.next_seq)) {
3010 SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
3011 " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":"
3012 " acked data that we haven't seen before",
3013 ssn, seq, p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
3014 } else {
3015 SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16
3016 " before last_ack %" PRIu32 ". next_seq %" PRIu32,
3017 ssn, seq, p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
3019 return -1;
3020 }
3021 }
3022
3023 int zerowindowprobe = 0;
3024 /* zero window probe */
3025 if (p->payload_len == 1 && seq == ssn->server.next_seq && ssn->server.window == 0) {
3026 SCLogDebug("ssn %p: zero window probe", ssn);
3027 zerowindowprobe = 1;
3030
3031 /* accept the segment */
3032 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3033
3034 } else if (SEQ_GEQ(seq + p->payload_len, ssn->server.next_seq)) {
3035 StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3036 }
3037
3038 if (zerowindowprobe) {
3039 SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
3040 } else if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
3042 SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
3043 "%" PRIu32 "",
3044 ssn, seq, ssn->server.next_win);
3045 ssn->client.window = window << ssn->client.wscale;
3046 SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
3047 ssn->client.window);
3048
3049 if (tcph->th_flags & TH_ACK) {
3050 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3051 if ((ssn->flags & STREAMTCP_FLAG_ASYNC) == 0 &&
3052 SEQ_GT(ssn->client.last_ack, ssn->client.next_seq)) {
3055 }
3056 }
3057
3058 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3059 StreamTcpHandleTimestamp(ssn, p);
3060 }
3061
3063
3064 StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3065
3066 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3067 } else {
3068 SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
3069 "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
3070 " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
3071 "%" PRIu32 "(%" PRIu32 ")",
3072 ssn, seq, p->payload_len, seq + p->payload_len, ssn->server.last_ack,
3073 ssn->server.next_win, seq + p->payload_len - ssn->server.next_win);
3075 return -1;
3076 }
3077 return 0;
3078}
3079
3080static bool StreamTcpPacketIsZeroWindowProbeAck(const TcpSession *ssn, const Packet *p)
3081{
3082 const TCPHdr *tcph = PacketGetTCP(p);
3083 if (ssn->state < TCP_ESTABLISHED)
3084 return false;
3085 if (p->payload_len != 0)
3086 return false;
3087 if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3088 return false;
3089
3090 const TcpStream *snd, *rcv;
3091 if (PKT_IS_TOCLIENT(p)) {
3092 snd = &ssn->server;
3093 rcv = &ssn->client;
3094 if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TS))
3095 return false;
3096 } else {
3097 snd = &ssn->client;
3098 rcv = &ssn->server;
3099 if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TC))
3100 return false;
3101 }
3102
3103 const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3104 if (pkt_win != 0)
3105 return false;
3106 if (pkt_win != rcv->window)
3107 return false;
3108
3109 if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3110 return false;
3111 if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3112 return false;
3113 SCLogDebug("ssn %p: packet %" PRIu64 " is a Zero Window Probe ACK", ssn, p->pcap_cnt);
3114 return true;
3115}
3116
3117/** \internal
3118 * \brief check if an ACK packet is a dup-ACK
3119 */
3120static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p)
3121{
3122 const TCPHdr *tcph = PacketGetTCP(p);
3123 if (ssn->state < TCP_ESTABLISHED)
3124 return false;
3125 if (p->payload_len != 0)
3126 return false;
3127 if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3128 return false;
3129
3130 const TcpStream *snd, *rcv;
3131 if (PKT_IS_TOCLIENT(p)) {
3132 snd = &ssn->server;
3133 rcv = &ssn->client;
3134 } else {
3135 snd = &ssn->client;
3136 rcv = &ssn->server;
3137 }
3138
3139 const uint32_t pkt_win = TCP_GET_RAW_WINDOW(tcph) << snd->wscale;
3140 if (pkt_win == 0 || rcv->window == 0)
3141 return false;
3142 if (pkt_win != rcv->window)
3143 return false;
3144
3145 if (TCP_GET_RAW_SEQ(tcph) != snd->next_seq)
3146 return false;
3147 if (TCP_GET_RAW_ACK(tcph) != rcv->last_ack)
3148 return false;
3149
3150 SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn,
3151 p->pcap_cnt, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_ACK(tcph), pkt_win, snd->next_seq,
3152 snd->last_ack, rcv->window, snd->next_seq, rcv->last_ack, rcv->window);
3153 return true;
3154}
3155
3156/** \internal
3157 * \brief check if a ACK packet is outdated so processing can be fast tracked
3158 *
3159 * Consider a packet outdated ack if:
3160 * - state is >= ESTABLISHED
3161 * - ACK < last_ACK
3162 * - SACK acks nothing new
3163 * - packet has no data
3164 * - SEQ == next_SEQ
3165 * - flags has ACK set but don't contain SYN/FIN/RST
3166 *
3167 * \todo the most likely explanation for this packet is that we already
3168 * accepted a "newer" ACK. We will not consider an outdated timestamp
3169 * option an issue for this packet, but we should probably still
3170 * check if the ts isn't too far off.
3171 */
3172static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p)
3173{
3174 const TCPHdr *tcph = PacketGetTCP(p);
3175 if (ssn->state < TCP_ESTABLISHED)
3176 return false;
3177 if (p->payload_len != 0)
3178 return false;
3179 if ((tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
3180 return false;
3181
3182 /* lets see if this is a packet that is entirely eclipsed by earlier ACKs */
3183 if (PKT_IS_TOSERVER(p)) {
3184 if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->client.next_seq) &&
3185 SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->server.last_ack)) {
3186 if (!TCP_HAS_SACK(p)) {
3187 SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3188 ssn->client.next_seq);
3189 return true;
3190 }
3191
3192 if (StreamTcpSackPacketIsOutdated(&ssn->server, p)) {
3193 SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3194 ssn->client.next_seq);
3195 return true;
3196 }
3197 }
3198 } else {
3199 if (SEQ_EQ(TCP_GET_RAW_SEQ(tcph), ssn->server.next_seq) &&
3200 SEQ_LT(TCP_GET_RAW_ACK(tcph), ssn->client.last_ack)) {
3201 if (!TCP_HAS_SACK(p)) {
3202 SCLogDebug("outdated ACK (no SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3203 ssn->client.next_seq);
3204 return true;
3205 }
3206
3207 if (StreamTcpSackPacketIsOutdated(&ssn->client, p)) {
3208 SCLogDebug("outdated ACK (have SACK, SEQ %u vs next_seq %u)", TCP_GET_RAW_SEQ(tcph),
3209 ssn->client.next_seq);
3210 return true;
3211 }
3212 }
3213 }
3214 return false;
3215}
3216
3217/** \internal
3218 * \brief check if packet is before ack'd windows
3219 * If packet is before last ack, we will not accept it
3220 *
3221 * \retval 0 not spurious retransmission
3222 * \retval 1 before last_ack, after base_seq
3223 * \retval 2 before last_ack and base_seq
3224 */
3225static int StreamTcpPacketIsSpuriousRetransmission(const TcpSession *ssn, Packet *p)
3226{
3227 const TcpStream *stream;
3228 if (PKT_IS_TOCLIENT(p)) {
3229 stream = &ssn->server;
3230 } else {
3231 stream = &ssn->client;
3232 }
3233 if (p->payload_len == 0)
3234 return 0;
3235
3236 const TCPHdr *tcph = PacketGetTCP(p);
3237 /* take base_seq into account to avoid edge cases where last_ack might be
3238 * too far ahead during heavy packet loss */
3239 if (!(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3240 if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->base_seq))) {
3241 SCLogDebug(
3242 "ssn %p: spurious retransmission; packet entirely before base_seq: SEQ %u(%u) "
3243 "last_ack %u base_seq %u",
3244 ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3245 stream->last_ack, stream->base_seq);
3247 return 2;
3248 }
3249 }
3250
3251 if ((SEQ_LEQ(TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack))) {
3252 SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) "
3253 "last_ack %u",
3254 ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len,
3255 stream->last_ack);
3257 return 1;
3258 }
3259
3260 SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ "
3261 "%u(%u) last_ack %u, base_seq %u",
3262 ssn, TCP_GET_RAW_SEQ(tcph), TCP_GET_RAW_SEQ(tcph) + p->payload_len, stream->last_ack,
3263 stream->base_seq);
3264 return 0;
3265}
3266
3267/**
3268 * \brief Function to handle the TCP_ESTABLISHED state. The function handles
3269 * ACK, FIN, RST packets and correspondingly changes the connection
3270 * state. The function handles the data inside packets and call
3271 * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
3272 *
3273 * \param tv Thread Variable containing input/output queue, cpu affinity etc.
3274 * \param p Packet which has to be handled in this TCP state.
3275 * \param stt Stream Thread module registered to handle the stream handling
3276 */
3277
3278static int StreamTcpPacketStateEstablished(
3280{
3281 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3282 const TCPHdr *tcph = PacketGetTCP(p);
3283 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3284 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3285 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3286
3287 if (tcph->th_flags & TH_RST) {
3288 if (!StreamTcpValidateRst(ssn, p))
3289 return -1;
3290
3291 if (PKT_IS_TOSERVER(p)) {
3292 StreamTcpCloseSsnWithReset(p, ssn);
3293
3294 ssn->server.next_seq = ack;
3295 ssn->client.next_seq = seq + p->payload_len;
3296 SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3297 ssn->server.next_seq);
3298 ssn->client.window = window << ssn->client.wscale;
3299
3300 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3301 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3302
3303 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
3304
3305 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3306 StreamTcpHandleTimestamp(ssn, p);
3307 }
3308
3309 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3310 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3311 "%" PRIu32 "", ssn, ssn->client.next_seq,
3312 ssn->server.last_ack);
3313
3314 /* don't return packets to pools here just yet, the pseudo
3315 * packet will take care, otherwise the normal session
3316 * cleanup. */
3317 } else {
3318 StreamTcpCloseSsnWithReset(p, ssn);
3319
3320 ssn->server.next_seq = seq + p->payload_len + 1;
3321 ssn->client.next_seq = ack;
3322
3323 SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
3324 ssn->server.next_seq);
3325 ssn->server.window = window << ssn->server.wscale;
3326
3327 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3328 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3329
3330 StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
3331
3332 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3333 StreamTcpHandleTimestamp(ssn, p);
3334 }
3335
3336 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3337 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3338 "%" PRIu32 "", ssn, ssn->server.next_seq,
3339 ssn->client.last_ack);
3340
3341 /* don't return packets to pools here just yet, the pseudo
3342 * packet will take care, otherwise the normal session
3343 * cleanup. */
3344 }
3345
3346 } else if (tcph->th_flags & TH_FIN) {
3347 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3348 if (!StreamTcpValidateTimestamp(ssn, p))
3349 return -1;
3350 }
3351
3352 SCLogDebug("ssn (%p: FIN received SEQ"
3353 " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
3354 " win %" PRIu32 "", ssn, ssn->server.next_seq,
3355 ssn->client.last_ack, ssn->server.next_win,
3356 ssn->server.window);
3357
3358 if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1)
3359 return -1;
3360
3361 /* SYN/ACK */
3362 } else if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
3363 SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
3364 ssn);
3365
3366 if (PKT_IS_TOSERVER(p)) {
3367 SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
3368
3370 return -1;
3371 }
3372
3373 /* Check if the SYN/ACK packets ACK matches the earlier
3374 * received SYN/ACK packet. */
3375 if (!(SEQ_EQ(ack, ssn->client.last_ack))) {
3376 SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
3377 "%" PRIu32 " from stream",
3378 ssn, ack, ssn->client.isn + 1);
3379
3381 return -1;
3382 }
3383
3384 /* Check if the SYN/ACK packet SEQ the earlier
3385 * received SYN packet. */
3386 if (!(SEQ_EQ(seq, ssn->server.isn))) {
3387 SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
3388 "%" PRIu32 " from stream",
3389 ssn, ack, ssn->client.isn + 1);
3390
3392 return -1;
3393 }
3394
3396 /* a resend of a SYN while we are established already -- fishy */
3398 return -1;
3399 }
3400
3401 SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
3402 "Likely due server not receiving final ACK in 3whs", ssn);
3403 return 0;
3404
3405 } else if (tcph->th_flags & TH_SYN) {
3406 SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
3407 if (PKT_IS_TOCLIENT(p)) {
3408 SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
3409
3411 return -1;
3412 }
3413
3414 if (!(SEQ_EQ(ack, ssn->client.isn))) {
3415 SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
3416
3418 return -1;
3419 }
3420
3421 /* a resend of a SYN while we are established already -- fishy */
3423 return -1;
3424
3425 } else if (tcph->th_flags & TH_ACK) {
3426 /* Urgent pointer size can be more than the payload size, as it tells
3427 * the future coming data from the sender will be handled urgently
3428 * until data of size equal to urgent offset has been processed
3429 * (RFC 2147) */
3430
3431 /* If the timestamp option is enabled for both the streams, then
3432 * validate the received packet timestamp value against the
3433 * stream->last_ts. If the timestamp is valid then process the
3434 * packet normally otherwise the drop the packet (RFC 1323) */
3435 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3436 if (!StreamTcpValidateTimestamp(ssn, p))
3437 return -1;
3438 }
3439
3440 if (PKT_IS_TOSERVER(p)) {
3441 /* Process the received packet to server */
3442 HandleEstablishedPacketToServer(tv, ssn, p, stt);
3443
3444 SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3445 " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3446 ssn->client.next_seq, ssn->server.last_ack
3447 ,ssn->client.next_win, ssn->client.window);
3448
3449 } else { /* implied to client */
3450 if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
3452 SCLogDebug("3whs is now confirmed by server");
3453 }
3454
3455 /* Process the received packet to client */
3456 HandleEstablishedPacketToClient(tv, ssn, p, stt);
3457
3458 SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
3459 " next win %" PRIu32 ", win %" PRIu32 "", ssn,
3460 ssn->server.next_seq, ssn->client.last_ack,
3461 ssn->server.next_win, ssn->server.window);
3462 }
3463 } else {
3464 SCLogDebug("ssn %p: default case", ssn);
3465 }
3466
3467 return 0;
3468}
3469
3470/**
3471 * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
3472 * TCP_ESTABLISHED and changes to another TCP state as required.
3473 *
3474 * \param tv Thread Variable containing input/output queue, cpu affinity
3475 * \param p Packet which has to be handled in this TCP state.
3476 * \param stt Stream Thread module registered to handle the stream handling
3477 *
3478 * \retval 0 success
3479 * \retval -1 something wrong with the packet
3480 */
3481
3482static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession *ssn, Packet *p)
3483{
3484 const TCPHdr *tcph = PacketGetTCP(p);
3485 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3486 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3487 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3488
3489 if (PKT_IS_TOSERVER(p)) {
3490 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
3491 " ACK %" PRIu32 "",
3492 ssn, p->payload_len, seq, ack);
3493
3494 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3495 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3497 return -1;
3498 }
3499
3500 const uint32_t pkt_re = seq + p->payload_len;
3501 SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3502 ssn->client.last_ack, ssn->client.next_win);
3503 if (SEQ_GEQ(seq, ssn->client.last_ack) && SEQ_LEQ(pkt_re, ssn->client.next_win)) {
3504 // within expectations
3505 } else {
3506 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3507 "%" PRIu32 " from stream",
3508 ssn, seq, ssn->client.next_seq);
3509
3511 return -1;
3512 }
3513
3514 if (tcph->th_flags & TH_SYN) {
3515 SCLogDebug("ssn %p: FIN+SYN", ssn);
3517 return -1;
3518 }
3519 StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
3520 SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
3521
3522 /* if we accept the FIN, next_seq needs to reflect the FIN */
3523 ssn->client.next_seq = seq + p->payload_len;
3524
3525 SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
3526 ssn->client.next_seq);
3527 ssn->server.window = window << ssn->server.wscale;
3528
3529 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3530 StreamTcpHandleTimestamp(ssn, p);
3531 }
3532
3533 /* Update the next_seq, in case if we have missed the client packet
3534 and server has already received and acked it */
3535 if (SEQ_LT(ssn->server.next_seq, ack))
3536 ssn->server.next_seq = ack;
3537
3538 if (tcph->th_flags & TH_ACK)
3539 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3540
3541 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3542
3543 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3544 ssn, ssn->client.next_seq, ssn->server.last_ack);
3545 } else { /* implied to client */
3546 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
3547 "ACK %" PRIu32 "",
3548 ssn, p->payload_len, seq, ack);
3549
3550 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3551 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3553 return -1;
3554 }
3555
3556 const uint32_t pkt_re = seq + p->payload_len;
3557 SCLogDebug("ssn %p: -> SEQ %u, re %u. last_ack %u next_win %u", ssn, seq, pkt_re,
3558 ssn->server.last_ack, ssn->server.next_win);
3559 if (SEQ_GEQ(seq, ssn->server.last_ack) && SEQ_LEQ(pkt_re, ssn->server.next_win)) {
3560 // within expectations
3561 } else {
3562 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
3563 "%" PRIu32 " from stream (last_ack %u win %u = %u)",
3564 ssn, seq, ssn->server.next_seq, ssn->server.last_ack, ssn->server.window,
3565 (ssn->server.last_ack + ssn->server.window));
3566
3568 return -1;
3569 }
3570
3571 StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
3572 SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
3573
3574 /* if we accept the FIN, next_seq needs to reflect the FIN */
3575 ssn->server.next_seq = seq + p->payload_len + 1;
3576 SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 " updated", ssn, ssn->server.next_seq);
3577
3578 ssn->client.window = window << ssn->client.wscale;
3579
3580 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3581 StreamTcpHandleTimestamp(ssn, p);
3582 }
3583
3584 /* Update the next_seq, in case if we have missed the client packet
3585 and server has already received and acked it */
3586 if (SEQ_LT(ssn->client.next_seq, ack))
3587 ssn->client.next_seq = ack;
3588
3589 if (tcph->th_flags & TH_ACK)
3590 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3591
3592 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3593
3594 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
3595 ssn, ssn->server.next_seq, ssn->client.last_ack);
3596 }
3597
3598 return 0;
3599}
3600
3601/**
3602 * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
3603 * ACK, FIN, RST packets and correspondingly changes the connection
3604 * state.
3605 *
3606 * \param tv Thread Variable containing input/output queue, cpu affinity
3607 * \param p Packet which has to be handled in this TCP state.
3608 * \param stt Stream Thread module registered to handle the stream handling
3609 *
3610 * \retval 0 success
3611 * \retval -1 something wrong with the packet
3612 */
3613
3614static int StreamTcpPacketStateFinWait1(
3616{
3617 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
3618 const TCPHdr *tcph = PacketGetTCP(p);
3619 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
3620 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
3621 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
3622
3623 if (tcph->th_flags & TH_RST) {
3624 if (!StreamTcpValidateRst(ssn, p))
3625 return -1;
3626
3627 StreamTcpCloseSsnWithReset(p, ssn);
3628
3629 if (PKT_IS_TOSERVER(p)) {
3630 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3631 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3632
3633 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
3634
3635 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3636 StreamTcpHandleTimestamp(ssn, p);
3637 }
3638
3639 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3640 } else {
3641 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3642 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3643
3644 StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
3645
3646 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3647 StreamTcpHandleTimestamp(ssn, p);
3648 }
3649
3650 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3651 }
3652
3653 } else if ((tcph->th_flags & (TH_FIN | TH_ACK)) == (TH_FIN | TH_ACK)) {
3654 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3655 if (!StreamTcpValidateTimestamp(ssn, p))
3656 return -1;
3657 }
3658
3659 if (PKT_IS_TOSERVER(p)) {
3660 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3661 "%" PRIu32 ", ACK %" PRIu32 "",
3662 ssn, p->payload_len, seq, ack);
3663 int retransmission = 0;
3664
3665 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3666 SCLogDebug("ssn %p: packet is retransmission", ssn);
3667 retransmission = 1;
3669
3670 } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3671 SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3672 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3673 " != %" PRIu32 " from stream",
3674 ssn, seq, ssn->client.next_seq);
3676 return -1;
3677 }
3678
3679 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3680 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3682 return -1;
3683 }
3684
3685 if (!retransmission) {
3686 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3687 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3688
3689 ssn->server.window = window << ssn->server.wscale;
3690 }
3691
3692 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3693 StreamTcpHandleTimestamp(ssn, p);
3694 }
3695
3696 /* Update the next_seq, in case if we have missed the client
3697 packet and server has already received and acked it */
3698 if (SEQ_LT(ssn->server.next_seq - 1, ack))
3699 ssn->server.next_seq = ack;
3700
3701 if (SEQ_EQ(ssn->client.next_seq, seq)) {
3702 StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3703 }
3704
3705 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3706
3707 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3708
3709 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3710 "%" PRIu32 "", ssn, ssn->client.next_seq,
3711 ssn->server.last_ack);
3712 } else { /* implied to client */
3713 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3714 "%" PRIu32 ", ACK %" PRIu32 "",
3715 ssn, p->payload_len, seq, ack);
3716 int retransmission = 0;
3717
3718 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3719 SCLogDebug("ssn %p: packet is retransmission", ssn);
3720 retransmission = 1;
3722
3723 } else if (SEQ_EQ(ssn->server.next_seq - 1, seq) && SEQ_EQ(ssn->client.last_ack, ack)) {
3724 SCLogDebug("ssn %p: packet is retransmission", ssn);
3725 retransmission = 1;
3727
3728 } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3729 SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3730 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3731 " != %" PRIu32 " from stream",
3732 ssn, seq, ssn->server.next_seq);
3734 return -1;
3735 }
3736
3737 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3738 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3740 return -1;
3741 }
3742
3743 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3744 StreamTcpHandleTimestamp(ssn, p);
3745 }
3746
3747 if (!retransmission) {
3748 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3749 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3750
3751 ssn->client.window = window << ssn->client.wscale;
3752
3753 /* Update the next_seq, in case if we have missed the client
3754 packet and server has already received and acked it */
3755 if (SEQ_LT(ssn->client.next_seq - 1, ack))
3756 ssn->client.next_seq = ack;
3757
3758 if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3759 StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3760 }
3761
3762 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3763 }
3764
3765 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3766
3767 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3768 "%" PRIu32 "", ssn, ssn->server.next_seq,
3769 ssn->client.last_ack);
3770 }
3771
3772 } else if (tcph->th_flags & TH_FIN) {
3773 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3774 if (!StreamTcpValidateTimestamp(ssn, p))
3775 return -1;
3776 }
3777
3778 if (PKT_IS_TOSERVER(p)) {
3779 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3780 "%" PRIu32 ", ACK %" PRIu32 "",
3781 ssn, p->payload_len, seq, ack);
3782 int retransmission = 0;
3783
3784 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3785 SCLogDebug("ssn %p: packet is retransmission", ssn);
3786 retransmission = 1;
3788
3789 } else if (SEQ_LT(seq, ssn->client.next_seq - 1) ||
3790 SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
3791 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3792 " != %" PRIu32 " from stream",
3793 ssn, seq, ssn->client.next_seq);
3795 return -1;
3796 }
3797
3798 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3799 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3801 return -1;
3802 }
3803
3804 if (!retransmission) {
3805 StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3806 SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3807
3808 ssn->server.window = window << ssn->server.wscale;
3809 }
3810
3811 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3812 StreamTcpHandleTimestamp(ssn, p);
3813 }
3814
3815 /* Update the next_seq, in case if we have missed the client
3816 packet and server has already received and acked it */
3817 if (SEQ_LT(ssn->server.next_seq - 1, ack))
3818 ssn->server.next_seq = ack;
3819
3820 if (SEQ_EQ(ssn->client.next_seq - 1, seq)) {
3821 StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3822 }
3823
3824 if (tcph->th_flags & TH_ACK)
3825 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3826
3827 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3828
3829 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3830 "%" PRIu32 "", ssn, ssn->client.next_seq,
3831 ssn->server.last_ack);
3832 } else { /* implied to client */
3833 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3834 "%" PRIu32 ", ACK %" PRIu32 "",
3835 ssn, p->payload_len, seq, ack);
3836
3837 int retransmission = 0;
3838
3839 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3840 SCLogDebug("ssn %p: packet is retransmission", ssn);
3841 retransmission = 1;
3843
3844 } else if (SEQ_LT(seq, ssn->server.next_seq - 1) ||
3845 SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
3846 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3847 " != %" PRIu32 " from stream",
3848 ssn, seq, ssn->server.next_seq);
3850 return -1;
3851 }
3852
3853 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3854 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3856 return -1;
3857 }
3858
3859 if (!retransmission) {
3860 StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3861 SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3862
3863 ssn->client.window = window << ssn->client.wscale;
3864 }
3865
3866 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3867 StreamTcpHandleTimestamp(ssn, p);
3868 }
3869
3870 /* Update the next_seq, in case if we have missed the client
3871 packet and server has already received and acked it */
3872 if (SEQ_LT(ssn->client.next_seq - 1, ack))
3873 ssn->client.next_seq = ack;
3874
3875 if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
3876 StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
3877 }
3878
3879 if (tcph->th_flags & TH_ACK)
3880 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
3881
3882 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
3883
3884 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3885 "%" PRIu32 "", ssn, ssn->server.next_seq,
3886 ssn->client.last_ack);
3887 }
3888 } else if (tcph->th_flags & TH_SYN) {
3889 SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
3891 return -1;
3892
3893 } else if (tcph->th_flags & TH_ACK) {
3894 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3895 if (!StreamTcpValidateTimestamp(ssn, p))
3896 return -1;
3897 }
3898
3899 if (PKT_IS_TOSERVER(p)) {
3900 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3901 "%" PRIu32 ", ACK %" PRIu32 "",
3902 ssn, p->payload_len, seq, ack);
3903 int retransmission = 0;
3904
3905 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3906 SCLogDebug("ssn %p: packet is retransmission", ssn);
3907 retransmission = 1;
3909 }
3910
3911 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3912 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3914 return -1;
3915 }
3916
3917 if (SEQ_LT(ack, ssn->server.next_seq)) {
3918 SCLogDebug(
3919 "ssn %p: ACK's older segment as %u < %u", ssn, ack, ssn->server.next_seq);
3920 } else if (!retransmission) {
3921 if (SEQ_EQ(ack, ssn->server.next_seq)) {
3922 if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
3924 SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
3925 "%" PRIu32 "",
3926 ssn, seq, ssn->client.next_win);
3927 SCLogDebug("seq %u client.next_seq %u", seq, ssn->client.next_seq);
3928 if (seq == ssn->client.next_seq) {
3929 StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3930 SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3931 }
3932 } else {
3933 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3934 " != %" PRIu32 " from stream",
3935 ssn, seq, ssn->client.next_seq);
3936
3938 return -1;
3939 }
3940
3941 ssn->server.window = window << ssn->server.wscale;
3942 }
3943 }
3944
3945 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3946 StreamTcpHandleTimestamp(ssn, p);
3947 }
3948
3949 /* Update the next_seq, in case if we have missed the client
3950 packet and server has already received and acked it */
3951 if (SEQ_LT(ssn->server.next_seq - 1, ack))
3952 ssn->server.next_seq = ack;
3953
3954 if (SEQ_EQ(ssn->client.next_seq, seq)) {
3955 StreamTcpUpdateNextSeq(ssn, &ssn->client, (seq + p->payload_len));
3956 }
3957
3958 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
3959
3961
3962 /* update next_win */
3963 StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3964
3965 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
3966
3967 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3968 "%" PRIu32 "", ssn, ssn->client.next_seq,
3969 ssn->server.last_ack);
3970
3971 } else { /* implied to client */
3972
3973 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3974 "%" PRIu32 ", ACK %" PRIu32 "",
3975 ssn, p->payload_len, seq, ack);
3976
3977 int retransmission = 0;
3978
3979 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3980 SCLogDebug("ssn %p: packet is retransmission", ssn);
3981 retransmission = 1;
3983 }
3984
3985 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3986 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3988 return -1;
3989 }
3990
3991 if (!retransmission) {
3992 if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
3994 SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
3995 "%" PRIu32 "",
3996 ssn, seq, ssn->server.next_win);
3997
3998 if (seq == ssn->server.next_seq - 1) {
3999 StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
4000 SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
4001 }
4002 } else {
4003 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4004 " != %" PRIu32 " from stream",
4005 ssn, seq, ssn->server.next_seq);
4007 return -1;
4008 }
4009
4010 ssn->client.window = window << ssn->client.wscale;
4011 }
4012
4013 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4014 StreamTcpHandleTimestamp(ssn, p);
4015 }
4016
4017 /* Update the next_seq, in case if we have missed the client
4018 packet and server has already received and acked it */
4019 if (SEQ_LT(ssn->client.next_seq - 1, ack))
4020 ssn->client.next_seq = ack;
4021
4022 if (SEQ_EQ(ssn->server.next_seq - 1, seq)) {
4023 StreamTcpUpdateNextSeq(ssn, &ssn->server, (seq + p->payload_len));
4024 }
4025
4026 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4027
4029
4030 /* update next_win */
4031 StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4032
4033 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4034
4035 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4036 "%" PRIu32 "", ssn, ssn->server.next_seq,
4037 ssn->client.last_ack);
4038 }
4039 } else {
4040 SCLogDebug("ssn (%p): default case", ssn);
4041 }
4042
4043 return 0;
4044}
4045
4046/**
4047 * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
4048 * ACK, RST, FIN packets and correspondingly changes the connection
4049 * state.
4050 *
4051 * \param tv Thread Variable containing input/output queue, cpu affinity
4052 * \param p Packet which has to be handled in this TCP state.
4053 * \param stt Stream Thread module registered to handle the stream handling
4054 */
4055
4056static int StreamTcpPacketStateFinWait2(
4058{
4059 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4060 const TCPHdr *tcph = PacketGetTCP(p);
4061 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4062 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4063 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4064
4065 if (tcph->th_flags & TH_RST) {
4066 if (!StreamTcpValidateRst(ssn, p))
4067 return -1;
4068
4069 StreamTcpCloseSsnWithReset(p, ssn);
4070
4071 if (PKT_IS_TOSERVER(p)) {
4072 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4073 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4074
4075 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4076
4077 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4078 StreamTcpHandleTimestamp(ssn, p);
4079 }
4080
4081 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4082 } else {
4083 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4084 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4085
4086 StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4087
4088 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4089 StreamTcpHandleTimestamp(ssn, p);
4090 }
4091
4092 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4093 }
4094
4095 } else if (tcph->th_flags & TH_FIN) {
4096 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4097 if (!StreamTcpValidateTimestamp(ssn, p))
4098 return -1;
4099 }
4100
4101 if (PKT_IS_TOSERVER(p)) {
4102 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4103 "%" PRIu32 ", ACK %" PRIu32 "",
4104 ssn, p->payload_len, seq, ack);
4105 int retransmission = 0;
4106
4107 if (SEQ_EQ(seq, ssn->client.next_seq - 1) && SEQ_EQ(ack, ssn->server.last_ack)) {
4108 SCLogDebug("ssn %p: retransmission", ssn);
4109 retransmission = 1;
4111 } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4112 SCLogDebug("ssn %p: packet is retransmission", ssn);
4113 retransmission = 1;
4115
4116 } else if (SEQ_LT(seq, ssn->client.next_seq) ||
4117 SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4118 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4119 "%" PRIu32 " != %" PRIu32 " from stream",
4120 ssn, seq, ssn->client.next_seq);
4122 return -1;
4123 }
4124
4125 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4126 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4128 return -1;
4129 }
4130
4131 if (!retransmission) {
4132 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4133 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4134
4135 if (SEQ_EQ(ssn->client.next_seq, seq)) {
4137 ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4138 }
4139 ssn->server.window = window << ssn->server.wscale;
4140 }
4141
4142 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4143 StreamTcpHandleTimestamp(ssn, p);
4144 }
4145
4146 /* Update the next_seq, in case if we have missed the client
4147 packet and server has already received and acked it */
4148 if (SEQ_LT(ssn->server.next_seq, ack))
4149 ssn->server.next_seq = ack;
4150
4151 if (tcph->th_flags & TH_ACK)
4152 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4153
4154 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4155
4156 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4157 "%" PRIu32 "", ssn, ssn->client.next_seq,
4158 ssn->server.last_ack);
4159 } else { /* implied to client */
4160 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4161 "%" PRIu32 ", ACK %" PRIu32 "",
4162 ssn, p->payload_len, seq, ack);
4163 int retransmission = 0;
4164
4165 if (SEQ_EQ(seq, ssn->server.next_seq - 1) && SEQ_EQ(ack, ssn->client.last_ack)) {
4166 SCLogDebug("ssn %p: retransmission", ssn);
4167 retransmission = 1;
4169 } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4170 SCLogDebug("ssn %p: packet is retransmission", ssn);
4171 retransmission = 1;
4173
4174 } else if (SEQ_LT(seq, ssn->server.next_seq) ||
4175 SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4176 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
4177 "%" PRIu32 " != %" PRIu32 " from stream",
4178 ssn, seq, ssn->server.next_seq);
4180 return -1;
4181 }
4182
4183 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4184 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4186 return -1;
4187 }
4188
4189 if (!retransmission) {
4190 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4191 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4192
4193 ssn->client.window = window << ssn->client.wscale;
4194 }
4195
4196 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4197 StreamTcpHandleTimestamp(ssn, p);
4198 }
4199
4200 /* Update the next_seq, in case if we have missed the client
4201 packet and server has already received and acked it */
4202 if (SEQ_LT(ssn->client.next_seq, ack))
4203 ssn->client.next_seq = ack;
4204
4205 if (tcph->th_flags & TH_ACK)
4206 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4207
4208 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4209 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4210 "%" PRIu32 "", ssn, ssn->server.next_seq,
4211 ssn->client.last_ack);
4212 }
4213
4214 } else if (tcph->th_flags & TH_SYN) {
4215 SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
4217 return -1;
4218
4219 } else if (tcph->th_flags & TH_ACK) {
4220 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4221 if (!StreamTcpValidateTimestamp(ssn, p))
4222 return -1;
4223 }
4224
4225 if (PKT_IS_TOSERVER(p)) {
4226 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4227 "%" PRIu32 ", ACK %" PRIu32 "",
4228 ssn, p->payload_len, seq, ack);
4229 int retransmission = 0;
4230
4231 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4232 SCLogDebug("ssn %p: packet is retransmission", ssn);
4233 retransmission = 1;
4235 }
4236
4237 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4238 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4240 return -1;
4241 }
4242
4243 if (!retransmission) {
4244 if (SEQ_LEQ(seq + p->payload_len, ssn->client.next_win) ||
4246 SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win "
4247 "%" PRIu32 "",
4248 ssn, seq, ssn->client.next_win);
4249
4250 } else {
4251 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4252 " != %" PRIu32 " from stream",
4253 ssn, seq, ssn->client.next_seq);
4255 return -1;
4256 }
4257
4258 ssn->server.window = window << ssn->server.wscale;
4259 }
4260
4261 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4262 StreamTcpHandleTimestamp(ssn, p);
4263 }
4264
4265 if (SEQ_EQ(ssn->client.next_seq, seq)) {
4266 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4267 }
4268
4269 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4270
4272
4273 /* update next_win */
4274 StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
4275
4276 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4277
4278 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4279 "%" PRIu32 "", ssn, ssn->client.next_seq,
4280 ssn->server.last_ack);
4281 } else { /* implied to client */
4282 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4283 "%" PRIu32 ", ACK %" PRIu32 "",
4284 ssn, p->payload_len, seq, ack);
4285 int retransmission = 0;
4286
4287 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4288 SCLogDebug("ssn %p: packet is retransmission", ssn);
4289 retransmission = 1;
4291 }
4292
4293 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4294 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4296 return -1;
4297 }
4298
4299 if (!retransmission) {
4300 if (SEQ_LEQ(seq + p->payload_len, ssn->server.next_win) ||
4302 SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win "
4303 "%" PRIu32 "",
4304 ssn, seq, ssn->server.next_win);
4305 } else {
4306 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4307 " != %" PRIu32 " from stream",
4308 ssn, seq, ssn->server.next_seq);
4310 return -1;
4311 }
4312
4313 ssn->client.window = window << ssn->client.wscale;
4314 }
4315
4316 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4317 StreamTcpHandleTimestamp(ssn, p);
4318 }
4319
4320 if (SEQ_EQ(ssn->server.next_seq, seq)) {
4321 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4322 }
4323
4324 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4325
4327
4328 /* update next_win */
4329 StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
4330
4331 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4332
4333 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4334 "%" PRIu32 "", ssn, ssn->server.next_seq,
4335 ssn->client.last_ack);
4336 }
4337 } else {
4338 SCLogDebug("ssn %p: default case", ssn);
4339 }
4340
4341 return 0;
4342}
4343
4344/**
4345 * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
4346 * the connection goes to TCP_TIME_WAIT state. The state has been
4347 * reached as both end application has been closed.
4348 *
4349 * \param tv Thread Variable containing input/output queue, cpu affinity
4350 * \param p Packet which has to be handled in this TCP state.
4351 * \param stt Stream Thread module registered to handle the stream handling
4352 */
4353
4354static int StreamTcpPacketStateClosing(
4356{
4357 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4358 const TCPHdr *tcph = PacketGetTCP(p);
4359 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4360 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4361 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4362
4363 if (tcph->th_flags & TH_RST) {
4364 if (!StreamTcpValidateRst(ssn, p))
4365 return -1;
4366
4367 StreamTcpCloseSsnWithReset(p, ssn);
4368
4369 if (PKT_IS_TOSERVER(p)) {
4370 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4371 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4372
4373 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4374
4375 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4376 StreamTcpHandleTimestamp(ssn, p);
4377 }
4378
4379 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4380 } else {
4381 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4382 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4383
4384 StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4385
4386 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4387 StreamTcpHandleTimestamp(ssn, p);
4388 }
4389
4390 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4391 }
4392
4393 } else if (tcph->th_flags & TH_SYN) {
4394 SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
4396 return -1;
4397
4398 } else if (tcph->th_flags & TH_ACK) {
4399 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4400 if (!StreamTcpValidateTimestamp(ssn, p))
4401 return -1;
4402 }
4403
4404 if (PKT_IS_TOSERVER(p)) {
4405 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4406 "%" PRIu32 ", ACK %" PRIu32 "",
4407 ssn, p->payload_len, seq, ack);
4408 int retransmission = 0;
4409 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4410 SCLogDebug("ssn %p: packet is retransmission", ssn);
4411 retransmission = 1;
4413 }
4414
4415 if (seq != ssn->client.next_seq) {
4416 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4417 " != %" PRIu32 " from stream",
4418 ssn, seq, ssn->client.next_seq);
4420 return -1;
4421 }
4422
4423 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4424 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4426 return -1;
4427 }
4428
4429 if (!retransmission) {
4430 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4431 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4432
4433 ssn->client.window = window << ssn->client.wscale;
4434 }
4435
4436 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4437 StreamTcpHandleTimestamp(ssn, p);
4438 }
4439 /* Update the next_seq, in case if we have missed the client
4440 packet and server has already received and acked it */
4441 if (SEQ_LT(ssn->server.next_seq, ack))
4442 ssn->server.next_seq = ack;
4443
4444 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4445
4446 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4447 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4448 "%" PRIu32 "", ssn, ssn->client.next_seq,
4449 ssn->server.last_ack);
4450 } else { /* implied to client */
4451 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4452 "%" PRIu32 ", ACK %" PRIu32 "",
4453 ssn, p->payload_len, seq, ack);
4454 int retransmission = 0;
4455 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4456 SCLogDebug("ssn %p: packet is retransmission", ssn);
4457 retransmission = 1;
4459 }
4460
4461 if (seq != ssn->server.next_seq) {
4462 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4463 " != %" PRIu32 " from stream",
4464 ssn, seq, ssn->server.next_seq);
4466 return -1;
4467 }
4468
4469 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4470 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4472 return -1;
4473 }
4474
4475 if (!retransmission) {
4476 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
4477 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
4478
4479 ssn->client.window = window << ssn->client.wscale;
4480 }
4481
4482 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4483 StreamTcpHandleTimestamp(ssn, p);
4484 }
4485
4486 /* Update the next_seq, in case if we have missed the client
4487 packet and server has already received and acked it */
4488 if (SEQ_LT(ssn->client.next_seq, ack))
4489 ssn->client.next_seq = ack;
4490
4491 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4492
4493 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4494 SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
4495 "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
4496 ssn->server.next_seq, ssn->client.last_ack);
4497 }
4498 } else {
4499 SCLogDebug("ssn %p: default case", ssn);
4500 }
4501
4502 return 0;
4503}
4504
4505/**
4506 * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
4507 * packet from server the connection goes to TCP_LAST_ACK state.
4508 * The state is possible only for server host.
4509 *
4510 * \param tv Thread Variable containing input/output queue, cpu affinity
4511 * \param p Packet which has to be handled in this TCP state.
4512 * \param stt Stream Thread module registered to handle the stream handling
4513 */
4514
4515static int StreamTcpPacketStateCloseWait(
4517{
4518 SCEnter();
4519 const TCPHdr *tcph = PacketGetTCP(p);
4520 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4521 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4522 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4523
4524 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4525
4526 if (PKT_IS_TOCLIENT(p)) {
4527 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4528 "%" PRIu32 ", ACK %" PRIu32 "",
4529 ssn, p->payload_len, seq, ack);
4530 } else {
4531 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4532 "%" PRIu32 ", ACK %" PRIu32 "",
4533 ssn, p->payload_len, seq, ack);
4534 }
4535
4536 if (tcph->th_flags & TH_RST) {
4537 if (!StreamTcpValidateRst(ssn, p))
4538 return -1;
4539
4540 StreamTcpCloseSsnWithReset(p, ssn);
4541
4542 if (PKT_IS_TOSERVER(p)) {
4543 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4544 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4545
4546 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4547
4548 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4549 StreamTcpHandleTimestamp(ssn, p);
4550 }
4551
4552 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4553 } else {
4554 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4555 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4556
4557 StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4558
4559 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4560 StreamTcpHandleTimestamp(ssn, p);
4561 }
4562
4563 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4564 }
4565
4566 } else if (tcph->th_flags & TH_FIN) {
4567 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4568 if (!StreamTcpValidateTimestamp(ssn, p))
4569 SCReturnInt(-1);
4570 }
4571
4572 if (PKT_IS_TOSERVER(p)) {
4573 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4574 "%" PRIu32 ", ACK %" PRIu32 "",
4575 ssn, p->payload_len, seq, ack);
4576
4577 int retransmission = 0;
4578 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4579 SCLogDebug("ssn %p: packet is retransmission", ssn);
4580 retransmission = 1;
4582 }
4583
4584 if (!retransmission) {
4585 if (SEQ_LT(seq, ssn->client.next_seq) ||
4586 SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4587 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4588 " != %" PRIu32 " from stream",
4589 ssn, seq, ssn->client.next_seq);
4591 SCReturnInt(-1);
4592 }
4593 }
4594
4595 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4596 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4598 SCReturnInt(-1);
4599 }
4600
4601 /* don't update to LAST_ACK here as we want a toclient FIN for that */
4602
4603 if (!retransmission)
4604 ssn->server.window = window << ssn->server.wscale;
4605
4606 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4607 StreamTcpHandleTimestamp(ssn, p);
4608 }
4609
4610 /* Update the next_seq, in case if we have missed the client
4611 packet and server has already received and acked it */
4612 if (SEQ_LT(ssn->server.next_seq, ack))
4613 ssn->server.next_seq = ack;
4614
4615 if (tcph->th_flags & TH_ACK)
4616 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4617
4618 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4619 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4620 "%" PRIu32 "", ssn, ssn->client.next_seq,
4621 ssn->server.last_ack);
4622 } else {
4623 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4624 "%" PRIu32 ", ACK %" PRIu32 "",
4625 ssn, p->payload_len, seq, ack);
4626
4627 int retransmission = 0;
4628 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4629 SCLogDebug("ssn %p: packet is retransmission", ssn);
4630 retransmission = 1;
4632 }
4633
4634 if (!retransmission) {
4635 if (SEQ_LT(seq, ssn->server.next_seq) ||
4636 SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4637 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4638 " != %" PRIu32 " from stream",
4639 ssn, seq, ssn->server.next_seq);
4641 SCReturnInt(-1);
4642 }
4643 }
4644
4645 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4646 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4648 SCReturnInt(-1);
4649 }
4650
4651 if (!retransmission) {
4652 StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
4653 SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
4654
4655 ssn->client.window = window << ssn->client.wscale;
4656 }
4657
4658 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4659 StreamTcpHandleTimestamp(ssn, p);
4660 }
4661
4662 /* Update the next_seq, in case if we have missed the client
4663 packet and server has already received and acked it */
4664 if (SEQ_LT(ssn->client.next_seq, ack))
4665 ssn->client.next_seq = ack;
4666
4667 if (tcph->th_flags & TH_ACK)
4668 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4669
4670 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4671 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4672 "%" PRIu32 "", ssn, ssn->server.next_seq,
4673 ssn->client.last_ack);
4674 }
4675
4676 } else if (tcph->th_flags & TH_SYN) {
4677 SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
4679 SCReturnInt(-1);
4680
4681 } else if (tcph->th_flags & TH_ACK) {
4682 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4683 if (!StreamTcpValidateTimestamp(ssn, p))
4684 SCReturnInt(-1);
4685 }
4686
4687 if (PKT_IS_TOSERVER(p)) {
4688 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4689 "%" PRIu32 ", ACK %" PRIu32 "",
4690 ssn, p->payload_len, seq, ack);
4691
4692 int retransmission = 0;
4693 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4694 SCLogDebug("ssn %p: packet is retransmission", ssn);
4695 retransmission = 1;
4697 }
4698
4699 if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->client.last_ack))) {
4700 SCLogDebug("ssn %p: -> retransmission", ssn);
4702 SCReturnInt(-1);
4703
4704 } else if (SEQ_GT(seq, (ssn->client.last_ack + ssn->client.window))) {
4705 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4706 " != %" PRIu32 " from stream",
4707 ssn, seq, ssn->client.next_seq);
4709 SCReturnInt(-1);
4710 }
4711
4712 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4713 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4715 SCReturnInt(-1);
4716 }
4717
4718 if (!retransmission) {
4719 ssn->server.window = window << ssn->server.wscale;
4720 }
4721
4722 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4723 StreamTcpHandleTimestamp(ssn, p);
4724 }
4725
4726 /* Update the next_seq, in case if we have missed the client
4727 packet and server has already received and acked it */
4728 if (SEQ_LT(ssn->server.next_seq, ack))
4729 ssn->server.next_seq = ack;
4730
4731 if (SEQ_EQ(seq, ssn->client.next_seq))
4732 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
4733
4734 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4735
4736 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4737 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4738 "%" PRIu32 "", ssn, ssn->client.next_seq,
4739 ssn->server.last_ack);
4740 } else {
4741 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4742 "%" PRIu32 ", ACK %" PRIu32 "",
4743 ssn, p->payload_len, seq, ack);
4744 int retransmission = 0;
4745 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4746 SCLogDebug("ssn %p: packet is retransmission", ssn);
4747 retransmission = 1;
4749 }
4750
4751 if (p->payload_len > 0 && (SEQ_LEQ((seq + p->payload_len), ssn->server.last_ack))) {
4752 SCLogDebug("ssn %p: -> retransmission", ssn);
4754 SCReturnInt(-1);
4755
4756 } else if (SEQ_GT(seq, (ssn->server.last_ack + ssn->server.window))) {
4757 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4758 " != %" PRIu32 " from stream",
4759 ssn, seq, ssn->server.next_seq);
4761 SCReturnInt(-1);
4762 }
4763
4764 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4765 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4767 SCReturnInt(-1);
4768 }
4769
4770 if (!retransmission) {
4771 ssn->client.window = window << ssn->client.wscale;
4772 }
4773
4774 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4775 StreamTcpHandleTimestamp(ssn, p);
4776 }
4777
4778 /* Update the next_seq, in case if we have missed the client
4779 packet and server has already received and acked it */
4780 if (SEQ_LT(ssn->client.next_seq, ack))
4781 ssn->client.next_seq = ack;
4782
4783 if (SEQ_EQ(seq, ssn->server.next_seq))
4784 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4785
4786 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4787
4788 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4789 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4790 "%" PRIu32 "", ssn, ssn->server.next_seq,
4791 ssn->client.last_ack);
4792 }
4793
4794 } else {
4795 SCLogDebug("ssn %p: default case", ssn);
4796 }
4797 SCReturnInt(0);
4798}
4799
4800/**
4801 * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
4802 * the connection goes to TCP_CLOSED state and stream memory is
4803 * returned back to pool. The state is possible only for server host.
4804 *
4805 * \param tv Thread Variable containing input/output queue, cpu affinity
4806 * \param p Packet which has to be handled in this TCP state.
4807 * \param stt Stream Thread module registered to handle the stream handling
4808 */
4809
4810static int StreamTcpPacketStateLastAck(
4812{
4813 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4814 const TCPHdr *tcph = PacketGetTCP(p);
4815 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4816 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4817 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4818
4819 if (tcph->th_flags & TH_RST) {
4820 if (!StreamTcpValidateRst(ssn, p))
4821 return -1;
4822
4823 StreamTcpCloseSsnWithReset(p, ssn);
4824
4825 if (PKT_IS_TOSERVER(p)) {
4826 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4827 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4828
4829 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4830
4831 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4832 StreamTcpHandleTimestamp(ssn, p);
4833 }
4834
4835 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4836 } else {
4837 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4838 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4839
4840 StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4841
4842 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4843 StreamTcpHandleTimestamp(ssn, p);
4844 }
4845
4846 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4847 }
4848
4849 } else if (tcph->th_flags & TH_FIN) {
4850 /** \todo */
4851 SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
4852
4853 } else if (tcph->th_flags & TH_SYN) {
4854 SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
4856 return -1;
4857
4858 } else if (tcph->th_flags & TH_ACK) {
4859 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4860 if (!StreamTcpValidateTimestamp(ssn, p))
4861 return -1;
4862 }
4863
4864 if (PKT_IS_TOSERVER(p)) {
4865 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4866 "%" PRIu32 ", ACK %" PRIu32 "",
4867 ssn, p->payload_len, seq, ack);
4868
4869 int retransmission = 0;
4870 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4871 SCLogDebug("ssn %p: packet is retransmission", ssn);
4872 retransmission = 1;
4874 }
4875
4876 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4877 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4879 SCReturnInt(-1);
4880 }
4881
4882 if (!retransmission) {
4883 if (SEQ_LT(seq, ssn->client.next_seq)) {
4884 SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
4885 } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
4886 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4887 " != %" PRIu32 " from stream",
4888 ssn, seq, ssn->client.next_seq);
4890 return -1;
4891 } else {
4892 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4893 SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4894 }
4895 ssn->server.window = window << ssn->server.wscale;
4896 }
4897
4898 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4899 StreamTcpHandleTimestamp(ssn, p);
4900 }
4901
4902 /* Update the next_seq, in case if we have missed the client
4903 packet and server has already received and acked it */
4904 if (SEQ_LT(ssn->server.next_seq, ack))
4905 ssn->server.next_seq = ack;
4906
4907 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4908
4909 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4910 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4911 "%" PRIu32 "", ssn, ssn->client.next_seq,
4912 ssn->server.last_ack);
4913 }
4914 } else {
4915 SCLogDebug("ssn %p: default case", ssn);
4916 }
4917
4918 return 0;
4919}
4920
4921/**
4922 * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
4923 * the connection goes to TCP_CLOSED state and stream memory is
4924 * returned back to pool.
4925 *
4926 * \param tv Thread Variable containing input/output queue, cpu affinity
4927 * \param p Packet which has to be handled in this TCP state.
4928 * \param stt Stream Thread module registered to handle the stream handling
4929 */
4930
4931static int StreamTcpPacketStateTimeWait(
4933{
4934 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
4935 const TCPHdr *tcph = PacketGetTCP(p);
4936 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
4937 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
4938 const uint16_t window = TCP_GET_RAW_WINDOW(tcph);
4939
4940 if (tcph->th_flags & TH_RST) {
4941 if (!StreamTcpValidateRst(ssn, p))
4942 return -1;
4943
4944 StreamTcpCloseSsnWithReset(p, ssn);
4945
4946 if (PKT_IS_TOSERVER(p)) {
4947 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4948 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
4949
4950 StreamTcpUpdateLastAck(ssn, &ssn->client, seq);
4951
4952 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4953 StreamTcpHandleTimestamp(ssn, p);
4954 }
4955
4956 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
4957 } else {
4958 if ((tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4959 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
4960
4961 StreamTcpUpdateLastAck(ssn, &ssn->server, seq);
4962
4963 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4964 StreamTcpHandleTimestamp(ssn, p);
4965 }
4966
4967 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
4968 }
4969
4970 } else if (tcph->th_flags & TH_FIN) {
4971 /** \todo */
4972
4973 } else if (tcph->th_flags & TH_SYN) {
4974 SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
4976 return -1;
4977
4978 } else if (tcph->th_flags & TH_ACK) {
4979 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4980 if (!StreamTcpValidateTimestamp(ssn, p))
4981 return -1;
4982 }
4983
4984 if (PKT_IS_TOSERVER(p)) {
4985 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4986 "%" PRIu32 ", ACK %" PRIu32 "",
4987 ssn, p->payload_len, seq, ack);
4988 int retransmission = 0;
4989 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4990 SCLogDebug("ssn %p: packet is retransmission", ssn);
4991 retransmission = 1;
4993
4994 } else if (seq != ssn->client.next_seq && seq != ssn->client.next_seq + 1) {
4995 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4996 " != %" PRIu32 " from stream",
4997 ssn, seq, ssn->client.next_seq);
4999 return -1;
5000 }
5001
5002 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
5003 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5005 SCReturnInt(-1);
5006 }
5007
5008 if (!retransmission) {
5009 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5010 SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5011
5012 ssn->server.window = window << ssn->server.wscale;
5013 }
5014
5015 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5016 StreamTcpHandleTimestamp(ssn, p);
5017 }
5018
5019 /* Update the next_seq, in case if we have missed the client
5020 packet and server has already received and acked it */
5021 if (SEQ_LT(ssn->server.next_seq, ack))
5022 ssn->server.next_seq = ack;
5023
5024 StreamTcpUpdateLastAck(ssn, &ssn->server, ack);
5025
5026 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5027 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5028 "%" PRIu32 "", ssn, ssn->client.next_seq,
5029 ssn->server.last_ack);
5030 } else {
5031 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
5032 "%" PRIu32 ", ACK %" PRIu32 "",
5033 ssn, p->payload_len, seq, ack);
5034 int retransmission = 0;
5035 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
5036 SCLogDebug("ssn %p: packet is retransmission", ssn);
5037 retransmission = 1;
5039 } else if (seq != ssn->server.next_seq - 1 && seq != ssn->server.next_seq) {
5040 if (p->payload_len > 0 && seq == ssn->server.last_ack) {
5041 SCLogDebug("ssn %p: -> retransmission", ssn);
5042 SCReturnInt(0);
5043 } else {
5044 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
5045 " != %" PRIu32 " from stream",
5046 ssn, seq, ssn->server.next_seq);
5048 return -1;
5049 }
5050 }
5051
5052 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
5053 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5055 SCReturnInt(-1);
5056 }
5057
5058 if (!retransmission) {
5059 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
5060 SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
5061
5062 ssn->client.window = window << ssn->client.wscale;
5063 }
5064
5065 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5066 StreamTcpHandleTimestamp(ssn, p);
5067 }
5068
5069 /* Update the next_seq, in case if we have missed the client
5070 packet and server has already received and acked it */
5071 if (SEQ_LT(ssn->client.next_seq, ack))
5072 ssn->client.next_seq = ack;
5073
5074 StreamTcpUpdateLastAck(ssn, &ssn->client, ack);
5075
5076 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5077 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
5078 "%" PRIu32 "", ssn, ssn->server.next_seq,
5079 ssn->client.last_ack);
5080 }
5081
5082 } else {
5083 SCLogDebug("ssn %p: default case", ssn);
5084 }
5085
5086 return 0;
5087}
5088
5089static int StreamTcpPacketStateClosed(
5091{
5092 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5093
5094 const TCPHdr *tcph = PacketGetTCP(p);
5095 if (tcph->th_flags & TH_RST) {
5096 SCLogDebug("RST on closed state");
5097 return 0;
5098 }
5099
5100 TcpStream *stream = NULL, *ostream = NULL;
5101 if (PKT_IS_TOSERVER(p)) {
5102 stream = &ssn->client;
5103 ostream = &ssn->server;
5104 } else {
5105 stream = &ssn->server;
5106 ostream = &ssn->client;
5107 }
5108
5109 SCLogDebug("stream %s ostream %s",
5110 stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
5111 ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
5112
5113 /* if we've seen a RST on our direction, but not on the other
5114 * see if we perhaps need to continue processing anyway. */
5115 if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
5116 if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5117 if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->pstate) < 0)
5118 return -1;
5119 /* if state is still "closed", it wasn't updated by our dispatch. */
5120 if (ssn->state == TCP_CLOSED)
5121 ssn->state = ssn->pstate;
5122 }
5123 }
5124 return 0;
5125}
5126
5127static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
5128{
5129 if (p->flags & PKT_PSEUDO_STREAM_END) {
5130 return;
5131 }
5132 const TCPHdr *tcph = PacketGetTCP(p);
5133 /* more RSTs are not unusual */
5134 if ((tcph->th_flags & (TH_RST)) != 0) {
5135 return;
5136 }
5137
5138 TcpStream *ostream = NULL;
5139 if (PKT_IS_TOSERVER(p)) {
5140 ostream = &ssn->server;
5141 } else {
5142 ostream = &ssn->client;
5143 }
5144
5145 if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
5146 SCLogDebug("regular packet %"PRIu64" from same sender as "
5147 "the previous RST. Looks like it injected!", p->pcap_cnt);
5148 ostream->flags &= ~STREAMTCP_STREAM_FLAG_RST_RECV;
5149 ssn->flags &= ~STREAMTCP_FLAG_CLOSED_BY_RST;
5151 return;
5152 }
5153}
5154
5155/**
5156 * \retval 1 packet is a keep alive pkt
5157 * \retval 0 packet is not a keep alive pkt
5158 */
5159static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
5160{
5162 return 0;
5163
5164 /* rfc 1122:
5165 An implementation SHOULD send a keep-alive segment with no
5166 data; however, it MAY be configurable to send a keep-alive
5167 segment containing one garbage octet, for compatibility with
5168 erroneous TCP implementations.
5169 */
5170 if (p->payload_len > 1)
5171 return 0;
5172
5173 const TCPHdr *tcph = PacketGetTCP(p);
5174 if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) {
5175 return 0;
5176 }
5177
5178 TcpStream *stream = NULL, *ostream = NULL;
5179 if (PKT_IS_TOSERVER(p)) {
5180 stream = &ssn->client;
5181 ostream = &ssn->server;
5182 } else {
5183 stream = &ssn->server;
5184 ostream = &ssn->client;
5185 }
5186
5187 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
5188 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
5189 if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
5190 SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
5193 return 1;
5194 }
5195 SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
5196 return 0;
5197}
5198
5199/**
5200 * \retval 1 packet is a keep alive ACK pkt
5201 * \retval 0 packet is not a keep alive ACK pkt
5202 */
5203static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
5204{
5205 TcpStream *stream = NULL, *ostream = NULL;
5206 uint32_t seq;
5207 uint32_t ack;
5208 uint32_t pkt_win;
5209
5211 return 0;
5212 /* should get a normal ACK to a Keep Alive */
5213 if (p->payload_len > 0)
5214 return 0;
5215
5216 const TCPHdr *tcph = PacketGetTCP(p);
5217 if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5218 return 0;
5219
5220 if (TCP_GET_RAW_WINDOW(tcph) == 0)
5221 return 0;
5222
5223 if (PKT_IS_TOSERVER(p)) {
5224 stream = &ssn->client;
5225 ostream = &ssn->server;
5226 } else {
5227 stream = &ssn->server;
5228 ostream = &ssn->client;
5229 }
5230
5231 seq = TCP_GET_RAW_SEQ(tcph);
5232 ack = TCP_GET_RAW_ACK(tcph);
5233
5234 pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5235 if (pkt_win != ostream->window)
5236 return 0;
5237
5238 if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
5239 SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
5240 ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
5242 return 1;
5243 }
5244 SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
5245 ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
5246 return 0;
5247}
5248
5249static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
5250{
5251 TcpStream *stream = NULL;
5252
5254 return;
5255
5256 if (PKT_IS_TOSERVER(p)) {
5257 stream = &ssn->client;
5258 } else {
5259 stream = &ssn->server;
5260 }
5261
5262 if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
5263 stream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
5264 SCLogDebug("FLAG_KEEPALIVE cleared");
5265 }
5266}
5267
5268/**
5269 * \retval 1 packet is a window update pkt
5270 * \retval 0 packet is not a window update pkt
5271 */
5272static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
5273{
5274 TcpStream *stream = NULL, *ostream = NULL;
5275 uint32_t seq;
5276 uint32_t ack;
5277 uint32_t pkt_win;
5278
5280 return 0;
5281
5282 if (ssn->state < TCP_ESTABLISHED)
5283 return 0;
5284
5285 if (p->payload_len > 0)
5286 return 0;
5287
5288 const TCPHdr *tcph = PacketGetTCP(p);
5289 if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5290 return 0;
5291
5292 if (TCP_GET_RAW_WINDOW(tcph) == 0)
5293 return 0;
5294
5295 if (PKT_IS_TOSERVER(p)) {
5296 stream = &ssn->client;
5297 ostream = &ssn->server;
5298 } else {
5299 stream = &ssn->server;
5300 ostream = &ssn->client;
5301 }
5302
5303 seq = TCP_GET_RAW_SEQ(tcph);
5304 ack = TCP_GET_RAW_ACK(tcph);
5305
5306 pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5307 if (pkt_win == ostream->window)
5308 return 0;
5309
5310 if (ack == ostream->last_ack && seq == stream->next_seq) {
5311 SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
5313 return 1;
5314 }
5315 SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5316 return 0;
5317}
5318
5319/**
5320 * Try to detect whether a packet is a valid FIN 4whs final ack.
5321 *
5322 */
5323static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
5324{
5325 TcpStream *stream = NULL, *ostream = NULL;
5326 uint32_t seq;
5327 uint32_t ack;
5328
5330 return 0;
5331 if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
5332 return 0;
5333 const TCPHdr *tcph = PacketGetTCP(p);
5334 if (tcph->th_flags != TH_ACK)
5335 return 0;
5336 if (p->payload_len != 0)
5337 return 0;
5338
5339 if (PKT_IS_TOSERVER(p)) {
5340 stream = &ssn->client;
5341 ostream = &ssn->server;
5342 } else {
5343 stream = &ssn->server;
5344 ostream = &ssn->client;
5345 }
5346
5347 seq = TCP_GET_RAW_SEQ(tcph);
5348 ack = TCP_GET_RAW_ACK(tcph);
5349
5350 SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
5351 p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
5352
5353 if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
5354 return 1;
5355 }
5356 return 0;
5357}
5358
5359/**
5360 * Try to detect packets doing bad window updates
5361 *
5362 * See bug 1238.
5363 *
5364 * Find packets that are unexpected, and shrink the window to the point
5365 * where the packets we do expect are rejected for being out of window.
5366 *
5367 * The logic we use here is:
5368 * - packet seq > next_seq
5369 * - packet ack > next_seq (packet acks unseen data)
5370 * - packet shrinks window more than it's own data size
5371 * - packet shrinks window more than the diff between it's ack and the
5372 * last_ack value
5373 *
5374 * Packets coming in after packet loss can look quite a bit like this.
5375 */
5376static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
5377{
5378 TcpStream *stream = NULL, *ostream = NULL;
5379 uint32_t seq;
5380 uint32_t ack;
5381 uint32_t pkt_win;
5382
5384 return 0;
5385
5386 if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
5387 return 0;
5388
5389 const TCPHdr *tcph = PacketGetTCP(p);
5390 if ((tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0)
5391 return 0;
5392
5393 if (PKT_IS_TOSERVER(p)) {
5394 stream = &ssn->client;
5395 ostream = &ssn->server;
5396 } else {
5397 stream = &ssn->server;
5398 ostream = &ssn->client;
5399 }
5400
5401 seq = TCP_GET_RAW_SEQ(tcph);
5402 ack = TCP_GET_RAW_ACK(tcph);
5403 pkt_win = TCP_GET_RAW_WINDOW(tcph) << ostream->wscale;
5404
5405 if (pkt_win < ostream->window) {
5406 uint32_t diff = ostream->window - pkt_win;
5407 if (diff > p->payload_len &&
5408 SEQ_GT(ack, ostream->next_seq) &&
5409 SEQ_GT(seq, stream->next_seq))
5410 {
5411 SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
5412 p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
5413 SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
5414 p->pcap_cnt, pkt_win, ostream->window);
5415 SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
5416 p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
5417 ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
5418
5419 /* get the expected window shrinking from looking at ack vs last_ack.
5420 * Observed a lot of just a little overrunning that value. So added some
5421 * margin that is still ok. To make sure this isn't a loophole to still
5422 * close the window, this is limited to windows above 1024. Both values
5423 * are rather arbitrary. */
5424 uint32_t adiff = ack - ostream->last_ack;
5425 if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
5426 ((pkt_win <= 1024) && (diff > adiff)))
5427 {
5428 SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
5429 "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
5430 SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
5432 return 1;
5433 }
5434 }
5435
5436 }
5437 SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
5438 return 0;
5439}
5440
5441/** \internal
5442 * \brief call packet handling function for 'state'
5443 * \param state current TCP state
5444 */
5445static inline int StreamTcpStateDispatch(
5446 ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state)
5447{
5448 DEBUG_VALIDATE_BUG_ON(ssn == NULL);
5449
5450 SCLogDebug("ssn: %p", ssn);
5451 switch (state) {
5452 case TCP_SYN_SENT:
5453 SCLogDebug("packet received on TCP_SYN_SENT state");
5454 if (StreamTcpPacketStateSynSent(tv, p, stt, ssn)) {
5455 return -1;
5456 }
5457 break;
5458 case TCP_SYN_RECV:
5459 SCLogDebug("packet received on TCP_SYN_RECV state");
5460 if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn)) {
5461 return -1;
5462 }
5463 break;
5464 case TCP_ESTABLISHED:
5465 SCLogDebug("packet received on TCP_ESTABLISHED state");
5466 if (StreamTcpPacketStateEstablished(tv, p, stt, ssn)) {
5467 return -1;
5468 }
5469 break;
5470 case TCP_FIN_WAIT1:
5471 SCLogDebug("packet received on TCP_FIN_WAIT1 state");
5472 if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn)) {
5473 return -1;
5474 }
5475 break;
5476 case TCP_FIN_WAIT2:
5477 SCLogDebug("packet received on TCP_FIN_WAIT2 state");
5478 if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn)) {
5479 return -1;
5480 }
5481 break;
5482 case TCP_CLOSING:
5483 SCLogDebug("packet received on TCP_CLOSING state");
5484 if (StreamTcpPacketStateClosing(tv, p, stt, ssn)) {
5485 return -1;
5486 }
5487 break;
5488 case TCP_CLOSE_WAIT:
5489 SCLogDebug("packet received on TCP_CLOSE_WAIT state");
5490 if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn)) {
5491 return -1;
5492 }
5493 break;
5494 case TCP_LAST_ACK:
5495 SCLogDebug("packet received on TCP_LAST_ACK state");
5496 if (StreamTcpPacketStateLastAck(tv, p, stt, ssn)) {
5497 return -1;
5498 }
5499 break;
5500 case TCP_TIME_WAIT:
5501 SCLogDebug("packet received on TCP_TIME_WAIT state");
5502 if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn)) {
5503 return -1;
5504 }
5505 break;
5506 case TCP_CLOSED:
5507 /* TCP session memory is not returned to pool until timeout. */
5508 SCLogDebug("packet received on closed state");
5509
5510 if (StreamTcpPacketStateClosed(tv, p, stt, ssn)) {
5511 return -1;
5512 }
5513
5514 break;
5515 default:
5516 SCLogDebug("packet received on default state");
5517 break;
5518 }
5519 return 0;
5520}
5521
5522static inline void CheckThreadId(ThreadVars *tv, Packet *p, StreamTcpThread *stt)
5523{
5524 const int idx = (!(PKT_IS_TOSERVER(p)));
5525
5526 /* assign the thread id to the flow */
5527 if (likely(p->flow->thread_id[idx] != 0)) {
5528 if (unlikely((FlowThreadId)tv->id != p->flow->thread_id[idx])) {
5529 SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id[idx], tv->id);
5530 if (p->pkt_src == PKT_SRC_WIRE) {
5532 if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
5535 }
5536 }
5537 }
5538 }
5539}
5540
5541/* flow is and stays locked */
5544{
5545 SCEnter();
5546
5548
5549 SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
5550
5551 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
5552 const TCPHdr *tcph = PacketGetTCP(p);
5553
5554 /* track TCP flags */
5555 if (ssn != NULL) {
5556 ssn->tcp_packet_flags |= tcph->th_flags;
5557 if (PKT_IS_TOSERVER(p))
5558 ssn->client.tcp_flags |= tcph->th_flags;
5559 else if (PKT_IS_TOCLIENT(p))
5560 ssn->server.tcp_flags |= tcph->th_flags;
5561
5562 /* check if we need to unset the ASYNC flag */
5563 if (ssn->flags & STREAMTCP_FLAG_ASYNC &&
5564 ssn->client.tcp_flags != 0 &&
5565 ssn->server.tcp_flags != 0)
5566 {
5567 SCLogDebug("ssn %p: removing ASYNC flag as we have packets on both sides", ssn);
5568 ssn->flags &= ~STREAMTCP_FLAG_ASYNC;
5569 }
5570 }
5571
5572 /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */
5573 if (!(tcph->th_flags & TH_ACK) && TCP_GET_RAW_ACK(tcph) != 0) {
5575 }
5576
5577 if ((tcph->th_flags & TH_URG) && StreamTcpInlineDropUrg()) {
5579 SCLogDebug("dropping urgent packet");
5580 SCReturnInt(0);
5581 }
5582
5583 /* If we are on IPS mode, and got a drop action triggered from
5584 * the IP only module, or from a reassembled msg and/or from an
5585 * applayer detection, then drop the rest of the packets of the
5586 * same stream and avoid inspecting it any further */
5587 if (StreamTcpCheckFlowDrops(p) == 1) {
5589 SCLogDebug("flow triggered a drop rule");
5591 /* return the segments to the pool */
5593 SCReturnInt(0);
5594 }
5595
5596 if (ssn == NULL || ssn->state == TCP_NONE) {
5597 if (StreamTcpPacketStateNone(tv, p, stt, ssn) == -1) {
5598 goto error;
5599 }
5600
5601 if (ssn != NULL)
5602 SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto);
5603 } else {
5604 /* special case for PKT_PSEUDO_STREAM_END packets:
5605 * bypass the state handling and various packet checks,
5606 * we care about reassembly here. */
5607 if (p->flags & PKT_PSEUDO_STREAM_END) {
5608 if (PKT_IS_TOCLIENT(p)) {
5609 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
5610 } else {
5611 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
5612 }
5613 /* straight to 'skip' as we already handled reassembly */
5614 goto skip;
5615 }
5616
5617 if (p->flow->flags & FLOW_WRONG_THREAD) {
5618 /* Stream and/or session in known bad condition. Block events
5619 * from being set. */
5621 }
5622
5623 if (StreamTcpPacketIsKeepAlive(ssn, p) == 1) {
5624 goto skip;
5625 }
5626 if (StreamTcpPacketIsKeepAliveACK(ssn, p) == 1) {
5627 StreamTcpClearKeepAliveFlag(ssn, p);
5628 goto skip;
5629 }
5630 StreamTcpClearKeepAliveFlag(ssn, p);
5631
5632 const bool is_zwp_ack = StreamTcpPacketIsZeroWindowProbeAck(ssn, p);
5633 if (PKT_IS_TOCLIENT(p)) {
5634 ssn->flags &= ~STREAMTCP_FLAG_ZWP_TS;
5635 } else {
5636 ssn->flags &= ~STREAMTCP_FLAG_ZWP_TC;
5637 }
5638 if (is_zwp_ack) {
5640 goto skip;
5641 }
5642
5643 if (StreamTcpPacketIsDupAck(ssn, p)) {
5645 // TODO see if we can skip work on these
5646 }
5647
5648 /* if packet is not a valid window update, check if it is perhaps
5649 * a bad window update that we should ignore (and alert on) */
5650 if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) {
5651 if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0) {
5652 if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
5653 goto skip;
5654 if (StreamTcpPacketIsOutdatedAck(ssn, p))
5655 goto skip;
5656 }
5657 }
5658
5659 int ret = StreamTcpPacketIsSpuriousRetransmission(ssn, p);
5660 if (ret > 0) {
5662 /* skip packet if fully before base_seq */
5663 if (ret == 2)
5664 goto skip;
5665 }
5666
5667 /* handle the per 'state' logic */
5668 if (StreamTcpStateDispatch(tv, p, stt, ssn, ssn->state) < 0)
5669 goto error;
5670
5671 skip:
5672 StreamTcpPacketCheckPostRst(ssn, p);
5673
5674 if (ssn->state >= TCP_ESTABLISHED) {
5675 p->flags |= PKT_STREAM_EST;
5676 }
5677 }
5678
5679 if (ssn != NULL) {
5680 /* recalc the csum on the packet if it was modified */
5681 if (p->flags & PKT_STREAM_MODIFIED) {
5683 }
5684 /* check for conditions that may make us not want to log this packet */
5685
5686 /* streams that hit depth */
5689 {
5690 /* we can call bypass callback, if enabled */
5691 if (StreamTcpBypassEnabled()) {
5693 }
5694 }
5695
5698 {
5700 }
5701
5702 /* encrypted packets */
5705 {
5707 }
5708
5709 if (ssn->flags & STREAMTCP_FLAG_BYPASS) {
5711 } else if (g_detect_disabled &&
5715 {
5716 /* if stream is dead and we have no detect engine at all, bypass. */
5717 SCLogDebug("bypass as stream is dead and we have no rules");
5719 }
5720 }
5721
5722 SCReturnInt(0);
5723
5724error:
5725 /* recalc the csum on the packet if it was modified */
5726 if (p->flags & PKT_STREAM_MODIFIED) {
5728 }
5729
5730 if (StreamTcpInlineDropInvalid()) {
5731 /* disable payload inspection as we're dropping this packet
5732 * anyway. Doesn't disable all detection, so we can still
5733 * match on the stream event that was set. */
5734 DecodeSetNoPayloadInspectionFlag(p);
5736 }
5737 SCReturnInt(-1);
5738}
5739
5740/**
5741 * \brief Function to validate the checksum of the received packet. If the
5742 * checksum is invalid, packet will be dropped, as the end system will
5743 * also drop the packet.
5744 *
5745 * \param p Packet of which checksum has to be validated
5746 * \retval 1 if the checksum is valid, otherwise 0
5747 */
5748static inline int StreamTcpValidateChecksum(Packet *p)
5749{
5750 int ret = 1;
5751
5752 if (p->flags & PKT_IGNORE_CHECKSUM)
5753 return ret;
5754
5755 if (!p->l4.csum_set) {
5756 const TCPHdr *tcph = PacketGetTCP(p);
5757 if (PacketIsIPv4(p)) {
5758 const IPV4Hdr *ip4h = PacketGetIPv4(p);
5759 p->l4.csum = TCPChecksum(ip4h->s_ip_addrs, (uint16_t *)tcph,
5760 (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5761 p->l4.csum_set = true;
5762 } else if (PacketIsIPv6(p)) {
5763 const IPV6Hdr *ip6h = PacketGetIPv6(p);
5764 p->l4.csum = TCPV6Checksum(ip6h->s_ip6_addrs, (uint16_t *)tcph,
5765 (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
5766 p->l4.csum_set = true;
5767 }
5768 }
5769
5770 if (p->l4.csum != 0) {
5771 ret = 0;
5772 if (p->livedev) {
5773 (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1);
5774 } else if (p->pcap_cnt) {
5776 }
5777 }
5778
5779 return ret;
5780}
5781
5782/** \internal
5783 * \brief check if a packet is a valid stream started
5784 * \retval bool true/false */
5785static int TcpSessionPacketIsStreamStarter(const Packet *p)
5786{
5787 const TCPHdr *tcph = PacketGetTCP(p);
5788 if (tcph->th_flags & (TH_RST | TH_FIN)) {
5789 return 0;
5790 }
5791
5792 if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5793 SCLogDebug("packet %" PRIu64 " is a stream starter: %02x", p->pcap_cnt, tcph->th_flags);
5794 return 1;
5795 }
5796
5798 if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5799 SCLogDebug("packet %" PRIu64 " is a midstream stream starter: %02x", p->pcap_cnt,
5800 tcph->th_flags);
5801 return 1;
5802 }
5803 }
5804 return 0;
5805}
5806
5807/** \internal
5808 * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused
5809 * \retval bool true yes reuse, false no keep tracking old ssn */
5810static bool TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn)
5811{
5812 const TCPHdr *tcph = PacketGetTCP(p);
5813 if (FlowGetPacketDirection(f, p) == TOSERVER) {
5814 if (ssn == NULL) {
5815 /* most likely a flow that was picked up after the 3whs, or a flow that
5816 * does not have a session due to memcap issues. */
5817 SCLogDebug("steam starter packet %" PRIu64 ", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5818 return true;
5819 }
5821 SCLogDebug("steam starter packet %" PRIu64
5822 ", ssn %p. STREAMTCP_FLAG_TFO_DATA_IGNORED set. Reuse.",
5823 p->pcap_cnt, ssn);
5824 return true;
5825 }
5826 if (SEQ_EQ(ssn->client.isn, TCP_GET_RAW_SEQ(tcph))) {
5827 SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5828 return false;
5829 }
5830 if (ssn->state >= TCP_LAST_ACK) {
5831 SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5832 return true;
5833 } else if (ssn->state == TCP_NONE) {
5834 SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5835 return true;
5836 } else { // < TCP_LAST_ACK
5837 SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5838 return false;
5839 }
5840
5841 } else {
5842 if (ssn == NULL) {
5843 SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5844 return true;
5845 }
5846 if (ssn->state >= TCP_LAST_ACK) {
5847 SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5848 return true;
5849 } else if (ssn->state == TCP_NONE) {
5850 SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5851 return true;
5852 } else { // < TCP_LAST_ACK
5853 SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5854 return false;
5855 }
5856 }
5857
5858 SCLogDebug("default: how did we get here?");
5859 return false;
5860}
5861
5862/** \internal
5863 * \brief check if ssn is done enough for reuse by syn/ack
5864 * \note should only be called if midstream is enabled
5865 */
5866static bool TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn)
5867{
5868 const TCPHdr *tcph = PacketGetTCP(p);
5869 if (FlowGetPacketDirection(f, p) == TOCLIENT) {
5870 if (ssn == NULL) {
5871 SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
5872 return false;
5873 }
5874 if (SEQ_EQ(ssn->server.isn, TCP_GET_RAW_SEQ(tcph))) {
5875 SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5876 return false;
5877 }
5878 if (ssn->state >= TCP_LAST_ACK) {
5879 SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5880 return true;
5881 } else if (ssn->state == TCP_NONE) {
5882 SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5883 return true;
5884 } else { // < TCP_LAST_ACK
5885 SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5886 return false;
5887 }
5888
5889 } else {
5890 if (ssn == NULL) {
5891 SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5892 return true;
5893 }
5894 if (ssn->state >= TCP_LAST_ACK) {
5895 SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5896 return true;
5897 } else if (ssn->state == TCP_NONE) {
5898 SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5899 return true;
5900 } else { // < TCP_LAST_ACK
5901 SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5902 return false;
5903 }
5904 }
5905
5906 SCLogDebug("default: how did we get here?");
5907 return false;
5908}
5909
5910/** \brief Check if SSN is done enough for reuse
5911 *
5912 * Reuse means a new TCP session reuses the tuple (flow in suri)
5913 *
5914 * \retval bool true if ssn can be reused, false if not */
5915static bool TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn)
5916{
5917 const TCPHdr *tcph = PacketGetTCP(p);
5918 if ((tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
5919 return TcpSessionReuseDoneEnoughSyn(p, f, ssn);
5920 }
5921
5923 if ((tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
5924 return TcpSessionReuseDoneEnoughSynAck(p, f, ssn);
5925 }
5926 }
5927
5928 return false;
5929}
5930
5931bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
5932{
5933 if (p->proto == IPPROTO_TCP && PacketIsTCP(p)) {
5934 if (TcpSessionPacketIsStreamStarter(p) == 1) {
5935 if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) {
5936 return true;
5937 }
5938 }
5939 }
5940 return false;
5941}
5942
5944{
5945 DEBUG_VALIDATE_BUG_ON(p->flow == NULL);
5946 if (unlikely(p->flow == NULL)) {
5947 return TM_ECODE_OK;
5948 }
5949
5950 StreamTcpThread *stt = (StreamTcpThread *)data;
5951
5952 SCLogDebug("p->pcap_cnt %" PRIu64 " direction %s pkt_src %s", p->pcap_cnt,
5953 p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
5954 : "noflow",
5956 t_pcapcnt = p->pcap_cnt;
5957
5958 if (!(PacketIsTCP(p))) {
5959 return TM_ECODE_OK;
5960 }
5961
5962 CheckThreadId(tv, p, stt);
5963
5964 /* only TCP packets with a flow from here */
5965
5966 if (!(p->flags & PKT_PSEUDO_STREAM_END)) {
5968 if (StreamTcpValidateChecksum(p) == 0) {
5970 return TM_ECODE_OK;
5971 }
5972 }
5973 }
5975
5976 (void)StreamTcpPacket(tv, p, stt, pq);
5977
5978 return TM_ECODE_OK;
5979}
5980
5981TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
5982{
5983 SCEnter();
5984 StreamTcpThread *stt = SCCalloc(1, sizeof(StreamTcpThread));
5985 if (unlikely(stt == NULL))
5987 stt->ssn_pool_id = -1;
5989
5990 *data = (void *)stt;
5991
5992 stt->counter_tcp_active_sessions = StatsRegisterCounter("tcp.active_sessions", tv);
5993 stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv);
5994 stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv);
5995 stt->counter_tcp_ssn_from_cache = StatsRegisterCounter("tcp.ssn_from_cache", tv);
5996 stt->counter_tcp_ssn_from_pool = StatsRegisterCounter("tcp.ssn_from_pool", tv);
5998 stream_config.ssn_memcap_policy, "exception_policy.tcp.ssn_memcap.",
5999 IsStreamTcpSessionMemcapExceptionPolicyStatsValid);
6000
6001 stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv);
6002 stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv);
6003 stt->counter_tcp_midstream_pickups = StatsRegisterCounter("tcp.midstream_pickups", tv);
6007 "exception_policy.tcp.midstream.", IsMidstreamExceptionPolicyStatsValid);
6008 } else {
6011 "exception_policy.tcp.midstream.", IsMidstreamExceptionPolicyStatsValid);
6012 }
6013
6014 stt->counter_tcp_wrong_thread = StatsRegisterCounter("tcp.pkt_on_wrong_thread", tv);
6015 stt->counter_tcp_ack_unseen_data = StatsRegisterCounter("tcp.ack_unseen_data", tv);
6016
6017 /* init reassembly ctx */
6019 if (stt->ra_ctx == NULL)
6021
6022 stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv);
6023
6026 "exception_policy.tcp.reassembly.", IsReassemblyMemcapExceptionPolicyStatsValid);
6027
6029 StatsRegisterCounter("tcp.segment_from_cache", tv);
6030 stt->ra_ctx->counter_tcp_segment_from_pool = StatsRegisterCounter("tcp.segment_from_pool", tv);
6031 stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv);
6032 stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv);
6034 stt->ra_ctx->counter_tcp_reass_overlap_diff_data = StatsRegisterCounter("tcp.overlap_diff_data", tv);
6035
6036 stt->ra_ctx->counter_tcp_reass_data_normal_fail = StatsRegisterCounter("tcp.insert_data_normal_fail", tv);
6037 stt->ra_ctx->counter_tcp_reass_data_overlap_fail = StatsRegisterCounter("tcp.insert_data_overlap_fail", tv);
6038 stt->ra_ctx->counter_tcp_urgent_oob = StatsRegisterCounter("tcp.urgent_oob_data", tv);
6039
6040 SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p",
6041 stt, stt->ra_ctx);
6042
6043 SCMutexLock(&ssn_pool_mutex);
6044 if (ssn_pool == NULL) {
6045 ssn_pool = PoolThreadInit(1, /* thread */
6046 0, /* unlimited */
6048 sizeof(TcpSession),
6049 StreamTcpSessionPoolAlloc,
6050 StreamTcpSessionPoolInit, NULL,
6051 StreamTcpSessionPoolCleanup, NULL);
6052 stt->ssn_pool_id = 0;
6053 SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6054 } else {
6055 /* grow ssn_pool until we have a element for our thread id */
6057 SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
6058 }
6059 SCMutexUnlock(&ssn_pool_mutex);
6060 if (stt->ssn_pool_id < 0 || ssn_pool == NULL) {
6061 SCLogError("failed to setup/expand stream session pool. Expand stream.memcap?");
6063 }
6064
6066}
6067
6069{
6070 SCEnter();
6071 StreamTcpThread *stt = (StreamTcpThread *)data;
6072 if (stt == NULL) {
6073 return TM_ECODE_OK;
6074 }
6075
6076 /* XXX */
6077
6078 /* free reassembly ctx */
6080
6081 /* clear memory */
6082 memset(stt, 0, sizeof(StreamTcpThread));
6083
6084 SCFree(stt);
6086}
6087
6088/**
6089 * \brief Function to check the validity of the RST packets based on the
6090 * target OS of the given packet.
6091 *
6092 * \param ssn TCP session to which the given packet belongs
6093 * \param p Packet which has to be checked for its validity
6094 *
6095 * \retval 0 unacceptable RST
6096 * \retval 1 acceptable RST
6097 *
6098 * WebSense sends RST packets that are:
6099 * - RST flag, win 0, ack 0, seq = nextseq
6100 *
6101 */
6102
6103static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
6104{
6105 uint8_t os_policy;
6106 const TCPHdr *tcph = PacketGetTCP(p);
6107 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6108
6110 SCReturnInt(1);
6111 }
6112
6113 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
6114 if (!StreamTcpValidateTimestamp(ssn, p)) {
6115 SCReturnInt(0);
6116 }
6117 }
6118
6119 /* RST with data, it's complicated:
6120
6121 4.2.2.12 RST Segment: RFC-793 Section 3.4
6122
6123 A TCP SHOULD allow a received RST segment to include data.
6124
6125 DISCUSSION
6126 It has been suggested that a RST segment could contain
6127 ASCII text that encoded and explained the cause of the
6128 RST. No standard has yet been established for such
6129 data.
6130 */
6131 if (p->payload_len)
6133
6134 /* Set up the os_policy to be used in validating the RST packets based on
6135 target system */
6136 if (PKT_IS_TOSERVER(p)) {
6137 if (ssn->server.os_policy == 0)
6138 StreamTcpSetOSPolicy(&ssn->server, p);
6139
6140 os_policy = ssn->server.os_policy;
6141
6142 if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6143 StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
6144 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6146 SCReturnInt(0);
6147 }
6148
6149 } else {
6150 if (ssn->client.os_policy == 0)
6151 StreamTcpSetOSPolicy(&ssn->client, p);
6152
6153 os_policy = ssn->client.os_policy;
6154
6155 if (tcph->th_flags & TH_ACK && TCP_GET_RAW_ACK(tcph) &&
6156 StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
6157 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
6159 SCReturnInt(0);
6160 }
6161 }
6162
6163 /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
6164 * validate these (requires key that is set/transferred out of band), we can't know
6165 * if the RST will be accepted or rejected by the end host. We accept it, but keep
6166 * tracking if the sender of it ignores it, which would be a sign of injection. */
6168 TcpStream *receiver_stream;
6169 if (PKT_IS_TOSERVER(p)) {
6170 receiver_stream = &ssn->server;
6171 } else {
6172 receiver_stream = &ssn->client;
6173 }
6174 SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
6175 receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
6176 }
6177
6178 if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
6179 if (PKT_IS_TOSERVER(p)) {
6180 if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6181 SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6182 return 1;
6183 }
6184 } else {
6185 if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6186 SCLogDebug("ssn %p: ASYNC accept RST", ssn);
6187 return 1;
6188 }
6189 }
6190 SCLogDebug("ssn %p: ASYNC reject RST", ssn);
6191 return 0;
6192 }
6193
6194 switch (os_policy) {
6195 case OS_POLICY_HPUX11:
6196 if(PKT_IS_TOSERVER(p)){
6197 if (SEQ_GEQ(seq, ssn->client.next_seq)) {
6198 SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6199 return 1;
6200 } else {
6201 SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " "
6202 "and server SEQ: %" PRIu32 "",
6203 seq, ssn->client.next_seq);
6204 return 0;
6205 }
6206 } else { /* implied to client */
6207 if (SEQ_GEQ(seq, ssn->server.next_seq)) {
6208 SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6209 return 1;
6210 } else {
6211 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6212 "and client SEQ: %" PRIu32 "",
6213 seq, ssn->server.next_seq);
6214 return 0;
6215 }
6216 }
6217 break;
6219 case OS_POLICY_LINUX:
6220 case OS_POLICY_SOLARIS:
6221 if(PKT_IS_TOSERVER(p)){
6222 if (SEQ_GEQ((seq + p->payload_len),
6223 ssn->client.last_ack)) { /*window base is needed !!*/
6224 if (SEQ_LT(seq, (ssn->client.next_seq + ssn->client.window))) {
6225 SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6226 return 1;
6227 }
6228 } else {
6229 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6230 " server SEQ: %" PRIu32 "",
6231 seq, ssn->client.next_seq);
6232 return 0;
6233 }
6234 } else { /* implied to client */
6235 if (SEQ_GEQ((seq + p->payload_len),
6236 ssn->server.last_ack)) { /*window base is needed !!*/
6237 if (SEQ_LT(seq, (ssn->server.next_seq + ssn->server.window))) {
6238 SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", seq);
6239 return 1;
6240 }
6241 } else {
6242 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6243 " client SEQ: %" PRIu32 "",
6244 seq, ssn->server.next_seq);
6245 return 0;
6246 }
6247 }
6248 break;
6249 default:
6250 case OS_POLICY_BSD:
6251 case OS_POLICY_FIRST:
6252 case OS_POLICY_HPUX10:
6253 case OS_POLICY_IRIX:
6254 case OS_POLICY_MACOS:
6255 case OS_POLICY_LAST:
6256 case OS_POLICY_WINDOWS:
6258 case OS_POLICY_VISTA:
6259 if(PKT_IS_TOSERVER(p)) {
6260 if (SEQ_EQ(seq, ssn->client.next_seq)) {
6261 SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", seq);
6262 return 1;
6263 } else {
6264 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
6265 "and server SEQ: %" PRIu32 "",
6266 seq, ssn->client.next_seq);
6267 return 0;
6268 }
6269 } else { /* implied to client */
6270 if (SEQ_EQ(seq, ssn->server.next_seq)) {
6271 SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u", seq,
6272 ssn->server.next_seq);
6273 return 1;
6274 } else {
6275 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
6276 " client SEQ: %" PRIu32 "",
6277 seq, ssn->server.next_seq);
6278 return 0;
6279 }
6280 }
6281 break;
6282 }
6283 return 0;
6284}
6285
6286/**
6287 * \brief Function to check the validity of the received timestamp based on
6288 * the target OS of the given stream.
6289 *
6290 * It's passive except for:
6291 * 1. it sets the os policy on the stream if necessary
6292 * 2. it sets an event in the packet if necessary
6293 *
6294 * \param ssn TCP session to which the given packet belongs
6295 * \param p Packet which has to be checked for its validity
6296 *
6297 * \retval 1 if the timestamp is valid
6298 * \retval 0 if the timestamp is invalid
6299 */
6300static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p)
6301{
6302 SCEnter();
6303
6304 TcpStream *sender_stream;
6305 TcpStream *receiver_stream;
6306 uint8_t ret = 1;
6307 uint8_t check_ts = 1;
6308 const TCPHdr *tcph = PacketGetTCP(p);
6309 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6310
6311 if (PKT_IS_TOSERVER(p)) {
6312 sender_stream = &ssn->client;
6313 receiver_stream = &ssn->server;
6314 } else {
6315 sender_stream = &ssn->server;
6316 receiver_stream = &ssn->client;
6317 }
6318
6319 /* Set up the os_policy to be used in validating the timestamps based on
6320 the target system */
6321 if (receiver_stream->os_policy == 0) {
6322 StreamTcpSetOSPolicy(receiver_stream, p);
6323 }
6324
6325 if (TCP_HAS_TS(p)) {
6326 uint32_t ts = TCP_GET_TSVAL(p);
6327 uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
6328 uint32_t last_ts = sender_stream->last_ts;
6329
6330 if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6331 /* The 3whs used the timestamp with 0 value. */
6332 switch (receiver_stream->os_policy) {
6333 case OS_POLICY_LINUX:
6335 /* Linux and windows 2003 does not allow the use of 0 as
6336 * timestamp in the 3whs. */
6337 check_ts = 0;
6338 break;
6339
6341 case OS_POLICY_WINDOWS:
6342 case OS_POLICY_VISTA:
6343 if (SEQ_EQ(sender_stream->next_seq, seq)) {
6344 last_ts = ts;
6345 check_ts = 0; /*next packet will be checked for validity
6346 and stream TS has been updated with this
6347 one.*/
6348 }
6349 break;
6350 }
6351 }
6352
6353 if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6354 /* HPUX11 ignores the timestamp of out of order packets */
6355 if (!SEQ_EQ(sender_stream->next_seq, seq))
6356 check_ts = 0;
6357 }
6358
6359 if (ts == 0) {
6360 switch (receiver_stream->os_policy) {
6362 case OS_POLICY_WINDOWS:
6364 case OS_POLICY_VISTA:
6365 case OS_POLICY_SOLARIS:
6366 /* Old Linux and windows allowed packet with 0 timestamp. */
6367 break;
6368 default:
6369 /* other OS simply drop the packet with 0 timestamp, when
6370 * 3whs has valid timestamp*/
6371 goto invalid;
6372 }
6373 }
6374
6375 if (check_ts) {
6376 int32_t result = 0;
6377
6378 SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts);
6379
6380 if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6381 /* Linux accepts TS which are off by one.*/
6382 result = (int32_t) ((ts - last_ts) + 1);
6383 } else {
6384 result = (int32_t) (ts - last_ts);
6385 }
6386
6387 SCLogDebug("result %" PRIi32 ", p->ts(secs) %" PRIuMAX "", result,
6388 (uintmax_t)SCTIME_SECS(p->ts));
6389
6390 if (last_pkt_ts == 0 &&
6392 {
6393 last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6394 }
6395
6396 if (result < 0) {
6397 SCLogDebug("timestamp is not valid last_ts "
6398 "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6399 "%" PRId32 "", last_ts, ts, result);
6400 /* candidate for rejection */
6401 ret = 0;
6402 } else if ((sender_stream->last_ts != 0) &&
6403 (((uint32_t)SCTIME_SECS(p->ts)) > last_pkt_ts + PAWS_24DAYS)) {
6404 SCLogDebug("packet is not valid last_pkt_ts "
6405 "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6406 last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6407 /* candidate for rejection */
6408 ret = 0;
6409 }
6410
6411 if (ret == 0) {
6412 /* if the timestamp of packet is not valid then, check if the
6413 * current stream timestamp is not so old. if so then we need to
6414 * accept the packet and update the stream->last_ts (RFC 1323)*/
6415 if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6416 (((uint32_t)SCTIME_SECS(p->ts) > (last_pkt_ts + PAWS_24DAYS)))) {
6417 SCLogDebug("timestamp considered valid anyway");
6418 } else {
6419 goto invalid;
6420 }
6421 }
6422 }
6423 }
6424
6425 SCReturnInt(1);
6426
6427invalid:
6429 SCReturnInt(0);
6430}
6431
6432/**
6433 * \brief Function to check the validity of the received timestamp based on
6434 * the target OS of the given stream and update the session.
6435 *
6436 * \param ssn TCP session to which the given packet belongs
6437 * \param p Packet which has to be checked for its validity
6438 *
6439 * \retval 1 if the timestamp is valid
6440 * \retval 0 if the timestamp is invalid
6441 */
6442static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p)
6443{
6444 SCEnter();
6445
6446 TcpStream *sender_stream;
6447 TcpStream *receiver_stream;
6448 uint8_t ret = 1;
6449 uint8_t check_ts = 1;
6450 const TCPHdr *tcph = PacketGetTCP(p);
6451 const uint32_t seq = TCP_GET_RAW_SEQ(tcph);
6452
6453 if (PKT_IS_TOSERVER(p)) {
6454 sender_stream = &ssn->client;
6455 receiver_stream = &ssn->server;
6456 } else {
6457 sender_stream = &ssn->server;
6458 receiver_stream = &ssn->client;
6459 }
6460
6461 /* Set up the os_policy to be used in validating the timestamps based on
6462 the target system */
6463 if (receiver_stream->os_policy == 0) {
6464 StreamTcpSetOSPolicy(receiver_stream, p);
6465 }
6466
6467 if (TCP_HAS_TS(p)) {
6468 uint32_t ts = TCP_GET_TSVAL(p);
6469
6470 if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
6471 /* The 3whs used the timestamp with 0 value. */
6472 switch (receiver_stream->os_policy) {
6473 case OS_POLICY_LINUX:
6475 /* Linux and windows 2003 does not allow the use of 0 as
6476 * timestamp in the 3whs. */
6477 ssn->flags &= ~STREAMTCP_FLAG_TIMESTAMP;
6478 check_ts = 0;
6479 break;
6480
6482 case OS_POLICY_WINDOWS:
6483 case OS_POLICY_VISTA:
6484 sender_stream->flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
6485 if (SEQ_EQ(sender_stream->next_seq, seq)) {
6486 sender_stream->last_ts = ts;
6487 check_ts = 0; /*next packet will be checked for validity
6488 and stream TS has been updated with this
6489 one.*/
6490 }
6491 break;
6492 default:
6493 break;
6494 }
6495 }
6496
6497 if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
6498 /*HPUX11 ignores the timestamp of out of order packets*/
6499 if (!SEQ_EQ(sender_stream->next_seq, seq))
6500 check_ts = 0;
6501 }
6502
6503 if (ts == 0) {
6504 switch (receiver_stream->os_policy) {
6506 case OS_POLICY_WINDOWS:
6508 case OS_POLICY_VISTA:
6509 case OS_POLICY_SOLARIS:
6510 /* Old Linux and windows allowed packet with 0 timestamp. */
6511 break;
6512 default:
6513 /* other OS simply drop the packet with 0 timestamp, when
6514 * 3whs has valid timestamp*/
6515 goto invalid;
6516 }
6517 }
6518
6519 if (check_ts) {
6520 int32_t result = 0;
6521
6522 SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts);
6523
6524 if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) {
6525 /* Linux accepts TS which are off by one.*/
6526 result = (int32_t) ((ts - sender_stream->last_ts) + 1);
6527 } else {
6528 result = (int32_t) (ts - sender_stream->last_ts);
6529 }
6530
6531 SCLogDebug("result %" PRIi32 ", p->ts(sec) %" PRIuMAX "", result,
6532 (uintmax_t)SCTIME_SECS(p->ts));
6533
6534 if (sender_stream->last_pkt_ts == 0 &&
6536 {
6537 sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6538 }
6539
6540 if (result < 0) {
6541 SCLogDebug("timestamp is not valid sender_stream->last_ts "
6542 "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
6543 "%" PRId32 "", sender_stream->last_ts, ts, result);
6544 /* candidate for rejection */
6545 ret = 0;
6546 } else if ((sender_stream->last_ts != 0) &&
6547 (((uint32_t)SCTIME_SECS(p->ts)) >
6548 sender_stream->last_pkt_ts + PAWS_24DAYS)) {
6549 SCLogDebug("packet is not valid sender_stream->last_pkt_ts "
6550 "%" PRIu32 " p->ts(sec) %" PRIu32 "",
6551 sender_stream->last_pkt_ts, (uint32_t)SCTIME_SECS(p->ts));
6552 /* candidate for rejection */
6553 ret = 0;
6554 }
6555
6556 if (ret == 1) {
6557 /* Update the timestamp and last seen packet time for this
6558 * stream */
6559 if (SEQ_EQ(sender_stream->next_seq, seq))
6560 sender_stream->last_ts = ts;
6561
6562 sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6563
6564 } else if (ret == 0) {
6565 /* if the timestamp of packet is not valid then, check if the
6566 * current stream timestamp is not so old. if so then we need to
6567 * accept the packet and update the stream->last_ts (RFC 1323)*/
6568 if ((SEQ_EQ(sender_stream->next_seq, seq)) &&
6569 (((uint32_t)SCTIME_SECS(p->ts) >
6570 (sender_stream->last_pkt_ts + PAWS_24DAYS)))) {
6571 sender_stream->last_ts = ts;
6572 sender_stream->last_pkt_ts = (uint32_t)SCTIME_SECS(p->ts);
6573
6574 SCLogDebug("timestamp considered valid anyway");
6575 } else {
6576 goto invalid;
6577 }
6578 }
6579 }
6580 } else {
6581 /* Solaris stops using timestamps if a packet is received
6582 without a timestamp and timestamps were used on that stream. */
6583 if (receiver_stream->os_policy == OS_POLICY_SOLARIS)
6584 ssn->flags &= ~STREAMTCP_FLAG_TIMESTAMP;
6585 }
6586
6587 SCReturnInt(1);
6588
6589invalid:
6591 SCReturnInt(0);
6592}
6593
6594/**
6595 * \brief Function to test the received ACK values against the stream window
6596 * and previous ack value. ACK values should be higher than previous
6597 * ACK value and less than the next_win value.
6598 *
6599 * \param ssn TcpSession for state access
6600 * \param stream TcpStream of which last_ack needs to be tested
6601 * \param p Packet which is used to test the last_ack
6602 *
6603 * \retval 0 ACK is valid, last_ack is updated if ACK was higher
6604 * \retval -1 ACK is invalid
6605 */
6606static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p)
6607{
6608 SCEnter();
6609
6610 const TCPHdr *tcph = PacketGetTCP(p);
6611 const uint32_t ack = TCP_GET_RAW_ACK(tcph);
6612
6613 if (!(tcph->th_flags & TH_ACK))
6614 SCReturnInt(0);
6615
6616 /* fast track */
6617 if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win))
6618 {
6619 SCLogDebug("ssn %p: ACK %u in bounds > %u <= %u", ssn, ack, stream->last_ack,
6620 stream->next_win);
6621 SCReturnInt(0);
6622 }
6623 /* fast track */
6624 else if (SEQ_EQ(ack, stream->last_ack)) {
6625 SCLogDebug("ssn %p: pkt ACK %" PRIu32 " == stream last ACK %" PRIu32, ssn, ack,
6626 stream->last_ack);
6627 SCReturnInt(0);
6628 }
6629
6630 /* exception handling */
6631 if (SEQ_LT(ack, stream->last_ack)) {
6632 SCLogDebug("pkt ACK %" PRIu32 " < stream last ACK %" PRIu32, ack, stream->last_ack);
6633
6634 /* This is an attempt to get a 'left edge' value that we can check against.
6635 * It doesn't work when the window is 0, need to think of a better way. */
6636
6637 if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) {
6638 SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window "
6639 "%"PRIu32" = %"PRIu32, ack, stream->last_ack,
6640 stream->window, stream->last_ack - stream->window);
6641 goto invalid;
6642 }
6643
6644 SCReturnInt(0);
6645 }
6646
6647 /* no further checks possible for ASYNC */
6648 if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
6649 SCReturnInt(0);
6650 }
6651
6652 if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) {
6653 SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win);
6654 goto invalid;
6655 /* a toclient RST as a response to SYN, next_win is 0, ack will be isn+1, just like
6656 * the syn ack */
6657 } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && tcph->th_flags & TH_RST &&
6658 SEQ_EQ(ack, stream->isn + 1)) {
6659 SCReturnInt(0);
6660 }
6661
6662 SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32
6663 " next_win %"PRIu32, ack, stream->last_ack, stream->next_win);
6664invalid:
6666 SCReturnInt(-1);
6667}
6668
6669/** \brief update reassembly progress
6670
6671 * \param ssn TCP Session
6672 * \param direction direction to set the flag in: 0 toserver, 1 toclient
6673 */
6675 const uint32_t progress)
6676{
6677 if (direction) {
6678 ssn->server.app_progress_rel += progress;
6679 SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->server));
6680 } else {
6681 ssn->client.app_progress_rel += progress;
6682 SCLogDebug("progress now %" PRIu64, STREAM_APP_PROGRESS(&ssn->client));
6683 }
6684}
6685
6686/** \brief disable reassembly
6687
6688 * Disable app layer and set raw inspect to no longer accept new data.
6689 * Stream engine will then fully disable raw after last inspection.
6690 *
6691 * \param ssn TCP Session to set the flag in
6692 * \param direction direction to set the flag in: 0 toserver, 1 toclient
6693 */
6699
6700/** \brief Set the No reassembly flag for the given direction in given TCP
6701 * session.
6702 *
6703 * \param ssn TCP Session to set the flag in
6704 * \param direction direction to set the flag in: 0 toserver, 1 toclient
6705 */
6711
6712/** \brief enable bypass
6713 *
6714 * \param ssn TCP Session to set the flag in
6715 * \param direction direction to set the flag in: 0 toserver, 1 toclient
6716 */
6721
6722/** \brief Create a pseudo packet injected into the engine to signal the
6723 * opposing direction of this stream trigger detection/logging.
6724 *
6725 * \param parent real packet
6726 * \param pq packet queue to store the new pseudo packet in
6727 * \param dir 0 ts 1 tc
6728 */
6729static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv,
6730 StreamTcpThread *stt, Packet *parent,
6731 TcpSession *ssn, PacketQueueNoLock *pq, int dir)
6732{
6733 SCEnter();
6734 Flow *f = parent->flow;
6735 TCPHdr *tcph = NULL;
6736
6737 if (parent->flags & PKT_PSEUDO_DETECTLOG_FLUSH) {
6738 SCReturn;
6739 }
6740 if ((f->flags & (FLOW_IPV4 | FLOW_IPV6)) == 0) {
6741 SCReturn;
6742 }
6743
6745 if (np == NULL) {
6746 SCReturn;
6747 }
6749
6750 np->tenant_id = f->tenant_id;
6751 np->datalink = DLT_RAW;
6752 np->proto = IPPROTO_TCP;
6753 FlowReference(&np->flow, f);
6754 np->flags |= PKT_STREAM_EST;
6755 np->flags |= PKT_HAS_FLOW;
6758 memcpy(&np->vlan_id[0], &f->vlan_id[0], sizeof(np->vlan_id));
6759 np->vlan_idx = f->vlan_idx;
6760 np->livedev = (struct LiveDevice_ *)f->livedev;
6761
6762 if (parent->flags & PKT_NOPACKET_INSPECTION) {
6763 DecodeSetNoPacketInspectionFlag(np);
6764 }
6765 if (parent->flags & PKT_NOPAYLOAD_INSPECTION) {
6766 DecodeSetNoPayloadInspectionFlag(np);
6767 }
6768
6769 if (dir == 0) {
6770 SCLogDebug("pseudo is to_server");
6772 } else {
6773 SCLogDebug("pseudo is to_client");
6775 }
6777 np->payload = NULL;
6778 np->payload_len = 0;
6779
6780 if (FLOW_IS_IPV4(f)) {
6781 if (dir == 0) {
6784 np->sp = f->sp;
6785 np->dp = f->dp;
6786 } else {
6789 np->sp = f->dp;
6790 np->dp = f->sp;
6791 }
6792
6793 /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
6794 * Force an allocation if it is not the case.
6795 */
6796 if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) {
6797 if (PacketCallocExtPkt(np, 40) == -1) {
6798 goto error;
6799 }
6800 }
6801 /* set the ip header */
6802 IPV4Hdr *ip4h = PacketSetIPV4(np, GET_PKT_DATA(np));
6803 /* version 4 and length 20 bytes for the tcp header */
6804 ip4h->ip_verhl = 0x45;
6805 ip4h->ip_tos = 0;
6806 ip4h->ip_len = htons(40);
6807 ip4h->ip_id = 0;
6808 ip4h->ip_off = 0;
6809 ip4h->ip_ttl = 64;
6810 ip4h->ip_proto = IPPROTO_TCP;
6811 if (dir == 0) {
6812 ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
6813 ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
6814 } else {
6815 ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
6816 ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
6817 }
6818
6819 /* set the tcp header */
6820 tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 20);
6821
6822 SET_PKT_LEN(np, 40); /* ipv4 hdr + tcp hdr */
6823 } else {
6824 /* implied IPv6 */
6825
6826 if (dir == 0) {
6829 np->sp = f->sp;
6830 np->dp = f->dp;
6831 } else {
6834 np->sp = f->dp;
6835 np->dp = f->sp;
6836 }
6837
6838 /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
6839 * Force an allocation if it is not the case.
6840 */
6841 if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) {
6842 if (PacketCallocExtPkt(np, 60) == -1) {
6843 goto error;
6844 }
6845 }
6846 /* set the ip header */
6847 IPV6Hdr *ip6h = PacketSetIPV6(np, GET_PKT_DATA(np));
6848 /* version 6 */
6849 ip6h->s_ip6_vfc = 0x60;
6850 ip6h->s_ip6_flow = 0;
6851 ip6h->s_ip6_nxt = IPPROTO_TCP;
6852 ip6h->s_ip6_plen = htons(20);
6853 ip6h->s_ip6_hlim = 64;
6854 if (dir == 0) {
6855 ip6h->s_ip6_src[0] = f->src.addr_data32[0];
6856 ip6h->s_ip6_src[1] = f->src.addr_data32[1];
6857 ip6h->s_ip6_src[2] = f->src.addr_data32[2];
6858 ip6h->s_ip6_src[3] = f->src.addr_data32[3];
6859 ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
6860 ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
6861 ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
6862 ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
6863 } else {
6864 ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
6865 ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
6866 ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
6867 ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
6868 ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
6869 ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
6870 ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
6871 ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
6872 }
6873
6874 /* set the tcp header */
6875 tcph = PacketSetTCP(np, GET_PKT_DATA(np) + 40);
6876
6877 SET_PKT_LEN(np, 60); /* ipv6 hdr + tcp hdr */
6878 }
6879
6880 tcph->th_offx2 = 0x50;
6881 tcph->th_flags |= TH_ACK;
6882 tcph->th_win = 10;
6883 tcph->th_urp = 0;
6884
6885 /* to server */
6886 if (dir == 0) {
6887 tcph->th_sport = htons(f->sp);
6888 tcph->th_dport = htons(f->dp);
6889
6890 tcph->th_seq = htonl(ssn->client.next_seq);
6891 tcph->th_ack = htonl(ssn->server.last_ack);
6892
6893 /* to client */
6894 } else {
6895 tcph->th_sport = htons(f->dp);
6896 tcph->th_dport = htons(f->sp);
6897
6898 tcph->th_seq = htonl(ssn->server.next_seq);
6899 tcph->th_ack = htonl(ssn->client.last_ack);
6900 }
6901
6902 /* use parent time stamp */
6903 np->ts = parent->ts;
6904
6905 SCLogDebug("np %p", np);
6906 PacketEnqueueNoLock(pq, np);
6907
6909 SCReturn;
6910error:
6911 FlowDeReference(&np->flow);
6912 SCReturn;
6913}
6914
6915/** \brief create packets in both directions to flush out logging
6916 * and detection before switching protocols.
6917 * In IDS mode, create first in packet dir, 2nd in opposing
6918 * In IPS mode, do the reverse.
6919 * Flag TCP engine that data needs to be inspected regardless
6920 * of how far we are wrt inspect limits.
6921 */
6924{
6925 TcpSession *ssn = f->protoctx;
6928 bool ts = PKT_IS_TOSERVER(p) ? true : false;
6930 StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^0);
6931 StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^1);
6932}
6933
6934/**
6935 * \brief Run callback function on each TCP segment in a single direction.
6936 *
6937 * \note when stream engine is running in inline mode all segments are used,
6938 * in IDS/non-inline mode only ack'd segments are iterated.
6939 *
6940 * \note Must be called under flow lock.
6941 * \var flag determines the direction to run callback on (either to server or to client).
6942 *
6943 * \return -1 in case of error, the number of segment in case of success
6944 *
6945 */
6946int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
6947{
6948 TcpStream *stream = NULL;
6949 int cnt = 0;
6950
6951 if (p->flow == NULL)
6952 return 0;
6953
6954 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
6955 if (ssn == NULL) {
6956 return 0;
6957 }
6958
6959 if (flag & STREAM_DUMP_TOSERVER) {
6960 stream = &(ssn->server);
6961 } else {
6962 stream = &(ssn->client);
6963 }
6964
6965 /* for IDS, return ack'd segments. For IPS all. */
6966 TcpSegment *seg;
6967 RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
6969 if (PKT_IS_PSEUDOPKT(p)) {
6970 /* use un-ACK'd data as well */
6971 } else {
6972 /* in IDS mode, use ACK'd data */
6973 if (SEQ_GEQ(seg->seq, stream->last_ack)) {
6974 break;
6975 }
6976 }
6977 }
6978
6979 const uint8_t *seg_data;
6980 uint32_t seg_datalen;
6981 StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
6982
6983 int ret = CallbackFunc(p, seg, data, seg_data, seg_datalen);
6984 if (ret != 1) {
6985 SCLogDebug("Callback function has failed");
6986 return -1;
6987 }
6988
6989 cnt++;
6990 }
6991 return cnt;
6992}
6993
6994/**
6995 * \brief Run callback function on each TCP segment in both directions of a session.
6996 *
6997 * \note when stream engine is running in inline mode all segments are used,
6998 * in IDS/non-inline mode only ack'd segments are iterated.
6999 *
7000 * \note Must be called under flow lock.
7001 *
7002 * \return -1 in case of error, the number of segment in case of success
7003 *
7004 */
7006 const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
7007{
7008 int ret = 0;
7009 int cnt = 0;
7010
7011 if (p->flow == NULL)
7012 return 0;
7013
7014 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
7015
7016 if (ssn == NULL) {
7017 return -1;
7018 }
7019
7020 TcpStream *server_stream = &(ssn->server);
7021 TcpStream *client_stream = &(ssn->client);
7022
7023 TcpSegment *server_node = RB_MIN(TCPSEG, &server_stream->seg_tree);
7024 TcpSegment *client_node = RB_MIN(TCPSEG, &client_stream->seg_tree);
7025 if (server_node == NULL && client_node == NULL) {
7026 return cnt;
7027 }
7028
7029 while (server_node != NULL || client_node != NULL) {
7030 const uint8_t *seg_data;
7031 uint32_t seg_datalen;
7032 if (server_node == NULL) {
7033 /*
7034 * This means the server side RB Tree has been completely searched,
7035 * thus all that remains is to dump the TcpSegments on the client
7036 * side.
7037 */
7039 &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7040 ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7041 if (ret != 1) {
7042 SCLogDebug("Callback function has failed");
7043 return -1;
7044 }
7045 client_node = TCPSEG_RB_NEXT(client_node);
7046 } else if (client_node == NULL) {
7047 /*
7048 * This means the client side RB Tree has been completely searched,
7049 * thus all that remains is to dump the TcpSegments on the server
7050 * side.
7051 */
7053 &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7054 ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7055 if (ret != 1) {
7056 SCLogDebug("Callback function has failed");
7057 return -1;
7058 }
7059 server_node = TCPSEG_RB_NEXT(server_node);
7060 } else {
7061 if (SCTIME_CMP_LT(
7062 client_node->pcap_hdr_storage->ts, server_node->pcap_hdr_storage->ts)) {
7064 &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
7065 ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
7066 if (ret != 1) {
7067 SCLogDebug("Callback function has failed");
7068 return -1;
7069 }
7070 client_node = TCPSEG_RB_NEXT(client_node);
7071 } else {
7073 &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
7074 ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
7075 if (ret != 1) {
7076 SCLogDebug("Callback function has failed");
7077 return -1;
7078 }
7079 server_node = TCPSEG_RB_NEXT(server_node);
7080 }
7081 }
7082
7083 cnt++;
7084 }
7085 return cnt;
7086}
7087
7092
7093/**
7094 * \brief See if stream engine is operating in inline mode
7095 *
7096 * \retval 0 no
7097 * \retval 1 yes
7098 */
7103
7104
7106{
7107 if (size > ssn->reassembly_depth || size == 0) {
7108 ssn->reassembly_depth = size;
7109 }
7110}
7111
7112const char *StreamTcpStateAsString(const enum TcpState state)
7113{
7114 const char *tcp_state = NULL;
7115 switch (state) {
7116 case TCP_NONE:
7117 tcp_state = "none";
7118 break;
7119 case TCP_SYN_SENT:
7120 tcp_state = "syn_sent";
7121 break;
7122 case TCP_SYN_RECV:
7123 tcp_state = "syn_recv";
7124 break;
7125 case TCP_ESTABLISHED:
7126 tcp_state = "established";
7127 break;
7128 case TCP_FIN_WAIT1:
7129 tcp_state = "fin_wait1";
7130 break;
7131 case TCP_FIN_WAIT2:
7132 tcp_state = "fin_wait2";
7133 break;
7134 case TCP_TIME_WAIT:
7135 tcp_state = "time_wait";
7136 break;
7137 case TCP_LAST_ACK:
7138 tcp_state = "last_ack";
7139 break;
7140 case TCP_CLOSE_WAIT:
7141 tcp_state = "close_wait";
7142 break;
7143 case TCP_CLOSING:
7144 tcp_state = "closing";
7145 break;
7146 case TCP_CLOSED:
7147 tcp_state = "closed";
7148 break;
7149 }
7150 return tcp_state;
7151}
7152
7154{
7155 if (ssn == NULL)
7156 return NULL;
7157 return StreamTcpStateAsString(ssn->state);
7158}
7159
7160#ifdef UNITTESTS
7161#include "tests/stream-tcp.c"
7162#endif
#define ACTION_DROP
#define AppLayerProfilingReset(app_tctx)
Definition app-layer.h:127
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition conf.c:181
int SCConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition conf.c:414
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition conf.c:497
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
Definition counters.c:1010
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition counters.c:952
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition counters.c:166
@ STREAM_EST_INVALID_ACK
@ STREAM_EST_PKT_BEFORE_LAST_ACK
@ STREAM_WRONG_THREAD
@ STREAM_LASTACK_ACK_WRONG_SEQ
@ STREAM_EST_SYNACK_RESEND
@ STREAM_RST_BUT_NO_SESSION
@ STREAM_4WHS_WRONG_SEQ
@ STREAM_LASTACK_INVALID_ACK
@ STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV
@ STREAM_3WHS_ACK_IN_WRONG_DIR
@ STREAM_PKT_RETRANSMISSION
@ STREAM_3WHS_SYNACK_TFO_DATA_IGNORED
@ STREAM_3WHS_WRONG_SEQ_WRONG_ACK
@ STREAM_PKT_INVALID_ACK
@ STREAM_RST_INVALID_ACK
@ STREAM_3WHS_SYNACK_FLOOD
@ STREAM_EST_PACKET_OUT_OF_WINDOW
@ STREAM_PKT_BAD_WINDOW_UPDATE
@ STREAM_FIN2_INVALID_ACK
@ STREAM_4WHS_SYNACK_WITH_WRONG_SYN
@ STREAM_4WHS_INVALID_ACK
@ STREAM_EST_ACK_ZWP_DATA
@ STREAM_3WHS_SYN_FLOOD
@ STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV
@ STREAM_FIN_SYN
@ STREAM_CLOSING_ACK_WRONG_SEQ
@ STREAM_FIN1_ACK_WRONG_SEQ
@ STREAM_CLOSING_INVALID_ACK
@ STREAM_EST_SYN_RESEND
@ STREAM_RST_WITH_DATA
@ STREAM_FIN_BUT_NO_SESSION
@ STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ
@ STREAM_CLOSEWAIT_INVALID_ACK
@ STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW
@ STREAM_FIN_OUT_OF_WINDOW
@ STREAM_SUSPECTED_RST_INJECT
@ STREAM_PKT_SPURIOUS_RETRANSMISSION
@ STREAM_3WHS_ACK_DATA_INJECT
@ STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION
@ STREAM_TIMEWAIT_INVALID_ACK
@ STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION
@ STREAM_TIMEWAIT_ACK_WRONG_SEQ
@ STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK
@ STREAM_3WHS_ASYNC_WRONG_SEQ
@ STREAM_SHUTDOWN_SYN_RESEND
@ STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK
@ STREAM_FIN2_FIN_WRONG_SEQ
@ STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW
@ STREAM_FIN2_ACK_WRONG_SEQ
@ STREAM_EST_SYN_RESEND_DIFF_SEQ
@ STREAM_FIN1_FIN_WRONG_SEQ
@ STREAM_EST_SYNACK_TOSERVER
@ STREAM_PKT_BROKEN_ACK
@ STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK
@ STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV
@ STREAM_3WHS_SYNACK_WITH_WRONG_ACK
@ STREAM_4WHS_SYNACK_WITH_WRONG_ACK
@ STREAM_PKT_INVALID_TIMESTAMP
@ STREAM_FIN_INVALID_ACK
@ STREAM_EST_SYN_TOCLIENT
@ STREAM_FIN1_INVALID_ACK
uint8_t flags
Definition decode-gre.h:0
#define TCP_GET_TSECR(p)
Definition decode-tcp.h:91
#define TCP_HAS_SACK(p)
Definition decode-tcp.h:94
#define TH_FIN
Definition decode-tcp.h:34
#define TCP_GET_RAW_SEQ(tcph)
Definition decode-tcp.h:80
#define TH_ACK
Definition decode-tcp.h:38
#define TCP_WSCALE_MAX
Definition decode-tcp.h:69
#define TH_URG
Definition decode-tcp.h:39
#define TCP_HAS_TS(p)
Definition decode-tcp.h:95
#define TH_RST
Definition decode-tcp.h:36
#define TCP_GET_RAW_ACK(tcph)
Definition decode-tcp.h:81
#define TCP_GET_SACKOK(p)
Definition decode-tcp.h:102
#define TH_SYN
Definition decode-tcp.h:35
#define TCP_GET_TSVAL(p)
Definition decode-tcp.h:88
#define TCP_GET_WSCALE(p)
Definition decode-tcp.h:100
#define TCP_HAS_WSCALE(p)
Definition decode-tcp.h:93
#define TCP_GET_RAW_WINDOW(tcph)
Definition decode-tcp.h:83
#define TCP_HAS_TFO(p)
Definition decode-tcp.h:97
#define TCP_GET_RAW_HLEN(tcph)
Definition decode-tcp.h:72
#define PKT_HAS_FLOW
Definition decode.h:1266
#define GET_IPV6_DST_ADDR(p)
Definition decode.h:204
#define GET_PKT_DIRECT_MAX_SIZE(p)
Definition decode.h:211
@ PKT_DROP_REASON_STREAM_ERROR
Definition decode.h:391
@ PKT_DROP_REASON_STREAM_MEMCAP
Definition decode.h:392
@ PKT_DROP_REASON_STREAM_URG
Definition decode.h:395
@ PKT_DROP_REASON_STREAM_MIDSTREAM
Definition decode.h:393
#define SET_PKT_LEN(p, len)
Definition decode.h:213
#define PKT_NOPACKET_INSPECTION
Definition decode.h:1247
#define PKT_NOPAYLOAD_INSPECTION
Definition decode.h:1252
#define PKT_PSEUDO_STREAM_END
Definition decode.h:1268
#define PKT_SET_SRC(p, src_val)
Definition decode.h:1325
#define GET_PKT_DATA(p)
Definition decode.h:209
#define PKT_PSEUDO_DETECTLOG_FLUSH
Definition decode.h:1308
#define PKT_STREAM_MODIFIED
Definition decode.h:1271
#define PKT_STREAM_NO_EVENTS
Definition decode.h:1312
#define PKT_STREAM_NOPCAPLOG
Definition decode.h:1277
#define PKT_IS_TOCLIENT(p)
Definition decode.h:239
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition decode.h:1321
#define PKT_IS_TOSERVER(p)
Definition decode.h:238
#define PKT_STREAM_EST
Definition decode.h:1262
@ PKT_SRC_WIRE
Definition decode.h:52
@ PKT_SRC_STREAM_TCP_DETECTLOG_FLUSH
Definition decode.h:59
#define GET_IPV4_DST_ADDR_PTR(p)
Definition decode.h:199
#define PKT_IGNORE_CHECKSUM
Definition decode.h:1282
int FlowSetProtoFreeFunc(uint8_t, void(*Free)(void *))
Function to set the function to get protocol specific flow state.
Definition flow.c:1125
void FlowUpdateState(Flow *f, const enum FlowState s)
Definition flow.c:1162
int FlowGetPacketDirection(const Flow *f, const Packet *p)
determine the direction of the packet compared to the flow
Definition flow.c:279
void FlowSwap(Flow *f)
swap the flow's direction
Definition flow.c:246
@ FLOW_STATE_CLOSED
Definition flow.h:506
@ FLOW_STATE_ESTABLISHED
Definition flow.h:505
#define FLOW_PKT_TOSERVER
Definition flow.h:233
#define FLOW_WRONG_THREAD
Definition flow.h:110
#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa)
Definition flow.h:180
uint16_t FlowThreadId
Definition flow.h:333
#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa)
Definition flow.h:185
#define FLOW_IPV6
Definition flow.h:102
#define FLOW_PKT_ESTABLISHED
Definition flow.h:235
#define FLOW_IPV4
Definition flow.h:100
#define TOCLIENT
Definition flow.h:46
#define TOSERVER
Definition flow.h:45
#define FLOW_IS_IPV4(f)
Definition flow.h:170
#define FLOW_PKT_TOCLIENT
Definition flow.h:234
ThreadVars * tv
void PacketSwap(Packet *p)
switch direction of a packet
Definition decode.c:577
int PacketCallocExtPkt(Packet *p, int datalen)
Definition decode.c:309
const char * PktSrcToString(enum PktSrcEnum pkt_src)
Definition decode.c:855
void PacketBypassCallback(Packet *p)
Definition decode.c:530
void PoolThreadFree(PoolThread *pt)
destroy the thread pool
int PoolThreadExpand(PoolThread *pt)
expand pool by one for a new thread
void * PoolThreadGetById(PoolThread *pt, uint16_t id)
get data from thread pool by thread id
int PoolThreadSize(PoolThread *pt)
get size of PoolThread (number of 'threads', so array elements)
PoolThread * PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int(*Init)(void *, void *), void *InitData, void(*Cleanup)(void *), void(*Free)(void *))
per thread Pool, initialization function
void PacketEnqueueNoLock(PacketQueueNoLock *qnl, Packet *p)
void PacketDrop(Packet *p, const uint8_t action, enum PacketDropReason r)
issue drop action
Definition packet.c:33
bool PacketCheckAction(const Packet *p, const uint8_t a)
Definition packet.c:49
uint64_t ts
void PcapIncreaseInvalidChecksum(void)
TcpSession * StreamTcpThreadCacheGetSession(void)
void StreamTcpThreadCacheEnable(void)
enable segment cache. Should only be done for worker threads
void StreamTcpThreadCacheReturnSession(TcpSession *ssn)
#define STREAM_PKT_FLAG_RETRANSMISSION
#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY
#define STREAMTCP_QUEUE_FLAG_WS
#define STREAMTCP_STREAM_FLAG_TIMESTAMP
#define SEQ_GEQ(a, b)
#define SEQ_GT(a, b)
#define STREAMTCP_STREAM_FLAG_DISABLE_RAW
#define STREAMTCP_FLAG_ASYNC
#define STREAMTCP_FLAG_CLOSED_BY_RST
#define STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE
#define SEQ_EQ(a, b)
#define STREAM_APP_PROGRESS(stream)
#define STREAMTCP_FLAG_BYPASS
#define STREAMTCP_FLAG_SERVER_WSCALE
#define STREAM_PKT_FLAG_DUP_ACK
#define STREAMTCP_FLAG_ZWP_TC
@ TCP_ESTABLISHED
@ TCP_SYN_RECV
@ TCP_LAST_ACK
@ TCP_CLOSE_WAIT
@ TCP_CLOSING
@ TCP_CLOSED
@ TCP_FIN_WAIT2
@ TCP_TIME_WAIT
@ TCP_SYN_SENT
@ TCP_FIN_WAIT1
#define STREAMTCP_SET_RA_BASE_SEQ(stream, seq)
#define STREAM_PKT_FLAG_SPURIOUS_RETRANSMISSION
#define PAWS_24DAYS
#define STREAM_PKT_FLAG_WINDOWUPDATE
#define STREAMTCP_FLAG_TFO_DATA_IGNORED
#define STREAMTCP_STREAM_FLAG_TRIGGER_RAW
#define STREAM_PKT_FLAG_STATE_UPDATE
#define SEQ_LEQ(a, b)
#define STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE_ACK
#define STREAM_PKT_FLAG_ACK_UNSEEN_DATA
#define STREAMTCP_FLAG_MIDSTREAM
#define STREAMTCP_FLAG_TCP_FAST_OPEN
#define STREAMTCP_FLAG_ZWP_TS
#define StreamTcpSetEvent(p, e)
#define STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT
PoolThreadId pool_id
#define STREAMTCP_FLAG_LOSSY_BE_LIBERAL
#define STREAMTCP_FLAG_3WHS_CONFIRMED
#define STREAM_PKT_FLAG_KEEPALIVEACK
#define STREAMTCP_FLAG_4WHS
#define STREAMTCP_QUEUE_FLAG_TS
uint32_t seq
#define STREAMTCP_FLAG_TIMESTAMP
#define STREAMTCP_QUEUE_FLAG_SACK
#define STREAMTCP_STREAM_FLAG_KEEPALIVE
#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
#define STREAMTCP_FLAG_MIDSTREAM_SYNACK
#define STREAMTCP_FLAG_SACKOK
#define STREAMTCP_STREAM_FLAG_RST_RECV
#define STREAM_PKT_FLAG_SET(p, f)
#define STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP
#define STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED
#define SEQ_LT(a, b)
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
#define STREAM_PKT_FLAG_KEEPALIVE
#define STREAMTCP_FLAG_CLIENT_SACKOK
#define STREAMTCP_STREAM_FLAG_DEPTH_REACHED
void StreamTcpDisableAppLayer(Flow *f)
void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx)
int StreamTcpReassembleInit(bool quiet)
TcpReassemblyThreadCtx * StreamTcpReassembleInitThreadCtx(ThreadVars *tv)
int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
void StreamTcpReassembleFree(bool quiet)
@ OS_POLICY_LAST
@ OS_POLICY_MACOS
@ OS_POLICY_WINDOWS
@ OS_POLICY_IRIX
@ OS_POLICY_HPUX10
@ OS_POLICY_VISTA
@ OS_POLICY_LINUX
@ OS_POLICY_OLD_LINUX
@ OS_POLICY_BSD
@ OS_POLICY_BSD_RIGHT
@ OS_POLICY_FIRST
@ OS_POLICY_WINDOWS2K3
@ OS_POLICY_OLD_SOLARIS
@ OS_POLICY_HPUX11
@ OS_POLICY_SOLARIS
#define OS_POLICY_DEFAULT
int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p)
Update stream with SACK records from a TCP packet.
void StreamTcpSackFreeList(TcpStream *stream)
Free SACK tree from a stream.
bool StreamTcpSackPacketIsOutdated(TcpStream *stream, Packet *p)
ExceptionPolicyStatsSetts stream_memcap_eps_stats
Definition stream-tcp.c:95
void StreamTcpInitMemuse(void)
Definition stream-tcp.c:223
int StreamTcpBypassEnabled(void)
TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
#define StreamTcpUpdateNextWin(ssn, stream, win)
macro to update next_win only if the new value is higher
TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data)
#define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP
Definition stream-tcp.c:87
int StreamTcpGetFlowState(void *)
void StreamTcpSessionCleanup(TcpSession *ssn)
Session cleanup function. Does not free the ssn.
Definition stream-tcp.c:327
int StreamTcpSegmentForSession(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
Run callback function on each TCP segment in both directions of a session.
ExceptionPolicyStatsSetts stream_midstream_disabled_eps_stats
Definition stream-tcp.c:173
#define StreamTcpUpdateLastAck(ssn, stream, ack)
macro to update last_ack only if the new value is higher
bool StreamTcpInlineMode(void)
See if stream engine is operating in inline mode.
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
void StreamTcpSetOSPolicy(TcpStream *, Packet *)
Function to set the OS policy for the given stream based on the destination of the received packet.
void StreamTcpIncrMemuse(uint64_t size)
Definition stream-tcp.c:228
bool TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
#define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE
Definition stream-tcp.c:88
const char * StreamTcpStateAsString(const enum TcpState state)
#define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE
Definition stream-tcp.c:89
void StreamTcpStreamCleanup(TcpStream *stream)
Definition stream-tcp.c:300
#define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED
Definition stream-tcp.c:91
void StreamTcpFreeConfig(bool quiet)
Definition stream-tcp.c:859
#define STREAMTCP_DEFAULT_PREALLOC
Definition stream-tcp.c:85
void StreamTcpDecrMemuse(uint64_t size)
Definition stream-tcp.c:234
void StreamTcpSetDisableRawReassemblyFlag(TcpSession *ssn, char direction)
Set the No reassembly flag for the given direction in given TCP session.
thread_local uint64_t t_pcapcnt
enum ExceptionPolicy StreamTcpSsnMemcapGetExceptionPolicy(void)
Definition stream-tcp.c:899
int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition stream-tcp.c:488
int StreamTcpCheckMemcap(uint64_t size)
Check if alloc'ing "size" would mean we're over memcap.
Definition stream-tcp.c:266
enum ExceptionPolicy StreamTcpReassemblyMemcapGetExceptionPolicy(void)
Definition stream-tcp.c:904
void StreamTcpReturnStreamSegments(TcpStream *)
return all segments in this stream into the pool(s)
void StreamTcpSetSessionNoReassemblyFlag(TcpSession *ssn, char direction)
disable reassembly
void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
uint64_t StreamTcpGetMemcap(void)
Return memcap value.
Definition stream-tcp.c:294
PoolThread * ssn_pool
Definition stream-tcp.c:213
TmEcode StreamTcp(ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq)
TcpStreamCnf stream_config
Definition stream-tcp.c:219
int StreamTcpPacket(ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueueNoLock *pq)
void StreamTcpSetSessionBypassFlag(TcpSession *ssn)
enable bypass
ExceptionPolicyStatsSetts stream_reassembly_memcap_eps_stats
Definition stream-tcp.c:121
void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p, PacketQueueNoLock *pq)
create packets in both directions to flush out logging and detection before switching protocols....
int StreamTcpSetMemcap(uint64_t size)
Update memcap value.
Definition stream-tcp.c:279
const char * StreamTcpSsnStateAsString(const TcpSession *ssn)
#define StreamTcpUpdateNextSeq(ssn, stream, seq)
#define STREAMTCP_DEFAULT_MEMCAP
Definition stream-tcp.c:86
void StreamTcpSessionClear(void *ssnptr)
Function to return the stream back to the pool. It returns the segments in the stream to the segment ...
Definition stream-tcp.c:351
ExceptionPolicyStatsSetts stream_midstream_enabled_eps_stats
Definition stream-tcp.c:147
uint64_t StreamTcpMemuseCounter(void)
Definition stream-tcp.c:254
enum ExceptionPolicy StreamMidstreamGetExceptionPolicy(void)
Definition stream-tcp.c:909
int g_detect_disabled
Definition suricata.c:186
#define STREAMTCP_DEFAULT_MAX_SYN_QUEUED
Definition stream-tcp.c:90
void StreamTcpSessionPktFree(Packet *p)
Function to return the stream segments back to the pool.
Definition stream-tcp.c:380
void StreamTcpUpdateAppLayerProgress(TcpSession *ssn, char direction, const uint32_t progress)
update reassembly progress
#define STREAMTCP_INIT_FLAG_DROP_INVALID
Definition stream-tcp.h:39
TcpStreamUrgentHandling
Definition stream-tcp.h:45
@ TCP_STREAM_URGENT_INLINE
Definition stream-tcp.h:46
@ TCP_STREAM_URGENT_DROP
Definition stream-tcp.h:48
@ TCP_STREAM_URGENT_OOB
Definition stream-tcp.h:49
@ TCP_STREAM_URGENT_GAP
Definition stream-tcp.h:50
#define STREAMTCP_INIT_FLAG_INLINE
Definition stream-tcp.h:41
#define TCP_STREAM_URGENT_DEFAULT
Definition stream-tcp.h:47
#define STREAMTCP_INIT_FLAG_BYPASS
Definition stream-tcp.h:40
#define STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION
Definition stream-tcp.h:38
int(* StreamSegmentCallback)(const Packet *, TcpSegment *, void *, const uint8_t *, uint32_t)
Definition stream.h:36
#define STREAM_DUMP_TOSERVER
Definition stream.h:33
uint16_t eps_id[EXCEPTION_POLICY_MAX]
bool valid_settings_ips[EXCEPTION_POLICY_MAX]
bool valid_settings_ids[EXCEPTION_POLICY_MAX]
Flow data structure.
Definition flow.h:356
Port dp
Definition flow.h:372
uint32_t flags
Definition flow.h:421
AppProto alproto
application level protocol
Definition flow.h:450
uint32_t tenant_id
Definition flow.h:416
uint8_t vlan_idx
Definition flow.h:382
void * protoctx
Definition flow.h:441
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition flow.h:380
struct LiveDevice_ * livedev
Definition flow.h:398
FlowThreadId thread_id[2]
Definition flow.h:394
FlowAddress src
Definition flow.h:359
Port sp
Definition flow.h:361
FlowAddress dst
Definition flow.h:359
uint8_t ip_verhl
Definition decode-ipv4.h:73
uint16_t ip_id
Definition decode-ipv4.h:76
uint8_t ip_tos
Definition decode-ipv4.h:74
uint16_t ip_off
Definition decode-ipv4.h:77
uint8_t ip_proto
Definition decode-ipv4.h:79
uint8_t ip_ttl
Definition decode-ipv4.h:78
uint16_t ip_len
Definition decode-ipv4.h:75
bool csum_set
Definition decode.h:466
union PacketL4::L4Vars vars
uint16_t csum
Definition decode.h:467
simple fifo queue for packets
uint32_t tenant_id
Definition decode.h:665
struct PacketL4 l4
Definition decode.h:601
uint8_t flowflags
Definition decode.h:532
uint64_t pcap_cnt
Definition decode.h:626
SCTime_t ts
Definition decode.h:555
uint8_t pkt_src
Definition decode.h:611
Address src
Definition decode.h:505
Port sp
Definition decode.h:508
struct Flow_ * flow
Definition decode.h:546
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition decode.h:528
uint8_t * payload
Definition decode.h:605
int datalink
Definition decode.h:639
uint16_t payload_len
Definition decode.h:606
struct LiveDevice_ * livedev
Definition decode.h:618
uint32_t flags
Definition decode.h:544
uint8_t vlan_idx
Definition decode.h:529
Address dst
Definition decode.h:506
uint8_t proto
Definition decode.h:523
Port dp
Definition decode.h:516
uint16_t counter_tcp_ack_unseen_data
Definition stream-tcp.h:114
uint16_t counter_tcp_ssn_from_pool
Definition stream-tcp.h:100
uint16_t counter_tcp_invalid_checksum
Definition stream-tcp.h:106
uint16_t counter_tcp_pseudo
Definition stream-tcp.h:104
uint16_t counter_tcp_ssn_memcap
Definition stream-tcp.h:98
uint16_t counter_tcp_active_sessions
Definition stream-tcp.h:95
uint16_t counter_tcp_sessions
Definition stream-tcp.h:96
TcpReassemblyThreadCtx * ra_ctx
Definition stream-tcp.h:117
uint16_t counter_tcp_midstream_pickups
Definition stream-tcp.h:108
ExceptionPolicyCounters counter_tcp_midstream_eps
Definition stream-tcp.h:110
uint16_t counter_tcp_ssn_from_cache
Definition stream-tcp.h:99
ExceptionPolicyCounters counter_tcp_ssn_memcap_eps
Definition stream-tcp.h:102
uint16_t counter_tcp_wrong_thread
Definition stream-tcp.h:112
uint16_t th_win
Definition decode-tcp.h:156
uint8_t th_offx2
Definition decode-tcp.h:154
uint32_t th_seq
Definition decode-tcp.h:152
uint32_t th_ack
Definition decode-tcp.h:153
uint16_t th_urp
Definition decode-tcp.h:158
uint16_t th_dport
Definition decode-tcp.h:151
uint8_t th_flags
Definition decode-tcp.h:155
uint16_t th_sport
Definition decode-tcp.h:150
uint8_t md5_option_present
Definition decode-tcp.h:164
uint8_t ao_option_present
Definition decode-tcp.h:165
ExceptionPolicyCounters counter_tcp_reas_eps
StreamingBufferSegment sbseg
TcpSegmentPcapHdrStorage * pcap_hdr_storage
TcpStateQueue * queue
uint32_t reassembly_depth
PoolThreadId pool_id
struct TcpStateQueue_ * next
bool liberal_timestamps
Definition stream-tcp.h:87
bool async_oneside
Definition stream-tcp.h:71
uint32_t prealloc_sessions
Definition stream-tcp.h:68
enum ExceptionPolicy reassembly_memcap_policy
Definition stream-tcp.h:81
enum ExceptionPolicy midstream_policy
Definition stream-tcp.h:82
uint16_t reassembly_toserver_chunk_size
Definition stream-tcp.h:77
uint32_t reassembly_depth
Definition stream-tcp.h:75
uint16_t reassembly_toclient_chunk_size
Definition stream-tcp.h:78
uint8_t max_synack_queued
Definition stream-tcp.h:66
enum TcpStreamUrgentHandling urgent_policy
Definition stream-tcp.h:83
uint8_t flags
Definition stream-tcp.h:65
uint8_t max_syn_queued
Definition stream-tcp.h:73
StreamingBufferConfig sbcnf
Definition stream-tcp.h:89
enum TcpStreamUrgentHandling urgent_oob_limit_policy
Definition stream-tcp.h:84
uint16_t stream_init_flags
Definition stream-tcp.h:62
enum ExceptionPolicy ssn_memcap_policy
Definition stream-tcp.h:80
StreamingBuffer sb
struct TCPSEG seg_tree
uint32_t app_progress_rel
Per thread variable structure.
Definition threadvars.h:58
#define BUG_ON(x)
int EngineModeIsIPS(void)
Definition suricata.c:242
int RunmodeIsUnittests(void)
Definition suricata.c:270
#define SCMutexDestroy
#define SCMUTEX_INITIALIZER
#define SCMutex
#define SCMutexUnlock(mut)
#define SCMutexLock(mut)
@ TM_ECODE_FAILED
@ TM_ECODE_OK
Packet * PacketPoolGetPacket(void)
Get a new packet from the packet pool.
uint32_t cnt
#define RB_MIN(name, x)
Definition tree.h:778
#define RB_FOREACH(x, name, head)
Definition tree.h:781
TCPVars tcp
Definition decode.h:478
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
#define SC_ATOMIC_DECLARE(type, name)
wrapper for declaring atomic variables.
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
int ReCalculateChecksum(Packet *p)
#define SCEnter(...)
Definition util-debug.h:277
#define FatalError(...)
Definition util-debug.h:510
#define BOOL2STR(b)
Definition util-debug.h:535
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition util-debug.h:243
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCLogConfig(...)
Definition util-debug.h:229
#define SCReturn
Definition util-debug.h:279
@ EXCEPTION_POLICY_PASS_FLOW
enum ExceptionPolicy ExceptionPolicyMidstreamParse(bool midstream_enabled)
enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow)
void ExceptionPolicySetStatsCounters(ThreadVars *tv, ExceptionPolicyCounters *counter, ExceptionPolicyStatsSetts *setting, enum ExceptionPolicy conf_policy, const char *default_str, bool(*isExceptionPolicyValid)(enum ExceptionPolicy))
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
int SCHInfoGetIPv6HostOSFlavour(uint8_t *addr)
Retrieves the host os flavour, given an ipv6 address in the raw address format.
int SCHInfoGetIPv4HostOSFlavour(uint8_t *addr)
Retrieves the host os flavour, given an ipv4 address in the raw address format.
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition util-misc.c:173
int ParseSizeStringU16(const char *size, uint16_t *res)
Definition util-misc.c:156
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition util-misc.c:190
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition util-misc.h:35
#define likely(expr)
#define unlikely(expr)
uint16_t PoolThreadId
long int RandomGet(void)
void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, const uint8_t **data, uint32_t *data_len)
void StreamingBufferClear(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
#define STREAMING_BUFFER_INITIALIZER
#define SCTIME_SECS(t)
Definition util-time.h:57
#define SCTIME_CMP_LT(a, b)
Definition util-time.h:105
#define DEBUG_VALIDATE_BUG_ON(exp)
#define DEBUG_ASSERT_FLOW_LOCKED(f)