1 /* Copyright (C) 2007-2016 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18 /**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
23 *
24 * TCP stream tracking and reassembly engine.
25 *
26 * \todo - 4WHS: what if after the 2nd SYN we turn out to be normal 3WHS anyway?
27 */
28
29 #include "suricata-common.h"
30 #include "suricata.h"
31
32 #include "decode.h"
33 #include "debug.h"
34 #include "detect.h"
35
36 #include "flow.h"
37 #include "flow-util.h"
38
39 #include "conf.h"
40 #include "conf-yaml-loader.h"
41
42 #include "threads.h"
43 #include "threadvars.h"
44 #include "tm-threads.h"
45
46 #include "util-pool.h"
47 #include "util-pool-thread.h"
48 #include "util-checksum.h"
49 #include "util-unittest.h"
50 #include "util-print.h"
51 #include "util-debug.h"
52 #include "util-device.h"
53
54 #include "stream-tcp-private.h"
55 #include "stream-tcp-reassemble.h"
56 #include "stream-tcp.h"
57 #include "stream-tcp-inline.h"
58 #include "stream-tcp-sack.h"
59 #include "stream-tcp-util.h"
60 #include "stream.h"
61
62 #include "pkt-var.h"
63 #include "host.h"
64
65 #include "app-layer.h"
66 #include "app-layer-parser.h"
67 #include "app-layer-protos.h"
68 #include "app-layer-htp-mem.h"
69
70 #include "util-host-os-info.h"
71 #include "util-privs.h"
72 #include "util-profiling.h"
73 #include "util-misc.h"
74 #include "util-validate.h"
75 #include "util-runmodes.h"
76 #include "util-random.h"
77
78 #include "source-pcap-file.h"
79
80 //#define DEBUG
81
82 #define STREAMTCP_DEFAULT_PREALLOC 2048
83 #define STREAMTCP_DEFAULT_MEMCAP (64 * 1024 * 1024) /* 64mb */
84 #define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP (256 * 1024 * 1024) /* 256mb */
85 #define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE 2560
86 #define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE 2560
87 #define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED 5
88
89 #define STREAMTCP_NEW_TIMEOUT 60
90 #define STREAMTCP_EST_TIMEOUT 3600
91 #define STREAMTCP_CLOSED_TIMEOUT 120
92
93 #define STREAMTCP_EMERG_NEW_TIMEOUT 10
94 #define STREAMTCP_EMERG_EST_TIMEOUT 300
95 #define STREAMTCP_EMERG_CLOSED_TIMEOUT 20
96
97 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *, PacketQueueNoLock *);
98 void StreamTcpReturnStreamSegments (TcpStream *);
99 void StreamTcpInitConfig(char);
100 int StreamTcpGetFlowState(void *);
101 void StreamTcpSetOSPolicy(TcpStream*, Packet*);
102
103 static int StreamTcpValidateTimestamp(TcpSession * , Packet *);
104 static int StreamTcpHandleTimestamp(TcpSession * , Packet *);
105 static int StreamTcpValidateRst(TcpSession * , Packet *);
106 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *, Packet *);
107 static int StreamTcpStateDispatch(ThreadVars *tv, Packet *p,
108 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq,
109 uint8_t state);
110
111 extern int g_detect_disabled;
112
113 static PoolThread *ssn_pool = NULL;
114 static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect initializing and growing pool */
115 #ifdef DEBUG
116 static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */
117 #endif
118
119 TcpStreamCnf stream_config;
120 uint64_t StreamTcpReassembleMemuseGlobalCounter(void);
121 SC_ATOMIC_DECLARE(uint64_t, st_memuse);
122
StreamTcpInitMemuse(void)123 void StreamTcpInitMemuse(void)
124 {
125 SC_ATOMIC_INIT(st_memuse);
126 }
127
StreamTcpIncrMemuse(uint64_t size)128 void StreamTcpIncrMemuse(uint64_t size)
129 {
130 (void) SC_ATOMIC_ADD(st_memuse, size);
131 SCLogDebug("STREAM %"PRIu64", incr %"PRIu64, StreamTcpMemuseCounter(), size);
132 return;
133 }
134
StreamTcpDecrMemuse(uint64_t size)135 void StreamTcpDecrMemuse(uint64_t size)
136 {
137 #ifdef DEBUG_VALIDATION
138 uint64_t presize = SC_ATOMIC_GET(st_memuse);
139 if (RunmodeIsUnittests()) {
140 BUG_ON(presize > UINT_MAX);
141 }
142 #endif
143
144 (void) SC_ATOMIC_SUB(st_memuse, size);
145
146 #ifdef DEBUG_VALIDATION
147 if (RunmodeIsUnittests()) {
148 uint64_t postsize = SC_ATOMIC_GET(st_memuse);
149 BUG_ON(postsize > presize);
150 }
151 #endif
152 SCLogDebug("STREAM %"PRIu64", decr %"PRIu64, StreamTcpMemuseCounter(), size);
153 return;
154 }
155
StreamTcpMemuseCounter(void)156 uint64_t StreamTcpMemuseCounter(void)
157 {
158 uint64_t memusecopy = SC_ATOMIC_GET(st_memuse);
159 return memusecopy;
160 }
161
162 /**
163 * \brief Check if alloc'ing "size" would mean we're over memcap
164 *
165 * \retval 1 if in bounds
166 * \retval 0 if not in bounds
167 */
StreamTcpCheckMemcap(uint64_t size)168 int StreamTcpCheckMemcap(uint64_t size)
169 {
170 uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.memcap);
171 if (memcapcopy == 0 || size + SC_ATOMIC_GET(st_memuse) <= memcapcopy)
172 return 1;
173 return 0;
174 }
175
176 /**
177 * \brief Update memcap value
178 *
179 * \param size new memcap value
180 */
StreamTcpSetMemcap(uint64_t size)181 int StreamTcpSetMemcap(uint64_t size)
182 {
183 if (size == 0 || (uint64_t)SC_ATOMIC_GET(st_memuse) < size) {
184 SC_ATOMIC_SET(stream_config.memcap, size);
185 return 1;
186 }
187
188 return 0;
189 }
190
191 /**
192 * \brief Return memcap value
193 *
194 * \param memcap memcap value
195 */
StreamTcpGetMemcap(void)196 uint64_t StreamTcpGetMemcap(void)
197 {
198 uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.memcap);
199 return memcapcopy;
200 }
201
StreamTcpStreamCleanup(TcpStream * stream)202 void StreamTcpStreamCleanup(TcpStream *stream)
203 {
204 if (stream != NULL) {
205 StreamTcpSackFreeList(stream);
206 StreamTcpReturnStreamSegments(stream);
207 StreamingBufferClear(&stream->sb);
208 }
209 }
210
211 /**
212 * \brief Session cleanup function. Does not free the ssn.
213 * \param ssn tcp session
214 */
StreamTcpSessionCleanup(TcpSession * ssn)215 void StreamTcpSessionCleanup(TcpSession *ssn)
216 {
217 SCEnter();
218 TcpStateQueue *q, *q_next;
219
220 if (ssn == NULL)
221 return;
222
223 StreamTcpStreamCleanup(&ssn->client);
224 StreamTcpStreamCleanup(&ssn->server);
225
226 q = ssn->queue;
227 while (q != NULL) {
228 q_next = q->next;
229 SCFree(q);
230 q = q_next;
231 StreamTcpDecrMemuse((uint64_t)sizeof(TcpStateQueue));
232 }
233 ssn->queue = NULL;
234 ssn->queue_len = 0;
235
236 SCReturn;
237 }
238
239 /**
240 * \brief Function to return the stream back to the pool. It returns the
241 * segments in the stream to the segment pool.
242 *
243 * This function is called when the flow is destroyed, so it should free
244 * *everything* related to the tcp session. So including the app layer
245 * data. We are guaranteed to only get here when the flow's use_cnt is 0.
246 *
247 * \param ssn Void ptr to the ssn.
248 */
StreamTcpSessionClear(void * ssnptr)249 void StreamTcpSessionClear(void *ssnptr)
250 {
251 SCEnter();
252 TcpSession *ssn = (TcpSession *)ssnptr;
253 if (ssn == NULL)
254 return;
255
256 StreamTcpSessionCleanup(ssn);
257
258 /* HACK: don't loose track of thread id */
259 PoolThreadReserved a = ssn->res;
260 memset(ssn, 0, sizeof(TcpSession));
261 ssn->res = a;
262
263 PoolThreadReturn(ssn_pool, ssn);
264 #ifdef DEBUG
265 SCMutexLock(&ssn_pool_mutex);
266 ssn_pool_cnt--;
267 SCMutexUnlock(&ssn_pool_mutex);
268 #endif
269
270 SCReturn;
271 }
272
273 /**
274 * \brief Function to return the stream segments back to the pool.
275 *
276 * We don't clear out the app layer storage here as that is under protection
277 * of the "use_cnt" reference counter in the flow. This function is called
278 * when the use_cnt is always at least 1 (this pkt has incremented the flow
279 * use_cnt itself), so we don't bother.
280 *
281 * \param p Packet used to identify the stream.
282 */
StreamTcpSessionPktFree(Packet * p)283 void StreamTcpSessionPktFree (Packet *p)
284 {
285 SCEnter();
286
287 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
288 if (ssn == NULL)
289 SCReturn;
290
291 StreamTcpReturnStreamSegments(&ssn->client);
292 StreamTcpReturnStreamSegments(&ssn->server);
293
294 SCReturn;
295 }
296
297 /** \brief Stream alloc function for the Pool
298 * \retval ptr void ptr to TcpSession structure with all vars set to 0/NULL
299 */
StreamTcpSessionPoolAlloc(void)300 static void *StreamTcpSessionPoolAlloc(void)
301 {
302 void *ptr = NULL;
303
304 if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpSession)) == 0)
305 return NULL;
306
307 ptr = SCMalloc(sizeof(TcpSession));
308 if (unlikely(ptr == NULL))
309 return NULL;
310
311 return ptr;
312 }
313
StreamTcpSessionPoolInit(void * data,void * initdata)314 static int StreamTcpSessionPoolInit(void *data, void* initdata)
315 {
316 memset(data, 0, sizeof(TcpSession));
317 StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession));
318
319 return 1;
320 }
321
322 /** \brief Pool cleanup function
323 * \param s Void ptr to TcpSession memory */
StreamTcpSessionPoolCleanup(void * s)324 static void StreamTcpSessionPoolCleanup(void *s)
325 {
326 if (s != NULL) {
327 StreamTcpSessionCleanup(s);
328 /** \todo not very clean, as the memory is not freed here */
329 StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession));
330 }
331 }
332
333 /**
334 * \brief See if stream engine is dropping invalid packet in inline mode
335 *
336 * \retval 0 no
337 * \retval 1 yes
338 */
StreamTcpInlineDropInvalid(void)339 int StreamTcpInlineDropInvalid(void)
340 {
341 return ((stream_config.flags & STREAMTCP_INIT_FLAG_INLINE)
342 && (stream_config.flags & STREAMTCP_INIT_FLAG_DROP_INVALID));
343 }
344
345 /* hack: stream random range code expects random values in range of 0-RAND_MAX,
346 * but we can get both <0 and >RAND_MAX values from RandomGet
347 */
RandomGetWrap(void)348 static int RandomGetWrap(void)
349 {
350 unsigned long r;
351
352 do {
353 r = RandomGet();
354 } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
355
356 return r % RAND_MAX;
357 }
358
359 /** \brief To initialize the stream global configuration data
360 *
361 * \param quiet It tells the mode of operation, if it is TRUE nothing will
362 * be get printed.
363 */
364
StreamTcpInitConfig(char quiet)365 void StreamTcpInitConfig(char quiet)
366 {
367 intmax_t value = 0;
368 uint16_t rdrange = 10;
369
370 SCLogDebug("Initializing Stream");
371
372 memset(&stream_config, 0, sizeof(stream_config));
373
374 SC_ATOMIC_INIT(stream_config.memcap);
375 SC_ATOMIC_INIT(stream_config.reassembly_memcap);
376
377 if ((ConfGetInt("stream.max-sessions", &value)) == 1) {
378 SCLogWarning(SC_WARN_OPTION_OBSOLETE, "max-sessions is obsolete. "
379 "Number of concurrent sessions is now only limited by Flow and "
380 "TCP stream engine memcaps.");
381 }
382
383 if ((ConfGetInt("stream.prealloc-sessions", &value)) == 1) {
384 stream_config.prealloc_sessions = (uint32_t)value;
385 } else {
386 if (RunmodeIsUnittests()) {
387 stream_config.prealloc_sessions = 128;
388 } else {
389 stream_config.prealloc_sessions = STREAMTCP_DEFAULT_PREALLOC;
390 if (ConfGetNode("stream.prealloc-sessions") != NULL) {
391 WarnInvalidConfEntry("stream.prealloc_sessions",
392 "%"PRIu32,
393 stream_config.prealloc_sessions);
394 }
395 }
396 }
397 if (!quiet) {
398 SCLogConfig("stream \"prealloc-sessions\": %"PRIu32" (per thread)",
399 stream_config.prealloc_sessions);
400 }
401
402 const char *temp_stream_memcap_str;
403 if (ConfGetValue("stream.memcap", &temp_stream_memcap_str) == 1) {
404 uint64_t stream_memcap_copy;
405 if (ParseSizeStringU64(temp_stream_memcap_str, &stream_memcap_copy) < 0) {
406 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing stream.memcap "
407 "from conf file - %s. Killing engine",
408 temp_stream_memcap_str);
409 exit(EXIT_FAILURE);
410 } else {
411 SC_ATOMIC_SET(stream_config.memcap, stream_memcap_copy);
412 }
413 } else {
414 SC_ATOMIC_SET(stream_config.memcap, STREAMTCP_DEFAULT_MEMCAP);
415 }
416
417 if (!quiet) {
418 SCLogConfig("stream \"memcap\": %"PRIu64, SC_ATOMIC_GET(stream_config.memcap));
419 }
420
421 ConfGetBool("stream.midstream", &stream_config.midstream);
422
423 if (!quiet) {
424 SCLogConfig("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled");
425 }
426
427 ConfGetBool("stream.async-oneside", &stream_config.async_oneside);
428
429 if (!quiet) {
430 SCLogConfig("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled");
431 }
432
433 int csum = 0;
434
435 if ((ConfGetBool("stream.checksum-validation", &csum)) == 1) {
436 if (csum == 1) {
437 stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION;
438 }
439 /* Default is that we validate the checksum of all the packets */
440 } else {
441 stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION;
442 }
443
444 if (!quiet) {
445 SCLogConfig("stream \"checksum-validation\": %s",
446 stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION ?
447 "enabled" : "disabled");
448 }
449
450 const char *temp_stream_inline_str;
451 if (ConfGetValue("stream.inline", &temp_stream_inline_str) == 1) {
452 int inl = 0;
453
454 /* checking for "auto" and falling back to boolean to provide
455 * backward compatibility */
456 if (strcmp(temp_stream_inline_str, "auto") == 0) {
457 if (EngineModeIsIPS()) {
458 stream_config.flags |= STREAMTCP_INIT_FLAG_INLINE;
459 }
460 } else if (ConfGetBool("stream.inline", &inl) == 1) {
461 if (inl) {
462 stream_config.flags |= STREAMTCP_INIT_FLAG_INLINE;
463 }
464 }
465 } else {
466 /* default to 'auto' */
467 if (EngineModeIsIPS()) {
468 stream_config.flags |= STREAMTCP_INIT_FLAG_INLINE;
469 }
470 }
471
472 if (!quiet) {
473 SCLogConfig("stream.\"inline\": %s",
474 stream_config.flags & STREAMTCP_INIT_FLAG_INLINE
475 ? "enabled" : "disabled");
476 }
477
478 int bypass = 0;
479 if ((ConfGetBool("stream.bypass", &bypass)) == 1) {
480 if (bypass == 1) {
481 stream_config.flags |= STREAMTCP_INIT_FLAG_BYPASS;
482 }
483 }
484
485 if (!quiet) {
486 SCLogConfig("stream \"bypass\": %s",
487 (stream_config.flags & STREAMTCP_INIT_FLAG_BYPASS)
488 ? "enabled" : "disabled");
489 }
490
491 int drop_invalid = 0;
492 if ((ConfGetBool("stream.drop-invalid", &drop_invalid)) == 1) {
493 if (drop_invalid == 1) {
494 stream_config.flags |= STREAMTCP_INIT_FLAG_DROP_INVALID;
495 }
496 } else {
497 stream_config.flags |= STREAMTCP_INIT_FLAG_DROP_INVALID;
498 }
499
500 if ((ConfGetInt("stream.max-synack-queued", &value)) == 1) {
501 if (value >= 0 && value <= 255) {
502 stream_config.max_synack_queued = (uint8_t)value;
503 } else {
504 stream_config.max_synack_queued = (uint8_t)STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED;
505 }
506 } else {
507 stream_config.max_synack_queued = (uint8_t)STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED;
508 }
509 if (!quiet) {
510 SCLogConfig("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued);
511 }
512
513 const char *temp_stream_reassembly_memcap_str;
514 if (ConfGetValue("stream.reassembly.memcap", &temp_stream_reassembly_memcap_str) == 1) {
515 uint64_t stream_reassembly_memcap_copy;
516 if (ParseSizeStringU64(temp_stream_reassembly_memcap_str,
517 &stream_reassembly_memcap_copy) < 0) {
518 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
519 "stream.reassembly.memcap "
520 "from conf file - %s. Killing engine",
521 temp_stream_reassembly_memcap_str);
522 exit(EXIT_FAILURE);
523 } else {
524 SC_ATOMIC_SET(stream_config.reassembly_memcap, stream_reassembly_memcap_copy);
525 }
526 } else {
527 SC_ATOMIC_SET(stream_config.reassembly_memcap , STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP);
528 }
529
530 if (!quiet) {
531 SCLogConfig("stream.reassembly \"memcap\": %"PRIu64"",
532 SC_ATOMIC_GET(stream_config.reassembly_memcap));
533 }
534
535 const char *temp_stream_reassembly_depth_str;
536 if (ConfGetValue("stream.reassembly.depth", &temp_stream_reassembly_depth_str) == 1) {
537 if (ParseSizeStringU32(temp_stream_reassembly_depth_str,
538 &stream_config.reassembly_depth) < 0) {
539 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
540 "stream.reassembly.depth "
541 "from conf file - %s. Killing engine",
542 temp_stream_reassembly_depth_str);
543 exit(EXIT_FAILURE);
544 }
545 } else {
546 stream_config.reassembly_depth = 0;
547 }
548
549 if (!quiet) {
550 SCLogConfig("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth);
551 }
552
553 int randomize = 0;
554 if ((ConfGetBool("stream.reassembly.randomize-chunk-size", &randomize)) == 0) {
555 /* randomize by default if value not set
556 * In ut mode we disable, to get predictible test results */
557 if (!(RunmodeIsUnittests()))
558 randomize = 1;
559 }
560
561 if (randomize) {
562 const char *temp_rdrange;
563 if (ConfGetValue("stream.reassembly.randomize-chunk-range",
564 &temp_rdrange) == 1) {
565 if (ParseSizeStringU16(temp_rdrange, &rdrange) < 0) {
566 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
567 "stream.reassembly.randomize-chunk-range "
568 "from conf file - %s. Killing engine",
569 temp_rdrange);
570 exit(EXIT_FAILURE);
571 } else if (rdrange >= 100) {
572 FatalError(SC_ERR_FATAL,
573 "stream.reassembly.randomize-chunk-range "
574 "must be lower than 100");
575 }
576 }
577 }
578
579 const char *temp_stream_reassembly_toserver_chunk_size_str;
580 if (ConfGetValue("stream.reassembly.toserver-chunk-size",
581 &temp_stream_reassembly_toserver_chunk_size_str) == 1) {
582 if (ParseSizeStringU16(temp_stream_reassembly_toserver_chunk_size_str,
583 &stream_config.reassembly_toserver_chunk_size) < 0) {
584 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
585 "stream.reassembly.toserver-chunk-size "
586 "from conf file - %s. Killing engine",
587 temp_stream_reassembly_toserver_chunk_size_str);
588 exit(EXIT_FAILURE);
589 }
590 } else {
591 stream_config.reassembly_toserver_chunk_size =
592 STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE;
593 }
594
595 if (randomize) {
596 long int r = RandomGetWrap();
597 stream_config.reassembly_toserver_chunk_size +=
598 (int) (stream_config.reassembly_toserver_chunk_size *
599 (r * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
600 }
601 const char *temp_stream_reassembly_toclient_chunk_size_str;
602 if (ConfGetValue("stream.reassembly.toclient-chunk-size",
603 &temp_stream_reassembly_toclient_chunk_size_str) == 1) {
604 if (ParseSizeStringU16(temp_stream_reassembly_toclient_chunk_size_str,
605 &stream_config.reassembly_toclient_chunk_size) < 0) {
606 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
607 "stream.reassembly.toclient-chunk-size "
608 "from conf file - %s. Killing engine",
609 temp_stream_reassembly_toclient_chunk_size_str);
610 exit(EXIT_FAILURE);
611 }
612 } else {
613 stream_config.reassembly_toclient_chunk_size =
614 STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE;
615 }
616
617 if (randomize) {
618 long int r = RandomGetWrap();
619 stream_config.reassembly_toclient_chunk_size +=
620 (int) (stream_config.reassembly_toclient_chunk_size *
621 (r * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
622 }
623 if (!quiet) {
624 SCLogConfig("stream.reassembly \"toserver-chunk-size\": %"PRIu16,
625 stream_config.reassembly_toserver_chunk_size);
626 SCLogConfig("stream.reassembly \"toclient-chunk-size\": %"PRIu16,
627 stream_config.reassembly_toclient_chunk_size);
628 }
629
630 int enable_raw = 1;
631 if (ConfGetBool("stream.reassembly.raw", &enable_raw) == 1) {
632 if (!enable_raw) {
633 stream_config.stream_init_flags = STREAMTCP_STREAM_FLAG_DISABLE_RAW;
634 }
635 } else {
636 enable_raw = 1;
637 }
638 if (!quiet)
639 SCLogConfig("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled");
640
641 /* init the memcap/use tracking */
642 StreamTcpInitMemuse();
643 StatsRegisterGlobalCounter("tcp.memuse", StreamTcpMemuseCounter);
644
645 StreamTcpReassembleInit(quiet);
646
647 /* set the default free function and flow state function
648 * values. */
649 FlowSetProtoFreeFunc(IPPROTO_TCP, StreamTcpSessionClear);
650
651 #ifdef UNITTESTS
652 if (RunmodeIsUnittests()) {
653 SCMutexLock(&ssn_pool_mutex);
654 if (ssn_pool == NULL) {
655 ssn_pool = PoolThreadInit(1, /* thread */
656 0, /* unlimited */
657 stream_config.prealloc_sessions,
658 sizeof(TcpSession),
659 StreamTcpSessionPoolAlloc,
660 StreamTcpSessionPoolInit, NULL,
661 StreamTcpSessionPoolCleanup, NULL);
662 }
663 SCMutexUnlock(&ssn_pool_mutex);
664 }
665 #endif
666 }
667
StreamTcpFreeConfig(char quiet)668 void StreamTcpFreeConfig(char quiet)
669 {
670 StreamTcpReassembleFree(quiet);
671
672 SCMutexLock(&ssn_pool_mutex);
673 if (ssn_pool != NULL) {
674 PoolThreadFree(ssn_pool);
675 ssn_pool = NULL;
676 }
677 SCMutexUnlock(&ssn_pool_mutex);
678 SCMutexDestroy(&ssn_pool_mutex);
679
680 SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt);
681 }
682
683 /** \internal
684 * \brief The function is used to to fetch a TCP session from the
685 * ssn_pool, when a TCP SYN is received.
686 *
687 * \param p packet starting the new TCP session.
688 * \param id thread pool id
689 *
690 * \retval ssn new TCP session.
691 */
StreamTcpNewSession(Packet * p,int id)692 static TcpSession *StreamTcpNewSession (Packet *p, int id)
693 {
694 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
695
696 if (ssn == NULL) {
697 p->flow->protoctx = PoolThreadGetById(ssn_pool, id);
698 #ifdef DEBUG
699 SCMutexLock(&ssn_pool_mutex);
700 if (p->flow->protoctx != NULL)
701 ssn_pool_cnt++;
702 SCMutexUnlock(&ssn_pool_mutex);
703 #endif
704
705 ssn = (TcpSession *)p->flow->protoctx;
706 if (ssn == NULL) {
707 SCLogDebug("ssn_pool is empty");
708 return NULL;
709 }
710
711 ssn->state = TCP_NONE;
712 ssn->reassembly_depth = stream_config.reassembly_depth;
713 ssn->tcp_packet_flags = p->tcph ? p->tcph->th_flags : 0;
714 ssn->server.flags = stream_config.stream_init_flags;
715 ssn->client.flags = stream_config.stream_init_flags;
716
717 StreamingBuffer x = STREAMING_BUFFER_INITIALIZER(&stream_config.sbcnf);
718 ssn->client.sb = x;
719 ssn->server.sb = x;
720
721 if (PKT_IS_TOSERVER(p)) {
722 ssn->client.tcp_flags = p->tcph ? p->tcph->th_flags : 0;
723 ssn->server.tcp_flags = 0;
724 } else if (PKT_IS_TOCLIENT(p)) {
725 ssn->server.tcp_flags = p->tcph ? p->tcph->th_flags : 0;
726 ssn->client.tcp_flags = 0;
727 }
728 }
729
730 return ssn;
731 }
732
StreamTcpPacketSetState(Packet * p,TcpSession * ssn,uint8_t state)733 static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn,
734 uint8_t state)
735 {
736 if (state == ssn->state || PKT_IS_PSEUDOPKT(p))
737 return;
738
739 ssn->pstate = ssn->state;
740 ssn->state = state;
741
742 /* update the flow state */
743 switch(ssn->state) {
744 case TCP_ESTABLISHED:
745 case TCP_FIN_WAIT1:
746 case TCP_FIN_WAIT2:
747 case TCP_CLOSING:
748 case TCP_CLOSE_WAIT:
749 FlowUpdateState(p->flow, FLOW_STATE_ESTABLISHED);
750 break;
751 case TCP_LAST_ACK:
752 case TCP_TIME_WAIT:
753 case TCP_CLOSED:
754 FlowUpdateState(p->flow, FLOW_STATE_CLOSED);
755 break;
756 }
757 }
758
759 /**
760 * \brief Function to set the OS policy for the given stream based on the
761 * destination of the received packet.
762 *
763 * \param stream TcpStream of which os_policy needs to set
764 * \param p Packet which is used to set the os policy
765 */
StreamTcpSetOSPolicy(TcpStream * stream,Packet * p)766 void StreamTcpSetOSPolicy(TcpStream *stream, Packet *p)
767 {
768 int ret = 0;
769
770 if (PKT_IS_IPV4(p)) {
771 /* Get the OS policy based on destination IP address, as destination
772 OS will decide how to react on the anomalies of newly received
773 packets */
774 ret = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
775 if (ret > 0)
776 stream->os_policy = ret;
777 else
778 stream->os_policy = OS_POLICY_DEFAULT;
779
780 } else if (PKT_IS_IPV6(p)) {
781 /* Get the OS policy based on destination IP address, as destination
782 OS will decide how to react on the anomalies of newly received
783 packets */
784 ret = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
785 if (ret > 0)
786 stream->os_policy = ret;
787 else
788 stream->os_policy = OS_POLICY_DEFAULT;
789 }
790
791 if (stream->os_policy == OS_POLICY_BSD_RIGHT)
792 stream->os_policy = OS_POLICY_BSD;
793 else if (stream->os_policy == OS_POLICY_OLD_SOLARIS)
794 stream->os_policy = OS_POLICY_SOLARIS;
795
796 SCLogDebug("Policy is %"PRIu8"", stream->os_policy);
797
798 }
799
800 /**
801 * \brief macro to update last_ack only if the new value is higher
802 *
803 * \param ssn session
804 * \param stream stream to update
805 * \param ack ACK value to test and set
806 */
807 #define StreamTcpUpdateLastAck(ssn, stream, ack) { \
808 if (SEQ_GT((ack), (stream)->last_ack)) \
809 { \
810 SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \
811 if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \
812 SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \
813 } else { \
814 SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \
815 }\
816 (stream)->last_ack = (ack); \
817 StreamTcpSackPruneList((stream)); \
818 } else { \
819 SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \
820 (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \
821 }\
822 }
823
824 #define StreamTcpAsyncLastAckUpdate(ssn, stream) { \
825 if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \
826 if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \
827 uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \
828 (stream)->last_ack += ack_diff; \
829 SCLogDebug("ssn %p: ASYNC last_ack set to %"PRIu32", moved %u forward", \
830 (ssn), (stream)->next_seq, ack_diff); \
831 } \
832 } \
833 }
834
835 #define StreamTcpUpdateNextSeq(ssn, stream, seq) { \
836 (stream)->next_seq = seq; \
837 SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \
838 StreamTcpAsyncLastAckUpdate((ssn), (stream)); \
839 }
840
841 /**
842 * \brief macro to update next_win only if the new value is higher
843 *
844 * \param ssn session
845 * \param stream stream to update
846 * \param win window value to test and set
847 */
848 #define StreamTcpUpdateNextWin(ssn, stream, win) { \
849 uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \
850 if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \
851 (stream)->next_win = ((win) + sacked_size__); \
852 SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \
853 } \
854 }
855
StreamTcpCloseSsnWithReset(Packet * p,TcpSession * ssn)856 static inline void StreamTcpCloseSsnWithReset(Packet *p, TcpSession *ssn)
857 {
858 ssn->flags |= STREAMTCP_FLAG_CLOSED_BY_RST;
859 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
860 SCLogDebug("ssn %p: (state: %s) Reset received and state changed to "
861 "TCP_CLOSED", ssn, StreamTcpStateAsString(ssn->state));
862 }
863
StreamTcpPacketIsRetransmission(TcpStream * stream,Packet * p)864 static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p)
865 {
866 if (p->payload_len == 0)
867 SCReturnInt(0);
868
869 /* retransmission of already partially ack'd data */
870 if (SEQ_LT(TCP_GET_SEQ(p), stream->last_ack) && SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack))
871 {
872 StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION);
873 SCReturnInt(1);
874 }
875
876 /* retransmission of already ack'd data */
877 if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) {
878 StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION);
879 SCReturnInt(1);
880 }
881
882 /* retransmission of in flight data */
883 if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->next_seq)) {
884 StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION);
885 SCReturnInt(2);
886 }
887
888 SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", TCP_GET_SEQ(p),
889 p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack, stream->next_seq);
890 SCReturnInt(0);
891 }
892
893 /**
894 * \internal
895 * \brief Function to handle the TCP_CLOSED or NONE state. The function handles
896 * packets while the session state is None which means a newly
897 * initialized structure, or a fully closed session.
898 *
899 * \param tv Thread Variable containig input/output queue, cpu affinity
900 * \param p Packet which has to be handled in this TCP state.
901 * \param stt Strean Thread module registered to handle the stream handling
902 *
903 * \retval 0 ok
904 * \retval -1 error
905 */
StreamTcpPacketStateNone(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)906 static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p,
907 StreamTcpThread *stt, TcpSession *ssn,
908 PacketQueueNoLock *pq)
909 {
910 if (p->tcph->th_flags & TH_RST) {
911 StreamTcpSetEvent(p, STREAM_RST_BUT_NO_SESSION);
912 SCLogDebug("RST packet received, no session setup");
913 return -1;
914
915 } else if (p->tcph->th_flags & TH_FIN) {
916 StreamTcpSetEvent(p, STREAM_FIN_BUT_NO_SESSION);
917 SCLogDebug("FIN packet received, no session setup");
918 return -1;
919
920 /* SYN/ACK */
921 } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
922 if (stream_config.midstream == FALSE &&
923 stream_config.async_oneside == FALSE)
924 return 0;
925
926 if (ssn == NULL) {
927 ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
928 if (ssn == NULL) {
929 StatsIncr(tv, stt->counter_tcp_ssn_memcap);
930 return -1;
931 }
932 StatsIncr(tv, stt->counter_tcp_sessions);
933 StatsIncr(tv, stt->counter_tcp_midstream_pickups);
934 }
935
936 /* reverse packet and flow */
937 SCLogDebug("reversing flow and packet");
938 PacketSwap(p);
939 FlowSwap(p->flow);
940
941 /* set the state */
942 StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
943 SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
944 "TCP_SYN_RECV", ssn);
945 ssn->flags |= STREAMTCP_FLAG_MIDSTREAM;
946 /* Flag used to change the direct in the later stage in the session */
947 ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_SYNACK;
948 if (stream_config.async_oneside) {
949 SCLogDebug("ssn %p: =~ ASYNC", ssn);
950 ssn->flags |= STREAMTCP_FLAG_ASYNC;
951 }
952
953 /* sequence number & window */
954 ssn->server.isn = TCP_GET_SEQ(p);
955 STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
956 ssn->server.next_seq = ssn->server.isn + 1;
957 ssn->server.window = TCP_GET_WINDOW(p);
958 SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
959
960 ssn->client.isn = TCP_GET_ACK(p) - 1;
961 STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
962 ssn->client.next_seq = ssn->client.isn + 1;
963
964 ssn->client.last_ack = TCP_GET_ACK(p);
965 ssn->server.last_ack = TCP_GET_SEQ(p);
966
967 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
968
969 /** If the client has a wscale option the server had it too,
970 * so set the wscale for the server to max. Otherwise none
971 * will have the wscale opt just like it should. */
972 if (TCP_HAS_WSCALE(p)) {
973 ssn->client.wscale = TCP_GET_WSCALE(p);
974 ssn->server.wscale = TCP_WSCALE_MAX;
975 SCLogDebug("ssn %p: wscale enabled. client %u server %u",
976 ssn, ssn->client.wscale, ssn->server.wscale);
977 }
978
979 SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
980 " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
981 ssn->client.isn, ssn->client.next_seq,
982 ssn->client.last_ack);
983 SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
984 " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
985 ssn->server.isn, ssn->server.next_seq,
986 ssn->server.last_ack);
987
988 /* Set the timestamp value for both streams, if packet has timestamp
989 * option enabled.*/
990 if (TCP_HAS_TS(p)) {
991 ssn->server.last_ts = TCP_GET_TSVAL(p);
992 ssn->client.last_ts = TCP_GET_TSECR(p);
993 SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
994 "ssn->client.last_ts %" PRIu32"", ssn,
995 ssn->server.last_ts, ssn->client.last_ts);
996
997 ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
998
999 ssn->server.last_pkt_ts = p->ts.tv_sec;
1000 if (ssn->server.last_ts == 0)
1001 ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1002 if (ssn->client.last_ts == 0)
1003 ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1004
1005 } else {
1006 ssn->server.last_ts = 0;
1007 ssn->client.last_ts = 0;
1008 }
1009
1010 if (TCP_GET_SACKOK(p) == 1) {
1011 ssn->flags |= STREAMTCP_FLAG_SACKOK;
1012 SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
1013 "SACK permitted for both sides", ssn);
1014 }
1015 return 0;
1016
1017 } else if (p->tcph->th_flags & TH_SYN) {
1018 if (ssn == NULL) {
1019 ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
1020 if (ssn == NULL) {
1021 StatsIncr(tv, stt->counter_tcp_ssn_memcap);
1022 return -1;
1023 }
1024
1025 StatsIncr(tv, stt->counter_tcp_sessions);
1026 }
1027
1028 /* set the state */
1029 StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
1030 SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
1031
1032 if (stream_config.async_oneside) {
1033 SCLogDebug("ssn %p: =~ ASYNC", ssn);
1034 ssn->flags |= STREAMTCP_FLAG_ASYNC;
1035 }
1036
1037 /* set the sequence numbers and window */
1038 ssn->client.isn = TCP_GET_SEQ(p);
1039 STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
1040 ssn->client.next_seq = ssn->client.isn + 1;
1041
1042 /* Set the stream timestamp value, if packet has timestamp option
1043 * enabled. */
1044 if (TCP_HAS_TS(p)) {
1045 ssn->client.last_ts = TCP_GET_TSVAL(p);
1046 SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
1047
1048 if (ssn->client.last_ts == 0)
1049 ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1050
1051 ssn->client.last_pkt_ts = p->ts.tv_sec;
1052 ssn->client.flags |= STREAMTCP_STREAM_FLAG_TIMESTAMP;
1053 }
1054
1055 ssn->server.window = TCP_GET_WINDOW(p);
1056 if (TCP_HAS_WSCALE(p)) {
1057 ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE;
1058 ssn->server.wscale = TCP_GET_WSCALE(p);
1059 }
1060
1061 if (TCP_GET_SACKOK(p) == 1) {
1062 ssn->flags |= STREAMTCP_FLAG_CLIENT_SACKOK;
1063 SCLogDebug("ssn %p: SACK permitted on SYN packet", ssn);
1064 }
1065
1066 if (TCP_HAS_TFO(p)) {
1067 ssn->flags |= STREAMTCP_FLAG_TCP_FAST_OPEN;
1068 if (p->payload_len) {
1069 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
1070 SCLogDebug("ssn: %p (TFO) [len: %d] isn %u base_seq %u next_seq %u payload len %u",
1071 ssn, p->tcpvars.tfo.len, ssn->client.isn, ssn->client.base_seq, ssn->client.next_seq, p->payload_len);
1072 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
1073 }
1074 }
1075
1076 SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
1077 "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
1078 "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
1079 ssn->client.last_ack);
1080
1081 } else if (p->tcph->th_flags & TH_ACK) {
1082 if (stream_config.midstream == FALSE)
1083 return 0;
1084
1085 if (ssn == NULL) {
1086 ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
1087 if (ssn == NULL) {
1088 StatsIncr(tv, stt->counter_tcp_ssn_memcap);
1089 return -1;
1090 }
1091 StatsIncr(tv, stt->counter_tcp_sessions);
1092 StatsIncr(tv, stt->counter_tcp_midstream_pickups);
1093 }
1094 /* set the state */
1095 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1096 SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
1097 "TCP_ESTABLISHED", ssn);
1098
1099 ssn->flags = STREAMTCP_FLAG_MIDSTREAM;
1100 ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED;
1101 if (stream_config.async_oneside) {
1102 SCLogDebug("ssn %p: =~ ASYNC", ssn);
1103 ssn->flags |= STREAMTCP_FLAG_ASYNC;
1104 }
1105
1106 /** window scaling for midstream pickups, we can't do much other
1107 * than assume that it's set to the max value: 14 */
1108 ssn->client.wscale = TCP_WSCALE_MAX;
1109 ssn->server.wscale = TCP_WSCALE_MAX;
1110
1111 /* set the sequence numbers and window */
1112 ssn->client.isn = TCP_GET_SEQ(p) - 1;
1113 STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
1114 ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
1115 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1116 ssn->client.last_ack = TCP_GET_SEQ(p);
1117 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1118 SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
1119 ssn, ssn->client.isn, ssn->client.next_seq);
1120
1121 ssn->server.isn = TCP_GET_ACK(p) - 1;
1122 STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
1123 ssn->server.next_seq = ssn->server.isn + 1;
1124 ssn->server.last_ack = TCP_GET_ACK(p);
1125 ssn->server.next_win = ssn->server.last_ack;
1126
1127 SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
1128 "ssn->server.next_win %"PRIu32"", ssn,
1129 ssn->client.next_win, ssn->server.next_win);
1130 SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
1131 "ssn->server.last_ack %"PRIu32"", ssn,
1132 ssn->client.last_ack, ssn->server.last_ack);
1133
1134 /* Set the timestamp value for both streams, if packet has timestamp
1135 * option enabled.*/
1136 if (TCP_HAS_TS(p)) {
1137 ssn->client.last_ts = TCP_GET_TSVAL(p);
1138 ssn->server.last_ts = TCP_GET_TSECR(p);
1139 SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1140 "ssn->client.last_ts %" PRIu32"", ssn,
1141 ssn->server.last_ts, ssn->client.last_ts);
1142
1143 ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
1144
1145 ssn->client.last_pkt_ts = p->ts.tv_sec;
1146 if (ssn->server.last_ts == 0)
1147 ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1148 if (ssn->client.last_ts == 0)
1149 ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1150
1151 } else {
1152 ssn->server.last_ts = 0;
1153 ssn->client.last_ts = 0;
1154 }
1155
1156 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
1157
1158 ssn->flags |= STREAMTCP_FLAG_SACKOK;
1159 SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
1160
1161 } else {
1162 SCLogDebug("default case");
1163 }
1164
1165 return 0;
1166 }
1167
1168 /** \internal
1169 * \brief Setup TcpStateQueue based on SYN/ACK packet
1170 */
StreamTcp3whsSynAckToStateQueue(Packet * p,TcpStateQueue * q)1171 static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
1172 {
1173 q->flags = 0;
1174 q->wscale = 0;
1175 q->ts = 0;
1176 q->win = TCP_GET_WINDOW(p);
1177 q->seq = TCP_GET_SEQ(p);
1178 q->ack = TCP_GET_ACK(p);
1179 q->pkt_ts = p->ts.tv_sec;
1180
1181 if (TCP_GET_SACKOK(p) == 1)
1182 q->flags |= STREAMTCP_QUEUE_FLAG_SACK;
1183
1184 if (TCP_HAS_WSCALE(p)) {
1185 q->flags |= STREAMTCP_QUEUE_FLAG_WS;
1186 q->wscale = TCP_GET_WSCALE(p);
1187 }
1188 if (TCP_HAS_TS(p)) {
1189 q->flags |= STREAMTCP_QUEUE_FLAG_TS;
1190 q->ts = TCP_GET_TSVAL(p);
1191 }
1192 }
1193
1194 /** \internal
1195 * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
1196 * \retval q or NULL */
StreamTcp3whsFindSynAckBySynAck(TcpSession * ssn,Packet * p)1197 static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
1198 {
1199 TcpStateQueue *q = ssn->queue;
1200 TcpStateQueue search;
1201
1202 StreamTcp3whsSynAckToStateQueue(p, &search);
1203
1204 while (q != NULL) {
1205 if (search.flags == q->flags &&
1206 search.wscale == q->wscale &&
1207 search.win == q->win &&
1208 search.seq == q->seq &&
1209 search.ack == q->ack &&
1210 search.ts == q->ts) {
1211 return q;
1212 }
1213
1214 q = q->next;
1215 }
1216
1217 return q;
1218 }
1219
StreamTcp3whsQueueSynAck(TcpSession * ssn,Packet * p)1220 static int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
1221 {
1222 /* first see if this is already in our list */
1223 if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
1224 return 0;
1225
1226 if (ssn->queue_len == stream_config.max_synack_queued) {
1227 SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
1228 StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_FLOOD);
1229 return -1;
1230 }
1231
1232 if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
1233 SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
1234 return -1;
1235 }
1236
1237 TcpStateQueue *q = SCMalloc(sizeof(*q));
1238 if (unlikely(q == NULL)) {
1239 SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
1240 return -1;
1241 }
1242 memset(q, 0x00, sizeof(*q));
1243 StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
1244
1245 StreamTcp3whsSynAckToStateQueue(p, q);
1246
1247 /* put in list */
1248 q->next = ssn->queue;
1249 ssn->queue = q;
1250 ssn->queue_len++;
1251 return 0;
1252 }
1253
1254 /** \internal
1255 * \brief Find the Queued SYN/ACK that goes with this ACK
1256 * \retval q or NULL */
StreamTcp3whsFindSynAckByAck(TcpSession * ssn,Packet * p)1257 static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
1258 {
1259 uint32_t ack = TCP_GET_SEQ(p);
1260 uint32_t seq = TCP_GET_ACK(p) - 1;
1261 TcpStateQueue *q = ssn->queue;
1262
1263 while (q != NULL) {
1264 if (seq == q->seq &&
1265 ack == q->ack) {
1266 return q;
1267 }
1268
1269 q = q->next;
1270 }
1271
1272 return NULL;
1273 }
1274
1275 /** \internal
1276 * \brief Update SSN after receiving a valid SYN/ACK
1277 *
1278 * Normally we update the SSN from the SYN/ACK packet. But in case
1279 * of queued SYN/ACKs, we can use one of those.
1280 *
1281 * \param ssn TCP session
1282 * \param p Packet
1283 * \param q queued state if used, NULL otherwise
1284 *
1285 * To make sure all SYN/ACK based state updates are in one place,
1286 * this function can updated based on Packet or TcpStateQueue, where
1287 * the latter takes precedence.
1288 */
StreamTcp3whsSynAckUpdate(TcpSession * ssn,Packet * p,TcpStateQueue * q)1289 static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
1290 {
1291 TcpStateQueue update;
1292 if (likely(q == NULL)) {
1293 StreamTcp3whsSynAckToStateQueue(p, &update);
1294 q = &update;
1295 }
1296
1297 if (ssn->state != TCP_SYN_RECV) {
1298 /* update state */
1299 StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1300 SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
1301 }
1302 /* sequence number & window */
1303 ssn->server.isn = q->seq;
1304 STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
1305 ssn->server.next_seq = ssn->server.isn + 1;
1306
1307 ssn->client.window = q->win;
1308 SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
1309
1310 /* Set the timestamp values used to validate the timestamp of
1311 * received packets.*/
1312 if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
1313 (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP))
1314 {
1315 ssn->server.last_ts = q->ts;
1316 SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
1317 "ssn->client.last_ts %" PRIu32"", ssn,
1318 ssn->server.last_ts, ssn->client.last_ts);
1319 ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
1320 ssn->server.last_pkt_ts = q->pkt_ts;
1321 if (ssn->server.last_ts == 0)
1322 ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1323 } else {
1324 ssn->client.last_ts = 0;
1325 ssn->server.last_ts = 0;
1326 ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1327 }
1328
1329 ssn->client.last_ack = q->ack;
1330 ssn->server.last_ack = ssn->server.isn + 1;
1331
1332 /** check for the presense of the ws ptr to determine if we
1333 * support wscale at all */
1334 if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1335 (q->flags & STREAMTCP_QUEUE_FLAG_WS))
1336 {
1337 ssn->client.wscale = q->wscale;
1338 } else {
1339 ssn->client.wscale = 0;
1340 }
1341
1342 if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1343 (q->flags & STREAMTCP_QUEUE_FLAG_SACK)) {
1344 ssn->flags |= STREAMTCP_FLAG_SACKOK;
1345 SCLogDebug("ssn %p: SACK permitted for session", ssn);
1346 } else {
1347 ssn->flags &= ~STREAMTCP_FLAG_SACKOK;
1348 }
1349
1350 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1351 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1352 SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
1353 ssn->server.next_win);
1354 SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
1355 ssn->client.next_win);
1356 SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
1357 "ssn->server.next_seq %" PRIu32 ", "
1358 "ssn->server.last_ack %" PRIu32 " "
1359 "(ssn->client.last_ack %" PRIu32 ")", ssn,
1360 ssn->server.isn, ssn->server.next_seq,
1361 ssn->server.last_ack, ssn->client.last_ack);
1362
1363 /* unset the 4WHS flag as we received this SYN/ACK as part of a
1364 * (so far) valid 3WHS */
1365 if (ssn->flags & STREAMTCP_FLAG_4WHS)
1366 SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
1367 " so considering 3WHS", ssn);
1368
1369 ssn->flags &=~ STREAMTCP_FLAG_4WHS;
1370 }
1371
1372 /** \internal
1373 * \brief detect timestamp anomalies when processing responses to the
1374 * SYN packet.
1375 * \retval true packet is ok
1376 * \retval false packet is bad
1377 */
StateSynSentValidateTimestamp(TcpSession * ssn,Packet * p)1378 static inline bool StateSynSentValidateTimestamp(TcpSession *ssn, Packet *p)
1379 {
1380 /* we only care about evil server here, so skip TS packets */
1381 if (PKT_IS_TOSERVER(p) || !(TCP_HAS_TS(p))) {
1382 return true;
1383 }
1384
1385 TcpStream *receiver_stream = &ssn->client;
1386 uint32_t ts_echo = TCP_GET_TSECR(p);
1387 if ((receiver_stream->flags & STREAMTCP_STREAM_FLAG_TIMESTAMP) != 0) {
1388 if (receiver_stream->last_ts != 0 && ts_echo != 0 &&
1389 ts_echo != receiver_stream->last_ts)
1390 {
1391 SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn,
1392 ts_echo, receiver_stream->last_ts);
1393 return false;
1394 }
1395 } else {
1396 if (receiver_stream->last_ts == 0 && ts_echo != 0) {
1397 SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn,
1398 ts_echo, receiver_stream->last_ts);
1399 return false;
1400 }
1401 }
1402 return true;
1403 }
1404
1405 /**
1406 * \brief Function to handle the TCP_SYN_SENT state. The function handles
1407 * SYN, SYN/ACK, RST packets and correspondingly changes the connection
1408 * state.
1409 *
1410 * \param tv Thread Variable containig input/output queue, cpu affinity
1411 * \param p Packet which has to be handled in this TCP state.
1412 * \param stt Strean Thread module registered to handle the stream handling
1413 */
1414
StreamTcpPacketStateSynSent(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)1415 static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p,
1416 StreamTcpThread *stt, TcpSession *ssn,
1417 PacketQueueNoLock *pq)
1418 {
1419 if (ssn == NULL)
1420 return -1;
1421
1422 SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ?
1423 "toclient":"toserver");
1424
1425 /* check for bad responses */
1426 if (StateSynSentValidateTimestamp(ssn, p) == false)
1427 return -1;
1428
1429 /* RST */
1430 if (p->tcph->th_flags & TH_RST) {
1431 if (!StreamTcpValidateRst(ssn, p))
1432 return -1;
1433
1434 if (PKT_IS_TOSERVER(p)) {
1435 if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) &&
1436 SEQ_EQ(TCP_GET_WINDOW(p), 0) &&
1437 SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1)))
1438 {
1439 SCLogDebug("ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
1440 ssn->server.flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
1441 StreamTcpCloseSsnWithReset(p, ssn);
1442 }
1443 } else {
1444 ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
1445 SCLogDebug("ssn->client.flags |= STREAMTCP_STREAM_FLAG_RST_RECV");
1446 StreamTcpCloseSsnWithReset(p, ssn);
1447 }
1448
1449 /* FIN */
1450 } else if (p->tcph->th_flags & TH_FIN) {
1451 /** \todo */
1452
1453 /* SYN/ACK */
1454 } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
1455 if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOSERVER(p)) {
1456 SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
1457
1458 /* Check if the SYN/ACK packet ack's the earlier
1459 * received SYN packet. */
1460 if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->server.isn + 1))) {
1461 StreamTcpSetEvent(p, STREAM_4WHS_SYNACK_WITH_WRONG_ACK);
1462
1463 SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %"PRIu32""
1464 " != %" PRIu32 " from stream", ssn,
1465 TCP_GET_ACK(p), ssn->server.isn + 1);
1466 return -1;
1467 }
1468
1469 /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
1470 * packet. */
1471 if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
1472 StreamTcpSetEvent(p, STREAM_4WHS_SYNACK_WITH_WRONG_SYN);
1473
1474 SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %"PRIu32""
1475 " != %" PRIu32 " from *first* SYN pkt", ssn,
1476 TCP_GET_SEQ(p), ssn->client.isn);
1477 return -1;
1478 }
1479
1480
1481 /* update state */
1482 StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
1483 SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
1484
1485 /* sequence number & window */
1486 ssn->client.isn = TCP_GET_SEQ(p);
1487 STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
1488 ssn->client.next_seq = ssn->client.isn + 1;
1489
1490 ssn->server.window = TCP_GET_WINDOW(p);
1491 SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn,
1492 ssn->client.window);
1493
1494 /* Set the timestamp values used to validate the timestamp of
1495 * received packets. */
1496 if ((TCP_HAS_TS(p)) &&
1497 (ssn->server.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP))
1498 {
1499 ssn->client.last_ts = TCP_GET_TSVAL(p);
1500 SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32" "
1501 "ssn->server.last_ts %" PRIu32"", ssn,
1502 ssn->client.last_ts, ssn->server.last_ts);
1503 ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
1504 ssn->client.last_pkt_ts = p->ts.tv_sec;
1505 if (ssn->client.last_ts == 0)
1506 ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1507 } else {
1508 ssn->server.last_ts = 0;
1509 ssn->client.last_ts = 0;
1510 ssn->server.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1511 }
1512
1513 ssn->server.last_ack = TCP_GET_ACK(p);
1514 ssn->client.last_ack = ssn->client.isn + 1;
1515
1516 /** check for the presense of the ws ptr to determine if we
1517 * support wscale at all */
1518 if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
1519 (TCP_HAS_WSCALE(p)))
1520 {
1521 ssn->server.wscale = TCP_GET_WSCALE(p);
1522 } else {
1523 ssn->server.wscale = 0;
1524 }
1525
1526 if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
1527 TCP_GET_SACKOK(p) == 1) {
1528 ssn->flags |= STREAMTCP_FLAG_SACKOK;
1529 SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
1530 }
1531
1532 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1533 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1534 SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn,
1535 ssn->client.next_win);
1536 SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn,
1537 ssn->server.next_win);
1538 SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
1539 "ssn->client.next_seq %" PRIu32 ", "
1540 "ssn->client.last_ack %" PRIu32 " "
1541 "(ssn->server.last_ack %" PRIu32 ")", ssn,
1542 ssn->client.isn, ssn->client.next_seq,
1543 ssn->client.last_ack, ssn->server.last_ack);
1544
1545 /* done here */
1546 return 0;
1547 }
1548
1549 if (PKT_IS_TOSERVER(p)) {
1550 StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION);
1551 SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
1552 return -1;
1553 }
1554
1555 if (!(TCP_HAS_TFO(p) || (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN))) {
1556 /* Check if the SYN/ACK packet ack's the earlier
1557 * received SYN packet. */
1558 if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) {
1559 StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK);
1560 SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1561 "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1562 ssn->client.isn + 1);
1563 return -1;
1564 }
1565 } else {
1566 if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.next_seq))) {
1567 StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK);
1568 SCLogDebug("ssn %p: (TFO) ACK mismatch, packet ACK %" PRIu32 " != "
1569 "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1570 ssn->client.next_seq);
1571 return -1;
1572 }
1573 SCLogDebug("ssn %p: (TFO) ACK match, packet ACK %" PRIu32 " == "
1574 "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1575 ssn->client.next_seq);
1576
1577 ssn->flags |= STREAMTCP_FLAG_TCP_FAST_OPEN;
1578 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1579 }
1580 StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
1581
1582 } else if (p->tcph->th_flags & TH_SYN) {
1583 SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
1584 if (ssn->flags & STREAMTCP_FLAG_4WHS) {
1585 SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
1586 "4WHS SYN", ssn);
1587 }
1588
1589 if (PKT_IS_TOCLIENT(p)) {
1590 /** a SYN only packet in the opposite direction could be:
1591 * http://www.breakingpointsystems.com/community/blog/tcp-
1592 * portals-the-three-way-handshake-is-a-lie
1593 *
1594 * \todo improve resetting the session */
1595
1596 /* indicate that we're dealing with 4WHS here */
1597 ssn->flags |= STREAMTCP_FLAG_4WHS;
1598 SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
1599
1600 /* set the sequence numbers and window for server
1601 * We leave the ssn->client.isn in place as we will
1602 * check the SYN/ACK pkt with that.
1603 */
1604 ssn->server.isn = TCP_GET_SEQ(p);
1605 STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
1606 ssn->server.next_seq = ssn->server.isn + 1;
1607
1608 /* Set the stream timestamp value, if packet has timestamp
1609 * option enabled. */
1610 if (TCP_HAS_TS(p)) {
1611 ssn->server.last_ts = TCP_GET_TSVAL(p);
1612 SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
1613
1614 if (ssn->server.last_ts == 0)
1615 ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1616 ssn->server.last_pkt_ts = p->ts.tv_sec;
1617 ssn->server.flags |= STREAMTCP_STREAM_FLAG_TIMESTAMP;
1618 }
1619
1620 ssn->server.window = TCP_GET_WINDOW(p);
1621 if (TCP_HAS_WSCALE(p)) {
1622 ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE;
1623 ssn->server.wscale = TCP_GET_WSCALE(p);
1624 } else {
1625 ssn->flags &= ~STREAMTCP_FLAG_SERVER_WSCALE;
1626 ssn->server.wscale = 0;
1627 }
1628
1629 if (TCP_GET_SACKOK(p) == 1) {
1630 ssn->flags |= STREAMTCP_FLAG_CLIENT_SACKOK;
1631 } else {
1632 ssn->flags &= ~STREAMTCP_FLAG_CLIENT_SACKOK;
1633 }
1634
1635 SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
1636 "ssn->server.next_seq %" PRIu32 ", "
1637 "ssn->server.last_ack %"PRIu32"", ssn,
1638 ssn->server.isn, ssn->server.next_seq,
1639 ssn->server.last_ack);
1640 SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
1641 "ssn->client.next_seq %" PRIu32 ", "
1642 "ssn->client.last_ack %"PRIu32"", ssn,
1643 ssn->client.isn, ssn->client.next_seq,
1644 ssn->client.last_ack);
1645 }
1646
1647 /** \todo check if it's correct or set event */
1648
1649 } else if (p->tcph->th_flags & TH_ACK) {
1650 /* Handle the asynchronous stream, when we receive a SYN packet
1651 and now istead of receving a SYN/ACK we receive a ACK from the
1652 same host, which sent the SYN, this suggests the ASNYC streams.*/
1653 if (stream_config.async_oneside == FALSE)
1654 return 0;
1655
1656 /* we are in AYNC (one side) mode now. */
1657
1658 /* one side async means we won't see a SYN/ACK, so we can
1659 * only check the SYN. */
1660 if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) {
1661 StreamTcpSetEvent(p, STREAM_3WHS_ASYNC_WRONG_SEQ);
1662
1663 SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
1664 "%" PRIu32 " from stream",ssn, TCP_GET_SEQ(p),
1665 ssn->client.next_seq);
1666 return -1;
1667 }
1668
1669 ssn->flags |= STREAMTCP_FLAG_ASYNC;
1670 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1671 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1672
1673 ssn->client.window = TCP_GET_WINDOW(p);
1674 ssn->client.last_ack = TCP_GET_SEQ(p);
1675 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1676
1677 /* Set the server side parameters */
1678 ssn->server.isn = TCP_GET_ACK(p) - 1;
1679 STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
1680 ssn->server.next_seq = ssn->server.isn + 1;
1681 ssn->server.last_ack = ssn->server.next_seq;
1682 ssn->server.next_win = ssn->server.last_ack;
1683
1684 SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
1685 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
1686 "ssn->client.next_seq %" PRIu32 ""
1687 ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
1688 + p->payload_len, ssn->client.next_seq);
1689
1690 /* if SYN had wscale, assume it to be supported. Otherwise
1691 * we know it not to be supported. */
1692 if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
1693 ssn->client.wscale = TCP_WSCALE_MAX;
1694 }
1695
1696 /* Set the timestamp values used to validate the timestamp of
1697 * received packets.*/
1698 if (TCP_HAS_TS(p) &&
1699 (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP))
1700 {
1701 ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
1702 ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_TIMESTAMP;
1703 ssn->client.last_pkt_ts = p->ts.tv_sec;
1704 } else {
1705 ssn->client.last_ts = 0;
1706 ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
1707 }
1708
1709 if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
1710 ssn->flags |= STREAMTCP_FLAG_SACKOK;
1711 }
1712
1713 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
1714 &ssn->client, p, pq);
1715
1716 } else {
1717 SCLogDebug("ssn %p: default case", ssn);
1718 }
1719
1720 return 0;
1721 }
1722
1723 /**
1724 * \brief Function to handle the TCP_SYN_RECV state. The function handles
1725 * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
1726 * the connection state.
1727 *
1728 * \param tv Thread Variable containig input/output queue, cpu affinity
1729 * \param p Packet which has to be handled in this TCP state.
1730 * \param stt Strean Thread module registered to handle the stream handling
1731 *
1732 * \retval 0 ok
1733 * \retval -1 error
1734 */
1735
StreamTcpPacketStateSynRecv(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)1736 static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p,
1737 StreamTcpThread *stt, TcpSession *ssn,
1738 PacketQueueNoLock *pq)
1739 {
1740 if (ssn == NULL)
1741 return -1;
1742
1743 if (p->tcph->th_flags & TH_RST) {
1744 if (!StreamTcpValidateRst(ssn, p))
1745 return -1;
1746
1747 uint8_t reset = TRUE;
1748 /* After receiveing the RST in SYN_RECV state and if detection
1749 evasion flags has been set, then the following operating
1750 systems will not closed the connection. As they consider the
1751 packet as stray packet and not belonging to the current
1752 session, for more information check
1753 http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
1754 if (ssn->flags & STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT) {
1755 if (PKT_IS_TOSERVER(p)) {
1756 if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
1757 (ssn->server.os_policy == OS_POLICY_OLD_LINUX) ||
1758 (ssn->server.os_policy == OS_POLICY_SOLARIS))
1759 {
1760 reset = FALSE;
1761 SCLogDebug("Detection evasion has been attempted, so"
1762 " not resetting the connection !!");
1763 }
1764 } else {
1765 if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
1766 (ssn->client.os_policy == OS_POLICY_OLD_LINUX) ||
1767 (ssn->client.os_policy == OS_POLICY_SOLARIS))
1768 {
1769 reset = FALSE;
1770 SCLogDebug("Detection evasion has been attempted, so"
1771 " not resetting the connection !!");
1772 }
1773 }
1774 }
1775
1776 if (reset == TRUE) {
1777 StreamTcpCloseSsnWithReset(p, ssn);
1778
1779 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1780 StreamTcpHandleTimestamp(ssn, p);
1781 }
1782 }
1783
1784 } else if (p->tcph->th_flags & TH_FIN) {
1785 /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
1786 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1787 if (!StreamTcpValidateTimestamp(ssn, p))
1788 return -1;
1789 }
1790
1791 if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1)
1792 return -1;
1793
1794 /* SYN/ACK */
1795 } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
1796 SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
1797
1798 if (PKT_IS_TOSERVER(p)) {
1799 SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
1800
1801 StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV);
1802 return -1;
1803 }
1804
1805 /* Check if the SYN/ACK packets ACK matches the earlier
1806 * received SYN/ACK packet. */
1807 if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
1808 SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
1809 "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
1810 ssn->client.isn + 1);
1811
1812 StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK);
1813 return -1;
1814 }
1815
1816 /* Check if the SYN/ACK packet SEQ the earlier
1817 * received SYN/ACK packet, server resend with different ISN. */
1818 if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
1819 SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
1820 "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
1821 ssn->client.isn);
1822
1823 if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
1824 return -1;
1825 SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
1826 }
1827
1828 } else if (p->tcph->th_flags & TH_SYN) {
1829 SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
1830
1831 if (PKT_IS_TOCLIENT(p)) {
1832 SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
1833
1834 StreamTcpSetEvent(p, STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV);
1835 return -1;
1836 }
1837
1838 if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
1839 SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
1840
1841 StreamTcpSetEvent(p, STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV);
1842 return -1;
1843 }
1844
1845 } else if (p->tcph->th_flags & TH_ACK) {
1846 if (ssn->queue_len) {
1847 SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
1848 TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
1849 if (q != NULL) {
1850 SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
1851 StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
1852 } else {
1853 SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
1854 }
1855 }
1856
1857
1858 /* If the timestamp option is enabled for both the streams, then
1859 * validate the received packet timestamp value against the
1860 * stream->last_ts. If the timestamp is valid then process the
1861 * packet normally otherwise the drop the packet (RFC 1323)*/
1862 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1863 if (!(StreamTcpValidateTimestamp(ssn, p))) {
1864 return -1;
1865 }
1866 }
1867
1868 if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) {
1869 SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
1870
1871 if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) {
1872 SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
1873 StreamTcpSetEvent(p, STREAM_4WHS_WRONG_SEQ);
1874 return -1;
1875 }
1876
1877 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
1878 SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
1879 StreamTcpSetEvent(p, STREAM_4WHS_INVALID_ACK);
1880 return -1;
1881 }
1882
1883 SCLogDebug("4WHS normal pkt");
1884 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
1885 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
1886 TCP_GET_SEQ(p), TCP_GET_ACK(p));
1887
1888 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1889 StreamTcpHandleTimestamp(ssn, p);
1890 }
1891
1892 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
1893 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
1894 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1895 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1896
1897 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1898 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1899
1900 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
1901 &ssn->server, p, pq);
1902
1903 SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
1904 "ssn->client.last_ack %"PRIu32"", ssn,
1905 ssn->client.next_win, ssn->client.last_ack);
1906 return 0;
1907 }
1908
1909 bool ack_indicates_missed_3whs_ack_packet = false;
1910 /* Check if the ACK received is in right direction. But when we have
1911 * picked up a mid stream session after missing the initial SYN pkt,
1912 * in this case the ACK packet can arrive from either client (normal
1913 * case) or from server itself (asynchronous streams). Therefore
1914 * the check has been avoided in this case */
1915 if (PKT_IS_TOCLIENT(p)) {
1916 /* special case, handle 4WHS, so SYN/ACK in the opposite
1917 * direction */
1918 if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK) {
1919 SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
1920 "pickup session",ssn);
1921 /* fall through */
1922 } else if (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) {
1923 SCLogDebug("ssn %p: ACK received on TFO session",ssn);
1924 /* fall through */
1925
1926 } else {
1927 /* if we missed traffic between the S/SA and the current
1928 * 'wrong direction' ACK, we could end up here. In IPS
1929 * reject it. But in IDS mode we continue.
1930 *
1931 * IPS rejects as it should see all packets, so pktloss
1932 * should lead to retransmissions. As this can also be
1933 * pattern for MOTS/MITM injection attacks, we need to be
1934 * careful.
1935 */
1936 if (StreamTcpInlineMode()) {
1937 if (p->payload_len > 0 &&
1938 SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) &&
1939 SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
1940 /* packet loss is possible but unlikely here */
1941 SCLogDebug("ssn %p: possible data injection", ssn);
1942 StreamTcpSetEvent(p, STREAM_3WHS_ACK_DATA_INJECT);
1943 return -1;
1944 }
1945
1946 SCLogDebug("ssn %p: ACK received in the wrong direction",
1947 ssn);
1948 StreamTcpSetEvent(p, STREAM_3WHS_ACK_IN_WRONG_DIR);
1949 return -1;
1950 }
1951 ack_indicates_missed_3whs_ack_packet = true;
1952 }
1953 }
1954
1955 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
1956 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
1957 TCP_GET_ACK(p));
1958
1959 /* Check both seq and ack number before accepting the packet and
1960 changing to ESTABLISHED state */
1961 if ((SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) &&
1962 SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) {
1963 SCLogDebug("normal pkt");
1964
1965 /* process the packet normal, No Async streams :) */
1966
1967 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
1968 StreamTcpHandleTimestamp(ssn, p);
1969 }
1970
1971 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
1972 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
1973 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
1974
1975 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
1976
1977 if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
1978 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
1979 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
1980 ssn->server.next_win = ssn->server.last_ack +
1981 ssn->server.window;
1982 if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
1983 /* window scaling for midstream pickups, we can't do much
1984 * other than assume that it's set to the max value: 14 */
1985 ssn->server.wscale = TCP_WSCALE_MAX;
1986 ssn->client.wscale = TCP_WSCALE_MAX;
1987 ssn->flags |= STREAMTCP_FLAG_SACKOK;
1988 }
1989 }
1990
1991 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
1992 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
1993
1994 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
1995 &ssn->client, p, pq);
1996
1997 /* If asynchronous stream handling is allowed then set the session,
1998 if packet's seq number is equal the expected seq no.*/
1999 } else if (stream_config.async_oneside == TRUE &&
2000 (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)))
2001 {
2002 /*set the ASYNC flag used to indicate the session as async stream
2003 and helps in relaxing the windows checks.*/
2004 ssn->flags |= STREAMTCP_FLAG_ASYNC;
2005 ssn->server.next_seq += p->payload_len;
2006 ssn->server.last_ack = TCP_GET_SEQ(p);
2007
2008 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2009 ssn->client.last_ack = TCP_GET_ACK(p);
2010
2011 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2012 StreamTcpHandleTimestamp(ssn, p);
2013 }
2014
2015 if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2016 ssn->server.window = TCP_GET_WINDOW(p);
2017 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2018 /* window scaling for midstream pickups, we can't do much
2019 * other than assume that it's set to the max value: 14 */
2020 ssn->server.wscale = TCP_WSCALE_MAX;
2021 ssn->client.wscale = TCP_WSCALE_MAX;
2022 ssn->flags |= STREAMTCP_FLAG_SACKOK;
2023 }
2024
2025 SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
2026 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2027 "ssn->server.next_seq %" PRIu32
2028 , ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
2029 + p->payload_len, ssn->server.next_seq);
2030
2031 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2032 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2033
2034 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
2035 &ssn->server, p, pq);
2036 /* Upon receiving the packet with correct seq number and wrong
2037 ACK number, it causes the other end to send RST. But some target
2038 system (Linux & solaris) does not RST the connection, so it is
2039 likely to avoid the detection */
2040 } else if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)){
2041 ssn->flags |= STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT;
2042 SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
2043 ssn);
2044
2045 StreamTcpSetEvent(p, STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION);
2046 return -1;
2047
2048 /* SYN/ACK followed by more TOCLIENT suggesting packet loss */
2049 } else if (PKT_IS_TOCLIENT(p) && !StreamTcpInlineMode() &&
2050 SEQ_GT(TCP_GET_SEQ(p), ssn->client.next_seq) &&
2051 SEQ_GT(TCP_GET_ACK(p), ssn->client.last_ack)) {
2052 SCLogDebug("ssn %p: ACK for missing data", ssn);
2053
2054 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2055 StreamTcpHandleTimestamp(ssn, p);
2056 }
2057
2058 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2059
2060 ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2061 SCLogDebug("ssn %p: ACK for missing data: ssn->server.next_seq %u", ssn,
2062 ssn->server.next_seq);
2063 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2064
2065 ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
2066
2067 ssn->client.window = TCP_GET_WINDOW(p);
2068 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2069
2070 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2071 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2072
2073 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
2074
2075 /* if we get a packet with a proper ack, but a seq that is beyond
2076 * next_seq but in-window, we probably missed some packets */
2077 } else if (SEQ_GT(TCP_GET_SEQ(p), ssn->client.next_seq) &&
2078 SEQ_LEQ(TCP_GET_SEQ(p), ssn->client.next_win) &&
2079 SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) {
2080 SCLogDebug("ssn %p: ACK for missing data", ssn);
2081
2082 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2083 StreamTcpHandleTimestamp(ssn, p);
2084 }
2085
2086 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2087
2088 ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2089 SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
2090 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2091
2092 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2093
2094 if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
2095 ssn->client.window = TCP_GET_WINDOW(p);
2096 ssn->server.next_win = ssn->server.last_ack +
2097 ssn->server.window;
2098 /* window scaling for midstream pickups, we can't do much
2099 * other than assume that it's set to the max value: 14 */
2100 ssn->server.wscale = TCP_WSCALE_MAX;
2101 ssn->client.wscale = TCP_WSCALE_MAX;
2102 ssn->flags |= STREAMTCP_FLAG_SACKOK;
2103 }
2104
2105 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2106 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2107
2108 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
2109 &ssn->client, p, pq);
2110
2111 /* toclient packet: after having missed the 3whs's final ACK */
2112 } else if ((ack_indicates_missed_3whs_ack_packet ||
2113 (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN)) &&
2114 SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) &&
2115 SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
2116 if (ack_indicates_missed_3whs_ack_packet) {
2117 SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn);
2118 } else {
2119 SCLogDebug("ssn %p: (TFO) expected packet fits perfectly after SYN/ACK", ssn);
2120 }
2121
2122 StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2123
2124 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2125 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2126
2127 StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
2128 SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
2129
2130 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
2131 &ssn->server, p, pq);
2132
2133 } else {
2134 SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
2135
2136 StreamTcpSetEvent(p, STREAM_3WHS_WRONG_SEQ_WRONG_ACK);
2137 return -1;
2138 }
2139
2140 SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
2141 "ssn->server.last_ack %"PRIu32"", ssn,
2142 ssn->server.next_win, ssn->server.last_ack);
2143 } else {
2144 SCLogDebug("ssn %p: default case", ssn);
2145 }
2146
2147 return 0;
2148 }
2149
2150 /**
2151 * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2152 * sent by the client to server. The function handles
2153 * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2154 * the reassembly.
2155 *
2156 * Timestamp has already been checked at this point.
2157 *
2158 * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2159 * \param ssn Pointer to the current TCP session
2160 * \param p Packet which has to be handled in this TCP state.
2161 * \param stt Strean Thread module registered to handle the stream handling
2162 */
HandleEstablishedPacketToServer(ThreadVars * tv,TcpSession * ssn,Packet * p,StreamTcpThread * stt,PacketQueueNoLock * pq)2163 static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Packet *p,
2164 StreamTcpThread *stt, PacketQueueNoLock *pq)
2165 {
2166 SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2167 "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
2168 TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p));
2169
2170 if (StreamTcpValidateAck(ssn, &(ssn->server), p) == -1) {
2171 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2172 StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK);
2173 return -1;
2174 }
2175
2176 /* check for Keep Alive */
2177 if ((p->payload_len == 0 || p->payload_len == 1) &&
2178 (TCP_GET_SEQ(p) == (ssn->client.next_seq - 1))) {
2179 SCLogDebug("ssn %p: pkt is keep alive", ssn);
2180
2181 /* normal pkt */
2182 } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack))) {
2183 if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2184 SCLogDebug("ssn %p: server => Asynchrouns stream, packet SEQ"
2185 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2186 " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2187 "%" PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2188 p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2189 ssn->client.last_ack, ssn->client.next_win,
2190 TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2191
2192 /* update the last_ack to current seq number as the session is
2193 * async and other stream is not updating it anymore :( */
2194 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2195
2196 } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p)) &&
2197 (stream_config.async_oneside == TRUE) &&
2198 (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2199 SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
2200 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2201 "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2202 "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2203 p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2204 ssn->client.last_ack, ssn->client.next_win,
2205 TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2206
2207 /* it seems we missed SYN and SYN/ACK packets of this session.
2208 * Update the last_ack to current seq number as the session
2209 * is async and other stream is not updating it anymore :( */
2210 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2211 ssn->flags |= STREAMTCP_FLAG_ASYNC;
2212
2213 } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
2214 (stream_config.async_oneside == TRUE) &&
2215 (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
2216 SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
2217 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2218 "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2219 "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2220 p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2221 ssn->client.last_ack, ssn->client.next_win,
2222 TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2223
2224 /* it seems we missed SYN and SYN/ACK packets of this session.
2225 * Update the last_ack to current seq number as the session
2226 * is async and other stream is not updating it anymore :(*/
2227 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
2228 ssn->flags |= STREAMTCP_FLAG_ASYNC;
2229
2230 /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2231 * In this case we do accept the data before last_ack if it is (partly)
2232 * beyond next seq */
2233 } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
2234 SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->client.next_seq))
2235 {
2236 SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2237 " before last_ack %"PRIu32", after next_seq %"PRIu32":"
2238 " acked data that we haven't seen before",
2239 ssn, TCP_GET_SEQ(p), p->payload_len, ssn->client.last_ack, ssn->client.next_seq);
2240 if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq)) {
2241 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2242 }
2243 } else {
2244 SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
2245 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
2246 "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2247 "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2248 p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2249 ssn->client.last_ack, ssn->client.next_win,
2250 TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
2251
2252 SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
2253 StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK);
2254 return -1;
2255 }
2256 }
2257
2258 int zerowindowprobe = 0;
2259 /* zero window probe */
2260 if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->client.next_seq && ssn->client.window == 0) {
2261 SCLogDebug("ssn %p: zero window probe", ssn);
2262 zerowindowprobe = 1;
2263
2264 /* expected packet */
2265 } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2266 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2267
2268 /* not completely as expected, but valid */
2269 } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->client.next_seq) &&
2270 SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->client.next_seq))
2271 {
2272 StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
2273 SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32
2274 " (started before next_seq, ended after)",
2275 ssn, ssn->client.next_seq);
2276
2277 /* if next_seq has fallen behind last_ack, we got some catching up to do */
2278 } else if (SEQ_LT(ssn->client.next_seq, ssn->client.last_ack)) {
2279 StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
2280 SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32
2281 " (next_seq had fallen behind last_ack)",
2282 ssn, ssn->client.next_seq);
2283
2284 } else {
2285 SCLogDebug("ssn %p: no update to ssn->client.next_seq %"PRIu32
2286 " SEQ %u SEQ+ %u last_ack %u",
2287 ssn, ssn->client.next_seq,
2288 TCP_GET_SEQ(p), TCP_GET_SEQ(p)+p->payload_len, ssn->client.last_ack);
2289 }
2290
2291 /* in window check */
2292 if (zerowindowprobe) {
2293 SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2294 } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
2295 (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC)))
2296 {
2297 SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
2298 "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
2299
2300 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2301 SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
2302 ssn->server.window);
2303
2304 /* Check if the ACK value is sane and inside the window limit */
2305 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2306 SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, ssn->server.next_seq);
2307
2308 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2309 StreamTcpHandleTimestamp(ssn, p);
2310 }
2311
2312 StreamTcpSackUpdatePacket(&ssn->server, p);
2313
2314 /* update next_win */
2315 StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
2316
2317 /* handle data (if any) */
2318 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
2319
2320 } else {
2321 SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
2322 "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2323 "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
2324 "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2325 p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2326 ssn->client.last_ack, ssn->client.next_win,
2327 (TCP_GET_SEQ(p) + p->payload_len) - ssn->client.next_win);
2328 SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
2329 StreamTcpSackedSize(&ssn->client));
2330 StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW);
2331 return -1;
2332 }
2333 return 0;
2334 }
2335
2336 /**
2337 * \brief Function to handle the TCP_ESTABLISHED state packets, which are
2338 * sent by the server to client. The function handles
2339 * ACK packets and call StreamTcpReassembleHandleSegment() to handle
2340 * the reassembly
2341 *
2342 * Timestamp has already been checked at this point.
2343 *
2344 * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2345 * \param ssn Pointer to the current TCP session
2346 * \param p Packet which has to be handled in this TCP state.
2347 * \param stt Strean Thread module registered to handle the stream handling
2348 */
HandleEstablishedPacketToClient(ThreadVars * tv,TcpSession * ssn,Packet * p,StreamTcpThread * stt,PacketQueueNoLock * pq)2349 static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Packet *p,
2350 StreamTcpThread *stt, PacketQueueNoLock *pq)
2351 {
2352 SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
2353 " ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
2354 TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p));
2355
2356 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2357 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2358 StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK);
2359 return -1;
2360 }
2361
2362 /* To get the server window value from the servers packet, when connection
2363 is picked up as midstream */
2364 if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
2365 (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED))
2366 {
2367 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2368 ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
2369 ssn->flags &= ~STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED;
2370 SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
2371 "%" PRIu32 "", ssn, ssn->server.next_win);
2372 }
2373
2374 /* check for Keep Alive */
2375 if ((p->payload_len == 0 || p->payload_len == 1) &&
2376 (TCP_GET_SEQ(p) == (ssn->server.next_seq - 1))) {
2377 SCLogDebug("ssn %p: pkt is keep alive", ssn);
2378
2379 /* normal pkt */
2380 } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->server.last_ack))) {
2381 if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
2382
2383 SCLogDebug("ssn %p: client => Asynchrouns stream, packet SEQ"
2384 " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2385 " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
2386 " %"PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2387 p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2388 ssn->server.last_ack, ssn->server.next_win,
2389 TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
2390
2391 ssn->server.last_ack = TCP_GET_SEQ(p);
2392
2393 /* if last ack is beyond next_seq, we have accepted ack's for missing data.
2394 * In this case we do accept the data before last_ack if it is (partly)
2395 * beyond next seq */
2396 } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
2397 SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->server.next_seq))
2398 {
2399 SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2400 " before last_ack %"PRIu32", after next_seq %"PRIu32":"
2401 " acked data that we haven't seen before",
2402 ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2403 if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq)) {
2404 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2405 }
2406 } else {
2407 SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
2408 " before last_ack %"PRIu32". next_seq %"PRIu32,
2409 ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
2410 StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK);
2411 return -1;
2412 }
2413 }
2414
2415 int zerowindowprobe = 0;
2416 /* zero window probe */
2417 if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->server.next_seq && ssn->server.window == 0) {
2418 SCLogDebug("ssn %p: zero window probe", ssn);
2419 zerowindowprobe = 1;
2420
2421 /* expected packet */
2422 } else if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
2423 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2424
2425 /* not completely as expected, but valid */
2426 } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->server.next_seq) &&
2427 SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->server.next_seq))
2428 {
2429 StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2430 SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32
2431 " (started before next_seq, ended after)",
2432 ssn, ssn->server.next_seq);
2433
2434 /* if next_seq has fallen behind last_ack, we got some catching up to do */
2435 } else if (SEQ_LT(ssn->server.next_seq, ssn->server.last_ack)) {
2436 StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));
2437 SCLogDebug("ssn %p: ssn->server.next_seq %"PRIu32
2438 " (next_seq had fallen behind last_ack)",
2439 ssn, ssn->server.next_seq);
2440
2441 } else {
2442 SCLogDebug("ssn %p: no update to ssn->server.next_seq %"PRIu32
2443 " SEQ %u SEQ+ %u last_ack %u",
2444 ssn, ssn->server.next_seq,
2445 TCP_GET_SEQ(p), TCP_GET_SEQ(p)+p->payload_len, ssn->server.last_ack);
2446 }
2447
2448 if (zerowindowprobe) {
2449 SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
2450 } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
2451 (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC)))
2452 {
2453 SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
2454 "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
2455 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2456 SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
2457 ssn->client.window);
2458
2459 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2460
2461 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2462 StreamTcpHandleTimestamp(ssn, p);
2463 }
2464
2465 StreamTcpSackUpdatePacket(&ssn->client, p);
2466
2467 StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
2468
2469 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
2470 } else {
2471 SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
2472 "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
2473 " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
2474 "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
2475 p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
2476 ssn->server.last_ack, ssn->server.next_win,
2477 TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
2478 StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW);
2479 return -1;
2480 }
2481 return 0;
2482 }
2483
2484 /**
2485 * \internal
2486 *
2487 * \brief Find the highest sequence number needed to consider all segments as ACK'd
2488 *
2489 * Used to treat all segments as ACK'd upon receiving a valid RST.
2490 *
2491 * \param stream stream to inspect the segments from
2492 * \param seq sequence number to check against
2493 *
2494 * \retval ack highest ack we need to set
2495 */
StreamTcpResetGetMaxAck(TcpStream * stream,uint32_t seq)2496 static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
2497 {
2498 uint32_t ack = seq;
2499
2500 if (STREAM_HAS_SEEN_DATA(stream)) {
2501 const uint32_t tail_seq = STREAM_SEQ_RIGHT_EDGE(stream);
2502 if (SEQ_GT(tail_seq, ack)) {
2503 ack = tail_seq;
2504 }
2505 }
2506
2507 SCReturnUInt(ack);
2508 }
2509
2510 /**
2511 * \brief Function to handle the TCP_ESTABLISHED state. The function handles
2512 * ACK, FIN, RST packets and correspondingly changes the connection
2513 * state. The function handles the data inside packets and call
2514 * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
2515 *
2516 * \param tv Thread Variable containig input/output queue, cpu affinity etc.
2517 * \param p Packet which has to be handled in this TCP state.
2518 * \param stt Strean Thread module registered to handle the stream handling
2519 */
2520
StreamTcpPacketStateEstablished(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)2521 static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p,
2522 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq)
2523 {
2524 if (ssn == NULL)
2525 return -1;
2526
2527 if (p->tcph->th_flags & TH_RST) {
2528 if (!StreamTcpValidateRst(ssn, p))
2529 return -1;
2530
2531 if (PKT_IS_TOSERVER(p)) {
2532 StreamTcpCloseSsnWithReset(p, ssn);
2533
2534 ssn->server.next_seq = TCP_GET_ACK(p);
2535 ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2536 SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2537 ssn->server.next_seq);
2538 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2539
2540 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
2541 StreamTcpUpdateLastAck(ssn, &ssn->server,
2542 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
2543
2544 StreamTcpUpdateLastAck(ssn, &ssn->client,
2545 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
2546
2547 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2548 StreamTcpHandleTimestamp(ssn, p);
2549 }
2550
2551 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
2552 &ssn->client, p, pq);
2553 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2554 "%" PRIu32 "", ssn, ssn->client.next_seq,
2555 ssn->server.last_ack);
2556
2557 /* don't return packets to pools here just yet, the pseudo
2558 * packet will take care, otherwise the normal session
2559 * cleanup. */
2560 } else {
2561 StreamTcpCloseSsnWithReset(p, ssn);
2562
2563 ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1;
2564 ssn->client.next_seq = TCP_GET_ACK(p);
2565
2566 SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2567 ssn->server.next_seq);
2568 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2569
2570 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
2571 StreamTcpUpdateLastAck(ssn, &ssn->client,
2572 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
2573
2574 StreamTcpUpdateLastAck(ssn, &ssn->server,
2575 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
2576
2577 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2578 StreamTcpHandleTimestamp(ssn, p);
2579 }
2580
2581 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
2582 &ssn->server, p, pq);
2583 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2584 "%" PRIu32 "", ssn, ssn->server.next_seq,
2585 ssn->client.last_ack);
2586
2587 /* don't return packets to pools here just yet, the pseudo
2588 * packet will take care, otherwise the normal session
2589 * cleanup. */
2590 }
2591
2592 } else if (p->tcph->th_flags & TH_FIN) {
2593 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2594 if (!StreamTcpValidateTimestamp(ssn, p))
2595 return -1;
2596 }
2597
2598 SCLogDebug("ssn (%p: FIN received SEQ"
2599 " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
2600 " win %" PRIu32 "", ssn, ssn->server.next_seq,
2601 ssn->client.last_ack, ssn->server.next_win,
2602 ssn->server.window);
2603
2604 if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1)
2605 return -1;
2606
2607 /* SYN/ACK */
2608 } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
2609 SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
2610 ssn);
2611
2612 if (PKT_IS_TOSERVER(p)) {
2613 SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
2614
2615 StreamTcpSetEvent(p, STREAM_EST_SYNACK_TOSERVER);
2616 return -1;
2617 }
2618
2619 /* Check if the SYN/ACK packets ACK matches the earlier
2620 * received SYN/ACK packet. */
2621 if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
2622 SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
2623 "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
2624 ssn->client.isn + 1);
2625
2626 StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK);
2627 return -1;
2628 }
2629
2630 /* Check if the SYN/ACK packet SEQ the earlier
2631 * received SYN packet. */
2632 if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
2633 SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
2634 "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
2635 ssn->client.isn + 1);
2636
2637 StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ);
2638 return -1;
2639 }
2640
2641 if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
2642 /* a resend of a SYN while we are established already -- fishy */
2643 StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND);
2644 return -1;
2645 }
2646
2647 SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
2648 "Likely due server not receiving final ACK in 3whs", ssn);
2649 return 0;
2650
2651 } else if (p->tcph->th_flags & TH_SYN) {
2652 SCLogDebug("ssn %p: SYN packet on state ESTABLISHED... resent", ssn);
2653 if (PKT_IS_TOCLIENT(p)) {
2654 SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
2655
2656 StreamTcpSetEvent(p, STREAM_EST_SYN_TOCLIENT);
2657 return -1;
2658 }
2659
2660 if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
2661 SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
2662
2663 StreamTcpSetEvent(p, STREAM_EST_SYN_RESEND_DIFF_SEQ);
2664 return -1;
2665 }
2666
2667 /* a resend of a SYN while we are established already -- fishy */
2668 StreamTcpSetEvent(p, STREAM_EST_SYN_RESEND);
2669 return -1;
2670
2671 } else if (p->tcph->th_flags & TH_ACK) {
2672 /* Urgent pointer size can be more than the payload size, as it tells
2673 * the future coming data from the sender will be handled urgently
2674 * until data of size equal to urgent offset has been processed
2675 * (RFC 2147) */
2676
2677 /* If the timestamp option is enabled for both the streams, then
2678 * validate the received packet timestamp value against the
2679 * stream->last_ts. If the timestamp is valid then process the
2680 * packet normally otherwise the drop the packet (RFC 1323) */
2681 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2682 if (!StreamTcpValidateTimestamp(ssn, p))
2683 return -1;
2684 }
2685
2686 if (PKT_IS_TOSERVER(p)) {
2687 /* Process the received packet to server */
2688 HandleEstablishedPacketToServer(tv, ssn, p, stt, pq);
2689
2690 SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
2691 " next win %" PRIu32 ", win %" PRIu32 "", ssn,
2692 ssn->client.next_seq, ssn->server.last_ack
2693 ,ssn->client.next_win, ssn->client.window);
2694
2695 } else { /* implied to client */
2696 if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
2697 ssn->flags |= STREAMTCP_FLAG_3WHS_CONFIRMED;
2698 SCLogDebug("3whs is now confirmed by server");
2699 }
2700
2701 /* Process the received packet to client */
2702 HandleEstablishedPacketToClient(tv, ssn, p, stt, pq);
2703
2704 SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
2705 " next win %" PRIu32 ", win %" PRIu32 "", ssn,
2706 ssn->server.next_seq, ssn->client.last_ack,
2707 ssn->server.next_win, ssn->server.window);
2708 }
2709 } else {
2710 SCLogDebug("ssn %p: default case", ssn);
2711 }
2712
2713 return 0;
2714 }
2715
2716 /**
2717 * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
2718 * TCP_ESTABLISHED and changes to another TCP state as required.
2719 *
2720 * \param tv Thread Variable containig input/output queue, cpu affinity
2721 * \param p Packet which has to be handled in this TCP state.
2722 * \param stt Strean Thread module registered to handle the stream handling
2723 *
2724 * \retval 0 success
2725 * \retval -1 something wrong with the packet
2726 */
2727
StreamTcpHandleFin(ThreadVars * tv,StreamTcpThread * stt,TcpSession * ssn,Packet * p,PacketQueueNoLock * pq)2728 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt,
2729 TcpSession *ssn, Packet *p, PacketQueueNoLock *pq)
2730 {
2731 if (PKT_IS_TOSERVER(p)) {
2732 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
2733 " ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
2734 TCP_GET_ACK(p));
2735
2736 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2737 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2738 StreamTcpSetEvent(p, STREAM_FIN_INVALID_ACK);
2739 return -1;
2740 }
2741
2742 if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
2743 SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
2744 {
2745 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
2746 "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
2747 ssn->client.next_seq);
2748
2749 StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW);
2750 return -1;
2751 }
2752
2753 if (p->tcph->th_flags & TH_SYN) {
2754 SCLogDebug("ssn %p: FIN+SYN", ssn);
2755 StreamTcpSetEvent(p, STREAM_FIN_SYN);
2756 return -1;
2757 }
2758 StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
2759 SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
2760
2761 if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))
2762 ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2763
2764 SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
2765 ssn->client.next_seq);
2766 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2767
2768 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2769
2770 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2771 StreamTcpHandleTimestamp(ssn, p);
2772 }
2773
2774 /* Update the next_seq, in case if we have missed the client packet
2775 and server has already received and acked it */
2776 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
2777 ssn->server.next_seq = TCP_GET_ACK(p);
2778
2779 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
2780
2781 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
2782 ssn, ssn->client.next_seq, ssn->server.last_ack);
2783 } else { /* implied to client */
2784 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
2785 "ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
2786 TCP_GET_ACK(p));
2787
2788 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2789 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2790 StreamTcpSetEvent(p, STREAM_FIN_INVALID_ACK);
2791 return -1;
2792 }
2793
2794 if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
2795 SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
2796 {
2797 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
2798 "%" PRIu32 " from stream (last_ack %u win %u = %u)", ssn, TCP_GET_SEQ(p),
2799 ssn->server.next_seq, ssn->server.last_ack, ssn->server.window, (ssn->server.last_ack + ssn->server.window));
2800
2801 StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW);
2802 return -1;
2803 }
2804
2805 StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
2806 SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
2807
2808 if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))
2809 ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len;
2810
2811 SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
2812 ssn->server.next_seq);
2813 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2814
2815 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2816
2817 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2818 StreamTcpHandleTimestamp(ssn, p);
2819 }
2820
2821 /* Update the next_seq, in case if we have missed the client packet
2822 and server has already received and acked it */
2823 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
2824 ssn->client.next_seq = TCP_GET_ACK(p);
2825
2826 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
2827
2828 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
2829 ssn, ssn->server.next_seq, ssn->client.last_ack);
2830 }
2831
2832 return 0;
2833 }
2834
2835 /**
2836 * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
2837 * ACK, FIN, RST packets and correspondingly changes the connection
2838 * state.
2839 *
2840 * \param tv Thread Variable containig input/output queue, cpu affinity
2841 * \param p Packet which has to be handled in this TCP state.
2842 * \param stt Strean Thread module registered to handle the stream handling
2843 *
2844 * \retval 0 success
2845 * \retval -1 something wrong with the packet
2846 */
2847
StreamTcpPacketStateFinWait1(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)2848 static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p,
2849 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq)
2850 {
2851 if (ssn == NULL)
2852 return -1;
2853
2854 if (p->tcph->th_flags & TH_RST) {
2855 if (!StreamTcpValidateRst(ssn, p))
2856 return -1;
2857
2858 StreamTcpCloseSsnWithReset(p, ssn);
2859
2860 if (PKT_IS_TOSERVER(p)) {
2861 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
2862 StreamTcpUpdateLastAck(ssn, &ssn->server,
2863 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
2864
2865 StreamTcpUpdateLastAck(ssn, &ssn->client,
2866 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
2867
2868 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2869 StreamTcpHandleTimestamp(ssn, p);
2870 }
2871
2872 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
2873 &ssn->client, p, pq);
2874 } else {
2875 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
2876 StreamTcpUpdateLastAck(ssn, &ssn->client,
2877 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
2878
2879 StreamTcpUpdateLastAck(ssn, &ssn->server,
2880 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
2881
2882 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2883 StreamTcpHandleTimestamp(ssn, p);
2884 }
2885
2886 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
2887 &ssn->server, p, pq);
2888 }
2889
2890 } else if ((p->tcph->th_flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) {
2891 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2892 if (!StreamTcpValidateTimestamp(ssn, p))
2893 return -1;
2894 }
2895
2896 if (PKT_IS_TOSERVER(p)) {
2897 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
2898 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2899 TCP_GET_SEQ(p), TCP_GET_ACK(p));
2900 int retransmission = 0;
2901
2902 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
2903 SCLogDebug("ssn %p: packet is retransmission", ssn);
2904 retransmission = 1;
2905
2906 } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
2907 SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
2908 {
2909 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2910 " != %" PRIu32 " from stream", ssn,
2911 TCP_GET_SEQ(p), ssn->client.next_seq);
2912 StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
2913 return -1;
2914 }
2915
2916 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
2917 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2918 StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
2919 return -1;
2920 }
2921
2922 if (!retransmission) {
2923 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
2924 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
2925
2926 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
2927 }
2928
2929 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
2930
2931 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2932 StreamTcpHandleTimestamp(ssn, p);
2933 }
2934
2935 /* Update the next_seq, in case if we have missed the client
2936 packet and server has already received and acked it */
2937 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
2938 ssn->server.next_seq = TCP_GET_ACK(p);
2939
2940 if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2941 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
2942 }
2943
2944 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
2945 &ssn->client, p, pq);
2946
2947 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
2948 "%" PRIu32 "", ssn, ssn->client.next_seq,
2949 ssn->server.last_ack);
2950 } else { /* implied to client */
2951 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2952 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
2953 TCP_GET_SEQ(p), TCP_GET_ACK(p));
2954 int retransmission = 0;
2955
2956 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
2957 SCLogDebug("ssn %p: packet is retransmission", ssn);
2958 retransmission = 1;
2959 } else if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p)) &&
2960 SEQ_EQ(ssn->client.last_ack, TCP_GET_ACK(p))) {
2961 SCLogDebug("ssn %p: packet is retransmission", ssn);
2962 retransmission = 1;
2963
2964 } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
2965 SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) {
2966 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
2967 " != %" PRIu32 " from stream", ssn,
2968 TCP_GET_SEQ(p), ssn->server.next_seq);
2969 StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
2970 return -1;
2971 }
2972
2973 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
2974 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
2975 StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
2976 return -1;
2977 }
2978
2979 if (!retransmission) {
2980 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
2981 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
2982
2983 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
2984 }
2985
2986 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
2987
2988 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
2989 StreamTcpHandleTimestamp(ssn, p);
2990 }
2991
2992 /* Update the next_seq, in case if we have missed the client
2993 packet and server has already received and acked it */
2994 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
2995 ssn->client.next_seq = TCP_GET_ACK(p);
2996
2997 if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
2998 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
2999 }
3000
3001 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3002 &ssn->server, p, pq);
3003
3004 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3005 "%" PRIu32 "", ssn, ssn->server.next_seq,
3006 ssn->client.last_ack);
3007 }
3008
3009 } else if (p->tcph->th_flags & TH_FIN) {
3010 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3011 if (!StreamTcpValidateTimestamp(ssn, p))
3012 return -1;
3013 }
3014
3015 if (PKT_IS_TOSERVER(p)) {
3016 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3017 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3018 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3019 int retransmission = 0;
3020
3021 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3022 SCLogDebug("ssn %p: packet is retransmission", ssn);
3023 retransmission = 1;
3024
3025 } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
3026 SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3027 {
3028 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3029 " != %" PRIu32 " from stream", ssn,
3030 TCP_GET_SEQ(p), ssn->client.next_seq);
3031 StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
3032 return -1;
3033 }
3034
3035 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3036 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3037 StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
3038 return -1;
3039 }
3040
3041 if (!retransmission) {
3042 StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3043 SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3044
3045 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3046 }
3047
3048 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3049
3050 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3051 StreamTcpHandleTimestamp(ssn, p);
3052 }
3053
3054 /* Update the next_seq, in case if we have missed the client
3055 packet and server has already received and acked it */
3056 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3057 ssn->server.next_seq = TCP_GET_ACK(p);
3058
3059 if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3060 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3061 }
3062
3063 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3064 &ssn->client, p, pq);
3065
3066 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3067 "%" PRIu32 "", ssn, ssn->client.next_seq,
3068 ssn->server.last_ack);
3069 } else { /* implied to client */
3070 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3071 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3072 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3073
3074 int retransmission = 0;
3075
3076 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3077 SCLogDebug("ssn %p: packet is retransmission", ssn);
3078 retransmission = 1;
3079
3080 } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
3081 SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3082 {
3083 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3084 " != %" PRIu32 " from stream", ssn,
3085 TCP_GET_SEQ(p), ssn->server.next_seq);
3086 StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
3087 return -1;
3088 }
3089
3090 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3091 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3092 StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
3093 return -1;
3094 }
3095
3096 if (!retransmission) {
3097 StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
3098 SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
3099
3100 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3101 }
3102
3103 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3104
3105 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3106 StreamTcpHandleTimestamp(ssn, p);
3107 }
3108
3109 /* Update the next_seq, in case if we have missed the client
3110 packet and server has already received and acked it */
3111 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3112 ssn->client.next_seq = TCP_GET_ACK(p);
3113
3114 if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3115 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3116 }
3117
3118 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3119 &ssn->server, p, pq);
3120
3121 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3122 "%" PRIu32 "", ssn, ssn->server.next_seq,
3123 ssn->client.last_ack);
3124 }
3125 } else if (p->tcph->th_flags & TH_SYN) {
3126 SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
3127 StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
3128 return -1;
3129
3130 } else if (p->tcph->th_flags & TH_ACK) {
3131 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3132 if (!StreamTcpValidateTimestamp(ssn, p))
3133 return -1;
3134 }
3135
3136 if (PKT_IS_TOSERVER(p)) {
3137 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3138 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3139 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3140 int retransmission = 0;
3141
3142 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3143 SCLogDebug("ssn %p: packet is retransmission", ssn);
3144 retransmission = 1;
3145 }
3146
3147 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3148 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3149 StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
3150 return -1;
3151 }
3152
3153 if (!retransmission) {
3154 if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
3155 (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC)))
3156 {
3157 SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
3158 "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
3159
3160 if (TCP_GET_SEQ(p) == ssn->client.next_seq) {
3161 StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3162 SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3163 }
3164 } else {
3165 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3166 " != %" PRIu32 " from stream", ssn,
3167 TCP_GET_SEQ(p), ssn->client.next_seq);
3168
3169 StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ);
3170 return -1;
3171 }
3172
3173 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3174 }
3175
3176 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3177
3178 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3179 StreamTcpHandleTimestamp(ssn, p);
3180 }
3181
3182 /* Update the next_seq, in case if we have missed the client
3183 packet and server has already received and acked it */
3184 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3185 ssn->server.next_seq = TCP_GET_ACK(p);
3186
3187 if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3188 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3189 }
3190
3191 StreamTcpSackUpdatePacket(&ssn->server, p);
3192
3193 /* update next_win */
3194 StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3195
3196 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3197 &ssn->client, p, pq);
3198
3199 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3200 "%" PRIu32 "", ssn, ssn->client.next_seq,
3201 ssn->server.last_ack);
3202
3203 } else { /* implied to client */
3204
3205 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3206 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3207 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3208
3209 int retransmission = 0;
3210
3211 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3212 SCLogDebug("ssn %p: packet is retransmission", ssn);
3213 retransmission = 1;
3214 }
3215
3216 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3217 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3218 StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
3219 return -1;
3220 }
3221
3222 if (!retransmission) {
3223 if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
3224 (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC)))
3225 {
3226 SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
3227 "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
3228
3229 if (TCP_GET_SEQ(p) == ssn->server.next_seq) {
3230 StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
3231 SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
3232 }
3233 } else {
3234 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3235 " != %" PRIu32 " from stream", ssn,
3236 TCP_GET_SEQ(p), ssn->server.next_seq);
3237 StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ);
3238 return -1;
3239 }
3240
3241 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3242 }
3243
3244 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3245
3246 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3247 StreamTcpHandleTimestamp(ssn, p);
3248 }
3249
3250 /* Update the next_seq, in case if we have missed the client
3251 packet and server has already received and acked it */
3252 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3253 ssn->client.next_seq = TCP_GET_ACK(p);
3254
3255 if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3256 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3257 }
3258
3259 StreamTcpSackUpdatePacket(&ssn->client, p);
3260
3261 /* update next_win */
3262 StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3263
3264 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3265 &ssn->server, p, pq);
3266
3267 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3268 "%" PRIu32 "", ssn, ssn->server.next_seq,
3269 ssn->client.last_ack);
3270 }
3271 } else {
3272 SCLogDebug("ssn (%p): default case", ssn);
3273 }
3274
3275 return 0;
3276 }
3277
3278 /**
3279 * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
3280 * ACK, RST, FIN packets and correspondingly changes the connection
3281 * state.
3282 *
3283 * \param tv Thread Variable containig input/output queue, cpu affinity
3284 * \param p Packet which has to be handled in this TCP state.
3285 * \param stt Strean Thread module registered to handle the stream handling
3286 */
3287
StreamTcpPacketStateFinWait2(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)3288 static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p,
3289 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq)
3290 {
3291 if (ssn == NULL)
3292 return -1;
3293
3294 if (p->tcph->th_flags & TH_RST) {
3295 if (!StreamTcpValidateRst(ssn, p))
3296 return -1;
3297
3298 StreamTcpCloseSsnWithReset(p, ssn);
3299
3300 if (PKT_IS_TOSERVER(p)) {
3301 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3302 StreamTcpUpdateLastAck(ssn, &ssn->server,
3303 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3304
3305 StreamTcpUpdateLastAck(ssn, &ssn->client,
3306 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3307
3308 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3309 StreamTcpHandleTimestamp(ssn, p);
3310 }
3311
3312 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3313 &ssn->client, p, pq);
3314 } else {
3315 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3316 StreamTcpUpdateLastAck(ssn, &ssn->client,
3317 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3318
3319 StreamTcpUpdateLastAck(ssn, &ssn->server,
3320 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3321
3322 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3323 StreamTcpHandleTimestamp(ssn, p);
3324 }
3325
3326 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3327 &ssn->server, p, pq);
3328 }
3329
3330 } else if (p->tcph->th_flags & TH_FIN) {
3331 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3332 if (!StreamTcpValidateTimestamp(ssn, p))
3333 return -1;
3334 }
3335
3336 if (PKT_IS_TOSERVER(p)) {
3337 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3338 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3339 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3340 int retransmission = 0;
3341
3342 if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq - 1) &&
3343 SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) {
3344 SCLogDebug("ssn %p: retransmission", ssn);
3345 retransmission = 1;
3346 } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3347 SCLogDebug("ssn %p: packet is retransmission", ssn);
3348 retransmission = 1;
3349
3350 } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
3351 SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3352 {
3353 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
3354 "%" PRIu32 " != %" PRIu32 " from stream", ssn,
3355 TCP_GET_SEQ(p), ssn->client.next_seq);
3356 StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ);
3357 return -1;
3358 }
3359
3360 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3361 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3362 StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK);
3363 return -1;
3364 }
3365
3366 if (!retransmission) {
3367 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3368 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3369
3370 if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3371 StreamTcpUpdateNextSeq(
3372 ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3373 }
3374 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3375 }
3376
3377 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3378
3379 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3380 StreamTcpHandleTimestamp(ssn, p);
3381 }
3382
3383 /* Update the next_seq, in case if we have missed the client
3384 packet and server has already received and acked it */
3385 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3386 ssn->server.next_seq = TCP_GET_ACK(p);
3387
3388 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3389 &ssn->client, p, pq);
3390
3391 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3392 "%" PRIu32 "", ssn, ssn->client.next_seq,
3393 ssn->server.last_ack);
3394 } else { /* implied to client */
3395 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3396 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3397 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3398 int retransmission = 0;
3399
3400 if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq - 1) &&
3401 SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) {
3402 SCLogDebug("ssn %p: retransmission", ssn);
3403 retransmission = 1;
3404 } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3405 SCLogDebug("ssn %p: packet is retransmission", ssn);
3406 retransmission = 1;
3407
3408 } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
3409 SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3410 {
3411 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
3412 "%" PRIu32 " != %" PRIu32 " from stream", ssn,
3413 TCP_GET_SEQ(p), ssn->server.next_seq);
3414 StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ);
3415 return -1;
3416 }
3417
3418 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3419 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3420 StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK);
3421 return -1;
3422 }
3423
3424 if (!retransmission) {
3425 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3426 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3427
3428 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3429 }
3430
3431 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3432
3433 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3434 StreamTcpHandleTimestamp(ssn, p);
3435 }
3436
3437 /* Update the next_seq, in case if we have missed the client
3438 packet and server has already received and acked it */
3439 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3440 ssn->client.next_seq = TCP_GET_ACK(p);
3441
3442 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3443 &ssn->server, p, pq);
3444 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3445 "%" PRIu32 "", ssn, ssn->server.next_seq,
3446 ssn->client.last_ack);
3447 }
3448
3449 } else if (p->tcph->th_flags & TH_SYN) {
3450 SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
3451 StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
3452 return -1;
3453
3454 } else if (p->tcph->th_flags & TH_ACK) {
3455 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3456 if (!StreamTcpValidateTimestamp(ssn, p))
3457 return -1;
3458 }
3459
3460 if (PKT_IS_TOSERVER(p)) {
3461 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3462 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3463 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3464 int retransmission = 0;
3465
3466 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3467 SCLogDebug("ssn %p: packet is retransmission", ssn);
3468 retransmission = 1;
3469 }
3470
3471 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3472 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3473 StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK);
3474 return -1;
3475 }
3476
3477 if (!retransmission) {
3478 if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
3479 (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC)))
3480 {
3481 SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
3482 "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
3483
3484 } else {
3485 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3486 " != %" PRIu32 " from stream", ssn,
3487 TCP_GET_SEQ(p), ssn->client.next_seq);
3488 StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ);
3489 return -1;
3490 }
3491
3492 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3493 }
3494
3495 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3496
3497 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3498 StreamTcpHandleTimestamp(ssn, p);
3499 }
3500
3501 if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
3502 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3503 }
3504
3505 StreamTcpSackUpdatePacket(&ssn->server, p);
3506
3507 /* update next_win */
3508 StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
3509
3510 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3511 &ssn->client, p, pq);
3512
3513 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3514 "%" PRIu32 "", ssn, ssn->client.next_seq,
3515 ssn->server.last_ack);
3516 } else { /* implied to client */
3517 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3518 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3519 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3520 int retransmission = 0;
3521
3522 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3523 SCLogDebug("ssn %p: packet is retransmission", ssn);
3524 retransmission = 1;
3525 }
3526
3527 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3528 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3529 StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK);
3530 return -1;
3531 }
3532
3533 if (!retransmission) {
3534 if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
3535 (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC)))
3536 {
3537 SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
3538 "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
3539 } else {
3540 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3541 " != %" PRIu32 " from stream", ssn,
3542 TCP_GET_SEQ(p), ssn->server.next_seq);
3543 StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ);
3544 return -1;
3545 }
3546
3547 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3548 }
3549
3550 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3551
3552 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3553 StreamTcpHandleTimestamp(ssn, p);
3554 }
3555
3556 if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
3557 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
3558 }
3559
3560 StreamTcpSackUpdatePacket(&ssn->client, p);
3561
3562 /* update next_win */
3563 StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
3564
3565 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3566 &ssn->server, p, pq);
3567
3568 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3569 "%" PRIu32 "", ssn, ssn->server.next_seq,
3570 ssn->client.last_ack);
3571 }
3572 } else {
3573 SCLogDebug("ssn %p: default case", ssn);
3574 }
3575
3576 return 0;
3577 }
3578
3579 /**
3580 * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
3581 * the connection goes to TCP_TIME_WAIT state. The state has been
3582 * reached as both end application has been closed.
3583 *
3584 * \param tv Thread Variable containig input/output queue, cpu affinity
3585 * \param p Packet which has to be handled in this TCP state.
3586 * \param stt Strean Thread module registered to handle the stream handling
3587 */
3588
StreamTcpPacketStateClosing(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)3589 static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p,
3590 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq)
3591 {
3592 if (ssn == NULL)
3593 return -1;
3594
3595 if (p->tcph->th_flags & TH_RST) {
3596 if (!StreamTcpValidateRst(ssn, p))
3597 return -1;
3598
3599 StreamTcpCloseSsnWithReset(p, ssn);
3600
3601 if (PKT_IS_TOSERVER(p)) {
3602 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3603 StreamTcpUpdateLastAck(ssn, &ssn->server,
3604 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3605
3606 StreamTcpUpdateLastAck(ssn, &ssn->client,
3607 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3608
3609 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3610 StreamTcpHandleTimestamp(ssn, p);
3611 }
3612
3613 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3614 &ssn->client, p, pq);
3615 } else {
3616 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3617 StreamTcpUpdateLastAck(ssn, &ssn->client,
3618 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3619
3620 StreamTcpUpdateLastAck(ssn, &ssn->server,
3621 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3622
3623 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3624 StreamTcpHandleTimestamp(ssn, p);
3625 }
3626
3627 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3628 &ssn->server, p, pq);
3629 }
3630
3631 } else if (p->tcph->th_flags & TH_SYN) {
3632 SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
3633 StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
3634 return -1;
3635
3636 } else if (p->tcph->th_flags & TH_ACK) {
3637 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3638 if (!StreamTcpValidateTimestamp(ssn, p))
3639 return -1;
3640 }
3641
3642 if (PKT_IS_TOSERVER(p)) {
3643 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3644 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3645 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3646 int retransmission = 0;
3647 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3648 SCLogDebug("ssn %p: packet is retransmission", ssn);
3649 retransmission = 1;
3650 }
3651
3652 if (TCP_GET_SEQ(p) != ssn->client.next_seq) {
3653 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3654 " != %" PRIu32 " from stream", ssn,
3655 TCP_GET_SEQ(p), ssn->client.next_seq);
3656 StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ);
3657 return -1;
3658 }
3659
3660 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3661 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3662 StreamTcpSetEvent(p, STREAM_CLOSING_INVALID_ACK);
3663 return -1;
3664 }
3665
3666 if (!retransmission) {
3667 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3668 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3669
3670 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3671 }
3672
3673 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3674
3675 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3676 StreamTcpHandleTimestamp(ssn, p);
3677 }
3678 /* Update the next_seq, in case if we have missed the client
3679 packet and server has already received and acked it */
3680 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3681 ssn->server.next_seq = TCP_GET_ACK(p);
3682
3683 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3684 &ssn->client, p, pq);
3685 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3686 "%" PRIu32 "", ssn, ssn->client.next_seq,
3687 ssn->server.last_ack);
3688 } else { /* implied to client */
3689 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3690 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3691 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3692 int retransmission = 0;
3693 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3694 SCLogDebug("ssn %p: packet is retransmission", ssn);
3695 retransmission = 1;
3696 }
3697
3698 if (TCP_GET_SEQ(p) != ssn->server.next_seq) {
3699 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3700 " != %" PRIu32 " from stream", ssn,
3701 TCP_GET_SEQ(p), ssn->server.next_seq);
3702 StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ);
3703 return -1;
3704 }
3705
3706 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3707 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3708 StreamTcpSetEvent(p, STREAM_CLOSING_INVALID_ACK);
3709 return -1;
3710 }
3711
3712 if (!retransmission) {
3713 StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
3714 SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
3715
3716 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3717 }
3718
3719 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3720
3721 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3722 StreamTcpHandleTimestamp(ssn, p);
3723 }
3724
3725 /* Update the next_seq, in case if we have missed the client
3726 packet and server has already received and acked it */
3727 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3728 ssn->client.next_seq = TCP_GET_ACK(p);
3729
3730 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3731 &ssn->server, p, pq);
3732 SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
3733 "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
3734 ssn->server.next_seq, ssn->client.last_ack);
3735 }
3736 } else {
3737 SCLogDebug("ssn %p: default case", ssn);
3738 }
3739
3740 return 0;
3741 }
3742
3743 /**
3744 * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
3745 * packet from server the connection goes to TCP_LAST_ACK state.
3746 * The state is possible only for server host.
3747 *
3748 * \param tv Thread Variable containig input/output queue, cpu affinity
3749 * \param p Packet which has to be handled in this TCP state.
3750 * \param stt Strean Thread module registered to handle the stream handling
3751 */
3752
StreamTcpPacketStateCloseWait(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)3753 static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p,
3754 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq)
3755 {
3756 SCEnter();
3757
3758 if (ssn == NULL) {
3759 SCReturnInt(-1);
3760 }
3761
3762 if (PKT_IS_TOCLIENT(p)) {
3763 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3764 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3765 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3766 } else {
3767 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3768 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3769 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3770 }
3771
3772 if (p->tcph->th_flags & TH_RST) {
3773 if (!StreamTcpValidateRst(ssn, p))
3774 return -1;
3775
3776 StreamTcpCloseSsnWithReset(p, ssn);
3777
3778 if (PKT_IS_TOSERVER(p)) {
3779 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
3780 StreamTcpUpdateLastAck(ssn, &ssn->server,
3781 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
3782
3783 StreamTcpUpdateLastAck(ssn, &ssn->client,
3784 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
3785
3786 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3787 StreamTcpHandleTimestamp(ssn, p);
3788 }
3789
3790 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3791 &ssn->client, p, pq);
3792 } else {
3793 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
3794 StreamTcpUpdateLastAck(ssn, &ssn->client,
3795 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
3796
3797 StreamTcpUpdateLastAck(ssn, &ssn->server,
3798 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
3799
3800 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3801 StreamTcpHandleTimestamp(ssn, p);
3802 }
3803
3804 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3805 &ssn->server, p, pq);
3806 }
3807
3808 } else if (p->tcph->th_flags & TH_FIN) {
3809 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3810 if (!StreamTcpValidateTimestamp(ssn, p))
3811 SCReturnInt(-1);
3812 }
3813
3814 if (PKT_IS_TOSERVER(p)) {
3815 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3816 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3817 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3818
3819 int retransmission = 0;
3820 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3821 SCLogDebug("ssn %p: packet is retransmission", ssn);
3822 retransmission = 1;
3823 }
3824
3825 if (!retransmission) {
3826 if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
3827 SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3828 {
3829 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3830 " != %" PRIu32 " from stream", ssn,
3831 TCP_GET_SEQ(p), ssn->client.next_seq);
3832 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW);
3833 SCReturnInt(-1);
3834 }
3835 }
3836
3837 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3838 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3839 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK);
3840 SCReturnInt(-1);
3841 }
3842
3843 /* don't update to LAST_ACK here as we want a toclient FIN for that */
3844
3845 if (!retransmission)
3846 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3847
3848 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3849
3850 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3851 StreamTcpHandleTimestamp(ssn, p);
3852 }
3853
3854 /* Update the next_seq, in case if we have missed the client
3855 packet and server has already received and acked it */
3856 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3857 ssn->server.next_seq = TCP_GET_ACK(p);
3858
3859 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3860 &ssn->client, p, pq);
3861 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3862 "%" PRIu32 "", ssn, ssn->client.next_seq,
3863 ssn->server.last_ack);
3864 } else {
3865 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3866 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3867 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3868
3869 int retransmission = 0;
3870 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3871 SCLogDebug("ssn %p: packet is retransmission", ssn);
3872 retransmission = 1;
3873 }
3874
3875 if (!retransmission) {
3876 if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
3877 SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3878 {
3879 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3880 " != %" PRIu32 " from stream", ssn,
3881 TCP_GET_SEQ(p), ssn->server.next_seq);
3882 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW);
3883 SCReturnInt(-1);
3884 }
3885 }
3886
3887 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
3888 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3889 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK);
3890 SCReturnInt(-1);
3891 }
3892
3893 if (!retransmission) {
3894 StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
3895 SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
3896
3897 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
3898 }
3899
3900 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
3901
3902 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3903 StreamTcpHandleTimestamp(ssn, p);
3904 }
3905
3906 /* Update the next_seq, in case if we have missed the client
3907 packet and server has already received and acked it */
3908 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
3909 ssn->client.next_seq = TCP_GET_ACK(p);
3910
3911 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3912 &ssn->server, p, pq);
3913 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3914 "%" PRIu32 "", ssn, ssn->server.next_seq,
3915 ssn->client.last_ack);
3916 }
3917
3918 } else if (p->tcph->th_flags & TH_SYN) {
3919 SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
3920 StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
3921 SCReturnInt(-1);
3922
3923 } else if (p->tcph->th_flags & TH_ACK) {
3924 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3925 if (!StreamTcpValidateTimestamp(ssn, p))
3926 SCReturnInt(-1);
3927 }
3928
3929 if (PKT_IS_TOSERVER(p)) {
3930 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
3931 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3932 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3933
3934 int retransmission = 0;
3935 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
3936 SCLogDebug("ssn %p: packet is retransmission", ssn);
3937 retransmission = 1;
3938 }
3939
3940 if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) {
3941 SCLogDebug("ssn %p: -> retransmission", ssn);
3942 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK);
3943 SCReturnInt(-1);
3944
3945 } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
3946 {
3947 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
3948 " != %" PRIu32 " from stream", ssn,
3949 TCP_GET_SEQ(p), ssn->client.next_seq);
3950 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW);
3951 SCReturnInt(-1);
3952 }
3953
3954 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
3955 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
3956 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK);
3957 SCReturnInt(-1);
3958 }
3959
3960 if (!retransmission) {
3961 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
3962 }
3963
3964 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
3965
3966 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
3967 StreamTcpHandleTimestamp(ssn, p);
3968 }
3969
3970 /* Update the next_seq, in case if we have missed the client
3971 packet and server has already received and acked it */
3972 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
3973 ssn->server.next_seq = TCP_GET_ACK(p);
3974
3975 if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq))
3976 StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len));
3977
3978 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
3979 &ssn->client, p, pq);
3980 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
3981 "%" PRIu32 "", ssn, ssn->client.next_seq,
3982 ssn->server.last_ack);
3983 } else {
3984 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
3985 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
3986 TCP_GET_SEQ(p), TCP_GET_ACK(p));
3987 int retransmission = 0;
3988 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
3989 SCLogDebug("ssn %p: packet is retransmission", ssn);
3990 retransmission = 1;
3991 }
3992
3993 if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) {
3994 SCLogDebug("ssn %p: -> retransmission", ssn);
3995 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK);
3996 SCReturnInt(-1);
3997
3998 } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
3999 {
4000 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4001 " != %" PRIu32 " from stream", ssn,
4002 TCP_GET_SEQ(p), ssn->server.next_seq);
4003 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW);
4004 SCReturnInt(-1);
4005 }
4006
4007 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4008 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4009 StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK);
4010 SCReturnInt(-1);
4011 }
4012
4013 if (!retransmission) {
4014 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
4015 }
4016
4017 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
4018
4019 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4020 StreamTcpHandleTimestamp(ssn, p);
4021 }
4022
4023 /* Update the next_seq, in case if we have missed the client
4024 packet and server has already received and acked it */
4025 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
4026 ssn->client.next_seq = TCP_GET_ACK(p);
4027
4028 if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq))
4029 StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len));
4030
4031 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4032 &ssn->server, p, pq);
4033 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4034 "%" PRIu32 "", ssn, ssn->server.next_seq,
4035 ssn->client.last_ack);
4036 }
4037
4038 } else {
4039 SCLogDebug("ssn %p: default case", ssn);
4040 }
4041 SCReturnInt(0);
4042 }
4043
4044 /**
4045 * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
4046 * the connection goes to TCP_CLOSED state and stream memory is
4047 * returned back to pool. The state is possible only for server host.
4048 *
4049 * \param tv Thread Variable containig input/output queue, cpu affinity
4050 * \param p Packet which has to be handled in this TCP state.
4051 * \param stt Strean Thread module registered to handle the stream handling
4052 */
4053
StreamTcpPacketStateLastAck(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)4054 static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p,
4055 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq)
4056 {
4057 if (ssn == NULL)
4058 return -1;
4059
4060 if (p->tcph->th_flags & TH_RST) {
4061 if (!StreamTcpValidateRst(ssn, p))
4062 return -1;
4063
4064 StreamTcpCloseSsnWithReset(p, ssn);
4065
4066 if (PKT_IS_TOSERVER(p)) {
4067 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4068 StreamTcpUpdateLastAck(ssn, &ssn->server,
4069 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
4070
4071 StreamTcpUpdateLastAck(ssn, &ssn->client,
4072 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
4073
4074 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4075 StreamTcpHandleTimestamp(ssn, p);
4076 }
4077
4078 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4079 &ssn->client, p, pq);
4080 } else {
4081 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4082 StreamTcpUpdateLastAck(ssn, &ssn->client,
4083 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
4084
4085 StreamTcpUpdateLastAck(ssn, &ssn->server,
4086 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
4087
4088 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4089 StreamTcpHandleTimestamp(ssn, p);
4090 }
4091
4092 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4093 &ssn->server, p, pq);
4094 }
4095
4096 } else if (p->tcph->th_flags & TH_FIN) {
4097 /** \todo */
4098 SCLogDebug("ssn (%p): FIN pkt on LastAck", ssn);
4099
4100 } else if (p->tcph->th_flags & TH_SYN) {
4101 SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
4102 StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
4103 return -1;
4104
4105 } else if (p->tcph->th_flags & TH_ACK) {
4106 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4107 if (!StreamTcpValidateTimestamp(ssn, p))
4108 return -1;
4109 }
4110
4111 if (PKT_IS_TOSERVER(p)) {
4112 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4113 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4114 TCP_GET_SEQ(p), TCP_GET_ACK(p));
4115
4116 int retransmission = 0;
4117 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4118 SCLogDebug("ssn %p: packet is retransmission", ssn);
4119 retransmission = 1;
4120 }
4121
4122 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4123 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4124 StreamTcpSetEvent(p, STREAM_LASTACK_INVALID_ACK);
4125 SCReturnInt(-1);
4126 }
4127
4128 if (!retransmission) {
4129 if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq)) {
4130 SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn);
4131 } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq + 1) {
4132 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4133 " != %" PRIu32 " from stream", ssn,
4134 TCP_GET_SEQ(p), ssn->client.next_seq);
4135 StreamTcpSetEvent(p, STREAM_LASTACK_ACK_WRONG_SEQ);
4136 return -1;
4137 } else {
4138 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4139 SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4140
4141 }
4142 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
4143 }
4144
4145 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4146
4147 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4148 StreamTcpHandleTimestamp(ssn, p);
4149 }
4150
4151 /* Update the next_seq, in case if we have missed the client
4152 packet and server has already received and acked it */
4153 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
4154 ssn->server.next_seq = TCP_GET_ACK(p);
4155
4156 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4157 &ssn->client, p, pq);
4158 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4159 "%" PRIu32 "", ssn, ssn->client.next_seq,
4160 ssn->server.last_ack);
4161 }
4162 } else {
4163 SCLogDebug("ssn %p: default case", ssn);
4164 }
4165
4166 return 0;
4167 }
4168
4169 /**
4170 * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
4171 * the connection goes to TCP_CLOSED state and stream memory is
4172 * returned back to pool.
4173 *
4174 * \param tv Thread Variable containig input/output queue, cpu affinity
4175 * \param p Packet which has to be handled in this TCP state.
4176 * \param stt Strean Thread module registered to handle the stream handling
4177 */
4178
StreamTcpPacketStateTimeWait(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)4179 static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p,
4180 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq)
4181 {
4182 if (ssn == NULL)
4183 return -1;
4184
4185 if (p->tcph->th_flags & TH_RST) {
4186 if (!StreamTcpValidateRst(ssn, p))
4187 return -1;
4188
4189 StreamTcpCloseSsnWithReset(p, ssn);
4190
4191 if (PKT_IS_TOSERVER(p)) {
4192 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
4193 StreamTcpUpdateLastAck(ssn, &ssn->server,
4194 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
4195
4196 StreamTcpUpdateLastAck(ssn, &ssn->client,
4197 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
4198
4199 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4200 StreamTcpHandleTimestamp(ssn, p);
4201 }
4202
4203 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4204 &ssn->client, p, pq);
4205 } else {
4206 if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
4207 StreamTcpUpdateLastAck(ssn, &ssn->client,
4208 StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
4209
4210 StreamTcpUpdateLastAck(ssn, &ssn->server,
4211 StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
4212
4213 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4214 StreamTcpHandleTimestamp(ssn, p);
4215 }
4216
4217 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4218 &ssn->server, p, pq);
4219 }
4220
4221 } else if (p->tcph->th_flags & TH_FIN) {
4222 /** \todo */
4223
4224 } else if (p->tcph->th_flags & TH_SYN) {
4225 SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
4226 StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
4227 return -1;
4228
4229 } else if (p->tcph->th_flags & TH_ACK) {
4230 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4231 if (!StreamTcpValidateTimestamp(ssn, p))
4232 return -1;
4233 }
4234
4235 if (PKT_IS_TOSERVER(p)) {
4236 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
4237 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4238 TCP_GET_SEQ(p), TCP_GET_ACK(p));
4239 int retransmission = 0;
4240 if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
4241 SCLogDebug("ssn %p: packet is retransmission", ssn);
4242 retransmission = 1;
4243
4244 } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq+1) {
4245 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4246 " != %" PRIu32 " from stream", ssn,
4247 TCP_GET_SEQ(p), ssn->client.next_seq);
4248 StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ);
4249 return -1;
4250 }
4251
4252 if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
4253 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4254 StreamTcpSetEvent(p, STREAM_TIMEWAIT_INVALID_ACK);
4255 SCReturnInt(-1);
4256 }
4257
4258 if (!retransmission) {
4259 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4260 SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4261
4262 ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
4263 }
4264
4265 StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
4266
4267 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4268 StreamTcpHandleTimestamp(ssn, p);
4269 }
4270
4271 /* Update the next_seq, in case if we have missed the client
4272 packet and server has already received and acked it */
4273 if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
4274 ssn->server.next_seq = TCP_GET_ACK(p);
4275
4276 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4277 &ssn->client, p, pq);
4278 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4279 "%" PRIu32 "", ssn, ssn->client.next_seq,
4280 ssn->server.last_ack);
4281 } else {
4282 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
4283 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
4284 TCP_GET_SEQ(p), TCP_GET_ACK(p));
4285 int retransmission = 0;
4286 if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
4287 SCLogDebug("ssn %p: packet is retransmission", ssn);
4288 retransmission = 1;
4289 } else if (TCP_GET_SEQ(p) != ssn->server.next_seq && TCP_GET_SEQ(p) != ssn->server.next_seq+1) {
4290 if (p->payload_len > 0 && TCP_GET_SEQ(p) == ssn->server.last_ack) {
4291 SCLogDebug("ssn %p: -> retransmission", ssn);
4292 SCReturnInt(0);
4293 } else {
4294 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
4295 " != %" PRIu32 " from stream", ssn,
4296 TCP_GET_SEQ(p), ssn->server.next_seq);
4297 StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ);
4298 return -1;
4299 }
4300 }
4301
4302 if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
4303 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
4304 StreamTcpSetEvent(p, STREAM_TIMEWAIT_INVALID_ACK);
4305 SCReturnInt(-1);
4306 }
4307
4308 if (!retransmission) {
4309 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
4310 SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
4311
4312 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
4313 }
4314
4315 StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
4316
4317 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
4318 StreamTcpHandleTimestamp(ssn, p);
4319 }
4320
4321 /* Update the next_seq, in case if we have missed the client
4322 packet and server has already received and acked it */
4323 if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
4324 ssn->client.next_seq = TCP_GET_ACK(p);
4325
4326 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4327 &ssn->server, p, pq);
4328 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
4329 "%" PRIu32 "", ssn, ssn->server.next_seq,
4330 ssn->client.last_ack);
4331 }
4332
4333 } else {
4334 SCLogDebug("ssn %p: default case", ssn);
4335 }
4336
4337 return 0;
4338 }
4339
StreamTcpPacketStateClosed(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq)4340 static int StreamTcpPacketStateClosed(ThreadVars *tv, Packet *p,
4341 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq)
4342 {
4343 if (ssn == NULL)
4344 return -1;
4345
4346 if (p->tcph->th_flags & TH_RST) {
4347 SCLogDebug("RST on closed state");
4348 return 0;
4349 }
4350
4351 TcpStream *stream = NULL, *ostream = NULL;
4352 if (PKT_IS_TOSERVER(p)) {
4353 stream = &ssn->client;
4354 ostream = &ssn->server;
4355 } else {
4356 stream = &ssn->server;
4357 ostream = &ssn->client;
4358 }
4359
4360 SCLogDebug("stream %s ostream %s",
4361 stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false",
4362 ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false");
4363
4364 /* if we've seen a RST on our direction, but not on the other
4365 * see if we perhaps need to continue processing anyway. */
4366 if ((stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) == 0) {
4367 if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
4368 if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->pstate) < 0)
4369 return -1;
4370 /* if state is still "closed", it wasn't updated by our dispatch. */
4371 if (ssn->state == TCP_CLOSED)
4372 ssn->state = ssn->pstate;
4373 }
4374 }
4375 return 0;
4376 }
4377
StreamTcpPacketCheckPostRst(TcpSession * ssn,Packet * p)4378 static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p)
4379 {
4380 if (p->flags & PKT_PSEUDO_STREAM_END) {
4381 return;
4382 }
4383 /* more RSTs are not unusual */
4384 if ((p->tcph->th_flags & (TH_RST)) != 0) {
4385 return;
4386 }
4387
4388 TcpStream *ostream = NULL;
4389 if (PKT_IS_TOSERVER(p)) {
4390 ostream = &ssn->server;
4391 } else {
4392 ostream = &ssn->client;
4393 }
4394
4395 if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
4396 SCLogDebug("regular packet %"PRIu64" from same sender as "
4397 "the previous RST. Looks like it injected!", p->pcap_cnt);
4398 ostream->flags &= ~STREAMTCP_STREAM_FLAG_RST_RECV;
4399 ssn->flags &= ~STREAMTCP_FLAG_CLOSED_BY_RST;
4400 StreamTcpSetEvent(p, STREAM_SUSPECTED_RST_INJECT);
4401 return;
4402 }
4403 return;
4404 }
4405
4406 /**
4407 * \retval 1 packet is a keep alive pkt
4408 * \retval 0 packet is not a keep alive pkt
4409 */
StreamTcpPacketIsKeepAlive(TcpSession * ssn,Packet * p)4410 static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
4411 {
4412 TcpStream *stream = NULL, *ostream = NULL;
4413 uint32_t seq;
4414 uint32_t ack;
4415
4416 if (p->flags & PKT_PSEUDO_STREAM_END)
4417 return 0;
4418
4419 /*
4420 rfc 1122:
4421 An implementation SHOULD send a keep-alive segment with no
4422 data; however, it MAY be configurable to send a keep-alive
4423 segment containing one garbage octet, for compatibility with
4424 erroneous TCP implementations.
4425 */
4426 if (p->payload_len > 1)
4427 return 0;
4428
4429 if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) {
4430 return 0;
4431 }
4432
4433 if (PKT_IS_TOSERVER(p)) {
4434 stream = &ssn->client;
4435 ostream = &ssn->server;
4436 } else {
4437 stream = &ssn->server;
4438 ostream = &ssn->client;
4439 }
4440
4441 seq = TCP_GET_SEQ(p);
4442 ack = TCP_GET_ACK(p);
4443
4444 if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
4445 SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
4446 stream->flags |= STREAMTCP_STREAM_FLAG_KEEPALIVE;
4447 return 1;
4448 }
4449 SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
4450 return 0;
4451 }
4452
4453 /**
4454 * \retval 1 packet is a keep alive ACK pkt
4455 * \retval 0 packet is not a keep alive ACK pkt
4456 */
StreamTcpPacketIsKeepAliveACK(TcpSession * ssn,Packet * p)4457 static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
4458 {
4459 TcpStream *stream = NULL, *ostream = NULL;
4460 uint32_t seq;
4461 uint32_t ack;
4462 uint32_t pkt_win;
4463
4464 if (p->flags & PKT_PSEUDO_STREAM_END)
4465 return 0;
4466 /* should get a normal ACK to a Keep Alive */
4467 if (p->payload_len > 0)
4468 return 0;
4469
4470 if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4471 return 0;
4472
4473 if (TCP_GET_WINDOW(p) == 0)
4474 return 0;
4475
4476 if (PKT_IS_TOSERVER(p)) {
4477 stream = &ssn->client;
4478 ostream = &ssn->server;
4479 } else {
4480 stream = &ssn->server;
4481 ostream = &ssn->client;
4482 }
4483
4484 seq = TCP_GET_SEQ(p);
4485 ack = TCP_GET_ACK(p);
4486
4487 pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4488 if (pkt_win != ostream->window)
4489 return 0;
4490
4491 if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
4492 SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
4493 ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
4494 return 1;
4495 }
4496 SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
4497 ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
4498 return 0;
4499 }
4500
StreamTcpClearKeepAliveFlag(TcpSession * ssn,Packet * p)4501 static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
4502 {
4503 TcpStream *stream = NULL;
4504
4505 if (p->flags & PKT_PSEUDO_STREAM_END)
4506 return;
4507
4508 if (PKT_IS_TOSERVER(p)) {
4509 stream = &ssn->client;
4510 } else {
4511 stream = &ssn->server;
4512 }
4513
4514 if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
4515 stream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
4516 SCLogDebug("FLAG_KEEPALIVE cleared");
4517 }
4518 }
4519
4520 /**
4521 * \retval 1 packet is a window update pkt
4522 * \retval 0 packet is not a window update pkt
4523 */
StreamTcpPacketIsWindowUpdate(TcpSession * ssn,Packet * p)4524 static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
4525 {
4526 TcpStream *stream = NULL, *ostream = NULL;
4527 uint32_t seq;
4528 uint32_t ack;
4529 uint32_t pkt_win;
4530
4531 if (p->flags & PKT_PSEUDO_STREAM_END)
4532 return 0;
4533
4534 if (ssn->state < TCP_ESTABLISHED)
4535 return 0;
4536
4537 if (p->payload_len > 0)
4538 return 0;
4539
4540 if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4541 return 0;
4542
4543 if (TCP_GET_WINDOW(p) == 0)
4544 return 0;
4545
4546 if (PKT_IS_TOSERVER(p)) {
4547 stream = &ssn->client;
4548 ostream = &ssn->server;
4549 } else {
4550 stream = &ssn->server;
4551 ostream = &ssn->client;
4552 }
4553
4554 seq = TCP_GET_SEQ(p);
4555 ack = TCP_GET_ACK(p);
4556
4557 pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4558 if (pkt_win == ostream->window)
4559 return 0;
4560
4561 if (ack == ostream->last_ack && seq == stream->next_seq) {
4562 SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
4563 return 1;
4564 }
4565 SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
4566 return 0;
4567 }
4568
4569 /**
4570 * Try to detect whether a packet is a valid FIN 4whs final ack.
4571 *
4572 */
StreamTcpPacketIsFinShutdownAck(TcpSession * ssn,Packet * p)4573 static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
4574 {
4575 TcpStream *stream = NULL, *ostream = NULL;
4576 uint32_t seq;
4577 uint32_t ack;
4578
4579 if (p->flags & PKT_PSEUDO_STREAM_END)
4580 return 0;
4581 if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
4582 return 0;
4583 if (p->tcph->th_flags != TH_ACK)
4584 return 0;
4585 if (p->payload_len != 0)
4586 return 0;
4587
4588 if (PKT_IS_TOSERVER(p)) {
4589 stream = &ssn->client;
4590 ostream = &ssn->server;
4591 } else {
4592 stream = &ssn->server;
4593 ostream = &ssn->client;
4594 }
4595
4596 seq = TCP_GET_SEQ(p);
4597 ack = TCP_GET_ACK(p);
4598
4599 SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
4600 p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
4601
4602 if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
4603 return 1;
4604 }
4605 return 0;
4606 }
4607
4608 /**
4609 * Try to detect packets doing bad window updates
4610 *
4611 * See bug 1238.
4612 *
4613 * Find packets that are unexpected, and shrink the window to the point
4614 * where the packets we do expect are rejected for being out of window.
4615 *
4616 * The logic we use here is:
4617 * - packet seq > next_seq
4618 * - packet ack > next_seq (packet acks unseen data)
4619 * - packet shrinks window more than it's own data size
4620 * - packet shrinks window more than the diff between it's ack and the
4621 * last_ack value
4622 *
4623 * Packets coming in after packet loss can look quite a bit like this.
4624 */
StreamTcpPacketIsBadWindowUpdate(TcpSession * ssn,Packet * p)4625 static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
4626 {
4627 TcpStream *stream = NULL, *ostream = NULL;
4628 uint32_t seq;
4629 uint32_t ack;
4630 uint32_t pkt_win;
4631
4632 if (p->flags & PKT_PSEUDO_STREAM_END)
4633 return 0;
4634
4635 if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
4636 return 0;
4637
4638 if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
4639 return 0;
4640
4641 if (PKT_IS_TOSERVER(p)) {
4642 stream = &ssn->client;
4643 ostream = &ssn->server;
4644 } else {
4645 stream = &ssn->server;
4646 ostream = &ssn->client;
4647 }
4648
4649 seq = TCP_GET_SEQ(p);
4650 ack = TCP_GET_ACK(p);
4651
4652 pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
4653
4654 if (pkt_win < ostream->window) {
4655 uint32_t diff = ostream->window - pkt_win;
4656 if (diff > p->payload_len &&
4657 SEQ_GT(ack, ostream->next_seq) &&
4658 SEQ_GT(seq, stream->next_seq))
4659 {
4660 SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
4661 p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
4662 SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
4663 p->pcap_cnt, pkt_win, ostream->window);
4664 SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
4665 p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
4666 ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
4667
4668 /* get the expected window shrinking from looking at ack vs last_ack.
4669 * Observed a lot of just a little overrunning that value. So added some
4670 * margin that is still ok. To make sure this isn't a loophole to still
4671 * close the window, this is limited to windows above 1024. Both values
4672 * are rather arbitrary. */
4673 uint32_t adiff = ack - ostream->last_ack;
4674 if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
4675 ((pkt_win <= 1024) && (diff > adiff)))
4676 {
4677 SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
4678 "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
4679 SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
4680 StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE);
4681 return 1;
4682 }
4683 }
4684
4685 }
4686 SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
4687 return 0;
4688 }
4689
4690 /** \internal
4691 * \brief call packet handling function for 'state'
4692 * \param state current TCP state
4693 */
StreamTcpStateDispatch(ThreadVars * tv,Packet * p,StreamTcpThread * stt,TcpSession * ssn,PacketQueueNoLock * pq,const uint8_t state)4694 static inline int StreamTcpStateDispatch(ThreadVars *tv, Packet *p,
4695 StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq,
4696 const uint8_t state)
4697 {
4698 SCLogDebug("ssn: %p", ssn);
4699 switch (state) {
4700 case TCP_SYN_SENT:
4701 if (StreamTcpPacketStateSynSent(tv, p, stt, ssn, pq)) {
4702 return -1;
4703 }
4704 break;
4705 case TCP_SYN_RECV:
4706 if (StreamTcpPacketStateSynRecv(tv, p, stt, ssn, pq)) {
4707 return -1;
4708 }
4709 break;
4710 case TCP_ESTABLISHED:
4711 if (StreamTcpPacketStateEstablished(tv, p, stt, ssn, pq)) {
4712 return -1;
4713 }
4714 break;
4715 case TCP_FIN_WAIT1:
4716 SCLogDebug("packet received on TCP_FIN_WAIT1 state");
4717 if (StreamTcpPacketStateFinWait1(tv, p, stt, ssn, pq)) {
4718 return -1;
4719 }
4720 break;
4721 case TCP_FIN_WAIT2:
4722 SCLogDebug("packet received on TCP_FIN_WAIT2 state");
4723 if (StreamTcpPacketStateFinWait2(tv, p, stt, ssn, pq)) {
4724 return -1;
4725 }
4726 break;
4727 case TCP_CLOSING:
4728 SCLogDebug("packet received on TCP_CLOSING state");
4729 if (StreamTcpPacketStateClosing(tv, p, stt, ssn, pq)) {
4730 return -1;
4731 }
4732 break;
4733 case TCP_CLOSE_WAIT:
4734 SCLogDebug("packet received on TCP_CLOSE_WAIT state");
4735 if (StreamTcpPacketStateCloseWait(tv, p, stt, ssn, pq)) {
4736 return -1;
4737 }
4738 break;
4739 case TCP_LAST_ACK:
4740 SCLogDebug("packet received on TCP_LAST_ACK state");
4741 if (StreamTcpPacketStateLastAck(tv, p, stt, ssn, pq)) {
4742 return -1;
4743 }
4744 break;
4745 case TCP_TIME_WAIT:
4746 SCLogDebug("packet received on TCP_TIME_WAIT state");
4747 if (StreamTcpPacketStateTimeWait(tv, p, stt, ssn, pq)) {
4748 return -1;
4749 }
4750 break;
4751 case TCP_CLOSED:
4752 /* TCP session memory is not returned to pool until timeout. */
4753 SCLogDebug("packet received on closed state");
4754
4755 if (StreamTcpPacketStateClosed(tv, p, stt, ssn, pq)) {
4756 return -1;
4757 }
4758
4759 break;
4760 default:
4761 SCLogDebug("packet received on default state");
4762 break;
4763 }
4764 return 0;
4765 }
4766
HandleThreadId(ThreadVars * tv,Packet * p,StreamTcpThread * stt)4767 static inline void HandleThreadId(ThreadVars *tv, Packet *p, StreamTcpThread *stt)
4768 {
4769 const int idx = (!(PKT_IS_TOSERVER(p)));
4770
4771 /* assign the thread id to the flow */
4772 if (unlikely(p->flow->thread_id[idx] == 0)) {
4773 p->flow->thread_id[idx] = (FlowThreadId)tv->id;
4774 } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id[idx])) {
4775 SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id[idx], tv->id);
4776 if (p->pkt_src == PKT_SRC_WIRE) {
4777 StatsIncr(tv, stt->counter_tcp_wrong_thread);
4778 if ((p->flow->flags & FLOW_WRONG_THREAD) == 0) {
4779 p->flow->flags |= FLOW_WRONG_THREAD;
4780 StreamTcpSetEvent(p, STREAM_WRONG_THREAD);
4781 }
4782 }
4783 }
4784 }
4785
4786 /* flow is and stays locked */
StreamTcpPacket(ThreadVars * tv,Packet * p,StreamTcpThread * stt,PacketQueueNoLock * pq)4787 int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt,
4788 PacketQueueNoLock *pq)
4789 {
4790 SCEnter();
4791
4792 DEBUG_ASSERT_FLOW_LOCKED(p->flow);
4793
4794 SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
4795
4796 HandleThreadId(tv, p, stt);
4797
4798 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
4799
4800 /* track TCP flags */
4801 if (ssn != NULL) {
4802 ssn->tcp_packet_flags |= p->tcph->th_flags;
4803 if (PKT_IS_TOSERVER(p))
4804 ssn->client.tcp_flags |= p->tcph->th_flags;
4805 else if (PKT_IS_TOCLIENT(p))
4806 ssn->server.tcp_flags |= p->tcph->th_flags;
4807
4808 /* check if we need to unset the ASYNC flag */
4809 if (ssn->flags & STREAMTCP_FLAG_ASYNC &&
4810 ssn->client.tcp_flags != 0 &&
4811 ssn->server.tcp_flags != 0)
4812 {
4813 SCLogDebug("ssn %p: removing ASYNC flag as we have packets on both sides", ssn);
4814 ssn->flags &= ~STREAMTCP_FLAG_ASYNC;
4815 }
4816 }
4817
4818 /* update counters */
4819 if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
4820 StatsIncr(tv, stt->counter_tcp_synack);
4821 } else if (p->tcph->th_flags & (TH_SYN)) {
4822 StatsIncr(tv, stt->counter_tcp_syn);
4823 }
4824 if (p->tcph->th_flags & (TH_RST)) {
4825 StatsIncr(tv, stt->counter_tcp_rst);
4826 }
4827
4828 /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */
4829 if (!(p->tcph->th_flags & TH_ACK) && TCP_GET_ACK(p) != 0) {
4830 StreamTcpSetEvent(p, STREAM_PKT_BROKEN_ACK);
4831 if (!(p->tcph->th_flags & TH_SYN))
4832 goto error;
4833 }
4834
4835 /* If we are on IPS mode, and got a drop action triggered from
4836 * the IP only module, or from a reassembled msg and/or from an
4837 * applayer detection, then drop the rest of the packets of the
4838 * same stream and avoid inspecting it any further */
4839 if (StreamTcpCheckFlowDrops(p) == 1) {
4840 SCLogDebug("This flow/stream triggered a drop rule");
4841 FlowSetNoPacketInspectionFlag(p->flow);
4842 DecodeSetNoPacketInspectionFlag(p);
4843 StreamTcpDisableAppLayer(p->flow);
4844 PACKET_DROP(p);
4845 /* return the segments to the pool */
4846 StreamTcpSessionPktFree(p);
4847 SCReturnInt(0);
4848 }
4849
4850 if (ssn == NULL || ssn->state == TCP_NONE) {
4851 if (StreamTcpPacketStateNone(tv, p, stt, ssn, &stt->pseudo_queue) == -1) {
4852 goto error;
4853 }
4854
4855 if (ssn != NULL)
4856 SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto);
4857 } else {
4858 /* special case for PKT_PSEUDO_STREAM_END packets:
4859 * bypass the state handling and various packet checks,
4860 * we care about reassembly here. */
4861 if (p->flags & PKT_PSEUDO_STREAM_END) {
4862 if (PKT_IS_TOCLIENT(p)) {
4863 ssn->client.last_ack = TCP_GET_ACK(p);
4864 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4865 &ssn->server, p, pq);
4866 } else {
4867 ssn->server.last_ack = TCP_GET_ACK(p);
4868 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4869 &ssn->client, p, pq);
4870 }
4871 /* straight to 'skip' as we already handled reassembly */
4872 goto skip;
4873 }
4874
4875 if (p->flow->flags & FLOW_WRONG_THREAD) {
4876 /* Stream and/or session in known bad condition. Block events
4877 * from being set. */
4878 p->flags |= PKT_STREAM_NO_EVENTS;
4879 }
4880
4881 if (StreamTcpPacketIsKeepAlive(ssn, p) == 1) {
4882 goto skip;
4883 }
4884 if (StreamTcpPacketIsKeepAliveACK(ssn, p) == 1) {
4885 StreamTcpClearKeepAliveFlag(ssn, p);
4886 goto skip;
4887 }
4888 StreamTcpClearKeepAliveFlag(ssn, p);
4889
4890 /* if packet is not a valid window update, check if it is perhaps
4891 * a bad window update that we should ignore (and alert on) */
4892 if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0)
4893 if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0)
4894 if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
4895 goto skip;
4896
4897 /* handle the per 'state' logic */
4898 if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->state) < 0)
4899 goto error;
4900
4901 skip:
4902 StreamTcpPacketCheckPostRst(ssn, p);
4903
4904 if (ssn->state >= TCP_ESTABLISHED) {
4905 p->flags |= PKT_STREAM_EST;
4906 }
4907 }
4908
4909 /* deal with a pseudo packet that is created upon receiving a RST
4910 * segment. To be sure we process both sides of the connection, we
4911 * inject a fake packet into the system, forcing reassembly of the
4912 * opposing direction.
4913 * There should be only one, but to be sure we do a while loop. */
4914 if (ssn != NULL) {
4915 while (stt->pseudo_queue.len > 0) {
4916 SCLogDebug("processing pseudo packet / stream end");
4917 Packet *np = PacketDequeueNoLock(&stt->pseudo_queue);
4918 if (np != NULL) {
4919 /* process the opposing direction of the original packet */
4920 if (PKT_IS_TOSERVER(np)) {
4921 SCLogDebug("pseudo packet is to server");
4922 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4923 &ssn->client, np, NULL);
4924 } else {
4925 SCLogDebug("pseudo packet is to client");
4926 StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
4927 &ssn->server, np, NULL);
4928 }
4929
4930 /* enqueue this packet so we inspect it in detect etc */
4931 PacketEnqueueNoLock(pq, np);
4932 }
4933 SCLogDebug("processing pseudo packet / stream end done");
4934 }
4935
4936 /* recalc the csum on the packet if it was modified */
4937 if (p->flags & PKT_STREAM_MODIFIED) {
4938 ReCalculateChecksum(p);
4939 }
4940 /* check for conditions that may make us not want to log this packet */
4941
4942 /* streams that hit depth */
4943 if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ||
4944 (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED))
4945 {
4946 /* we can call bypass callback, if enabled */
4947 if (StreamTcpBypassEnabled()) {
4948 PacketBypassCallback(p);
4949 }
4950 }
4951
4952 if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ||
4953 (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED))
4954 {
4955 p->flags |= PKT_STREAM_NOPCAPLOG;
4956 }
4957
4958 /* encrypted packets */
4959 if ((PKT_IS_TOSERVER(p) && (ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) ||
4960 (PKT_IS_TOCLIENT(p) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)))
4961 {
4962 p->flags |= PKT_STREAM_NOPCAPLOG;
4963 }
4964
4965 if (ssn->flags & STREAMTCP_FLAG_BYPASS) {
4966 /* we can call bypass callback, if enabled */
4967 if (StreamTcpBypassEnabled()) {
4968 PacketBypassCallback(p);
4969 }
4970
4971 /* if stream is dead and we have no detect engine at all, bypass. */
4972 } else if (g_detect_disabled &&
4973 (ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
4974 (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
4975 StreamTcpBypassEnabled())
4976 {
4977 SCLogDebug("bypass as stream is dead and we have no rules");
4978 PacketBypassCallback(p);
4979 }
4980 }
4981
4982 SCReturnInt(0);
4983
4984 error:
4985 /* make sure we don't leave packets in our pseudo queue */
4986 while (stt->pseudo_queue.len > 0) {
4987 Packet *np = PacketDequeueNoLock(&stt->pseudo_queue);
4988 if (np != NULL) {
4989 PacketEnqueueNoLock(pq, np);
4990 }
4991 }
4992
4993 /* recalc the csum on the packet if it was modified */
4994 if (p->flags & PKT_STREAM_MODIFIED) {
4995 ReCalculateChecksum(p);
4996 }
4997
4998 if (StreamTcpInlineDropInvalid()) {
4999 /* disable payload inspection as we're dropping this packet
5000 * anyway. Doesn't disable all detection, so we can still
5001 * match on the stream event that was set. */
5002 DecodeSetNoPayloadInspectionFlag(p);
5003 PACKET_DROP(p);
5004 }
5005 SCReturnInt(-1);
5006 }
5007
5008 /**
5009 * \brief Function to validate the checksum of the received packet. If the
5010 * checksum is invalid, packet will be dropped, as the end system will
5011 * also drop the packet.
5012 *
5013 * \param p Packet of which checksum has to be validated
5014 * \retval 1 if the checksum is valid, otherwise 0
5015 */
StreamTcpValidateChecksum(Packet * p)5016 static inline int StreamTcpValidateChecksum(Packet *p)
5017 {
5018 int ret = 1;
5019
5020 if (p->flags & PKT_IGNORE_CHECKSUM)
5021 return ret;
5022
5023 if (p->level4_comp_csum == -1) {
5024 if (PKT_IS_IPV4(p)) {
5025 p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs,
5026 (uint16_t *)p->tcph,
5027 (p->payload_len +
5028 TCP_GET_HLEN(p)),
5029 p->tcph->th_sum);
5030 } else if (PKT_IS_IPV6(p)) {
5031 p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs,
5032 (uint16_t *)p->tcph,
5033 (p->payload_len +
5034 TCP_GET_HLEN(p)),
5035 p->tcph->th_sum);
5036 }
5037 }
5038
5039 if (p->level4_comp_csum != 0) {
5040 ret = 0;
5041 if (p->livedev) {
5042 (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1);
5043 } else if (p->pcap_cnt) {
5044 PcapIncreaseInvalidChecksum();
5045 }
5046 }
5047
5048 return ret;
5049 }
5050
5051 /** \internal
5052 * \brief check if a packet is a valid stream started
5053 * \retval bool true/false */
TcpSessionPacketIsStreamStarter(const Packet * p)5054 static int TcpSessionPacketIsStreamStarter(const Packet *p)
5055 {
5056 if (p->tcph->th_flags == TH_SYN) {
5057 SCLogDebug("packet %"PRIu64" is a stream starter: %02x", p->pcap_cnt, p->tcph->th_flags);
5058 return 1;
5059 }
5060
5061 if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) {
5062 if (p->tcph->th_flags == (TH_SYN|TH_ACK)) {
5063 SCLogDebug("packet %"PRIu64" is a midstream stream starter: %02x", p->pcap_cnt, p->tcph->th_flags);
5064 return 1;
5065 }
5066 }
5067 return 0;
5068 }
5069
5070 /** \internal
5071 * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused
5072 * \retval bool true yes reuse, false no keep tracking old ssn */
TcpSessionReuseDoneEnoughSyn(const Packet * p,const Flow * f,const TcpSession * ssn)5073 static int TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn)
5074 {
5075 if (FlowGetPacketDirection(f, p) == TOSERVER) {
5076 if (ssn == NULL) {
5077 SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
5078 return 0;
5079 }
5080 if (SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p))) {
5081 SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5082 return 0;
5083 }
5084 if (ssn->state >= TCP_LAST_ACK) {
5085 SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5086 return 1;
5087 }
5088 if (ssn->state == TCP_NONE) {
5089 SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5090 return 1;
5091 }
5092 if (ssn->state < TCP_LAST_ACK) {
5093 SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5094 return 0;
5095 }
5096
5097 } else {
5098 if (ssn == NULL) {
5099 SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5100 return 1;
5101 }
5102 if (ssn->state >= TCP_LAST_ACK) {
5103 SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5104 return 1;
5105 }
5106 if (ssn->state == TCP_NONE) {
5107 SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5108 return 1;
5109 }
5110 if (ssn->state < TCP_LAST_ACK) {
5111 SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5112 return 0;
5113 }
5114 }
5115
5116 SCLogDebug("default: how did we get here?");
5117 return 0;
5118 }
5119
5120 /** \internal
5121 * \brief check if ssn is done enough for reuse by syn/ack
5122 * \note should only be called if midstream is enabled
5123 */
TcpSessionReuseDoneEnoughSynAck(const Packet * p,const Flow * f,const TcpSession * ssn)5124 static int TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn)
5125 {
5126 if (FlowGetPacketDirection(f, p) == TOCLIENT) {
5127 if (ssn == NULL) {
5128 SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
5129 return 0;
5130 }
5131 if (SEQ_EQ(ssn->server.isn, TCP_GET_SEQ(p))) {
5132 SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
5133 return 0;
5134 }
5135 if (ssn->state >= TCP_LAST_ACK) {
5136 SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5137 return 1;
5138 }
5139 if (ssn->state == TCP_NONE) {
5140 SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5141 return 1;
5142 }
5143 if (ssn->state < TCP_LAST_ACK) {
5144 SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5145 return 0;
5146 }
5147
5148 } else {
5149 if (ssn == NULL) {
5150 SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
5151 return 1;
5152 }
5153 if (ssn->state >= TCP_LAST_ACK) {
5154 SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5155 return 1;
5156 }
5157 if (ssn->state == TCP_NONE) {
5158 SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
5159 return 1;
5160 }
5161 if (ssn->state < TCP_LAST_ACK) {
5162 SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
5163 return 0;
5164 }
5165 }
5166
5167 SCLogDebug("default: how did we get here?");
5168 return 0;
5169 }
5170
5171 /** \brief Check if SSN is done enough for reuse
5172 *
5173 * Reuse means a new TCP session reuses the tuple (flow in suri)
5174 *
5175 * \retval bool true if ssn can be reused, false if not */
TcpSessionReuseDoneEnough(const Packet * p,const Flow * f,const TcpSession * ssn)5176 static int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn)
5177 {
5178 if (p->tcph->th_flags == TH_SYN) {
5179 return TcpSessionReuseDoneEnoughSyn(p, f, ssn);
5180 }
5181
5182 if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) {
5183 if (p->tcph->th_flags == (TH_SYN|TH_ACK)) {
5184 return TcpSessionReuseDoneEnoughSynAck(p, f, ssn);
5185 }
5186 }
5187
5188 return 0;
5189 }
5190
TcpSessionPacketSsnReuse(const Packet * p,const Flow * f,const void * tcp_ssn)5191 int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
5192 {
5193 if (p->proto == IPPROTO_TCP && p->tcph != NULL) {
5194 if (TcpSessionPacketIsStreamStarter(p) == 1) {
5195 if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) {
5196 return 1;
5197 }
5198 }
5199 }
5200 return 0;
5201 }
5202
StreamTcp(ThreadVars * tv,Packet * p,void * data,PacketQueueNoLock * pq)5203 TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq)
5204 {
5205 StreamTcpThread *stt = (StreamTcpThread *)data;
5206
5207 SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
5208
5209 if (!(PKT_IS_TCP(p))) {
5210 return TM_ECODE_OK;
5211 }
5212
5213 if (p->flow == NULL) {
5214 StatsIncr(tv, stt->counter_tcp_no_flow);
5215 return TM_ECODE_OK;
5216 }
5217
5218 /* only TCP packets with a flow from here */
5219
5220 if (!(p->flags & PKT_PSEUDO_STREAM_END)) {
5221 if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) {
5222 if (StreamTcpValidateChecksum(p) == 0) {
5223 StatsIncr(tv, stt->counter_tcp_invalid_checksum);
5224 return TM_ECODE_OK;
5225 }
5226 } else {
5227 p->flags |= PKT_IGNORE_CHECKSUM;
5228 }
5229 } else {
5230 p->flags |= PKT_IGNORE_CHECKSUM; //TODO check that this is set at creation
5231 }
5232 AppLayerProfilingReset(stt->ra_ctx->app_tctx);
5233
5234 (void)StreamTcpPacket(tv, p, stt, pq);
5235
5236 return TM_ECODE_OK;
5237 }
5238
StreamTcpThreadInit(ThreadVars * tv,void * initdata,void ** data)5239 TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
5240 {
5241 SCEnter();
5242 StreamTcpThread *stt = SCMalloc(sizeof(StreamTcpThread));
5243 if (unlikely(stt == NULL))
5244 SCReturnInt(TM_ECODE_FAILED);
5245 memset(stt, 0, sizeof(StreamTcpThread));
5246 stt->ssn_pool_id = -1;
5247
5248 *data = (void *)stt;
5249
5250 stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv);
5251 stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv);
5252 stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv);
5253 stt->counter_tcp_pseudo_failed = StatsRegisterCounter("tcp.pseudo_failed", tv);
5254 stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv);
5255 stt->counter_tcp_no_flow = StatsRegisterCounter("tcp.no_flow", tv);
5256 stt->counter_tcp_syn = StatsRegisterCounter("tcp.syn", tv);
5257 stt->counter_tcp_synack = StatsRegisterCounter("tcp.synack", tv);
5258 stt->counter_tcp_rst = StatsRegisterCounter("tcp.rst", tv);
5259 stt->counter_tcp_midstream_pickups = StatsRegisterCounter("tcp.midstream_pickups", tv);
5260 stt->counter_tcp_wrong_thread = StatsRegisterCounter("tcp.pkt_on_wrong_thread", tv);
5261
5262 /* init reassembly ctx */
5263 stt->ra_ctx = StreamTcpReassembleInitThreadCtx(tv);
5264 if (stt->ra_ctx == NULL)
5265 SCReturnInt(TM_ECODE_FAILED);
5266
5267 stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv);
5268 stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv);
5269 stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv);
5270 stt->ra_ctx->counter_tcp_reass_overlap = StatsRegisterCounter("tcp.overlap", tv);
5271 stt->ra_ctx->counter_tcp_reass_overlap_diff_data = StatsRegisterCounter("tcp.overlap_diff_data", tv);
5272
5273 stt->ra_ctx->counter_tcp_reass_data_normal_fail = StatsRegisterCounter("tcp.insert_data_normal_fail", tv);
5274 stt->ra_ctx->counter_tcp_reass_data_overlap_fail = StatsRegisterCounter("tcp.insert_data_overlap_fail", tv);
5275 stt->ra_ctx->counter_tcp_reass_list_fail = StatsRegisterCounter("tcp.insert_list_fail", tv);
5276
5277
5278 SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p",
5279 stt, stt->ra_ctx);
5280
5281 SCMutexLock(&ssn_pool_mutex);
5282 if (ssn_pool == NULL) {
5283 ssn_pool = PoolThreadInit(1, /* thread */
5284 0, /* unlimited */
5285 stream_config.prealloc_sessions,
5286 sizeof(TcpSession),
5287 StreamTcpSessionPoolAlloc,
5288 StreamTcpSessionPoolInit, NULL,
5289 StreamTcpSessionPoolCleanup, NULL);
5290 stt->ssn_pool_id = 0;
5291 SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
5292 } else {
5293 /* grow ssn_pool until we have a element for our thread id */
5294 stt->ssn_pool_id = PoolThreadExpand(ssn_pool);
5295 SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
5296 }
5297 SCMutexUnlock(&ssn_pool_mutex);
5298 if (stt->ssn_pool_id < 0 || ssn_pool == NULL) {
5299 SCLogError(SC_ERR_MEM_ALLOC, "failed to setup/expand stream session pool. Expand stream.memcap?");
5300 SCReturnInt(TM_ECODE_FAILED);
5301 }
5302
5303 SCReturnInt(TM_ECODE_OK);
5304 }
5305
StreamTcpThreadDeinit(ThreadVars * tv,void * data)5306 TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data)
5307 {
5308 SCEnter();
5309 StreamTcpThread *stt = (StreamTcpThread *)data;
5310 if (stt == NULL) {
5311 return TM_ECODE_OK;
5312 }
5313
5314 /* XXX */
5315
5316 /* free reassembly ctx */
5317 StreamTcpReassembleFreeThreadCtx(stt->ra_ctx);
5318
5319 /* clear memory */
5320 memset(stt, 0, sizeof(StreamTcpThread));
5321
5322 SCFree(stt);
5323 SCReturnInt(TM_ECODE_OK);
5324 }
5325
5326 /**
5327 * \brief Function to check the validity of the RST packets based on the
5328 * target OS of the given packet.
5329 *
5330 * \param ssn TCP session to which the given packet belongs
5331 * \param p Packet which has to be checked for its validity
5332 *
5333 * \retval 0 unacceptable RST
5334 * \retval 1 acceptable RST
5335 *
5336 * WebSense sends RST packets that are:
5337 * - RST flag, win 0, ack 0, seq = nextseq
5338 *
5339 */
5340
StreamTcpValidateRst(TcpSession * ssn,Packet * p)5341 static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
5342 {
5343 uint8_t os_policy;
5344
5345 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
5346 if (!StreamTcpValidateTimestamp(ssn, p)) {
5347 SCReturnInt(0);
5348 }
5349 }
5350
5351 /* Set up the os_policy to be used in validating the RST packets based on
5352 target system */
5353 if (PKT_IS_TOSERVER(p)) {
5354 if (ssn->server.os_policy == 0)
5355 StreamTcpSetOSPolicy(&ssn->server, p);
5356
5357 os_policy = ssn->server.os_policy;
5358
5359 if (p->tcph->th_flags & TH_ACK &&
5360 TCP_GET_ACK(p) && StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
5361 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5362 StreamTcpSetEvent(p, STREAM_RST_INVALID_ACK);
5363 SCReturnInt(0);
5364 }
5365
5366 } else {
5367 if (ssn->client.os_policy == 0)
5368 StreamTcpSetOSPolicy(&ssn->client, p);
5369
5370 os_policy = ssn->client.os_policy;
5371
5372 if (p->tcph->th_flags & TH_ACK &&
5373 TCP_GET_ACK(p) && StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
5374 SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
5375 StreamTcpSetEvent(p, STREAM_RST_INVALID_ACK);
5376 SCReturnInt(0);
5377 }
5378 }
5379
5380 /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
5381 * validate these (requires key that is set/transfered out of band), we can't know
5382 * if the RST will be accepted or rejected by the end host. We accept it, but keep
5383 * tracking if the sender of it ignores it, which would be a sign of injection. */
5384 if (p->tcpvars.md5_option_present || p->tcpvars.ao_option_present) {
5385 TcpStream *receiver_stream;
5386 if (PKT_IS_TOSERVER(p)) {
5387 receiver_stream = &ssn->server;
5388 } else {
5389 receiver_stream = &ssn->client;
5390 }
5391 SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
5392 receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
5393 }
5394
5395 if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
5396 if (PKT_IS_TOSERVER(p)) {
5397 if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {
5398 SCLogDebug("ssn %p: ASYNC accept RST", ssn);
5399 return 1;
5400 }
5401 } else {
5402 if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
5403 SCLogDebug("ssn %p: ASYNC accept RST", ssn);
5404 return 1;
5405 }
5406 }
5407 SCLogDebug("ssn %p: ASYNC reject RST", ssn);
5408 return 0;
5409 }
5410
5411 switch (os_policy) {
5412 case OS_POLICY_HPUX11:
5413 if(PKT_IS_TOSERVER(p)){
5414 if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {
5415 SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "",
5416 TCP_GET_SEQ(p));
5417 return 1;
5418 } else {
5419 SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " "
5420 "and server SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
5421 ssn->client.next_seq);
5422 return 0;
5423 }
5424 } else { /* implied to client */
5425 if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
5426 SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "",
5427 TCP_GET_SEQ(p));
5428 return 1;
5429 } else {
5430 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
5431 "and client SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
5432 ssn->server.next_seq);
5433 return 0;
5434 }
5435 }
5436 break;
5437 case OS_POLICY_OLD_LINUX:
5438 case OS_POLICY_LINUX:
5439 case OS_POLICY_SOLARIS:
5440 if(PKT_IS_TOSERVER(p)){
5441 if(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len),
5442 ssn->client.last_ack))
5443 { /*window base is needed !!*/
5444 if(SEQ_LT(TCP_GET_SEQ(p),
5445 (ssn->client.next_seq + ssn->client.window)))
5446 {
5447 SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "",
5448 TCP_GET_SEQ(p));
5449 return 1;
5450 }
5451 } else {
5452 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
5453 " server SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
5454 ssn->client.next_seq);
5455 return 0;
5456 }
5457 } else { /* implied to client */
5458 if(SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len),
5459 ssn->server.last_ack))
5460 { /*window base is needed !!*/
5461 if(SEQ_LT(TCP_GET_SEQ(p),
5462 (ssn->server.next_seq + ssn->server.window)))
5463 {
5464 SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "",
5465 TCP_GET_SEQ(p));
5466 return 1;
5467 }
5468 } else {
5469 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
5470 " client SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
5471 ssn->server.next_seq);
5472 return 0;
5473 }
5474 }
5475 break;
5476 default:
5477 case OS_POLICY_BSD:
5478 case OS_POLICY_FIRST:
5479 case OS_POLICY_HPUX10:
5480 case OS_POLICY_IRIX:
5481 case OS_POLICY_MACOS:
5482 case OS_POLICY_LAST:
5483 case OS_POLICY_WINDOWS:
5484 case OS_POLICY_WINDOWS2K3:
5485 case OS_POLICY_VISTA:
5486 if(PKT_IS_TOSERVER(p)) {
5487 if(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {
5488 SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "",
5489 TCP_GET_SEQ(p));
5490 return 1;
5491 } else {
5492 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
5493 "and server SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
5494 ssn->client.next_seq);
5495 return 0;
5496 }
5497 } else { /* implied to client */
5498 if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
5499 SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u",
5500 TCP_GET_SEQ(p), ssn->server.next_seq);
5501 return 1;
5502 } else {
5503 SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
5504 " client SEQ: %" PRIu32 "",
5505 TCP_GET_SEQ(p), ssn->server.next_seq);
5506 return 0;
5507 }
5508 }
5509 break;
5510 }
5511 return 0;
5512 }
5513
5514 /**
5515 * \brief Function to check the validity of the received timestamp based on
5516 * the target OS of the given stream.
5517 *
5518 * It's passive except for:
5519 * 1. it sets the os policy on the stream if necessary
5520 * 2. it sets an event in the packet if necessary
5521 *
5522 * \param ssn TCP session to which the given packet belongs
5523 * \param p Packet which has to be checked for its validity
5524 *
5525 * \retval 1 if the timestamp is valid
5526 * \retval 0 if the timestamp is invalid
5527 */
StreamTcpValidateTimestamp(TcpSession * ssn,Packet * p)5528 static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p)
5529 {
5530 SCEnter();
5531
5532 TcpStream *sender_stream;
5533 TcpStream *receiver_stream;
5534 uint8_t ret = 1;
5535 uint8_t check_ts = 1;
5536
5537 if (PKT_IS_TOSERVER(p)) {
5538 sender_stream = &ssn->client;
5539 receiver_stream = &ssn->server;
5540 } else {
5541 sender_stream = &ssn->server;
5542 receiver_stream = &ssn->client;
5543 }
5544
5545 /* Set up the os_policy to be used in validating the timestamps based on
5546 the target system */
5547 if (receiver_stream->os_policy == 0) {
5548 StreamTcpSetOSPolicy(receiver_stream, p);
5549 }
5550
5551 if (TCP_HAS_TS(p)) {
5552 uint32_t ts = TCP_GET_TSVAL(p);
5553 uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
5554 uint32_t last_ts = sender_stream->last_ts;
5555
5556 if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
5557 /* The 3whs used the timestamp with 0 value. */
5558 switch (receiver_stream->os_policy) {
5559 case OS_POLICY_LINUX:
5560 case OS_POLICY_WINDOWS2K3:
5561 /* Linux and windows 2003 does not allow the use of 0 as
5562 * timestamp in the 3whs. */
5563 check_ts = 0;
5564 break;
5565
5566 case OS_POLICY_OLD_LINUX:
5567 case OS_POLICY_WINDOWS:
5568 case OS_POLICY_VISTA:
5569 if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) {
5570 last_ts = ts;
5571 check_ts = 0; /*next packet will be checked for validity
5572 and stream TS has been updated with this
5573 one.*/
5574 }
5575 break;
5576 }
5577 }
5578
5579 if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
5580 /* HPUX11 igoners the timestamp of out of order packets */
5581 if (!SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p)))
5582 check_ts = 0;
5583 }
5584
5585 if (ts == 0) {
5586 switch (receiver_stream->os_policy) {
5587 case OS_POLICY_OLD_LINUX:
5588 case OS_POLICY_WINDOWS:
5589 case OS_POLICY_WINDOWS2K3:
5590 case OS_POLICY_VISTA:
5591 case OS_POLICY_SOLARIS:
5592 /* Old Linux and windows allowed packet with 0 timestamp. */
5593 break;
5594 default:
5595 /* other OS simply drop the pakcet with 0 timestamp, when
5596 * 3whs has valid timestamp*/
5597 goto invalid;
5598 }
5599 }
5600
5601 if (check_ts) {
5602 int32_t result = 0;
5603
5604 SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts);
5605
5606 if (receiver_stream->os_policy == OS_POLICY_LINUX) {
5607 /* Linux accepts TS which are off by one.*/
5608 result = (int32_t) ((ts - last_ts) + 1);
5609 } else {
5610 result = (int32_t) (ts - last_ts);
5611 }
5612
5613 SCLogDebug("result %"PRIi32", p->ts.tv_sec %"PRIuMAX"", result, (uintmax_t)p->ts.tv_sec);
5614
5615 if (last_pkt_ts == 0 &&
5616 (ssn->flags & STREAMTCP_FLAG_MIDSTREAM))
5617 {
5618 last_pkt_ts = p->ts.tv_sec;
5619 }
5620
5621 if (result < 0) {
5622 SCLogDebug("timestamp is not valid last_ts "
5623 "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
5624 "%" PRId32 "", last_ts, ts, result);
5625 /* candidate for rejection */
5626 ret = 0;
5627 } else if ((sender_stream->last_ts != 0) &&
5628 (((uint32_t) p->ts.tv_sec) >
5629 last_pkt_ts + PAWS_24DAYS))
5630 {
5631 SCLogDebug("packet is not valid last_pkt_ts "
5632 "%" PRIu32 " p->ts.tv_sec %" PRIu32 "",
5633 last_pkt_ts, (uint32_t) p->ts.tv_sec);
5634 /* candidate for rejection */
5635 ret = 0;
5636 }
5637
5638 if (ret == 0) {
5639 /* if the timestamp of packet is not valid then, check if the
5640 * current stream timestamp is not so old. if so then we need to
5641 * accept the packet and update the stream->last_ts (RFC 1323)*/
5642 if ((SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) &&
5643 (((uint32_t) p->ts.tv_sec > (last_pkt_ts + PAWS_24DAYS))))
5644 {
5645 SCLogDebug("timestamp considered valid anyway");
5646 } else {
5647 goto invalid;
5648 }
5649 }
5650 }
5651 }
5652
5653 SCReturnInt(1);
5654
5655 invalid:
5656 StreamTcpSetEvent(p, STREAM_PKT_INVALID_TIMESTAMP);
5657 SCReturnInt(0);
5658 }
5659
5660 /**
5661 * \brief Function to check the validity of the received timestamp based on
5662 * the target OS of the given stream and update the session.
5663 *
5664 * \param ssn TCP session to which the given packet belongs
5665 * \param p Packet which has to be checked for its validity
5666 *
5667 * \retval 1 if the timestamp is valid
5668 * \retval 0 if the timestamp is invalid
5669 */
StreamTcpHandleTimestamp(TcpSession * ssn,Packet * p)5670 static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p)
5671 {
5672 SCEnter();
5673
5674 TcpStream *sender_stream;
5675 TcpStream *receiver_stream;
5676 uint8_t ret = 1;
5677 uint8_t check_ts = 1;
5678
5679 if (PKT_IS_TOSERVER(p)) {
5680 sender_stream = &ssn->client;
5681 receiver_stream = &ssn->server;
5682 } else {
5683 sender_stream = &ssn->server;
5684 receiver_stream = &ssn->client;
5685 }
5686
5687 /* Set up the os_policy to be used in validating the timestamps based on
5688 the target system */
5689 if (receiver_stream->os_policy == 0) {
5690 StreamTcpSetOSPolicy(receiver_stream, p);
5691 }
5692
5693 if (TCP_HAS_TS(p)) {
5694 uint32_t ts = TCP_GET_TSVAL(p);
5695
5696 if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
5697 /* The 3whs used the timestamp with 0 value. */
5698 switch (receiver_stream->os_policy) {
5699 case OS_POLICY_LINUX:
5700 case OS_POLICY_WINDOWS2K3:
5701 /* Linux and windows 2003 does not allow the use of 0 as
5702 * timestamp in the 3whs. */
5703 ssn->flags &= ~STREAMTCP_FLAG_TIMESTAMP;
5704 check_ts = 0;
5705 break;
5706
5707 case OS_POLICY_OLD_LINUX:
5708 case OS_POLICY_WINDOWS:
5709 case OS_POLICY_VISTA:
5710 sender_stream->flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
5711 if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) {
5712 sender_stream->last_ts = ts;
5713 check_ts = 0; /*next packet will be checked for validity
5714 and stream TS has been updated with this
5715 one.*/
5716 }
5717 break;
5718 default:
5719 break;
5720 }
5721 }
5722
5723 if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
5724 /*HPUX11 igoners the timestamp of out of order packets*/
5725 if (!SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p)))
5726 check_ts = 0;
5727 }
5728
5729 if (ts == 0) {
5730 switch (receiver_stream->os_policy) {
5731 case OS_POLICY_OLD_LINUX:
5732 case OS_POLICY_WINDOWS:
5733 case OS_POLICY_WINDOWS2K3:
5734 case OS_POLICY_VISTA:
5735 case OS_POLICY_SOLARIS:
5736 /* Old Linux and windows allowed packet with 0 timestamp. */
5737 break;
5738 default:
5739 /* other OS simply drop the pakcet with 0 timestamp, when
5740 * 3whs has valid timestamp*/
5741 goto invalid;
5742 }
5743 }
5744
5745 if (check_ts) {
5746 int32_t result = 0;
5747
5748 SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts);
5749
5750 if (receiver_stream->os_policy == OS_POLICY_LINUX) {
5751 /* Linux accepts TS which are off by one.*/
5752 result = (int32_t) ((ts - sender_stream->last_ts) + 1);
5753 } else {
5754 result = (int32_t) (ts - sender_stream->last_ts);
5755 }
5756
5757 SCLogDebug("result %"PRIi32", p->ts.tv_sec %"PRIuMAX"", result, (uintmax_t)p->ts.tv_sec);
5758
5759 if (sender_stream->last_pkt_ts == 0 &&
5760 (ssn->flags & STREAMTCP_FLAG_MIDSTREAM))
5761 {
5762 sender_stream->last_pkt_ts = p->ts.tv_sec;
5763 }
5764
5765 if (result < 0) {
5766 SCLogDebug("timestamp is not valid sender_stream->last_ts "
5767 "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
5768 "%" PRId32 "", sender_stream->last_ts, ts, result);
5769 /* candidate for rejection */
5770 ret = 0;
5771 } else if ((sender_stream->last_ts != 0) &&
5772 (((uint32_t) p->ts.tv_sec) >
5773 sender_stream->last_pkt_ts + PAWS_24DAYS))
5774 {
5775 SCLogDebug("packet is not valid sender_stream->last_pkt_ts "
5776 "%" PRIu32 " p->ts.tv_sec %" PRIu32 "",
5777 sender_stream->last_pkt_ts, (uint32_t) p->ts.tv_sec);
5778 /* candidate for rejection */
5779 ret = 0;
5780 }
5781
5782 if (ret == 1) {
5783 /* Update the timestamp and last seen packet time for this
5784 * stream */
5785 if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p)))
5786 sender_stream->last_ts = ts;
5787
5788 sender_stream->last_pkt_ts = p->ts.tv_sec;
5789
5790 } else if (ret == 0) {
5791 /* if the timestamp of packet is not valid then, check if the
5792 * current stream timestamp is not so old. if so then we need to
5793 * accept the packet and update the stream->last_ts (RFC 1323)*/
5794 if ((SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) &&
5795 (((uint32_t) p->ts.tv_sec > (sender_stream->last_pkt_ts + PAWS_24DAYS))))
5796 {
5797 sender_stream->last_ts = ts;
5798 sender_stream->last_pkt_ts = p->ts.tv_sec;
5799
5800 SCLogDebug("timestamp considered valid anyway");
5801 } else {
5802 goto invalid;
5803 }
5804 }
5805 }
5806 } else {
5807 /* Solaris stops using timestamps if a packet is received
5808 without a timestamp and timestamps were used on that stream. */
5809 if (receiver_stream->os_policy == OS_POLICY_SOLARIS)
5810 ssn->flags &= ~STREAMTCP_FLAG_TIMESTAMP;
5811 }
5812
5813 SCReturnInt(1);
5814
5815 invalid:
5816 StreamTcpSetEvent(p, STREAM_PKT_INVALID_TIMESTAMP);
5817 SCReturnInt(0);
5818 }
5819
5820 /**
5821 * \brief Function to test the received ACK values against the stream window
5822 * and previous ack value. ACK values should be higher than previous
5823 * ACK value and less than the next_win value.
5824 *
5825 * \param ssn TcpSession for state access
5826 * \param stream TcpStream of which last_ack needs to be tested
5827 * \param p Packet which is used to test the last_ack
5828 *
5829 * \retval 0 ACK is valid, last_ack is updated if ACK was higher
5830 * \retval -1 ACK is invalid
5831 */
StreamTcpValidateAck(TcpSession * ssn,TcpStream * stream,Packet * p)5832 static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p)
5833 {
5834 SCEnter();
5835
5836 uint32_t ack = TCP_GET_ACK(p);
5837
5838 /* fast track */
5839 if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win))
5840 {
5841 SCLogDebug("ACK in bounds");
5842 SCReturnInt(0);
5843 }
5844 /* fast track */
5845 else if (SEQ_EQ(ack, stream->last_ack)) {
5846 SCLogDebug("pkt ACK %"PRIu32" == stream last ACK %"PRIu32, TCP_GET_ACK(p), stream->last_ack);
5847 SCReturnInt(0);
5848 }
5849
5850 /* exception handling */
5851 if (SEQ_LT(ack, stream->last_ack)) {
5852 SCLogDebug("pkt ACK %"PRIu32" < stream last ACK %"PRIu32, TCP_GET_ACK(p), stream->last_ack);
5853
5854 /* This is an attempt to get a 'left edge' value that we can check against.
5855 * It doesn't work when the window is 0, need to think of a better way. */
5856
5857 if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) {
5858 SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window "
5859 "%"PRIu32" = %"PRIu32, ack, stream->last_ack,
5860 stream->window, stream->last_ack - stream->window);
5861 goto invalid;
5862 }
5863
5864 SCReturnInt(0);
5865 }
5866
5867 /* no further checks possible for ASYNC */
5868 if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
5869 SCReturnInt(0);
5870 }
5871
5872 if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) {
5873 SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win);
5874 goto invalid;
5875 /* a toclient RST as a reponse to SYN, next_win is 0, ack will be isn+1, just like
5876 * the syn ack */
5877 } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) &&
5878 p->tcph->th_flags & TH_RST &&
5879 SEQ_EQ(ack, stream->isn + 1)) {
5880 SCReturnInt(0);
5881 }
5882
5883 SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32
5884 " next_win %"PRIu32, ack, stream->last_ack, stream->next_win);
5885 invalid:
5886 StreamTcpSetEvent(p, STREAM_PKT_INVALID_ACK);
5887 SCReturnInt(-1);
5888 }
5889
5890 /** \brief update reassembly progress
5891
5892 * \param ssn TCP Session
5893 * \param direction direction to set the flag in: 0 toserver, 1 toclient
5894 */
StreamTcpUpdateAppLayerProgress(TcpSession * ssn,char direction,const uint32_t progress)5895 void StreamTcpUpdateAppLayerProgress(TcpSession *ssn, char direction,
5896 const uint32_t progress)
5897 {
5898 if (direction) {
5899 ssn->server.app_progress_rel += progress;
5900 } else {
5901 ssn->client.app_progress_rel += progress;
5902 }
5903 }
5904
5905 /** \brief disable reassembly
5906
5907 * Disable app layer and set raw inspect to no longer accept new data.
5908 * Stream engine will then fully disable raw after last inspection.
5909 *
5910 * \param ssn TCP Session to set the flag in
5911 * \param direction direction to set the flag in: 0 toserver, 1 toclient
5912 */
StreamTcpSetSessionNoReassemblyFlag(TcpSession * ssn,char direction)5913 void StreamTcpSetSessionNoReassemblyFlag(TcpSession *ssn, char direction)
5914 {
5915 ssn->flags |= STREAMTCP_FLAG_APP_LAYER_DISABLED;
5916 if (direction) {
5917 ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED;
5918 } else {
5919 ssn->client.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED;
5920 }
5921 }
5922
5923 /** \brief Set the No reassembly flag for the given direction in given TCP
5924 * session.
5925 *
5926 * \param ssn TCP Session to set the flag in
5927 * \param direction direction to set the flag in: 0 toserver, 1 toclient
5928 */
StreamTcpSetDisableRawReassemblyFlag(TcpSession * ssn,char direction)5929 void StreamTcpSetDisableRawReassemblyFlag(TcpSession *ssn, char direction)
5930 {
5931 direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) :
5932 (ssn->client.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED);
5933 }
5934
5935 /** \brief enable bypass
5936 *
5937 * \param ssn TCP Session to set the flag in
5938 * \param direction direction to set the flag in: 0 toserver, 1 toclient
5939 */
StreamTcpSetSessionBypassFlag(TcpSession * ssn)5940 void StreamTcpSetSessionBypassFlag(TcpSession *ssn)
5941 {
5942 ssn->flags |= STREAMTCP_FLAG_BYPASS;
5943 }
5944
5945 #define PSEUDO_PKT_SET_IPV4HDR(nipv4h,ipv4h) do { \
5946 IPV4_SET_RAW_VER(nipv4h, IPV4_GET_RAW_VER(ipv4h)); \
5947 IPV4_SET_RAW_HLEN(nipv4h, IPV4_GET_RAW_HLEN(ipv4h)); \
5948 IPV4_SET_RAW_IPLEN(nipv4h, IPV4_GET_RAW_IPLEN(ipv4h)); \
5949 IPV4_SET_RAW_IPTOS(nipv4h, IPV4_GET_RAW_IPTOS(ipv4h)); \
5950 IPV4_SET_RAW_IPPROTO(nipv4h, IPV4_GET_RAW_IPPROTO(ipv4h)); \
5951 (nipv4h)->s_ip_src = IPV4_GET_RAW_IPDST(ipv4h); \
5952 (nipv4h)->s_ip_dst = IPV4_GET_RAW_IPSRC(ipv4h); \
5953 } while (0)
5954
5955 #define PSEUDO_PKT_SET_IPV6HDR(nipv6h,ipv6h) do { \
5956 (nipv6h)->s_ip6_src[0] = (ipv6h)->s_ip6_dst[0]; \
5957 (nipv6h)->s_ip6_src[1] = (ipv6h)->s_ip6_dst[1]; \
5958 (nipv6h)->s_ip6_src[2] = (ipv6h)->s_ip6_dst[2]; \
5959 (nipv6h)->s_ip6_src[3] = (ipv6h)->s_ip6_dst[3]; \
5960 (nipv6h)->s_ip6_dst[0] = (ipv6h)->s_ip6_src[0]; \
5961 (nipv6h)->s_ip6_dst[1] = (ipv6h)->s_ip6_src[1]; \
5962 (nipv6h)->s_ip6_dst[2] = (ipv6h)->s_ip6_src[2]; \
5963 (nipv6h)->s_ip6_dst[3] = (ipv6h)->s_ip6_src[3]; \
5964 IPV6_SET_RAW_NH(nipv6h, IPV6_GET_RAW_NH(ipv6h)); \
5965 } while (0)
5966
5967 #define PSEUDO_PKT_SET_TCPHDR(ntcph,tcph) do { \
5968 COPY_PORT((tcph)->th_dport, (ntcph)->th_sport); \
5969 COPY_PORT((tcph)->th_sport, (ntcph)->th_dport); \
5970 (ntcph)->th_seq = (tcph)->th_ack; \
5971 (ntcph)->th_ack = (tcph)->th_seq; \
5972 } while (0)
5973
5974 /**
5975 * \brief Function to fetch a packet from the packet allocation queue for
5976 * creation of the pseudo packet from the reassembled stream.
5977 *
5978 * @param parent Pointer to the parent of the pseudo packet
5979 * @param pkt pointer to the raw packet of the parent
5980 * @param len length of the packet
5981 * @return upon success returns the pointer to the new pseudo packet
5982 * otherwise NULL
5983 */
StreamTcpPseudoSetup(Packet * parent,uint8_t * pkt,uint32_t len)5984 Packet *StreamTcpPseudoSetup(Packet *parent, uint8_t *pkt, uint32_t len)
5985 {
5986 SCEnter();
5987
5988 if (len == 0) {
5989 SCReturnPtr(NULL, "Packet");
5990 }
5991
5992 Packet *p = PacketGetFromQueueOrAlloc();
5993 if (p == NULL) {
5994 SCReturnPtr(NULL, "Packet");
5995 }
5996
5997 /* set the root ptr to the lowest layer */
5998 if (parent->root != NULL)
5999 p->root = parent->root;
6000 else
6001 p->root = parent;
6002
6003 /* copy packet and set lenght, proto */
6004 p->proto = parent->proto;
6005 p->datalink = parent->datalink;
6006
6007 PacketCopyData(p, pkt, len);
6008 p->recursion_level = parent->recursion_level + 1;
6009 p->ts.tv_sec = parent->ts.tv_sec;
6010 p->ts.tv_usec = parent->ts.tv_usec;
6011
6012 FlowReference(&p->flow, parent->flow);
6013 /* set tunnel flags */
6014
6015 /* tell new packet it's part of a tunnel */
6016 SET_TUNNEL_PKT(p);
6017 /* tell parent packet it's part of a tunnel */
6018 SET_TUNNEL_PKT(parent);
6019
6020 /* increment tunnel packet refcnt in the root packet */
6021 TUNNEL_INCR_PKT_TPR(p);
6022
6023 return p;
6024 }
6025
6026 /** \brief Create a pseudo packet injected into the engine to signal the
6027 * opposing direction of this stream trigger detection/logging.
6028 *
6029 * \param parent real packet
6030 * \param pq packet queue to store the new pseudo packet in
6031 * \param dir 0 ts 1 tc
6032 */
StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars * tv,StreamTcpThread * stt,Packet * parent,TcpSession * ssn,PacketQueueNoLock * pq,int dir)6033 static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv,
6034 StreamTcpThread *stt, Packet *parent,
6035 TcpSession *ssn, PacketQueueNoLock *pq, int dir)
6036 {
6037 SCEnter();
6038 Flow *f = parent->flow;
6039
6040 if (parent->flags & PKT_PSEUDO_DETECTLOG_FLUSH) {
6041 SCReturn;
6042 }
6043
6044 Packet *np = PacketPoolGetPacket();
6045 if (np == NULL) {
6046 SCReturn;
6047 }
6048 PKT_SET_SRC(np, PKT_SRC_STREAM_TCP_DETECTLOG_FLUSH);
6049
6050 np->tenant_id = f->tenant_id;
6051 np->datalink = DLT_RAW;
6052 np->proto = IPPROTO_TCP;
6053 FlowReference(&np->flow, f);
6054 np->flags |= PKT_STREAM_EST;
6055 np->flags |= PKT_HAS_FLOW;
6056 np->flags |= PKT_IGNORE_CHECKSUM;
6057 np->flags |= PKT_PSEUDO_DETECTLOG_FLUSH;
6058 np->vlan_id[0] = f->vlan_id[0];
6059 np->vlan_id[1] = f->vlan_id[1];
6060 np->vlan_idx = f->vlan_idx;
6061 np->livedev = (struct LiveDevice_ *)f->livedev;
6062
6063 if (f->flags & FLOW_NOPACKET_INSPECTION) {
6064 DecodeSetNoPacketInspectionFlag(np);
6065 }
6066 if (f->flags & FLOW_NOPAYLOAD_INSPECTION) {
6067 DecodeSetNoPayloadInspectionFlag(np);
6068 }
6069
6070 if (dir == 0) {
6071 SCLogDebug("pseudo is to_server");
6072 np->flowflags |= FLOW_PKT_TOSERVER;
6073 } else {
6074 SCLogDebug("pseudo is to_client");
6075 np->flowflags |= FLOW_PKT_TOCLIENT;
6076 }
6077 np->flowflags |= FLOW_PKT_ESTABLISHED;
6078 np->payload = NULL;
6079 np->payload_len = 0;
6080
6081 if (FLOW_IS_IPV4(f)) {
6082 if (dir == 0) {
6083 FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &np->src);
6084 FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &np->dst);
6085 np->sp = f->sp;
6086 np->dp = f->dp;
6087 } else {
6088 FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &np->dst);
6089 FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &np->src);
6090 np->sp = f->dp;
6091 np->dp = f->sp;
6092 }
6093
6094 /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
6095 * Force an allocation if it is not the case.
6096 */
6097 if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) {
6098 if (PacketCallocExtPkt(np, 40) == -1) {
6099 goto error;
6100 }
6101 }
6102 /* set the ip header */
6103 np->ip4h = (IPV4Hdr *)GET_PKT_DATA(np);
6104 /* version 4 and length 20 bytes for the tcp header */
6105 np->ip4h->ip_verhl = 0x45;
6106 np->ip4h->ip_tos = 0;
6107 np->ip4h->ip_len = htons(40);
6108 np->ip4h->ip_id = 0;
6109 np->ip4h->ip_off = 0;
6110 np->ip4h->ip_ttl = 64;
6111 np->ip4h->ip_proto = IPPROTO_TCP;
6112 if (dir == 0) {
6113 np->ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
6114 np->ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
6115 } else {
6116 np->ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
6117 np->ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
6118 }
6119
6120 /* set the tcp header */
6121 np->tcph = (TCPHdr *)((uint8_t *)GET_PKT_DATA(np) + 20);
6122
6123 SET_PKT_LEN(np, 40); /* ipv4 hdr + tcp hdr */
6124
6125 } else if (FLOW_IS_IPV6(f)) {
6126 if (dir == 0) {
6127 FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &np->src);
6128 FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &np->dst);
6129 np->sp = f->sp;
6130 np->dp = f->dp;
6131 } else {
6132 FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &np->dst);
6133 FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &np->src);
6134 np->sp = f->dp;
6135 np->dp = f->sp;
6136 }
6137
6138 /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
6139 * Force an allocation if it is not the case.
6140 */
6141 if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) {
6142 if (PacketCallocExtPkt(np, 60) == -1) {
6143 goto error;
6144 }
6145 }
6146 /* set the ip header */
6147 np->ip6h = (IPV6Hdr *)GET_PKT_DATA(np);
6148 /* version 6 */
6149 np->ip6h->s_ip6_vfc = 0x60;
6150 np->ip6h->s_ip6_flow = 0;
6151 np->ip6h->s_ip6_nxt = IPPROTO_TCP;
6152 np->ip6h->s_ip6_plen = htons(20);
6153 np->ip6h->s_ip6_hlim = 64;
6154 if (dir == 0) {
6155 np->ip6h->s_ip6_src[0] = f->src.addr_data32[0];
6156 np->ip6h->s_ip6_src[1] = f->src.addr_data32[1];
6157 np->ip6h->s_ip6_src[2] = f->src.addr_data32[2];
6158 np->ip6h->s_ip6_src[3] = f->src.addr_data32[3];
6159 np->ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
6160 np->ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
6161 np->ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
6162 np->ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
6163 } else {
6164 np->ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
6165 np->ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
6166 np->ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
6167 np->ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
6168 np->ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
6169 np->ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
6170 np->ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
6171 np->ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
6172 }
6173
6174 /* set the tcp header */
6175 np->tcph = (TCPHdr *)((uint8_t *)GET_PKT_DATA(np) + 40);
6176
6177 SET_PKT_LEN(np, 60); /* ipv6 hdr + tcp hdr */
6178 }
6179
6180 np->tcph->th_offx2 = 0x50;
6181 np->tcph->th_flags |= TH_ACK;
6182 np->tcph->th_win = 10;
6183 np->tcph->th_urp = 0;
6184
6185 /* to server */
6186 if (dir == 0) {
6187 np->tcph->th_sport = htons(f->sp);
6188 np->tcph->th_dport = htons(f->dp);
6189
6190 np->tcph->th_seq = htonl(ssn->client.next_seq);
6191 np->tcph->th_ack = htonl(ssn->server.last_ack);
6192
6193 /* to client */
6194 } else {
6195 np->tcph->th_sport = htons(f->dp);
6196 np->tcph->th_dport = htons(f->sp);
6197
6198 np->tcph->th_seq = htonl(ssn->server.next_seq);
6199 np->tcph->th_ack = htonl(ssn->client.last_ack);
6200 }
6201
6202 /* use parent time stamp */
6203 memcpy(&np->ts, &parent->ts, sizeof(struct timeval));
6204
6205 SCLogDebug("np %p", np);
6206 PacketEnqueueNoLock(pq, np);
6207
6208 StatsIncr(tv, stt->counter_tcp_pseudo);
6209 SCReturn;
6210 error:
6211 FlowDeReference(&np->flow);
6212 SCReturn;
6213 }
6214
6215 /** \brief create packets in both directions to flush out logging
6216 * and detection before switching protocols.
6217 * In IDS mode, create first in packet dir, 2nd in opposing
6218 * In IPS mode, do the reverse.
6219 * Flag TCP engine that data needs to be inspected regardless
6220 * of how far we are wrt inspect limits.
6221 */
StreamTcpDetectLogFlush(ThreadVars * tv,StreamTcpThread * stt,Flow * f,Packet * p,PacketQueueNoLock * pq)6222 void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p,
6223 PacketQueueNoLock *pq)
6224 {
6225 TcpSession *ssn = f->protoctx;
6226 ssn->client.flags |= STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
6227 ssn->server.flags |= STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
6228 bool ts = PKT_IS_TOSERVER(p) ? true : false;
6229 ts ^= StreamTcpInlineMode();
6230 StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^0);
6231 StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^1);
6232 }
6233
6234 /**
6235 * \brief Run callback function on each TCP segment
6236 *
6237 * \note when stream engine is running in inline mode all segments are used,
6238 * in IDS/non-inline mode only ack'd segments are iterated.
6239 *
6240 * \note Must be called under flow lock.
6241 *
6242 * \return -1 in case of error, the number of segment in case of success
6243 *
6244 */
StreamTcpSegmentForEach(const Packet * p,uint8_t flag,StreamSegmentCallback CallbackFunc,void * data)6245 int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
6246 {
6247 TcpSession *ssn = NULL;
6248 TcpStream *stream = NULL;
6249 int ret = 0;
6250 int cnt = 0;
6251
6252 if (p->flow == NULL)
6253 return 0;
6254
6255 ssn = (TcpSession *)p->flow->protoctx;
6256
6257 if (ssn == NULL) {
6258 return 0;
6259 }
6260
6261 if (flag & FLOW_PKT_TOSERVER) {
6262 stream = &(ssn->server);
6263 } else {
6264 stream = &(ssn->client);
6265 }
6266
6267 /* for IDS, return ack'd segments. For IPS all. */
6268 TcpSegment *seg;
6269 RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
6270 if (!((stream_config.flags & STREAMTCP_INIT_FLAG_INLINE)
6271 || SEQ_LT(seg->seq, stream->last_ack)))
6272 break;
6273
6274 const uint8_t *seg_data;
6275 uint32_t seg_datalen;
6276 StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
6277
6278 ret = CallbackFunc(p, data, seg_data, seg_datalen);
6279 if (ret != 1) {
6280 SCLogDebug("Callback function has failed");
6281 return -1;
6282 }
6283
6284 cnt++;
6285 }
6286 return cnt;
6287 }
6288
StreamTcpBypassEnabled(void)6289 int StreamTcpBypassEnabled(void)
6290 {
6291 return (stream_config.flags & STREAMTCP_INIT_FLAG_BYPASS);
6292 }
6293
6294 /**
6295 * \brief See if stream engine is operating in inline mode
6296 *
6297 * \retval 0 no
6298 * \retval 1 yes
6299 */
StreamTcpInlineMode(void)6300 int StreamTcpInlineMode(void)
6301 {
6302 return (stream_config.flags & STREAMTCP_INIT_FLAG_INLINE) ? 1 : 0;
6303 }
6304
6305
TcpSessionSetReassemblyDepth(TcpSession * ssn,uint32_t size)6306 void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
6307 {
6308 if (size > ssn->reassembly_depth || size == 0) {
6309 ssn->reassembly_depth = size;
6310 }
6311
6312 return;
6313 }
6314
StreamTcpStateAsString(const enum TcpState state)6315 const char *StreamTcpStateAsString(const enum TcpState state)
6316 {
6317 const char *tcp_state = NULL;
6318 switch (state) {
6319 case TCP_NONE:
6320 tcp_state = "none";
6321 break;
6322 case TCP_LISTEN:
6323 tcp_state = "listen";
6324 break;
6325 case TCP_SYN_SENT:
6326 tcp_state = "syn_sent";
6327 break;
6328 case TCP_SYN_RECV:
6329 tcp_state = "syn_recv";
6330 break;
6331 case TCP_ESTABLISHED:
6332 tcp_state = "established";
6333 break;
6334 case TCP_FIN_WAIT1:
6335 tcp_state = "fin_wait1";
6336 break;
6337 case TCP_FIN_WAIT2:
6338 tcp_state = "fin_wait2";
6339 break;
6340 case TCP_TIME_WAIT:
6341 tcp_state = "time_wait";
6342 break;
6343 case TCP_LAST_ACK:
6344 tcp_state = "last_ack";
6345 break;
6346 case TCP_CLOSE_WAIT:
6347 tcp_state = "close_wait";
6348 break;
6349 case TCP_CLOSING:
6350 tcp_state = "closing";
6351 break;
6352 case TCP_CLOSED:
6353 tcp_state = "closed";
6354 break;
6355 }
6356 return tcp_state;
6357 }
6358
StreamTcpSsnStateAsString(const TcpSession * ssn)6359 const char *StreamTcpSsnStateAsString(const TcpSession *ssn)
6360 {
6361 if (ssn == NULL)
6362 return NULL;
6363 return StreamTcpStateAsString(ssn->state);
6364 }
6365
6366 #ifdef UNITTESTS
6367
6368 #define SET_ISN(stream, setseq) \
6369 (stream)->isn = (setseq); \
6370 (stream)->base_seq = (setseq) + 1
6371
6372 /**
6373 * \test Test the allocation of TCP session for a given packet from the
6374 * ssn_pool.
6375 *
6376 * \retval On success it returns 1 and on failure 0.
6377 */
6378
StreamTcpTest01(void)6379 static int StreamTcpTest01 (void)
6380 {
6381 StreamTcpThread stt;
6382 Packet *p = SCMalloc(SIZE_OF_PACKET);
6383 if (unlikely(p == NULL))
6384 return 0;
6385 Flow f;
6386 memset(p, 0, SIZE_OF_PACKET);
6387 memset (&f, 0, sizeof(Flow));
6388 FLOW_INITIALIZE(&f);
6389 p->flow = &f;
6390 int ret = 0;
6391
6392 StreamTcpUTInit(&stt.ra_ctx);
6393
6394 TcpSession *ssn = StreamTcpNewSession(p, 0);
6395 if (ssn == NULL) {
6396 printf("Session can not be allocated: ");
6397 goto end;
6398 }
6399 f.protoctx = ssn;
6400
6401 if (f.alparser != NULL) {
6402 printf("AppLayer field not set to NULL: ");
6403 goto end;
6404 }
6405 if (ssn->state != 0) {
6406 printf("TCP state field not set to 0: ");
6407 goto end;
6408 }
6409
6410 StreamTcpSessionClear(p->flow->protoctx);
6411
6412 ret = 1;
6413 end:
6414 SCFree(p);
6415 FLOW_DESTROY(&f);
6416 StreamTcpUTDeinit(stt.ra_ctx);
6417 return ret;
6418 }
6419
6420 /**
6421 * \test Test the deallocation of TCP session for a given packet and return
6422 * the memory back to ssn_pool and corresponding segments to segment
6423 * pool.
6424 *
6425 * \retval On success it returns 1 and on failure 0.
6426 */
6427
StreamTcpTest02(void)6428 static int StreamTcpTest02 (void)
6429 {
6430 Packet *p = SCMalloc(SIZE_OF_PACKET);
6431 FAIL_IF(unlikely(p == NULL));
6432 Flow f;
6433 ThreadVars tv;
6434 StreamTcpThread stt;
6435 uint8_t payload[4];
6436 TCPHdr tcph;
6437 PacketQueueNoLock pq;
6438 memset(&pq,0,sizeof(pq));
6439 memset(p, 0, SIZE_OF_PACKET);
6440 memset (&f, 0, sizeof(Flow));
6441 memset(&tv, 0, sizeof (ThreadVars));
6442 memset(&stt, 0, sizeof (StreamTcpThread));
6443 memset(&tcph, 0, sizeof (TCPHdr));
6444
6445 FLOW_INITIALIZE(&f);
6446 p->flow = &f;
6447 tcph.th_win = htons(5480);
6448 tcph.th_flags = TH_SYN;
6449 p->tcph = &tcph;
6450 p->flowflags = FLOW_PKT_TOSERVER;
6451
6452 StreamTcpUTInit(&stt.ra_ctx);
6453
6454 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6455
6456 p->tcph->th_ack = htonl(1);
6457 p->tcph->th_flags = TH_SYN | TH_ACK;
6458 p->flowflags = FLOW_PKT_TOCLIENT;
6459
6460 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6461
6462 p->tcph->th_ack = htonl(1);
6463 p->tcph->th_seq = htonl(1);
6464 p->tcph->th_flags = TH_ACK;
6465 p->flowflags = FLOW_PKT_TOSERVER;
6466
6467 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6468
6469 p->tcph->th_ack = htonl(1);
6470 p->tcph->th_seq = htonl(2);
6471 p->tcph->th_flags = TH_PUSH | TH_ACK;
6472 p->flowflags = FLOW_PKT_TOSERVER;
6473
6474 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
6475 p->payload = payload;
6476 p->payload_len = 3;
6477
6478 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6479
6480 p->flowflags = FLOW_PKT_TOCLIENT;
6481 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6482
6483 p->tcph->th_ack = htonl(1);
6484 p->tcph->th_seq = htonl(6);
6485 p->tcph->th_flags = TH_PUSH | TH_ACK;
6486 p->flowflags = FLOW_PKT_TOSERVER;
6487
6488 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
6489 p->payload = payload;
6490 p->payload_len = 3;
6491
6492 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6493
6494 p->flowflags = FLOW_PKT_TOCLIENT;
6495 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6496
6497 StreamTcpSessionClear(p->flow->protoctx);
6498 //StreamTcpUTClearSession(p->flow->protoctx);
6499
6500 SCFree(p);
6501 FLOW_DESTROY(&f);
6502 StreamTcpUTDeinit(stt.ra_ctx);
6503 PASS;
6504 }
6505
6506 /**
6507 * \test Test the setting up a TCP session when we missed the intial
6508 * SYN packet of the session. The session is setup only if midstream
6509 * sessions are allowed to setup.
6510 *
6511 * \retval On success it returns 1 and on failure 0.
6512 */
6513
StreamTcpTest03(void)6514 static int StreamTcpTest03 (void)
6515 {
6516 Packet *p = SCMalloc(SIZE_OF_PACKET);
6517 if (unlikely(p == NULL))
6518 return 0;
6519 Flow f;
6520 ThreadVars tv;
6521 StreamTcpThread stt;
6522 TCPHdr tcph;
6523 memset(p, 0, SIZE_OF_PACKET);
6524 PacketQueueNoLock pq;
6525 memset(&pq,0,sizeof(pq));
6526 memset (&f, 0, sizeof(Flow));
6527 memset(&tv, 0, sizeof (ThreadVars));
6528 memset(&stt, 0, sizeof (StreamTcpThread));
6529 memset(&tcph, 0, sizeof (TCPHdr));
6530 FLOW_INITIALIZE(&f);
6531 p->flow = &f;
6532
6533 StreamTcpUTInit(&stt.ra_ctx);
6534
6535 tcph.th_win = htons(5480);
6536 tcph.th_seq = htonl(10);
6537 tcph.th_ack = htonl(20);
6538 tcph.th_flags = TH_SYN|TH_ACK;
6539 p->tcph = &tcph;
6540 int ret = 0;
6541
6542 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6543 goto end;
6544
6545 p->tcph->th_seq = htonl(20);
6546 p->tcph->th_ack = htonl(11);
6547 p->tcph->th_flags = TH_ACK;
6548 p->flowflags = FLOW_PKT_TOSERVER;
6549
6550 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6551 goto end;
6552
6553 p->tcph->th_seq = htonl(19);
6554 p->tcph->th_ack = htonl(11);
6555 p->tcph->th_flags = TH_ACK|TH_PUSH;
6556 p->flowflags = FLOW_PKT_TOSERVER;
6557
6558 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6559 goto end;
6560
6561 if (stream_config.midstream != TRUE) {
6562 ret = 1;
6563 goto end;
6564 }
6565 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
6566 goto end;
6567
6568 if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 20 &&
6569 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11)
6570 goto end;
6571
6572 StreamTcpSessionClear(p->flow->protoctx);
6573
6574 ret = 1;
6575 end:
6576 SCFree(p);
6577 FLOW_DESTROY(&f);
6578 StreamTcpUTDeinit(stt.ra_ctx);
6579 return ret;
6580 }
6581
6582 /**
6583 * \test Test the setting up a TCP session when we missed the intial
6584 * SYN/ACK packet of the session. The session is setup only if
6585 * midstream sessions are allowed to setup.
6586 *
6587 * \retval On success it returns 1 and on failure 0.
6588 */
6589
StreamTcpTest04(void)6590 static int StreamTcpTest04 (void)
6591 {
6592 Packet *p = SCMalloc(SIZE_OF_PACKET);
6593 if (unlikely(p == NULL))
6594 return 0;
6595 Flow f;
6596 ThreadVars tv;
6597 StreamTcpThread stt;
6598 TCPHdr tcph;
6599 memset(p, 0, SIZE_OF_PACKET);
6600 PacketQueueNoLock pq;
6601 memset(&pq,0,sizeof(pq));
6602 memset (&f, 0, sizeof(Flow));
6603 memset(&tv, 0, sizeof (ThreadVars));
6604 memset(&stt, 0, sizeof (StreamTcpThread));
6605 memset(&tcph, 0, sizeof (TCPHdr));
6606 FLOW_INITIALIZE(&f);
6607 p->flow = &f;
6608
6609 StreamTcpUTInit(&stt.ra_ctx);
6610
6611 tcph.th_win = htons(5480);
6612 tcph.th_seq = htonl(10);
6613 tcph.th_ack = htonl(20);
6614 tcph.th_flags = TH_ACK;
6615 p->tcph = &tcph;
6616
6617 int ret = 0;
6618
6619 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6620 goto end;
6621
6622 p->tcph->th_seq = htonl(9);
6623 p->tcph->th_ack = htonl(19);
6624 p->tcph->th_flags = TH_ACK|TH_PUSH;
6625 p->flowflags = FLOW_PKT_TOSERVER;
6626
6627 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6628 goto end;
6629
6630 if (stream_config.midstream != TRUE) {
6631 ret = 1;
6632 goto end;
6633 }
6634 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
6635 goto end;
6636
6637 if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 10 &&
6638 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 20)
6639 goto end;
6640
6641 StreamTcpSessionClear(p->flow->protoctx);
6642
6643 ret = 1;
6644 end:
6645 SCFree(p);
6646 FLOW_DESTROY(&f);
6647 StreamTcpUTDeinit(stt.ra_ctx);
6648 return ret;
6649 }
6650
6651 /**
6652 * \test Test the setting up a TCP session when we missed the intial
6653 * 3WHS packet of the session. The session is setup only if
6654 * midstream sessions are allowed to setup.
6655 *
6656 * \retval On success it returns 1 and on failure 0.
6657 */
6658
StreamTcpTest05(void)6659 static int StreamTcpTest05 (void)
6660 {
6661 Packet *p = SCMalloc(SIZE_OF_PACKET);
6662 if (unlikely(p == NULL))
6663 return 0;
6664 Flow f;
6665 ThreadVars tv;
6666 StreamTcpThread stt;
6667 TCPHdr tcph;
6668 uint8_t payload[4];
6669 memset(p, 0, SIZE_OF_PACKET);
6670 PacketQueueNoLock pq;
6671 memset(&pq,0,sizeof(PacketQueueNoLock));
6672 memset (&f, 0, sizeof(Flow));
6673 memset(&tv, 0, sizeof (ThreadVars));
6674 memset(&stt, 0, sizeof (StreamTcpThread));
6675 memset(&tcph, 0, sizeof (TCPHdr));
6676 FLOW_INITIALIZE(&f);
6677 p->flow = &f;
6678 int ret = 0;
6679
6680 StreamTcpUTInit(&stt.ra_ctx);
6681 tcph.th_win = htons(5480);
6682 tcph.th_seq = htonl(10);
6683 tcph.th_ack = htonl(20);
6684 tcph.th_flags = TH_ACK|TH_PUSH;
6685 p->tcph = &tcph;
6686
6687 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
6688 p->payload = payload;
6689 p->payload_len = 3;
6690
6691 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6692 goto end;
6693
6694 p->tcph->th_seq = htonl(20);
6695 p->tcph->th_ack = htonl(13);
6696 p->tcph->th_flags = TH_ACK|TH_PUSH;
6697 p->flowflags = FLOW_PKT_TOCLIENT;
6698
6699 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
6700 p->payload = payload;
6701 p->payload_len = 3;
6702
6703 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6704 goto end;
6705
6706 p->tcph->th_seq = htonl(13);
6707 p->tcph->th_ack = htonl(23);
6708 p->tcph->th_flags = TH_ACK|TH_PUSH;
6709 p->flowflags = FLOW_PKT_TOSERVER;
6710
6711 StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/
6712 p->payload = payload;
6713 p->payload_len = 3;
6714
6715 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6716 goto end;
6717
6718 p->tcph->th_seq = htonl(19);
6719 p->tcph->th_ack = htonl(16);
6720 p->tcph->th_flags = TH_ACK|TH_PUSH;
6721 p->flowflags = FLOW_PKT_TOCLIENT;
6722
6723 StreamTcpCreateTestPacket(payload, 0x44, 3, 4); /*DDD*/
6724 p->payload = payload;
6725 p->payload_len = 3;
6726
6727 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
6728 goto end;
6729
6730 if (stream_config.midstream != TRUE) {
6731 ret = 1;
6732 goto end;
6733 }
6734 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
6735 goto end;
6736
6737 if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 16 &&
6738 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23)
6739 goto end;
6740
6741 StreamTcpSessionClear(p->flow->protoctx);
6742
6743 ret = 1;
6744 end:
6745 SCFree(p);
6746 FLOW_DESTROY(&f);
6747 StreamTcpUTDeinit(stt.ra_ctx);
6748 return ret;
6749 }
6750
6751 /**
6752 * \test Test the setting up a TCP session when we have seen only the
6753 * FIN, RST packets packet of the session. The session is setup only if
6754 * midstream sessions are allowed to setup.
6755 *
6756 * \retval On success it returns 1 and on failure 0.
6757 */
6758
StreamTcpTest06(void)6759 static int StreamTcpTest06 (void)
6760 {
6761 Packet *p = SCMalloc(SIZE_OF_PACKET);
6762 if (unlikely(p == NULL))
6763 return 0;
6764 Flow f;
6765 TcpSession ssn;
6766 ThreadVars tv;
6767 StreamTcpThread stt;
6768 TCPHdr tcph;
6769 memset(p, 0, SIZE_OF_PACKET);
6770 PacketQueueNoLock pq;
6771 memset(&pq,0,sizeof(PacketQueueNoLock));
6772 memset (&f, 0, sizeof(Flow));
6773 memset(&ssn, 0, sizeof (TcpSession));
6774 memset(&tv, 0, sizeof (ThreadVars));
6775 memset(&stt, 0, sizeof (StreamTcpThread));
6776 memset(&tcph, 0, sizeof (TCPHdr));
6777 FLOW_INITIALIZE(&f);
6778 p->flow = &f;
6779 int ret = 0;
6780
6781 StreamTcpUTInit(&stt.ra_ctx);
6782
6783 tcph.th_flags = TH_FIN;
6784 p->tcph = &tcph;
6785
6786 /* StreamTcpPacket returns -1 on unsolicited FIN */
6787 if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) {
6788 printf("StreamTcpPacket failed: ");
6789 goto end;
6790 }
6791
6792 if (((TcpSession *)(p->flow->protoctx)) != NULL) {
6793 printf("we have a ssn while we shouldn't: ");
6794 goto end;
6795 }
6796
6797 p->tcph->th_flags = TH_RST;
6798 /* StreamTcpPacket returns -1 on unsolicited RST */
6799 if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) {
6800 printf("StreamTcpPacket failed (2): ");
6801 goto end;
6802 }
6803
6804 if (((TcpSession *)(p->flow->protoctx)) != NULL) {
6805 printf("we have a ssn while we shouldn't (2): ");
6806 goto end;
6807 }
6808
6809 ret = 1;
6810 end:
6811 SCFree(p);
6812 FLOW_DESTROY(&f);
6813 StreamTcpUTDeinit(stt.ra_ctx);
6814 return ret;
6815 }
6816
6817 /**
6818 * \test Test the working on PAWS. The packet will be dropped by stream, as
6819 * its timestamp is old, although the segment is in the window.
6820 */
6821
StreamTcpTest07(void)6822 static int StreamTcpTest07 (void)
6823 {
6824 Packet *p = SCMalloc(SIZE_OF_PACKET);
6825 FAIL_IF(unlikely(p == NULL));
6826 Flow f;
6827 ThreadVars tv;
6828 StreamTcpThread stt;
6829 TCPHdr tcph;
6830 uint8_t payload[1] = {0x42};
6831 PacketQueueNoLock pq;
6832
6833 memset(p, 0, SIZE_OF_PACKET);
6834 memset(&pq,0,sizeof(PacketQueueNoLock));
6835 memset (&f, 0, sizeof(Flow));
6836 memset(&tv, 0, sizeof (ThreadVars));
6837 memset(&stt, 0, sizeof(StreamTcpThread));
6838 memset(&tcph, 0, sizeof(TCPHdr));
6839
6840 FLOW_INITIALIZE(&f);
6841 p->flow = &f;
6842
6843 StreamTcpUTInit(&stt.ra_ctx);
6844 stream_config.midstream = TRUE;
6845
6846 tcph.th_win = htons(5480);
6847 tcph.th_seq = htonl(10);
6848 tcph.th_ack = htonl(20);
6849 tcph.th_flags = TH_ACK|TH_PUSH;
6850 p->tcph = &tcph;
6851
6852 p->tcpvars.ts_set = TRUE;
6853 p->tcpvars.ts_val = 10;
6854 p->tcpvars.ts_ecr = 11;
6855
6856 p->payload = payload;
6857 p->payload_len = 1;
6858
6859 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6860
6861 p->tcph->th_seq = htonl(11);
6862 p->tcph->th_ack = htonl(23);
6863 p->tcph->th_flags = TH_ACK|TH_PUSH;
6864 p->flowflags = FLOW_PKT_TOSERVER;
6865
6866 p->tcpvars.ts_val = 2;
6867
6868 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) != -1);
6869
6870 FAIL_IF(((TcpSession *) (p->flow->protoctx))->client.next_seq != 11);
6871
6872 StreamTcpSessionClear(p->flow->protoctx);
6873 SCFree(p);
6874 FLOW_DESTROY(&f);
6875 StreamTcpUTDeinit(stt.ra_ctx);
6876 PASS;
6877 }
6878
6879 /**
6880 * \test Test the working on PAWS. The packet will be accpeted by engine as
6881 * the timestamp is valid and it is in window.
6882 */
6883
StreamTcpTest08(void)6884 static int StreamTcpTest08 (void)
6885 {
6886 Packet *p = SCMalloc(SIZE_OF_PACKET);
6887 FAIL_IF(unlikely(p == NULL));
6888 Flow f;
6889 ThreadVars tv;
6890 StreamTcpThread stt;
6891 TCPHdr tcph;
6892 uint8_t payload[1] = {0x42};
6893
6894 memset(p, 0, SIZE_OF_PACKET);
6895 PacketQueueNoLock pq;
6896 memset(&pq,0,sizeof(PacketQueueNoLock));
6897 memset (&f, 0, sizeof(Flow));
6898 memset(&tv, 0, sizeof (ThreadVars));
6899 memset(&stt, 0, sizeof(StreamTcpThread));
6900 memset(&tcph, 0, sizeof(TCPHdr));
6901
6902 FLOW_INITIALIZE(&f);
6903 p->flow = &f;
6904
6905 StreamTcpUTInit(&stt.ra_ctx);
6906 stream_config.midstream = TRUE;
6907
6908 tcph.th_win = htons(5480);
6909 tcph.th_seq = htonl(10);
6910 tcph.th_ack = htonl(20);
6911 tcph.th_flags = TH_ACK|TH_PUSH;
6912 p->tcph = &tcph;
6913
6914 p->tcpvars.ts_set = TRUE;
6915 p->tcpvars.ts_val = 10;
6916 p->tcpvars.ts_ecr = 11;
6917
6918 p->payload = payload;
6919 p->payload_len = 1;
6920
6921 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6922
6923 p->tcph->th_seq = htonl(11);
6924 p->tcph->th_ack = htonl(20);
6925 p->tcph->th_flags = TH_ACK|TH_PUSH;
6926 p->flowflags = FLOW_PKT_TOSERVER;
6927
6928 p->tcpvars.ts_val = 12;
6929
6930 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6931
6932 FAIL_IF(((TcpSession *) (p->flow->protoctx))->client.next_seq != 12);
6933
6934 StreamTcpSessionClear(p->flow->protoctx);
6935
6936 SCFree(p);
6937 FLOW_DESTROY(&f);
6938 StreamTcpUTDeinit(stt.ra_ctx);
6939 PASS;
6940 }
6941
6942 /**
6943 * \test Test the working of No stream reassembly flag. The stream will not
6944 * reassemble the segment if the flag is set.
6945 */
6946
StreamTcpTest09(void)6947 static int StreamTcpTest09 (void)
6948 {
6949 Packet *p = SCMalloc(SIZE_OF_PACKET);
6950 FAIL_IF(unlikely(p == NULL));
6951 Flow f;
6952 ThreadVars tv;
6953 StreamTcpThread stt;
6954 TCPHdr tcph;
6955 uint8_t payload[1] = {0x42};
6956
6957 memset(p, 0, SIZE_OF_PACKET);
6958 PacketQueueNoLock pq;
6959 memset(&pq,0,sizeof(PacketQueueNoLock));
6960 memset (&f, 0, sizeof(Flow));
6961 memset(&tv, 0, sizeof (ThreadVars));
6962 memset(&stt, 0, sizeof(StreamTcpThread));
6963 memset(&tcph, 0, sizeof(TCPHdr));
6964
6965 FLOW_INITIALIZE(&f);
6966 p->flow = &f;
6967
6968 StreamTcpUTInit(&stt.ra_ctx);
6969 stream_config.midstream = TRUE;
6970
6971 tcph.th_win = htons(5480);
6972 tcph.th_seq = htonl(10);
6973 tcph.th_ack = htonl(20);
6974 tcph.th_flags = TH_ACK|TH_PUSH;
6975 p->tcph = &tcph;
6976
6977 p->payload = payload;
6978 p->payload_len = 1;
6979
6980 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6981
6982 p->tcph->th_seq = htonl(12);
6983 p->tcph->th_ack = htonl(23);
6984 p->tcph->th_flags = TH_ACK|TH_PUSH;
6985 p->flowflags = FLOW_PKT_TOSERVER;
6986
6987 FAIL_IF(p->flow->protoctx == NULL);
6988
6989 StreamTcpSetSessionNoReassemblyFlag(((TcpSession *)(p->flow->protoctx)), 0);
6990
6991 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6992
6993 p->tcph->th_seq = htonl(11);
6994 p->tcph->th_ack = htonl(23);
6995 p->tcph->th_flags = TH_ACK|TH_PUSH;
6996 p->flowflags = FLOW_PKT_TOSERVER;
6997
6998 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
6999
7000 TcpSession *ssn = p->flow->protoctx;
7001 FAIL_IF_NULL(ssn);
7002 TcpSegment *seg = RB_MIN(TCPSEG, &ssn->client.seg_tree);
7003 FAIL_IF_NULL(seg);
7004 FAIL_IF(TCPSEG_RB_NEXT(seg) != NULL);
7005
7006 StreamTcpSessionClear(p->flow->protoctx);
7007 SCFree(p);
7008 FLOW_DESTROY(&f);
7009 StreamTcpUTDeinit(stt.ra_ctx);
7010 PASS;
7011 }
7012
7013 /**
7014 * \test Test the setting up a TCP session when we are seeing asynchronous
7015 * stream, while we see all the packets in that stream from start.
7016 */
7017
StreamTcpTest10(void)7018 static int StreamTcpTest10 (void)
7019 {
7020 Packet *p = SCMalloc(SIZE_OF_PACKET);
7021 FAIL_IF(unlikely(p == NULL));
7022 Flow f;
7023 ThreadVars tv;
7024 StreamTcpThread stt;
7025 TCPHdr tcph;
7026 uint8_t payload[4];
7027 memset(p, 0, SIZE_OF_PACKET);
7028 PacketQueueNoLock pq;
7029 memset(&pq,0,sizeof(PacketQueueNoLock));
7030 memset (&f, 0, sizeof(Flow));
7031 memset(&tv, 0, sizeof (ThreadVars));
7032 memset(&stt, 0, sizeof (StreamTcpThread));
7033 memset(&tcph, 0, sizeof (TCPHdr));
7034 FLOW_INITIALIZE(&f);
7035 p->flow = &f;
7036
7037 StreamTcpUTInit(&stt.ra_ctx);
7038 stream_config.async_oneside = TRUE;
7039
7040 tcph.th_win = htons(5480);
7041 tcph.th_seq = htonl(10);
7042 tcph.th_ack = 0;
7043 tcph.th_flags = TH_SYN;
7044 p->tcph = &tcph;
7045
7046 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
7047
7048 p->tcph->th_seq = htonl(11);
7049 p->tcph->th_ack = htonl(11);
7050 p->tcph->th_flags = TH_ACK;
7051 p->flowflags = FLOW_PKT_TOSERVER;
7052
7053 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
7054
7055 p->tcph->th_seq = htonl(11);
7056 p->tcph->th_ack = htonl(11);
7057 p->tcph->th_flags = TH_ACK|TH_PUSH;
7058 p->flowflags = FLOW_PKT_TOSERVER;
7059
7060 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7061 p->payload = payload;
7062 p->payload_len = 3;
7063
7064 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
7065
7066 p->tcph->th_seq = htonl(6);
7067 p->tcph->th_ack = htonl(11);
7068 p->tcph->th_flags = TH_ACK|TH_PUSH;
7069 p->flowflags = FLOW_PKT_TOSERVER;
7070
7071 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7072 p->payload = payload;
7073 p->payload_len = 3;
7074
7075 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
7076
7077 FAIL_IF(((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED);
7078
7079 FAIL_IF(! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC));
7080
7081 FAIL_IF(((TcpSession *)(p->flow->protoctx))->client.last_ack != 6 &&
7082 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11);
7083
7084 StreamTcpSessionClear(p->flow->protoctx);
7085
7086 SCFree(p);
7087 FLOW_DESTROY(&f);
7088 StreamTcpUTDeinit(stt.ra_ctx);
7089 PASS;
7090 }
7091
7092 /**
7093 * \test Test the setting up a TCP session when we are seeing asynchronous
7094 * stream, while we missed the SYN packet of that stream.
7095 */
7096
StreamTcpTest11(void)7097 static int StreamTcpTest11 (void)
7098 {
7099 Packet *p = SCMalloc(SIZE_OF_PACKET);
7100 FAIL_IF(unlikely(p == NULL));
7101 Flow f;
7102 ThreadVars tv;
7103 StreamTcpThread stt;
7104 TCPHdr tcph;
7105 uint8_t payload[4];
7106 memset(p, 0, SIZE_OF_PACKET);
7107 PacketQueueNoLock pq;
7108 memset(&pq,0,sizeof(PacketQueueNoLock));
7109 memset (&f, 0, sizeof(Flow));
7110 memset(&tv, 0, sizeof (ThreadVars));
7111 memset(&stt, 0, sizeof (StreamTcpThread));
7112 memset(&tcph, 0, sizeof (TCPHdr));
7113 FLOW_INITIALIZE(&f);
7114 p->flow = &f;
7115
7116 StreamTcpUTInit(&stt.ra_ctx);
7117 stream_config.async_oneside = TRUE;
7118
7119 tcph.th_win = htons(5480);
7120 tcph.th_seq = htonl(10);
7121 tcph.th_ack = htonl(1);
7122 tcph.th_flags = TH_SYN|TH_ACK;
7123 p->tcph = &tcph;
7124
7125 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
7126
7127 p->tcph->th_seq = htonl(11);
7128 p->tcph->th_ack = htonl(1);
7129 p->tcph->th_flags = TH_ACK;
7130 p->flowflags = FLOW_PKT_TOSERVER;
7131
7132 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
7133
7134 p->tcph->th_seq = htonl(11);
7135 p->tcph->th_ack = htonl(1);
7136 p->tcph->th_flags = TH_ACK|TH_PUSH;
7137 p->flowflags = FLOW_PKT_TOSERVER;
7138
7139 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7140 p->payload = payload;
7141 p->payload_len = 3;
7142
7143 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
7144
7145 p->tcph->th_seq = htonl(2);
7146 p->tcph->th_ack = htonl(1);
7147 p->tcph->th_flags = TH_ACK|TH_PUSH;
7148 p->flowflags = FLOW_PKT_TOSERVER;
7149
7150 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7151 p->payload = payload;
7152 p->payload_len = 3;
7153
7154 FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
7155
7156 FAIL_IF(! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC));
7157
7158 FAIL_IF(((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED);
7159
7160 FAIL_IF(((TcpSession *)(p->flow->protoctx))->server.last_ack != 2 &&
7161 ((TcpSession *)(p->flow->protoctx))->client.next_seq != 1);
7162
7163 StreamTcpSessionClear(p->flow->protoctx);
7164 SCFree(p);
7165 FLOW_DESTROY(&f);
7166 StreamTcpUTDeinit(stt.ra_ctx);
7167 PASS;
7168 }
7169
7170 /**
7171 * \test Test the setting up a TCP session when we are seeing asynchronous
7172 * stream, while we missed the SYN and SYN/ACK packets in that stream.
7173 *
7174 * \retval On success it returns 1 and on failure 0.
7175 */
7176
StreamTcpTest12(void)7177 static int StreamTcpTest12 (void)
7178 {
7179 Packet *p = SCMalloc(SIZE_OF_PACKET);
7180 if (unlikely(p == NULL))
7181 return 0;
7182 Flow f;
7183 ThreadVars tv;
7184 StreamTcpThread stt;
7185 TCPHdr tcph;
7186 uint8_t payload[4];
7187 memset(p, 0, SIZE_OF_PACKET);
7188 PacketQueueNoLock pq;
7189 memset(&pq,0,sizeof(PacketQueueNoLock));
7190 memset (&f, 0, sizeof(Flow));
7191 memset(&tv, 0, sizeof (ThreadVars));
7192 memset(&stt, 0, sizeof (StreamTcpThread));
7193 memset(&tcph, 0, sizeof (TCPHdr));
7194 FLOW_INITIALIZE(&f);
7195 p->flow = &f;
7196
7197 StreamTcpUTInit(&stt.ra_ctx);
7198
7199 tcph.th_win = htons(5480);
7200 tcph.th_seq = htonl(10);
7201 tcph.th_ack = htonl(11);
7202 tcph.th_flags = TH_ACK;
7203 p->tcph = &tcph;
7204 int ret = 0;
7205
7206 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7207 goto end;
7208
7209 p->tcph->th_seq = htonl(10);
7210 p->tcph->th_ack = htonl(11);
7211 p->tcph->th_flags = TH_ACK|TH_PUSH;
7212 p->flowflags = FLOW_PKT_TOSERVER;
7213
7214 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7215 p->payload = payload;
7216 p->payload_len = 3;
7217
7218 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7219 goto end;
7220
7221 p->tcph->th_seq = htonl(6);
7222 p->tcph->th_ack = htonl(11);
7223 p->tcph->th_flags = TH_ACK|TH_PUSH;
7224 p->flowflags = FLOW_PKT_TOSERVER;
7225
7226 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7227 p->payload = payload;
7228 p->payload_len = 3;
7229
7230 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7231 goto end;
7232
7233 if (stream_config.async_oneside != TRUE) {
7234 ret = 1;
7235 goto end;
7236 }
7237
7238 if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) {
7239 printf("failed in setting asynchronous session\n");
7240 goto end;
7241 }
7242
7243 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
7244 printf("failed in setting state\n");
7245 goto end;
7246 }
7247
7248 if (((TcpSession *)(p->flow->protoctx))->client.last_ack != 6 &&
7249 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11) {
7250 printf("failed in seq %"PRIu32" match\n",
7251 ((TcpSession *)(p->flow->protoctx))->client.last_ack);
7252 goto end;
7253 }
7254
7255 StreamTcpSessionClear(p->flow->protoctx);
7256
7257 ret = 1;
7258 end:
7259 SCFree(p);
7260 FLOW_DESTROY(&f);
7261 StreamTcpUTDeinit(stt.ra_ctx);
7262 return ret;
7263 }
7264
7265 /**
7266 * \test Test the setting up a TCP session when we are seeing asynchronous
7267 * stream, while we missed the SYN and SYN/ACK packets in that stream.
7268 * Later, we start to receive the packet from other end stream too.
7269 *
7270 * \retval On success it returns 1 and on failure 0.
7271 */
7272
StreamTcpTest13(void)7273 static int StreamTcpTest13 (void)
7274 {
7275 Packet *p = SCMalloc(SIZE_OF_PACKET);
7276 if (unlikely(p == NULL))
7277 return 0;
7278 Flow f;
7279 ThreadVars tv;
7280 StreamTcpThread stt;
7281 TCPHdr tcph;
7282 uint8_t payload[4];
7283 memset(p, 0, SIZE_OF_PACKET);
7284 PacketQueueNoLock pq;
7285 memset(&pq,0,sizeof(PacketQueueNoLock));
7286 memset (&f, 0, sizeof(Flow));
7287 memset(&tv, 0, sizeof (ThreadVars));
7288 memset(&stt, 0, sizeof (StreamTcpThread));
7289 memset(&tcph, 0, sizeof (TCPHdr));
7290 FLOW_INITIALIZE(&f);
7291 p->flow = &f;
7292
7293 StreamTcpUTInit(&stt.ra_ctx);
7294
7295 tcph.th_win = htons(5480);
7296 tcph.th_seq = htonl(10);
7297 tcph.th_ack = htonl(11);
7298 tcph.th_flags = TH_ACK;
7299 p->tcph = &tcph;
7300 int ret = 0;
7301
7302 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7303 goto end;
7304
7305 p->tcph->th_seq = htonl(10);
7306 p->tcph->th_ack = htonl(11);
7307 p->tcph->th_flags = TH_ACK|TH_PUSH;
7308 p->flowflags = FLOW_PKT_TOSERVER;
7309
7310 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7311 p->payload = payload;
7312 p->payload_len = 3;
7313
7314 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7315 goto end;
7316
7317 p->tcph->th_seq = htonl(6);
7318 p->tcph->th_ack = htonl(11);
7319 p->tcph->th_flags = TH_ACK|TH_PUSH;
7320 p->flowflags = FLOW_PKT_TOSERVER;
7321
7322 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7323 p->payload = payload;
7324 p->payload_len = 3;
7325
7326 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7327 goto end;
7328
7329 if (stream_config.async_oneside != TRUE) {
7330 ret = 1;
7331 goto end;
7332 }
7333
7334 if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) {
7335 printf("failed in setting asynchronous session\n");
7336 goto end;
7337 }
7338
7339 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
7340 printf("failed in setting state\n");
7341 goto end;
7342 }
7343
7344 p->tcph->th_seq = htonl(11);
7345 p->tcph->th_ack = htonl(9);
7346 p->tcph->th_flags = TH_ACK|TH_PUSH;
7347 p->flowflags = FLOW_PKT_TOCLIENT;
7348
7349 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
7350 p->payload = payload;
7351 p->payload_len = 3;
7352
7353 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7354 goto end;
7355
7356 if (((TcpSession *)(p->flow->protoctx))->client.last_ack != 9 &&
7357 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 14) {
7358 printf("failed in seq %"PRIu32" match\n",
7359 ((TcpSession *)(p->flow->protoctx))->client.last_ack);
7360 goto end;
7361 }
7362
7363 StreamTcpSessionPktFree(p);
7364
7365 ret = 1;
7366 end:
7367 SCFree(p);
7368 FLOW_DESTROY(&f);
7369 StreamTcpUTDeinit(stt.ra_ctx);
7370 return ret;
7371 }
7372
7373 /* Dummy conf string to setup the OS policy for unit testing */
7374 static const char *dummy_conf_string =
7375 "%YAML 1.1\n"
7376 "---\n"
7377 "\n"
7378 "default-log-dir: /var/log/eidps\n"
7379 "\n"
7380 "logging:\n"
7381 "\n"
7382 " default-log-level: debug\n"
7383 "\n"
7384 " default-format: \"<%t> - <%l>\"\n"
7385 "\n"
7386 " default-startup-message: Your IDS has started.\n"
7387 "\n"
7388 " default-output-filter:\n"
7389 "\n"
7390 "host-os-policy:\n"
7391 "\n"
7392 " windows: 192.168.0.1\n"
7393 "\n"
7394 " linux: 192.168.0.2\n"
7395 "\n";
7396 /* Dummy conf string to setup the OS policy for unit testing */
7397 static const char *dummy_conf_string1 =
7398 "%YAML 1.1\n"
7399 "---\n"
7400 "\n"
7401 "default-log-dir: /var/log/eidps\n"
7402 "\n"
7403 "logging:\n"
7404 "\n"
7405 " default-log-level: debug\n"
7406 "\n"
7407 " default-format: \"<%t> - <%l>\"\n"
7408 "\n"
7409 " default-startup-message: Your IDS has started.\n"
7410 "\n"
7411 " default-output-filter:\n"
7412 "\n"
7413 "host-os-policy:\n"
7414 "\n"
7415 " windows: 192.168.0.0/24," "192.168.1.1\n"
7416 "\n"
7417 " linux: 192.168.1.0/24," "192.168.0.1\n"
7418 "\n";
7419
7420 /**
7421 * \brief Function to parse the dummy conf string and get the value of IP
7422 * address for the corresponding OS policy type.
7423 *
7424 * \param conf_val_name Name of the OS policy type
7425 * \retval returns IP address as string on success and NULL on failure
7426 */
StreamTcpParseOSPolicy(char * conf_var_name)7427 static const char *StreamTcpParseOSPolicy (char *conf_var_name)
7428 {
7429 SCEnter();
7430 char conf_var_type_name[15] = "host-os-policy";
7431 char *conf_var_full_name = NULL;
7432 const char *conf_var_value = NULL;
7433
7434 if (conf_var_name == NULL)
7435 goto end;
7436
7437 /* the + 2 is for the '.' and the string termination character '\0' */
7438 conf_var_full_name = (char *)SCMalloc(strlen(conf_var_type_name) +
7439 strlen(conf_var_name) + 2);
7440 if (conf_var_full_name == NULL)
7441 goto end;
7442
7443 if (snprintf(conf_var_full_name,
7444 strlen(conf_var_type_name) + strlen(conf_var_name) + 2, "%s.%s",
7445 conf_var_type_name, conf_var_name) < 0) {
7446 SCLogError(SC_ERR_INVALID_VALUE, "Error in making the conf full name");
7447 goto end;
7448 }
7449
7450 if (ConfGet(conf_var_full_name, &conf_var_value) != 1) {
7451 SCLogError(SC_ERR_UNKNOWN_VALUE, "Error in getting conf value for conf name %s",
7452 conf_var_full_name);
7453 goto end;
7454 }
7455
7456 SCLogDebug("Value obtained from the yaml conf file, for the var "
7457 "\"%s\" is \"%s\"", conf_var_name, conf_var_value);
7458
7459 end:
7460 if (conf_var_full_name != NULL)
7461 SCFree(conf_var_full_name);
7462 SCReturnCharPtr(conf_var_value);
7463
7464
7465 }
7466 /**
7467 * \test Test the setting up a OS policy. Te OS policy values are defined in
7468 * the config string "dummy_conf_string"
7469 *
7470 * \retval On success it returns 1 and on failure 0
7471 */
7472
StreamTcpTest14(void)7473 static int StreamTcpTest14 (void)
7474 {
7475 Packet *p = SCMalloc(SIZE_OF_PACKET);
7476 if (unlikely(p == NULL))
7477 return 0;
7478 Flow f;
7479 ThreadVars tv;
7480 StreamTcpThread stt;
7481 TCPHdr tcph;
7482 uint8_t payload[4];
7483 struct in_addr addr;
7484 IPV4Hdr ipv4h;
7485 char os_policy_name[10] = "windows";
7486 const char *ip_addr;
7487 PacketQueueNoLock pq;
7488 memset(&pq,0,sizeof(PacketQueueNoLock));
7489
7490 memset(p, 0, SIZE_OF_PACKET);
7491 memset (&f, 0, sizeof(Flow));
7492 memset(&tv, 0, sizeof (ThreadVars));
7493 memset(&stt, 0, sizeof (StreamTcpThread));
7494 memset(&tcph, 0, sizeof (TCPHdr));
7495 memset(&addr, 0, sizeof(addr));
7496 memset(&ipv4h, 0, sizeof(ipv4h));
7497 FLOW_INITIALIZE(&f);
7498 p->flow = &f;
7499 int ret = 0;
7500
7501 StreamTcpUTInit(&stt.ra_ctx);
7502
7503 /* Load the config string in to parser */
7504 ConfCreateContextBackup();
7505 ConfInit();
7506 ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
7507
7508 /* Get the IP address as string and add it to Host info tree for lookups */
7509 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
7510 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
7511 strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name));
7512 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
7513 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
7514 addr.s_addr = inet_addr("192.168.0.1");
7515 tcph.th_win = htons(5480);
7516 tcph.th_seq = htonl(10);
7517 tcph.th_ack = htonl(20);
7518 tcph.th_flags = TH_ACK|TH_PUSH;
7519 p->tcph = &tcph;
7520 p->dst.family = AF_INET;
7521 p->dst.address.address_un_data32[0] = addr.s_addr;
7522 p->ip4h = &ipv4h;
7523
7524 StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/
7525 p->payload = payload;
7526 p->payload_len = 3;
7527
7528 FLOWLOCK_WRLOCK(&f);
7529 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7530 goto end;
7531
7532 p->tcph->th_seq = htonl(20);
7533 p->tcph->th_ack = htonl(13);
7534 p->tcph->th_flags = TH_ACK|TH_PUSH;
7535 p->flowflags = FLOW_PKT_TOCLIENT;
7536
7537 StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/
7538 p->payload = payload;
7539 p->payload_len = 3;
7540
7541 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7542 goto end;
7543
7544 p->tcph->th_seq = htonl(15);
7545 p->tcph->th_ack = htonl(23);
7546 p->tcph->th_flags = TH_ACK|TH_PUSH;
7547 p->flowflags = FLOW_PKT_TOSERVER;
7548
7549 StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
7550 p->payload = payload;
7551 p->payload_len = 3;
7552
7553 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7554 goto end;
7555
7556 p->tcph->th_seq = htonl(14);
7557 p->tcph->th_ack = htonl(23);
7558 p->tcph->th_flags = TH_ACK|TH_PUSH;
7559 p->flowflags = FLOW_PKT_TOSERVER;
7560
7561 StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
7562 p->payload = payload;
7563 p->payload_len = 3;
7564
7565 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7566 goto end;
7567
7568 addr.s_addr = inet_addr("192.168.0.2");
7569 p->tcph->th_seq = htonl(25);
7570 p->tcph->th_ack = htonl(13);
7571 p->tcph->th_flags = TH_ACK|TH_PUSH;
7572 p->flowflags = FLOW_PKT_TOCLIENT;
7573 p->dst.address.address_un_data32[0] = addr.s_addr;
7574
7575 StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
7576 p->payload = payload;
7577 p->payload_len = 3;
7578
7579 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7580 goto end;
7581
7582 p->tcph->th_seq = htonl(24);
7583 p->tcph->th_ack = htonl(13);
7584 p->tcph->th_flags = TH_ACK|TH_PUSH;
7585 p->flowflags = FLOW_PKT_TOCLIENT;
7586
7587 StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
7588 p->payload = payload;
7589 p->payload_len = 3;
7590
7591 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7592 goto end;
7593
7594 if (stream_config.midstream != TRUE) {
7595 ret = 1;
7596 goto end;
7597 }
7598 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
7599 goto end;
7600
7601 if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 &&
7602 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) {
7603 printf("failed in next_seq match client.next_seq %"PRIu32""
7604 " server.next_seq %"PRIu32"\n",
7605 ((TcpSession *)(p->flow->protoctx))->client.next_seq,
7606 ((TcpSession *)(p->flow->protoctx))->server.next_seq);
7607 goto end;
7608 }
7609
7610 if (((TcpSession *)(p->flow->protoctx))->client.os_policy !=
7611 OS_POLICY_WINDOWS && ((TcpSession *)
7612 (p->flow->protoctx))->server.os_policy != OS_POLICY_LINUX)
7613 {
7614 printf("failed in setting up OS policy, client.os_policy: %"PRIu8""
7615 " should be %"PRIu8" and server.os_policy: %"PRIu8""
7616 " should be %"PRIu8"\n", ((TcpSession *)
7617 (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_WINDOWS,
7618 ((TcpSession *)(p->flow->protoctx))->server.os_policy,
7619 (uint8_t)OS_POLICY_LINUX);
7620 goto end;
7621 }
7622 StreamTcpSessionClear(p->flow->protoctx);
7623
7624 ret = 1;
7625 end:
7626 ConfDeInit();
7627 ConfRestoreContextBackup();
7628 FLOWLOCK_UNLOCK(&f);
7629 SCFree(p);
7630 FLOW_DESTROY(&f);
7631 StreamTcpUTDeinit(stt.ra_ctx);
7632 return ret;
7633 }
7634
7635 /**
7636 * \test Test the setting up a TCP session using the 4WHS:
7637 * SYN, SYN, SYN/ACK, ACK
7638 *
7639 * \retval On success it returns 1 and on failure 0.
7640 */
7641
StreamTcp4WHSTest01(void)7642 static int StreamTcp4WHSTest01 (void)
7643 {
7644 int ret = 0;
7645 Packet *p = SCMalloc(SIZE_OF_PACKET);
7646 if (unlikely(p == NULL))
7647 return 0;
7648 Flow f;
7649 ThreadVars tv;
7650 StreamTcpThread stt;
7651 TCPHdr tcph;
7652 memset(p, 0, SIZE_OF_PACKET);
7653 PacketQueueNoLock pq;
7654 memset(&pq,0,sizeof(PacketQueueNoLock));
7655 memset (&f, 0, sizeof(Flow));
7656 memset(&tv, 0, sizeof (ThreadVars));
7657 memset(&stt, 0, sizeof (StreamTcpThread));
7658 memset(&tcph, 0, sizeof (TCPHdr));
7659 FLOW_INITIALIZE(&f);
7660 p->flow = &f;
7661
7662 StreamTcpUTInit(&stt.ra_ctx);
7663
7664 tcph.th_win = htons(5480);
7665 tcph.th_seq = htonl(10);
7666 tcph.th_ack = 0;
7667 tcph.th_flags = TH_SYN;
7668 p->tcph = &tcph;
7669
7670 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7671 goto end;
7672
7673 p->tcph->th_seq = htonl(20);
7674 p->tcph->th_ack = 0;
7675 p->tcph->th_flags = TH_SYN;
7676 p->flowflags = FLOW_PKT_TOCLIENT;
7677
7678 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7679 goto end;
7680
7681 if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) {
7682 printf("STREAMTCP_FLAG_4WHS flag not set: ");
7683 goto end;
7684 }
7685
7686 p->tcph->th_seq = htonl(10);
7687 p->tcph->th_ack = htonl(21); /* the SYN/ACK uses the SEQ from the first SYN pkt */
7688 p->tcph->th_flags = TH_SYN|TH_ACK;
7689 p->flowflags = FLOW_PKT_TOSERVER;
7690
7691 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7692 goto end;
7693
7694 p->tcph->th_seq = htonl(21);
7695 p->tcph->th_ack = htonl(10);
7696 p->tcph->th_flags = TH_ACK;
7697 p->flowflags = FLOW_PKT_TOCLIENT;
7698
7699 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7700 goto end;
7701
7702 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
7703 printf("state is not ESTABLISHED: ");
7704 goto end;
7705 }
7706
7707 ret = 1;
7708 end:
7709 StreamTcpSessionClear(p->flow->protoctx);
7710 SCFree(p);
7711 FLOW_DESTROY(&f);
7712 StreamTcpUTDeinit(stt.ra_ctx);
7713 return ret;
7714 }
7715
7716 /**
7717 * \test set up a TCP session using the 4WHS:
7718 * SYN, SYN, SYN/ACK, ACK, but the SYN/ACK does
7719 * not have the right SEQ
7720 *
7721 * \retval On success it returns 1 and on failure 0.
7722 */
7723
StreamTcp4WHSTest02(void)7724 static int StreamTcp4WHSTest02 (void)
7725 {
7726 int ret = 0;
7727 Packet *p = SCMalloc(SIZE_OF_PACKET);
7728 if (unlikely(p == NULL))
7729 return 0;
7730 Flow f;
7731 ThreadVars tv;
7732 StreamTcpThread stt;
7733 TCPHdr tcph;
7734 memset(p, 0, SIZE_OF_PACKET);
7735 PacketQueueNoLock pq;
7736 memset(&pq,0,sizeof(PacketQueueNoLock));
7737 memset (&f, 0, sizeof(Flow));
7738 memset(&tv, 0, sizeof (ThreadVars));
7739 memset(&stt, 0, sizeof (StreamTcpThread));
7740 memset(&tcph, 0, sizeof (TCPHdr));
7741 FLOW_INITIALIZE(&f);
7742 p->flow = &f;
7743
7744 StreamTcpUTInit(&stt.ra_ctx);
7745
7746 tcph.th_win = htons(5480);
7747 tcph.th_seq = htonl(10);
7748 tcph.th_ack = 0;
7749 tcph.th_flags = TH_SYN;
7750 p->tcph = &tcph;
7751
7752 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7753 goto end;
7754
7755 p->tcph->th_seq = htonl(20);
7756 p->tcph->th_ack = 0;
7757 p->tcph->th_flags = TH_SYN;
7758 p->flowflags = FLOW_PKT_TOCLIENT;
7759
7760 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7761 goto end;
7762
7763 if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) {
7764 printf("STREAMTCP_FLAG_4WHS flag not set: ");
7765 goto end;
7766 }
7767
7768 p->tcph->th_seq = htonl(30);
7769 p->tcph->th_ack = htonl(21); /* the SYN/ACK uses the SEQ from the first SYN pkt */
7770 p->tcph->th_flags = TH_SYN|TH_ACK;
7771 p->flowflags = FLOW_PKT_TOSERVER;
7772
7773 if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) {
7774 printf("SYN/ACK pkt not rejected but it should have: ");
7775 goto end;
7776 }
7777
7778 ret = 1;
7779 end:
7780 StreamTcpSessionClear(p->flow->protoctx);
7781 SCFree(p);
7782 FLOW_DESTROY(&f);
7783 StreamTcpUTDeinit(stt.ra_ctx);
7784 return ret;
7785 }
7786
7787 /**
7788 * \test set up a TCP session using the 4WHS:
7789 * SYN, SYN, SYN/ACK, ACK: however the SYN/ACK and ACK
7790 * are part of a normal 3WHS
7791 *
7792 * \retval On success it returns 1 and on failure 0.
7793 */
7794
StreamTcp4WHSTest03(void)7795 static int StreamTcp4WHSTest03 (void)
7796 {
7797 int ret = 0;
7798 Packet *p = SCMalloc(SIZE_OF_PACKET);
7799 FAIL_IF(unlikely(p == NULL));
7800 Flow f;
7801 ThreadVars tv;
7802 StreamTcpThread stt;
7803 TCPHdr tcph;
7804 memset(p, 0, SIZE_OF_PACKET);
7805 PacketQueueNoLock pq;
7806 memset(&pq,0,sizeof(PacketQueueNoLock));
7807 memset (&f, 0, sizeof(Flow));
7808 memset(&tv, 0, sizeof (ThreadVars));
7809 memset(&stt, 0, sizeof (StreamTcpThread));
7810 memset(&tcph, 0, sizeof (TCPHdr));
7811 FLOW_INITIALIZE(&f);
7812 p->flow = &f;
7813
7814 StreamTcpUTInit(&stt.ra_ctx);
7815
7816 tcph.th_win = htons(5480);
7817 tcph.th_seq = htonl(10);
7818 tcph.th_ack = 0;
7819 tcph.th_flags = TH_SYN;
7820 p->tcph = &tcph;
7821
7822 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7823 goto end;
7824
7825 p->tcph->th_seq = htonl(20);
7826 p->tcph->th_ack = 0;
7827 p->tcph->th_flags = TH_SYN;
7828 p->flowflags = FLOW_PKT_TOCLIENT;
7829
7830 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7831 goto end;
7832
7833 if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) {
7834 printf("STREAMTCP_FLAG_4WHS flag not set: ");
7835 goto end;
7836 }
7837
7838 p->tcph->th_seq = htonl(30);
7839 p->tcph->th_ack = htonl(11);
7840 p->tcph->th_flags = TH_SYN|TH_ACK;
7841 p->flowflags = FLOW_PKT_TOCLIENT;
7842
7843 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7844 goto end;
7845
7846 p->tcph->th_seq = htonl(11);
7847 p->tcph->th_ack = htonl(31);
7848 p->tcph->th_flags = TH_ACK;
7849 p->flowflags = FLOW_PKT_TOSERVER;
7850
7851 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7852 goto end;
7853
7854 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
7855 printf("state is not ESTABLISHED: ");
7856 goto end;
7857 }
7858
7859 ret = 1;
7860 end:
7861 StreamTcpSessionClear(p->flow->protoctx);
7862 SCFree(p);
7863 FLOW_DESTROY(&f);
7864 StreamTcpUTDeinit(stt.ra_ctx);
7865 return ret;
7866 }
7867
7868 /**
7869 * \test Test the setting up a OS policy. Te OS policy values are defined in
7870 * the config string "dummy_conf_string1"
7871 *
7872 * \retval On success it returns 1 and on failure 0
7873 */
7874
StreamTcpTest15(void)7875 static int StreamTcpTest15 (void)
7876 {
7877 Packet *p = SCMalloc(SIZE_OF_PACKET);
7878 if (unlikely(p == NULL))
7879 return 0;
7880 Flow f;
7881 ThreadVars tv;
7882 StreamTcpThread stt;
7883 TCPHdr tcph;
7884 uint8_t payload[4];
7885 struct in_addr addr;
7886 IPV4Hdr ipv4h;
7887 char os_policy_name[10] = "windows";
7888 const char *ip_addr;
7889 PacketQueueNoLock pq;
7890 memset(&pq,0,sizeof(PacketQueueNoLock));
7891
7892 memset(p, 0, SIZE_OF_PACKET);
7893 memset (&f, 0, sizeof(Flow));
7894 memset(&tv, 0, sizeof (ThreadVars));
7895 memset(&stt, 0, sizeof (StreamTcpThread));
7896 memset(&tcph, 0, sizeof (TCPHdr));
7897 memset(&addr, 0, sizeof(addr));
7898 memset(&ipv4h, 0, sizeof(ipv4h));
7899 FLOW_INITIALIZE(&f);
7900 p->flow = &f;
7901 int ret = 0;
7902
7903 StreamTcpUTInit(&stt.ra_ctx);
7904
7905 /* Load the config string in to parser */
7906 ConfCreateContextBackup();
7907 ConfInit();
7908 ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
7909
7910 /* Get the IP address as string and add it to Host info tree for lookups */
7911 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
7912 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
7913 strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name));
7914 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
7915 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
7916 addr.s_addr = inet_addr("192.168.0.20");
7917 tcph.th_win = htons(5480);
7918 tcph.th_seq = htonl(10);
7919 tcph.th_ack = htonl(20);
7920 tcph.th_flags = TH_ACK|TH_PUSH;
7921 p->tcph = &tcph;
7922 p->dst.family = AF_INET;
7923 p->dst.address.address_un_data32[0] = addr.s_addr;
7924 p->ip4h = &ipv4h;
7925
7926 StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/
7927 p->payload = payload;
7928 p->payload_len = 3;
7929
7930 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7931 goto end;
7932
7933 p->tcph->th_seq = htonl(20);
7934 p->tcph->th_ack = htonl(13);
7935 p->tcph->th_flags = TH_ACK|TH_PUSH;
7936 p->flowflags = FLOW_PKT_TOCLIENT;
7937
7938 StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/
7939 p->payload = payload;
7940 p->payload_len = 3;
7941
7942 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7943 goto end;
7944
7945 p->tcph->th_seq = htonl(15);
7946 p->tcph->th_ack = htonl(23);
7947 p->tcph->th_flags = TH_ACK|TH_PUSH;
7948 p->flowflags = FLOW_PKT_TOSERVER;
7949
7950 StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
7951 p->payload = payload;
7952 p->payload_len = 3;
7953
7954 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7955 goto end;
7956
7957 p->tcph->th_seq = htonl(14);
7958 p->tcph->th_ack = htonl(23);
7959 p->tcph->th_flags = TH_ACK|TH_PUSH;
7960 p->flowflags = FLOW_PKT_TOSERVER;
7961
7962 StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
7963 p->payload = payload;
7964 p->payload_len = 3;
7965
7966 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7967 goto end;
7968
7969 addr.s_addr = inet_addr("192.168.1.20");
7970 p->tcph->th_seq = htonl(25);
7971 p->tcph->th_ack = htonl(13);
7972 p->tcph->th_flags = TH_ACK|TH_PUSH;
7973 p->flowflags = FLOW_PKT_TOCLIENT;
7974 p->dst.address.address_un_data32[0] = addr.s_addr;
7975
7976 StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
7977 p->payload = payload;
7978 p->payload_len = 3;
7979
7980 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7981 goto end;
7982
7983 p->tcph->th_seq = htonl(24);
7984 p->tcph->th_ack = htonl(13);
7985 p->tcph->th_flags = TH_ACK|TH_PUSH;
7986 p->flowflags = FLOW_PKT_TOCLIENT;
7987
7988 StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
7989 p->payload = payload;
7990 p->payload_len = 3;
7991
7992 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
7993 goto end;
7994
7995 if (stream_config.midstream != TRUE) {
7996 ret = 1;
7997 goto end;
7998 }
7999 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
8000 goto end;
8001
8002 if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 &&
8003 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) {
8004 printf("failed in next_seq match client.next_seq %"PRIu32""
8005 " server.next_seq %"PRIu32"\n",
8006 ((TcpSession *)(p->flow->protoctx))->client.next_seq,
8007 ((TcpSession *)(p->flow->protoctx))->server.next_seq);
8008 goto end;
8009 }
8010
8011 if (((TcpSession *)(p->flow->protoctx))->client.os_policy !=
8012 OS_POLICY_WINDOWS && ((TcpSession *)
8013 (p->flow->protoctx))->server.os_policy != OS_POLICY_LINUX)
8014 {
8015 printf("failed in setting up OS policy, client.os_policy: %"PRIu8""
8016 " should be %"PRIu8" and server.os_policy: %"PRIu8""
8017 " should be %"PRIu8"\n", ((TcpSession *)
8018 (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_WINDOWS,
8019 ((TcpSession *)(p->flow->protoctx))->server.os_policy,
8020 (uint8_t)OS_POLICY_LINUX);
8021 goto end;
8022 }
8023 StreamTcpSessionPktFree(p);
8024
8025 ret = 1;
8026 end:
8027 ConfDeInit();
8028 ConfRestoreContextBackup();
8029 SCFree(p);
8030 FLOW_DESTROY(&f);
8031 StreamTcpUTDeinit(stt.ra_ctx);
8032 return ret;
8033 }
8034
8035 /**
8036 * \test Test the setting up a OS policy. Te OS policy values are defined in
8037 * the config string "dummy_conf_string1"
8038 *
8039 * \retval On success it returns 1 and on failure 0
8040 */
8041
StreamTcpTest16(void)8042 static int StreamTcpTest16 (void)
8043 {
8044 Packet *p = SCMalloc(SIZE_OF_PACKET);
8045 if (unlikely(p == NULL))
8046 return 0;
8047 Flow f;
8048 ThreadVars tv;
8049 StreamTcpThread stt;
8050 TCPHdr tcph;
8051 uint8_t payload[4];
8052 struct in_addr addr;
8053 IPV4Hdr ipv4h;
8054 char os_policy_name[10] = "windows";
8055 const char *ip_addr;
8056 PacketQueueNoLock pq;
8057 memset(&pq,0,sizeof(PacketQueueNoLock));
8058
8059 memset(p, 0, SIZE_OF_PACKET);
8060 memset (&f, 0, sizeof(Flow));
8061 memset(&tv, 0, sizeof (ThreadVars));
8062 memset(&stt, 0, sizeof (StreamTcpThread));
8063 memset(&tcph, 0, sizeof (TCPHdr));
8064 memset(&addr, 0, sizeof(addr));
8065 memset(&ipv4h, 0, sizeof(ipv4h));
8066 FLOW_INITIALIZE(&f);
8067 p->flow = &f;
8068 int ret = 0;
8069
8070 StreamTcpUTInit(&stt.ra_ctx);
8071
8072 /* Load the config string in to parser */
8073 ConfCreateContextBackup();
8074 ConfInit();
8075 ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
8076
8077 /* Get the IP address as string and add it to Host info tree for lookups */
8078 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8079 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8080 strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name));
8081 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8082 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8083 addr.s_addr = inet_addr("192.168.0.1");
8084 tcph.th_win = htons(5480);
8085 tcph.th_seq = htonl(10);
8086 tcph.th_ack = htonl(20);
8087 tcph.th_flags = TH_ACK|TH_PUSH;
8088 p->tcph = &tcph;
8089 p->dst.family = AF_INET;
8090 p->dst.address.address_un_data32[0] = addr.s_addr;
8091 p->ip4h = &ipv4h;
8092
8093 StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/
8094 p->payload = payload;
8095 p->payload_len = 3;
8096
8097 FLOWLOCK_WRLOCK(&f);
8098 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8099 goto end;
8100
8101 p->tcph->th_seq = htonl(20);
8102 p->tcph->th_ack = htonl(13);
8103 p->tcph->th_flags = TH_ACK|TH_PUSH;
8104 p->flowflags = FLOW_PKT_TOCLIENT;
8105
8106 StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/
8107 p->payload = payload;
8108 p->payload_len = 3;
8109
8110 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8111 goto end;
8112
8113 p->tcph->th_seq = htonl(15);
8114 p->tcph->th_ack = htonl(23);
8115 p->tcph->th_flags = TH_ACK|TH_PUSH;
8116 p->flowflags = FLOW_PKT_TOSERVER;
8117
8118 StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
8119 p->payload = payload;
8120 p->payload_len = 3;
8121
8122 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8123 goto end;
8124
8125 p->tcph->th_seq = htonl(14);
8126 p->tcph->th_ack = htonl(23);
8127 p->tcph->th_flags = TH_ACK|TH_PUSH;
8128 p->flowflags = FLOW_PKT_TOSERVER;
8129
8130 StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
8131 p->payload = payload;
8132 p->payload_len = 3;
8133
8134 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8135 goto end;
8136
8137 addr.s_addr = inet_addr("192.168.1.1");
8138 p->tcph->th_seq = htonl(25);
8139 p->tcph->th_ack = htonl(13);
8140 p->tcph->th_flags = TH_ACK|TH_PUSH;
8141 p->flowflags = FLOW_PKT_TOCLIENT;
8142 p->dst.address.address_un_data32[0] = addr.s_addr;
8143
8144 StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
8145 p->payload = payload;
8146 p->payload_len = 3;
8147
8148 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8149 goto end;
8150
8151 p->tcph->th_seq = htonl(24);
8152 p->tcph->th_ack = htonl(13);
8153 p->tcph->th_flags = TH_ACK|TH_PUSH;
8154 p->flowflags = FLOW_PKT_TOCLIENT;
8155
8156 StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
8157 p->payload = payload;
8158 p->payload_len = 3;
8159
8160 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8161 goto end;
8162
8163 if (stream_config.midstream != TRUE) {
8164 ret = 1;
8165 goto end;
8166 }
8167 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
8168 goto end;
8169
8170 if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 &&
8171 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) {
8172 printf("failed in next_seq match client.next_seq %"PRIu32""
8173 " server.next_seq %"PRIu32"\n",
8174 ((TcpSession *)(p->flow->protoctx))->client.next_seq,
8175 ((TcpSession *)(p->flow->protoctx))->server.next_seq);
8176 goto end;
8177 }
8178
8179 if (((TcpSession *)(p->flow->protoctx))->client.os_policy !=
8180 OS_POLICY_LINUX && ((TcpSession *)
8181 (p->flow->protoctx))->server.os_policy != OS_POLICY_WINDOWS)
8182 {
8183 printf("failed in setting up OS policy, client.os_policy: %"PRIu8""
8184 " should be %"PRIu8" and server.os_policy: %"PRIu8""
8185 " should be %"PRIu8"\n", ((TcpSession *)
8186 (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_LINUX,
8187 ((TcpSession *)(p->flow->protoctx))->server.os_policy,
8188 (uint8_t)OS_POLICY_WINDOWS);
8189 goto end;
8190 }
8191 StreamTcpSessionPktFree(p);
8192
8193 ret = 1;
8194 end:
8195 ConfDeInit();
8196 ConfRestoreContextBackup();
8197 FLOWLOCK_UNLOCK(&f);
8198 SCFree(p);
8199 FLOW_DESTROY(&f);
8200 StreamTcpUTDeinit(stt.ra_ctx);
8201 return ret;
8202 }
8203
8204 /**
8205 * \test Test the setting up a OS policy. Te OS policy values are defined in
8206 * the config string "dummy_conf_string1". To check the setting of
8207 * Default os policy
8208 *
8209 * \retval On success it returns 1 and on failure 0
8210 */
8211
StreamTcpTest17(void)8212 static int StreamTcpTest17 (void)
8213 {
8214 Packet *p = SCMalloc(SIZE_OF_PACKET);
8215 if (unlikely(p == NULL))
8216 return 0;
8217 Flow f;
8218 ThreadVars tv;
8219 StreamTcpThread stt;
8220 TCPHdr tcph;
8221 uint8_t payload[4];
8222 struct in_addr addr;
8223 IPV4Hdr ipv4h;
8224 char os_policy_name[10] = "windows";
8225 const char *ip_addr;
8226 PacketQueueNoLock pq;
8227 memset(&pq,0,sizeof(PacketQueueNoLock));
8228
8229 memset(p, 0, SIZE_OF_PACKET);
8230 memset (&f, 0, sizeof(Flow));
8231 memset(&tv, 0, sizeof (ThreadVars));
8232 memset(&stt, 0, sizeof (StreamTcpThread));
8233 memset(&tcph, 0, sizeof (TCPHdr));
8234 memset(&addr, 0, sizeof(addr));
8235 memset(&ipv4h, 0, sizeof(ipv4h));
8236 FLOW_INITIALIZE(&f);
8237 p->flow = &f;
8238 int ret = 0;
8239
8240 StreamTcpUTInit(&stt.ra_ctx);
8241
8242 /* Load the config string in to parser */
8243 ConfCreateContextBackup();
8244 ConfInit();
8245 ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
8246
8247 /* Get the IP address as string and add it to Host info tree for lookups */
8248 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8249 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8250 strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name));
8251 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8252 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8253 addr.s_addr = inet_addr("192.168.0.1");
8254 tcph.th_win = htons(5480);
8255 tcph.th_seq = htonl(10);
8256 tcph.th_ack = htonl(20);
8257 tcph.th_flags = TH_ACK|TH_PUSH;
8258 p->tcph = &tcph;
8259 p->dst.family = AF_INET;
8260 p->dst.address.address_un_data32[0] = addr.s_addr;
8261 p->ip4h = &ipv4h;
8262
8263 StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/
8264 p->payload = payload;
8265 p->payload_len = 3;
8266
8267 FLOWLOCK_WRLOCK(&f);
8268 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8269 goto end;
8270
8271 p->tcph->th_seq = htonl(20);
8272 p->tcph->th_ack = htonl(13);
8273 p->tcph->th_flags = TH_ACK|TH_PUSH;
8274 p->flowflags = FLOW_PKT_TOCLIENT;
8275
8276 StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/
8277 p->payload = payload;
8278 p->payload_len = 3;
8279
8280 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8281 goto end;
8282
8283 p->tcph->th_seq = htonl(15);
8284 p->tcph->th_ack = htonl(23);
8285 p->tcph->th_flags = TH_ACK|TH_PUSH;
8286 p->flowflags = FLOW_PKT_TOSERVER;
8287
8288 StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
8289 p->payload = payload;
8290 p->payload_len = 3;
8291
8292 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8293 goto end;
8294
8295 p->tcph->th_seq = htonl(14);
8296 p->tcph->th_ack = htonl(23);
8297 p->tcph->th_flags = TH_ACK|TH_PUSH;
8298 p->flowflags = FLOW_PKT_TOSERVER;
8299
8300 StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
8301 p->payload = payload;
8302 p->payload_len = 3;
8303
8304 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8305 goto end;
8306
8307 addr.s_addr = inet_addr("10.1.1.1");
8308 p->tcph->th_seq = htonl(25);
8309 p->tcph->th_ack = htonl(13);
8310 p->tcph->th_flags = TH_ACK|TH_PUSH;
8311 p->flowflags = FLOW_PKT_TOCLIENT;
8312 p->dst.address.address_un_data32[0] = addr.s_addr;
8313
8314 StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
8315 p->payload = payload;
8316 p->payload_len = 3;
8317
8318 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8319 goto end;
8320
8321 p->tcph->th_seq = htonl(24);
8322 p->tcph->th_ack = htonl(13);
8323 p->tcph->th_flags = TH_ACK|TH_PUSH;
8324 p->flowflags = FLOW_PKT_TOCLIENT;
8325
8326 StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
8327 p->payload = payload;
8328 p->payload_len = 3;
8329
8330 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8331 goto end;
8332
8333 if (stream_config.midstream != TRUE) {
8334 ret = 1;
8335 goto end;
8336 }
8337 if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
8338 goto end;
8339
8340 if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 &&
8341 ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) {
8342 printf("failed in next_seq match client.next_seq %"PRIu32""
8343 " server.next_seq %"PRIu32"\n",
8344 ((TcpSession *)(p->flow->protoctx))->client.next_seq,
8345 ((TcpSession *)(p->flow->protoctx))->server.next_seq);
8346 goto end;
8347 }
8348
8349 if (((TcpSession *)(p->flow->protoctx))->client.os_policy !=
8350 OS_POLICY_LINUX && ((TcpSession *)
8351 (p->flow->protoctx))->server.os_policy != OS_POLICY_DEFAULT)
8352 {
8353 printf("failed in setting up OS policy, client.os_policy: %"PRIu8""
8354 " should be %"PRIu8" and server.os_policy: %"PRIu8""
8355 " should be %"PRIu8"\n", ((TcpSession *)
8356 (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_LINUX,
8357 ((TcpSession *)(p->flow->protoctx))->server.os_policy,
8358 (uint8_t)OS_POLICY_DEFAULT);
8359 goto end;
8360 }
8361 StreamTcpSessionPktFree(p);
8362
8363 ret = 1;
8364 end:
8365 ConfDeInit();
8366 ConfRestoreContextBackup();
8367 FLOWLOCK_UNLOCK(&f);
8368 SCFree(p);
8369 FLOW_DESTROY(&f);
8370 StreamTcpUTDeinit(stt.ra_ctx);
8371 return ret;
8372 }
8373
8374 /** \test Test the various OS policies based on different IP addresses from
8375 confuguration defined in 'dummy_conf_string1' */
StreamTcpTest18(void)8376 static int StreamTcpTest18 (void)
8377 {
8378 StreamTcpThread stt;
8379 struct in_addr addr;
8380 char os_policy_name[10] = "windows";
8381 const char *ip_addr;
8382 TcpStream stream;
8383 Packet *p = SCMalloc(SIZE_OF_PACKET);
8384 if (unlikely(p == NULL))
8385 return 0;
8386 IPV4Hdr ipv4h;
8387 int ret = 0;
8388
8389 memset(&addr, 0, sizeof(addr));
8390 memset(&stream, 0, sizeof(stream));
8391 memset(p, 0, SIZE_OF_PACKET);
8392 memset(&ipv4h, 0, sizeof(ipv4h));
8393
8394 StreamTcpUTInit(&stt.ra_ctx);
8395 SCHInfoCleanResources();
8396
8397 /* Load the config string in to parser */
8398 ConfCreateContextBackup();
8399 ConfInit();
8400 ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
8401
8402 /* Get the IP address as string and add it to Host info tree for lookups */
8403 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8404 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8405
8406 p->dst.family = AF_INET;
8407 p->ip4h = &ipv4h;
8408 addr.s_addr = inet_addr("192.168.1.1");
8409 p->dst.address.address_un_data32[0] = addr.s_addr;
8410 StreamTcpSetOSPolicy(&stream, p);
8411
8412 if (stream.os_policy != OS_POLICY_WINDOWS)
8413 goto end;
8414
8415 ret = 1;
8416 end:
8417 ConfDeInit();
8418 ConfRestoreContextBackup();
8419 SCFree(p);
8420 StreamTcpUTDeinit(stt.ra_ctx);
8421 return ret;
8422 }
8423 /** \test Test the various OS policies based on different IP addresses from
8424 confuguration defined in 'dummy_conf_string1' */
StreamTcpTest19(void)8425 static int StreamTcpTest19 (void)
8426 {
8427 StreamTcpThread stt;
8428 struct in_addr addr;
8429 char os_policy_name[10] = "windows";
8430 const char *ip_addr;
8431 TcpStream stream;
8432 Packet *p = SCMalloc(SIZE_OF_PACKET);
8433 if (unlikely(p == NULL))
8434 return 0;
8435 IPV4Hdr ipv4h;
8436 int ret = 0;
8437
8438 memset(&addr, 0, sizeof(addr));
8439 memset(&stream, 0, sizeof(stream));
8440 memset(p, 0, SIZE_OF_PACKET);
8441 memset(&ipv4h, 0, sizeof(ipv4h));
8442
8443 StreamTcpUTInit(&stt.ra_ctx);
8444 SCHInfoCleanResources();
8445
8446 /* Load the config string in to parser */
8447 ConfCreateContextBackup();
8448 ConfInit();
8449 ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
8450
8451 /* Get the IP address as string and add it to Host info tree for lookups */
8452 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8453 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8454
8455 p->dst.family = AF_INET;
8456 p->ip4h = &ipv4h;
8457 addr.s_addr = inet_addr("192.168.0.30");
8458 p->dst.address.address_un_data32[0] = addr.s_addr;
8459 StreamTcpSetOSPolicy(&stream, p);
8460
8461 if (stream.os_policy != OS_POLICY_WINDOWS) {
8462 printf("expected os_policy: %"PRIu8" but received %"PRIu8": ",
8463 (uint8_t)OS_POLICY_WINDOWS, stream.os_policy);
8464 goto end;
8465 }
8466
8467 ret = 1;
8468 end:
8469 ConfDeInit();
8470 ConfRestoreContextBackup();
8471 SCFree(p);
8472 StreamTcpUTDeinit(stt.ra_ctx);
8473 return ret;
8474 }
8475 /** \test Test the various OS policies based on different IP addresses from
8476 confuguration defined in 'dummy_conf_string1' */
StreamTcpTest20(void)8477 static int StreamTcpTest20 (void)
8478 {
8479 StreamTcpThread stt;
8480 struct in_addr addr;
8481 char os_policy_name[10] = "linux";
8482 const char *ip_addr;
8483 TcpStream stream;
8484 Packet *p = SCMalloc(SIZE_OF_PACKET);
8485 if (unlikely(p == NULL))
8486 return 0;
8487 IPV4Hdr ipv4h;
8488 int ret = 0;
8489
8490 memset(&addr, 0, sizeof(addr));
8491 memset(&stream, 0, sizeof(stream));
8492 memset(p, 0, SIZE_OF_PACKET);
8493 memset(&ipv4h, 0, sizeof(ipv4h));
8494
8495 StreamTcpUTInit(&stt.ra_ctx);
8496 SCHInfoCleanResources();
8497
8498 /* Load the config string in to parser */
8499 ConfCreateContextBackup();
8500 ConfInit();
8501 ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
8502
8503 /* Get the IP address as string and add it to Host info tree for lookups */
8504 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8505 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8506
8507 p->dst.family = AF_INET;
8508 p->ip4h = &ipv4h;
8509 addr.s_addr = inet_addr("192.168.0.1");
8510 p->dst.address.address_un_data32[0] = addr.s_addr;
8511 StreamTcpSetOSPolicy(&stream, p);
8512
8513 if (stream.os_policy != OS_POLICY_LINUX) {
8514 printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n",
8515 (uint8_t)OS_POLICY_LINUX, stream.os_policy);
8516 goto end;
8517 }
8518
8519 ret = 1;
8520 end:
8521 ConfDeInit();
8522 ConfRestoreContextBackup();
8523 SCFree(p);
8524 StreamTcpUTDeinit(stt.ra_ctx);
8525 return ret;
8526 }
8527 /** \test Test the various OS policies based on different IP addresses from
8528 confuguration defined in 'dummy_conf_string1' */
StreamTcpTest21(void)8529 static int StreamTcpTest21 (void)
8530 {
8531 StreamTcpThread stt;
8532 struct in_addr addr;
8533 char os_policy_name[10] = "linux";
8534 const char *ip_addr;
8535 TcpStream stream;
8536 Packet *p = SCMalloc(SIZE_OF_PACKET);
8537 if (unlikely(p == NULL))
8538 return 0;
8539 IPV4Hdr ipv4h;
8540 int ret = 0;
8541
8542 memset(&addr, 0, sizeof(addr));
8543 memset(&stream, 0, sizeof(stream));
8544 memset(p, 0, SIZE_OF_PACKET);
8545 memset(&ipv4h, 0, sizeof(ipv4h));
8546
8547 StreamTcpUTInit(&stt.ra_ctx);
8548 SCHInfoCleanResources();
8549
8550 /* Load the config string in to parser */
8551 ConfCreateContextBackup();
8552 ConfInit();
8553 ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
8554
8555 /* Get the IP address as string and add it to Host info tree for lookups */
8556 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8557 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8558
8559 p->dst.family = AF_INET;
8560 p->ip4h = &ipv4h;
8561 addr.s_addr = inet_addr("192.168.1.30");
8562 p->dst.address.address_un_data32[0] = addr.s_addr;
8563 StreamTcpSetOSPolicy(&stream, p);
8564
8565 if (stream.os_policy != OS_POLICY_LINUX) {
8566 printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n",
8567 (uint8_t)OS_POLICY_LINUX, stream.os_policy);
8568 goto end;
8569 }
8570
8571 ret = 1;
8572 end:
8573 ConfDeInit();
8574 ConfRestoreContextBackup();
8575 SCFree(p);
8576 StreamTcpUTDeinit(stt.ra_ctx);
8577 return ret;
8578 }
8579 /** \test Test the various OS policies based on different IP addresses from
8580 confuguration defined in 'dummy_conf_string1' */
StreamTcpTest22(void)8581 static int StreamTcpTest22 (void)
8582 {
8583 StreamTcpThread stt;
8584 struct in_addr addr;
8585 char os_policy_name[10] = "windows";
8586 const char *ip_addr;
8587 TcpStream stream;
8588 Packet *p = SCMalloc(SIZE_OF_PACKET);
8589 if (unlikely(p == NULL))
8590 return 0;
8591 IPV4Hdr ipv4h;
8592 int ret = 0;
8593
8594 memset(&addr, 0, sizeof(addr));
8595 memset(&stream, 0, sizeof(stream));
8596 memset(p, 0, SIZE_OF_PACKET);
8597 memset(&ipv4h, 0, sizeof(ipv4h));
8598
8599 StreamTcpUTInit(&stt.ra_ctx);
8600 SCHInfoCleanResources();
8601
8602 /* Load the config string in to parser */
8603 ConfCreateContextBackup();
8604 ConfInit();
8605 ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
8606
8607 /* Get the IP address as string and add it to Host info tree for lookups */
8608 ip_addr = StreamTcpParseOSPolicy(os_policy_name);
8609 SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
8610
8611 p->dst.family = AF_INET;
8612 p->ip4h = &ipv4h;
8613 addr.s_addr = inet_addr("123.231.2.1");
8614 p->dst.address.address_un_data32[0] = addr.s_addr;
8615 StreamTcpSetOSPolicy(&stream, p);
8616
8617 if (stream.os_policy != OS_POLICY_DEFAULT) {
8618 printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n",
8619 (uint8_t)OS_POLICY_DEFAULT, stream.os_policy);
8620 goto end;
8621 }
8622
8623 ret = 1;
8624 end:
8625 ConfDeInit();
8626 ConfRestoreContextBackup();
8627 SCFree(p);
8628 StreamTcpUTDeinit(stt.ra_ctx);
8629 return ret;
8630 }
8631
8632 /** \test Test the stream mem leaks conditions. */
StreamTcpTest23(void)8633 static int StreamTcpTest23(void)
8634 {
8635 StreamTcpThread stt;
8636 TcpSession ssn;
8637 Flow f;
8638 TCPHdr tcph;
8639 uint8_t packet[1460] = "";
8640 ThreadVars tv;
8641 PacketQueueNoLock pq;
8642
8643 Packet *p = SCMalloc(SIZE_OF_PACKET);
8644 FAIL_IF(p == NULL);
8645
8646 memset(&pq,0,sizeof(PacketQueueNoLock));
8647 memset(p, 0, SIZE_OF_PACKET);
8648 memset(&f, 0, sizeof (Flow));
8649 memset(&tcph, 0, sizeof (TCPHdr));
8650 memset(&tv, 0, sizeof (ThreadVars));
8651
8652 StreamTcpUTInit(&stt.ra_ctx);
8653 StreamTcpUTSetupSession(&ssn);
8654 FLOW_INITIALIZE(&f);
8655 ssn.client.os_policy = OS_POLICY_BSD;
8656 f.protoctx = &ssn;
8657 p->src.family = AF_INET;
8658 p->dst.family = AF_INET;
8659 p->proto = IPPROTO_TCP;
8660 p->flow = &f;
8661 tcph.th_win = 5480;
8662 tcph.th_flags = TH_PUSH | TH_ACK;
8663 p->tcph = &tcph;
8664 p->flowflags = FLOW_PKT_TOSERVER;
8665 p->payload = packet;
8666 SET_ISN(&ssn.client, 3184324452UL);
8667
8668 p->tcph->th_seq = htonl(3184324453UL);
8669 p->tcph->th_ack = htonl(3373419609UL);
8670 p->payload_len = 2;
8671
8672 FAIL_IF(StreamTcpReassembleHandleSegment(&tv, stt.ra_ctx, &ssn, &ssn.client, p, &pq) == -1);
8673
8674 p->tcph->th_seq = htonl(3184324455UL);
8675 p->tcph->th_ack = htonl(3373419621UL);
8676 p->payload_len = 2;
8677
8678 FAIL_IF(StreamTcpReassembleHandleSegment(&tv, stt.ra_ctx, &ssn, &ssn.client, p, &pq) == -1);
8679
8680 p->tcph->th_seq = htonl(3184324453UL);
8681 p->tcph->th_ack = htonl(3373419621UL);
8682 p->payload_len = 6;
8683
8684 FAIL_IF(StreamTcpReassembleHandleSegment(&tv, stt.ra_ctx, &ssn, &ssn.client, p, &pq) == -1);
8685
8686 TcpSegment *seg = RB_MAX(TCPSEG, &ssn.client.seg_tree);
8687 FAIL_IF_NULL(seg);
8688 FAIL_IF(TCP_SEG_LEN(seg) != 2);
8689
8690 StreamTcpUTClearSession(&ssn);
8691 SCFree(p);
8692 FLOW_DESTROY(&f);
8693 StreamTcpUTDeinit(stt.ra_ctx);
8694 FAIL_IF(SC_ATOMIC_GET(st_memuse) > 0);
8695 PASS;
8696 }
8697
8698 /** \test Test the stream mem leaks conditions. */
StreamTcpTest24(void)8699 static int StreamTcpTest24(void)
8700 {
8701 StreamTcpThread stt;
8702 TcpSession ssn;
8703 Packet *p = SCMalloc(SIZE_OF_PACKET);
8704 FAIL_IF (p == NULL);
8705 Flow f;
8706 TCPHdr tcph;
8707 uint8_t packet[1460] = "";
8708 ThreadVars tv;
8709 memset(&tv, 0, sizeof (ThreadVars));
8710 PacketQueueNoLock pq;
8711 memset(&pq,0,sizeof(PacketQueueNoLock));
8712
8713 StreamTcpUTInit(&stt.ra_ctx);
8714 StreamTcpUTSetupSession(&ssn);
8715
8716 memset(p, 0, SIZE_OF_PACKET);
8717 memset(&f, 0, sizeof (Flow));
8718 memset(&tcph, 0, sizeof (TCPHdr));
8719 FLOW_INITIALIZE(&f);
8720 ssn.client.os_policy = OS_POLICY_BSD;
8721 f.protoctx = &ssn;
8722 p->src.family = AF_INET;
8723 p->dst.family = AF_INET;
8724 p->proto = IPPROTO_TCP;
8725 p->flow = &f;
8726 tcph.th_win = 5480;
8727 tcph.th_flags = TH_PUSH | TH_ACK;
8728 p->tcph = &tcph;
8729 p->flowflags = FLOW_PKT_TOSERVER;
8730 p->payload = packet;
8731 //ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
8732 SET_ISN(&ssn.client, 3184324453UL);
8733
8734 p->tcph->th_seq = htonl(3184324455UL);
8735 p->tcph->th_ack = htonl(3373419621UL);
8736 p->payload_len = 4;
8737
8738 FAIL_IF (StreamTcpReassembleHandleSegment(&tv, stt.ra_ctx, &ssn, &ssn.client, p, &pq) == -1);
8739
8740 p->tcph->th_seq = htonl(3184324459UL);
8741 p->tcph->th_ack = htonl(3373419633UL);
8742 p->payload_len = 2;
8743
8744 FAIL_IF(StreamTcpReassembleHandleSegment(&tv, stt.ra_ctx, &ssn, &ssn.client, p, &pq) == -1);
8745
8746 p->tcph->th_seq = htonl(3184324459UL);
8747 p->tcph->th_ack = htonl(3373419657UL);
8748 p->payload_len = 4;
8749
8750 FAIL_IF(StreamTcpReassembleHandleSegment(&tv, stt.ra_ctx, &ssn, &ssn.client, p, &pq) == -1);
8751
8752 TcpSegment *seg = RB_MAX(TCPSEG, &ssn.client.seg_tree);
8753 FAIL_IF_NULL(seg);
8754 FAIL_IF(TCP_SEG_LEN(seg) != 4);
8755
8756 StreamTcpUTClearSession(&ssn);
8757 SCFree(p);
8758 FLOW_DESTROY(&f);
8759 StreamTcpUTDeinit(stt.ra_ctx);
8760 FAIL_IF(SC_ATOMIC_GET(st_memuse) > 0);
8761 PASS;
8762 }
8763
8764 /**
8765 * \test Test the initialization of tcp streams with congestion flags
8766 *
8767 * \retval On success it returns 1 and on failure 0.
8768 */
StreamTcpTest25(void)8769 static int StreamTcpTest25(void)
8770 {
8771 Packet *p = SCMalloc(SIZE_OF_PACKET);
8772 if (unlikely(p == NULL))
8773 return 0;
8774 Flow f;
8775 ThreadVars tv;
8776 StreamTcpThread stt;
8777 uint8_t payload[4];
8778 TCPHdr tcph;
8779 int ret = 0;
8780 PacketQueueNoLock pq;
8781 memset(&pq,0,sizeof(PacketQueueNoLock));
8782
8783 memset(p, 0, SIZE_OF_PACKET);
8784 memset (&f, 0, sizeof(Flow));
8785 memset(&tv, 0, sizeof (ThreadVars));
8786 memset(&stt, 0, sizeof (StreamTcpThread));
8787 memset(&tcph, 0, sizeof (TCPHdr));
8788
8789 FLOW_INITIALIZE(&f);
8790 p->flow = &f;
8791 tcph.th_win = htons(5480);
8792 tcph.th_flags = TH_SYN | TH_CWR;
8793 p->tcph = &tcph;
8794 p->flowflags = FLOW_PKT_TOSERVER;
8795 StreamTcpUTInit(&stt.ra_ctx);
8796
8797 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8798 goto end;
8799
8800 p->tcph->th_ack = htonl(1);
8801 p->tcph->th_flags = TH_SYN | TH_ACK;
8802 p->flowflags = FLOW_PKT_TOCLIENT;
8803
8804 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8805 goto end;
8806
8807 p->tcph->th_ack = htonl(1);
8808 p->tcph->th_seq = htonl(1);
8809 p->tcph->th_flags = TH_ACK;
8810 p->flowflags = FLOW_PKT_TOSERVER;
8811
8812 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8813 goto end;
8814
8815 p->tcph->th_ack = htonl(1);
8816 p->tcph->th_seq = htonl(2);
8817 p->tcph->th_flags = TH_PUSH | TH_ACK;
8818 p->flowflags = FLOW_PKT_TOSERVER;
8819
8820 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
8821 p->payload = payload;
8822 p->payload_len = 3;
8823
8824 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8825 goto end;
8826
8827 p->flowflags = FLOW_PKT_TOCLIENT;
8828 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8829 goto end;
8830
8831 p->tcph->th_ack = htonl(1);
8832 p->tcph->th_seq = htonl(6);
8833 p->tcph->th_flags = TH_PUSH | TH_ACK;
8834 p->flowflags = FLOW_PKT_TOSERVER;
8835
8836 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
8837 p->payload = payload;
8838 p->payload_len = 3;
8839
8840 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8841 goto end;
8842
8843 p->flowflags = FLOW_PKT_TOCLIENT;
8844 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8845 goto end;
8846
8847 StreamTcpSessionClear(p->flow->protoctx);
8848
8849 ret = 1;
8850 end:
8851 SCFree(p);
8852 FLOW_DESTROY(&f);
8853 StreamTcpUTDeinit(stt.ra_ctx);
8854 return ret;
8855 }
8856
8857 /**
8858 * \test Test the initialization of tcp streams with congestion flags
8859 *
8860 * \retval On success it returns 1 and on failure 0.
8861 */
StreamTcpTest26(void)8862 static int StreamTcpTest26(void)
8863 {
8864 Packet *p = SCMalloc(SIZE_OF_PACKET);
8865 if (unlikely(p == NULL))
8866 return 0;
8867 Flow f;
8868 ThreadVars tv;
8869 StreamTcpThread stt;
8870 uint8_t payload[4];
8871 TCPHdr tcph;
8872 int ret = 0;
8873 PacketQueueNoLock pq;
8874 memset(&pq,0,sizeof(PacketQueueNoLock));
8875
8876 memset(p, 0, SIZE_OF_PACKET);
8877 memset (&f, 0, sizeof(Flow));
8878 memset(&tv, 0, sizeof (ThreadVars));
8879 memset(&stt, 0, sizeof (StreamTcpThread));
8880 memset(&tcph, 0, sizeof (TCPHdr));
8881
8882 FLOW_INITIALIZE(&f);
8883 p->flow = &f;
8884 tcph.th_win = htons(5480);
8885 tcph.th_flags = TH_SYN | TH_ECN;
8886 p->tcph = &tcph;
8887 p->flowflags = FLOW_PKT_TOSERVER;
8888
8889 StreamTcpUTInit(&stt.ra_ctx);
8890
8891 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8892 goto end;
8893
8894 p->tcph->th_ack = htonl(1);
8895 p->tcph->th_flags = TH_SYN | TH_ACK;
8896 p->flowflags = FLOW_PKT_TOCLIENT;
8897
8898 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8899 goto end;
8900
8901 p->tcph->th_ack = htonl(1);
8902 p->tcph->th_seq = htonl(1);
8903 p->tcph->th_flags = TH_ACK;
8904 p->flowflags = FLOW_PKT_TOSERVER;
8905
8906 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8907 goto end;
8908
8909 p->tcph->th_ack = htonl(1);
8910 p->tcph->th_seq = htonl(2);
8911 p->tcph->th_flags = TH_PUSH | TH_ACK;
8912 p->flowflags = FLOW_PKT_TOSERVER;
8913
8914 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
8915 p->payload = payload;
8916 p->payload_len = 3;
8917
8918 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8919 goto end;
8920
8921 p->flowflags = FLOW_PKT_TOCLIENT;
8922 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8923 goto end;
8924
8925 p->tcph->th_ack = htonl(1);
8926 p->tcph->th_seq = htonl(6);
8927 p->tcph->th_flags = TH_PUSH | TH_ACK;
8928 p->flowflags = FLOW_PKT_TOSERVER;
8929
8930 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
8931 p->payload = payload;
8932 p->payload_len = 3;
8933
8934 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8935 goto end;
8936
8937 p->flowflags = FLOW_PKT_TOCLIENT;
8938 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8939 goto end;
8940
8941 StreamTcpSessionClear(p->flow->protoctx);
8942
8943 ret = 1;
8944 end:
8945 SCFree(p);
8946 FLOW_DESTROY(&f);
8947 StreamTcpUTDeinit(stt.ra_ctx);
8948 return ret;
8949 }
8950
8951 /**
8952 * \test Test the initialization of tcp streams with congestion flags
8953 *
8954 * \retval On success it returns 1 and on failure 0.
8955 */
StreamTcpTest27(void)8956 static int StreamTcpTest27(void)
8957 {
8958 Packet *p = SCMalloc(SIZE_OF_PACKET);
8959 if (unlikely(p == NULL))
8960 return 0;
8961 Flow f;
8962 ThreadVars tv;
8963 StreamTcpThread stt;
8964 uint8_t payload[4];
8965 TCPHdr tcph;
8966 int ret = 0;
8967 PacketQueueNoLock pq;
8968 memset(&pq,0,sizeof(PacketQueueNoLock));
8969
8970 memset(p, 0, SIZE_OF_PACKET);
8971 memset (&f, 0, sizeof(Flow));
8972 memset(&tv, 0, sizeof (ThreadVars));
8973 memset(&stt, 0, sizeof (StreamTcpThread));
8974 memset(&tcph, 0, sizeof (TCPHdr));
8975
8976 FLOW_INITIALIZE(&f);
8977 p->flow = &f;
8978 tcph.th_win = htons(5480);
8979 tcph.th_flags = TH_SYN | TH_CWR | TH_ECN;
8980 p->tcph = &tcph;
8981 p->flowflags = FLOW_PKT_TOSERVER;
8982
8983 StreamTcpUTInit(&stt.ra_ctx);
8984
8985 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
8986 goto end;
8987
8988 p->tcph->th_ack = htonl(1);
8989 p->tcph->th_flags = TH_SYN | TH_ACK;
8990 p->flowflags = FLOW_PKT_TOCLIENT;
8991
8992 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
8993 goto end;
8994
8995 p->tcph->th_ack = htonl(1);
8996 p->tcph->th_seq = htonl(1);
8997 p->tcph->th_flags = TH_ACK;
8998 p->flowflags = FLOW_PKT_TOSERVER;
8999
9000 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
9001 goto end;
9002
9003 p->tcph->th_ack = htonl(1);
9004 p->tcph->th_seq = htonl(2);
9005 p->tcph->th_flags = TH_PUSH | TH_ACK;
9006 p->flowflags = FLOW_PKT_TOSERVER;
9007
9008 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
9009 p->payload = payload;
9010 p->payload_len = 3;
9011
9012 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
9013 goto end;
9014
9015 p->flowflags = FLOW_PKT_TOCLIENT;
9016 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
9017 goto end;
9018
9019 p->tcph->th_ack = htonl(1);
9020 p->tcph->th_seq = htonl(6);
9021 p->tcph->th_flags = TH_PUSH | TH_ACK;
9022 p->flowflags = FLOW_PKT_TOSERVER;
9023
9024 StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
9025 p->payload = payload;
9026 p->payload_len = 3;
9027
9028 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
9029 goto end;
9030
9031 p->flowflags = FLOW_PKT_TOCLIENT;
9032 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
9033 goto end;
9034
9035 StreamTcpSessionClear(p->flow->protoctx);
9036
9037 ret = 1;
9038 end:
9039 SCFree(p);
9040 FLOW_DESTROY(&f);
9041 StreamTcpUTDeinit(stt.ra_ctx);
9042 return ret;
9043 }
9044
9045 /** \test Test the memcap incrementing/decrementing and memcap check */
StreamTcpTest28(void)9046 static int StreamTcpTest28(void)
9047 {
9048 StreamTcpThread stt;
9049 StreamTcpUTInit(&stt.ra_ctx);
9050
9051 uint32_t memuse = SC_ATOMIC_GET(st_memuse);
9052
9053 StreamTcpIncrMemuse(500);
9054 FAIL_IF(SC_ATOMIC_GET(st_memuse) != (memuse+500));
9055
9056 StreamTcpDecrMemuse(500);
9057 FAIL_IF(SC_ATOMIC_GET(st_memuse) != memuse);
9058
9059 FAIL_IF(StreamTcpCheckMemcap(500) != 1);
9060
9061 FAIL_IF(StreamTcpCheckMemcap((memuse + SC_ATOMIC_GET(stream_config.memcap))) != 0);
9062
9063 StreamTcpUTDeinit(stt.ra_ctx);
9064
9065 FAIL_IF(SC_ATOMIC_GET(st_memuse) != 0);
9066 PASS;
9067 }
9068
9069 #if 0
9070 /**
9071 * \test Test the resetting of the sesison with bad checksum packet and later
9072 * send the malicious contents on the session. Engine should drop the
9073 * packet with the bad checksum.
9074 *
9075 * \retval On success it returns 1 and on failure 0.
9076 */
9077 static int StreamTcpTest29(void)
9078 {
9079 Packet p;
9080 Flow f;
9081 ThreadVars tv;
9082 StreamTcpThread stt;
9083 TCPHdr tcph;
9084 TcpSession ssn;
9085 IPV4Hdr ipv4h;
9086 struct in_addr addr;
9087 struct in_addr addr1;
9088 TCPCache tcpc;
9089 TCPVars tcpvars;
9090 TcpStream server;
9091 TcpStream client;
9092
9093 memset (&p, 0, SIZE_OF_PACKET);
9094 memset (&f, 0, sizeof(Flow));
9095 memset(&tv, 0, sizeof (ThreadVars));
9096 memset(&stt, 0, sizeof (StreamTcpThread));
9097 memset(&tcph, 0, sizeof (TCPHdr));
9098 memset (&ipv4h, 0, sizeof(IPV4Hdr));
9099 memset (&addr, 0, sizeof(addr));
9100 memset (&addr1, 0, sizeof(addr1));
9101 memset (&tcpc, 0, sizeof(tcpc));
9102 memset (&tcpvars, 0, sizeof(tcpvars));
9103 memset(&ssn, 0, sizeof (TcpSession));
9104 memset(&server, 0, sizeof (TcpStream));
9105 memset(&client, 0, sizeof (TcpStream));
9106 uint8_t packet[1460] = "";
9107 int result = 1;
9108
9109 FLOW_INITIALIZE(&f);
9110 StreamTcpInitConfig(TRUE);
9111
9112 /* prevent L7 from kicking in */
9113
9114 ssn.client.os_policy = OS_POLICY_BSD;
9115 p.src.family = AF_INET;
9116 p.dst.family = AF_INET;
9117 p.proto = IPPROTO_TCP;
9118 p.flow = &f;
9119 tcph.th_win = 5480;
9120 p.tcph = &tcph;
9121 p.payload = packet;
9122 p.ip4h = &ipv4h;
9123 p.tcpc = tcpc;
9124 p.tcpc.level4_comp_csum = -1;
9125 tcpvars.hlen = 20;
9126 p.tcpvars = tcpvars;
9127 ssn.state = TCP_ESTABLISHED;
9128 addr.s_addr = inet_addr("10.1.3.53");
9129 p.dst.address.address_un_data32[0] = addr.s_addr;
9130 addr1.s_addr = inet_addr("10.1.3.7");
9131 p.src.address.address_un_data32[0] = addr1.s_addr;
9132 f.protoctx = &ssn;
9133 stt.ra_ctx = ra_ctx;
9134 ssn.server = server;
9135 ssn.client = client;
9136 ssn.client.isn = 10;
9137 ssn.client.window = 5184;
9138 ssn.client.last_ack = 10;
9139 ssn.client.ra_base_seq = 10;
9140 ssn.client.next_win = 5184;
9141 ssn.server.isn = 119197101;
9142 ssn.server.window = 5184;
9143 ssn.server.next_win = 5184;
9144 ssn.server.last_ack = 119197101;
9145 ssn.server.ra_base_seq = 119197101;
9146
9147 tcph.th_flags = TH_PUSH | TH_ACK;
9148 p.flowflags = FLOW_PKT_TOSERVER;
9149 p.tcph->th_seq = htonl(11);
9150 p.tcph->th_ack = htonl(119197102);
9151 p.payload_len = 4;
9152 p.ip4h->ip_src = addr1;
9153 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
9154 (uint16_t *)p.tcph,
9155 (p.payload_len +
9156 p.tcpvars.hlen) );
9157
9158 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9159 printf("failed in segment reassmebling\n");
9160 result &= 0;
9161 goto end;
9162 }
9163
9164 tcph.th_flags = TH_ACK;
9165 p.flowflags = FLOW_PKT_TOCLIENT;
9166 p.tcph->th_seq = htonl(119197102);
9167 p.tcph->th_ack = htonl(15);
9168 p.payload_len = 0;
9169 p.ip4h->ip_src = addr;
9170 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
9171 (uint16_t *)p.tcph,
9172 (p.payload_len +
9173 p.tcpvars.hlen) );
9174
9175 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9176 printf("failed in segment reassmebling\n");
9177 result &= 0;
9178 goto end;
9179 }
9180
9181 tcph.th_flags = TH_RST | TH_ACK;
9182 p.flowflags = FLOW_PKT_TOSERVER;
9183 p.tcph->th_seq = htonl(15);
9184 p.tcph->th_ack = htonl(119197102);
9185 p.payload_len = 0;
9186 p.ip4h->ip_src = addr1;
9187 p.tcph->th_sum = 12345;
9188
9189 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9190 printf("failed in segment reassmebling\n");
9191 result &= 0;
9192 goto end;
9193 }
9194
9195 if (ssn.state != TCP_ESTABLISHED) {
9196 printf("the ssn.state should be TCP_ESTABLISHED(%"PRIu8"), not %"PRIu8""
9197 "\n", TCP_ESTABLISHED, ssn.state);
9198 result &= 0;
9199 goto end;
9200 }
9201
9202 end:
9203 StreamTcpReturnStreamSegments(&ssn.client);
9204 StreamTcpFreeConfig(TRUE);
9205 return result;
9206 }
9207
9208 /**
9209 * \test Test the overlapping of the packet with bad checksum packet and later
9210 * send the malicious contents on the session. Engine should drop the
9211 * packet with the bad checksum.
9212 *
9213 * \retval On success it returns 1 and on failure 0.
9214 */
9215 static int StreamTcpTest30(void)
9216 {
9217 Packet p;
9218 Flow f;
9219 ThreadVars tv;
9220 StreamTcpThread stt;
9221 TCPHdr tcph;
9222 TcpSession ssn;
9223 IPV4Hdr ipv4h;
9224 struct in_addr addr;
9225 struct in_addr addr1;
9226 TCPCache tcpc;
9227 TCPVars tcpvars;
9228 TcpStream server;
9229 TcpStream client;
9230
9231 memset (&p, 0, SIZE_OF_PACKET);
9232 memset (&f, 0, sizeof(Flow));
9233 memset(&tv, 0, sizeof (ThreadVars));
9234 memset(&stt, 0, sizeof (StreamTcpThread));
9235 memset(&tcph, 0, sizeof (TCPHdr));
9236 memset (&ipv4h, 0, sizeof(IPV4Hdr));
9237 memset (&addr, 0, sizeof(addr));
9238 memset (&addr1, 0, sizeof(addr1));
9239 memset (&tcpc, 0, sizeof(tcpc));
9240 memset (&tcpvars, 0, sizeof(tcpvars));
9241 memset(&ssn, 0, sizeof (TcpSession));
9242 memset(&server, 0, sizeof (TcpStream));
9243 memset(&client, 0, sizeof (TcpStream));
9244 uint8_t payload[9] = "AAAAAAAAA";
9245 uint8_t payload1[9] = "GET /EVIL";
9246 uint8_t expected_content[9] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x45, 0x56,
9247 0x49, 0x4c };
9248 int result = 1;
9249
9250 FLOW_INITIALIZE(&f);
9251 StreamTcpInitConfig(TRUE);
9252
9253 /* prevent L7 from kicking in */
9254
9255 ssn.client.os_policy = OS_POLICY_BSD;
9256 p.src.family = AF_INET;
9257 p.dst.family = AF_INET;
9258 p.proto = IPPROTO_TCP;
9259 p.flow = &f;
9260 tcph.th_win = 5480;
9261 p.tcph = &tcph;
9262 p.payload = payload;
9263 p.ip4h = &ipv4h;
9264 p.tcpc = tcpc;
9265 p.tcpc.level4_comp_csum = -1;
9266 p.tcpvars = tcpvars;
9267 ssn.state = TCP_ESTABLISHED;
9268 addr.s_addr = inet_addr("10.1.3.53");
9269 p.dst.address.address_un_data32[0] = addr.s_addr;
9270 addr1.s_addr = inet_addr("10.1.3.7");
9271 p.src.address.address_un_data32[0] = addr1.s_addr;
9272 f.protoctx = &ssn;
9273 stt.ra_ctx = ra_ctx;
9274 ssn.server = server;
9275 ssn.client = client;
9276 ssn.client.isn = 10;
9277 ssn.client.window = 5184;
9278 ssn.client.last_ack = 10;
9279 ssn.client.ra_base_seq = 10;
9280 ssn.client.next_win = 5184;
9281 ssn.server.isn = 1351079940;
9282 ssn.server.window = 5184;
9283 ssn.server.next_win = 1351088132;
9284 ssn.server.last_ack = 1351079940;
9285 ssn.server.ra_base_seq = 1351079940;
9286
9287 tcph.th_flags = TH_PUSH | TH_ACK;
9288 p.flowflags = FLOW_PKT_TOSERVER;
9289 p.tcph->th_seq = htonl(11);
9290 p.tcph->th_ack = htonl(1351079940);
9291 p.payload_len = 9;
9292 p.ip4h->ip_src = addr1;
9293 p.tcph->th_sum = 12345;
9294
9295 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9296 printf("failed in segment reassmebling\n");
9297 result &= 0;
9298 goto end;
9299 }
9300
9301 tcph.th_flags = TH_PUSH | TH_ACK;
9302 p.flowflags = FLOW_PKT_TOSERVER;
9303 p.tcph->th_seq = htonl(11);
9304 p.tcph->th_ack = htonl(1351079940);
9305 p.payload = payload1;
9306 p.payload_len = 9;
9307 p.ip4h->ip_src = addr1;
9308 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
9309 (uint16_t *)p.tcph,
9310 (p.payload_len +
9311 p.tcpvars.hlen) );
9312
9313 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9314 printf("failed in segment reassmebling\n");
9315 result &= 0;
9316 goto end;
9317 }
9318
9319 tcph.th_flags = TH_ACK;
9320 p.flowflags = FLOW_PKT_TOCLIENT;
9321 p.tcph->th_seq = htonl(1351079940);
9322 p.tcph->th_ack = htonl(20);
9323 p.payload_len = 0;
9324 p.ip4h->ip_src = addr;
9325 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
9326 (uint16_t *)p.tcph,
9327 (p.payload_len +
9328 p.tcpvars.hlen) );
9329
9330 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9331 printf("failed in segment reassmebling\n");
9332 result &= 0;
9333 goto end;
9334 }
9335
9336 if (StreamTcpCheckStreamContents(expected_content, 9, &ssn.client) != 1) {
9337 printf("the contents are not as expected(GET /EVIL), contents are: ");
9338 PrintRawDataFp(stdout, ssn.client.seg_list->payload, 9);
9339 result &= 0;
9340 goto end;
9341 }
9342
9343 end:
9344 StreamTcpReturnStreamSegments(&ssn.client);
9345 StreamTcpFreeConfig(TRUE);
9346 return result;
9347 }
9348
9349 /**
9350 * \test Test the multiple SYN packet handling with bad checksum and timestamp
9351 * value. Engine should drop the bad checksum packet and establish
9352 * TCP session correctly.
9353 *
9354 * \retval On success it returns 1 and on failure 0.
9355 */
9356 static int StreamTcpTest31(void)
9357 {
9358 Packet p;
9359 Flow f;
9360 ThreadVars tv;
9361 StreamTcpThread stt;
9362 TCPHdr tcph;
9363 TcpSession ssn;
9364 IPV4Hdr ipv4h;
9365 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
9366 struct in_addr addr;
9367 struct in_addr addr1;
9368 TCPCache tcpc;
9369 TCPVars tcpvars;
9370 TcpStream server;
9371 TcpStream client;
9372 TCPOpt tcpopt;
9373
9374 memset (&p, 0, SIZE_OF_PACKET);
9375 memset (&f, 0, sizeof(Flow));
9376 memset(&tv, 0, sizeof (ThreadVars));
9377 memset(&stt, 0, sizeof (StreamTcpThread));
9378 memset(&tcph, 0, sizeof (TCPHdr));
9379 memset (&ipv4h, 0, sizeof(IPV4Hdr));
9380 memset (&addr, 0, sizeof(addr));
9381 memset (&addr1, 0, sizeof(addr1));
9382 memset (&tcpc, 0, sizeof(tcpc));
9383 memset (&tcpvars, 0, sizeof(tcpvars));
9384 memset(&ssn, 0, sizeof (TcpSession));
9385 memset(&server, 0, sizeof (TcpStream));
9386 memset(&client, 0, sizeof (TcpStream));
9387 memset(&tcpopt, 0, sizeof (TCPOpt));
9388 int result = 1;
9389
9390 StreamTcpInitConfig(TRUE);
9391
9392 FLOW_INITIALIZE(&f);
9393 /* prevent L7 from kicking in */
9394
9395 ssn.client.os_policy = OS_POLICY_LINUX;
9396 p.src.family = AF_INET;
9397 p.dst.family = AF_INET;
9398 p.proto = IPPROTO_TCP;
9399 p.flow = &f;
9400 tcph.th_win = 5480;
9401 p.tcph = &tcph;
9402 p.ip4h = &ipv4h;
9403 p.tcpc = tcpc;
9404 p.tcpc.level4_comp_csum = -1;
9405 p.tcpvars = tcpvars;
9406 p.tcpvars.ts = &tcpopt;
9407 addr.s_addr = inet_addr("10.1.3.53");
9408 p.dst.address.address_un_data32[0] = addr.s_addr;
9409 addr1.s_addr = inet_addr("10.1.3.7");
9410 p.src.address.address_un_data32[0] = addr1.s_addr;
9411 f.protoctx = &ssn;
9412 stt.ra_ctx = ra_ctx;
9413 ssn.server = server;
9414 ssn.client = client;
9415 ssn.client.isn = 10;
9416 ssn.client.window = 5184;
9417 ssn.client.last_ack = 10;
9418 ssn.client.ra_base_seq = 10;
9419 ssn.client.next_win = 5184;
9420 ssn.server.isn = 1351079940;
9421 ssn.server.window = 5184;
9422 ssn.server.next_win = 1351088132;
9423 ssn.server.last_ack = 1351079940;
9424 ssn.server.ra_base_seq = 1351079940;
9425
9426 tcph.th_flags = TH_SYN;
9427 p.flowflags = FLOW_PKT_TOSERVER;
9428 p.tcph->th_seq = htonl(10);
9429 p.payload_len = 0;
9430 p.ip4h->ip_src = addr1;
9431 p.tcpc.ts1 = 100;
9432 p.tcph->th_sum = 12345;
9433
9434 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9435 printf("failed in segment reassmebling\n");
9436 result &= 0;
9437 goto end;
9438 }
9439
9440 tcph.th_flags = TH_SYN;
9441 p.flowflags = FLOW_PKT_TOSERVER;
9442 p.tcph->th_seq = htonl(10);
9443 p.payload_len = 0;
9444 p.ip4h->ip_src = addr1;
9445 p.tcpc.ts1 = 10;
9446 p.tcpc.level4_comp_csum = -1;
9447 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
9448 (uint16_t *)p.tcph,
9449 (p.payload_len +
9450 p.tcpvars.hlen) );
9451
9452 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9453 printf("failed in segment reassmebling\n");
9454 result &= 0;
9455 goto end;
9456 }
9457
9458 ssn.flags |= STREAMTCP_FLAG_TIMESTAMP;
9459 tcph.th_flags = TH_SYN | TH_ACK;
9460 p.flowflags = FLOW_PKT_TOCLIENT;
9461 p.tcph->th_seq = htonl(1351079940);
9462 p.tcph->th_ack = htonl(11);
9463 p.payload_len = 0;
9464 p.tcpc.ts1 = 10;
9465 p.ip4h->ip_src = addr;
9466 p.tcpc.level4_comp_csum = -1;
9467 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
9468 (uint16_t *)p.tcph,
9469 (p.payload_len +
9470 p.tcpvars.hlen) );
9471
9472 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9473 printf("failed in segment reassmebling\n");
9474 result &= 0;
9475 goto end;
9476 }
9477
9478 tcph.th_flags = TH_ACK;
9479 p.flowflags = FLOW_PKT_TOSERVER;
9480 p.tcph->th_seq = htonl(11);
9481 p.tcph->th_ack = htonl(1351079941);
9482 p.payload_len = 0;
9483 p.tcpc.ts1 = 10;
9484 p.ip4h->ip_src = addr1;
9485 p.tcpc.level4_comp_csum = -1;
9486 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
9487 (uint16_t *)p.tcph,
9488 (p.payload_len +
9489 p.tcpvars.hlen) );
9490
9491 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
9492 printf("failed in segment reassmebling\n");
9493 result &= 0;
9494 goto end;
9495 }
9496
9497 if (ssn.state != TCP_ESTABLISHED) {
9498 printf("the should have been changed to TCP_ESTABLISHED!!\n ");
9499 result &= 0;
9500 goto end;
9501 }
9502
9503 end:
9504 StreamTcpReturnStreamSegments(&ssn.client);
9505 StreamTcpFreeConfig(TRUE);
9506 return result;
9507 }
9508
9509 /**
9510 * \test Test the initialization of tcp streams with ECN & CWR flags
9511 *
9512 * \retval On success it returns 1 and on failure 0.
9513 */
9514 static int StreamTcpTest32(void)
9515 {
9516 Packet p;
9517 Flow f;
9518 ThreadVars tv;
9519 StreamTcpThread stt;
9520 uint8_t payload[4];
9521 TCPHdr tcph;
9522 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
9523 int ret = 0;
9524 PacketQueueNoLock pq;
9525 memset(&pq,0,sizeof(PacketQueueNoLock));
9526
9527 memset (&p, 0, SIZE_OF_PACKET);
9528 memset (&f, 0, sizeof(Flow));
9529 memset(&tv, 0, sizeof (ThreadVars));
9530 memset(&stt, 0, sizeof (StreamTcpThread));
9531 memset(&tcph, 0, sizeof (TCPHdr));
9532
9533 FLOW_INITIALIZE(&f);
9534 stt.ra_ctx = ra_ctx;
9535 p.flow = &f;
9536 tcph.th_win = htons(5480);
9537 tcph.th_flags = TH_SYN | TH_CWR | TH_ECN;
9538 p.tcph = &tcph;
9539 p.flowflags = FLOW_PKT_TOSERVER;
9540
9541 StreamTcpInitConfig(TRUE);
9542
9543 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9544 goto end;
9545
9546 p.tcph->th_ack = htonl(1);
9547 p.tcph->th_flags = TH_SYN | TH_ACK | TH_ECN;
9548 p.flowflags = FLOW_PKT_TOCLIENT;
9549
9550 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
9551 printf("failed in processing packet\n");
9552 goto end;
9553 }
9554
9555 p.tcph->th_ack = htonl(1);
9556 p.tcph->th_seq = htonl(1);
9557 p.tcph->th_flags = TH_ACK | TH_ECN | TH_CWR;
9558 p.flowflags = FLOW_PKT_TOSERVER;
9559
9560 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
9561 printf("failed in processing packet\n");
9562 goto end;
9563 }
9564
9565 p.tcph->th_ack = htonl(1);
9566 p.tcph->th_seq = htonl(2);
9567 p.tcph->th_flags = TH_PUSH | TH_ACK | TH_ECN | TH_CWR;
9568 p.flowflags = FLOW_PKT_TOSERVER;
9569
9570 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
9571 p.payload = payload;
9572 p.payload_len = 3;
9573
9574 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
9575 printf("failed in processing packet\n");
9576 goto end;
9577 }
9578
9579 p.flowflags = FLOW_PKT_TOCLIENT;
9580 p.tcph->th_flags = TH_ACK;
9581 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
9582 printf("failed in processing packet\n");
9583 goto end;
9584 }
9585
9586 if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) {
9587 printf("the TCP state should be TCP_ESTABLISEHD\n");
9588 goto end;
9589 }
9590 StreamTcpSessionClear(p.flow->protoctx);
9591
9592 ret = 1;
9593 end:
9594 StreamTcpFreeConfig(TRUE);
9595 return ret;
9596 }
9597
9598 /**
9599 * \test Test the allocation of TCP session for a given packet when the same
9600 * ports have been used to start the new session after resetting the
9601 * previous session.
9602 *
9603 * \retval On success it returns 1 and on failure 0.
9604 */
9605
9606 static int StreamTcpTest33 (void)
9607 {
9608 Packet p;
9609 Flow f;
9610 ThreadVars tv;
9611 StreamTcpThread stt;
9612 TCPHdr tcph;
9613 TcpReassemblyThreadCtx ra_ctx;
9614 PacketQueueNoLock pq;
9615 memset(&pq,0,sizeof(PacketQueueNoLock));
9616 memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
9617 memset (&p, 0, SIZE_OF_PACKET);
9618 memset (&f, 0, sizeof(Flow));
9619 memset(&tv, 0, sizeof (ThreadVars));
9620 memset(&stt, 0, sizeof (StreamTcpThread));
9621 memset(&tcph, 0, sizeof (TCPHdr));
9622
9623 FLOW_INITIALIZE(&f);
9624 p.flow = &f;
9625 tcph.th_win = htons(5480);
9626 tcph.th_flags = TH_SYN;
9627 p.tcph = &tcph;
9628 p.flowflags = FLOW_PKT_TOSERVER;
9629 int ret = 0;
9630 stt.ra_ctx = &ra_ctx;
9631
9632 StreamTcpInitConfig(TRUE);
9633
9634 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9635 goto end;
9636
9637 p.tcph->th_ack = htonl(1);
9638 p.tcph->th_flags = TH_SYN | TH_ACK;
9639 p.flowflags = FLOW_PKT_TOCLIENT;
9640
9641 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9642 goto end;
9643
9644 p.tcph->th_ack = htonl(1);
9645 p.tcph->th_seq = htonl(1);
9646 p.tcph->th_flags = TH_ACK;
9647 p.flowflags = FLOW_PKT_TOSERVER;
9648
9649 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9650 goto end;
9651
9652 p.tcph->th_ack = htonl(1);
9653 p.tcph->th_seq = htonl(1);
9654 p.tcph->th_flags = TH_RST | TH_ACK;
9655 p.flowflags = FLOW_PKT_TOSERVER;
9656
9657 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9658 goto end;
9659
9660 if (((TcpSession *)(p.flow->protoctx))->state != TCP_CLOSED) {
9661 printf("Tcp session should have been closed\n");
9662 goto end;
9663 }
9664
9665 p.tcph->th_seq = htonl(1);
9666 p.tcph->th_flags = TH_SYN;
9667 p.flowflags = FLOW_PKT_TOSERVER;
9668
9669 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9670 goto end;
9671
9672 p.tcph->th_seq = htonl(1);
9673 p.tcph->th_ack = htonl(2);
9674 p.tcph->th_flags = TH_SYN | TH_ACK;
9675 p.flowflags = FLOW_PKT_TOCLIENT;
9676
9677 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9678 goto end;
9679
9680 p.tcph->th_ack = htonl(2);
9681 p.tcph->th_seq = htonl(2);
9682 p.tcph->th_flags = TH_ACK;
9683 p.flowflags = FLOW_PKT_TOSERVER;
9684
9685 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9686 goto end;
9687
9688 if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
9689 printf("Tcp session should have been ESTABLISHED\n");
9690 goto end;
9691 }
9692
9693 ret = 1;
9694 end:
9695 StreamTcpSessionClear(p.flow->protoctx);
9696 StreamTcpFreeConfig(TRUE);
9697 return ret;
9698 }
9699
9700 /**
9701 * \test Test the allocation of TCP session for a given packet when the SYN
9702 * packet is sent with the PUSH flag set.
9703 *
9704 * \retval On success it returns 1 and on failure 0.
9705 */
9706
9707 static int StreamTcpTest34 (void)
9708 {
9709 Packet p;
9710 Flow f;
9711 ThreadVars tv;
9712 StreamTcpThread stt;
9713 TCPHdr tcph;
9714 TcpReassemblyThreadCtx ra_ctx;
9715 PacketQueueNoLock pq;
9716 memset(&pq,0,sizeof(PacketQueueNoLock));
9717 memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
9718 memset (&p, 0, SIZE_OF_PACKET);
9719 memset (&f, 0, sizeof(Flow));
9720 memset(&tv, 0, sizeof (ThreadVars));
9721 memset(&stt, 0, sizeof (StreamTcpThread));
9722 memset(&tcph, 0, sizeof (TCPHdr));
9723
9724 FLOW_INITIALIZE(&f);
9725 p.flow = &f;
9726 tcph.th_win = htons(5480);
9727 tcph.th_flags = TH_SYN|TH_PUSH;
9728 p.tcph = &tcph;
9729 p.flowflags = FLOW_PKT_TOSERVER;
9730 int ret = 0;
9731 stt.ra_ctx = &ra_ctx;
9732
9733 StreamTcpInitConfig(TRUE);
9734
9735 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9736 goto end;
9737
9738 p.tcph->th_ack = htonl(1);
9739 p.tcph->th_flags = TH_SYN | TH_ACK;
9740 p.flowflags = FLOW_PKT_TOCLIENT;
9741
9742 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9743 goto end;
9744
9745 p.tcph->th_ack = htonl(1);
9746 p.tcph->th_seq = htonl(1);
9747 p.tcph->th_flags = TH_ACK;
9748 p.flowflags = FLOW_PKT_TOSERVER;
9749
9750 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9751 goto end;
9752
9753 if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
9754 printf("Tcp session should have been establisehd\n");
9755 goto end;
9756 }
9757
9758 ret = 1;
9759 end:
9760 StreamTcpSessionClear(p.flow->protoctx);
9761 StreamTcpFreeConfig(TRUE);
9762 return ret;
9763 }
9764
9765 /**
9766 * \test Test the allocation of TCP session for a given packet when the SYN
9767 * packet is sent with the URG flag set.
9768 *
9769 * \retval On success it returns 1 and on failure 0.
9770 */
9771
9772 static int StreamTcpTest35 (void)
9773 {
9774 Packet p;
9775 Flow f;
9776 ThreadVars tv;
9777 StreamTcpThread stt;
9778 TCPHdr tcph;
9779 TcpReassemblyThreadCtx ra_ctx;
9780 PacketQueueNoLock pq;
9781 memset(&pq,0,sizeof(PacketQueueNoLock));
9782 memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
9783 memset (&p, 0, SIZE_OF_PACKET);
9784 memset (&f, 0, sizeof(Flow));
9785 memset(&tv, 0, sizeof (ThreadVars));
9786 memset(&stt, 0, sizeof (StreamTcpThread));
9787 memset(&tcph, 0, sizeof (TCPHdr));
9788
9789 FLOW_INITIALIZE(&f);
9790 p.flow = &f;
9791 tcph.th_win = htons(5480);
9792 tcph.th_flags = TH_SYN|TH_URG;
9793 p.tcph = &tcph;
9794 p.flowflags = FLOW_PKT_TOSERVER;
9795 int ret = 0;
9796 stt.ra_ctx = &ra_ctx;
9797
9798 StreamTcpInitConfig(TRUE);
9799
9800 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9801 goto end;
9802
9803 p.tcph->th_ack = htonl(1);
9804 p.tcph->th_flags = TH_SYN | TH_ACK;
9805 p.flowflags = FLOW_PKT_TOCLIENT;
9806
9807 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9808 goto end;
9809
9810 p.tcph->th_ack = htonl(1);
9811 p.tcph->th_seq = htonl(1);
9812 p.tcph->th_flags = TH_ACK;
9813 p.flowflags = FLOW_PKT_TOSERVER;
9814
9815 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
9816 goto end;
9817
9818 if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
9819 printf("Tcp session should have been establisehd\n");
9820 goto end;
9821 }
9822
9823 ret = 1;
9824 end:
9825 StreamTcpSessionClear(p.flow->protoctx);
9826 StreamTcpFreeConfig(TRUE);
9827 return ret;
9828 }
9829
9830 /**
9831 * \test Test the processing of PSH and URG flag in tcp session.
9832 *
9833 * \retval On success it returns 1 and on failure 0.
9834 */
9835 static int StreamTcpTest36(void)
9836 {
9837 Packet p;
9838 Flow f;
9839 ThreadVars tv;
9840 StreamTcpThread stt;
9841 uint8_t payload[4];
9842 TCPHdr tcph;
9843 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
9844 int ret = 0;
9845 PacketQueueNoLock pq;
9846 memset(&pq,0,sizeof(PacketQueueNoLock));
9847
9848 memset (&p, 0, SIZE_OF_PACKET);
9849 memset (&f, 0, sizeof(Flow));
9850 memset(&tv, 0, sizeof (ThreadVars));
9851 memset(&stt, 0, sizeof (StreamTcpThread));
9852 memset(&tcph, 0, sizeof (TCPHdr));
9853
9854 FLOW_INITIALIZE(&f);
9855 stt.ra_ctx = ra_ctx;
9856 p.flow = &f;
9857 tcph.th_win = htons(5480);
9858 tcph.th_flags = TH_SYN;
9859 p.tcph = &tcph;
9860 p.flowflags = FLOW_PKT_TOSERVER;
9861
9862 StreamTcpInitConfig(TRUE);
9863
9864 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) {
9865 printf("failed in processing packet\n");
9866 goto end;
9867 }
9868
9869 p.tcph->th_ack = htonl(1);
9870 p.tcph->th_flags = TH_SYN | TH_ACK;
9871 p.flowflags = FLOW_PKT_TOCLIENT;
9872
9873 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
9874 printf("failed in processing packet\n");
9875 goto end;
9876 }
9877
9878 p.tcph->th_ack = htonl(1);
9879 p.tcph->th_seq = htonl(1);
9880 p.tcph->th_flags = TH_ACK;
9881 p.flowflags = FLOW_PKT_TOSERVER;
9882
9883 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
9884 printf("failed in processing packet\n");
9885 goto end;
9886 }
9887
9888 if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) {
9889 printf("the TCP state should be TCP_ESTABLISEHD\n");
9890 goto end;
9891 }
9892
9893 p.tcph->th_ack = htonl(2);
9894 p.tcph->th_seq = htonl(1);
9895 p.tcph->th_flags = TH_PUSH | TH_ACK | TH_URG;
9896 p.flowflags = FLOW_PKT_TOSERVER;
9897
9898 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
9899 p.payload = payload;
9900 p.payload_len = 3;
9901
9902 if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
9903 printf("failed in processing packet\n");
9904 goto end;
9905 }
9906
9907 if (((TcpSession *)p.flow->protoctx)->client.next_seq != 4) {
9908 printf("the ssn->client.next_seq should be 4, but it is %"PRIu32"\n",
9909 ((TcpSession *)p.flow->protoctx)->client.next_seq);
9910 goto end;
9911 }
9912
9913 StreamTcpSessionClear(p.flow->protoctx);
9914
9915 ret = 1;
9916 end:
9917 StreamTcpFreeConfig(TRUE);
9918 return ret;
9919 }
9920 #endif
9921
9922 /**
9923 * \test Test the processing of out of order FIN packets in tcp session.
9924 *
9925 * \retval On success it returns 1 and on failure 0.
9926 */
StreamTcpTest37(void)9927 static int StreamTcpTest37(void)
9928 {
9929 Packet *p = SCMalloc(SIZE_OF_PACKET);
9930 if (unlikely(p == NULL))
9931 return 0;
9932 Flow f;
9933 ThreadVars tv;
9934 StreamTcpThread stt;
9935 uint8_t payload[4];
9936 TCPHdr tcph;
9937 int ret = 0;
9938 PacketQueueNoLock pq;
9939 memset(&pq,0,sizeof(PacketQueueNoLock));
9940
9941 memset(p, 0, SIZE_OF_PACKET);
9942 memset (&f, 0, sizeof(Flow));
9943 memset(&tv, 0, sizeof (ThreadVars));
9944 memset(&stt, 0, sizeof (StreamTcpThread));
9945 memset(&tcph, 0, sizeof (TCPHdr));
9946
9947 FLOW_INITIALIZE(&f);
9948
9949 p->flow = &f;
9950 tcph.th_win = htons(5480);
9951 tcph.th_flags = TH_SYN;
9952 p->tcph = &tcph;
9953 p->flowflags = FLOW_PKT_TOSERVER;
9954
9955 StreamTcpUTInit(&stt.ra_ctx);
9956
9957 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
9958 printf("failed in processing packet\n");
9959 goto end;
9960 }
9961
9962 p->tcph->th_ack = htonl(1);
9963 p->tcph->th_flags = TH_SYN | TH_ACK;
9964 p->flowflags = FLOW_PKT_TOCLIENT;
9965
9966 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
9967 printf("failed in processing packet\n");
9968 goto end;
9969 }
9970
9971 p->tcph->th_ack = htonl(1);
9972 p->tcph->th_seq = htonl(1);
9973 p->tcph->th_flags = TH_ACK;
9974 p->flowflags = FLOW_PKT_TOSERVER;
9975
9976 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
9977 printf("failed in processing packet\n");
9978 goto end;
9979 }
9980
9981 if (((TcpSession *)p->flow->protoctx)->state != TCP_ESTABLISHED) {
9982 printf("the TCP state should be TCP_ESTABLISEHD\n");
9983 goto end;
9984 }
9985
9986 p->tcph->th_ack = htonl(2);
9987 p->tcph->th_seq = htonl(4);
9988 p->tcph->th_flags = TH_ACK|TH_FIN;
9989 p->flowflags = FLOW_PKT_TOSERVER;
9990
9991 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
9992 printf("failed in processing packet\n");
9993 goto end;
9994 }
9995
9996 if (((TcpSession *)p->flow->protoctx)->state != TCP_CLOSE_WAIT) {
9997 printf("the TCP state should be TCP_CLOSE_WAIT\n");
9998 goto end;
9999 }
10000
10001 p->tcph->th_ack = htonl(1);
10002 p->tcph->th_seq = htonl(1);
10003 p->tcph->th_flags = TH_PUSH | TH_ACK;
10004 p->flowflags = FLOW_PKT_TOSERVER;
10005
10006 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
10007 p->payload = payload;
10008 p->payload_len = 3;
10009
10010 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
10011 printf("failed in processing packet\n");
10012 goto end;
10013 }
10014
10015 p->tcph->th_ack = htonl(4);
10016 p->tcph->th_seq = htonl(2);
10017 p->tcph->th_flags = TH_ACK;
10018 p->payload_len = 0;
10019 p->flowflags = FLOW_PKT_TOCLIENT;
10020
10021 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
10022 printf("failed in processing packet\n");
10023 goto end;
10024 }
10025
10026 TcpStream *stream = &(((TcpSession *)p->flow->protoctx)->client);
10027 FAIL_IF(STREAM_RAW_PROGRESS(stream) != 0); // no detect no progress update
10028
10029 StreamTcpSessionClear(p->flow->protoctx);
10030
10031 ret = 1;
10032 end:
10033 SCFree(p);
10034 FLOW_DESTROY(&f);
10035 StreamTcpUTDeinit(stt.ra_ctx);
10036 return ret;
10037 }
10038
10039 /**
10040 * \test Test the validation of the ACK number before setting up the
10041 * stream.last_ack.
10042 *
10043 * \retval On success it returns 1 and on failure 0.
10044 */
10045
StreamTcpTest38(void)10046 static int StreamTcpTest38 (void)
10047 {
10048 int ret = 0;
10049 Flow f;
10050 ThreadVars tv;
10051 StreamTcpThread stt;
10052 uint8_t payload[128];
10053 TCPHdr tcph;
10054 PacketQueueNoLock pq;
10055
10056 memset (&f, 0, sizeof(Flow));
10057 memset(&tv, 0, sizeof (ThreadVars));
10058 memset(&stt, 0, sizeof (StreamTcpThread));
10059 memset(&tcph, 0, sizeof (TCPHdr));
10060 memset(&pq,0,sizeof(PacketQueueNoLock));
10061
10062 Packet *p = SCMalloc(SIZE_OF_PACKET);
10063 if (unlikely(p == NULL))
10064 return 0;
10065 memset(p, 0, SIZE_OF_PACKET);
10066
10067 FLOW_INITIALIZE(&f);
10068 p->flow = &f;
10069 tcph.th_win = htons(5480);
10070 tcph.th_flags = TH_SYN;
10071 p->tcph = &tcph;
10072 p->flowflags = FLOW_PKT_TOSERVER;
10073
10074 StreamTcpUTInit(&stt.ra_ctx);
10075 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10076 printf("failed in processing packet in StreamTcpPacket\n");
10077 goto end;
10078 }
10079
10080 p->tcph->th_ack = htonl(1);
10081 p->tcph->th_flags = TH_SYN | TH_ACK;
10082 p->flowflags = FLOW_PKT_TOCLIENT;
10083
10084 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10085 printf("failed in processing packet in StreamTcpPacket\n");
10086 goto end;
10087 }
10088
10089 p->tcph->th_ack = htonl(1);
10090 p->tcph->th_seq = htonl(1);
10091 p->tcph->th_flags = TH_ACK;
10092 p->flowflags = FLOW_PKT_TOSERVER;
10093
10094 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10095 printf("failed in processing packet in StreamTcpPacket\n");
10096 goto end;
10097 }
10098
10099 p->tcph->th_ack = htonl(29847);
10100 p->tcph->th_seq = htonl(2);
10101 p->tcph->th_flags = TH_PUSH | TH_ACK;
10102 p->flowflags = FLOW_PKT_TOSERVER;
10103
10104 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
10105 p->payload = payload;
10106 p->payload_len = 3;
10107
10108 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10109 printf("failed in processing packet in StreamTcpPacket\n");
10110 goto end;
10111 }
10112
10113 /* last_ack value should be 1 as the previous sent ACK value is out of
10114 window */
10115 if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 1) {
10116 printf("the server.last_ack should be 1, but it is %"PRIu32"\n",
10117 ((TcpSession *)(p->flow->protoctx))->server.last_ack);
10118 goto end;
10119 }
10120
10121 p->tcph->th_ack = htonl(1);
10122 p->tcph->th_seq = htonl(1);
10123 p->tcph->th_flags = TH_PUSH | TH_ACK;
10124 p->flowflags = FLOW_PKT_TOCLIENT;
10125
10126 StreamTcpCreateTestPacket(payload, 0x41, 127, 128); /*AAA*/
10127 p->payload = payload;
10128 p->payload_len = 127;
10129
10130 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10131 printf("failed in processing packet in StreamTcpPacket\n");
10132 goto end;
10133 }
10134
10135 if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 128) {
10136 printf("the server.next_seq should be 128, but it is %"PRIu32"\n",
10137 ((TcpSession *)(p->flow->protoctx))->server.next_seq);
10138 goto end;
10139 }
10140
10141 p->tcph->th_ack = htonl(256); // in window, but beyond next_seq
10142 p->tcph->th_seq = htonl(5);
10143 p->tcph->th_flags = TH_PUSH | TH_ACK;
10144 p->flowflags = FLOW_PKT_TOSERVER;
10145
10146 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
10147 p->payload = payload;
10148 p->payload_len = 3;
10149
10150 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10151 printf("failed in processing packet in StreamTcpPacket\n");
10152 goto end;
10153 }
10154
10155 /* last_ack value should be 256, as the previous sent ACK value
10156 is inside window */
10157 if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 256) {
10158 printf("the server.last_ack should be 1, but it is %"PRIu32"\n",
10159 ((TcpSession *)(p->flow->protoctx))->server.last_ack);
10160 goto end;
10161 }
10162
10163 p->tcph->th_ack = htonl(128);
10164 p->tcph->th_seq = htonl(8);
10165 p->tcph->th_flags = TH_PUSH | TH_ACK;
10166 p->flowflags = FLOW_PKT_TOSERVER;
10167
10168 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
10169 p->payload = payload;
10170 p->payload_len = 3;
10171
10172 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10173 printf("failed in processing packet in StreamTcpPacket\n");
10174 goto end;
10175 }
10176
10177 /* last_ack value should be 256 as the previous sent ACK value is inside
10178 window */
10179 if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 256) {
10180 printf("the server.last_ack should be 256, but it is %"PRIu32"\n",
10181 ((TcpSession *)(p->flow->protoctx))->server.last_ack);
10182 goto end;
10183 }
10184
10185 ret = 1;
10186
10187 end:
10188 StreamTcpSessionClear(p->flow->protoctx);
10189 SCFree(p);
10190 FLOW_DESTROY(&f);
10191 StreamTcpUTDeinit(stt.ra_ctx);
10192 return ret;
10193 }
10194
10195 /**
10196 * \test Test the validation of the ACK number before setting up the
10197 * stream.last_ack and update the next_seq after loosing the .
10198 *
10199 * \retval On success it returns 1 and on failure 0.
10200 */
10201
StreamTcpTest39(void)10202 static int StreamTcpTest39 (void)
10203 {
10204 Flow f;
10205 ThreadVars tv;
10206 StreamTcpThread stt;
10207 uint8_t payload[4];
10208 TCPHdr tcph;
10209 PacketQueueNoLock pq;
10210
10211 memset (&f, 0, sizeof(Flow));
10212 memset(&tv, 0, sizeof (ThreadVars));
10213 memset(&stt, 0, sizeof (StreamTcpThread));
10214 memset(&tcph, 0, sizeof (TCPHdr));
10215 memset(&pq,0,sizeof(PacketQueueNoLock));
10216
10217 Packet *p = SCMalloc(SIZE_OF_PACKET);
10218 if (unlikely(p == NULL))
10219 return 0;
10220 memset(p, 0, SIZE_OF_PACKET);
10221
10222 FLOW_INITIALIZE(&f);
10223 p->flow = &f;
10224 tcph.th_win = htons(5480);
10225 tcph.th_flags = TH_SYN;
10226 p->tcph = &tcph;
10227 p->flowflags = FLOW_PKT_TOSERVER;
10228 int ret = 0;
10229
10230 StreamTcpUTInit(&stt.ra_ctx);
10231
10232 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10233 printf("failed in processing packet in StreamTcpPacket\n");
10234 goto end;
10235 }
10236
10237 p->tcph->th_ack = htonl(1);
10238 p->tcph->th_flags = TH_SYN | TH_ACK;
10239 p->flowflags = FLOW_PKT_TOCLIENT;
10240
10241 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10242 printf("failed in processing packet in StreamTcpPacket\n");
10243 goto end;
10244 }
10245
10246 p->tcph->th_ack = htonl(1);
10247 p->tcph->th_seq = htonl(1);
10248 p->tcph->th_flags = TH_ACK;
10249 p->flowflags = FLOW_PKT_TOSERVER;
10250
10251 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10252 printf("failed in processing packet in StreamTcpPacket\n");
10253 goto end;
10254 }
10255
10256 p->tcph->th_ack = htonl(1);
10257 p->tcph->th_seq = htonl(1);
10258 p->tcph->th_flags = TH_PUSH | TH_ACK;
10259 p->flowflags = FLOW_PKT_TOCLIENT;
10260
10261 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
10262 p->payload = payload;
10263 p->payload_len = 3;
10264
10265 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10266 printf("failed in processing packet in StreamTcpPacket\n");
10267 goto end;
10268 }
10269
10270 if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 4) {
10271 printf("the server.next_seq should be 4, but it is %"PRIu32"\n",
10272 ((TcpSession *)(p->flow->protoctx))->server.next_seq);
10273 goto end;
10274 }
10275
10276 p->tcph->th_ack = htonl(4);
10277 p->tcph->th_seq = htonl(2);
10278 p->tcph->th_flags = TH_PUSH | TH_ACK;
10279 p->flowflags = FLOW_PKT_TOSERVER;
10280
10281 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
10282 p->payload = payload;
10283 p->payload_len = 3;
10284
10285 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10286 printf("failed in processing packet in StreamTcpPacket\n");
10287 goto end;
10288 }
10289
10290 /* last_ack value should be 4 as the previous sent ACK value is inside
10291 window */
10292 if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 4) {
10293 printf("the server.last_ack should be 4, but it is %"PRIu32"\n",
10294 ((TcpSession *)(p->flow->protoctx))->server.last_ack);
10295 goto end;
10296 }
10297
10298 p->tcph->th_seq = htonl(4);
10299 p->tcph->th_ack = htonl(5);
10300 p->tcph->th_flags = TH_PUSH | TH_ACK;
10301 p->flowflags = FLOW_PKT_TOCLIENT;
10302
10303 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
10304 p->payload = payload;
10305 p->payload_len = 3;
10306
10307 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
10308 printf("failed in processing packet in StreamTcpPacket\n");
10309 goto end;
10310 }
10311
10312 /* next_seq value should be 2987 as the previous sent ACK value is inside
10313 window */
10314 if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 7) {
10315 printf("the server.next_seq should be 7, but it is %"PRIu32"\n",
10316 ((TcpSession *)(p->flow->protoctx))->server.next_seq);
10317 goto end;
10318 }
10319
10320 ret = 1;
10321
10322 end:
10323 StreamTcpSessionClear(p->flow->protoctx);
10324 SCFree(p);
10325 FLOW_DESTROY(&f);
10326 StreamTcpUTDeinit(stt.ra_ctx);
10327 return ret;
10328 }
10329
10330 /** \test multiple different SYN/ACK, pick first */
StreamTcpTest42(void)10331 static int StreamTcpTest42 (void)
10332 {
10333 int ret = 0;
10334 Flow f;
10335 ThreadVars tv;
10336 StreamTcpThread stt;
10337 TCPHdr tcph;
10338 PacketQueueNoLock pq;
10339 Packet *p = SCMalloc(SIZE_OF_PACKET);
10340 TcpSession *ssn;
10341
10342 if (unlikely(p == NULL))
10343 return 0;
10344 memset(p, 0, SIZE_OF_PACKET);
10345
10346 memset(&pq,0,sizeof(PacketQueueNoLock));
10347 memset (&f, 0, sizeof(Flow));
10348 memset(&tv, 0, sizeof (ThreadVars));
10349 memset(&stt, 0, sizeof (StreamTcpThread));
10350 memset(&tcph, 0, sizeof (TCPHdr));
10351
10352 StreamTcpUTInit(&stt.ra_ctx);
10353
10354 FLOW_INITIALIZE(&f);
10355 p->tcph = &tcph;
10356 tcph.th_win = htons(5480);
10357 p->flow = &f;
10358
10359 /* SYN pkt */
10360 tcph.th_flags = TH_SYN;
10361 tcph.th_seq = htonl(100);
10362 p->flowflags = FLOW_PKT_TOSERVER;
10363
10364 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10365 goto end;
10366
10367 /* SYN/ACK */
10368 p->tcph->th_seq = htonl(500);
10369 p->tcph->th_ack = htonl(101);
10370 p->tcph->th_flags = TH_SYN | TH_ACK;
10371 p->flowflags = FLOW_PKT_TOCLIENT;
10372
10373 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10374 goto end;
10375
10376 /* SYN/ACK */
10377 p->tcph->th_seq = htonl(1000);
10378 p->tcph->th_ack = htonl(101);
10379 p->tcph->th_flags = TH_SYN | TH_ACK;
10380 p->flowflags = FLOW_PKT_TOCLIENT;
10381
10382 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10383 goto end;
10384
10385 /* ACK */
10386 p->tcph->th_ack = htonl(501);
10387 p->tcph->th_seq = htonl(101);
10388 p->tcph->th_flags = TH_ACK;
10389 p->flowflags = FLOW_PKT_TOSERVER;
10390
10391 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10392 goto end;
10393
10394 ssn = p->flow->protoctx;
10395
10396 if (ssn->state != TCP_ESTABLISHED) {
10397 printf("state not TCP_ESTABLISHED: ");
10398 goto end;
10399 }
10400
10401 if (ssn->server.isn != 500) {
10402 SCLogDebug("ssn->server.isn %"PRIu32" != %"PRIu32"",
10403 ssn->server.isn, 500);
10404 goto end;
10405 }
10406 if (ssn->client.isn != 100) {
10407 SCLogDebug("ssn->client.isn %"PRIu32" != %"PRIu32"",
10408 ssn->client.isn, 100);
10409 goto end;
10410 }
10411
10412 StreamTcpSessionClear(p->flow->protoctx);
10413
10414 ret = 1;
10415 end:
10416 SCFree(p);
10417 FLOW_DESTROY(&f);
10418 StreamTcpUTDeinit(stt.ra_ctx);
10419 return ret;
10420 }
10421
10422 /** \test multiple different SYN/ACK, pick second */
StreamTcpTest43(void)10423 static int StreamTcpTest43 (void)
10424 {
10425 int ret = 0;
10426 Flow f;
10427 ThreadVars tv;
10428 StreamTcpThread stt;
10429 TCPHdr tcph;
10430 PacketQueueNoLock pq;
10431 Packet *p = SCMalloc(SIZE_OF_PACKET);
10432 TcpSession *ssn;
10433
10434 if (unlikely(p == NULL))
10435 return 0;
10436 memset(p, 0, SIZE_OF_PACKET);
10437
10438 memset(&pq,0,sizeof(PacketQueueNoLock));
10439 memset (&f, 0, sizeof(Flow));
10440 memset(&tv, 0, sizeof (ThreadVars));
10441 memset(&stt, 0, sizeof (StreamTcpThread));
10442 memset(&tcph, 0, sizeof (TCPHdr));
10443
10444 StreamTcpUTInit(&stt.ra_ctx);
10445
10446 FLOW_INITIALIZE(&f);
10447 p->tcph = &tcph;
10448 tcph.th_win = htons(5480);
10449 p->flow = &f;
10450
10451 /* SYN pkt */
10452 tcph.th_flags = TH_SYN;
10453 tcph.th_seq = htonl(100);
10454 p->flowflags = FLOW_PKT_TOSERVER;
10455
10456 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10457 goto end;
10458
10459 /* SYN/ACK */
10460 p->tcph->th_seq = htonl(500);
10461 p->tcph->th_ack = htonl(101);
10462 p->tcph->th_flags = TH_SYN | TH_ACK;
10463 p->flowflags = FLOW_PKT_TOCLIENT;
10464
10465 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10466 goto end;
10467
10468 /* SYN/ACK */
10469 p->tcph->th_seq = htonl(1000);
10470 p->tcph->th_ack = htonl(101);
10471 p->tcph->th_flags = TH_SYN | TH_ACK;
10472 p->flowflags = FLOW_PKT_TOCLIENT;
10473
10474 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10475 goto end;
10476
10477 /* ACK */
10478 p->tcph->th_ack = htonl(1001);
10479 p->tcph->th_seq = htonl(101);
10480 p->tcph->th_flags = TH_ACK;
10481 p->flowflags = FLOW_PKT_TOSERVER;
10482
10483 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10484 goto end;
10485
10486 ssn = p->flow->protoctx;
10487
10488 if (ssn->state != TCP_ESTABLISHED) {
10489 printf("state not TCP_ESTABLISHED: ");
10490 goto end;
10491 }
10492
10493 if (ssn->server.isn != 1000) {
10494 SCLogDebug("ssn->server.isn %"PRIu32" != %"PRIu32"",
10495 ssn->server.isn, 1000);
10496 goto end;
10497 }
10498 if (ssn->client.isn != 100) {
10499 SCLogDebug("ssn->client.isn %"PRIu32" != %"PRIu32"",
10500 ssn->client.isn, 100);
10501 goto end;
10502 }
10503
10504 StreamTcpSessionClear(p->flow->protoctx);
10505
10506 ret = 1;
10507 end:
10508 SCFree(p);
10509 FLOW_DESTROY(&f);
10510 StreamTcpUTDeinit(stt.ra_ctx);
10511 return ret;
10512 }
10513
10514 /** \test multiple different SYN/ACK, pick neither */
StreamTcpTest44(void)10515 static int StreamTcpTest44 (void)
10516 {
10517 int ret = 0;
10518 Flow f;
10519 ThreadVars tv;
10520 StreamTcpThread stt;
10521 TCPHdr tcph;
10522 PacketQueueNoLock pq;
10523 Packet *p = SCMalloc(SIZE_OF_PACKET);
10524 TcpSession *ssn;
10525
10526 if (unlikely(p == NULL))
10527 return 0;
10528 memset(p, 0, SIZE_OF_PACKET);
10529
10530 memset(&pq,0,sizeof(PacketQueueNoLock));
10531 memset (&f, 0, sizeof(Flow));
10532 memset(&tv, 0, sizeof (ThreadVars));
10533 memset(&stt, 0, sizeof (StreamTcpThread));
10534 memset(&tcph, 0, sizeof (TCPHdr));
10535
10536 StreamTcpUTInit(&stt.ra_ctx);
10537
10538 FLOW_INITIALIZE(&f);
10539 p->tcph = &tcph;
10540 tcph.th_win = htons(5480);
10541 p->flow = &f;
10542
10543 /* SYN pkt */
10544 tcph.th_flags = TH_SYN;
10545 tcph.th_seq = htonl(100);
10546 p->flowflags = FLOW_PKT_TOSERVER;
10547
10548 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10549 goto end;
10550
10551 /* SYN/ACK */
10552 p->tcph->th_seq = htonl(500);
10553 p->tcph->th_ack = htonl(101);
10554 p->tcph->th_flags = TH_SYN | TH_ACK;
10555 p->flowflags = FLOW_PKT_TOCLIENT;
10556
10557 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10558 goto end;
10559
10560 /* SYN/ACK */
10561 p->tcph->th_seq = htonl(1000);
10562 p->tcph->th_ack = htonl(101);
10563 p->tcph->th_flags = TH_SYN | TH_ACK;
10564 p->flowflags = FLOW_PKT_TOCLIENT;
10565
10566 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10567 goto end;
10568
10569 /* ACK */
10570 p->tcph->th_ack = htonl(3001);
10571 p->tcph->th_seq = htonl(101);
10572 p->tcph->th_flags = TH_ACK;
10573 p->flowflags = FLOW_PKT_TOSERVER;
10574
10575 if (StreamTcpPacket(&tv, p, &stt, &pq) != -1)
10576 goto end;
10577
10578 ssn = p->flow->protoctx;
10579
10580 if (ssn->state != TCP_SYN_RECV) {
10581 SCLogDebug("state not TCP_SYN_RECV");
10582 goto end;
10583 }
10584
10585 if (ssn->client.isn != 100) {
10586 SCLogDebug("ssn->client.isn %"PRIu32" != %"PRIu32"",
10587 ssn->client.isn, 100);
10588 goto end;
10589 }
10590
10591 StreamTcpSessionClear(p->flow->protoctx);
10592
10593 ret = 1;
10594 end:
10595 SCFree(p);
10596 FLOW_DESTROY(&f);
10597 StreamTcpUTDeinit(stt.ra_ctx);
10598 return ret;
10599 }
10600
10601 /** \test multiple different SYN/ACK, over the limit */
StreamTcpTest45(void)10602 static int StreamTcpTest45 (void)
10603 {
10604 int ret = 0;
10605 Flow f;
10606 ThreadVars tv;
10607 StreamTcpThread stt;
10608 TCPHdr tcph;
10609 PacketQueueNoLock pq;
10610 Packet *p = SCMalloc(SIZE_OF_PACKET);
10611 TcpSession *ssn;
10612
10613 if (unlikely(p == NULL))
10614 return 0;
10615 memset(p, 0, SIZE_OF_PACKET);
10616
10617 memset(&pq,0,sizeof(PacketQueueNoLock));
10618 memset (&f, 0, sizeof(Flow));
10619 memset(&tv, 0, sizeof (ThreadVars));
10620 memset(&stt, 0, sizeof (StreamTcpThread));
10621 memset(&tcph, 0, sizeof (TCPHdr));
10622
10623 StreamTcpUTInit(&stt.ra_ctx);
10624 stream_config.max_synack_queued = 2;
10625
10626 FLOW_INITIALIZE(&f);
10627 p->tcph = &tcph;
10628 tcph.th_win = htons(5480);
10629 p->flow = &f;
10630
10631 /* SYN pkt */
10632 tcph.th_flags = TH_SYN;
10633 tcph.th_seq = htonl(100);
10634 p->flowflags = FLOW_PKT_TOSERVER;
10635
10636 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10637 goto end;
10638
10639 /* SYN/ACK */
10640 p->tcph->th_seq = htonl(500);
10641 p->tcph->th_ack = htonl(101);
10642 p->tcph->th_flags = TH_SYN | TH_ACK;
10643 p->flowflags = FLOW_PKT_TOCLIENT;
10644
10645 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10646 goto end;
10647
10648 /* SYN/ACK */
10649 p->tcph->th_seq = htonl(1000);
10650 p->tcph->th_ack = htonl(101);
10651 p->tcph->th_flags = TH_SYN | TH_ACK;
10652 p->flowflags = FLOW_PKT_TOCLIENT;
10653
10654 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10655 goto end;
10656
10657 /* SYN/ACK */
10658 p->tcph->th_seq = htonl(2000);
10659 p->tcph->th_ack = htonl(101);
10660 p->tcph->th_flags = TH_SYN | TH_ACK;
10661 p->flowflags = FLOW_PKT_TOCLIENT;
10662
10663 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10664 goto end;
10665
10666 /* SYN/ACK */
10667 p->tcph->th_seq = htonl(3000);
10668 p->tcph->th_ack = htonl(101);
10669 p->tcph->th_flags = TH_SYN | TH_ACK;
10670 p->flowflags = FLOW_PKT_TOCLIENT;
10671
10672 if (StreamTcpPacket(&tv, p, &stt, &pq) != -1)
10673 goto end;
10674
10675 /* ACK */
10676 p->tcph->th_ack = htonl(1001);
10677 p->tcph->th_seq = htonl(101);
10678 p->tcph->th_flags = TH_ACK;
10679 p->flowflags = FLOW_PKT_TOSERVER;
10680
10681 if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
10682 goto end;
10683
10684 ssn = p->flow->protoctx;
10685
10686 if (ssn->state != TCP_ESTABLISHED) {
10687 printf("state not TCP_ESTABLISHED: ");
10688 goto end;
10689 }
10690
10691 if (ssn->server.isn != 1000) {
10692 SCLogDebug("ssn->server.isn %"PRIu32" != %"PRIu32"",
10693 ssn->server.isn, 1000);
10694 goto end;
10695 }
10696 if (ssn->client.isn != 100) {
10697 SCLogDebug("ssn->client.isn %"PRIu32" != %"PRIu32"",
10698 ssn->client.isn, 100);
10699 goto end;
10700 }
10701
10702 StreamTcpSessionClear(p->flow->protoctx);
10703
10704 ret = 1;
10705 end:
10706 SCFree(p);
10707 StreamTcpUTDeinit(stt.ra_ctx);
10708 return ret;
10709 }
10710
10711 #endif /* UNITTESTS */
10712
StreamTcpRegisterTests(void)10713 void StreamTcpRegisterTests (void)
10714 {
10715 #ifdef UNITTESTS
10716 UtRegisterTest("StreamTcpTest01 -- TCP session allocation",
10717 StreamTcpTest01);
10718 UtRegisterTest("StreamTcpTest02 -- TCP session deallocation",
10719 StreamTcpTest02);
10720 UtRegisterTest("StreamTcpTest03 -- SYN missed MidStream session",
10721 StreamTcpTest03);
10722 UtRegisterTest("StreamTcpTest04 -- SYN/ACK missed MidStream session",
10723 StreamTcpTest04);
10724 UtRegisterTest("StreamTcpTest05 -- 3WHS missed MidStream session",
10725 StreamTcpTest05);
10726 UtRegisterTest("StreamTcpTest06 -- FIN, RST message MidStream session",
10727 StreamTcpTest06);
10728 UtRegisterTest("StreamTcpTest07 -- PAWS invalid timestamp",
10729 StreamTcpTest07);
10730 UtRegisterTest("StreamTcpTest08 -- PAWS valid timestamp", StreamTcpTest08);
10731 UtRegisterTest("StreamTcpTest09 -- No Client Reassembly", StreamTcpTest09);
10732 UtRegisterTest("StreamTcpTest10 -- No missed packet Async stream",
10733 StreamTcpTest10);
10734 UtRegisterTest("StreamTcpTest11 -- SYN missed Async stream",
10735 StreamTcpTest11);
10736 UtRegisterTest("StreamTcpTest12 -- SYN/ACK missed Async stream",
10737 StreamTcpTest12);
10738 UtRegisterTest("StreamTcpTest13 -- opposite stream packets for Async " "stream",
10739 StreamTcpTest13);
10740 UtRegisterTest("StreamTcp4WHSTest01", StreamTcp4WHSTest01);
10741 UtRegisterTest("StreamTcp4WHSTest02", StreamTcp4WHSTest02);
10742 UtRegisterTest("StreamTcp4WHSTest03", StreamTcp4WHSTest03);
10743 UtRegisterTest("StreamTcpTest14 -- setup OS policy", StreamTcpTest14);
10744 UtRegisterTest("StreamTcpTest15 -- setup OS policy", StreamTcpTest15);
10745 UtRegisterTest("StreamTcpTest16 -- setup OS policy", StreamTcpTest16);
10746 UtRegisterTest("StreamTcpTest17 -- setup OS policy", StreamTcpTest17);
10747 UtRegisterTest("StreamTcpTest18 -- setup OS policy", StreamTcpTest18);
10748 UtRegisterTest("StreamTcpTest19 -- setup OS policy", StreamTcpTest19);
10749 UtRegisterTest("StreamTcpTest20 -- setup OS policy", StreamTcpTest20);
10750 UtRegisterTest("StreamTcpTest21 -- setup OS policy", StreamTcpTest21);
10751 UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22);
10752 UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23);
10753 UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24);
10754 UtRegisterTest("StreamTcpTest25 -- test ecn/cwr sessions",
10755 StreamTcpTest25);
10756 UtRegisterTest("StreamTcpTest26 -- test ecn/cwr sessions",
10757 StreamTcpTest26);
10758 UtRegisterTest("StreamTcpTest27 -- test ecn/cwr sessions",
10759 StreamTcpTest27);
10760 UtRegisterTest("StreamTcpTest28 -- Memcap Test", StreamTcpTest28);
10761
10762 #if 0 /* VJ 2010/09/01 disabled since they blow up on Fedora and Fedora is
10763 * right about blowing up. The checksum functions are not used properly
10764 * in the tests. */
10765 UtRegisterTest("StreamTcpTest29 -- Badchecksum Reset Test", StreamTcpTest29, 1);
10766 UtRegisterTest("StreamTcpTest30 -- Badchecksum Overlap Test", StreamTcpTest30, 1);
10767 UtRegisterTest("StreamTcpTest31 -- MultipleSyns Test", StreamTcpTest31, 1);
10768 UtRegisterTest("StreamTcpTest32 -- Bogus CWR Test", StreamTcpTest32, 1);
10769 UtRegisterTest("StreamTcpTest33 -- RST-SYN Again Test", StreamTcpTest33, 1);
10770 UtRegisterTest("StreamTcpTest34 -- SYN-PUSH Test", StreamTcpTest34, 1);
10771 UtRegisterTest("StreamTcpTest35 -- SYN-URG Test", StreamTcpTest35, 1);
10772 UtRegisterTest("StreamTcpTest36 -- PUSH-URG Test", StreamTcpTest36, 1);
10773 #endif
10774 UtRegisterTest("StreamTcpTest37 -- Out of order FIN Test",
10775 StreamTcpTest37);
10776
10777 UtRegisterTest("StreamTcpTest38 -- validate ACK", StreamTcpTest38);
10778 UtRegisterTest("StreamTcpTest39 -- update next_seq", StreamTcpTest39);
10779
10780 UtRegisterTest("StreamTcpTest42 -- SYN/ACK queue", StreamTcpTest42);
10781 UtRegisterTest("StreamTcpTest43 -- SYN/ACK queue", StreamTcpTest43);
10782 UtRegisterTest("StreamTcpTest44 -- SYN/ACK queue", StreamTcpTest44);
10783 UtRegisterTest("StreamTcpTest45 -- SYN/ACK queue", StreamTcpTest45);
10784
10785 /* set up the reassembly tests as well */
10786 StreamTcpReassembleRegisterTests();
10787
10788 StreamTcpSackRegisterTests ();
10789 #endif /* UNITTESTS */
10790 }
10791