1 /* $Id$ */
2 /****************************************************************************
3 *
4 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
5 * Copyright (C) 2005-2013 Sourcefire, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License Version 2 as
9 * published by the Free Software Foundation. You may not use, modify or
10 * distribute this program under any other version of the GNU General
11 * Public License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 ****************************************************************************/
23
24 /**
25 * @file snort_stream_tcp.c
26 * @author Martin Roesch <roesch@sourcefire.com>
27 * @author Steven Sturges <ssturges@sourcefire.com>
28 *
29 */
30
31 /*
32 * TODOs:
33 * - midstream ssn pickup (done, SAS 10/14/2005)
34 * - syn flood protection (done, SAS 9/27/2005)
35 *
36 * - review policy anomaly detection
37 * + URG pointer (TODO)
38 * + data on SYN (done, SAS 10/12/2005)
39 * + data on FIN (done, SAS 10/12/2005)
40 * + data after FIN (done, SAS 10/13/2005)
41 * + window scaling/window size max (done, SAS 10/13/2005)
42 * + PAWS, TCP Timestamps (done, SAS 10/12/2005)
43 *
44 * - session shutdown/Reset handling (done, SAS)
45 * - flush policy for Window/Consumed
46 * - limit on number of overlapping packets (done, SAS)
47 */
48
49 #include <errno.h>
50 #include <assert.h>
51
52 #ifdef HAVE_CONFIG_H
53 #include "config.h"
54 #endif
55
56 #include "perf.h"
57 #include "sf_types.h"
58 #include "snort_debug.h"
59 #include "detect.h"
60 #include "plugbase.h"
61 #include "mstring.h"
62 #include "sfxhash.h"
63 #include "util.h"
64 #include "sflsq.h"
65 #include "snort_bounds.h"
66 #include "generators.h"
67 #include "event_queue.h"
68 #include "snort.h"
69 #include "memory_stats.h"
70 #include "parser/IpAddrSet.h"
71
72 #include "decode.h"
73 #include "encode.h"
74 #include "log.h"
75 #include "active.h"
76 #include "spp_normalize.h"
77
78 #include "sf_sdlist.h"
79
80 #include "spp_session.h"
81 #include "session_api.h"
82 #include "snort_session.h"
83
84 #include "stream_common.h"
85 #include "snort_stream_tcp.h"
86 #include "stream_api.h"
87 #include "session_expect.h"
88 #include "stream_paf.h"
89 #include "stream5_ha.h"
90
91 #ifdef TARGET_BASED
92 #include "sftarget_protocol_reference.h"
93 #include "sftarget_hostentry.h"
94 #endif
95
96 #include "profiler.h"
97
98 #include "ipv6_port.h"
99 #include "sf_iph.h"
100
101 #include "sp_preprocopt.h"
102 #include "sfPolicy.h"
103 #include "sfActionQueue.h"
104 #include "detection_util.h"
105 #include "file_api.h"
106
107 #ifdef REG_TEST
108 #include "reg_test.h"
109 #include <stdio.h>
110 #endif
111
112 // port reassembly registration utils
113 static void StreamCreateReassemblyPortList( void );
114 static void StreamDestoryReassemblyPortList( void );
115
116 #ifdef PERF_PROFILING
117 PreprocStats s5TcpPerfStats;
118 PreprocStats s5TcpNewSessPerfStats;
119 PreprocStats s5TcpStatePerfStats;
120 PreprocStats s5TcpDataPerfStats;
121 PreprocStats s5TcpInsertPerfStats;
122 PreprocStats s5TcpPAFPerfStats;
123 PreprocStats s5TcpFlushPerfStats;
124 PreprocStats s5TcpBuildPacketPerfStats;
125 PreprocStats s5TcpProcessRebuiltPerfStats;
126
127 PreprocStats streamSizePerfStats;
128 PreprocStats streamReassembleRuleOptionPerfStats;
129 extern PreprocStats preprocRuleOptionPerfStats;
130
131 #endif
132
133 /* M A C R O S **************************************************/
134
135 /* TCP flags */
136 #define TH_FIN 0x01
137 #define TH_SYN 0x02
138 #define TH_RST 0x04
139 #define TH_PUSH 0x08
140 #define TH_ACK 0x10
141 #define TH_URG 0x20
142 #define TH_ECE 0x40
143 #define TH_CWR 0x80
144 #define TH_NORESERVED (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG)
145
146 /* TCP states */
147 #define TCP_STATE_NONE 0
148 #define TCP_STATE_LISTEN 1
149 #define TCP_STATE_SYN_RCVD 2
150 #define TCP_STATE_SYN_SENT 3
151 #define TCP_STATE_ESTABLISHED 4
152 #define TCP_STATE_CLOSE_WAIT 5
153 #define TCP_STATE_LAST_ACK 6
154 #define TCP_STATE_FIN_WAIT_1 7
155 #define TCP_STATE_CLOSING 8
156 #define TCP_STATE_FIN_WAIT_2 9
157 #define TCP_STATE_TIME_WAIT 10
158 #define TCP_STATE_CLOSED 11
159
160 #ifndef MIN
161 # define MIN(a,b) (((a)<(b)) ? (a):(b))
162 #endif
163 #ifndef MAX
164 # define MAX(a,b) (((a)>(b)) ? (a):(b))
165 #endif
166
167 #define PAWS_WINDOW 60
168 #define PAWS_24DAYS 2147483647 /* 2^ 31 -1 - approx 24 days in milli secs*/
169
170 /* for state transition queuing */
171 #define CHK_SEQ 0
172 #define NO_CHK_SEQ 1
173
174 #define STREAM_UNALIGNED 0
175 #define STREAM_ALIGNED 1
176
177 /* actions */
178 #define ACTION_NOTHING 0x00000000
179 #define ACTION_FLUSH_SENDER_STREAM 0x00000001
180 #define ACTION_FLUSH_RECEIVER_STREAM 0x00000002
181 #define ACTION_DROP_SESSION 0x00000004
182 #define ACTION_ACK_SENDER_DATA 0x00000008
183 #define ACTION_ACK_RECEIVER_DATA 0x00000010
184 #define ACTION_SET_SSN 0x00000040
185 #define ACTION_COMPLETE_TWH 0x00000080
186 #define ACTION_RST 0x00000100
187 #define ACTION_BAD_SEQ 0x00000200
188 #define ACTION_BAD_PKT 0x00000400
189 #define ACTION_LWSSN_CLOSED 0x00000800
190 #define ACTION_DISABLE_INSPECTION 0x00001000
191
192 /* events */
193 #define EVENT_SYN_ON_EST 0x00000001
194 #define EVENT_DATA_ON_SYN 0x00000002
195 #define EVENT_DATA_ON_CLOSED 0x00000004
196 #define EVENT_BAD_TIMESTAMP 0x00000008
197 #define EVENT_BAD_SEGMENT 0x00000010
198 #define EVENT_WINDOW_TOO_LARGE 0x00000020
199 #define EVENT_EXCESSIVE_TCP_OVERLAPS 0x00000040
200 #define EVENT_DATA_AFTER_RESET 0x00000080
201 #define EVENT_SESSION_HIJACK_CLIENT 0x00000100
202 #define EVENT_SESSION_HIJACK_SERVER 0x00000200
203 #define EVENT_DATA_WITHOUT_FLAGS 0x00000400
204 #define EVENT_4WHS 0x00000800
205 #define EVENT_NO_TIMESTAMP 0x00001000
206 #define EVENT_BAD_RST 0x00002000
207 #define EVENT_BAD_FIN 0x00004000
208 #define EVENT_BAD_ACK 0x00008000
209 #define EVENT_DATA_AFTER_RST_RCVD 0x00010000
210 #define EVENT_WINDOW_SLAM 0x00020000
211
212 #define TF_NONE 0x0000
213 #define TF_WSCALE 0x0001
214 #define TF_TSTAMP 0x0002
215 #define TF_TSTAMP_ZERO 0x0004
216 #define TF_MSS 0x0008
217 #define TF_FORCE_FLUSH 0x0010
218 #define TF_PKT_MISSED 0x0020 // sticky
219 #define TF_MISSING_PKT 0x0040 // used internally
220 #define TF_MISSING_PREV_PKT 0x0080 // reset for each reassembled
221 #define TF_FIRST_PKT_MISSING 0x0100
222 #define TF_ALL 0xFFFF
223
224 #define STREAM_INSERT_OK 0
225 #define STREAM_INSERT_ANOMALY 1
226 #define STREAM_INSERT_TIMEOUT 2
227 #define STREAM_INSERT_FAILED 3
228
229 #define STREAM_DEFAULT_TCP_PACKET_MEMCAP 8388608 /* 8MB */
230 #define STREAM_MIN_OVERLAP_LIMIT 0
231 #define STREAM_MAX_OVERLAP_LIMIT 255
232 #define STREAM_MAX_FLUSH_FACTOR 2048
233
234 #define REASSEMBLY_POLICY_FIRST 1
235 #define REASSEMBLY_POLICY_LINUX 2
236 #define REASSEMBLY_POLICY_BSD 3
237 #define REASSEMBLY_POLICY_OLD_LINUX 4
238 #define REASSEMBLY_POLICY_LAST 5
239 #define REASSEMBLY_POLICY_WINDOWS 6
240 #define REASSEMBLY_POLICY_SOLARIS 7
241 #define REASSEMBLY_POLICY_HPUX11 8
242 #define REASSEMBLY_POLICY_IRIX 9
243 #define REASSEMBLY_POLICY_MACOS 10
244 #define REASSEMBLY_POLICY_HPUX10 11
245 #define REASSEMBLY_POLICY_VISTA 12
246 #define REASSEMBLY_POLICY_WINDOWS2K3 13
247 #define REASSEMBLY_POLICY_NOACK 14
248 #define REASSEMBLY_POLICY_DEFAULT REASSEMBLY_POLICY_BSD
249
250 #define SUB_SYN_SENT 0x01
251 #define SUB_ACK_SENT 0x02
252 #define SUB_SETUP_OK 0x03
253 #define SUB_RST_SENT 0x04
254 #define SUB_FIN_SENT 0x08
255
256 // flush types
257 #define STREAM_FT_INTERNAL 0 // normal s5 "footprint"
258 #define STREAM_FT_EXTERNAL 1 // set by other preprocessor
259 #define STREAM_FT_PAF_MAX 2 // paf_max + footprint fp
260
261 #define SLAM_MAX 4
262
263 /* Only track a maximum number of alerts per session */
264 #define MAX_SESSION_ALERTS 8
265
266 //#define STREAM_DEBUG_ENABLED
267 #ifdef STREAM_DEBUG_ENABLED
268 #define STREAM_DEBUG_WRAP(x) DEBUG_WRAP(x)
269 #else
270 #define STREAM_DEBUG_WRAP(x)
271 #endif
272
273 /* client/server ip/port dereference */
274 #define tcp_client_ip scb->client_ip
275 #define tcp_client_port scb->client_port
276 #define tcp_server_ip scb->server_ip
277 #define tcp_server_port scb->server_port
278
279 static uint32_t pkt_snaplen = 0;
280 #define PKT_SNAPLEN 1514
281
282 /* D A T A S T R U C T U R E S ***********************************/
283 typedef struct _TcpDataBlock
284 {
285 uint32_t seq;
286 uint32_t ack;
287 uint32_t win;
288 uint32_t end_seq;
289 uint32_t ts;
290 } TcpDataBlock;
291
292 typedef struct _StateMgr
293 {
294 uint8_t state;
295 uint8_t sub_state;
296 uint8_t state_queue;
297 uint8_t expected_flags;
298 uint32_t transition_seq;
299 uint32_t stq_get_seq;
300 } StateMgr;
301
302 #define RAND_FLUSH_POINTS 64
303
304 //-------------------------------------------------------------------------
305 // extra, extra - read all about it!
306 // -- u2 is the only output plugin that currently supports extra data
307 // -- extra data may be captured before or after alerts
308 // -- extra data may be per packet or persistent (saved on session)
309 //
310 // -- per packet extra data is logged iff we alert on the packet
311 // containing the extra data - u2 drives this
312 // -- an extra data mask is added to Packet to indicate when per packet
313 // extra data is available
314 //
315 // -- persistent extra data must be logged exactly once for each alert
316 // regardless of capture/alert ordering - s5 purge_alerts drives this
317 // -- an extra data mask is added to the session trackers to indicate that
318 // persistent extra data is available
319 //
320 // -- event id and second are added to the session alert trackers so that
321 // the extra data can be correlated with events
322 // -- event id and second are not available when StreamAddSessionAlertTcp
323 // is called; u2 calls StreamUpdateSessionAlertTcp as events are logged
324 // to set these fields
325 //-------------------------------------------------------------------------
326
327 typedef struct _StreamAlertInfo
328 {
329 /* For storing alerts that have already been seen on the session */
330 uint32_t sid;
331 uint32_t gid;
332 uint32_t seq;
333 // if we log extra data, event_* is used to correlate with alert
334 uint32_t event_id;
335 uint32_t event_second;
336 } StreamAlertInfo;
337
338 //-----------------------------------------------------------------
339 // we make a lot of StreamSegments, StreamTrackers, and TcpSessions
340 // so they are organized by member size/alignment requirements to
341 // minimize unused space in the structs.
342 // ... however, use of padding below is critical, adjust if needed
343 //-----------------------------------------------------------------
344
345 typedef struct _StreamSegment
346 {
347 uint8_t *data;
348 uint8_t *payload;
349
350 struct _StreamSegment *prev;
351 struct _StreamSegment *next;
352
353 #ifdef DEBUG
354 int ordinal;
355 #endif
356 struct timeval tv;
357 uint32_t caplen;
358 uint32_t pktlen;
359
360 uint32_t ts;
361 uint32_t seq;
362
363 uint16_t orig_dsize;
364 uint16_t size;
365
366 uint16_t urg_offset;
367
368 uint8_t buffered;
369
370 // this sequence ensures 4-byte alignment of iph in pkt
371 // (only significant if we call the grinder)
372 uint8_t pad1;
373 uint16_t pad2;
374 uint8_t pkt[1]; // variable length
375
376 } StreamSegment;
377
378 typedef struct _StreamTracker
379 {
380 StateMgr s_mgr; /* state tracking goodies */
381 FlushMgr flush_mgr; /* please flush twice, it's a long way to
382 * the bitbucket... */
383
384 // this is intended to be private to s5_paf but is included
385 // directly to avoid the need for allocation; do not directly
386 // manipulate within this module.
387 PAF_State paf_state; // for tracking protocol aware flushing
388
389 StreamAlertInfo alerts[MAX_SESSION_ALERTS]; /* history of alerts */
390
391 StreamTcpPolicy *tcp_policy;
392 StreamSegment *seglist; /* first queued segment */
393 StreamSegment *seglist_tail; /* last queued segment */
394
395 // TBD move out of here since only used per packet?
396 StreamSegment* seglist_next; /* next queued segment to flush */
397
398 StreamSegment *held_segment; /* blocked segment of http connection */
399 #ifdef DEBUG
400 int segment_ordinal;
401 #endif
402 /* Local in the context of these variables means the local part
403 * of the connection. For example, if this particular StreamTracker
404 * was tracking the client side of a connection, the l_unackd value
405 * would represent the client side of the connection's last unacked
406 * sequence number
407 */
408 uint32_t l_unackd; /* local unack'd seq number */
409 uint32_t l_nxt_seq; /* local next expected sequence */
410 uint32_t l_window; /* local receive window */
411
412 uint32_t r_nxt_ack; /* next expected ack from remote side */
413 uint32_t r_win_base; /* remote side window base sequence number
414 * (i.e. the last ack we got) */
415 uint32_t isn; /* initial sequence number */
416 uint32_t ts_last; /* last timestamp (for PAWS) */
417 uint32_t ts_last_pkt; /* last packet timestamp we got */
418
419 uint32_t seglist_base_seq; /* seq of first queued segment */
420 uint32_t seg_count; /* number of current queued segments */
421 uint32_t seg_bytes_total; /* total bytes currently queued */
422 uint32_t seg_bytes_logical; /* logical bytes queued (total - overlaps) */
423 uint32_t total_bytes_queued; /* total bytes queued (life of session) */
424 uint32_t total_segs_queued; /* number of segments queued (life) */
425 uint32_t overlap_count; /* overlaps encountered */
426 uint32_t small_seg_count;
427 uint32_t flush_count; /* number of flushed queued segments */
428 uint32_t xtradata_mask; /* extra data available to log */
429
430 uint16_t os_policy;
431 uint16_t reassembly_policy;
432
433 uint16_t wscale; /* window scale setting */
434 uint16_t mss; /* max segment size */
435 uint16_t flags; /* bitmap flags (TF_xxx) */
436
437 uint8_t mac_addr[6];
438
439 uint8_t alert_count; /* number alerts stored (up to MAX_SESSION_ALERTS) */
440
441 } StreamTracker;
442
443 typedef struct _TcpSession
444 {
445 StreamTracker client;
446 StreamTracker server;
447 SessionControlBlock *scb;
448
449 #ifdef DEBUG
450 struct timeval ssn_time;
451 #endif
452
453 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
454 int32_t ingress_index; /* Index of the inbound interface. */
455 int32_t egress_index; /* Index of the outbound interface. */
456 int32_t ingress_group; /* Index of the inbound group. */
457 int32_t egress_group; /* Index of the outbound group. */
458 uint32_t daq_flags; /* Flags for the packet (DAQ_PKT_FLAG_*) */
459 void *priv_ptr; /* private data pointer. used in pinhole */
460 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
461 uint16_t address_space_id_src;
462 uint16_t address_space_id_dst;
463 #else
464 uint16_t address_space_id;
465 #endif
466 #ifdef HAVE_DAQ_FLOW_ID
467 uint32_t daq_flow_id;
468 #endif
469 #endif
470 uint8_t ecn;
471 bool session_decrypted;
472 uint8_t pp_flags;
473 } TcpSession;
474
475 #define SL_BUF_FLUSHED 1
476
SetupOK(const StreamTracker * st)477 static inline int SetupOK (const StreamTracker* st)
478 {
479 return ( (st->s_mgr.sub_state & SUB_SETUP_OK) == SUB_SETUP_OK );
480 }
481
Stream_NormGetMode(uint16_t reassembly_policy,const SnortConfig * sc,NormFlags nf)482 static inline int Stream_NormGetMode(uint16_t reassembly_policy, const SnortConfig* sc, NormFlags nf)
483 {
484 if ( reassembly_policy == REASSEMBLY_POLICY_NOACK )
485 return NORM_MODE_OFF;
486 return Normalize_GetMode(sc, nf);
487 }
488
SegsToFlush(const StreamTracker * st,unsigned max)489 static inline uint32_t SegsToFlush (const StreamTracker* st, unsigned max)
490 {
491 uint32_t n = st->seg_count - st->flush_count;
492 StreamSegment* s;
493
494 if ( !n || max == 1 )
495 return n;
496
497 n = 0;
498 s = st->seglist;
499
500 while ( s )
501 {
502 if ( !s->buffered && SEQ_LT(s->seq, st->r_win_base) )
503 n++;
504
505 if ( max && n == max )
506 return n;
507
508 s = s->next;
509 }
510 return n;
511 }
512
DataToFlush(const StreamTracker * st)513 static inline bool DataToFlush (const StreamTracker* st)
514 {
515 if ( (st->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL)
516 #ifdef NORMALIZER
517 || (st->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL_IPS)
518 #endif
519 || st->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL_NOACK
520 || st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK
521 )
522 return ( SegsToFlush(st, 1) > 0 );
523
524 #ifdef NORMALIZER
525 if ((st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS) || (st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS_FTP))
526 return ( SegsToFlush(st, 1) > 1 );
527 #endif
528
529 return ( SegsToFlush(st, 2) > 1 );
530 }
531
532 #ifdef REG_TEST
533 int default_ports[] =
534 {
535 21, 23, 25, 42, 53, 80, 110, 111, 135, 136, 137, 139, 143, 445,
536 513, 514, 1433, 1521, 2401, 3306
537 };
538 #define DEFAULT_PORTS_SIZE (int)(sizeof(default_ports)/sizeof(int))
539 #else
540 int *default_ports = 0;
541 #define DEFAULT_PORTS_SIZE 0
542 #endif
543
544 #ifdef TARGET_BASED
545 char *default_protocols[] =
546 {
547 "ftp", "telnet", "smtp", "nameserver", "dns", "http", "pop3", "sunrpc",
548 "dcerpc", "netbios-ssn", "imap", "login", "shell", "mssql", "oracle", "cvs",
549 "mysql"
550 };
551 #endif
552
553 FlushConfig ignore_flush_policy[MAX_PORTS];
554 #ifdef TARGET_BASED
555 FlushConfig ignore_flush_policy_protocol[MAX_PROTOCOL_ORDINAL];
556 #endif
557
558 /* P R O T O T Y P E S ********************************************/
559 static void StreamParseTcpArgs(struct _SnortConfig *, StreamTcpConfig *, char *, StreamTcpPolicy *);
560 static void StreamPrintTcpConfig(StreamTcpPolicy *);
561
562 static void StreamInitPacket();
563 static inline void SetupTcpDataBlock(TcpDataBlock *, Packet *);
564 static int ProcessTcp(SessionControlBlock *, Packet *, TcpDataBlock *,
565 StreamTcpPolicy *, SFXHASH_NODE *);
566 #if OLD_CODE_NOLONGER_USED_DEPENDS_ON_CURRENT_STATE
567 static inline void QueueState(uint8_t, StreamTracker*, uint8_t,
568 uint32_t, uint8_t);
569 static inline int EvalStateQueue(StreamTracker *, uint8_t, uint32_t);
570 #endif
571 static inline int CheckFlushPolicyOnData(
572 StreamTcpConfig *config, TcpSession *, StreamTracker *,
573 StreamTracker *, TcpDataBlock *, Packet *);
574 static inline int CheckFlushPolicyOnAck(
575 StreamTcpConfig *config, TcpSession *, StreamTracker *,
576 StreamTracker *, TcpDataBlock *, Packet *);
577 static void StreamSeglistAddNode(StreamTracker *, StreamSegment *,
578 StreamSegment *);
579 static int StreamSeglistDeleteNode(StreamTracker *, StreamSegment *);
580 static int StreamSeglistDeleteNodeTrim(StreamTracker*, StreamSegment*, uint32_t flush_seq);
581 static int AddStreamNode(StreamTracker *st, Packet *p,
582 TcpDataBlock*,
583 TcpSession *tcpssn,
584 uint16_t len,
585 uint32_t slide,
586 uint32_t trunc,
587 uint32_t seq,
588 StreamSegment *left,
589 StreamSegment **retSeg);
590 static int DupStreamNode(
591 Packet*,
592 StreamTracker*,
593 StreamSegment* left,
594 StreamSegment** retSeg);
595
596 static uint32_t StreamGetWscale(Packet *, uint16_t *);
597 static uint32_t StreamPacketHasWscale(Packet *);
598 static uint32_t StreamGetMss(Packet *, uint16_t *);
599 static uint32_t StreamGetTcpTimestamp(Packet *, uint32_t *, int strip);
600 static int FlushStream(
601 Packet*, StreamTracker *st, uint32_t toSeq, uint8_t *flushbuf,
602 const uint8_t *flushbuf_end);
603 static void TcpSessionCleanup(SessionControlBlock *ssn, int freeApplicationData);
604 static void TcpSessionCleanupWithFreeApplicationData(void *ssn);
605 static void FlushQueuedSegs(SessionControlBlock *ssn, TcpSession *tcpssn);
606
607 int s5TcpStreamSizeInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr);
608 int s5TcpStreamSizeEval(void *p, const uint8_t **cursor, void *dataPtr);
609 void s5TcpStreamSizeCleanup(void *dataPtr);
610 int s5TcpStreamReassembleRuleOptionInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr);
611 int s5TcpStreamReassembleRuleOptionEval(void *p, const uint8_t **cursor, void *dataPtr);
612 void s5TcpStreamReassembleRuleOptionCleanup(void *dataPtr);
613 static inline void ResetFlushMgrs(void);
614 static void targetPolicyIterate(void (*callback)(int));
615 static void policyDecoderFlagsSaveNClear(int policyId);
616 static void policyDecoderFlagsRestore(int policyId);
617 static void policyChecksumFlagsSaveNClear(int policyId);
618 static void policyChecksumFlagsRestore(int policyId);
619 static inline uint16_t GetTcpReassemblyPolicy(int os_policy);
620
621 /* G L O B A L S **************************************************/
622 static SessionCache* tcp_lws_cache = NULL;
623 static Packet *s5_pkt = NULL;
624 static Packet *tcp_cleanup_pkt = NULL;
625 static const uint8_t *s5_pkt_end = NULL;
626 static char midstream_allowed = 0;
627 static Packet *wire_packet = NULL;
628 static uint8_t flush_policy_for_dir = 0;
629
630 /* enum for policy names */
631 static char *reassembly_policy_names[] = {
632 "no policy!",
633 "FIRST",
634 "LINUX",
635 "BSD",
636 "OLD LINUX",
637 "LAST",
638 "WINDOWS",
639 "SOLARIS",
640 "HPUX11",
641 "IRIX",
642 "MACOS",
643 "HPUX10",
644 "WINDOWS VISTA",
645 "WINDOWS 2003"
646 "IPS"
647 };
648
649 #ifdef STREAM_DEBUG_ENABLED
650 static char *state_names[] = {
651 "NONE",
652 "LISTEN",
653 "SYN_RCVD",
654 "SYN_SENT",
655 "ESTABLISHED",
656 "CLOSE_WAIT",
657 "LAST_ACK",
658 "FIN_WAIT_1",
659 "CLOSING",
660 "FIN_WAIT_2",
661 "TIME_WAIT",
662 "CLOSED"
663 };
664 #endif
665
666 static char *flush_policy_names[] = {
667 "None",
668 "Footprint",
669 "Logical",
670 "Response",
671 "Sliding Window",
672 #if 0
673 "Consumed",
674 #endif
675 "Ignore",
676 "Protocol",
677 "Footprint-IPS",
678 "Protocol-IPS",
679 "Footprint-NOACK",
680 "Protocol-NOACK",
681 "Footprint-IPS-FTP",
682 "Disabled"
683 };
684
685 static int s5_tcp_cleanup = 0;
686
687 static uint32_t g_static_points[RAND_FLUSH_POINTS] =
688 { 128, 217, 189, 130, 240, 221, 134, 129,
689 250, 232, 141, 131, 144, 177, 201, 130,
690 230, 190, 177, 142, 130, 200, 173, 129,
691 250, 244, 174, 151, 201, 190, 180, 198,
692 220, 201, 142, 185, 219, 129, 194, 140,
693 145, 191, 197, 183, 199, 220, 231, 245,
694 233, 135, 143, 158, 174, 194, 200, 180,
695 201, 142, 153, 187, 173, 199, 143, 201 };
696
697 /* F U N C T I O N S **********************************************/
GenerateFlushPoint(FlushPointList * flush_point_list)698 static inline uint32_t GenerateFlushPoint(FlushPointList *flush_point_list)
699 {
700 return (rand() % flush_point_list->flush_range) + flush_point_list->flush_base;
701 }
702
InitFlushPointList(FlushPointList * flush_point_list,uint32_t value,uint32_t range,int use_static)703 static inline void InitFlushPointList(FlushPointList *flush_point_list, uint32_t value, uint32_t range, int use_static)
704 {
705 uint32_t i;
706 uint32_t flush_range = range;
707 uint32_t flush_base = value - range/2;
708
709 if (!flush_point_list)
710 return;
711
712 if (!flush_point_list->initialized)
713 {
714 #ifdef REG_TEST
715 const char* sfp = getenv("S5_FPT");
716 // no error checking required - atoi() is sufficient
717 uint32_t cfp = sfp ? atoi(sfp) : 0;
718 if ( cfp < 128 || cfp > 255 ) cfp = 192;
719 #else
720 const uint32_t cfp = 192;
721 #endif
722
723 flush_point_list->flush_range = flush_range;
724 flush_point_list->flush_base = flush_base;
725 #ifndef DYNAMIC_RANDOM_FLUSH_POINTS
726 flush_point_list->current = 0;
727
728 flush_point_list->flush_points = SnortPreprocAlloc(RAND_FLUSH_POINTS, sizeof(uint32_t),
729 PP_STREAM, PP_MEM_CATEGORY_CONFIG);
730 for (i=0;i<RAND_FLUSH_POINTS;i++)
731 {
732 if (snort_conf->run_flags & RUN_FLAG__STATIC_HASH)
733 {
734 if ( i == 0 )
735 LogMessage("WARNING: using constant flush point = %u!\n", cfp);
736 flush_point_list->flush_points[i] = cfp;
737
738 }
739 else if (use_static)
740 {
741 if ( i == 0 )
742 LogMessage("WARNING: using static flush points.\n");
743 flush_point_list->flush_points[i] = g_static_points[i];
744 }
745 else
746 {
747 flush_point_list->flush_points[i] = GenerateFlushPoint(flush_point_list);
748 }
749 }
750 #endif
751 flush_point_list->initialized = 1;
752 }
753 }
754
UpdateFlushMgr(SnortConfig * sc,FlushMgr * mgr,FlushPointList * flush_point_list,uint32_t flags)755 static inline void UpdateFlushMgr( SnortConfig *sc,
756 FlushMgr *mgr, FlushPointList *flush_point_list, uint32_t flags)
757 {
758 if ( mgr->flush_type == STREAM_FT_EXTERNAL )
759 return;
760
761 switch (mgr->flush_policy)
762 {
763 case STREAM_FLPOLICY_FOOTPRINT:
764 case STREAM_FLPOLICY_LOGICAL:
765 break;
766
767 case STREAM_FLPOLICY_PROTOCOL:
768 if ( flags & TF_PKT_MISSED )
769 {
770 mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT;
771 mgr->flush_type = STREAM_FT_PAF_MAX;
772 }
773 break;
774
775 #ifdef NORMALIZER
776 case STREAM_FLPOLICY_FOOTPRINT_IPS:
777 case STREAM_FLPOLICY_FOOTPRINT_IPS_FTP:
778 break;
779
780 case STREAM_FLPOLICY_PROTOCOL_IPS:
781 if ( flags & TF_PKT_MISSED )
782 {
783 mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS;
784 mgr->flush_type = STREAM_FT_PAF_MAX;
785 }
786 break;
787 #endif
788 case STREAM_FLPOLICY_FOOTPRINT_NOACK:
789 break;
790 case STREAM_FLPOLICY_PROTOCOL_NOACK:
791 if ( flags & TF_PKT_MISSED )
792 {
793 mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT_NOACK;
794 mgr->flush_type = STREAM_FT_PAF_MAX;
795 }
796 break;
797 default:
798 return;
799 }
800 /* Ideally, we would call rand() each time, but that
801 * is a performance headache waiting to happen. */
802 #ifdef DYNAMIC_RANDOM_FLUSH_POINTS
803 mgr->flush_pt = GenerateFlushPoint();
804 #else
805 if (flush_point_list)
806 {
807 /* Handle case where it wasn't initialized... */
808 if (flush_point_list->initialized == 0)
809 {
810 InitFlushPointList(flush_point_list, 192, 128, 0);
811 }
812 mgr->flush_pt = flush_point_list->flush_points[flush_point_list->current];
813 flush_point_list->current = (flush_point_list->current+1) % RAND_FLUSH_POINTS;
814 }
815 #endif
816 //Do not reset the last_size for FTP flush policy
817 if(mgr->flush_policy != STREAM_FLPOLICY_FOOTPRINT_IPS_FTP)
818 {
819 mgr->last_size = 0;
820 mgr->last_count = 0;
821 }
822
823 if ( mgr->flush_type == STREAM_FT_PAF_MAX )
824 mgr->flush_pt += ScPafMaxNewConf(sc);
825 }
826
InitFlushMgr(SnortConfig * sc,FlushMgr * mgr,FlushPointList * flush_point_list,uint8_t policy,uint8_t auto_disable)827 static inline void InitFlushMgr( SnortConfig *sc, FlushMgr *mgr, FlushPointList *flush_point_list,
828 uint8_t policy, uint8_t auto_disable)
829 {
830 // if policy is to disable reassembly just set policy in flush manager and
831 // return
832 if( policy == STREAM_FLPOLICY_DISABLED )
833 {
834 mgr->flush_policy = policy;
835 return;
836 }
837 else if ( mgr->flush_policy == STREAM_FLPOLICY_DISABLED )
838 {
839 WarningMessage( "Stream policy has disabled reassembly on this port." );
840 return;
841 }
842
843 mgr->flush_policy = policy;
844 mgr->flush_type = STREAM_FT_INTERNAL;
845 mgr->auto_disable = auto_disable;
846
847 UpdateFlushMgr(sc, mgr, flush_point_list, 0);
848
849 #ifdef NORMALIZER
850 if ( Normalize_GetMode(sc, NORM_TCP_IPS) == NORM_MODE_ON)
851 {
852 if ( policy == STREAM_FLPOLICY_FOOTPRINT )
853 mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS;
854
855 else if ( policy == STREAM_FLPOLICY_PROTOCOL )
856 mgr->flush_policy = STREAM_FLPOLICY_PROTOCOL_IPS;
857 }
858 #endif
859 }
860
InitFlushMgrByPort(SessionControlBlock * scb,StreamTracker * pst,uint16_t port,bool c2s,uint8_t flush_policy,bool all_services)861 static inline void InitFlushMgrByPort (
862 SessionControlBlock* scb, StreamTracker* pst,
863 uint16_t port, bool c2s, uint8_t flush_policy, bool all_services)
864 {
865 uint16_t registration, auto_disable = 0;
866 bool flush = (flush_policy != STREAM_FLPOLICY_IGNORE);
867
868 #if 0
869 // this check required if PAF doesn't abort
870 if ( scb->session_state & STREAM_STATE_MIDSTREAM )
871 registration = 0;
872 else
873 #endif
874 if(all_services)
875 {
876 registration = s5_paf_port_registration_all(
877 ( ( StreamConfig * ) scb->stream_config )->tcp_config->paf_config, port, c2s, flush);
878 }
879 else
880 {
881 registration = s5_paf_port_registration(
882 ( ( StreamConfig * ) scb->stream_config )->tcp_config->paf_config, port, c2s, flush);
883 }
884
885 if ( registration )
886 {
887 if( flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK )
888 flush_policy = STREAM_FLPOLICY_PROTOCOL_NOACK;
889 else
890 flush_policy = STREAM_FLPOLICY_PROTOCOL;
891 s5_paf_setup(&pst->paf_state, registration);
892 auto_disable = !flush;
893 }
894 InitFlushMgr(snort_conf, &pst->flush_mgr,
895 &pst->tcp_policy->flush_point_list, flush_policy, auto_disable);
896 }
897
InitFlushMgrByService(SessionControlBlock * scb,StreamTracker * pst,int16_t service,bool c2s,uint8_t flush_policy)898 static inline void InitFlushMgrByService (
899 SessionControlBlock* scb, StreamTracker* pst,
900 int16_t service, bool c2s, uint8_t flush_policy)
901 {
902 uint16_t registration, auto_disable = 0;
903 bool flush = (flush_policy != STREAM_FLPOLICY_IGNORE);
904
905 #if 0
906 // this check required if PAF doesn't abort
907 if ( scb->session_state & STREAM_STATE_MIDSTREAM )
908 registration = 0;
909 else
910 #endif
911 registration = s5_paf_service_registration(
912 ( ( StreamConfig * ) scb->stream_config )->tcp_config->paf_config, service, c2s, flush);
913
914 if ( registration )
915 {
916 if( flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK )
917 flush_policy = STREAM_FLPOLICY_PROTOCOL_NOACK;
918 else
919 flush_policy = STREAM_FLPOLICY_PROTOCOL;
920 s5_paf_setup(&pst->paf_state, registration);
921 auto_disable = !flush;
922 }
923 InitFlushMgr(snort_conf, &pst->flush_mgr,
924 &pst->tcp_policy->flush_point_list, flush_policy, auto_disable);
925 }
926
ResetFlushMgrsPolicy(tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)927 static int ResetFlushMgrsPolicy(
928 tSfPolicyUserContextId config,
929 tSfPolicyId policyId,
930 void* pData
931 )
932 {
933 int i;
934 StreamConfig *pPolicyConfig = (StreamConfig *)pData;
935
936 //do any housekeeping before freeing StreamConfig
937 if (pPolicyConfig->tcp_config == NULL)
938 return 0;
939
940 for (i = 0; i < pPolicyConfig->tcp_config->num_policies; i++)
941 {
942 int j;
943 StreamTcpPolicy *policy = pPolicyConfig->tcp_config->policy_list[i];
944 FlushPointList *fpl = &policy->flush_point_list;
945 FlushMgr *client, *server;
946 uint8_t flush_policy;
947
948 fpl->current = 0;
949
950 for (j = 0; j < MAX_PORTS; j++)
951 {
952 client = &policy->flush_config[j].client;
953 flush_policy = policy->flush_config[j].client.flush_policy;
954 InitFlushMgr(snort_conf, client, fpl, flush_policy, 0);
955
956 server = &policy->flush_config[j].server;
957 flush_policy = policy->flush_config[j].server.flush_policy;
958 InitFlushMgr(snort_conf, server, fpl, flush_policy, 0);
959 }
960 #ifdef TARGET_BASED
961 /* protocol 0 is the unknown case. skip it */
962 for (j = 1; j < MAX_PROTOCOL_ORDINAL; j++)
963 {
964 client = &policy->flush_config_protocol[j].client;
965 flush_policy = policy->flush_config_protocol[j].client.flush_policy;
966 InitFlushMgr(snort_conf, client, fpl, flush_policy, 0);
967
968 server = &policy->flush_config_protocol[j].server;
969 flush_policy = policy->flush_config_protocol[j].server.flush_policy;
970 InitFlushMgr(snort_conf, server, fpl, flush_policy, 0);
971 }
972 #endif
973 }
974
975 return 0;
976 }
977
ResetFlushMgrs(void)978 static inline void ResetFlushMgrs( void )
979 {
980 if( stream_online_config == NULL )
981 return;
982
983 sfPolicyUserDataFreeIterate( stream_online_config, ResetFlushMgrsPolicy );
984 }
985
StreamGetPAFUserDataTcp(SessionControlBlock * scb,bool to_server,uint8_t id)986 void **StreamGetPAFUserDataTcp( SessionControlBlock* scb, bool to_server, uint8_t id )
987 {
988 TcpSession* tcpssn;
989 PAF_State *ps;
990 int8_t i;
991
992 if(!id)
993 return NULL;
994
995 if( !scb->proto_specific_data )
996 return NULL;
997
998 tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
999
1000 if ( !tcpssn )
1001 return NULL;
1002
1003 ps = ( to_server ) ? &tcpssn->server.paf_state
1004 :
1005 &tcpssn->client.paf_state;
1006
1007 i = s5_paf_get_user_data_index( ps, id );
1008
1009 if( i >= 0 )
1010 return &ps->user[i];
1011 else
1012 return NULL;
1013 }
1014
StreamIsPafActiveTcp(SessionControlBlock * scb,bool to_server)1015 bool StreamIsPafActiveTcp( SessionControlBlock *scb, bool to_server )
1016 {
1017 TcpSession *tcpssn;
1018 FlushMgr *fm;
1019
1020 if( !scb->proto_specific_data )
1021 return false;
1022
1023 tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
1024
1025 if( !tcpssn )
1026 return false;
1027
1028 fm = ( to_server ) ? &tcpssn->server.flush_mgr : &tcpssn->client.flush_mgr;
1029
1030 return ( ( fm->flush_policy == STREAM_FLPOLICY_PROTOCOL )
1031 #ifdef NORMALIZER
1032 || ( fm->flush_policy == STREAM_FLPOLICY_PROTOCOL_IPS )
1033 #endif
1034 || (fm->flush_policy == STREAM_FLPOLICY_PROTOCOL_NOACK)
1035 );
1036 }
1037
StreamActivatePafTcp(SessionControlBlock * scb,int dir,int16_t service_port,uint8_t type)1038 bool StreamActivatePafTcp (SessionControlBlock *scb, int dir, int16_t service_port, uint8_t type)
1039 {
1040 TcpSession *tcpssn;
1041 StreamTracker *trk;
1042 FlushMgr *fm;
1043 uint8_t flush_policy;
1044
1045 if( !scb->proto_specific_data )
1046 return false;
1047
1048 tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
1049
1050 if( !tcpssn || !ScPafEnabled() )
1051 return false;
1052
1053 // must have valid stream config for this session, may need to reset after a reload
1054 if( scb->stream_config == NULL )
1055 {
1056 WarningMessage("Stream Configuration NULL For In Progress Session, Reinitializing.\n");
1057 scb->stream_config = sfPolicyUserDataGet( stream_online_config, getNapRuntimePolicy() );
1058 if( scb->stream_config == NULL )
1059 {
1060 ErrorMessage("No Valid Stream Configurations, Stream Processing Terminated For This Packet.\n");
1061 return false;
1062 }
1063 }
1064
1065 switch ( dir )
1066 {
1067 case SSN_DIR_TO_CLIENT:
1068 {
1069 trk = &tcpssn->client;
1070 fm = &tcpssn->client.flush_mgr;
1071 flush_policy = fm->flush_policy;
1072 if ( flush_policy == STREAM_FLPOLICY_IGNORE )
1073 flush_policy = STREAM_FLPOLICY_PROTOCOL;
1074
1075 if ( type == PAF_TYPE_SERVICE )
1076 {
1077 InitFlushMgrByService(scb, trk, service_port, false, flush_policy);
1078 }
1079 else
1080 {
1081 InitFlushMgrByPort(scb, trk, service_port, false, flush_policy, true);
1082 }
1083 }
1084 break;
1085 case SSN_DIR_TO_SERVER:
1086 {
1087 trk = &tcpssn->server;
1088 fm = &tcpssn->server.flush_mgr;
1089 flush_policy = fm->flush_policy;
1090 if ( flush_policy == STREAM_FLPOLICY_IGNORE )
1091 flush_policy = STREAM_FLPOLICY_PROTOCOL;
1092
1093 if ( type == PAF_TYPE_SERVICE )
1094 {
1095 InitFlushMgrByService(scb, trk, service_port, true, flush_policy);
1096 }
1097 else
1098 {
1099 InitFlushMgrByPort(scb, trk, service_port, true, flush_policy, true );
1100 }
1101 }
1102 break;
1103 case SSN_DIR_BOTH:
1104 {
1105 trk = &tcpssn->server;
1106 fm = &tcpssn->server.flush_mgr;
1107 flush_policy = fm->flush_policy;
1108 if ( flush_policy == STREAM_FLPOLICY_IGNORE )
1109 flush_policy = STREAM_FLPOLICY_PROTOCOL;
1110
1111 if ( type == PAF_TYPE_SERVICE )
1112 {
1113 InitFlushMgrByService(scb, trk, service_port, true, flush_policy);
1114 }
1115 else
1116 {
1117 InitFlushMgrByPort(scb, trk, service_port, true, flush_policy, true );
1118 }
1119 }
1120 {
1121 trk = &tcpssn->client;
1122 fm = &tcpssn->client.flush_mgr;
1123 flush_policy = fm->flush_policy;
1124 if ( flush_policy == STREAM_FLPOLICY_IGNORE )
1125 flush_policy = STREAM_FLPOLICY_PROTOCOL;
1126
1127 if ( type == PAF_TYPE_SERVICE )
1128 {
1129 InitFlushMgrByService(scb, trk, service_port, false, flush_policy);
1130 }
1131 else
1132 {
1133 InitFlushMgrByPort(scb, trk, service_port, false, flush_policy, true);
1134 }
1135 }
1136 break;
1137
1138 default:
1139 return false;
1140 }
1141
1142 return true;
1143 }
1144
StreamResetPolicyPerTrk(StreamTracker * trk,uint16_t policy,uint16_t mss)1145 static inline void StreamResetPolicyPerTrk( StreamTracker* trk, uint16_t policy, uint16_t mss )
1146 {
1147 trk->tcp_policy->policy = trk->os_policy = policy;
1148 trk->reassembly_policy = GetTcpReassemblyPolicy( policy );
1149 trk->mss = mss;
1150 }
1151
StreamResetPolicyTcp(SessionControlBlock * scb,int dir,uint16_t policy,uint16_t mss)1152 void StreamResetPolicyTcp ( SessionControlBlock *scb, int dir, uint16_t policy, uint16_t mss)
1153 {
1154 TcpSession *tcpssn;
1155
1156 if( !scb->proto_specific_data )
1157 return;
1158
1159 tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
1160
1161 if( !tcpssn )
1162 return;
1163
1164 switch( dir )
1165 {
1166 case SSN_DIR_TO_CLIENT:
1167 StreamResetPolicyPerTrk( &tcpssn->client, policy, mss );
1168 break;
1169
1170 case SSN_DIR_TO_SERVER:
1171 StreamResetPolicyPerTrk( &tcpssn->server, policy, mss );
1172 break;
1173
1174 case SSN_DIR_BOTH:
1175 StreamResetPolicyPerTrk( &tcpssn->server, policy, mss );
1176 StreamResetPolicyPerTrk( &tcpssn->client, policy, mss );
1177 break;
1178
1179 default:
1180 break;
1181 }
1182 }
1183
StreamSetSessionDecryptedTcp(SessionControlBlock * scb,bool enable)1184 void StreamSetSessionDecryptedTcp( SessionControlBlock *scb, bool enable )
1185 {
1186 TcpSession *tcpssn;
1187
1188 if( !scb->proto_specific_data )
1189 return;
1190
1191 tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
1192
1193 if ( !tcpssn )
1194 return;
1195
1196 if((SegsToFlush(&tcpssn->server, 1) > 0) || (SegsToFlush(&tcpssn->client, 1) > 0))
1197 {
1198 FlushQueuedSegs(scb, tcpssn);
1199 Active_Reset();
1200 }
1201
1202 tcpssn->session_decrypted = enable;
1203 }
1204
StreamIsSessionDecryptedTcp(SessionControlBlock * scb)1205 bool StreamIsSessionDecryptedTcp( SessionControlBlock *scb )
1206 {
1207 TcpSession *tcpssn;
1208
1209 if( !scb->proto_specific_data )
1210 return false;
1211
1212 tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
1213
1214 if ( !tcpssn )
1215 return false;
1216
1217 return ( tcpssn->session_decrypted == true );
1218 }
1219
StreamGetPreprocFlagsTcp(SessionControlBlock * scb)1220 uint32_t StreamGetPreprocFlagsTcp(SessionControlBlock *scb)
1221 {
1222 TcpSession *tcpssn;
1223
1224 if( !scb->proto_specific_data )
1225 return 0;
1226
1227 tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
1228
1229 if ( !tcpssn )
1230 return 0;
1231
1232 return tcpssn->pp_flags;
1233 }
1234
1235 //-------------------------------------------------------------------------
1236 // tcp ha stuff
1237
1238 #ifdef ENABLE_HA
StreamTCPCreateSession(const SessionKey * key)1239 static SessionControlBlock *StreamTCPCreateSession( const SessionKey *key )
1240 {
1241 setNapRuntimePolicy( getDefaultPolicy() );
1242
1243 /* TODO: Set the TCP policy to something here? */
1244 return session_api->create_session( tcp_lws_cache, NULL, key );
1245 }
1246
StreamTCPDeactivateSession(SessionControlBlock * scb)1247 static void StreamTCPDeactivateSession( SessionControlBlock *scb )
1248 {
1249 if( scb->proto_specific_data )
1250 {
1251 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
1252 "Cleaning up the TCP session associated with the session being put into standby.\n"););
1253 TcpSessionCleanup( scb, 0 );
1254 }
1255
1256 scb->session_state &= ~( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK |
1257 STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED );
1258 scb->ha_state.session_flags &= ~( SSNFLAG_SEEN_CLIENT | SSNFLAG_SEEN_SERVER );
1259 }
1260
StreamTCPDeleteSession(const SessionKey * key)1261 static int StreamTCPDeleteSession( const SessionKey *key )
1262 {
1263 SessionControlBlock *scb = session_api->get_session_by_key( tcp_lws_cache, key );
1264
1265 if( scb != NULL )
1266 {
1267 if( StreamSetRuntimeConfiguration( scb, scb->protocol ) == 0 )
1268 {
1269 if (!session_api->delete_session( tcp_lws_cache, scb, "ha sync", false ))
1270 s5stats.active_tcp_sessions--;
1271 }
1272 else
1273 WarningMessage(" WARNING: Attempt to delete a TCP Session when no valid runtime configuration.\n" );
1274 }
1275
1276 return 0;
1277 }
1278 #endif
1279
GetLWTcpSession(const SessionKey * key)1280 SessionControlBlock *GetLWTcpSession( const SessionKey *key )
1281 {
1282 return session_api->get_session_by_key( tcp_lws_cache, key );
1283 }
1284
1285 #ifdef ENABLE_HA
1286
1287 static HA_Api ha_tcp_api = {
1288 /*.get_lws = */ GetLWTcpSession,
1289
1290 /*.create_session = */ StreamTCPCreateSession,
1291 /*.deactivate_session = */ StreamTCPDeactivateSession,
1292 /*.delete_session = */ StreamTCPDeleteSession,
1293 };
1294
1295 #endif
1296
setTcpDirectionAndPorts(Packet * p,SessionControlBlock * scb)1297 void setTcpDirectionAndPorts( Packet *p, SessionControlBlock *scb )
1298 {
1299 if( TCP_ISFLAGSET( p->tcph, TH_SYN ) && !TCP_ISFLAGSET( p->tcph, TH_ACK ) )
1300 {
1301 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
1302 "Stream SYN PACKET, establishing lightweight session direction.\n"););
1303 /* SYN packet from client */
1304 scb->ha_state.direction = FROM_CLIENT;
1305 IP_COPY_VALUE( scb->client_ip, GET_SRC_IP( p ) );
1306 scb->client_port = p->tcph->th_sport;
1307 IP_COPY_VALUE( scb->server_ip, GET_DST_IP( p ) );
1308 scb->server_port = p->tcph->th_dport;
1309 }
1310 else if( TCP_ISFLAGSET( p->tcph, ( TH_SYN | TH_ACK ) ) )
1311 {
1312 scb->ha_state.direction = FROM_SERVER;
1313 IP_COPY_VALUE( scb->client_ip, GET_DST_IP( p ) );
1314 scb->client_port = p->tcph->th_dport;
1315 IP_COPY_VALUE( scb->server_ip, GET_SRC_IP( p ) );
1316 scb->server_port = p->tcph->th_sport;
1317 }
1318 else
1319 {
1320 /* Assume from client, can update later */
1321 if( p->sp > p->dp )
1322 {
1323 scb->ha_state.direction = FROM_CLIENT;
1324 IP_COPY_VALUE( scb->client_ip, GET_SRC_IP( p ) );
1325 scb->client_port = p->tcph->th_sport;
1326 IP_COPY_VALUE( scb->server_ip, GET_DST_IP( p ) );
1327 scb->server_port = p->tcph->th_dport;
1328 }
1329 else
1330 {
1331 scb->ha_state.direction = FROM_SERVER;
1332 IP_COPY_VALUE( scb->client_ip, GET_DST_IP( p ) );
1333 scb->client_port = p->tcph->th_dport;
1334 IP_COPY_VALUE( scb->server_ip, GET_SRC_IP( p ) );
1335 scb->server_port = p->tcph->th_sport;
1336 }
1337 }
1338 }
StreamInitTcp(void)1339 void StreamInitTcp( void )
1340 {
1341 if( tcp_lws_cache == NULL )
1342 {
1343 tcp_lws_cache = session_api->init_session_cache( SESSION_PROTO_TCP,
1344 sizeof( TcpSession ),
1345 &TcpSessionCleanupWithFreeApplicationData );
1346 StreamTcpRegisterPreprocProfiles();
1347 }
1348 #ifdef ENABLE_HA
1349 ha_set_api( IPPROTO_TCP, &ha_tcp_api );
1350 #endif
1351
1352 pkt_snaplen = (snort_conf->pkt_snaplen > 0) ? snort_conf->pkt_snaplen : PKT_SNAPLEN;
1353 }
1354
StreamTcpRegisterPreprocProfiles(void)1355 void StreamTcpRegisterPreprocProfiles( void )
1356 {
1357 #ifdef PERF_PROFILING
1358 RegisterPreprocessorProfile( "s5TcpNewSess", &s5TcpNewSessPerfStats, 2, &s5TcpPerfStats , NULL);
1359 RegisterPreprocessorProfile( "s5TcpState", &s5TcpStatePerfStats, 2, &s5TcpPerfStats , NULL);
1360 RegisterPreprocessorProfile( "s5TcpData", &s5TcpDataPerfStats, 3, &s5TcpStatePerfStats , NULL);
1361 RegisterPreprocessorProfile( "s5TcpPktInsert", &s5TcpInsertPerfStats, 4, &s5TcpDataPerfStats , NULL);
1362 RegisterPreprocessorProfile( "s5TcpPAF", &s5TcpPAFPerfStats, 3, &s5TcpStatePerfStats , NULL);
1363 RegisterPreprocessorProfile( "s5TcpFlush", &s5TcpFlushPerfStats, 3, &s5TcpStatePerfStats , NULL);
1364 RegisterPreprocessorProfile( "s5TcpBuildPacket", &s5TcpBuildPacketPerfStats, 4, &s5TcpFlushPerfStats , NULL);
1365 RegisterPreprocessorProfile( "s5TcpProcessRebuilt", &s5TcpProcessRebuiltPerfStats,
1366 4, &s5TcpFlushPerfStats, NULL );
1367 #endif
1368 }
1369
StreamTcpRegisterRuleOptions(struct _SnortConfig * sc)1370 void StreamTcpRegisterRuleOptions( struct _SnortConfig *sc )
1371 {
1372 /* Register the 'stream_size' rule option */
1373 RegisterPreprocessorRuleOption( sc, "stream_size", &s5TcpStreamSizeInit,
1374 &s5TcpStreamSizeEval, &s5TcpStreamSizeCleanup,
1375 NULL, NULL, NULL, NULL );
1376
1377 RegisterPreprocessorRuleOption( sc, "stream_reassemble", &s5TcpStreamReassembleRuleOptionInit,
1378 &s5TcpStreamReassembleRuleOptionEval,
1379 &s5TcpStreamReassembleRuleOptionCleanup,
1380 NULL, NULL, NULL, NULL );
1381 #ifdef PERF_PROFILING
1382 RegisterPreprocessorProfile( "stream_size", &streamSizePerfStats, 4, &preprocRuleOptionPerfStats , NULL);
1383 RegisterPreprocessorProfile( "reassemble", &streamReassembleRuleOptionPerfStats,
1384 4, &preprocRuleOptionPerfStats, NULL);
1385 #endif
1386 }
1387
StreamTcpInitFlushPoints(void)1388 void StreamTcpInitFlushPoints( void )
1389 {
1390 int i;
1391
1392 /* Seed the flushpoint random generator */
1393 srand( ( unsigned int ) sizeof( default_ports ) + ( unsigned int ) time( NULL ) );
1394
1395 /* Default is to ignore, for all ports */
1396 for( i = 0; i < MAX_PORTS; i++ )
1397 {
1398 ignore_flush_policy[i].client.flush_policy = STREAM_FLPOLICY_IGNORE;
1399 ignore_flush_policy[i].server.flush_policy = STREAM_FLPOLICY_IGNORE;
1400 }
1401 #ifdef TARGET_BASED
1402 for( i = 0; i < MAX_PROTOCOL_ORDINAL; i++)
1403 {
1404 ignore_flush_policy_protocol[i].client.flush_policy = STREAM_FLPOLICY_IGNORE;
1405 ignore_flush_policy_protocol[i].server.flush_policy = STREAM_FLPOLICY_IGNORE;
1406 }
1407 #endif
1408 }
1409
addStreamTcpPolicyToList(StreamTcpConfig * config,StreamTcpPolicy * policy)1410 static void addStreamTcpPolicyToList( StreamTcpConfig *config, StreamTcpPolicy *policy )
1411 {
1412 config->num_policies++;
1413
1414 /* Now add this context to the internal list */
1415 if( config->policy_list == NULL )
1416 {
1417 config->policy_list = ( StreamTcpPolicy ** ) SnortPreprocAlloc(1,
1418 sizeof( StreamTcpPolicy * ), PP_STREAM,
1419 PP_MEM_CATEGORY_CONFIG);
1420 }
1421 else
1422 {
1423 uint32_t policyListSize = sizeof( StreamTcpPolicy * ) * ( config->num_policies );
1424 StreamTcpPolicy **tmpPolicyList = ( StreamTcpPolicy ** ) SnortPreprocAlloc(1,
1425 policyListSize, PP_STREAM,
1426 PP_MEM_CATEGORY_CONFIG);
1427
1428 // copy the existing policies to new list, free old list and point to new...
1429 memcpy( tmpPolicyList, config->policy_list, policyListSize - sizeof( StreamTcpPolicy * ) );
1430 SnortPreprocFree( config->policy_list, sizeof( StreamTcpPolicy * ), PP_STREAM,
1431 PP_MEM_CATEGORY_CONFIG );
1432 config->policy_list = tmpPolicyList;
1433 }
1434
1435 // add new policy to end of the list
1436 config->policy_list[config->num_policies - 1] = policy;
1437 }
1438
initTcpPolicyInstance(void)1439 StreamTcpPolicy *initTcpPolicyInstance( void )
1440 {
1441 StreamTcpPolicy *tcp_policy = (StreamTcpPolicy *) SnortPreprocAlloc(1,
1442 sizeof(StreamTcpPolicy), PP_STREAM,
1443 PP_MEM_CATEGORY_CONFIG);
1444
1445 /* Initialize flush policy to Ignore */
1446 memcpy(&tcp_policy->flush_config, ignore_flush_policy,
1447 sizeof(FlushConfig) * MAX_PORTS);
1448 #ifdef TARGET_BASED
1449 memcpy(&tcp_policy->flush_config_protocol, ignore_flush_policy_protocol,
1450 sizeof(FlushConfig) * MAX_PROTOCOL_ORDINAL);
1451 #endif
1452
1453 return tcp_policy;
1454 }
1455
StreamTcpPolicyClone(StreamTcpPolicy * master,StreamConfig * config)1456 StreamTcpPolicy *StreamTcpPolicyClone( StreamTcpPolicy *master, StreamConfig *config )
1457 {
1458 StreamTcpPolicy *clone = initTcpPolicyInstance( );
1459
1460 clone->policy = master->policy;
1461 clone->reassembly_policy = master->reassembly_policy;
1462 clone->flags = master->flags;
1463 clone->flush_factor = master->flush_factor;
1464 clone->session_timeout = master->session_timeout;
1465 clone->max_window = master->max_window;
1466 clone->overlap_limit = master->overlap_limit;
1467 clone->hs_timeout = master->hs_timeout;
1468 clone->max_queued_bytes = master->max_queued_bytes;
1469 clone->max_queued_segs = master->max_queued_segs;
1470 clone->max_consec_small_segs = master->max_consec_small_segs;
1471 clone->max_consec_small_seg_size = master->max_consec_small_seg_size;
1472 memcpy(clone->small_seg_ignore, master->small_seg_ignore, sizeof(master->small_seg_ignore));
1473
1474 addStreamTcpPolicyToList( config->tcp_config, clone );
1475
1476 return clone;
1477 }
1478
StreamTcpPolicyInit(struct _SnortConfig * sc,StreamTcpConfig * config,char * args)1479 void StreamTcpPolicyInit(struct _SnortConfig *sc, StreamTcpConfig *config, char *args)
1480 {
1481 StreamTcpPolicy *s5TcpPolicy;
1482
1483 if (config == NULL)
1484 return;
1485
1486 // create list for caching port reassembly requests...
1487 StreamCreateReassemblyPortList( );
1488
1489 s5TcpPolicy = initTcpPolicyInstance( );
1490 StreamParseTcpArgs(sc, config, args, s5TcpPolicy);
1491 addStreamTcpPolicyToList( config, s5TcpPolicy );
1492
1493 if ( ScPafEnabledNewConf(sc) && !config->paf_config )
1494 config->paf_config = s5_paf_new();
1495
1496 // register callback with Session that determines direction and client/server ports
1497 registerDirectionPortCallback( SESSION_PROTO_TCP, setTcpDirectionAndPorts );
1498
1499 StreamPrintTcpConfig(s5TcpPolicy);
1500
1501 #ifdef REG_TEST
1502 LogMessage(" TCP Session Size: %lu\n", (long unsigned int)sizeof(TcpSession));
1503 #endif
1504 }
1505
StreamPolicyIdFromName(char * name)1506 static inline uint16_t StreamPolicyIdFromName(char *name)
1507 {
1508 if (!name)
1509 {
1510 return STREAM_POLICY_DEFAULT;
1511 }
1512
1513 if(!strcasecmp(name, "bsd"))
1514 {
1515 return STREAM_POLICY_BSD;
1516 }
1517 else if(!strcasecmp(name, "old-linux"))
1518 {
1519 return STREAM_POLICY_OLD_LINUX;
1520 }
1521 else if(!strcasecmp(name, "linux"))
1522 {
1523 return STREAM_POLICY_LINUX;
1524 }
1525 else if(!strcasecmp(name, "first"))
1526 {
1527 return STREAM_POLICY_FIRST;
1528 }
1529 else if(!strcasecmp(name, "noack"))
1530 {
1531 return STREAM_POLICY_NOACK;
1532 }
1533 else if(!strcasecmp(name, "last"))
1534 {
1535 return STREAM_POLICY_LAST;
1536 }
1537 else if(!strcasecmp(name, "windows"))
1538 {
1539 return STREAM_POLICY_WINDOWS;
1540 }
1541 else if(!strcasecmp(name, "solaris"))
1542 {
1543 return STREAM_POLICY_SOLARIS;
1544 }
1545 else if(!strcasecmp(name, "win2003") ||
1546 !strcasecmp(name, "win2k3"))
1547 {
1548 return STREAM_POLICY_WINDOWS2K3;
1549 }
1550 else if(!strcasecmp(name, "vista"))
1551 {
1552 return STREAM_POLICY_VISTA;
1553 }
1554 else if(!strcasecmp(name, "hpux") ||
1555 !strcasecmp(name, "hpux11"))
1556 {
1557 return STREAM_POLICY_HPUX11;
1558 }
1559 else if(!strcasecmp(name, "hpux10"))
1560 {
1561 return STREAM_POLICY_HPUX10;
1562 }
1563 else if(!strcasecmp(name, "irix"))
1564 {
1565 return STREAM_POLICY_IRIX;
1566 }
1567 else if(!strcasecmp(name, "macos") ||
1568 !strcasecmp(name, "grannysmith"))
1569 {
1570 return STREAM_POLICY_MACOS;
1571 }
1572 return STREAM_POLICY_DEFAULT; /* BSD is the default */
1573 }
1574
GetTcpReassemblyPolicy(int os_policy)1575 static inline uint16_t GetTcpReassemblyPolicy(int os_policy)
1576 {
1577 switch (os_policy)
1578 {
1579 case STREAM_POLICY_FIRST:
1580 return REASSEMBLY_POLICY_FIRST;
1581 case STREAM_POLICY_LINUX:
1582 return REASSEMBLY_POLICY_LINUX;
1583 case STREAM_POLICY_BSD:
1584 return REASSEMBLY_POLICY_BSD;
1585 case STREAM_POLICY_OLD_LINUX:
1586 return REASSEMBLY_POLICY_OLD_LINUX;
1587 case STREAM_POLICY_LAST:
1588 return REASSEMBLY_POLICY_LAST;
1589 case STREAM_POLICY_WINDOWS:
1590 return REASSEMBLY_POLICY_WINDOWS;
1591 case STREAM_POLICY_SOLARIS:
1592 return REASSEMBLY_POLICY_SOLARIS;
1593 case STREAM_POLICY_WINDOWS2K3:
1594 return REASSEMBLY_POLICY_WINDOWS2K3;
1595 case STREAM_POLICY_VISTA:
1596 return REASSEMBLY_POLICY_VISTA;
1597 case STREAM_POLICY_HPUX11:
1598 return REASSEMBLY_POLICY_HPUX11;
1599 case STREAM_POLICY_HPUX10:
1600 return REASSEMBLY_POLICY_HPUX10;
1601 case STREAM_POLICY_IRIX:
1602 return REASSEMBLY_POLICY_IRIX;
1603 case STREAM_POLICY_MACOS:
1604 return REASSEMBLY_POLICY_MACOS;
1605 case STREAM_POLICY_NOACK:
1606 return REASSEMBLY_POLICY_NOACK;
1607 default:
1608 return REASSEMBLY_POLICY_DEFAULT;
1609 }
1610 }
1611
1612 #define STATIC_FP ((s5TcpPolicy->flags & STREAM_CONFIG_STATIC_FLUSHPOINTS)?1:0)
1613
StreamParseTcpArgs(struct _SnortConfig * sc,StreamTcpConfig * config,char * args,StreamTcpPolicy * s5TcpPolicy)1614 static void StreamParseTcpArgs(struct _SnortConfig *sc, StreamTcpConfig *config, char *args, StreamTcpPolicy *s5TcpPolicy)
1615 {
1616 char **toks;
1617 int num_toks;
1618 int i;
1619 char **stoks = NULL;
1620 int s_toks;
1621 char *endPtr = NULL;
1622 char set_flush_policy = 0;
1623 #ifdef TARGET_BASED
1624 char set_target_flush_policy = 0;
1625 #endif
1626 int reassembly_direction = SSN_DIR_FROM_CLIENT;
1627 int32_t long_val = 0;
1628
1629 s5TcpPolicy->policy = STREAM_POLICY_DEFAULT;
1630 s5TcpPolicy->reassembly_policy = REASSEMBLY_POLICY_DEFAULT;
1631 s5TcpPolicy->session_timeout = STREAM_DEFAULT_SSN_TIMEOUT;
1632 s5TcpPolicy->max_window = 0;
1633 s5TcpPolicy->flags = 0;
1634 s5TcpPolicy->max_queued_bytes = STREAM_DEFAULT_MAX_QUEUED_BYTES;
1635 s5TcpPolicy->max_queued_segs = STREAM_DEFAULT_MAX_QUEUED_SEGS;
1636
1637 s5TcpPolicy->max_consec_small_segs = STREAM_DEFAULT_CONSEC_SMALL_SEGS;
1638 s5TcpPolicy->max_consec_small_seg_size = STREAM_DEFAULT_MAX_SMALL_SEG_SIZE;
1639 s5TcpPolicy->log_asymmetric_traffic = false;
1640
1641 if(args != NULL && strlen(args) != 0)
1642 {
1643 toks = mSplit(args, ",", 0, &num_toks, 0);
1644
1645 for (i = 0; i < num_toks; i++)
1646 {
1647 if(!strcasecmp(toks[i], "use_static_footprint_sizes"))
1648 s5TcpPolicy->flags |= STREAM_CONFIG_STATIC_FLUSHPOINTS;
1649 }
1650
1651 for (i = 0; i < num_toks; i++)
1652 {
1653 int max_s_toks = 1; // set to 0 to disable check
1654 stoks = mSplit(toks[i], " ", 3, &s_toks, 0);
1655
1656 if (s_toks == 0)
1657 {
1658 FatalError("%s(%d) => Missing parameter in Stream TCP config.\n",
1659 file_name, file_line);
1660 }
1661
1662 if(!strcasecmp(stoks[0], "timeout"))
1663 {
1664 if(stoks[1])
1665 {
1666 s5TcpPolicy->session_timeout = strtoul(stoks[1], &endPtr, 10);
1667 }
1668
1669 if (!stoks[1] || (endPtr == &stoks[1][0]) || *endPtr)
1670 {
1671 FatalError("%s(%d) => Invalid timeout in config file. "
1672 "Integer parameter required.\n",
1673 file_name, file_line);
1674 }
1675
1676 if ((s5TcpPolicy->session_timeout > STREAM_MAX_SSN_TIMEOUT) ||
1677 (s5TcpPolicy->session_timeout < STREAM_MIN_SSN_TIMEOUT))
1678 {
1679 FatalError("%s(%d) => Invalid timeout in config file. "
1680 "Must be between %d and %d\n",
1681 file_name, file_line,
1682 STREAM_MIN_SSN_TIMEOUT, STREAM_MAX_SSN_TIMEOUT);
1683 }
1684 max_s_toks = 2;
1685 }
1686 else if(!strcasecmp(stoks[0], "log_asymmetric_traffic"))
1687 {
1688 if(stoks[1])
1689 {
1690 if(!strcasecmp(stoks[1], "no"))
1691 s5TcpPolicy->log_asymmetric_traffic = false;
1692 else if(!strcasecmp(stoks[1], "yes"))
1693 s5TcpPolicy->log_asymmetric_traffic = true;
1694 else
1695 FatalError("%s(%d) => invalid: value must be 'yes' or 'no'\n", file_name, file_line);
1696 }
1697 else
1698 {
1699 FatalError("%s(%d) => 'log_asymmetric_traffic' missing option\n", file_name, file_line);
1700 }
1701 max_s_toks = 2;
1702 }
1703 else if(!strcasecmp(stoks[0], "overlap_limit"))
1704 {
1705 if(stoks[1])
1706 {
1707 long_val = SnortStrtol(stoks[1], &endPtr, 10);
1708 if (errno == ERANGE)
1709 {
1710 errno = 0;
1711 long_val = -1;
1712 }
1713 s5TcpPolicy->overlap_limit = (uint8_t)long_val;
1714 }
1715
1716 if (!stoks[1] || (endPtr == &stoks[1][0]))
1717 {
1718 FatalError("%s(%d) => Invalid overlap limit in config file."
1719 "Integer parameter required\n",
1720 file_name, file_line);
1721 }
1722
1723 if ((long_val > STREAM_MAX_OVERLAP_LIMIT) ||
1724 (long_val < STREAM_MIN_OVERLAP_LIMIT))
1725 {
1726 FatalError("%s(%d) => Invalid overlap limit in config file."
1727 " Must be between %d and %d\n",
1728 file_name, file_line,
1729 STREAM_MIN_OVERLAP_LIMIT, STREAM_MAX_OVERLAP_LIMIT);
1730 }
1731 max_s_toks = 2;
1732 }
1733 else if(!strcasecmp(stoks[0], "detect_anomalies"))
1734 {
1735 s5TcpPolicy->flags |= STREAM_CONFIG_ENABLE_ALERTS;
1736 }
1737 else if(!strcasecmp(stoks[0], "policy"))
1738 {
1739 if(s_toks != 2)
1740 ParseError("Invalid Stream TCP policy option");
1741 s5TcpPolicy->policy = StreamPolicyIdFromName(stoks[1]);
1742
1743 if ((s5TcpPolicy->policy == STREAM_POLICY_DEFAULT) &&
1744 (strcasecmp(stoks[1], "bsd")))
1745 {
1746 /* Default is BSD. If we don't have "bsd", its
1747 * the default and invalid.
1748 */
1749 FatalError("%s(%d) => Bad policy name \"%s\"\n",
1750 file_name, file_line, stoks[1]);
1751 }
1752 s5TcpPolicy->reassembly_policy =
1753 GetTcpReassemblyPolicy(s5TcpPolicy->policy);
1754
1755 max_s_toks = 2;
1756 }
1757 else if(!strcasecmp(stoks[0], "require_3whs"))
1758 {
1759 s5TcpPolicy->flags |= STREAM_CONFIG_REQUIRE_3WHS;
1760
1761 if (s_toks > 1)
1762 {
1763 s5TcpPolicy->hs_timeout = SnortStrtoul(stoks[1], &endPtr, 10);
1764
1765 if ((endPtr == &stoks[1][0]) || (*endPtr != '\0') || (errno == ERANGE))
1766 {
1767 FatalError("%s(%d) => Invalid 3Way Handshake allowable. Integer parameter required.\n",
1768 file_name, file_line);
1769 }
1770
1771 if (s5TcpPolicy->hs_timeout > STREAM_MAX_SSN_TIMEOUT)
1772 {
1773 FatalError("%s(%d) => Invalid handshake timeout in "
1774 "config file. Must be between %d and %d\n",
1775 file_name, file_line,
1776 STREAM_MIN_ALT_HS_TIMEOUT, STREAM_MAX_SSN_TIMEOUT);
1777 }
1778 }
1779
1780 max_s_toks = 2;
1781 }
1782 else if(!strcasecmp(stoks[0], "bind_to"))
1783 {
1784 if (s_toks < 2)
1785 {
1786 FatalError("%s(%d) => Invalid Stream TCP Policy option - "
1787 "\"bind_to\" option requires an argument.\n",
1788 file_name, file_line);
1789 }
1790
1791 if(strstr(stoks[1], "["))
1792 {
1793 FatalError("%s(%d) => Invalid Stream TCP Policy option. IP lists are not allowed.\n",
1794 file_name, file_line);
1795 }
1796
1797 s5TcpPolicy->bound_addrs = IpAddrSetParse(sc, stoks[1]);
1798 max_s_toks = 2;
1799 }
1800 else if(!strcasecmp(stoks[0], "max_window"))
1801 {
1802 if(stoks[1])
1803 {
1804 long_val = SnortStrtol(stoks[1], &endPtr, 10);
1805 if (errno == ERANGE)
1806 {
1807 errno = 0;
1808 FatalError("%s(%d) => Invalid Max Window size. Integer parameter required.\n",
1809 file_name, file_line);
1810 }
1811 s5TcpPolicy->max_window = (uint32_t)long_val;
1812 }
1813
1814 if (!stoks[1] || (endPtr == &stoks[1][0]))
1815 {
1816 FatalError("%s(%d) => Invalid Max Window size. Integer parameter required.\n",
1817 file_name, file_line);
1818 }
1819
1820 if ((long_val > STREAM_MAX_MAX_WINDOW) ||
1821 (long_val < STREAM_MIN_MAX_WINDOW))
1822 {
1823 FatalError("%s(%d) => Invalid Max Window size."
1824 " Must be between %d and %d\n",
1825 file_name, file_line,
1826 STREAM_MIN_MAX_WINDOW, STREAM_MAX_MAX_WINDOW);
1827 }
1828 max_s_toks = 2;
1829 }
1830 else if(!strcasecmp(stoks[0], "use_static_footprint_sizes"))
1831 {
1832 // we already handled this one above
1833 }
1834 else if(!strcasecmp(stoks[0], "flush_factor"))
1835 {
1836 if (stoks[1])
1837 {
1838 s5TcpPolicy->flush_factor = (uint16_t)SnortStrtoulRange(
1839 stoks[1], &endPtr, 10, 0, STREAM_MAX_FLUSH_FACTOR);
1840 }
1841 if (
1842 (!stoks[1] || (endPtr == &stoks[1][0])) ||
1843 (s5TcpPolicy->flush_factor > STREAM_MAX_FLUSH_FACTOR))
1844 {
1845 FatalError("%s(%d) => 'flush_factor %d' invalid: "
1846 "value must be between 0 and %d segments.\n",
1847 file_name, file_line, s5TcpPolicy->flush_factor,
1848 STREAM_MAX_FLUSH_FACTOR);
1849 }
1850 max_s_toks = 2;
1851 }
1852 else if(!strcasecmp(stoks[0], "dont_store_large_packets"))
1853 {
1854 s5TcpPolicy->flags |= STREAM_CONFIG_PERFORMANCE;
1855 }
1856 else if(!strcasecmp(stoks[0], "check_session_hijacking"))
1857 {
1858 s5TcpPolicy->flags |= STREAM_CONFIG_CHECK_SESSION_HIJACKING;
1859 }
1860 else if(!strcasecmp(stoks[0], "ignore_any_rules"))
1861 {
1862 s5TcpPolicy->flags |= STREAM_CONFIG_IGNORE_ANY;
1863 }
1864 else if(!strcasecmp(stoks[0], "dont_reassemble_async"))
1865 {
1866 s5TcpPolicy->flags |= STREAM_CONFIG_NO_ASYNC_REASSEMBLY;
1867 }
1868 else if(!strcasecmp(stoks[0], "max_queued_bytes"))
1869 {
1870 if(stoks[1])
1871 {
1872 long_val = SnortStrtol(stoks[1], &endPtr, 10);
1873 if (errno == ERANGE)
1874 {
1875 errno = 0;
1876 FatalError("%s(%d) => Invalid Max Queued Bytes. Integer parameter required.\n",
1877 file_name, file_line);
1878 }
1879 s5TcpPolicy->max_queued_bytes = (uint32_t)long_val;
1880 }
1881
1882 if (!stoks[1] || (endPtr == &stoks[1][0]))
1883 {
1884 FatalError("%s(%d) => Invalid Max Queued Bytes. Integer parameter required.\n",
1885 file_name, file_line);
1886 }
1887 if (((long_val > STREAM_MAX_MAX_QUEUED_BYTES) ||
1888 (long_val < STREAM_MIN_MAX_QUEUED_BYTES)) &&
1889 (long_val != 0))
1890 {
1891 FatalError("%s(%d) => Invalid Max Queued Bytes."
1892 " Must be 0 (disabled) or between %d and %d\n",
1893 file_name, file_line,
1894 STREAM_MIN_MAX_QUEUED_BYTES, STREAM_MAX_MAX_QUEUED_BYTES);
1895 }
1896 max_s_toks = 2;
1897 }
1898 else if(!strcasecmp(stoks[0], "max_queued_segs"))
1899 {
1900 if(stoks[1])
1901 {
1902 long_val = SnortStrtol(stoks[1], &endPtr, 10);
1903 if (errno == ERANGE)
1904 {
1905 errno = 0;
1906 FatalError("%s(%d) => Invalid Max Queued Bytes. Integer parameter required.\n",
1907 file_name, file_line);
1908 }
1909 s5TcpPolicy->max_queued_segs = (uint32_t)long_val;
1910 }
1911
1912 if (!stoks[1] || (endPtr == &stoks[1][0]))
1913 {
1914 FatalError("%s(%d) => Invalid Max Queued Bytes. Integer parameter required.\n",
1915 file_name, file_line);
1916 }
1917
1918 if (((long_val > STREAM_MAX_MAX_QUEUED_SEGS) ||
1919 (long_val < STREAM_MIN_MAX_QUEUED_SEGS)) &&
1920 (long_val != 0))
1921 {
1922 FatalError("%s(%d) => Invalid Max Queued Bytes."
1923 " Must be 0 (disabled) or between %d and %d\n",
1924 file_name, file_line,
1925 STREAM_MIN_MAX_QUEUED_SEGS, STREAM_MAX_MAX_QUEUED_SEGS);
1926 }
1927 max_s_toks = 2;
1928 }
1929 else if (!strcasecmp(stoks[0], "small_segments"))
1930 {
1931 char **ptoks;
1932 int num_ptoks;
1933
1934 /* Small segments takes at least 3 parameters... */
1935 if (s_toks < 3)
1936 {
1937 FatalError("%s(%d) => Insufficient parameters to small "
1938 "segments configuration. Syntax is: "
1939 "<number> bytes <number> ignore_ports p1 p2, "
1940 "with ignore_ports being an optional parameter\n",
1941 file_name, file_line);
1942 }
1943
1944 /* first the number of consecutive segments */
1945 long_val = SnortStrtol(stoks[1], &endPtr, 10);
1946 if (errno == ERANGE)
1947 {
1948 errno = 0;
1949 FatalError("%s(%d) => Invalid Small Segment number. Integer parameter required.\n",
1950 file_name, file_line);
1951 }
1952 s5TcpPolicy->max_consec_small_segs = (uint32_t)long_val;
1953
1954 if ((long_val > STREAM_MAX_CONSEC_SMALL_SEGS) ||
1955 (long_val < STREAM_MIN_CONSEC_SMALL_SEGS))
1956 {
1957 FatalError("%s(%d) => Invalid Small Segments."
1958 " Must be integer between %d and %d, inclusive\n",
1959 file_name, file_line,
1960 STREAM_MIN_CONSEC_SMALL_SEGS, STREAM_MAX_CONSEC_SMALL_SEGS);
1961 }
1962
1963 ptoks = mSplit(stoks[2], " ", MAX_PORTS + 3, &num_ptoks, 0);
1964
1965 /* the bytes keyword */
1966 if (strcasecmp(ptoks[0], "bytes") || (num_ptoks < 2))
1967 {
1968 FatalError("%s(%d) => Insufficient parameters to small "
1969 "segments configuration. Syntax is: "
1970 "<number> bytes <number> ignore_ports p1 p2, "
1971 "with ignore_ports being an optional parameter\n",
1972 file_name, file_line);
1973 }
1974
1975 /* the minimum bytes for a segment to be considered "small" */
1976 long_val = SnortStrtol(ptoks[1], &endPtr, 10);
1977 if (errno == ERANGE)
1978 {
1979 errno = 0;
1980 FatalError("%s(%d) => Invalid Small Segment bytes. Integer parameter required.\n",
1981 file_name, file_line);
1982 }
1983 s5TcpPolicy->max_consec_small_seg_size = (uint32_t)long_val;
1984
1985 if ((long_val > STREAM_MAX_MAX_SMALL_SEG_SIZE) ||
1986 (long_val < STREAM_MIN_MAX_SMALL_SEG_SIZE))
1987 {
1988 FatalError("%s(%d) => Invalid Small Segments bytes."
1989 " Must be integer between %d and %d, inclusive\n",
1990 file_name, file_line,
1991 STREAM_MIN_MAX_SMALL_SEG_SIZE, STREAM_MAX_MAX_SMALL_SEG_SIZE);
1992 }
1993
1994 /* and the optional ignore_ports */
1995 if (num_ptoks > 2)
1996 {
1997 int j;
1998 unsigned short port = 0;
1999 long long_port = 0;
2000 if (strcasecmp(ptoks[2], "ignore_ports") || (num_ptoks < 4))
2001 {
2002 FatalError("%s(%d) => Insufficient parameters to small "
2003 "segments configuration. Syntax is: "
2004 "<number> bytes <number> ignore_ports p1 p2, "
2005 "with ignore_ports being an optional parameter\n",
2006 file_name, file_line);
2007 }
2008
2009 for (j=3; j<num_ptoks;j++)
2010 {
2011 if (ptoks[j])
2012 {
2013 long_port = strtol(ptoks[j], &endPtr, 10);
2014 }
2015 if (!ptoks[j] || (endPtr == &ptoks[j][0]))
2016 {
2017 FatalError("%s(%d) => Invalid Port for small segments ignore_ports parameter. Integer parameter required.\n",
2018 file_name, file_line);
2019 }
2020
2021 if ((long_port < 0) || (long_port > MAX_PORTS-1))
2022 {
2023 FatalError(
2024 "%s(%d) => Invalid port %ld for small segments ignore_ports "
2025 "parameter, must be between 0 and %d, inclusive\n",
2026 file_name, file_line, long_port, MAX_PORTS-1);
2027 }
2028 port = (unsigned short)long_port;
2029
2030 s5TcpPolicy->small_seg_ignore[port/8] |= (1 << (port %8));
2031 }
2032 }
2033 max_s_toks = 0; // we already checked all tokens
2034 mSplitFree(&ptoks, num_ptoks);
2035 }
2036 else if (!strcasecmp(stoks[0], "ports"))
2037 {
2038 if (s_toks > 1)
2039 {
2040 if(!strcasecmp(stoks[1], "client"))
2041 {
2042 reassembly_direction = SSN_DIR_FROM_CLIENT;
2043 }
2044 else if(!strcasecmp(stoks[1], "server"))
2045 {
2046 reassembly_direction = SSN_DIR_FROM_SERVER;
2047 }
2048 else if(!strcasecmp(stoks[1], "both"))
2049 {
2050 reassembly_direction = SSN_DIR_BOTH;
2051 }
2052 else
2053 {
2054 FatalError(
2055 "%s(%d) => Invalid direction for reassembly "
2056 "configuration \"%s\". Valid values are 'client', "
2057 "'server', or 'both'.\n",
2058 file_name, file_line, stoks[1]);
2059 }
2060 }
2061
2062 if (s_toks > 2)
2063 {
2064 char **ptoks;
2065 int num_ptoks;
2066 int j;
2067 unsigned short port = 0;
2068 long long_port = 0;
2069
2070 /* Initialize it if not already... */
2071 InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP);
2072
2073 if (!strcasecmp(stoks[2], "all"))
2074 {
2075 for (j=0; j<MAX_PORTS; j++)
2076 {
2077 if (reassembly_direction & SSN_DIR_FROM_CLIENT)
2078 {
2079 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].client;
2080 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2081 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2082 }
2083 if (reassembly_direction & SSN_DIR_FROM_SERVER)
2084 {
2085 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].server;
2086 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2087 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2088 }
2089 }
2090 }
2091 else if (!strcasecmp(stoks[2], "none"))
2092 {
2093 for (j=0; j<MAX_PORTS; j++)
2094 {
2095 if (reassembly_direction & SSN_DIR_FROM_CLIENT)
2096 {
2097 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].client;
2098 flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE;
2099 }
2100 if (reassembly_direction & SSN_DIR_FROM_SERVER)
2101 {
2102 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].server;
2103 flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE;
2104 }
2105 }
2106 }
2107 else
2108 {
2109 ptoks = mSplit(stoks[2], " ", MAX_PORTS, &num_ptoks, 0);
2110
2111 for (j=0; j < num_ptoks; j++)
2112 {
2113 FlushPolicy flush_policy = STREAM_FLPOLICY_FOOTPRINT;
2114
2115 if (ptoks[j])
2116 {
2117 // check for '!' not port syntax used to disable reassembly on a port
2118 // even if requested later by a preproc...
2119 if ( ptoks[j][0] == '!' )
2120 {
2121 flush_policy = STREAM_FLPOLICY_DISABLED;
2122 long_port = strtol(&ptoks[j][1], &endPtr, 10);
2123 }
2124 else
2125 {
2126 long_port = strtol(ptoks[j], &endPtr, 10);
2127 }
2128 }
2129
2130 if (!ptoks[j] || (endPtr == &ptoks[j][0]))
2131 {
2132 FatalError("%s(%d) => Invalid Port list. Integer parameter required.\n",
2133 file_name, file_line);
2134 }
2135
2136 if ((long_port < 0) || (long_port > MAX_PORTS-1))
2137 {
2138 FatalError(
2139 "%s(%d) => Invalid port %ld, must be between 0 and %d, "
2140 "inclusive\n",
2141 file_name, file_line, long_port, MAX_PORTS-1);
2142 }
2143 port = (unsigned short)long_port;
2144
2145 if (reassembly_direction & SSN_DIR_FROM_CLIENT)
2146 {
2147 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[port].client;
2148 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2149 InitFlushMgr(sc, flush_mgr, flush_point_list, flush_policy, 0);
2150 }
2151 if (reassembly_direction & SSN_DIR_FROM_SERVER)
2152 {
2153 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[port].server;
2154 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2155 InitFlushMgr(sc, flush_mgr, flush_point_list, flush_policy, 0);
2156 }
2157 }
2158 mSplitFree(&ptoks, num_ptoks);
2159 }
2160 set_flush_policy = 1;
2161 }
2162 max_s_toks = 0; // we already checked all tokens
2163 }
2164 #ifdef TARGET_BASED
2165 else if (!strcasecmp(stoks[0], "protocol"))
2166 {
2167 if (s_toks > 1)
2168 {
2169 if(!strcasecmp(stoks[1], "client"))
2170 {
2171 reassembly_direction = SSN_DIR_FROM_CLIENT;
2172 }
2173 else if(!strcasecmp(stoks[1], "server"))
2174 {
2175 reassembly_direction = SSN_DIR_FROM_SERVER;
2176 }
2177 else if(!strcasecmp(stoks[1], "both"))
2178 {
2179 reassembly_direction = SSN_DIR_BOTH;
2180 }
2181 else
2182 {
2183 FatalError(
2184 "%s(%d) => Invalid direction for reassembly "
2185 "configuration \"%s\". Valid values are 'client', "
2186 "'server', or 'both'.\n",
2187 file_name, file_line, stoks[1]);
2188 }
2189 }
2190
2191 if (s_toks > 2)
2192 {
2193 char **ptoks;
2194 int num_ptoks;
2195 int j;
2196
2197 /* Initialize it if not already... */
2198 InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP);
2199
2200 if (!strcasecmp(stoks[2], "all"))
2201 {
2202 for (j=1; j<MAX_PROTOCOL_ORDINAL; j++)
2203 {
2204 if (reassembly_direction & SSN_DIR_FROM_CLIENT)
2205 {
2206 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].client;
2207 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2208 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2209 }
2210 if (reassembly_direction & SSN_DIR_FROM_SERVER)
2211 {
2212 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].server;
2213 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2214 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2215 }
2216 s5TcpPolicy->flush_config_protocol[j].configured = 1;
2217 }
2218 }
2219 else if (!strcasecmp(stoks[2], "none"))
2220 {
2221 for (j=1; j<MAX_PROTOCOL_ORDINAL; j++)
2222 {
2223 if (reassembly_direction & SSN_DIR_FROM_CLIENT)
2224 {
2225 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].client;
2226 flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE;
2227 }
2228 if (reassembly_direction & SSN_DIR_FROM_SERVER)
2229 {
2230 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].server;
2231 flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE;
2232 }
2233 s5TcpPolicy->flush_config_protocol[j].configured = 1;
2234 }
2235 }
2236 else
2237 {
2238 ptoks = mSplit(stoks[2], " ", MAX_PROTOCOL_ORDINAL, &num_ptoks, 0);
2239
2240 for (j=0;j<num_ptoks;j++)
2241 {
2242 int16_t proto_ordinal;
2243 if (!ptoks[j])
2244 {
2245 FatalError("%s(%d) => Invalid Protocol Name. Protocol name must be specified.\n",
2246 file_name, file_line);
2247 }
2248 /* First look it up */
2249 proto_ordinal = FindProtocolReference(ptoks[j]);
2250 if (proto_ordinal == SFTARGET_UNKNOWN_PROTOCOL)
2251 {
2252 /* Not known -- add it */
2253 proto_ordinal = AddProtocolReference(ptoks[j]);
2254 if (proto_ordinal == SFTARGET_UNKNOWN_PROTOCOL)
2255 {
2256 FatalError("%s(%d) => Failed to find protocol reference for '%s'\n",
2257 file_name, file_line, ptoks[j]);
2258 }
2259 }
2260
2261 if (reassembly_direction & SSN_DIR_FROM_CLIENT)
2262 {
2263 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[proto_ordinal].client;
2264 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2265 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2266 }
2267 if (reassembly_direction & SSN_DIR_FROM_SERVER)
2268 {
2269 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[proto_ordinal].server;
2270 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2271 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2272 }
2273 s5TcpPolicy->flush_config_protocol[proto_ordinal].configured = 1;
2274 }
2275 mSplitFree(&ptoks, num_ptoks);
2276 }
2277 set_target_flush_policy = 1;
2278 }
2279 max_s_toks = 0; // we already checked all tokens
2280 }
2281 #endif
2282 else
2283 {
2284 FatalError("%s(%d) => Invalid Stream TCP policy option\n",
2285 file_name, file_line);
2286 }
2287
2288 if ( max_s_toks && (s_toks > max_s_toks) )
2289 {
2290 FatalError("%s(%d) => Invalid Stream TCP Policy option. Missing comma?\n",
2291 file_name, file_line);
2292 }
2293 mSplitFree(&stoks, s_toks);
2294 }
2295
2296 mSplitFree(&toks, num_toks);
2297 }
2298
2299 if (s5TcpPolicy->bound_addrs == NULL)
2300 {
2301 if (config->default_policy != NULL)
2302 {
2303 FatalError("%s(%d) => Default Stream TCP Policy already set. "
2304 "This policy must be bound to a specific host or "
2305 "network.\n", file_name, file_line);
2306 }
2307
2308 config->default_policy = s5TcpPolicy;
2309 }
2310 else
2311 {
2312 if (s5TcpPolicy->flags & STREAM_CONFIG_IGNORE_ANY)
2313 {
2314 FatalError("%s(%d) => \"ignore_any_rules\" option can be used only"
2315 " with Default Stream TCP Policy\n", file_name, file_line);
2316 }
2317 }
2318
2319 if (!set_flush_policy)
2320 {
2321 /* Initialize it if not already... */
2322 InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP);
2323 for (i=0; i<DEFAULT_PORTS_SIZE; i++)
2324 {
2325 if (reassembly_direction & SSN_DIR_FROM_CLIENT)
2326 {
2327 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[default_ports[i]].client;
2328 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2329 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2330 }
2331 if (reassembly_direction & SSN_DIR_FROM_SERVER)
2332 {
2333 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[default_ports[i]].server;
2334 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2335 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2336 }
2337 }
2338 }
2339
2340 #ifdef TARGET_BASED
2341 if (!set_target_flush_policy)
2342 {
2343 int app_id;
2344 /* Initialize it if not already... */
2345 InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP);
2346 for (i=0; i<(int)(sizeof(default_protocols)/sizeof(char *)); i++)
2347 {
2348 /* Look up the protocol by name. Add it if it doesn't exist. */
2349 app_id = FindProtocolReference(default_protocols[i]);
2350 if (app_id == SFTARGET_UNKNOWN_PROTOCOL)
2351 {
2352 app_id = AddProtocolReference(default_protocols[i]);
2353 }
2354
2355 /* While this should never happen, I don't feel guilty adding this
2356 * logic as it executes at parse time. */
2357 if (app_id == SFTARGET_UNKNOWN_PROTOCOL)
2358 continue;
2359
2360 /* Set flush managers. */
2361 if (reassembly_direction & SSN_DIR_FROM_CLIENT)
2362 {
2363 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[app_id].client;
2364 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2365 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2366 }
2367 if (reassembly_direction & SSN_DIR_FROM_SERVER)
2368 {
2369 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[app_id].server;
2370 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
2371 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
2372 }
2373 s5TcpPolicy->flush_config_protocol[app_id].configured = 1;
2374 }
2375 }
2376 #endif
2377 }
2378
StreamPrintTcpConfig(StreamTcpPolicy * s5TcpPolicy)2379 static void StreamPrintTcpConfig(StreamTcpPolicy *s5TcpPolicy)
2380 {
2381 int i=0, j=0;
2382 LogMessage("Stream TCP Policy config:\n");
2383 if (s5TcpPolicy->bound_addrs != NULL)
2384 {
2385 IpAddrSetPrint(" Bound Addresses: ", s5TcpPolicy->bound_addrs);
2386 }
2387 else
2388 {
2389 LogMessage(" Bound Address: default\n");
2390 }
2391 LogMessage(" Reassembly Policy: %s\n",
2392 reassembly_policy_names[s5TcpPolicy->reassembly_policy]);
2393 LogMessage(" Timeout: %d seconds\n", s5TcpPolicy->session_timeout);
2394 if (s5TcpPolicy->max_window != 0)
2395 LogMessage(" Max TCP Window: %u\n", s5TcpPolicy->max_window);
2396 if (s5TcpPolicy->overlap_limit)
2397 LogMessage(" Limit on TCP Overlaps: %d\n", s5TcpPolicy->overlap_limit);
2398 if (s5TcpPolicy->max_queued_bytes != 0)
2399 {
2400 LogMessage(" Maximum number of bytes to queue per session: %d\n",
2401 s5TcpPolicy->max_queued_bytes);
2402 }
2403 if (s5TcpPolicy->max_queued_segs != 0)
2404 {
2405 LogMessage(" Maximum number of segs to queue per session: %d\n",
2406 s5TcpPolicy->max_queued_segs);
2407 }
2408 if (s5TcpPolicy->flags)
2409 {
2410 LogMessage(" Options:\n");
2411 if (s5TcpPolicy->flags & STREAM_CONFIG_REQUIRE_3WHS)
2412 {
2413 LogMessage(" Require 3-Way Handshake: YES\n");
2414 if (s5TcpPolicy->hs_timeout != 0)
2415 {
2416 LogMessage(" 3-Way Handshake Timeout: %d\n",
2417 s5TcpPolicy->hs_timeout);
2418 }
2419 }
2420 if (s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS)
2421 {
2422 LogMessage(" Detect Anomalies: YES\n");
2423 }
2424 if (s5TcpPolicy->flags & STREAM_CONFIG_STATIC_FLUSHPOINTS)
2425 {
2426 LogMessage(" Static Flushpoint Sizes: YES\n");
2427 }
2428 if (s5TcpPolicy->flags & STREAM_CONFIG_PERFORMANCE)
2429 {
2430 LogMessage(" Don't Queue Large Packets for Reassembly: YES\n");
2431 }
2432 if (s5TcpPolicy->flags & STREAM_CONFIG_CHECK_SESSION_HIJACKING)
2433 {
2434 LogMessage(" Check for TCP Session Hijacking: YES\n");
2435 }
2436 if (s5TcpPolicy->flags & STREAM_CONFIG_IGNORE_ANY)
2437 {
2438 LogMessage(" Ignore Any -> Any Rules: YES\n");
2439 }
2440 if (s5TcpPolicy->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY)
2441 {
2442 LogMessage(" Don't queue packets on one-sided sessions: YES\n");
2443 }
2444 }
2445 LogMessage(" Reassembly Ports:\n");
2446 for (i=0; i<MAX_PORTS; i++)
2447 {
2448 int direction = 0;
2449 int client_flushpolicy = s5TcpPolicy->flush_config[i].client.flush_policy;
2450 int server_flushpolicy = s5TcpPolicy->flush_config[i].server.flush_policy;
2451 char client_policy_str[STD_BUF];
2452 char server_policy_str[STD_BUF];
2453 client_policy_str[0] = server_policy_str[0] = '\0';
2454
2455 if (client_flushpolicy != STREAM_FLPOLICY_IGNORE)
2456 {
2457 direction |= SSN_DIR_FROM_CLIENT;
2458
2459 if (client_flushpolicy < STREAM_FLPOLICY_MAX)
2460 SnortSnprintf(client_policy_str, STD_BUF, "client (%s)",
2461 flush_policy_names[client_flushpolicy]);
2462 }
2463 if (server_flushpolicy != STREAM_FLPOLICY_IGNORE)
2464 {
2465 direction |= SSN_DIR_FROM_SERVER;
2466
2467 if (server_flushpolicy < STREAM_FLPOLICY_MAX)
2468 SnortSnprintf(server_policy_str, STD_BUF, "server (%s)",
2469 flush_policy_names[server_flushpolicy]);
2470 }
2471 if (direction)
2472 {
2473 if (j<MAX_PORTS_TO_PRINT)
2474 {
2475 LogMessage(" %d %s %s\n", i,
2476 client_policy_str, server_policy_str);
2477 }
2478 j++;
2479 }
2480 }
2481
2482 if (j > MAX_PORTS_TO_PRINT)
2483 {
2484 LogMessage(" additional ports configured but not printed.\n");
2485 }
2486 }
2487
2488 #ifdef TARGET_BASED
StreamPolicyIdFromHostAttributeEntry(HostAttributeEntry * host_entry)2489 int StreamPolicyIdFromHostAttributeEntry(HostAttributeEntry *host_entry)
2490 {
2491 if (!host_entry)
2492 return 0;
2493
2494 host_entry->hostInfo.streamPolicy = StreamPolicyIdFromName(host_entry->hostInfo.streamPolicyName);
2495 host_entry->hostInfo.streamPolicySet = 1;
2496
2497 STREAM_DEBUG_WRAP(
2498 DebugMessage(DEBUG_STREAM_STATE,
2499 "STREAM INIT: %s(%d) for Entry %s\n",
2500 reassembly_policy_names[host_entry->hostInfo.streamPolicy],
2501 host_entry->hostInfo.streamPolicy,
2502 host_entry->hostInfo.streamPolicyName););
2503 return 0;
2504 }
2505 #endif
2506
StreamPostConfigTcp(struct _SnortConfig * sc,void * pv)2507 void StreamPostConfigTcp (struct _SnortConfig *sc, void* pv)
2508 {
2509 // enable all ports registered by preprocessors for reassembly
2510 enableRegisteredPortsForReassembly( sc );
2511 }
2512
2513 void s5TcpPrintPortFilter();
2514
2515 /**
2516 * StreamVerifyTcpConfig is is called after all preprocs (static & dynamic)
2517 * are inited.
2518 */
StreamVerifyTcpConfig(struct _SnortConfig * sc,StreamTcpConfig * config,tSfPolicyId policy_id)2519 int StreamVerifyTcpConfig(struct _SnortConfig *sc, StreamTcpConfig *config, tSfPolicyId policy_id)
2520 {
2521 if (config == NULL)
2522 return -1;
2523
2524 if (!tcp_lws_cache)
2525 {
2526 LogMessage("WARNING: Stream TCP Session Cache not initialized.\n");
2527 return -1;
2528 }
2529
2530 if (config->num_policies == 0)
2531 {
2532 LogMessage("WARNING: Stream TCP no policies specified in configuration.\n");
2533 return -1;
2534 }
2535
2536 if (config->default_policy == NULL)
2537 {
2538 LogMessage("WARNING: Stream TCP default policy not specified in configuration.\n");
2539 return -1;
2540 }
2541
2542 /* Do this now
2543 * verify config is called after all preprocs (static & dynamic)
2544 * are inited. Gives us the correct number of bits for
2545 * p->preprocessor_bits
2546 */
2547 if (!s5_pkt)
2548 StreamInitPacket();
2549
2550 #ifdef TARGET_BASED
2551 SFAT_SetPolicyIds(StreamPolicyIdFromHostAttributeEntry, policy_id);
2552 #endif
2553
2554 /* Post-process TCP rules to establish TCP ports to inspect. */
2555 setPortFilterList(sc, config->port_filter, IPPROTO_TCP,
2556 (config->default_policy->flags & STREAM_CONFIG_IGNORE_ANY), policy_id);
2557
2558 //printf ("TCP Ports with Inspection/Monitoring\n");
2559 //s5PrintPortFilter(config->tcpPortFilter);
2560 return 0;
2561 }
2562
2563
StreamGetTcpPrunes(void)2564 uint32_t StreamGetTcpPrunes(void)
2565 {
2566 if( tcp_lws_cache )
2567 return session_api->get_session_prune_count( SESSION_PROTO_TCP );
2568 else
2569 return s5stats.tcp_prunes;
2570 }
2571
StreamResetTcpPrunes(void)2572 void StreamResetTcpPrunes(void)
2573 {
2574 session_api->reset_session_prune_count( SESSION_PROTO_TCP );
2575 }
2576
StreamResetTcp(void)2577 void StreamResetTcp(void)
2578 {
2579 if (snort_conf == NULL)
2580 {
2581 ErrorMessage("Snort configuration is NULL.\n");
2582 return;
2583 }
2584
2585 /* Unset decoder flags for the purge */
2586 targetPolicyIterate(policyDecoderFlagsSaveNClear);
2587
2588 s5_tcp_cleanup = 1;
2589 session_api->purge_session_cache(tcp_lws_cache);
2590 s5_tcp_cleanup = 0;
2591 session_api->clean_protocol_session_pool( SESSION_PROTO_TCP );
2592
2593 /* Set decoder flags back to original */
2594 targetPolicyIterate(policyDecoderFlagsRestore);
2595
2596 ResetFlushMgrs();
2597 }
2598
2599
StreamCleanTcp(void)2600 void StreamCleanTcp(void)
2601 {
2602 if (snort_conf == NULL)
2603 {
2604 ErrorMessage("Snort configuration is NULL.\n");
2605 return;
2606 }
2607
2608 s5stats.tcp_prunes = session_api->get_session_prune_count( SESSION_PROTO_TCP );
2609
2610 /* Turn off decoder alerts since we're decoding stored
2611 * packets that we already alerted on. */
2612 targetPolicyIterate(policyDecoderFlagsSaveNClear);
2613
2614 /* Set s5_tcp_cleanup to force a flush of all queued data */
2615 s5_tcp_cleanup = 1;
2616 /* Clean up session cache */
2617 session_api->delete_session_cache( SESSION_PROTO_TCP );
2618 tcp_lws_cache = NULL;
2619
2620 /* Cleanup the rebuilt packet */
2621 if (s5_pkt)
2622 {
2623 Encode_Delete(s5_pkt);
2624 s5_pkt = NULL;
2625 }
2626
2627 /* Cleanup TCP session cleanup packet */
2628 if (tcp_cleanup_pkt)
2629 {
2630 DeleteGrinderPkt(tcp_cleanup_pkt);
2631 tcp_cleanup_pkt = NULL;
2632 }
2633
2634 /* cleanup is over... */
2635 s5_tcp_cleanup = 0;
2636
2637 /* And turn decoder alerts back on (or whatever they were set to) */
2638 targetPolicyIterate(policyDecoderFlagsRestore);
2639 }
2640
StreamTcpConfigFree(StreamTcpConfig * config)2641 void StreamTcpConfigFree(StreamTcpConfig *config)
2642 {
2643 int i;
2644
2645 if (config == NULL)
2646 return;
2647
2648 /* Cleanup TCP Policies and the list */
2649 for (i = 0; i < config->num_policies; i++)
2650 {
2651 StreamTcpPolicy *policy = config->policy_list[i];
2652
2653 SnortPreprocFree(policy->flush_point_list.flush_points,
2654 sizeof(uint32_t) * RAND_FLUSH_POINTS, PP_STREAM,
2655 PP_MEM_CATEGORY_CONFIG);
2656
2657 if (policy->bound_addrs != NULL)
2658 sfvar_free(policy->bound_addrs);
2659 SnortPreprocFree(policy, sizeof( StreamTcpPolicy * ), PP_STREAM,
2660 PP_MEM_CATEGORY_CONFIG);
2661 }
2662
2663 if ( config->paf_config )
2664 s5_paf_delete(config->paf_config);
2665
2666 SnortPreprocFree(config->policy_list,
2667 sizeof(StreamTcpPolicy *) * (config->num_policies), PP_STREAM,
2668 PP_MEM_CATEGORY_CONFIG);
2669 SnortPreprocFree(config, sizeof(StreamTcpConfig), PP_STREAM, PP_MEM_CATEGORY_CONFIG);
2670 }
2671
2672 #ifdef STREAM_DEBUG_ENABLED
PrintStateMgr(StateMgr * s)2673 static void PrintStateMgr(StateMgr *s)
2674 {
2675 LogMessage("StateMgr:\n");
2676 LogMessage(" state: %s\n", state_names[s->state]);
2677 LogMessage(" state_queue: %s\n", state_names[s->state_queue]);
2678 LogMessage(" expected_flags: 0x%X\n", s->expected_flags);
2679 LogMessage(" transition_seq: 0x%X\n", s->transition_seq);
2680 LogMessage(" stq_get_seq: %d\n", s->stq_get_seq);
2681 }
2682
PrintStreamTracker(StreamTracker * s)2683 static void PrintStreamTracker(StreamTracker *s)
2684 {
2685 LogMessage(" + StreamTracker +\n");
2686 LogMessage(" isn: 0x%X\n", s->isn);
2687 LogMessage(" ts_last: %u\n", s->ts_last);
2688 LogMessage(" wscale: %u\n", s->wscale);
2689 LogMessage(" mss: 0x%08X\n", s->mss);
2690 LogMessage(" l_unackd: %X\n", s->l_unackd);
2691 LogMessage(" l_nxt_seq: %X\n", s->l_nxt_seq);
2692 LogMessage(" l_window: %u\n", s->l_window);
2693 LogMessage(" r_nxt_ack: %X\n", s->r_nxt_ack);
2694 LogMessage(" r_win_base: %X\n", s->r_win_base);
2695 LogMessage(" seglist_base_seq: %X\n", s->seglist_base_seq);
2696 LogMessage(" seglist: %p\n", (void*)s->seglist);
2697 LogMessage(" seglist_tail: %p\n", (void*)s->seglist_tail);
2698 LogMessage(" seg_count: %d\n", s->seg_count);
2699 LogMessage(" seg_bytes_total: %d\n", s->seg_bytes_total);
2700 LogMessage(" seg_bytes_logical: %d\n", s->seg_bytes_logical);
2701
2702 PrintStateMgr(&s->s_mgr);
2703 }
2704
PrintTcpSession(TcpSession * ts)2705 static void PrintTcpSession(TcpSession *ts)
2706 {
2707 char buf[64];
2708
2709 LogMessage("TcpSession:\n");
2710 #ifdef DEBUG
2711 LogMessage(" ssn_time: %lu\n", ts->ssn_time.tv_sec);
2712 #endif
2713 sfip_ntop(&ts->tcp_server_ip, buf, sizeof(buf));
2714 LogMessage(" server IP: %s\n", buf);
2715 sfip_ntop(&ts->tcp_client_ip, buf, sizeof(buf));
2716 LogMessage(" client IP: %s\n", buf);
2717
2718 LogMessage(" server port: %d\n", ts->tcp_server_port);
2719 LogMessage(" client port: %d\n", ts->tcp_client_port);
2720
2721 LogMessage(" flags: 0x%X\n", ts->scb->ha_state.session_flags);
2722
2723 LogMessage("Client Tracker:\n");
2724 PrintStreamTracker(&ts->client);
2725 LogMessage("Server Tracker:\n");
2726 PrintStreamTracker(&ts->server);
2727 }
2728
PrintTcpDataBlock(TcpDataBlock * tdb)2729 static void PrintTcpDataBlock(TcpDataBlock *tdb)
2730 {
2731 LogMessage("TcpDataBlock:\n");
2732 LogMessage(" seq: 0x%08X\n", tdb->seq);
2733 LogMessage(" ack: 0x%08X\n", tdb->ack);
2734 LogMessage(" win: %d\n", tdb->win);
2735 LogMessage(" end: 0x%08X\n", tdb->end_seq);
2736 }
2737
2738 #ifdef STREAM_DEBUG_ENABLED
PrintFlushMgr(FlushMgr * fm)2739 static void PrintFlushMgr(FlushMgr *fm)
2740 {
2741 if(fm == NULL)
2742 return;
2743
2744 switch(fm->flush_policy)
2745 {
2746 case STREAM_FLPOLICY_NONE:
2747 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
2748 " NONE\n"););
2749 break;
2750 case STREAM_FLPOLICY_FOOTPRINT:
2751 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
2752 " FOOTPRINT %d\n", fm->flush_pt););
2753 break;
2754 case STREAM_FLPOLICY_LOGICAL:
2755 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
2756 " LOGICAL %d\n", fm->flush_pt););
2757 break;
2758 case STREAM_FLPOLICY_RESPONSE:
2759 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
2760 " RESPONSE\n"););
2761 break;
2762 case STREAM_FLPOLICY_SLIDING_WINDOW:
2763 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
2764 " SLIDING_WINDOW %d\n", fm->flush_pt););
2765 break;
2766 #if 0
2767 case STREAM_FLPOLICY_CONSUMED:
2768 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
2769 " CONSUMED %d\n", fm->flush_pt););
2770 break;
2771 #endif
2772 case STREAM_FLPOLICY_IGNORE:
2773 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
2774 " IGNORE\n"););
2775 break;
2776
2777 case STREAM_FLPOLICY_PROTOCOL:
2778 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
2779 " PROTOCOL\n"););
2780 break;
2781 }
2782 }
2783 #endif // DEBUG
2784 #endif // STREAM_DEBUG_ENABLED
2785
Discard()2786 static inline void Discard ()
2787 {
2788 s5stats.tcp_discards++;
2789 }
EventSynOnEst(StreamTcpPolicy * s5TcpPolicy)2790 static inline void EventSynOnEst(StreamTcpPolicy *s5TcpPolicy)
2791 {
2792 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2793 return;
2794
2795 s5stats.events++;
2796
2797 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2798 STREAM_SYN_ON_EST, /* SID */
2799 1, /* rev */
2800 0, /* class */
2801 3, /* priority */
2802 STREAM_SYN_ON_EST_STR, /* event msg */
2803 NULL); /* rule info ptr */
2804 }
2805
EventExcessiveOverlap(StreamTcpPolicy * s5TcpPolicy)2806 static inline void EventExcessiveOverlap(StreamTcpPolicy *s5TcpPolicy)
2807 {
2808 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2809 return;
2810
2811 s5stats.events++;
2812
2813 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2814 STREAM_EXCESSIVE_TCP_OVERLAPS, /* SID */
2815 1, /* rev */
2816 0, /* class */
2817 3, /* priority */
2818 STREAM_EXCESSIVE_TCP_OVERLAPS_STR, /* event msg */
2819 NULL); /* rule info ptr */
2820 }
2821
EventBadTimestamp(StreamTcpPolicy * s5TcpPolicy)2822 static inline void EventBadTimestamp(StreamTcpPolicy *s5TcpPolicy)
2823 {
2824 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2825 return;
2826
2827 s5stats.events++;
2828
2829 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2830 STREAM_BAD_TIMESTAMP, /* SID */
2831 1, /* rev */
2832 0, /* class */
2833 3, /* priority */
2834 STREAM_BAD_TIMESTAMP_STR, /* event msg */
2835 NULL); /* rule info ptr */
2836 }
2837
EventWindowTooLarge(StreamTcpPolicy * s5TcpPolicy)2838 static inline void EventWindowTooLarge(StreamTcpPolicy *s5TcpPolicy)
2839 {
2840 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2841 return;
2842
2843 s5stats.events++;
2844
2845 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2846 STREAM_WINDOW_TOO_LARGE, /* SID */
2847 1, /* rev */
2848 0, /* class */
2849 3, /* priority */
2850 STREAM_WINDOW_TOO_LARGE_STR, /* event msg */
2851 NULL); /* rule info ptr */
2852 }
2853
EventDataOnSyn(StreamTcpPolicy * s5TcpPolicy)2854 static inline void EventDataOnSyn(StreamTcpPolicy *s5TcpPolicy)
2855 {
2856 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2857 return;
2858
2859 s5stats.events++;
2860
2861 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2862 STREAM_DATA_ON_SYN, /* SID */
2863 1, /* rev */
2864 0, /* class */
2865 3, /* priority */
2866 STREAM_DATA_ON_SYN_STR, /* event msg */
2867 NULL); /* rule info ptr */
2868 }
2869
EventDataOnClosed(StreamTcpPolicy * s5TcpPolicy)2870 static inline void EventDataOnClosed(StreamTcpPolicy *s5TcpPolicy)
2871 {
2872 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2873 return;
2874
2875 s5stats.events++;
2876
2877 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2878 STREAM_DATA_ON_CLOSED, /* SID */
2879 1, /* rev */
2880 0, /* class */
2881 3, /* priority */
2882 STREAM_DATA_ON_CLOSED_STR, /* event msg */
2883 NULL); /* rule info ptr */
2884 }
2885
EventDataAfterReset(StreamTcpPolicy * s5TcpPolicy)2886 static inline void EventDataAfterReset(StreamTcpPolicy *s5TcpPolicy)
2887 {
2888 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2889 return;
2890
2891 s5stats.events++;
2892
2893 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2894 STREAM_DATA_AFTER_RESET, /* SID */
2895 1, /* rev */
2896 0, /* class */
2897 3, /* priority */
2898 STREAM_DATA_AFTER_RESET_STR, /* event msg */
2899 NULL); /* rule info ptr */
2900 }
2901
EventBadSegment(StreamTcpPolicy * s5TcpPolicy)2902 static inline void EventBadSegment(StreamTcpPolicy *s5TcpPolicy)
2903 {
2904 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2905 return;
2906
2907 s5stats.events++;
2908
2909 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2910 STREAM_BAD_SEGMENT, /* SID */
2911 1, /* rev */
2912 0, /* class */
2913 3, /* priority */
2914 STREAM_BAD_SEGMENT_STR, /* event msg */
2915 NULL); /* rule info ptr */
2916 }
2917
EventSessionHijackedClient(StreamTcpPolicy * s5TcpPolicy)2918 static inline void EventSessionHijackedClient(StreamTcpPolicy *s5TcpPolicy)
2919 {
2920 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2921 return;
2922
2923 s5stats.events++;
2924
2925 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2926 STREAM_SESSION_HIJACKED_CLIENT, /* SID */
2927 1, /* rev */
2928 0, /* class */
2929 3, /* priority */
2930 STREAM_SESSION_HIJACKED_CLIENT_STR, /* event msg */
2931 NULL); /* rule info ptr */
2932 }
EventSessionHijackedServer(StreamTcpPolicy * s5TcpPolicy)2933 static inline void EventSessionHijackedServer(StreamTcpPolicy *s5TcpPolicy)
2934 {
2935 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2936 return;
2937
2938 s5stats.events++;
2939
2940 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2941 STREAM_SESSION_HIJACKED_SERVER, /* SID */
2942 1, /* rev */
2943 0, /* class */
2944 3, /* priority */
2945 STREAM_SESSION_HIJACKED_SERVER_STR, /* event msg */
2946 NULL); /* rule info ptr */
2947 }
2948
EventDataWithoutFlags(StreamTcpPolicy * s5TcpPolicy)2949 static inline void EventDataWithoutFlags(StreamTcpPolicy *s5TcpPolicy)
2950 {
2951 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2952 return;
2953
2954 s5stats.events++;
2955
2956 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2957 STREAM_DATA_WITHOUT_FLAGS, /* SID */
2958 1, /* rev */
2959 0, /* class */
2960 3, /* priority */
2961 STREAM_DATA_WITHOUT_FLAGS_STR, /* event msg */
2962 NULL); /* rule info ptr */
2963 }
2964
EventMaxSmallSegsExceeded(StreamTcpPolicy * s5TcpPolicy)2965 static inline void EventMaxSmallSegsExceeded(StreamTcpPolicy *s5TcpPolicy)
2966 {
2967 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2968 return;
2969
2970 s5stats.events++;
2971
2972 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2973 STREAM_SMALL_SEGMENT, /* SID */
2974 1, /* rev */
2975 0, /* class */
2976 3, /* priority */
2977 STREAM_SMALL_SEGMENT_STR, /* event msg */
2978 NULL); /* rule info ptr */
2979 }
2980
Event4whs(StreamTcpPolicy * s5TcpPolicy)2981 static inline void Event4whs(StreamTcpPolicy *s5TcpPolicy)
2982 {
2983 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
2984 return;
2985
2986 s5stats.events++;
2987
2988 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
2989 STREAM_4WAY_HANDSHAKE, /* SID */
2990 1, /* rev */
2991 0, /* class */
2992 3, /* priority */
2993 STREAM_4WAY_HANDSHAKE_STR, /* event msg */
2994 NULL); /* rule info ptr */
2995 }
2996
EventNoTimestamp(StreamTcpPolicy * s5TcpPolicy)2997 static inline void EventNoTimestamp(StreamTcpPolicy *s5TcpPolicy)
2998 {
2999 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
3000 return;
3001
3002 s5stats.events++;
3003
3004 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
3005 STREAM_NO_TIMESTAMP, /* SID */
3006 1, /* rev */
3007 0, /* class */
3008 3, /* priority */
3009 STREAM_NO_TIMESTAMP_STR, /* event msg */
3010 NULL); /* rule info ptr */
3011 }
3012
EventBadReset(StreamTcpPolicy * s5TcpPolicy)3013 static inline void EventBadReset(StreamTcpPolicy *s5TcpPolicy)
3014 {
3015 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
3016 return;
3017
3018 s5stats.events++;
3019
3020 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
3021 STREAM_BAD_RST, /* SID */
3022 1, /* rev */
3023 0, /* class */
3024 3, /* priority */
3025 STREAM_BAD_RST_STR, /* event msg */
3026 NULL); /* rule info ptr */
3027 }
3028
EventBadFin(StreamTcpPolicy * s5TcpPolicy)3029 static inline void EventBadFin(StreamTcpPolicy *s5TcpPolicy)
3030 {
3031 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
3032 return;
3033
3034 s5stats.events++;
3035
3036 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
3037 STREAM_BAD_FIN, /* SID */
3038 1, /* rev */
3039 0, /* class */
3040 3, /* priority */
3041 STREAM_BAD_FIN_STR, /* event msg */
3042 NULL); /* rule info ptr */
3043 }
3044
EventBadAck(StreamTcpPolicy * s5TcpPolicy)3045 static inline void EventBadAck(StreamTcpPolicy *s5TcpPolicy)
3046 {
3047 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
3048 return;
3049
3050 s5stats.events++;
3051
3052 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
3053 STREAM_BAD_ACK, /* SID */
3054 1, /* rev */
3055 0, /* class */
3056 3, /* priority */
3057 STREAM_BAD_ACK_STR, /* event msg */
3058 NULL); /* rule info ptr */
3059 }
3060
EventDataAfterRstRcvd(StreamTcpPolicy * s5TcpPolicy)3061 static inline void EventDataAfterRstRcvd(StreamTcpPolicy *s5TcpPolicy)
3062 {
3063 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
3064 return;
3065
3066 s5stats.events++;
3067
3068 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
3069 STREAM_DATA_AFTER_RST_RCVD, /* SID */
3070 1, /* rev */
3071 0, /* class */
3072 3, /* priority */
3073 STREAM_DATA_AFTER_RST_RCVD_STR, /* event msg */
3074 NULL); /* rule info ptr */
3075 }
3076
EventInternal(uint32_t eventSid)3077 static inline void EventInternal (uint32_t eventSid)
3078 {
3079 if ( !InternalEventIsEnabled(snort_conf->rate_filter_config, eventSid) )
3080 return;
3081
3082 s5stats.internalEvents++;
3083
3084 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3085 "Stream raised internal event %d\n", eventSid););
3086
3087 SnortEventqAdd(
3088 GENERATOR_INTERNAL, /* GID */
3089 eventSid, /* SID */
3090 1, /* rev */
3091 0, /* class */
3092 3, /* priority */
3093 STREAM_INTERNAL_EVENT_STR, /* event msg*/
3094 NULL /* rule info ptr */
3095 );
3096 }
3097
EventWindowSlam(StreamTcpPolicy * s5TcpPolicy)3098 static inline void EventWindowSlam (StreamTcpPolicy *s5TcpPolicy)
3099 {
3100 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
3101 return;
3102
3103 s5stats.events++;
3104
3105 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
3106 STREAM_WINDOW_SLAM, /* SID */
3107 1, /* rev */
3108 0, /* class */
3109 3, /* priority */
3110 STREAM_WINDOW_SLAM_STR, /* event msg */
3111 NULL); /* rule info ptr */
3112 }
3113
EventNo3whs(StreamTcpPolicy * s5TcpPolicy)3114 static inline void EventNo3whs (StreamTcpPolicy *s5TcpPolicy)
3115 {
3116 if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
3117 return;
3118
3119 s5stats.events++;
3120
3121 SnortEventqAdd(GENERATOR_SPP_STREAM, /* GID */
3122 STREAM_NO_3WHS, /* SID */
3123 1, /* rev */
3124 0, /* class */
3125 3, /* priority */
3126 STREAM_NO_3WHS_STR, /* event msg */
3127 NULL); /* rule info ptr */
3128 }
3129
3130 /*
3131 * Utility functions for TCP stuff
3132 */
3133 #ifdef NORMALIZER
3134 typedef enum {
3135 PC_TCP_ECN_SSN,
3136 PC_TCP_TS_NOP,
3137 PC_TCP_IPS_DATA,
3138 PC_TCP_BLOCK,
3139 PC_TCP_TRIM_SYN,
3140 PC_TCP_TRIM_RST,
3141 PC_TCP_TRIM_WIN,
3142 PC_TCP_TRIM_MSS,
3143 PC_MAX
3144 } PegCounts;
3145
3146 static uint64_t normStats[PC_MAX][NORM_MODE_MAX];
3147
3148 static const char* pegName[PC_MAX] = {
3149 "tcp::ecn_ssn",
3150 "tcp::ts_nop",
3151 "tcp::ips_data",
3152 "tcp::block",
3153 "tcp::trim_syn",
3154 "tcp::trim_rst",
3155 "tcp::trim_win",
3156 "tcp::trim_mss",
3157 };
3158
Stream_PrintNormalizationStats(void)3159 void Stream_PrintNormalizationStats (void)
3160 {
3161 int i;
3162 // header output by normalizer
3163
3164 for ( i = 0; i < PC_MAX; i++ )
3165 {
3166 // same alignment as in Norm_PrintStats()
3167 LogMessage("%23s: " STDu64 "\n", pegName[i], normStats[i][NORM_MODE_ON]);
3168 LogMessage("Would %17s: " STDu64 "\n", pegName[i], normStats[i][NORM_MODE_WOULDA]);
3169 }
3170 }
3171
Stream_ResetNormalizationStats(void)3172 void Stream_ResetNormalizationStats (void)
3173 {
3174 memset(normStats, 0, sizeof(normStats));
3175 }
3176
3177 //-----------------------------------------------------------------------
3178 // instead of centralizing all these normalizations so that
3179 // Normalize_GetMode() is called only once, the checks and
3180 // normalizations are localized. this should lead to many
3181 // fewer total checks. however, it is best to minimize
3182 // configuration checks on a per packet basis so there is
3183 // still room for improvement.
3184
NormalDropPacket(Packet * p)3185 static inline bool NormalDropPacket (Packet* p)
3186 {
3187 NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_BLOCK);
3188 if ( mode != NORM_MODE_OFF )
3189 {
3190 normStats[PC_TCP_BLOCK][mode]++;
3191 sfBase.iPegs[PERF_COUNT_TCP_BLOCK][mode]++;
3192 if ( mode == NORM_MODE_ON )
3193 {
3194 Active_NapDropPacket(p);
3195 if (pkt_trace_enabled)
3196 {
3197 addPktTraceData(VERDICT_REASON_STREAM, snprintf(trace_line, MAX_TRACE_LINE,
3198 "Stream: TCP normalization error in timestamp, window, seq, ack, fin, flags, or unexpected data, %s\n",
3199 getPktTraceActMsg()));
3200 }
3201 else addPktTraceData(VERDICT_REASON_STREAM, 0);
3202 return true;
3203 }
3204 }
3205 return false;
3206 }
3207
NormalStripTimeStamp(Packet * p,int i)3208 static inline bool NormalStripTimeStamp (Packet* p, int i)
3209 {
3210 uint8_t* opt;
3211 NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_OPT);
3212
3213 if ( mode != NORM_MODE_OFF )
3214 {
3215 if ( i < 0 )
3216 {
3217 for ( i = 0; i < p->tcp_option_count; i++ )
3218 if ( p->tcp_options[i].code == TCPOPT_TIMESTAMP )
3219 break;
3220 if ( i == p->tcp_option_count )
3221 return false;
3222 }
3223
3224 normStats[PC_TCP_TS_NOP][mode]++;
3225 sfBase.iPegs[PERF_COUNT_TCP_TS_NOP][mode]++;
3226 if ( mode == NORM_MODE_ON )
3227 {
3228 // first set raw option bytes to nops
3229 opt = (uint8_t*)p->tcp_options[i].data - 2;
3230 memset(opt, TCPOPT_NOP, TCPOLEN_TIMESTAMP);
3231
3232 // then nop decoded option code only
3233 p->tcp_options[i].code = TCPOPT_NOP;
3234
3235 p->packet_flags |= PKT_MODIFIED;
3236 return true;
3237 }
3238 }
3239 return false;
3240 }
3241
NormalTrimPayload(Packet * p,uint32_t max,TcpDataBlock * tdb)3242 static inline void NormalTrimPayload (Packet* p, uint32_t max, TcpDataBlock* tdb)
3243 {
3244 uint16_t fat = p->dsize - max;
3245 p->dsize = max;
3246 p->packet_flags |= (PKT_MODIFIED|PKT_RESIZED);
3247 tdb->end_seq -= fat;
3248 }
3249
NormalTrimPayloadIfSyn(Packet * p,uint32_t max,TcpDataBlock * tdb)3250 static inline bool NormalTrimPayloadIfSyn ( Packet *p, uint32_t max, TcpDataBlock *tdb )
3251 {
3252 NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_TRIM_SYN);
3253 if ( mode != NORM_MODE_OFF && p->dsize > max )
3254 {
3255 normStats[PC_TCP_TRIM_SYN][mode]++;
3256 sfBase.iPegs[PERF_COUNT_TCP_TRIM_SYN][mode]++;
3257 if( mode == NORM_MODE_ON )
3258 {
3259 NormalTrimPayload(p, max, tdb);
3260 return true;
3261 }
3262 }
3263 return false;
3264 }
3265
NormalTrimPayloadIfRst(Packet * p,uint32_t max,TcpDataBlock * tdb)3266 static inline bool NormalTrimPayloadIfRst ( Packet *p, uint32_t max, TcpDataBlock *tdb )
3267 {
3268 NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_TRIM_RST);
3269 if ( mode != NORM_MODE_OFF && p->dsize > max )
3270 {
3271 normStats[PC_TCP_TRIM_RST][mode]++;
3272 sfBase.iPegs[PERF_COUNT_TCP_TRIM_RST][mode]++;
3273 if( mode == NORM_MODE_ON )
3274 {
3275 NormalTrimPayload(p, max, tdb);
3276 return true;
3277 }
3278 }
3279 return false;
3280 }
3281
NormalTrimPayloadIfWin(Packet * p,uint32_t max,TcpDataBlock * tdb)3282 static inline bool NormalTrimPayloadIfWin ( Packet *p, uint32_t max, TcpDataBlock *tdb )
3283 {
3284 NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_TRIM_WIN);
3285 if ( mode != NORM_MODE_OFF && p->dsize > max )
3286 {
3287 normStats[PC_TCP_TRIM_WIN][mode]++;
3288 sfBase.iPegs[PERF_COUNT_TCP_TRIM_WIN][mode]++;
3289 if( mode == NORM_MODE_ON )
3290 {
3291 NormalTrimPayload(p, max, tdb);
3292 return true;
3293 }
3294 }
3295 return false;
3296 }
3297
NormalTrimPayloadIfMss(Packet * p,uint32_t max,TcpDataBlock * tdb)3298 static inline bool NormalTrimPayloadIfMss ( Packet *p, uint32_t max, TcpDataBlock *tdb )
3299 {
3300 NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_TRIM_MSS);
3301 if ( mode != NORM_MODE_OFF && p->dsize > max )
3302 {
3303 normStats[PC_TCP_TRIM_MSS][mode]++;
3304 sfBase.iPegs[PERF_COUNT_TCP_TRIM_MSS][mode]++;
3305 if( mode == NORM_MODE_ON )
3306 {
3307 NormalTrimPayload(p, max, tdb);
3308 return true;
3309 }
3310 }
3311 return false;
3312 }
3313
NormalTrackECN(TcpSession * s,const TCPHdr * tcph,int req3way)3314 static inline void NormalTrackECN (TcpSession* s, const TCPHdr* tcph, int req3way)
3315 {
3316 if ( !s )
3317 return;
3318
3319 if ( TCP_ISFLAGSET(tcph, TH_SYN|TH_ACK) )
3320 {
3321 if ( !req3way || s->ecn )
3322 s->ecn = ((tcph->th_flags & (TH_ECE|TH_CWR)) == TH_ECE);
3323 }
3324 else if ( TCP_ISFLAGSET(tcph, TH_SYN) )
3325 s->ecn = TCP_ISFLAGSET(tcph, (TH_ECE|TH_CWR));
3326 }
3327
NormalCheckECN(TcpSession * s,Packet * p)3328 static inline void NormalCheckECN (TcpSession* s, Packet* p)
3329 {
3330 NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_ECN_STR);
3331 if ( mode != NORM_MODE_OFF )
3332 {
3333 if ( !s->ecn && (p->tcph->th_flags & (TH_ECE|TH_CWR)) )
3334 {
3335 normStats[PC_TCP_ECN_SSN][mode]++;
3336 sfBase.iPegs[PERF_COUNT_TCP_ECN_SSN][mode]++;
3337 if ( mode == NORM_MODE_ON )
3338 {
3339 ((TCPHdr*)p->tcph)->th_flags &= ~(TH_ECE|TH_CWR);
3340 p->packet_flags |= PKT_MODIFIED;
3341 }
3342 }
3343 }
3344 }
3345 #else
3346 #define NormalDropPacket(p)
3347 #define NormalTrackECN(s, h, r)
3348 #endif
3349
StreamUpdatePerfBaseState(SFBASE * sf_base,SessionControlBlock * scb,char newState)3350 void StreamUpdatePerfBaseState(SFBASE *sf_base,
3351 SessionControlBlock *scb,
3352 char newState)
3353 {
3354 if (!scb)
3355 {
3356 return;
3357 }
3358
3359 switch (newState)
3360 {
3361 case TCP_STATE_SYN_SENT:
3362 if (!(scb->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE))
3363 {
3364 sf_base->iSessionsInitializing++;
3365 scb->ha_state.session_flags |= SSNFLAG_COUNTED_INITIALIZE;
3366 }
3367 break;
3368 case TCP_STATE_ESTABLISHED:
3369 if (!(scb->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH))
3370 {
3371 sf_base->iSessionsEstablished++;
3372 EventInternal(INTERNAL_EVENT_SESSION_ADD);
3373
3374 if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP))
3375 UpdateFlowIPState(&sfFlow, IP_ARG(scb->client_ip), IP_ARG(scb->server_ip), SFS_STATE_TCP_ESTABLISHED);
3376
3377 scb->ha_state.session_flags |= SSNFLAG_COUNTED_ESTABLISH;
3378
3379 if ((scb->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE) &&
3380 !(scb->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING))
3381 {
3382 assert(sf_base->iSessionsInitializing);
3383 sf_base->iSessionsInitializing--;
3384 }
3385 }
3386 break;
3387 case TCP_STATE_CLOSING:
3388 if (!(scb->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING))
3389 {
3390 sf_base->iSessionsClosing++;
3391 scb->ha_state.session_flags |= SSNFLAG_COUNTED_CLOSING;
3392 if (scb->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH)
3393 {
3394 assert(sf_base->iSessionsEstablished);
3395 sf_base->iSessionsEstablished--;
3396
3397 if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP))
3398 UpdateFlowIPState(&sfFlow, IP_ARG(scb->client_ip), IP_ARG(scb->server_ip), SFS_STATE_TCP_CLOSED);
3399 }
3400 else if (scb->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE)
3401 {
3402 assert(sf_base->iSessionsInitializing);
3403 sf_base->iSessionsInitializing--;
3404 }
3405 }
3406 break;
3407 case TCP_STATE_CLOSED:
3408 if (scb->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING)
3409 {
3410 assert(sf_base->iSessionsClosing);
3411 sf_base->iSessionsClosing--;
3412 }
3413 else if (scb->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH)
3414 {
3415 assert(sf_base->iSessionsEstablished);
3416 sf_base->iSessionsEstablished--;
3417
3418 if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP))
3419 UpdateFlowIPState(&sfFlow, IP_ARG(scb->client_ip), IP_ARG(scb->server_ip), SFS_STATE_TCP_CLOSED);
3420 }
3421 else if (scb->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE)
3422 {
3423 assert(sf_base->iSessionsInitializing);
3424 sf_base->iSessionsInitializing--;
3425 }
3426 break;
3427 default:
3428 break;
3429 }
3430 sf_base->stream5_mem_in_use = session_mem_in_use;
3431 }
3432
3433 //-------------------------------------------------------------------------
3434 // ssn ingress is client; ssn egress is server
3435
3436 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
SetPacketHeaderFoo(TcpSession * tcpssn,const Packet * p)3437 static inline void SetPacketHeaderFoo (TcpSession* tcpssn, const Packet* p)
3438 {
3439 if ( ( p->packet_flags & PKT_FROM_CLIENT ) || p->pkth->egress_index == DAQ_PKTHDR_UNKNOWN )
3440 {
3441 tcpssn->ingress_index = p->pkth->ingress_index;
3442 tcpssn->ingress_group = p->pkth->ingress_group;
3443 // ssn egress may be unknown, but will be correct
3444 tcpssn->egress_index = p->pkth->egress_index;
3445 tcpssn->egress_group = p->pkth->egress_group;
3446 }
3447 else
3448 {
3449 if ( p->pkth->egress_index != DAQ_PKTHDR_FLOOD )
3450 {
3451 tcpssn->ingress_index = p->pkth->egress_index;
3452 tcpssn->ingress_group = p->pkth->egress_group;
3453 }
3454 tcpssn->egress_index = p->pkth->ingress_index;
3455 tcpssn->egress_group = p->pkth->ingress_group;
3456 }
3457 #ifdef HAVE_DAQ_FLOW_ID
3458 tcpssn->daq_flow_id = p->pkth->flow_id;
3459 #endif
3460 tcpssn->daq_flags = p->pkth->flags;
3461 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
3462 tcpssn->address_space_id_dst = p->pkth->address_space_id_dst;
3463 tcpssn->address_space_id_src = p->pkth->address_space_id_src;
3464 #else
3465 tcpssn->address_space_id = p->pkth->address_space_id;
3466 #endif
3467 }
3468
GetPacketHeaderFoo(const TcpSession * tcpssn,const DAQ_PktHdr_t * phdr,EncodeFlags fwd,DAQ_PktHdr_t * pkth,uint32_t dir)3469 static inline void GetPacketHeaderFoo (
3470 const TcpSession* tcpssn, const DAQ_PktHdr_t* phdr, EncodeFlags fwd,
3471 DAQ_PktHdr_t* pkth, uint32_t dir)
3472 {
3473 if ( (dir & PKT_FROM_CLIENT) || tcpssn->egress_index == DAQ_PKTHDR_UNKNOWN )
3474 {
3475 pkth->ingress_index = tcpssn->ingress_index;
3476 pkth->ingress_group = tcpssn->ingress_group;
3477 pkth->egress_index = tcpssn->egress_index;
3478 pkth->egress_group = tcpssn->egress_group;
3479 }
3480 else
3481 {
3482 pkth->ingress_index = tcpssn->egress_index;
3483 pkth->ingress_group = tcpssn->egress_group;
3484 pkth->egress_index = tcpssn->ingress_index;
3485 pkth->egress_group = tcpssn->ingress_group;
3486 }
3487 #ifdef HAVE_DAQ_FLOW_ID
3488 pkth->flow_id = tcpssn->daq_flow_id;
3489 #endif
3490 pkth->flags = tcpssn->daq_flags;
3491 pkth->priv_ptr = tcpssn->priv_ptr;
3492 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
3493 pkth->address_space_id_dst = tcpssn->address_space_id_dst;
3494 pkth->address_space_id_src = tcpssn->address_space_id_src;
3495 #else
3496 pkth->address_space_id = tcpssn->address_space_id;
3497 #endif
3498 #if defined(DAQ_VERSION) && DAQ_VERSION > 8
3499 pkth->proto = phdr->proto;
3500 #endif
3501
3502 #if !defined(SFLINUX) && defined(DAQ_CAPA_CARRIER_ID) && defined(DAQ_VERSION) && DAQ_VERSION > 10
3503 pkth->carrier_id = phdr->carrier_id;
3504 #endif
3505
3506 #ifdef HAVE_DAQ_REAL_ADDRESSES
3507 if (phdr->flags & DAQ_PKT_FLAG_REAL_ADDRESSES)
3508 {
3509 pkth->flags &= ~(DAQ_PKT_FLAG_REAL_SIP_V6 | DAQ_PKT_FLAG_REAL_DIP_V6);
3510 if (fwd)
3511 {
3512 pkth->flags |= phdr->flags & (DAQ_PKT_FLAG_REAL_SIP_V6 | DAQ_PKT_FLAG_REAL_DIP_V6);
3513 pkth->n_real_sPort = phdr->n_real_sPort;
3514 pkth->n_real_dPort = phdr->n_real_dPort;
3515 pkth->real_sIP = phdr->real_sIP;
3516 pkth->real_dIP = phdr->real_dIP;
3517 }
3518 else
3519 {
3520 if (phdr->flags & DAQ_PKT_FLAG_REAL_SIP_V6)
3521 pkth->flags |= DAQ_PKT_FLAG_REAL_DIP_V6;
3522 if (phdr->flags & DAQ_PKT_FLAG_REAL_DIP_V6)
3523 pkth->flags |= DAQ_PKT_FLAG_REAL_SIP_V6;
3524 pkth->n_real_sPort = phdr->n_real_dPort;
3525 pkth->n_real_dPort = phdr->n_real_sPort;
3526 pkth->real_sIP = phdr->real_dIP;
3527 pkth->real_dIP = phdr->real_sIP;
3528 }
3529 }
3530 #endif
3531 }
3532
SwapPacketHeaderFoo(TcpSession * tcpssn)3533 static inline void SwapPacketHeaderFoo (TcpSession* tcpssn)
3534 {
3535 if ( tcpssn->egress_index != DAQ_PKTHDR_UNKNOWN )
3536 {
3537 int32_t ingress_index;
3538 int32_t ingress_group;
3539
3540 ingress_index = tcpssn->ingress_index;
3541 ingress_group = tcpssn->ingress_group;
3542 tcpssn->ingress_index = tcpssn->egress_index;
3543 tcpssn->ingress_group = tcpssn->egress_group;
3544 tcpssn->egress_index = ingress_index;
3545 tcpssn->egress_group = ingress_group;
3546 }
3547 }
3548 #endif
3549
3550
3551 //-------------------------------------------------------------------------
3552
IsBetween(uint32_t low,uint32_t high,uint32_t cur)3553 static inline int IsBetween(uint32_t low, uint32_t high, uint32_t cur)
3554 {
3555 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3556 "(%X, %X, %X) = (low, high, cur)\n", low,high,cur););
3557
3558 /* If we haven't seen anything, ie, low & high are 0, return true */
3559 if ((low == 0) && (low == high))
3560 return 1;
3561
3562 return (SEQ_GEQ(cur, low) && SEQ_LEQ(cur, high));
3563 }
3564
TwoWayTraffic(SessionControlBlock * scb)3565 static inline bool TwoWayTraffic (SessionControlBlock *scb)
3566 {
3567 return ( (scb->ha_state.session_flags & SSNFLAG_SEEN_BOTH) == SSNFLAG_SEEN_BOTH );
3568 }
3569
StreamGetWindow(SessionControlBlock * scb,StreamTracker * st,TcpDataBlock * tdb)3570 static inline uint32_t StreamGetWindow(
3571 SessionControlBlock *scb, StreamTracker* st, TcpDataBlock* tdb)
3572 {
3573 int32_t window;
3574
3575 if ( st->l_window )
3576 {
3577 // don't use the window if we may have missed scaling
3578 if ( !(scb->session_state & STREAM_STATE_MIDSTREAM) )
3579 return st->l_window;
3580 }
3581 // one way zero window is unitialized
3582 // two way zero window is actually closed (regardless of scaling)
3583 else if ( TwoWayTraffic(scb) )
3584 return st->l_window;
3585
3586 // ensure the data is in the window
3587 window = tdb->end_seq - st->r_win_base;
3588
3589 if(window < 0)
3590 window = 0;
3591
3592 return (uint32_t) window;
3593 }
3594
3595 // ack number must ack syn
ValidRstSynSent(StreamTracker * st,TcpDataBlock * tdb)3596 static inline int ValidRstSynSent(StreamTracker *st, TcpDataBlock *tdb)
3597 {
3598 return tdb->ack == st->l_unackd;
3599 }
3600
3601 // per rfc 793 a rst is valid if the seq number is in window
3602 // for all states but syn-sent (handled above). however, we
3603 // validate here based on how various implementations actually
3604 // handle a rst.
ValidRst(SessionControlBlock * scb,StreamTracker * st,TcpDataBlock * tdb)3605 static inline int ValidRst(
3606 SessionControlBlock *scb, StreamTracker *st, TcpDataBlock *tdb)
3607 {
3608 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3609 "Checking end_seq (%X) > r_win_base (%X) && "
3610 "seq (%X) < r_nxt_ack(%X)\n",
3611 tdb->end_seq, st->r_win_base, tdb->seq,
3612 st->r_nxt_ack+StreamGetWindow(scb, st, tdb)););
3613
3614 switch (st->os_policy)
3615 {
3616 case STREAM_POLICY_HPUX11:
3617 if (SEQ_GEQ(tdb->seq, st->r_nxt_ack))
3618 {
3619 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3620 "rst is valid seq (>= next seq)!\n"););
3621 return 1;
3622 }
3623 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3624 "rst is not valid seq (>= next seq)!\n"););
3625 return 0;
3626 break;
3627 case STREAM_POLICY_FIRST:
3628 case STREAM_POLICY_NOACK:
3629 case STREAM_POLICY_LAST:
3630 case STREAM_POLICY_MACOS:
3631 case STREAM_POLICY_WINDOWS:
3632 case STREAM_POLICY_VISTA:
3633 case STREAM_POLICY_WINDOWS2K3:
3634 case STREAM_POLICY_HPUX10:
3635 case STREAM_POLICY_IRIX:
3636 if (SEQ_EQ(tdb->seq, st->r_nxt_ack))
3637 {
3638 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3639 "rst is valid seq (next seq)!\n"););
3640 return 1;
3641 }
3642 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3643 "rst is not valid seq (next seq)!\n"););
3644 return 0;
3645 break;
3646 case STREAM_POLICY_BSD:
3647 case STREAM_POLICY_LINUX:
3648 case STREAM_POLICY_OLD_LINUX:
3649 case STREAM_POLICY_SOLARIS:
3650 if(SEQ_GEQ(tdb->end_seq, st->r_win_base))
3651 {
3652 // reset must be admitted when window closed
3653 if ( SEQ_LEQ(tdb->seq, st->r_win_base+StreamGetWindow(scb, st, tdb)) )
3654 {
3655 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3656 "rst is valid seq (within window)!\n"););
3657 return 1;
3658 }
3659 }
3660
3661 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3662 "rst is not valid seq (within window)!\n"););
3663 return 0;
3664 break;
3665 }
3666
3667 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3668 "rst is not valid!\n"););
3669 return 0;
3670 }
3671
ValidTimestamp(StreamTracker * talker,StreamTracker * listener,TcpDataBlock * tdb,Packet * p,int * eventcode,int * got_ts)3672 static inline int ValidTimestamp(StreamTracker *talker, StreamTracker *listener, TcpDataBlock *tdb,
3673 Packet *p, int *eventcode, int *got_ts)
3674 {
3675 if((p->tcph->th_flags & TH_RST) || (listener->tcp_policy->policy == STREAM_POLICY_NOACK))
3676 return ACTION_NOTHING;
3677
3678 #ifdef NORMALIZER
3679 #if 0
3680 if ( p->tcph->th_flags & TH_ACK &&
3681 Normalize_GetMode(snort_conf, NORM_TCP_OPT) != NORM_MODE_OFF)
3682 {
3683 // FIXTHIS validate tsecr here (check that it was previously sent)
3684 // checking for the most recent ts is easy enough must check if
3685 // ts are up to date in retransmitted packets
3686 }
3687 #endif
3688 #endif
3689 /*
3690 * check PAWS
3691 */
3692 if((talker->flags & TF_TSTAMP) && (listener->flags & TF_TSTAMP))
3693 {
3694 char validate_timestamp = 1;
3695 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3696 "Checking timestamps for PAWS\n"););
3697
3698 *got_ts = StreamGetTcpTimestamp(p, &tdb->ts, 0);
3699
3700 if (*got_ts)
3701 {
3702 if (listener->tcp_policy->policy == STREAM_POLICY_HPUX11)
3703 {
3704 /* HPUX 11 ignores timestamps for out of order segments */
3705 if ((listener->flags & TF_PKT_MISSED) ||
3706 !SEQ_EQ(listener->r_nxt_ack, tdb->seq))
3707 {
3708 validate_timestamp = 0;
3709 }
3710 }
3711
3712 if (talker->flags & TF_TSTAMP_ZERO)
3713 {
3714 /* Handle the case where the 3whs used a 0 timestamp. Next packet
3715 * from that endpoint should have a valid timestamp... */
3716 if ((listener->tcp_policy->policy == STREAM_POLICY_LINUX) ||
3717 (listener->tcp_policy->policy == STREAM_POLICY_WINDOWS2K3))
3718 {
3719 /* Linux, Win2k3 et al. do not support timestamps if
3720 * the 3whs used a 0 timestamp. */
3721 talker->flags &= ~TF_TSTAMP;
3722 listener->flags &= ~TF_TSTAMP;
3723 validate_timestamp = 0;
3724 }
3725 else if ((listener->tcp_policy->policy == STREAM_POLICY_OLD_LINUX) ||
3726 (listener->tcp_policy->policy == STREAM_POLICY_WINDOWS) ||
3727 (listener->tcp_policy->policy == STREAM_POLICY_VISTA))
3728 {
3729 /* Older Linux (2.2 kernel & earlier), Win32 (non 2K3)
3730 * allow the 3whs to use a 0 timestamp. */
3731 talker->flags &= ~TF_TSTAMP_ZERO;
3732 if(SEQ_EQ(listener->r_nxt_ack, tdb->seq))
3733 {
3734 talker->ts_last = tdb->ts;
3735 validate_timestamp = 0; /* Ignore the timestamp for this
3736 * first packet, next one will
3737 * checked. */
3738 }
3739 }
3740 }
3741
3742 if (validate_timestamp)
3743 {
3744 int result = 0;
3745 if (listener->tcp_policy->policy == STREAM_POLICY_LINUX)
3746 {
3747 /* Linux 2.6 accepts timestamp values that are off
3748 * by one. */
3749 result = (int)((tdb->ts - talker->ts_last) + 1);
3750 }
3751 else
3752 {
3753 result = (int)(tdb->ts - talker->ts_last);
3754 }
3755
3756 #ifdef DAQ_PKT_FLAG_RETRY_PACKET
3757 if(result < 0 && (p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET))
3758 {
3759 // Retry packets can legitimately have old timestamps
3760 // in TCP options (if a re-transmit comes in before
3761 // the retry) so don't consider it an error.
3762 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3763 "Retry packet had old timestamp. Reseting to last timestamp seen.\n"););
3764 tdb->ts = talker->ts_last;
3765 }
3766 else
3767 #endif
3768 if( (talker->ts_last != 0) && result < 0)
3769 {
3770 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3771 "Packet outside PAWS window, dropping\n"););
3772 /* bail, we've got a packet outside the PAWS window! */
3773 //Discard();
3774 *eventcode |= EVENT_BAD_TIMESTAMP;
3775 NormalDropPacket(p);
3776 return ACTION_BAD_PKT;
3777 }
3778 else if ((talker->ts_last != 0) &&
3779 ((uint32_t)p->pkth->ts.tv_sec > talker->ts_last_pkt+PAWS_24DAYS))
3780 {
3781 /* this packet is from way too far into the future */
3782 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3783 "packet PAWS timestamp way too far ahead of"
3784 "last packet %d %d...\n", p->pkth->ts.tv_sec,
3785 talker->ts_last_pkt););
3786 //Discard();
3787 *eventcode |= EVENT_BAD_TIMESTAMP;
3788 NormalDropPacket(p);
3789 return ACTION_BAD_PKT;
3790 }
3791 else
3792 {
3793 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3794 "packet PAWS ok...\n"););
3795 }
3796 }
3797 }
3798 else
3799 {
3800 /* we've got a packet with no timestamp, but 3whs indicated talker
3801 * was doing timestamps. This breaks protocol, however, some servers
3802 * still ack the packet with the missing timestamp. Log an alert,
3803 * but continue to process the packet
3804 */
3805 *eventcode |= EVENT_NO_TIMESTAMP;
3806 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3807 "packet no timestamp, had one earlier from this side...ok for now...\n"););
3808
3809 if (listener->tcp_policy->policy == STREAM_POLICY_SOLARIS)
3810 {
3811 /* Solaris stops using timestamps if it receives a packet
3812 * without a timestamp and there were timestamps in use.
3813 */
3814 listener->flags &= ~TF_TSTAMP;
3815 }
3816 NormalDropPacket(p);
3817 }
3818 }
3819 else if ( TCP_ISFLAGSET(p->tcph, TH_SYN) &&
3820 !TCP_ISFLAGSET(p->tcph, TH_ACK) )
3821 {
3822 *got_ts = StreamGetTcpTimestamp(p, &tdb->ts, 0);
3823 if ( *got_ts ) {
3824 talker->flags |= TF_TSTAMP;
3825 // In case of SYN, there is no ts_last is 0
3826 // set it to the current value, so that computation of
3827 // ts_last is correct for subsequent packets.
3828 talker->ts_last = tdb->ts;
3829 talker->ts_last_pkt = p->pkth->ts.tv_sec;
3830 }
3831 }
3832 else
3833 {
3834 #ifdef NORMALIZER
3835 // if we are not handling timestamps, and this isn't a syn
3836 // (only), and we have seen a valid 3way setup, then we strip
3837 // (nop) the timestamp option. this includes the cases where
3838 // we disable timestamp handling.
3839 int strip = ( SetupOK(talker) && SetupOK(listener) );
3840 #else
3841 int strip = 0;
3842 #endif
3843 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3844 "listener not doing timestamps...\n"););
3845 *got_ts = StreamGetTcpTimestamp(p, &tdb->ts, strip);
3846
3847 if (*got_ts)
3848 {
3849 if (!(talker->flags & TF_TSTAMP))
3850 {
3851 /* Since we skipped the SYN, may have missed the talker's
3852 * timestamp there, so set it now.
3853 */
3854 talker->flags |= TF_TSTAMP;
3855 if (tdb->ts == 0)
3856 {
3857 talker->flags |= TF_TSTAMP_ZERO;
3858 }
3859 }
3860
3861 /* Only valid to test this if listener is using timestamps.
3862 * Otherwise, timestamp in this packet is not used, regardless
3863 * of its value. */
3864 if ((tdb->ts == 0) && (listener->flags & TF_TSTAMP))
3865 {
3866 switch (listener->os_policy)
3867 {
3868 case STREAM_POLICY_WINDOWS:
3869 case STREAM_POLICY_VISTA:
3870 case STREAM_POLICY_WINDOWS2K3:
3871 case STREAM_POLICY_OLD_LINUX:
3872 case STREAM_POLICY_SOLARIS:
3873 /* Old Linux & Windows allows a 0 timestamp value. */
3874 break;
3875 default:
3876 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3877 "Packet with 0 timestamp, dropping\n"););
3878 //Discard();
3879 /* bail */
3880 *eventcode |= EVENT_BAD_TIMESTAMP;
3881 return ACTION_BAD_PKT;
3882 }
3883 }
3884 }
3885 }
3886 return ACTION_NOTHING;
3887 }
3888
3889 #ifdef S5_PEDANTIC
3890 // From RFC 793:
3891 //
3892 // Segment Receive Test
3893 // Length Window
3894 // ------- ------- -------------------------------------------
3895 //
3896 // 0 0 SEG.SEQ = RCV.NXT
3897 //
3898 // 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
3899 //
3900 // >0 0 not acceptable
3901 //
3902 // >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
3903 // or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
3904 //
ValidSeq(const Packet * p,SessionControlBlock * scb,StreamTracker * st,TcpDataBlock * tdb,bool * before_win_base)3905 static inline int ValidSeq(
3906 const Packet* p, SessionControlBlock *scb, StreamTracker *st, TcpDataBlock *tdb, bool *before_win_base)
3907 {
3908 uint32_t win = StreamGetWindow(scb, st, tdb);
3909
3910 if ( !p->dsize )
3911 {
3912 if ( !win )
3913 {
3914 return ( tdb->seq == st->r_win_base );
3915 }
3916 return SEQ_LEQ(st->r_win_base, tdb->seq) &&
3917 SEQ_LT(tdb->seq, st->r_win_base+win);
3918 }
3919 if ( !win )
3920 return 0;
3921
3922 if ( SEQ_LEQ(st->r_win_base, tdb->seq) &&
3923 SEQ_LT(tdb->seq, st->r_win_base+win) )
3924 return 1;
3925
3926 return SEQ_LEQ(st->r_win_base, tdb->end_seq) &&
3927 SEQ_LT(tdb->end_seq, st->r_win_base+win);
3928 }
3929 #else
ValidSeq(const Packet * p,SessionControlBlock * scb,StreamTracker * st,TcpDataBlock * tdb,bool * before_win_base)3930 static inline int ValidSeq(
3931 const Packet* p, SessionControlBlock *scb, StreamTracker *st, TcpDataBlock *tdb, bool *before_win_base)
3932 {
3933 int right_ok;
3934 uint32_t left_seq;
3935
3936 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3937 "Checking end_seq (%X) > r_win_base (%X) && "
3938 "seq (%X) < r_nxt_ack(%X)\n",
3939 tdb->end_seq, st->r_win_base, tdb->seq,
3940 st->r_nxt_ack+StreamGetWindow(scb, st, tdb)););
3941
3942 if ( SEQ_LT(st->r_nxt_ack, st->r_win_base) )
3943 left_seq = st->r_nxt_ack;
3944 else
3945 left_seq = st->r_win_base;
3946
3947 if ( p->dsize )
3948 right_ok = SEQ_GT(tdb->end_seq, left_seq);
3949 else
3950 right_ok = SEQ_GEQ(tdb->end_seq, left_seq);
3951
3952 if ( right_ok )
3953 {
3954 uint32_t win = StreamGetWindow(scb, st, tdb);
3955
3956 if( SEQ_LEQ(tdb->seq, st->r_win_base+win) )
3957 {
3958 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3959 "seq is within window!\n"););
3960 return 1;
3961 }
3962 else
3963 {
3964 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3965 "seq is past the end of the window!\n"););
3966 }
3967 }
3968 else
3969 {
3970 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
3971 "end_seq is before win_base\n"););
3972 *before_win_base = true;
3973 }
3974 return 0;
3975 }
3976 #endif
3977
UpdateSsn(Packet * p,StreamTracker * rcv,StreamTracker * snd,TcpDataBlock * tdb)3978 static inline void UpdateSsn(Packet* p, StreamTracker *rcv, StreamTracker *snd, TcpDataBlock *tdb)
3979 {
3980 #if 0
3981 #ifdef NORMALIZER
3982 if (
3983 // FIXTHIS these checks are a hack to avoid off by one normalization
3984 // due to FIN ... if last segment filled a hole, r_nxt_ack is not at
3985 // end of data, FIN is ignored so sequence isn't bumped, and this
3986 // forces seq-- on ACK of FIN. :(
3987 rcv->s_mgr.state == TCP_STATE_ESTABLISHED &&
3988 rcv->s_mgr.state_queue == TCP_STATE_NONE &&
3989 Normalize_GetMode(snort_conf, NORM_TCP_IPS) )
3990 {
3991 // walk the seglist until a gap or tdb->ack whichever is first
3992 // if a gap exists prior to ack, move ack back to start of gap
3993 StreamSegment* seg = snd->seglist;
3994
3995 // FIXTHIS must check ack oob with empty seglist
3996 // FIXTHIS add lower gap bound to tracker for efficiency?
3997 while ( seg )
3998 {
3999 uint32_t seq = seg->seq + seg->size;
4000 if ( SEQ_LEQ(tdb->ack, seq) )
4001 break;
4002
4003 seg = seg->next;
4004
4005 if ( !seg || seg->seq > seq )
4006 {
4007 // normalize here
4008 tdb->ack = seq;
4009 ((TCPHdr*)p->tcph)->th_ack = htonl(seq);
4010 p->packet_flags |= PKT_MODIFIED;
4011 break;
4012 }
4013 }
4014 }
4015 #endif
4016 #endif
4017 // ** if we don't see a segment, we can't track seq at ** below
4018 // so we update the seq by the ack if it is beyond next expected
4019 if(SEQ_GT(tdb->ack, rcv->l_unackd))
4020 rcv->l_unackd = tdb->ack;
4021
4022 // ** this is how we track the last seq number sent
4023 // as is l_unackd is the "last left" seq recvd
4024 snd->l_unackd = tdb->seq;
4025
4026 if (SEQ_GT(tdb->end_seq, snd->l_nxt_seq))
4027 snd->l_nxt_seq = tdb->end_seq;
4028
4029 #ifdef S5_PEDANTIC
4030 if ( SEQ_GT(tdb->ack, snd->r_win_base) &&
4031 SEQ_LEQ(tdb->ack, snd->r_nxt_ack) )
4032 #else
4033 if ( SEQ_GT(tdb->ack, snd->r_win_base) )
4034 #endif
4035 snd->r_win_base = tdb->ack;
4036
4037 snd->l_window = tdb->win;
4038 }
4039
StreamInitPacket(void)4040 static void StreamInitPacket(void)
4041 {
4042 s5_pkt = Encode_New();
4043 }
4044
SetupTcpDataBlock(TcpDataBlock * tdb,Packet * p)4045 static inline void SetupTcpDataBlock(TcpDataBlock *tdb, Packet *p)
4046 {
4047 tdb->seq = ntohl(p->tcph->th_seq);
4048 tdb->ack = ntohl(p->tcph->th_ack);
4049 tdb->win = ntohs(p->tcph->th_win);
4050 tdb->end_seq = tdb->seq + (uint32_t) p->dsize;
4051 tdb->ts = 0;
4052
4053 if(p->tcph->th_flags & TH_SYN)
4054 {
4055 tdb->end_seq++;
4056 }
4057 // don't bump end_seq for fin here
4058 // we will bump if/when fin is processed
4059
4060 return;
4061 }
4062
SegmentFree(StreamSegment * seg)4063 static void SegmentFree (StreamSegment *seg)
4064 {
4065 unsigned dropped = sizeof(StreamSegment);
4066
4067 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
4068 "Dumping segment at seq %X, size %d, caplen %d\n",
4069 seg->seq, seg->size, seg->caplen););
4070
4071 if ( seg->caplen > 0 )
4072 dropped += seg->caplen - 1; // seg contains 1st byte
4073
4074 session_mem_in_use -= dropped;
4075 SnortPreprocFree(seg, dropped, PP_STREAM, PP_MEM_CATEGORY_SESSION);
4076 s5stats.tcp_streamsegs_released++;
4077
4078 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
4079 "SegmentFree dropped %d bytes\n", dropped););
4080 }
4081
DeleteSeglist(StreamSegment * listhead)4082 static void DeleteSeglist(StreamSegment *listhead)
4083 {
4084 StreamSegment *idx = listhead;
4085 StreamSegment *dump_me;
4086 int i = 0;
4087
4088 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
4089 "In DeleteSeglist\n"););
4090 while(idx)
4091 {
4092 i++;
4093 dump_me = idx;
4094 idx = idx->next;
4095 SegmentFree(dump_me);
4096 }
4097
4098 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
4099 "Dropped %d segments\n", i););
4100 }
4101
purge_alerts(StreamTracker * st,uint32_t flush_seq,void * ssnptr)4102 static inline int purge_alerts(StreamTracker *st, uint32_t flush_seq, void *ssnptr)
4103 {
4104 int i;
4105 int new_count = 0;
4106
4107 for (i=0;i<st->alert_count;i++)
4108 {
4109 StreamAlertInfo* ai = st->alerts + i;
4110
4111 if (SEQ_LT(ai->seq, flush_seq) )
4112 {
4113 if(st->xtradata_mask && extra_data_log)
4114 {
4115 extra_data_log(
4116 ssnptr, extra_data_config, xtradata_map,
4117 xtradata_func_count, st->xtradata_mask,
4118 ai->event_id, ai->event_second);
4119 }
4120 memset(ai, 0, sizeof(*ai));
4121 }
4122 else
4123 {
4124 if (new_count != i)
4125 {
4126 st->alerts[new_count] = st->alerts[i];
4127 }
4128 new_count++;
4129 }
4130 }
4131 st->alert_count = new_count;
4132
4133 return new_count;
4134 }
4135
purge_to_seq(TcpSession * tcpssn,StreamTracker * st,uint32_t flush_seq)4136 static inline int purge_to_seq(TcpSession *tcpssn, StreamTracker *st, uint32_t flush_seq)
4137 {
4138 StreamSegment *ss = NULL;
4139 StreamSegment *dump_me = NULL;
4140 int purged_bytes = 0;
4141 uint32_t last_ts = 0;
4142
4143 if(st->seglist == NULL)
4144 {
4145 if ( SEQ_LT(st->seglist_base_seq, flush_seq) )
4146 {
4147 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4148 "setting st->seglist_base_seq to 0x%X\n", flush_seq););
4149 st->seglist_base_seq = flush_seq;
4150 }
4151 return 0;
4152 }
4153
4154 ss = st->seglist;
4155
4156 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4157 "In purge_to_seq, start seq = 0x%X end seq = 0x%X delta %d\n",
4158 ss->seq, flush_seq, flush_seq-ss->seq););
4159 while(ss)
4160 {
4161 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4162 "s: %X sz: %d\n", ss->seq, ss->size););
4163 dump_me = ss;
4164
4165 ss = ss->next;
4166 if(SEQ_LT(dump_me->seq, flush_seq))
4167 {
4168 if (dump_me->ts > last_ts)
4169 {
4170 last_ts = dump_me->ts;
4171 }
4172 purged_bytes += StreamSeglistDeleteNodeTrim(st, dump_me, flush_seq);
4173 }
4174 else
4175 break;
4176 }
4177
4178 if ( SEQ_LT(st->seglist_base_seq, flush_seq) )
4179 {
4180 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4181 "setting st->seglist_base_seq to 0x%X\n", flush_seq););
4182 st->seglist_base_seq = flush_seq;
4183 }
4184 if ( SEQ_LT(st->r_nxt_ack, flush_seq) )
4185 st->r_nxt_ack = flush_seq;
4186
4187 purge_alerts(st, flush_seq, (void *)tcpssn->scb);
4188
4189 if (st->seglist == NULL)
4190 {
4191 st->seglist_tail = NULL;
4192 }
4193
4194 /* Update the "last" time stamp seen from the other side
4195 * to be the most recent timestamp (largest) that was removed
4196 * from the queue. This will ensure that as we go forward,
4197 * last timestamp is the highest one that we had stored and
4198 * purged and handle the case when packets arrive out of order,
4199 * such as:
4200 * P1: seq 10, length 10, timestamp 10
4201 * P3: seq 30, length 10, timestamp 30
4202 * P2: seq 20, length 10, timestamp 20
4203 *
4204 * Without doing it this way, the timestamp would be 20. With
4205 * the next packet to arrive (P4, seq 40), the ts_last value
4206 * wouldn't be updated for the talker in ProcessTcp() since that
4207 * code specificially looks for the NEXT sequence number.
4208 */
4209 if ( !last_ts )
4210 return purged_bytes;
4211
4212 if (st == &tcpssn->client)
4213 {
4214 int32_t delta = last_ts - tcpssn->server.ts_last;
4215 if (delta > 0)
4216 tcpssn->server.ts_last = last_ts;
4217 }
4218 else if (st == &tcpssn->server)
4219 {
4220 int32_t delta = last_ts - tcpssn->client.ts_last;
4221 if (delta > 0)
4222 tcpssn->client.ts_last = last_ts;
4223 }
4224
4225 return purged_bytes;
4226 }
4227
purge_all(StreamTracker * st)4228 static inline void purge_all (StreamTracker *st)
4229 {
4230 DeleteSeglist(st->seglist);
4231 st->seglist = st->seglist_tail = st->seglist_next = NULL;
4232 st->seg_count = st->flush_count = 0;
4233 st->seg_bytes_total = st->seg_bytes_logical = 0;
4234 }
4235
4236 // purge_flushed_ackd():
4237 // * must only purge flushed and acked bytes
4238 // * we may flush partial segments
4239 // * must adjust seq->seq and seg->size when a flush gets only the
4240 // initial part of a segment
4241 // * FIXTHIS need flag to mark any reassembled packets that have a gap
4242 // (if we reassemble such)
purge_flushed_ackd(TcpSession * tcpssn,StreamTracker * st)4243 static inline int purge_flushed_ackd (TcpSession *tcpssn, StreamTracker *st)
4244 {
4245 StreamSegment* seg = st->seglist;
4246 uint32_t seq;
4247
4248 if ( !st->seglist )
4249 return 0;
4250
4251 seq = st->seglist->seq;
4252
4253 while ( seg && seg->buffered )
4254 {
4255 uint32_t end = seg->seq + seg->size;
4256
4257 if ( SEQ_GT(end, st->r_win_base) )
4258 {
4259 seq = st->r_win_base;
4260 break;
4261 }
4262 seq = end;
4263 seg = seg->next;
4264 }
4265 if ( seq != st->seglist->seq )
4266 return purge_to_seq(tcpssn, st, seq);
4267
4268 return 0;
4269 }
4270
ShowRebuiltPacket(Packet * p)4271 static void ShowRebuiltPacket (Packet* p)
4272 {
4273 if(stream_session_config->flags & STREAM_CONFIG_SHOW_PACKETS)
4274 {
4275 //ClearDumpBuf();
4276 printf("+++++++++++++++++++Stream Packet+++++++++++++++++++++\n");
4277 PrintIPPkt(stdout, IPPROTO_TCP, p);
4278 printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
4279 //ClearDumpBuf();
4280 }
4281 }
4282
_flush_to_seq_noack(TcpSession * tcpssn,StreamTracker * st,uint32_t bytes,Packet * p,sfaddr_t * sip,sfaddr_t * dip,uint16_t sp,uint16_t dp,uint32_t dir)4283 static inline int _flush_to_seq_noack( TcpSession *tcpssn, StreamTracker *st, uint32_t bytes,
4284 Packet *p, sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir )
4285 {
4286 uint32_t stop_seq;
4287 uint32_t footprint = 0;
4288 uint32_t bytes_processed = 0;
4289 PROFILE_VARS;
4290
4291 PREPROC_PROFILE_START(s5TcpFlushPerfStats);
4292
4293 if(p->dsize == 0)
4294 return bytes_processed;
4295
4296 // if not specified, set bytes to flush to what was acked
4297 if ( !bytes && SEQ_GT(st->r_win_base, st->seglist_base_seq) )
4298 bytes = st->r_win_base - st->seglist_base_seq;
4299
4300 stop_seq = st->seglist_base_seq + bytes;
4301
4302 {
4303 footprint = stop_seq - st->seglist_base_seq;
4304
4305 if(footprint == 0)
4306 {
4307 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4308 "Negative footprint, bailing %d (0x%X - 0x%X)\n",
4309 footprint, stop_seq, st->seglist_base_seq););
4310 PREPROC_PROFILE_END(s5TcpFlushPerfStats);
4311
4312 return bytes_processed;
4313 }
4314
4315 #if 0
4316 //Might not need this as we are not buffering the packets??
4317 #ifdef DEBUG_STREAM
4318 if(footprint < st->seg_bytes_logical)
4319 {
4320 STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4321 "Footprint less than queued bytes, "
4322 "win_base: 0x%X base_seq: 0x%X\n",
4323 stop_seq, st->seglist_base_seq););
4324 }
4325 #endif
4326 #endif
4327
4328 #if 0
4329 //Won't need this as we are not buffering the packets
4330 if(footprint > p->max_dsize)
4331 {
4332 /* this is as much as we can pack into a stream buffer */
4333 footprint = p->max_dsize;
4334 stop_seq = st->seglist_base_seq + footprint;
4335 }
4336 #endif
4337
4338 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4339 "Attempting to flush %lu bytes\n", footprint););
4340
4341 st->seglist_base_seq = stop_seq;
4342 st->seglist_next->buffered = SL_BUF_FLUSHED;
4343 st->flush_count++;
4344 p->packet_flags &= ~PKT_STREAM_INSERT;
4345 p->packet_flags |= (PKT_REBUILT_STREAM|PKT_STREAM_EST);
4346 bytes_processed = p->dsize;
4347
4348 sfBase.iStreamFlushes++;
4349 ShowRebuiltPacket(p);
4350 s5stats.tcp_rebuilt_packets++;
4351 UpdateStreamReassStats(&sfBase, bytes_processed);
4352
4353 }
4354
4355 if ( st->tcp_policy )
4356 UpdateFlushMgr(snort_conf, &st->flush_mgr, &st->tcp_policy->flush_point_list, st->flags);
4357
4358 /* tell them how many bytes we processed */
4359 PREPROC_PROFILE_END(s5TcpFlushPerfStats);
4360 return bytes_processed;
4361 }
4362
getSegmentFlushSize(StreamTracker * st,StreamSegment * ss,uint32_t to_seq,unsigned int flushBufSize)4363 static inline unsigned int getSegmentFlushSize(
4364 StreamTracker* st,
4365 StreamSegment *ss,
4366 uint32_t to_seq,
4367 unsigned int flushBufSize
4368 )
4369 {
4370 unsigned int flushSize = ss->size;
4371
4372 //copy only till flush buffer gets full
4373 if ( flushSize > flushBufSize )
4374 flushSize = flushBufSize;
4375
4376 // copy only to flush point
4377 if ( s5_paf_active(&st->paf_state) && SEQ_GT(ss->seq + flushSize, to_seq) )
4378 flushSize = to_seq - ss->seq;
4379
4380 return flushSize;
4381 }
4382
PseudoFlushStream(Packet * p,StreamTracker * st,uint32_t toSeq,uint8_t * flushbuf,const uint8_t * flushbuf_end)4383 static int PseudoFlushStream(
4384 Packet* p, StreamTracker *st, uint32_t toSeq,
4385 uint8_t *flushbuf, const uint8_t *flushbuf_end)
4386 {
4387 StreamSegment *ss = NULL, *seglist;
4388 uint16_t bytes_flushed = 0;
4389 uint32_t flushbuf_size, bytes_to_copy;
4390 int ret;
4391 PROFILE_VARS;
4392
4393 if ( st->seglist == NULL || st->seglist_tail == NULL )
4394 return -1;
4395
4396 PREPROC_PROFILE_START(s5TcpBuildPacketPerfStats);
4397
4398 // skip over previously pseudo flushed segments
4399 seglist = st->seglist_next;
4400
4401 for(ss = seglist; ss && SEQ_LT(ss->seq, toSeq); ss = ss->next)
4402 {
4403 flushbuf_size = flushbuf_end - flushbuf;
4404 bytes_to_copy = getSegmentFlushSize(st, ss, toSeq, flushbuf_size);
4405
4406 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4407 "Copying %u bytes for pseudo flushing from %X\n",
4408 bytes_to_copy, ss->seq););
4409
4410 ret = SafeMemcpy(flushbuf, ss->payload,
4411 bytes_to_copy, flushbuf, flushbuf_end);
4412
4413 if (ret == SAFEMEM_ERROR)
4414 {
4415 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4416 "ERROR writing flushbuf while pseudo flushing."
4417 "Attempting to write flushbuf out of range!\n"););
4418 }
4419 else
4420 {
4421 flushbuf += bytes_to_copy;
4422 }
4423
4424 bytes_flushed += bytes_to_copy;
4425 if (ss->next)
4426 {
4427 st->seglist_next = ss->next;
4428 }
4429
4430 if ( flushbuf >= flushbuf_end )
4431 break;
4432
4433 if ( SEQ_EQ(ss->seq + bytes_to_copy, toSeq) )
4434 break;
4435
4436 }
4437
4438 PREPROC_PROFILE_END(s5TcpBuildPacketPerfStats);
4439 return bytes_flushed;
4440 }
4441
pseudo_flush(TcpSession * tcpssn,StreamTracker * st,uint32_t bytes,Packet * p,sfaddr_t * sip,sfaddr_t * dip,uint16_t sp,uint16_t dp,uint32_t dir)4442 static inline void pseudo_flush(
4443 TcpSession *tcpssn, StreamTracker *st, uint32_t bytes, Packet *p,
4444 sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
4445 {
4446 uint32_t start_seq;
4447 uint32_t stop_seq;
4448 uint32_t footprint = 0;
4449 uint32_t bytes_processed = 0;
4450 int32_t flushed_bytes;
4451 StreamSegment *ss = NULL;
4452
4453 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
4454 DAQ_PktHdr_t pkth;
4455 #endif
4456 EncodeFlags enc_flags = 0;
4457 PROFILE_VARS;
4458
4459 if (!bytes)
4460 {
4461 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4462 "No bytes to pseudo flush\n"););
4463 return;
4464 }
4465 PREPROC_PROFILE_START(s5TcpFlushPerfStats);
4466
4467 if ( !p->packet_flags || (dir & p->packet_flags) )
4468 enc_flags = ENC_FLAG_FWD;
4469
4470 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
4471 GetPacketHeaderFoo(tcpssn, p->pkth, enc_flags, &pkth, dir);
4472 Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, &pkth, 0);
4473 #elif defined(HAVE_DAQ_ACQUIRE_WITH_META)
4474 Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, 0);
4475 #else
4476 Encode_Format(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP);
4477 #endif
4478
4479 s5_pkt_end = s5_pkt->data + s5_pkt->max_dsize;
4480
4481 ss = st->seglist_next;
4482 stop_seq = st->seglist_next->seq + bytes;
4483 do
4484 {
4485 footprint = bytes;
4486 if(footprint > s5_pkt->max_dsize)
4487 {
4488 /* this is as much as we can pack into a stream buffer */
4489 footprint = s5_pkt->max_dsize;
4490 stop_seq = st->seglist_next->seq + footprint;
4491 }
4492
4493 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4494 "Attempting to pseudo flush %lu bytes\n", footprint););
4495 /* Capture the seq of the first octet before flush changes the sequence numbers */
4496 start_seq = htonl(st->seglist_next->seq);
4497
4498 /* setup the pseudopacket payload */
4499 flushed_bytes = PseudoFlushStream(p, st, stop_seq, (uint8_t *)s5_pkt->data, s5_pkt_end);
4500
4501 if(flushed_bytes == -1)
4502 {
4503 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4504 "Failed to pseudo flush the stream\n"););
4505 return;
4506 }
4507 if (flushed_bytes == 0)
4508 {
4509 /* No more ACK'd data... bail */
4510 break;
4511 }
4512
4513 bytes_processed += flushed_bytes;
4514
4515 ((TCPHdr *)s5_pkt->tcph)->th_seq = start_seq;
4516 s5_pkt->packet_flags |= (PKT_REBUILT_STREAM|PKT_STREAM_EST);
4517 s5_pkt->dsize = (uint16_t)flushed_bytes;
4518
4519 s5_pkt->packet_flags |= PKT_PDU_TAIL;
4520 s5_pkt->packet_flags |= PKT_PSEUDO_FLUSH;
4521
4522 Encode_Update(s5_pkt);
4523
4524 if(IS_IP4(s5_pkt))
4525 {
4526 s5_pkt->inner_ip4h.ip_len = s5_pkt->iph->ip_len;
4527 }
4528 else
4529 {
4530 IP6RawHdr* ip6h = (IP6RawHdr*)s5_pkt->raw_ip6h;
4531 if ( ip6h ) s5_pkt->inner_ip6h.len = ip6h->ip6plen;
4532 }
4533
4534 ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_sec = st->seglist_next->tv.tv_sec;
4535 ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_usec = st->seglist_next->tv.tv_usec;
4536
4537 s5_pkt->packet_flags |= dir;
4538 s5_pkt->ssnptr = (void *) tcpssn->scb;
4539 #ifdef TARGET_BASED
4540 s5_pkt->application_protocol_ordinal = p->application_protocol_ordinal;
4541 #endif
4542 PREPROC_PROFILE_TMPEND(s5TcpFlushPerfStats);
4543 {
4544 int tmp_do_detect, tmp_do_detect_content;
4545 PROFILE_VARS;
4546
4547 PREPROC_PROFILE_START(s5TcpProcessRebuiltPerfStats);
4548 tmp_do_detect = do_detect;
4549 tmp_do_detect_content = do_detect_content;
4550
4551 SnortEventqPush();
4552 Preprocess(s5_pkt);
4553 SnortEventqPop();
4554 DetectReset(s5_pkt->data, s5_pkt->dsize);
4555
4556 do_detect = tmp_do_detect;
4557 do_detect_content = tmp_do_detect_content;
4558 PREPROC_PROFILE_END(s5TcpProcessRebuiltPerfStats);
4559 }
4560 PREPROC_PROFILE_TMPSTART(s5TcpFlushPerfStats);
4561 } while(bytes_processed < bytes);
4562
4563 st->seglist_next = ss;
4564 PREPROC_PROFILE_END(s5TcpFlushPerfStats);
4565 }
4566
_flush_to_seq(TcpSession * tcpssn,StreamTracker * st,uint32_t bytes,Packet * p,sfaddr_t * sip,sfaddr_t * dip,uint16_t sp,uint16_t dp,uint32_t dir)4567 static inline int _flush_to_seq (
4568
4569 TcpSession *tcpssn, StreamTracker *st, uint32_t bytes, Packet *p,
4570 sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
4571 {
4572 uint32_t start_seq;
4573 uint32_t stop_seq;
4574 uint32_t footprint = 0;
4575 uint32_t bytes_processed = 0;
4576 int32_t flushed_bytes;
4577
4578 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
4579 DAQ_PktHdr_t pkth;
4580 #endif
4581 EncodeFlags enc_flags = 0;
4582 PROFILE_VARS;
4583
4584 PREPROC_PROFILE_START(s5TcpFlushPerfStats);
4585
4586 if(st->paf_state.fpt_eoh)
4587 tcpssn->pp_flags |= PP_HTTPINSPECT_PAF_FLUSH_POST_HDR;
4588 else
4589 tcpssn->pp_flags &= ~PP_HTTPINSPECT_PAF_FLUSH_POST_HDR;
4590
4591 if ( !p->packet_flags || (dir & p->packet_flags) )
4592 enc_flags = ENC_FLAG_FWD;
4593
4594 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
4595 GetPacketHeaderFoo(tcpssn, p->pkth, enc_flags, &pkth, dir);
4596 Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, &pkth, 0);
4597 #elif defined(HAVE_DAQ_ACQUIRE_WITH_META)
4598 Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, 0);
4599 #else
4600 Encode_Format(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP);
4601 #endif
4602
4603 s5_pkt_end = s5_pkt->data + s5_pkt->max_dsize;
4604
4605 // TBD in ips mode, these should be coming from current packet (tdb)
4606 ((TCPHdr *)s5_pkt->tcph)->th_ack = htonl(st->l_unackd);
4607 ((TCPHdr *)s5_pkt->tcph)->th_win = htons((uint16_t)st->l_window);
4608
4609 // if not specified, set bytes to flush to what was acked
4610 if ( !bytes && SEQ_GT(st->r_win_base, st->seglist_base_seq) )
4611 bytes = st->r_win_base - st->seglist_base_seq;
4612
4613 stop_seq = st->seglist_base_seq + bytes;
4614
4615 do
4616 {
4617 footprint = stop_seq - st->seglist_base_seq;
4618
4619 if(footprint == 0)
4620 {
4621 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4622 "Negative footprint, bailing %d (0x%X - 0x%X)\n",
4623 footprint, stop_seq, st->seglist_base_seq););
4624 PREPROC_PROFILE_END(s5TcpFlushPerfStats);
4625
4626 return bytes_processed;
4627 }
4628
4629 #ifdef STREAM_DEBUG_ENABLED
4630 if(footprint < st->seg_bytes_logical)
4631 {
4632 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4633 "Footprint less than queued bytes, "
4634 "win_base: 0x%X base_seq: 0x%X\n",
4635 stop_seq, st->seglist_base_seq););
4636 }
4637 #endif
4638
4639 if(footprint > s5_pkt->max_dsize)
4640 {
4641 /* this is as much as we can pack into a stream buffer */
4642 footprint = s5_pkt->max_dsize;
4643 stop_seq = st->seglist_base_seq + footprint;
4644 }
4645
4646 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4647 "Attempting to flush %lu bytes\n", footprint););
4648
4649 /* Capture the seq of the first octet before flush changes the sequence numbers */
4650 start_seq = htonl(st->seglist_next->seq);
4651
4652 /* setup the pseudopacket payload */
4653 flushed_bytes = FlushStream(p, st, stop_seq, (uint8_t *)s5_pkt->data, s5_pkt_end);
4654
4655 if(flushed_bytes == -1)
4656 {
4657 /* couldn't put a stream together for whatever reason
4658 * should probably clean the seglist and bail...
4659 */
4660 if(st->seglist)
4661 {
4662 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4663 "dumping entire seglist!\n"););
4664 purge_all(st);
4665 }
4666
4667 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4668 "setting st->seglist_base_seq to 0x%X\n", stop_seq););
4669 st->seglist_base_seq = stop_seq;
4670
4671 PREPROC_PROFILE_END(s5TcpFlushPerfStats);
4672 return bytes_processed;
4673 }
4674
4675 if (flushed_bytes == 0)
4676 {
4677 /* No more ACK'd data... bail */
4678 break;
4679 }
4680
4681 ((TCPHdr *)s5_pkt->tcph)->th_seq = start_seq;
4682 s5_pkt->packet_flags |= (PKT_REBUILT_STREAM|PKT_STREAM_EST);
4683 s5_pkt->dsize = (uint16_t)flushed_bytes;
4684
4685 if ((p->packet_flags & PKT_PDU_TAIL))
4686 s5_pkt->packet_flags |= PKT_PDU_TAIL;
4687
4688 /* Rebuilt packet with only and complete http-post header is set with PKT_EVAL_DROP,
4689 * it will be used to evalute drop/allow packet by preprocs
4690 */
4691 if (tcpssn->pp_flags & PP_HTTPINSPECT_PAF_FLUSH_POST_HDR)
4692 s5_pkt->packet_flags |= PKT_EVAL_DROP;
4693
4694 Encode_Update(s5_pkt);
4695
4696 if(IS_IP4(s5_pkt))
4697 {
4698 s5_pkt->inner_ip4h.ip_len = s5_pkt->iph->ip_len;
4699 }
4700 else
4701 {
4702 IP6RawHdr* ip6h = (IP6RawHdr*)s5_pkt->raw_ip6h;
4703 if ( ip6h ) s5_pkt->inner_ip6h.len = ip6h->ip6plen;
4704 }
4705
4706 ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_sec = st->seglist_next->tv.tv_sec;
4707 ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_usec = st->seglist_next->tv.tv_usec;
4708
4709 sfBase.iStreamFlushes++;
4710 bytes_processed += s5_pkt->dsize;
4711
4712 s5_pkt->packet_flags |= dir;
4713 s5_pkt->ssnptr = (void *) tcpssn->scb;
4714 #ifdef TARGET_BASED
4715 s5_pkt->application_protocol_ordinal = p->application_protocol_ordinal;
4716 #endif
4717 ShowRebuiltPacket(s5_pkt);
4718 s5stats.tcp_rebuilt_packets++;
4719 UpdateStreamReassStats(&sfBase, flushed_bytes);
4720
4721 PREPROC_PROFILE_TMPEND(s5TcpFlushPerfStats);
4722 {
4723 int tmp_do_detect, tmp_do_detect_content;
4724 PROFILE_VARS;
4725
4726 PREPROC_PROFILE_START(s5TcpProcessRebuiltPerfStats);
4727 tmp_do_detect = do_detect;
4728 tmp_do_detect_content = do_detect_content;
4729
4730 SnortEventqPush();
4731 Preprocess(s5_pkt);
4732 SnortEventqPop();
4733 DetectReset(s5_pkt->data, s5_pkt->dsize);
4734
4735 do_detect = tmp_do_detect;
4736 do_detect_content = tmp_do_detect_content;
4737 PREPROC_PROFILE_END(s5TcpProcessRebuiltPerfStats);
4738 }
4739 PREPROC_PROFILE_TMPSTART(s5TcpFlushPerfStats);
4740
4741 // TBD abort should be by PAF callback only since
4742 // recovery may be possible in some cases
4743 if ( st->flags & TF_MISSING_PKT )
4744 {
4745 st->flags |= TF_MISSING_PREV_PKT;
4746 st->flags |= TF_PKT_MISSED;
4747 st->flags &= ~TF_MISSING_PKT;
4748 s5stats.tcp_gaps++;
4749 }
4750 else
4751 {
4752 st->flags &= ~TF_MISSING_PREV_PKT;
4753 }
4754 } while ( DataToFlush(st) );
4755
4756 if ( st->tcp_policy )
4757 UpdateFlushMgr(snort_conf, &st->flush_mgr, &st->tcp_policy->flush_point_list, st->flags);
4758
4759 /* tell them how many bytes we processed */
4760 PREPROC_PROFILE_END(s5TcpFlushPerfStats);
4761 return bytes_processed;
4762 }
4763
flush_to_seq_noack(TcpSession * tcpssn,StreamTracker * st,uint32_t bytes,Packet * p,sfaddr_t * sip,sfaddr_t * dip,uint16_t sp,uint16_t dp,uint32_t dir)4764 static inline int flush_to_seq_noack( TcpSession *tcpssn, StreamTracker *st, uint32_t bytes,
4765 Packet *p, sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir )
4766 {
4767 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4768 "In flush_to_seq_noack()\n"););
4769
4770 if ( !bytes )
4771 {
4772 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4773 "bailing, no data\n"););
4774 return 0;
4775 }
4776
4777 if ( !st->seglist_next )
4778 {
4779 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4780 "bailing, bad seglist ptr\n"););
4781 return 0;
4782 }
4783
4784 #if 0
4785 //Might not need this. Check with Russ.
4786 if (!DataToFlush(st) && !(st->flags & TF_FORCE_FLUSH))
4787 {
4788 STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4789 "only 1 packet in seglist no need to flush\n"););
4790 return 0;
4791 }
4792 #endif
4793
4794 st->flags &= ~TF_MISSING_PKT;
4795 st->flags &= ~TF_MISSING_PREV_PKT;
4796
4797 /* This will set this flag on the first reassembly
4798 * if reassembly for this direction was set midstream */
4799 if ( SEQ_LT(st->seglist_base_seq, st->seglist_next->seq) )
4800 {
4801 uint32_t missed = st->seglist_next->seq - st->seglist_base_seq;
4802
4803 if ( missed <= bytes )
4804 bytes -= missed;
4805
4806 st->flags |= TF_MISSING_PREV_PKT;
4807 st->flags |= TF_PKT_MISSED;
4808 s5stats.tcp_gaps++;
4809 st->seglist_base_seq = st->seglist_next->seq;
4810
4811 if ( !bytes )
4812 return 0;
4813 }
4814
4815 return _flush_to_seq_noack(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
4816
4817 }
4818 /*
4819 * flush a seglist up to the given point, generate a pseudopacket,
4820 * and fire it thru the system.
4821 */
flush_to_seq(TcpSession * tcpssn,StreamTracker * st,uint32_t bytes,Packet * p,sfaddr_t * sip,sfaddr_t * dip,uint16_t sp,uint16_t dp,uint32_t dir)4822 static inline int flush_to_seq(
4823 TcpSession *tcpssn, StreamTracker *st, uint32_t bytes, Packet *p,
4824 sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
4825 {
4826 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4827 "In flush_to_seq()\n"););
4828
4829 if ( !bytes )
4830 {
4831 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4832 "bailing, no data\n"););
4833 return 0;
4834 }
4835
4836 if ( !st->seglist_next )
4837 {
4838 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4839 "bailing, bad seglist ptr\n"););
4840 return 0;
4841 }
4842
4843 if (!DataToFlush(st) && !(st->flags & TF_FORCE_FLUSH))
4844 {
4845 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
4846 "only 1 packet in seglist no need to flush\n"););
4847 return 0;
4848 }
4849
4850 st->flags &= ~TF_MISSING_PREV_PKT;
4851
4852 /* This will set this flag on the first reassembly
4853 * if reassembly for this direction was set midstream */
4854 if ( SEQ_LT(st->seglist_base_seq, st->seglist_next->seq) &&
4855 !(st->flags & TF_FIRST_PKT_MISSING) )
4856 {
4857 uint32_t missed = st->seglist_next->seq - st->seglist_base_seq;
4858
4859 if ( missed <= bytes )
4860 bytes -= missed;
4861
4862 st->flags |= TF_MISSING_PREV_PKT;
4863 st->flags |= TF_PKT_MISSED;
4864 s5stats.tcp_gaps++;
4865 st->seglist_base_seq = st->seglist_next->seq;
4866
4867 if ( !bytes )
4868 return 0;
4869 }
4870 st->flags &= ~TF_FIRST_PKT_MISSING;
4871
4872 if (p->packet_flags & PKT_PSEUDO_FLUSH)
4873 {
4874 pseudo_flush(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
4875 return 0;
4876 }
4877
4878 return _flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
4879
4880 }
4881
4882 /*
4883 * get the footprint for the current seglist, the difference
4884 * between our base sequence and the last ack'd sequence we
4885 * received
4886 */
get_q_footprint(StreamTracker * st)4887 static inline uint32_t get_q_footprint(StreamTracker *st)
4888 {
4889 uint32_t fp;
4890
4891 if (st == NULL)
4892 {
4893 return 0;
4894 }
4895
4896 fp = st->r_win_base - st->seglist_base_seq;
4897
4898 if(fp <= 0)
4899 return 0;
4900
4901 st->seglist_next = st->seglist;
4902 return fp;
4903 }
4904
4905 static bool two_way_traffic=true;
4906 // FIXTHIS get_q_sequenced() performance could possibly be
4907 // boosted by tracking sequenced bytes as seglist is updated
4908 // to avoid the while loop, etc. below.
get_q_sequenced(StreamTracker * st)4909 static inline uint32_t get_q_sequenced(StreamTracker *st)
4910 {
4911 uint32_t len;
4912 StreamSegment* seg = st ? st->seglist : NULL;
4913 StreamSegment* base = NULL;
4914
4915 if ( !seg )
4916 return 0;
4917
4918 if ( two_way_traffic && SEQ_LT(st->r_win_base, seg->seq) )
4919 return 0;
4920
4921 while ( seg->next && (seg->next->seq == seg->seq + seg->size) )
4922 {
4923 if ( !seg->buffered && !base )
4924 base = seg;
4925 seg = seg->next;
4926 }
4927 if ( !seg->buffered && !base )
4928 base = seg;
4929
4930 if ( !base )
4931 return 0;
4932
4933 st->seglist_next = base;
4934 st->seglist_base_seq = base->seq;
4935 len = seg->seq + seg->size - base->seq;
4936
4937 return ( len > 0 ) ? len : 0;
4938 }
4939
flush_ackd(TcpSession * tcpssn,StreamTracker * st,Packet * p,sfaddr_t * sip,sfaddr_t * dip,uint16_t sp,uint16_t dp,uint32_t dir)4940 static inline int flush_ackd(
4941 TcpSession *tcpssn, StreamTracker *st, Packet *p,
4942 sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
4943 {
4944 uint32_t bytes = get_q_footprint(st);
4945 return flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
4946 }
4947
4948 // FIXTHIS flush_stream() calls should be replaced with calls to
4949 // CheckFlushPolicyOn*() with the exception that for the *OnAck() case,
4950 // any available ackd data must be flushed in both directions.
flush_stream(TcpSession * tcpssn,StreamTracker * st,Packet * p,sfaddr_t * sip,sfaddr_t * dip,uint16_t sp,uint16_t dp,uint32_t dir)4951 static inline int flush_stream(
4952 TcpSession *tcpssn, StreamTracker *st, Packet *p,
4953 sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
4954 {
4955 FlushMgr* fm;
4956 #ifdef NORMALIZER
4957 if ( Stream_NormGetMode(st->reassembly_policy, snort_conf, NORM_TCP_IPS) == NORM_MODE_ON )
4958 {
4959 uint32_t bytes = get_q_sequenced(st);
4960 return flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
4961 }
4962 #endif
4963 fm = &tcpssn->server.flush_mgr;
4964 if(fm->flush_policy == STREAM_FLPOLICY_PROTOCOL_NOACK)
4965 {
4966 uint32_t bytes = get_q_sequenced(st);
4967 return flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
4968 }
4969 else if (fm->flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK)
4970 {
4971 uint32_t bytes = get_q_sequenced(st);
4972 return flush_to_seq_noack(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
4973 }
4974 return flush_ackd(tcpssn, st, p, sip, dip, sp, dp, dir);
4975 }
4976
FlushStream(Packet * p,StreamTracker * st,uint32_t toSeq,uint8_t * flushbuf,const uint8_t * flushbuf_end)4977 static int FlushStream(
4978 Packet* p, StreamTracker *st, uint32_t toSeq, uint8_t *flushbuf,
4979 const uint8_t *flushbuf_end)
4980 {
4981 StreamSegment *ss = NULL, *seglist, *sr;
4982 uint16_t bytes_flushed = 0;
4983 uint16_t bytes_skipped = 0;
4984 uint32_t bytes_queued = st->seg_bytes_logical;
4985 uint32_t segs = 0;
4986 int ret;
4987 PROFILE_VARS;
4988
4989 if ( st->seglist == NULL || st->seglist_tail == NULL )
4990 return -1;
4991
4992 PREPROC_PROFILE_START(s5TcpBuildPacketPerfStats);
4993
4994 // skip over previously flushed segments
4995 seglist = st->seglist_next;
4996
4997 for(ss = seglist; ss && SEQ_LT(ss->seq, toSeq); ss = ss->next)
4998 {
4999 unsigned int flushbuf_size = flushbuf_end - flushbuf;
5000 unsigned int bytes_to_copy = getSegmentFlushSize(st, ss, toSeq, flushbuf_size);
5001
5002 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5003 "Flushing %u bytes from %X\n", bytes_to_copy, ss->seq));
5004
5005 if(ss->urg_offset >= 1)
5006 {
5007 /* if urg_offset is set, seq + urg_offset is seq # of octet
5008 * in stream following the last urgent octet. all preceding
5009 * octets in segment are considered urgent. this code will
5010 * skip over the urgent data when flushing.
5011 */
5012
5013 unsigned int non_urgent_bytes =
5014 ss->urg_offset < bytes_to_copy ? (bytes_to_copy - ss->urg_offset) : 0;
5015
5016 if ( non_urgent_bytes )
5017 {
5018 ret = SafeMemcpy(flushbuf, ss->payload+ss->urg_offset,
5019 non_urgent_bytes, flushbuf, flushbuf_end);
5020
5021 if (ret == SAFEMEM_ERROR)
5022 {
5023 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5024 "ERROR writing flushbuf attempting to "
5025 "write flushbuf out of range!\n"););
5026 }
5027 else
5028 flushbuf += non_urgent_bytes;
5029
5030 bytes_skipped += ss->urg_offset;
5031 }
5032 else
5033 {
5034 ss->urg_offset = 0;
5035 }
5036 }
5037 else
5038 {
5039 ret = SafeMemcpy(flushbuf, ss->payload,
5040 bytes_to_copy, flushbuf, flushbuf_end);
5041
5042 if (ret == SAFEMEM_ERROR)
5043 {
5044 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5045 "ERROR writing flushbuf attempting to "
5046 "write flushbuf out of range!\n"););
5047 }
5048 else
5049 flushbuf += bytes_to_copy;
5050 }
5051
5052 if ( !st->paf_state.fpt_eoh &&
5053 bytes_to_copy < ss->size &&
5054 DupStreamNode(NULL, st, ss, &sr) == STREAM_INSERT_OK )
5055 {
5056 ss->size = bytes_to_copy;
5057 sr->seq += bytes_to_copy;
5058 sr->size -= bytes_to_copy;
5059 sr->payload += bytes_to_copy + (ss->payload - ss->data);
5060 }
5061
5062 bytes_flushed += bytes_to_copy;
5063 if(!st->paf_state.fpt_eoh){
5064 ss->buffered = SL_BUF_FLUSHED;
5065 st->flush_count++;
5066 segs++;
5067 }
5068
5069 if ( flushbuf >= flushbuf_end )
5070 break;
5071
5072 if ( SEQ_EQ(ss->seq + bytes_to_copy, toSeq) )
5073 break;
5074
5075 /* Check for a gap/missing packet */
5076 // FIXTHIS PAF should account for missing data and resume
5077 // scanning at the start of next PDU instead of aborting.
5078 // FIXTHIS FIN may be in toSeq causing bogus gap counts.
5079 if ( ((ss->next && (ss->seq + ss->size != ss->next->seq)) ||
5080 (!ss->next && (ss->seq + ss->size < toSeq))) &&
5081 !(st->flags & TF_FIRST_PKT_MISSING) )
5082 {
5083 if ( ss->next )
5084 {
5085 toSeq = ss->next->seq;
5086 st->seglist_next = ss->next;
5087 }
5088 st->flags |= TF_MISSING_PKT;
5089 break;
5090 }
5091 }
5092
5093 st->seglist_base_seq = toSeq;
5094
5095 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5096 "setting st->seglist_base_seq to 0x%X\n", st->seglist_base_seq););
5097
5098 bytes_queued -= bytes_flushed;
5099
5100 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5101 "flushed %d bytes / %d segs on stream, "
5102 "skipped %d bytes, %d still queued\n",
5103 bytes_flushed, segs, bytes_skipped, bytes_queued););
5104
5105 PREPROC_PROFILE_END(s5TcpBuildPacketPerfStats);
5106 return bytes_flushed - bytes_skipped;
5107 }
5108
StreamFlushServer(Packet * p,SessionControlBlock * scb)5109 int StreamFlushServer(Packet *p, SessionControlBlock *scb)
5110 {
5111 int flushed;
5112 TcpSession *tcpssn = NULL;
5113 StreamTracker *flushTracker = NULL;
5114
5115 if (scb->proto_specific_data)
5116 tcpssn = (TcpSession *)scb->proto_specific_data->data;
5117
5118 if (!tcpssn)
5119 return 0;
5120
5121 flushTracker = &tcpssn->server;
5122
5123 flushTracker->flags |= TF_FORCE_FLUSH;
5124
5125 /* If this is a rebuilt packet, don't flush now because we'll
5126 * overwrite the packet being processed.
5127 */
5128 if (p->packet_flags & PKT_REBUILT_STREAM)
5129 {
5130 /* We'll check & clear the TF_FORCE_FLUSH next time through */
5131 return 0;
5132 }
5133
5134 /* Need to convert the addresses to network order */
5135 flushed = flush_stream(tcpssn, flushTracker, p,
5136 &tcpssn->tcp_server_ip,
5137 &tcpssn->tcp_client_ip,
5138 tcpssn->tcp_server_port,
5139 tcpssn->tcp_client_port,
5140 PKT_FROM_SERVER);
5141 if (flushed)
5142 purge_flushed_ackd(tcpssn, flushTracker);
5143
5144 flushTracker->flags &= ~TF_FORCE_FLUSH;
5145
5146 return flushed;
5147 }
5148
StreamFlushClient(Packet * p,SessionControlBlock * scb)5149 int StreamFlushClient(Packet *p, SessionControlBlock *scb)
5150 {
5151 int flushed;
5152 TcpSession *tcpssn = NULL;
5153 StreamTracker *flushTracker = NULL;
5154
5155 if (scb->proto_specific_data)
5156 tcpssn = (TcpSession *)scb->proto_specific_data->data;
5157
5158 if (!tcpssn)
5159 return 0;
5160
5161 flushTracker = &tcpssn->client;
5162
5163 flushTracker->flags |= TF_FORCE_FLUSH;
5164
5165 /* If this is a rebuilt packet, don't flush now because we'll
5166 * overwrite the packet being processed.
5167 */
5168 if (p->packet_flags & PKT_REBUILT_STREAM)
5169 {
5170 /* We'll check & clear the TF_FORCE_FLUSH next time through */
5171 return 0;
5172 }
5173
5174 /* Need to convert the addresses to network order */
5175 flushed = flush_stream(tcpssn, flushTracker, p,
5176 &tcpssn->tcp_client_ip,
5177 &tcpssn->tcp_server_ip,
5178 tcpssn->tcp_client_port,
5179 tcpssn->tcp_server_port,
5180 PKT_FROM_CLIENT);
5181 if (flushed)
5182 purge_flushed_ackd(tcpssn, flushTracker);
5183
5184 flushTracker->flags &= ~TF_FORCE_FLUSH;
5185
5186 return flushed;
5187 }
5188
StreamFlushListener(Packet * p,SessionControlBlock * scb)5189 int StreamFlushListener(Packet *p, SessionControlBlock *scb)
5190 {
5191 TcpSession *tcpssn = NULL;
5192 StreamTracker *listener = NULL;
5193 int dir = 0;
5194 int flushed = 0;
5195
5196 if (scb->proto_specific_data)
5197 tcpssn = (TcpSession *)scb->proto_specific_data->data;
5198
5199 if (!tcpssn)
5200 return 0;
5201
5202 /* figure out direction of this packet -- we should've already
5203 * looked at it, so the packet_flags are already set. */
5204 if(p->packet_flags & PKT_FROM_SERVER)
5205 {
5206 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5207 "Flushing listener on packet from server\n"););
5208 listener = &tcpssn->client;
5209 /* dir of flush is the data from the opposite side */
5210 dir = PKT_FROM_SERVER;
5211 }
5212 else if (p->packet_flags & PKT_FROM_CLIENT)
5213 {
5214 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5215 "Flushing listener on packet from client\n"););
5216 listener = &tcpssn->server;
5217 /* dir of flush is the data from the opposite side */
5218 dir = PKT_FROM_CLIENT;
5219 }
5220
5221 if (dir != 0)
5222 {
5223 listener->flags |= TF_FORCE_FLUSH;
5224 flushed = flush_stream(tcpssn, listener, p,
5225 GET_SRC_IP(p), GET_DST_IP(p),
5226 p->tcph->th_sport, p->tcph->th_dport, dir);
5227 if (flushed)
5228 purge_flushed_ackd(tcpssn, listener);
5229
5230 listener->flags &= ~TF_FORCE_FLUSH;
5231 }
5232
5233 return flushed;
5234 }
5235
StreamFlushTalker(Packet * p,SessionControlBlock * scb)5236 int StreamFlushTalker(Packet *p, SessionControlBlock *scb)
5237 {
5238 TcpSession *tcpssn = NULL;
5239 StreamTracker *talker = NULL;
5240 int dir = 0;
5241 int flushed = 0;
5242
5243 if (scb->proto_specific_data)
5244 tcpssn = (TcpSession *)scb->proto_specific_data->data;
5245
5246 if (!tcpssn)
5247 {
5248 return 0;
5249 }
5250
5251 /* figure out direction of this packet -- we should've already
5252 * looked at it, so the packet_flags are already set. */
5253 if(p->packet_flags & PKT_FROM_SERVER)
5254 {
5255 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5256 "Flushing talker on packet from server\n"););
5257 talker = &tcpssn->server;
5258 /* dir of flush is the data from the opposite side */
5259 dir = PKT_FROM_CLIENT;
5260 }
5261 else if (p->packet_flags & PKT_FROM_CLIENT)
5262 {
5263 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5264 "Flushing talker on packet from client\n"););
5265 talker = &tcpssn->client;
5266 /* dir of flush is the data from the opposite side */
5267 dir = PKT_FROM_SERVER;
5268 }
5269
5270 if (dir != 0)
5271 {
5272 talker->flags |= TF_FORCE_FLUSH;
5273 flushed = flush_stream(tcpssn, talker, p,
5274 GET_DST_IP(p), GET_SRC_IP(p),
5275 p->tcph->th_dport, p->tcph->th_sport, dir);
5276 if (flushed)
5277 purge_flushed_ackd(tcpssn, talker);
5278
5279 talker->flags &= ~TF_FORCE_FLUSH;
5280 }
5281
5282 return flushed;
5283 }
5284
TcpSessionClear(SessionControlBlock * scb,TcpSession * tcpssn,int freeApplicationData)5285 static void TcpSessionClear (SessionControlBlock* scb, TcpSession* tcpssn, int freeApplicationData)
5286 {
5287 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
5288 "In TcpSessionClear, %lu bytes in use\n", session_mem_in_use););
5289 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
5290 "client has %d segs queued\n", tcpssn->client.seg_count););
5291 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
5292 "server has %d segs queued\n", tcpssn->server.seg_count););
5293
5294 // update stats
5295 s5stats.tcp_streamtrackers_released++;
5296 if (s5stats.active_tcp_sessions > 0 )
5297 s5stats.active_tcp_sessions--;
5298 StreamUpdatePerfBaseState(&sfBase, tcpssn->scb, TCP_STATE_CLOSED);
5299 RemoveStreamSession(&sfBase);
5300
5301 if (scb->ha_state.session_flags & SSNFLAG_PRUNED)
5302 CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED);
5303 else if (scb->ha_state.session_flags & SSNFLAG_TIMEDOUT)
5304 CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED | SESSION_CLOSED_TIMEDOUT);
5305 else
5306 CloseStreamSession(&sfBase, SESSION_CLOSED_NORMALLY);
5307
5308
5309 // release external state
5310 if (freeApplicationData)
5311 session_api->free_application_data(scb);
5312 StreamResetFlowBits(scb);
5313
5314 // release internal protocol specific state
5315 purge_all(&tcpssn->client);
5316 purge_all(&tcpssn->server);
5317
5318 s5_paf_clear(&tcpssn->client.paf_state);
5319 s5_paf_clear(&tcpssn->server.paf_state);
5320
5321 session_api->free_protocol_session_pool( SESSION_PROTO_TCP, scb );
5322 scb->proto_specific_data = NULL;
5323
5324 // update light-weight state
5325 scb->ha_state.session_flags = SSNFLAG_NONE;
5326 scb->session_state = STREAM_STATE_NONE;
5327 scb->expire_time = 0;
5328 scb->ha_state.ignore_direction = 0;
5329
5330 // generate event for rate filtering
5331 EventInternal(INTERNAL_EVENT_SESSION_DEL);
5332
5333 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
5334 "After cleaning, %lu bytes in use\n", session_mem_in_use););
5335 }
StreamSearchTcpConfigForBoundPolicy(StreamTcpConfig * tcp_config,sfaddr_t * ip)5336 static StreamTcpPolicy *StreamSearchTcpConfigForBoundPolicy(StreamTcpConfig *tcp_config, sfaddr_t *ip)
5337 {
5338 int policyIndex;
5339 StreamTcpPolicy *policy = NULL;
5340
5341 for (policyIndex = 0; policyIndex < tcp_config->num_policies; policyIndex++)
5342 {
5343 policy = tcp_config->policy_list[policyIndex];
5344
5345 if (policy->bound_addrs == NULL)
5346 continue;
5347
5348 /*
5349 * Does this policy handle packets to this IP address?
5350 */
5351 if(sfvar_ip_in(policy->bound_addrs, ip))
5352 {
5353 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
5354 "[Stream] Found tcp policy in IpAddrSet\n"););
5355 break;
5356 }
5357 }
5358
5359 if (policyIndex == tcp_config->num_policies)
5360 policy = tcp_config->default_policy;
5361
5362 return policy;
5363 }
5364
StreamPolicyLookup(SessionControlBlock * scb,sfaddr_t * ip)5365 static inline StreamTcpPolicy *StreamPolicyLookup( SessionControlBlock *scb, sfaddr_t *ip)
5366 {
5367 StreamTcpConfig *tcp_config = ( ( StreamConfig * ) scb->stream_config )->tcp_config;
5368
5369 if( tcp_config != NULL )
5370 return StreamSearchTcpConfigForBoundPolicy( tcp_config, ip );
5371 else
5372 return NULL;
5373 }
5374
FlushQueuedSegs(SessionControlBlock * scb,TcpSession * tcpssn)5375 static void FlushQueuedSegs(SessionControlBlock *scb, TcpSession *tcpssn)
5376 {
5377 DAQ_PktHdr_t tmp_pcap_hdr;
5378
5379 #ifdef REG_TEST
5380 if (getRegTestFlags() & REG_TEST_FLAG_STREAM_DECODE)
5381 printf("\nFlushQueuedSegs | ");
5382 #endif
5383
5384 /* Flush ack'd data on both sides as necessary */
5385 {
5386 Packet *p = NewGrinderPkt(tcp_cleanup_pkt, NULL, NULL);
5387
5388 int flushed;
5389
5390 tcp_cleanup_pkt = p;
5391
5392 if (!s5_tcp_cleanup)
5393 {
5394 /* Turn off decoder alerts since we're decoding stored
5395 * packets that we already alerted on. */
5396 policyDecoderFlagsSaveNClear(scb->napPolicyId);
5397 }
5398 policyChecksumFlagsSaveNClear(scb->napPolicyId);
5399
5400 /* Flush the client */
5401 if (tcpssn->client.seglist && !(scb->ha_state.ignore_direction & SSN_DIR_FROM_SERVER) )
5402 {
5403 pc.s5tcp1++;
5404 /* Do each field individually because of size differences on 64bit OS */
5405 memset(&tmp_pcap_hdr, 0, sizeof(tmp_pcap_hdr));
5406 tmp_pcap_hdr.ts.tv_sec = tcpssn->client.seglist->tv.tv_sec;
5407 tmp_pcap_hdr.ts.tv_usec = tcpssn->client.seglist->tv.tv_usec;
5408 tmp_pcap_hdr.caplen = tcpssn->client.seglist->caplen;
5409 tmp_pcap_hdr.pktlen = tcpssn->client.seglist->pktlen;
5410
5411 SnortEventqPush();
5412 (*grinder)(p, &tmp_pcap_hdr, tcpssn->client.seglist->pkt);
5413
5414 p->ssnptr = scb;
5415
5416 //set policy id for this packet
5417 {
5418 #ifdef HAVE_DAQ_REAL_ADDRESSES
5419 sfaddr_t* srcIp = (p->iph)? GET_SRC_IP((p)) : NULL;
5420 sfaddr_t* dstIp = (p->iph)? GET_DST_IP((p)) : NULL;
5421
5422 if (srcIp && dstIp)
5423 {
5424 if (srcIp->family == AF_INET6)
5425 {
5426 memcpy(&((((DAQ_PktHdr_t*)p->pkth)->real_sIP).s6_addr), &(srcIp)->ia32, sizeof(struct in6_addr));
5427 memcpy(&((((DAQ_PktHdr_t*)p->pkth)->real_dIP).s6_addr), &(dstIp)->ia32, sizeof(struct in6_addr));
5428 ((DAQ_PktHdr_t*)p->pkth)->flags |= (DAQ_PKT_FLAG_REAL_SIP_V6 | DAQ_PKT_FLAG_REAL_DIP_V6);
5429 }
5430 else
5431 {
5432 memcpy(&((((DAQ_PktHdr_t*)p->pkth)->real_sIP).s6_addr), &(srcIp)->ia32[3], sizeof(uint32_t));
5433 memcpy(&((((DAQ_PktHdr_t*)p->pkth)->real_dIP).s6_addr), &(dstIp)->ia32[3], sizeof(uint32_t));
5434 }
5435 ((DAQ_PktHdr_t*)p->pkth)->flags |= DAQ_PKT_FLAG_REAL_ADDRESSES;
5436
5437 if( tcpssn->daq_flags & DAQ_PKT_FLAG_IGNORE_VLAN )
5438 ((DAQ_PktHdr_t*)p->pkth)->flags |= DAQ_PKT_FLAG_IGNORE_VLAN;
5439 }
5440 #endif
5441
5442 if( scb->session_config != session_configuration )
5443 {
5444 getSessionPlugins()->select_session_nap(p, true );
5445 scb->napPolicyId = getNapRuntimePolicy();
5446 scb->ipsPolicyId = getDefaultPolicy();
5447 p->configPolicyId = snort_conf->targeted_policies[scb->ipsPolicyId]->configPolicyId;
5448 scb->stream_config = sfPolicyUserDataGet( stream_online_config, scb->napPolicyId );
5449 tcpssn->client.tcp_policy = StreamPolicyLookup(scb, GET_DST_IP(p));
5450 tcpssn->server.tcp_policy = StreamPolicyLookup(scb, GET_SRC_IP(p));
5451 }
5452 else
5453 {
5454 setNapRuntimePolicy(scb->napPolicyId);
5455 setIpsRuntimePolicy(scb->ipsPolicyId);
5456 p->configPolicyId = snort_conf->targeted_policies[scb->ipsPolicyId]->configPolicyId;
5457 scb->stream_config = sfPolicyUserDataGet( stream_online_config, scb->napPolicyId );
5458 }
5459
5460 //actions are queued only for IDS case
5461 sfActionQueueExecAll(decoderActionQ);
5462 }
5463 SnortEventqPop();
5464 tcpssn->client.flags |= TF_FORCE_FLUSH;
5465
5466 if ( !p->tcph )
5467 {
5468 flushed = 0;
5469 }
5470 else
5471 {
5472 flushed = flush_stream(tcpssn, &tcpssn->client, p,
5473 p->iph_api->iph_ret_src(p), p->iph_api->iph_ret_dst(p),
5474 p->tcph->th_sport, p->tcph->th_dport,
5475 PKT_FROM_SERVER);
5476 }
5477 if (flushed)
5478 purge_flushed_ackd(tcpssn, &tcpssn->client);
5479 else
5480 {
5481 SnortEventqPush();
5482 SnortEventqLog(snort_conf->event_queue, p);
5483 SnortEventqReset();
5484 SnortEventqPop();
5485 }
5486 tcpssn->client.flags &= ~TF_FORCE_FLUSH;
5487 }
5488
5489 /* Flush the server */
5490 if (tcpssn->server.seglist && !(scb->ha_state.ignore_direction & SSN_DIR_FROM_CLIENT) )
5491 {
5492 pc.s5tcp2++;
5493 /* Do each field individually because of size differences on 64bit OS */
5494 memset(&tmp_pcap_hdr, 0, sizeof(tmp_pcap_hdr));
5495 tmp_pcap_hdr.ts.tv_sec = tcpssn->server.seglist->tv.tv_sec;
5496 tmp_pcap_hdr.ts.tv_usec = tcpssn->server.seglist->tv.tv_usec;
5497 tmp_pcap_hdr.caplen = tcpssn->server.seglist->caplen;
5498 tmp_pcap_hdr.pktlen = tcpssn->server.seglist->pktlen;
5499
5500 SnortEventqPush();
5501 (*grinder)(p, &tmp_pcap_hdr, tcpssn->server.seglist->pkt);
5502
5503 p->ssnptr = scb;
5504
5505 //set policy id for this packet
5506 {
5507 #ifdef HAVE_DAQ_REAL_ADDRESSES
5508 sfaddr_t* srcIp = (p->iph)? GET_SRC_IP((p)) : NULL;
5509 sfaddr_t* dstIp = (p->iph)? GET_DST_IP((p)) : NULL;
5510
5511 if (srcIp && dstIp)
5512 {
5513 if (srcIp->family == AF_INET6)
5514 {
5515 memcpy(&((((DAQ_PktHdr_t*)p->pkth)->real_sIP).s6_addr), &(srcIp)->ia32, sizeof(struct in6_addr));
5516 memcpy(&((((DAQ_PktHdr_t*)p->pkth)->real_dIP).s6_addr), &(dstIp)->ia32, sizeof(struct in6_addr));
5517 ((DAQ_PktHdr_t*)p->pkth)->flags |= (DAQ_PKT_FLAG_REAL_SIP_V6 | DAQ_PKT_FLAG_REAL_DIP_V6);
5518 }
5519 else
5520 {
5521 memcpy(&((((DAQ_PktHdr_t*)p->pkth)->real_sIP).s6_addr), &(srcIp)->ia32[3], sizeof(uint32_t));
5522 memcpy(&((((DAQ_PktHdr_t*)p->pkth)->real_dIP).s6_addr), &(dstIp)->ia32[3], sizeof(uint32_t));
5523 }
5524 ((DAQ_PktHdr_t*)p->pkth)->flags |= DAQ_PKT_FLAG_REAL_ADDRESSES;
5525
5526 if( tcpssn->daq_flags & DAQ_PKT_FLAG_IGNORE_VLAN )
5527 ((DAQ_PktHdr_t*)p->pkth)->flags |= DAQ_PKT_FLAG_IGNORE_VLAN;
5528 }
5529 #endif
5530
5531 if( scb->session_config != session_configuration )
5532 {
5533 getSessionPlugins()->select_session_nap(p, false );
5534 scb->ipsPolicyId = getDefaultPolicy();
5535 scb->napPolicyId = getNapRuntimePolicy();
5536 p->configPolicyId = snort_conf->targeted_policies[scb->ipsPolicyId]->configPolicyId;
5537 scb->stream_config = sfPolicyUserDataGet( stream_online_config, scb->napPolicyId );
5538 tcpssn->client.tcp_policy = StreamPolicyLookup(scb, GET_SRC_IP(p));
5539 tcpssn->server.tcp_policy = StreamPolicyLookup(scb, GET_DST_IP(p));
5540 }
5541 else
5542 {
5543 setNapRuntimePolicy(scb->napPolicyId);
5544 setIpsRuntimePolicy(scb->ipsPolicyId);
5545 p->configPolicyId = snort_conf->targeted_policies[scb->ipsPolicyId]->configPolicyId;
5546 scb->stream_config = sfPolicyUserDataGet( stream_online_config, scb->napPolicyId );
5547 }
5548
5549 //actions are queued only for IDS case
5550 sfActionQueueExecAll(decoderActionQ);
5551 }
5552 SnortEventqPop();
5553 tcpssn->server.flags |= TF_FORCE_FLUSH;
5554
5555 if ( !p->tcph )
5556 {
5557 flushed = 0;
5558 }
5559 else
5560 {
5561 flushed = flush_stream(tcpssn, &tcpssn->server, p,
5562 p->iph_api->iph_ret_src(p), p->iph_api->iph_ret_dst(p),
5563 p->tcph->th_sport, p->tcph->th_dport,
5564 PKT_FROM_CLIENT);
5565 }
5566 if (flushed)
5567 purge_flushed_ackd(tcpssn, &tcpssn->server);
5568 else
5569 {
5570 SnortEventqPush();
5571 SnortEventqLog(snort_conf->event_queue, p);
5572 SnortEventqReset();
5573 SnortEventqPop();
5574 }
5575 tcpssn->server.flags &= ~TF_FORCE_FLUSH;
5576 }
5577
5578 if (!s5_tcp_cleanup)
5579 {
5580 /* And turn decoder alerts back on (or whatever they were set to) */
5581 policyDecoderFlagsRestore(scb->napPolicyId);
5582 }
5583 policyChecksumFlagsRestore(scb->napPolicyId);
5584
5585 }
5586
5587 }
5588
TcpSessionCleanup(SessionControlBlock * scb,int freeApplicationData)5589 static void TcpSessionCleanup(SessionControlBlock *scb, int freeApplicationData)
5590 {
5591 TcpSession *tcpssn = NULL;
5592
5593 if (scb->proto_specific_data)
5594 tcpssn = (TcpSession *)scb->proto_specific_data->data;
5595
5596 if (!tcpssn)
5597 {
5598 /* Huh? */
5599 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_CLOSED);
5600 return;
5601 }
5602
5603 stream_session_config = scb->session_config;
5604
5605 FlushQueuedSegs(scb, tcpssn);
5606
5607 TcpSessionClear(scb, tcpssn, freeApplicationData);
5608 }
5609
TcpSessionCleanupWithFreeApplicationData(void * scb)5610 static void TcpSessionCleanupWithFreeApplicationData(void *scb)
5611 {
5612 TcpSessionCleanup( ( SessionControlBlock * ) scb, 1);
5613 }
5614
5615 struct session_state_cleanup_cache
5616 {
5617 uint32_t old_mem_in_use;
5618 sfaddr_t client_ip;
5619 sfaddr_t server_ip;
5620
5621 uint16_t client_port;
5622 uint16_t server_port;
5623 uint16_t lw_session_state;
5624 uint32_t lw_session_flags;
5625 int16_t app_proto_id;
5626 };
5627
cleanup_cache_session_state(SessionControlBlock * scb,struct session_state_cleanup_cache * sscc)5628 static inline void cleanup_cache_session_state( SessionControlBlock *scb, struct session_state_cleanup_cache *sscc )
5629 {
5630 sscc->old_mem_in_use = session_mem_in_use;
5631
5632 sscc->client_port = scb->client_port;
5633 sscc->server_port = scb->server_port;
5634 sscc->lw_session_state = scb->session_state;
5635 sscc->lw_session_flags = scb->ha_state.session_flags;
5636
5637 #ifdef TARGET_BASED
5638 sscc->app_proto_id = scb->ha_state.application_protocol;
5639 #else
5640 sscc->app_proto_id = 0;
5641 #endif
5642
5643 sfip_set_ip(&sscc->client_ip, &scb->client_ip);
5644 sfip_set_ip(&sscc->server_ip, &scb->server_ip);
5645 }
5646
cleanup_log_session_state(char * delete_reason,struct session_state_cleanup_cache * sscc)5647 static inline void cleanup_log_session_state( char *delete_reason, struct session_state_cleanup_cache *sscc )
5648 {
5649 if (stream_session_config->prune_log_max &&
5650 (sscc->old_mem_in_use - session_mem_in_use) > stream_session_config->prune_log_max)
5651 {
5652 char *client_ip_str, *server_ip_str;
5653 client_ip_str = SnortStrdup(inet_ntoa(&sscc->client_ip));
5654 server_ip_str = SnortStrdup(inet_ntoa(&sscc->server_ip));
5655
5656 LogMessage("S5: Pruned session from cache that was "
5657 "using %d bytes (%s). %s %d --> %s %d (%d) : "
5658 "LWstate 0x%x LWFlags 0x%x\n",
5659 sscc->old_mem_in_use - session_mem_in_use,
5660 delete_reason,
5661 client_ip_str, sscc->client_port,
5662 server_ip_str, sscc->server_port,
5663 sscc->app_proto_id, sscc->lw_session_state, sscc->lw_session_flags);
5664
5665 free(client_ip_str);
5666 free(server_ip_str);
5667 }
5668
5669 }
5670
5671
5672 #ifdef SEG_TEST
CheckSegments(const StreamTracker * a)5673 static void CheckSegments (const StreamTracker* a)
5674 {
5675 StreamSegment* ss = a->seglist;
5676 uint32_t sx = ss ? ss->seq : 0;
5677
5678 while ( ss )
5679 {
5680 if ( SEQ_GT(sx, ss->seq) )
5681 {
5682 const int SEGBORK = 0;
5683 assert(SEGBORK);
5684 }
5685 sx = ss->seq + ss->size;
5686 ss = ss->next;
5687 }
5688 }
5689 #endif
5690
5691 #ifdef REG_TEST
5692 #define LCL(p, x) (p->x - p->isn)
5693 #define RMT(p, x, q) (p->x - (q ? q->isn : 0))
5694
5695 static int s5_trace_enabled = -1;
5696
TraceEvent(const Packet * p,TcpDataBlock * tdb,uint32_t txd,uint32_t rxd)5697 static void TraceEvent (
5698 const Packet* p, TcpDataBlock* tdb, uint32_t txd, uint32_t rxd
5699 ) {
5700 int i;
5701 char flags[7] = "UAPRSF";
5702 const TCPHdr* h = p->tcph;
5703 const char* order = "";
5704
5705 if ( !h )
5706 return;
5707
5708 for ( i = 0; i < 6; i++)
5709 if ( !((1<<(5-i)) & h->th_flags) ) flags[i] = '-';
5710
5711 // force relative ack to zero if not conveyed
5712 if ( flags[1] != 'A' ) rxd = ntohl(h->th_ack);
5713
5714 if ( p->packet_flags & PKT_STREAM_ORDER_OK )
5715 order = " (ins)";
5716
5717 else if ( p->packet_flags & PKT_STREAM_ORDER_BAD )
5718 order = " (oos)";
5719
5720 fprintf(stdout,
5721 "\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u%s\n",
5722 //"\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u End=%-4u%s\n",
5723 pc.total_from_daq, flags, h->th_flags,
5724 ntohl(h->th_seq)-txd, ntohl(h->th_ack)-rxd,
5725 ntohs(h->th_win), p->dsize, order
5726 //ntohs(h->th_win), p->dsize, tdb->end_seq-txd, order
5727 );
5728 }
5729
TraceSession(const SessionControlBlock * lws)5730 static void TraceSession (const SessionControlBlock* lws)
5731 {
5732 fprintf(stdout, " LWS: ST=0x%x SF=0x%x CP=%u SP=%u\n",
5733 (unsigned)lws->session_state, lws->ha_state.session_flags,
5734 (unsigned)ntohs(lws->client_port), (unsigned)ntohs(lws->server_port));
5735 }
5736
5737 static const char* statext[] = {
5738 "NON", "LST", "SYR", "SYS", "EST", "CLW",
5739 "LAK", "FW1", "CLG", "FW2", "TWT", "CLD"
5740 };
5741
5742 static const char* flushxt[] = {
5743 "NON", "FPR", "LOG", "RSP", "SLW",
5744 #if 0
5745 "CON",
5746 #endif
5747 "IGN", "PRO",
5748 #ifdef NORMALIZER
5749 "PRE", "PAF"
5750 #endif
5751 };
5752
TraceSegments(const StreamTracker * a)5753 static void TraceSegments (const StreamTracker* a)
5754 {
5755 StreamSegment* ss = a->seglist;
5756 uint32_t sx = a->r_win_base;
5757 unsigned segs = 0, bytes = 0;
5758
5759 while ( ss )
5760 {
5761 if ( SEQ_LT(sx, ss->seq) )
5762 fprintf(stdout, " +%u", ss->seq-sx);
5763 else if ( SEQ_GT(sx, ss->seq) )
5764 fprintf(stdout, " -%u", sx-ss->seq);
5765
5766 fprintf(stdout, " %u", ss->size);
5767
5768 segs++;
5769 bytes += ss->size;
5770
5771 sx = ss->seq + ss->size;
5772 ss = ss->next;
5773 }
5774 assert(a->seg_count == segs);
5775 assert(a->seg_bytes_logical == bytes);
5776 }
5777
TraceState(const StreamTracker * a,const StreamTracker * b,const char * s)5778 static void TraceState (const StreamTracker* a, const StreamTracker* b, const char* s)
5779 {
5780 uint32_t why = a->l_nxt_seq ? LCL(a, l_nxt_seq) : 0;
5781
5782 fprintf(stdout,
5783 " %s ST=%s:%02x UA=%-4u NS=%-4u LW=%-5u RN=%-4u RW=%-4u ",
5784 s, statext[a->s_mgr.state], a->s_mgr.sub_state,
5785 LCL(a, l_unackd), why, a->l_window,
5786 RMT(a, r_nxt_ack, b), RMT(a, r_win_base, b)
5787 );
5788 if ( a->s_mgr.state_queue )
5789 fprintf(stdout,
5790 "QS=%s QC=0x%02x QA=%-4u",
5791 statext[a->s_mgr.state_queue], a->s_mgr.expected_flags,
5792 RMT(a, s_mgr.transition_seq, b)
5793 );
5794 fprintf(stdout, "\n");
5795 fprintf(stdout,
5796 " FP=%s:%-4u SC=%-4u FL=%-4u SL=%-5u BS=%-4u",
5797 flushxt[a->flush_mgr.flush_policy], a->flush_mgr.flush_pt,
5798 a->seg_count, a->flush_count, a->seg_bytes_logical,
5799 a->seglist_base_seq - b->isn
5800 );
5801 if ( s5_trace_enabled == 2 )
5802 TraceSegments(a);
5803
5804 fprintf(stdout, "\n");
5805 }
5806
TraceTCP(const Packet * p,const SessionControlBlock * lws,TcpDataBlock * tdb,int event)5807 static void TraceTCP (
5808 const Packet* p, const SessionControlBlock* lws, TcpDataBlock* tdb, int event
5809 ) {
5810 const TcpSession* ssn = (lws && lws->proto_specific_data) ?
5811 (TcpSession*)lws->proto_specific_data->data : NULL;
5812 const StreamTracker* srv = ssn ? &ssn->server : NULL;
5813 const StreamTracker* cli = ssn ? &ssn->client : NULL;
5814
5815 const char* cdir = "?", *sdir = "?";
5816 uint32_t txd = 0, rxd = 0;
5817
5818 if ( p->packet_flags & PKT_FROM_SERVER )
5819 {
5820 sdir = "SRV>";
5821 cdir = "CLI<";
5822 if ( srv ) txd = srv->isn;
5823 if ( cli ) rxd = cli->isn;
5824 }
5825 else if ( p->packet_flags & PKT_FROM_CLIENT )
5826 {
5827 sdir = "SRV<";
5828 cdir = "CLI>";
5829 if ( cli ) txd = cli->isn;
5830 if ( srv ) rxd = srv->isn;
5831 }
5832 TraceEvent(p, tdb, txd, rxd);
5833
5834 if ( lws && lws->session_established ) TraceSession(lws);
5835
5836 if ( !event )
5837 {
5838 if ( cli ) TraceState(cli, srv, cdir);
5839 if ( srv ) TraceState(srv, cli, sdir);
5840 }
5841 }
5842
S5TraceTCP(const Packet * p,const SessionControlBlock * lws,TcpDataBlock * tdb,int event)5843 static inline void S5TraceTCP (
5844 const Packet* p, const SessionControlBlock* lws, TcpDataBlock* tdb, int event
5845 ) {
5846 if ( !s5_trace_enabled )
5847 return;
5848
5849 if ( s5_trace_enabled < 0 )
5850 {
5851 const char* s5t = getenv("S5_TRACE");
5852
5853 if ( !s5t ) {
5854 s5_trace_enabled = 0;
5855 return;
5856 }
5857 // no error checking required - atoi() is sufficient
5858 s5_trace_enabled = atoi(s5t);
5859 }
5860 TraceTCP(p, lws, tdb, event);
5861 }
5862 #endif // REG_TEST
5863
5864 /*
5865 * Main entry point for TCP
5866 */
StreamProcessTcp(Packet * p,SessionControlBlock * scb,StreamTcpPolicy * s5TcpPolicy,SessionKey * skey)5867 int StreamProcessTcp(Packet *p, SessionControlBlock *scb, StreamTcpPolicy *s5TcpPolicy, SessionKey *skey)
5868 {
5869 TcpDataBlock tdb;
5870 SFXHASH_NODE *hash_node = NULL;
5871 int rc, status;
5872 PROFILE_VARS;
5873 #if defined(DAQ_CAPA_CST_TIMEOUT)
5874 uint64_t timeout;
5875 #endif
5876
5877 STREAM_DEBUG_WRAP(
5878 char flagbuf[9];
5879 CreateTCPFlagString(p, flagbuf);
5880 DebugMessage((DEBUG_STREAM|DEBUG_STREAM_STATE),
5881 "Got TCP Packet 0x%X:%d -> 0x%X:%d %s\nseq: 0x%X ack:0x%X "
5882 "dsize: %u\n"
5883 "active sessions: %u\n",
5884 GET_SRC_IP(p),
5885 p->sp,
5886 GET_DST_IP(p),
5887 p->dp,
5888 flagbuf,
5889 ntohl(p->tcph->th_seq), ntohl(p->tcph->th_ack), p->dsize,
5890 sfxhash_count(tcp_lws_cache->hashTable));
5891 );
5892
5893 PREPROC_PROFILE_START(s5TcpPerfStats);
5894
5895 if( scb->ha_state.session_flags & ( SSNFLAG_DROP_CLIENT | SSNFLAG_DROP_SERVER ) )
5896 {
5897 /* Got a packet on a session that was dropped (by a rule). */
5898 session_api->set_packet_direction_flag(p, scb);
5899
5900 /* Drop this packet */
5901 if( ( ( p->packet_flags & PKT_FROM_SERVER) &&
5902 ( scb->ha_state.session_flags & SSNFLAG_DROP_SERVER ) )
5903 ||
5904 ( ( p->packet_flags & PKT_FROM_CLIENT ) &&
5905 ( scb->ha_state.session_flags & SSNFLAG_DROP_CLIENT ) ) )
5906 {
5907 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
5908 "Blocking %s packet as session was blocked\n",
5909 p->packet_flags & PKT_FROM_SERVER ?
5910 "server" : "client"););
5911 DisableAllDetect( p );
5912
5913 if( scb->ha_state.session_flags & SSNFLAG_FORCE_BLOCK )
5914 Active_ForceDropSessionWithoutReset();
5915 else
5916 Active_DropSessionWithoutReset(p);
5917
5918 #ifdef ACTIVE_RESPONSE
5919 StreamActiveResponse(p, scb);
5920 #endif
5921 if (pkt_trace_enabled)
5922 addPktTraceData(VERDICT_REASON_STREAM, snprintf(trace_line, MAX_TRACE_LINE,
5923 "Stream: TCP session was already blocked, %s\n", getPktTraceActMsg()));
5924 else addPktTraceData(VERDICT_REASON_STREAM, 0);
5925
5926 PREPROC_PROFILE_END(s5TcpPerfStats);
5927 return ACTION_NOTHING;
5928 }
5929 }
5930
5931 if( s5TcpPolicy == NULL )
5932 {
5933 /* Find an Tcp policy for this packet */
5934 s5TcpPolicy = StreamPolicyLookup( scb, GET_DST_IP( p ) );
5935 if( !s5TcpPolicy )
5936 {
5937 STREAM_DEBUG_WRAP( DebugMessage( DEBUG_STREAM,
5938 "[Stream] Could not find Tcp Policy context "
5939 "for IP %s\n", inet_ntoa( GET_DST_ADDR( p ) ) ); );
5940 PREPROC_PROFILE_END( s5TcpPerfStats );
5941 return 0;
5942 }
5943 #if defined(DAQ_CAPA_CST_TIMEOUT)
5944 if (Daq_Capa_Timeout)
5945 {
5946 GetTimeout(p,&timeout);
5947 s5TcpPolicy->session_timeout = timeout + STREAM_DELAY_TIMEOUT_AFTER_CONNECTION_ENDED;
5948 }
5949 #endif
5950 }
5951
5952 rc = isPacketFilterDiscard( p,
5953 ( ( ( StreamConfig * ) scb->stream_config )->tcp_config->default_policy->flags & STREAM_CONFIG_IGNORE_ANY ) );
5954 if( rc == PORT_MONITOR_PACKET_DISCARD )
5955 {
5956 //ignore the packet
5957 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
5958 "[Stream] %s:%d -> %s:%d Packet discarded due to port filtering\n",
5959 inet_ntoa(GET_SRC_ADDR(p)),p->sp,inet_ntoa(GET_DST_ADDR(p)),p->dp););
5960
5961 UpdateFilteredPacketStats(&sfBase, IPPROTO_TCP);
5962 PREPROC_PROFILE_END(s5TcpPerfStats);
5963 return 0;
5964 }
5965
5966 SetupTcpDataBlock( &tdb, p );
5967
5968 #ifdef STREAM_DEBUG_ENABLED
5969 PrintTcpDataBlock( &tdb );
5970 #endif
5971
5972 if( !scb->session_established )
5973 {
5974 if( s5TcpPolicy->flags & STREAM_CONFIG_REQUIRE_3WHS )
5975 {
5976 /* if require 3WHS, set session state to SYN rx'ed if we got one */
5977 if( TCP_ISFLAGSET( p->tcph, TH_SYN ) && !TCP_ISFLAGSET( p->tcph, TH_ACK ) )
5978 {
5979 /* SYN only */
5980 scb->session_state = STREAM_STATE_SYN;
5981 scb->session_established = true;
5982 scb->proto_policy = s5TcpPolicy;
5983 s5stats.total_tcp_sessions++;
5984 s5stats.active_tcp_sessions++;
5985 }
5986 else
5987 {
5988 /* If we're within the "startup" window, try to handle
5989 * this packet as midstream pickup -- allows for
5990 * connections that already existed before snort started.
5991 */
5992 if (p->pkth->ts.tv_sec - firstPacketTime < s5TcpPolicy->hs_timeout)
5993 {
5994 midstream_allowed = 1;
5995 goto midstream_pickup_allowed;
5996 }
5997 /*
5998 * Do nothing with this packet since we require a 3-way.
5999 * Wow that just sounds cool... Require a 3-way. Hehe.
6000 */
6001 DEBUG_WRAP(
6002 DebugMessage(DEBUG_STREAM_STATE, "Stream: Requiring 3-way "
6003 "Handshake, but failed to retrieve session object "
6004 "for non SYN packet.\n"););
6005
6006 midstream_allowed = 0;
6007 EventNo3whs(s5TcpPolicy);
6008 PREPROC_PROFILE_END(s5TcpPerfStats);
6009 #ifdef REG_TEST
6010 S5TraceTCP(p, scb, &tdb, 1);
6011 #endif
6012 return 0;
6013 }
6014 }
6015 else
6016 {
6017 midstream_pickup_allowed:
6018 if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK)))
6019 {
6020 /* If we have a SYN/ACK */
6021 scb->session_established = true;
6022 scb->proto_policy = s5TcpPolicy;
6023 s5stats.total_tcp_sessions++;
6024 s5stats.active_tcp_sessions++;
6025 }
6026 else if (p->dsize > 0)
6027 {
6028 /* If we have data -- missed the SYN/ACK
6029 * somehow -- maybe just an incomplete PCAP.
6030 * This handles data on SYN situations
6031 */
6032 scb->session_established = true;
6033 scb->proto_policy = s5TcpPolicy;
6034 s5stats.total_tcp_sessions++;
6035 s5stats.active_tcp_sessions++;
6036 }
6037 else if( ( ( ( ( StreamConfig * ) scb->stream_config )->tcp_config->session_on_syn ||
6038 ( StreamPacketHasWscale(p) & TF_WSCALE ) )
6039 && TCP_ISFLAGSET(p->tcph, TH_SYN) ) || StreamExpectIsExpected( p, &hash_node ) )
6040 {
6041 /* If we have a wscale option or this is an expected connection, need to save the
6042 * option if its the first SYN from client or continue to get the expected session
6043 * data. */
6044 scb->session_state = STREAM_STATE_SYN;
6045 scb->session_established = true;
6046 scb->proto_policy = s5TcpPolicy;
6047 s5stats.total_tcp_sessions++;
6048 s5stats.active_tcp_sessions++;
6049 }
6050 else
6051 {
6052 /* No data, no need to create session yet */
6053 /* This is done to handle SYN flood DoS attacks */
6054 #ifdef STREAM_DEBUG_ENABLED
6055 if (TCP_ISFLAGSET(p->tcph, TH_SYN))
6056 {
6057 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6058 "Stream: no data in packet (SYN only), no need to"
6059 "create lightweight session.\n"););
6060 }
6061 else
6062 {
6063 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6064 "Stream: no data in packet (non SYN/keep alive "
6065 "ACK?), no need to create lightweight session.\n"););
6066 }
6067 #endif
6068
6069 if(TCP_ISFLAGSET(p->tcph, TH_SYN))
6070 scb->session_state |= STREAM_STATE_SYN;
6071 PREPROC_PROFILE_END(s5TcpPerfStats);
6072 #ifdef REG_TEST
6073 S5TraceTCP(p, scb, &tdb, 1);
6074 #endif
6075 return 0;
6076 }
6077 }
6078 }
6079
6080 p->ssnptr = scb;
6081
6082 /*
6083 * Check if the session is expired.
6084 * Should be done before we do something with the packet...
6085 * ie, Insert a packet, or handle state change SYN, FIN, RST, etc.
6086 */
6087 if( ( scb->session_state & STREAM_STATE_TIMEDOUT) || StreamExpire( p, scb ) )
6088 {
6089 scb->ha_state.session_flags |= SSNFLAG_TIMEDOUT;
6090
6091 #ifdef ENABLE_HA
6092 /* Notify the HA peer of the session cleanup/reset by way of a deletion notification. */
6093 PREPROC_PROFILE_TMPEND(s5TcpPerfStats);
6094 SessionHANotifyDeletion(scb);
6095 PREPROC_PROFILE_TMPSTART(s5TcpPerfStats);
6096 scb->ha_flags = HA_FLAG_NEW | HA_FLAG_MODIFIED;
6097 #endif
6098
6099 /* If this one has been reset, delete the TCP portion, and start a new. */
6100 if( scb->ha_state.session_flags & SSNFLAG_RESET )
6101 {
6102 struct session_state_cleanup_cache sscc;
6103
6104 cleanup_cache_session_state( scb, &sscc );
6105 TcpSessionCleanupWithFreeApplicationData(scb);
6106 cleanup_log_session_state( "new data/reset", &sscc );
6107 status = ProcessTcp( scb, p, &tdb, s5TcpPolicy, hash_node );
6108
6109 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6110 "Finished Stream TCP cleanly!\n"
6111 "---------------------------------------------------\n"););
6112 }
6113 else
6114 {
6115 /* Not reset, simply time'd out. Clean it up */
6116 struct session_state_cleanup_cache sscc;
6117
6118 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream TCP session timedout!\n"););
6119
6120 cleanup_cache_session_state( scb, &sscc );
6121 TcpSessionCleanupWithFreeApplicationData( scb );
6122 cleanup_log_session_state( "new data/timedout", &sscc );
6123 status = ProcessTcp(scb, p, &tdb, s5TcpPolicy, hash_node);
6124 }
6125 }
6126 else
6127 {
6128 status = ProcessTcp( scb, p, &tdb, s5TcpPolicy, hash_node );
6129 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6130 "Finished Stream TCP cleanly!\n"
6131 "---------------------------------------------------\n"););
6132 }
6133
6134 if( !( status & ACTION_LWSSN_CLOSED ) )
6135 {
6136 MarkupPacketFlags( p, scb );
6137 /* Receiving valid RST for a ongoing/hanged tcp session,
6138 * override configured session timeout to non-configurable
6139 * lower timeout of 180 seconds to clean up the session.
6140 */
6141 if((status & ACTION_RST) &&
6142 (scb->expire_time - (((uint64_t)p->pkth->ts.tv_sec ) * TCP_HZ)) > (STREAM_SSN_RST_TIMEOUT * TCP_HZ))
6143 {
6144 session_api->set_expire_timer(p, scb, STREAM_SSN_RST_TIMEOUT);
6145 }
6146 else
6147 {
6148 session_api->set_expire_timer( p, scb, s5TcpPolicy->session_timeout );
6149 }
6150 }
6151 #ifdef ENABLE_HA
6152 else
6153 {
6154 /* TCP Session closed, so send an HA deletion event for the session. */
6155 SessionHANotifyDeletion( scb );
6156 }
6157 #endif
6158 if( status & ACTION_DISABLE_INSPECTION )
6159 {
6160 session_api->disable_inspection( scb, p );
6161
6162 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6163 "Stream Ignoring packet from %d. Session marked as ignore\n",
6164 p->packet_flags & PKT_FROM_SERVER? "server" : "client"););
6165 }
6166
6167 PREPROC_PROFILE_END(s5TcpPerfStats);
6168 #ifdef REG_TEST
6169 S5TraceTCP( p, scb, &tdb, 0 );
6170 #endif
6171 return 0;
6172 }
6173
StreamGetTcpTimestamp(Packet * p,uint32_t * ts,int strip)6174 static uint32_t StreamGetTcpTimestamp( Packet *p, uint32_t *ts, int strip )
6175 {
6176 unsigned int i = 0;
6177
6178 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6179 "Getting timestamp...\n"););
6180 while(i < p->tcp_option_count && i < TCP_OPTLENMAX)
6181 {
6182 if(p->tcp_options[i].code == TCPOPT_TIMESTAMP)
6183 {
6184 #ifdef NORMALIZER
6185 if ( strip && Normalize_GetMode(snort_conf, NORM_TCP_OPT) == NORM_MODE_ON )
6186 {
6187 NormalStripTimeStamp(p, i);
6188 }
6189 else
6190 if ( !strip || !NormalStripTimeStamp(p, i) )
6191 #endif
6192 {
6193 *ts = EXTRACT_32BITS(p->tcp_options[i].data);
6194 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6195 "Found timestamp %lu\n", *ts););
6196
6197 return TF_TSTAMP;
6198 }
6199 }
6200 i++;
6201 }
6202 *ts = 0;
6203
6204 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6205 "No timestamp...\n"););
6206
6207 return TF_NONE;
6208 }
6209
StreamGetMss(Packet * p,uint16_t * value)6210 static uint32_t StreamGetMss(Packet *p, uint16_t *value)
6211 {
6212 unsigned int i = 0;
6213
6214 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6215 "Getting MSS...\n"););
6216 while(i < p->tcp_option_count && i < TCP_OPTLENMAX)
6217 {
6218 if(p->tcp_options[i].code == TCPOPT_MAXSEG)
6219 {
6220 *value = EXTRACT_16BITS(p->tcp_options[i].data);
6221 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6222 "Found MSS %u\n", *value););
6223 return TF_MSS;
6224 }
6225
6226 i++;
6227 }
6228
6229 *value = 0;
6230
6231 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6232 "No MSS...\n"););
6233 return TF_NONE;
6234 }
6235
StreamGetWscale(Packet * p,uint16_t * value)6236 static uint32_t StreamGetWscale(Packet *p, uint16_t *value)
6237 {
6238 unsigned int i = 0;
6239
6240 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6241 "Getting wscale...\n"););
6242 while(i < p->tcp_option_count && i < TCP_OPTLENMAX)
6243 {
6244 if(p->tcp_options[i].code == TCPOPT_WSCALE)
6245 {
6246 *value = (uint16_t) p->tcp_options[i].data[0];
6247 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6248 "Found wscale %d\n", *value););
6249
6250 /* If scale specified in option is larger than 14,
6251 * use 14 because of limitation in the math of
6252 * shifting a 32bit value (max scaled window is 2^30th).
6253 *
6254 * See RFC 1323 for details.
6255 */
6256 if (*value > 14)
6257 {
6258 *value = 14;
6259 }
6260
6261 return TF_WSCALE;
6262 }
6263
6264 i++;
6265 }
6266
6267 *value = 0;
6268 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6269 "No wscale...\n"););
6270 return TF_NONE;
6271 }
6272
StreamPacketHasWscale(Packet * p)6273 static uint32_t StreamPacketHasWscale(Packet *p)
6274 {
6275 uint16_t wscale;
6276
6277 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6278 "Checking for wscale...\n"););
6279 return StreamGetWscale(p, &wscale);
6280 }
6281
IsWellFormed(Packet * p,StreamTracker * ts)6282 static inline int IsWellFormed(Packet *p, StreamTracker *ts)
6283 {
6284 return ( !ts->mss || (p->dsize <= ts->mss) );
6285 }
6286
FinishServerInit(Packet * p,TcpDataBlock * tdb,TcpSession * ssn)6287 static void FinishServerInit(Packet *p, TcpDataBlock *tdb, TcpSession *ssn)
6288 {
6289 StreamTracker *server;
6290 StreamTracker *client;
6291
6292 if (!ssn)
6293 {
6294 return;
6295 }
6296
6297 server = &ssn->server;
6298 client = &ssn->client;
6299
6300 server->l_window = tdb->win; /* set initial server window */
6301 server->l_unackd = tdb->end_seq;
6302 server->l_nxt_seq = server->l_unackd;
6303 server->isn = tdb->seq;
6304
6305 client->r_nxt_ack = tdb->seq + 1;
6306
6307 if ( p->tcph->th_flags & TH_FIN )
6308 server->l_nxt_seq--;
6309
6310 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6311 "seglist_base_seq = %X\n", client->seglist_base_seq););
6312
6313 if (!(ssn->scb->session_state & STREAM_STATE_MIDSTREAM))
6314 {
6315 server->s_mgr.state = TCP_STATE_SYN_RCVD;
6316 client->seglist_base_seq = server->l_unackd;
6317
6318 if ( tdb->seq == tdb->end_seq )
6319 client->r_win_base = tdb->end_seq;
6320 else
6321 client->r_win_base = tdb->seq + 1;
6322 }
6323 else
6324 {
6325 client->seglist_base_seq = tdb->seq;
6326 client->r_win_base = tdb->seq;
6327 }
6328 server->flags |= StreamGetTcpTimestamp(p, &server->ts_last, 0);
6329 if (server->ts_last == 0)
6330 server->flags |= TF_TSTAMP_ZERO;
6331 else
6332 server->ts_last_pkt = p->pkth->ts.tv_sec;
6333 server->flags |= StreamGetMss(p, &server->mss);
6334 server->flags |= StreamGetWscale(p, &server->wscale);
6335
6336 #ifdef STREAM_DEBUG_ENABLED
6337 PrintTcpSession(ssn);
6338 #endif
6339 }
6340
6341 #ifdef OLD_CODE_NOLONGER_USED_DEPENDS_ON_CURRENT_STATE
QueueState(uint8_t transition,StreamTracker * st,uint8_t expected_flags,uint32_t seq_num,uint8_t get_seq)6342 static inline void QueueState(uint8_t transition, StreamTracker *st,
6343 uint8_t expected_flags, uint32_t seq_num, uint8_t get_seq)
6344 {
6345 StateMgr *smgr = &st->s_mgr;
6346
6347 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6348 "[^^] Queing transition to %s, flag 0x%X, seq: 0x%X\n",
6349 state_names[transition], expected_flags, seq_num););
6350
6351 smgr->state_queue = transition;
6352 smgr->expected_flags = expected_flags;
6353 smgr->stq_get_seq = get_seq;
6354 smgr->transition_seq = seq_num;
6355
6356 #ifdef STREAM_DEBUG_ENABLED
6357 PrintStateMgr(smgr);
6358 #endif
6359 return;
6360 }
6361
EvalStateQueue(StreamTracker * sptr,uint8_t flags,uint32_t ack)6362 static inline int EvalStateQueue(StreamTracker *sptr, uint8_t flags,
6363 uint32_t ack)
6364 {
6365 StateMgr *smgr = &sptr->s_mgr;
6366
6367 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6368 "Evaluating state queue!\n"););
6369 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6370 "StreamTracker %p, flags 0x%X ack: 0x%X\n", sptr, flags, ack);
6371 PrintStateMgr(smgr););
6372
6373 if(smgr->expected_flags != 0)
6374 {
6375 if((flags & smgr->expected_flags) != 0)
6376 {
6377 if(smgr->stq_get_seq && (SEQ_GEQ(ack, smgr->transition_seq)))
6378 {
6379
6380 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6381 "[^^] Accepting %s state transition\n",
6382 state_names[smgr->state_queue]););
6383 smgr->state = smgr->state_queue;
6384 smgr->expected_flags = 0;
6385 smgr->transition_seq = 0;
6386 return 1;
6387 }
6388 else if(!smgr->stq_get_seq)
6389 {
6390 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6391 "[^^] Accepting %s state transition\n",
6392 state_names[smgr->state_queue]););
6393 smgr->state = smgr->state_queue;
6394 smgr->expected_flags = 0;
6395 smgr->transition_seq = 0;
6396 return 1;
6397
6398 }
6399 else
6400 {
6401 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6402 "[!!] sptr->stq_get_seq: %d "
6403 "[ack: 0x%X expected: 0x%X]\n", smgr->stq_get_seq,
6404 ack, smgr->transition_seq););
6405 }
6406 }
6407 else
6408 {
6409 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6410 "[!!] flags: 0x%X expected: 0x%X, bitwise: 0x%X\n",
6411 flags, smgr->expected_flags,
6412 (flags & smgr->expected_flags)););
6413 }
6414 }
6415 else
6416 {
6417 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6418 "No transition queued, returning\n"););
6419 }
6420
6421 return 0;
6422 }
6423 #endif
6424
IgnoreLargePkt(StreamTracker * st,Packet * p,TcpDataBlock * tdb)6425 static inline int IgnoreLargePkt(StreamTracker *st, Packet *p, TcpDataBlock *tdb)
6426 {
6427 if((st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT) &&
6428 (st->tcp_policy->flags & STREAM_CONFIG_PERFORMANCE))
6429 {
6430 if ((p->dsize > st->flush_mgr.flush_pt * 2) &&
6431 (st->seg_count == 0))
6432 {
6433 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6434 "WARNING: Data larger than twice flushpoint. Not "
6435 "inserting for reassembly: seq: %d, size %d!\n"
6436 "This is a tradeoff of performance versus the remote "
6437 "possibility of catching an exploit that spans two or "
6438 "more consecuvitve large packets.\n",
6439 tdb->seq, p->dsize););
6440 return 1;
6441 }
6442 }
6443 return 0;
6444 }
6445
NewQueue(StreamTracker * st,Packet * p,TcpDataBlock * tdb,TcpSession * tcpssn)6446 static void NewQueue(StreamTracker *st, Packet *p, TcpDataBlock *tdb, TcpSession *tcpssn)
6447 {
6448 StreamSegment *ss = NULL;
6449 uint32_t overlap = 0;
6450 PROFILE_VARS;
6451
6452 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6453 "In NewQueue\n"););
6454
6455 PREPROC_PROFILE_START(s5TcpInsertPerfStats);
6456
6457 if(st->flush_mgr.flush_policy != STREAM_FLPOLICY_IGNORE)
6458 {
6459 uint32_t seq = tdb->seq;
6460
6461 /* Check if we should not insert a large packet */
6462 if (IgnoreLargePkt(st, p, tdb))
6463 {
6464 return;
6465 }
6466
6467 if ( p->tcph->th_flags & TH_SYN )
6468 seq++;
6469
6470 /* new packet seq is below the last ack... */
6471 if ( SEQ_GT(st->r_win_base, seq) )
6472 {
6473 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6474 "segment overlaps ack'd data...\n"););
6475 overlap = st->r_win_base - tdb->seq;
6476 if (overlap >= p->dsize)
6477 {
6478 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6479 "full overlap on ack'd data, dropping segment\n"););
6480 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
6481 return;
6482 }
6483 }
6484
6485 AddStreamNode(st, p, tdb, tcpssn, p->dsize, overlap, 0, tdb->seq+overlap, NULL, &ss);
6486
6487 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6488 "Attached new queue to seglist, %d bytes queued, "
6489 "base_seq 0x%X\n",
6490 ss->size, st->seglist_base_seq););
6491 }
6492
6493 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
6494 return;
6495 }
6496
6497 #if 0
6498 static inline StreamSegment *FindSegment(StreamTracker *st, uint32_t pkt_seq)
6499 {
6500 int32_t dist_head;
6501 int32_t dist_tail;
6502 StreamSegment *ss;
6503
6504 if (!st->seglist)
6505 return NULL;
6506
6507 dist_head = pkt_seq - st->seglist->seq;
6508 dist_tail = pkt_seq - st->seglist_tail->seq;
6509
6510 if (dist_head <= dist_tail)
6511 {
6512 /* Start iterating at the head (left) */
6513 for (ss = st->seglist; ss; ss = ss->next)
6514 {
6515 if (SEQ_EQ(ss->seq, pkt_seq))
6516 return ss;
6517
6518 if (SEQ_GEQ(ss->seq, pkt_seq))
6519 break;
6520 }
6521 }
6522 else
6523 {
6524 /* Start iterating at the tail (right) */
6525 for (ss = st->seglist_tail; ss; ss = ss->prev)
6526 {
6527 if (SEQ_EQ(ss->seq, pkt_seq))
6528 return ss;
6529
6530 if (SEQ_LT(ss->seq, pkt_seq))
6531 break;
6532 }
6533 }
6534 return NULL;
6535 }
6536 #endif
6537
StreamTcpSessionClear(Packet * p)6538 void StreamTcpSessionClear(Packet *p)
6539 {
6540 SessionControlBlock *scb;
6541 TcpSession *ssn;
6542
6543 if ((!p) || (!p->ssnptr))
6544 return;
6545
6546 scb = (SessionControlBlock *)p->ssnptr;
6547
6548 if (!scb->proto_specific_data)
6549 return;
6550
6551 ssn = (TcpSession *)scb->proto_specific_data->data;
6552
6553 if (!ssn)
6554 return;
6555
6556 TcpSessionClear(scb, ssn, 1);
6557 }
6558
SegmentFastTrack(StreamSegment * tail,TcpDataBlock * tdb)6559 static inline int SegmentFastTrack(StreamSegment *tail, TcpDataBlock *tdb)
6560 {
6561 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6562 "Checking seq for fast track: %X > %X\n", tdb->seq,
6563 tail->seq + tail->size););
6564
6565 if(SEQ_EQ(tdb->seq, tail->seq + tail->size))
6566 return 1;
6567
6568 return 0;
6569 }
6570
SegmentAlloc(Packet * p,const struct timeval * tv,uint32_t caplen,uint32_t pktlen,const uint8_t * pkt)6571 static inline StreamSegment* SegmentAlloc (
6572 Packet* p, const struct timeval* tv, uint32_t caplen, uint32_t pktlen, const uint8_t* pkt)
6573 {
6574 StreamSegment* ss;
6575 unsigned size = sizeof(*ss);
6576
6577 if ( caplen > 0 )
6578 size += caplen - 1; // ss contains 1st byte
6579
6580 session_mem_in_use += size;
6581
6582 if (session_mem_in_use > stream_session_config->memcap)
6583 {
6584 pc.str_mem_faults++;
6585 sfBase.iStreamFaults++;
6586
6587 if ( !p )
6588 {
6589 session_mem_in_use -= size;
6590 return NULL;
6591 }
6592
6593 /* Smack the older time'd out sessions */
6594 if ( !session_api->prune_session_cache( tcp_lws_cache, p->pkth->ts.tv_sec,
6595 ( SessionControlBlock * ) p->ssnptr, 0 ) )
6596 {
6597 /* Try the memcap - last parameter (1) specifies check
6598 * based on memory cap. */
6599 session_api->prune_session_cache(tcp_lws_cache, 0, (SessionControlBlock*) p->ssnptr, 1);
6600 }
6601 }
6602 if (session_mem_in_use > stream_session_config->memcap)
6603 {
6604 session_mem_in_use -= size;
6605 return NULL;
6606 }
6607
6608 ss = SnortPreprocAlloc(1, size, PP_STREAM, PP_MEM_CATEGORY_SESSION);
6609
6610 ss->tv.tv_sec = tv->tv_sec;
6611 ss->tv.tv_usec = tv->tv_usec;
6612 ss->caplen = caplen;
6613 ss->pktlen = pktlen;
6614
6615 memcpy(ss->pkt, pkt, caplen);
6616
6617 return ss;
6618 }
6619
AddStreamNode(StreamTracker * st,Packet * p,TcpDataBlock * tdb,TcpSession * tcpssn,uint16_t len,uint32_t slide,uint32_t trunc,uint32_t seq,StreamSegment * left,StreamSegment ** retSeg)6620 static int AddStreamNode(StreamTracker *st, Packet *p,
6621 TcpDataBlock* tdb,
6622 TcpSession *tcpssn,
6623 uint16_t len,
6624 uint32_t slide,
6625 uint32_t trunc,
6626 uint32_t seq,
6627 StreamSegment *left,
6628 StreamSegment **retSeg)
6629 {
6630 StreamSegment *ss = NULL;
6631 uint16_t reassembly_policy;
6632 int32_t newSize = len - slide - trunc;
6633 reassembly_policy = st->reassembly_policy;
6634
6635 if(st->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT)
6636 {
6637 //If FIN is already queued, when adding a segment, take target-based approach
6638 switch(reassembly_policy)
6639 {
6640 case REASSEMBLY_POLICY_LAST:
6641 st->s_mgr.state_queue = TCP_STATE_NONE;
6642 break;
6643 case REASSEMBLY_POLICY_FIRST:
6644 default:
6645 if(SEQ_GT(seq + newSize, st->s_mgr.transition_seq - 1))
6646 {
6647 uint32_t delta = seq + newSize - (st->s_mgr.transition_seq - 1);
6648 newSize = newSize - delta;
6649 }
6650 break;
6651 }
6652 }
6653
6654 if (newSize <= 0)
6655 {
6656 /*
6657 * zero size data because of trimming. Don't
6658 * insert it
6659 */
6660 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6661 "zero size TCP data after left & right trimming "
6662 "(len: %d slide: %d trunc: %d)\n",
6663 len, slide, trunc););
6664 Discard();
6665 NormalTrimPayloadIfWin(p, 0, tdb);
6666
6667 #ifdef STREAM_DEBUG_ENABLED
6668 {
6669 StreamSegment *idx = st->seglist;
6670 unsigned long i = 0;
6671 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6672 "Dumping seglist, %d segments\n", st->seg_count););
6673 while (idx)
6674 {
6675 i++;
6676 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6677 "%d ptr: %p seq: 0x%X size: %d nxt: %p prv: %p\n",
6678 i, idx, idx->seq, idx->size, idx->next, idx->prev););
6679
6680 if(st->seg_count < i)
6681 FatalError("Circular list, WTF?\n");
6682
6683 idx = idx->next;
6684 }
6685 }
6686 #endif
6687 return STREAM_INSERT_ANOMALY;
6688 }
6689
6690 ss = SegmentAlloc(p, &p->pkth->ts, p->pkth->caplen, p->pkth->pktlen, p->pkt);
6691 if (!ss)
6692 return STREAM_INSERT_ANOMALY;
6693
6694 ss->data = ss->pkt + (p->data - p->pkt);
6695 ss->orig_dsize = p->dsize;
6696
6697 ss->payload = ss->data + slide;
6698 ss->size = (uint16_t)newSize;
6699 ss->seq = seq;
6700 ss->ts = tdb->ts;
6701
6702 /* handle the urg ptr */
6703 if(p->tcph->th_flags & TH_URG)
6704 {
6705 if(ntohs(p->tcph->th_urp) < p->dsize)
6706 {
6707 switch(st->os_policy)
6708 {
6709 case STREAM_POLICY_LINUX:
6710 case STREAM_POLICY_OLD_LINUX:
6711 /* Linux, Old linux discard data from urgent pointer */
6712 /* If urg pointer is 0, it's treated as a 1 */
6713 ss->urg_offset = ntohs(p->tcph->th_urp);
6714 if (ss->urg_offset == 0)
6715 {
6716 ss->urg_offset = 1;
6717 }
6718 break;
6719 case STREAM_POLICY_FIRST:
6720 case STREAM_POLICY_NOACK:
6721 case STREAM_POLICY_LAST:
6722 case STREAM_POLICY_BSD:
6723 case STREAM_POLICY_MACOS:
6724 case STREAM_POLICY_SOLARIS:
6725 case STREAM_POLICY_WINDOWS:
6726 case STREAM_POLICY_WINDOWS2K3:
6727 case STREAM_POLICY_VISTA:
6728 case STREAM_POLICY_HPUX11:
6729 case STREAM_POLICY_HPUX10:
6730 case STREAM_POLICY_IRIX:
6731 /* Others discard data from urgent pointer */
6732 /* If urg pointer is beyond this packet, it's treated as a 0 */
6733 ss->urg_offset = ntohs(p->tcph->th_urp);
6734 if (ss->urg_offset > p->dsize)
6735 {
6736 ss->urg_offset = 0;
6737 }
6738 break;
6739 }
6740 }
6741 }
6742
6743 StreamSeglistAddNode(st, left, ss);
6744 st->seg_bytes_logical += ss->size;
6745 st->seg_bytes_total += ss->caplen; /* Includes protocol headers and payload */
6746 st->total_segs_queued++;
6747 st->total_bytes_queued += ss->size;
6748
6749 p->packet_flags |= PKT_STREAM_INSERT;
6750
6751 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6752 "added %d bytes on segment list @ seq: 0x%X, total %lu, "
6753 "%d segments queued\n", ss->size, ss->seq,
6754 st->seg_bytes_logical, SegsToFlush(st, 0)););
6755
6756 *retSeg = ss;
6757 #ifdef SEG_TEST
6758 CheckSegments(st);
6759 #endif
6760 return STREAM_INSERT_OK;
6761 }
6762
DupStreamNode(Packet * p,StreamTracker * st,StreamSegment * left,StreamSegment ** retSeg)6763 static int DupStreamNode(Packet *p,
6764 StreamTracker *st,
6765 StreamSegment *left,
6766 StreamSegment **retSeg)
6767 {
6768 StreamSegment* ss = SegmentAlloc(p, &left->tv, left->caplen, left->pktlen, left->pkt);
6769
6770 if ( !ss )
6771 return STREAM_INSERT_FAILED;
6772
6773 ss->data = ss->pkt + (left->data - left->pkt);
6774 ss->orig_dsize = left->orig_dsize;
6775
6776 /* twiddle the values for overlaps */
6777 ss->payload = ss->data;
6778 ss->size = left->size;
6779 ss->seq = left->seq;
6780
6781 StreamSeglistAddNode(st, left, ss);
6782 st->seg_bytes_total += ss->caplen;
6783 st->total_segs_queued++;
6784 //st->total_bytes_queued += ss->size;
6785
6786 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6787 "added %d bytes on segment list @ seq: 0x%X, total %lu, "
6788 "%d segments queued\n", ss->size, ss->seq,
6789 st->seg_bytes_logical, SegsToFlush(st, 0)););
6790
6791 *retSeg = ss;
6792 return STREAM_INSERT_OK;
6793
6794 }
6795
IsRetransmit(StreamSegment * seg,const uint8_t * rdata,uint16_t rsize,uint32_t rseq,bool check_frt,bool * full_retransmit)6796 static inline bool IsRetransmit(StreamSegment *seg, const uint8_t *rdata,
6797 uint16_t rsize, uint32_t rseq, bool check_frt, bool *full_retransmit)
6798 {
6799 // If seg->orig_size == seg->size, then it's sequence number wasn't adjusted
6800 // so can just do a straight compare of the sequence numbers.
6801 // Don't want to count as a retransmit if segment's size/sequence number
6802 // has been adjusted.
6803 *full_retransmit = false;
6804 if (SEQ_EQ(seg->seq, rseq) && (seg->orig_dsize == seg->size))
6805 {
6806 if (((seg->size <= rsize) && (memcmp(seg->data, rdata, seg->size) == 0))
6807 || ((seg->size > rsize) && (memcmp(seg->data, rdata, rsize) == 0)))
6808 return true;
6809 }
6810 //Checking for a possible split of segment in which case
6811 //we compare complete data of the segment to find a retransmission
6812 else if(check_frt && SEQ_EQ(seg->seq, rseq) && seg->orig_dsize == rsize )
6813 {
6814 if(memcmp(seg->data, rdata, rsize) == 0)
6815 {
6816 *full_retransmit = true;
6817 return true;
6818 }
6819 }
6820 return false;
6821 }
6822
RetransmitProcess(Packet * p,TcpSession * tcpssn)6823 static inline void RetransmitProcess(Packet *p, TcpSession *tcpssn)
6824 {
6825 // Data has already been analyzed so don't bother looking at it again.
6826 DisableDetect( p );
6827
6828 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Allowing retransmitted data "
6829 "-- not blocked previously\n"););
6830 }
6831
RetransmitHandle(Packet * p,TcpSession * tcpssn)6832 static inline void RetransmitHandle(Packet *p, TcpSession *tcpssn)
6833 {
6834
6835 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Calling SE_REXMIT Handler\n"););
6836
6837 if ( tcpssn->scb->handler[SE_REXMIT] )
6838 StreamCallHandler(p, tcpssn->scb->handler[SE_REXMIT]);
6839 }
6840
EndOfFileHandle(Packet * p,TcpSession * tcpssn)6841 static inline void EndOfFileHandle(Packet *p, TcpSession *tcpssn)
6842 {
6843 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Calling SE_EOF Handler\n"););
6844
6845 if ( tcpssn->scb->handler[SE_EOF] )
6846 StreamCallHandler(p, tcpssn->scb->handler[SE_EOF]);
6847 }
6848
IsRetransmitOfHeldSegment(Packet * p,TcpDataBlock * tdb,StreamTracker * listener)6849 static inline bool IsRetransmitOfHeldSegment(Packet *p, TcpDataBlock *tdb,
6850 StreamTracker *listener)
6851 {
6852 StreamSegment *held_seg = listener->held_segment;
6853
6854 if (held_seg == NULL)
6855 return FALSE;
6856
6857 if (held_seg->seq == tdb->seq)
6858 return TRUE;
6859
6860 return FALSE;
6861 }
6862
IsTCPFastOpenPkt(Packet * p)6863 static bool IsTCPFastOpenPkt (Packet *p)
6864 {
6865 uint8_t opt_count = 0;
6866
6867 while (opt_count < p->tcp_option_count)
6868 {
6869 if (p->tcp_options[opt_count].code == TCPOPT_TFO)
6870 {
6871 return TRUE;
6872 }
6873 opt_count++;
6874 }
6875 return FALSE;
6876 }
6877
StreamQueue(StreamTracker * st,Packet * p,TcpDataBlock * tdb,TcpSession * tcpssn)6878 static int StreamQueue(StreamTracker *st, Packet *p, TcpDataBlock *tdb,
6879 TcpSession *tcpssn)
6880 {
6881 StreamSegment *ss = NULL;
6882 StreamSegment *left = NULL;
6883 StreamSegment *right = NULL;
6884 StreamSegment *dump_me = NULL;
6885 uint32_t seq = tdb->seq;
6886 uint32_t seq_end = tdb->end_seq;
6887 uint16_t len = p->dsize;
6888 int trunc = 0;
6889 int overlap = 0;
6890 int slide = 0;
6891 int ret = STREAM_INSERT_OK;
6892 char done = 0;
6893 char addthis = 1;
6894 int32_t dist_head;
6895 int32_t dist_tail;
6896 uint16_t reassembly_policy;
6897 #ifdef NORMALIZER
6898 NormMode ips_data;
6899 #endif
6900 // To check for retransmitted data
6901 const uint8_t *rdata = p->data;
6902 uint16_t rsize = p->dsize;
6903 uint32_t rseq = tdb->seq;
6904 PROFILE_VARS;
6905 STREAM_DEBUG_WRAP(
6906 StreamSegment *lastptr = NULL;
6907 uint32_t base_seq = st->seglist_base_seq;
6908 int last = 0;
6909 );
6910
6911 #ifdef NORMALIZER
6912 ips_data = Stream_NormGetMode(st->reassembly_policy, snort_conf, NORM_TCP_IPS);
6913 if ( ips_data == NORM_MODE_ON )
6914 reassembly_policy = REASSEMBLY_POLICY_FIRST;
6915 else
6916 #endif
6917 reassembly_policy = st->reassembly_policy;
6918
6919 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6920 "Queuing %d bytes on stream!\n"
6921 "base_seq: %X seq: %X seq_end: %X\n",
6922 seq_end - seq, base_seq, seq, seq_end););
6923
6924 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6925 "%d segments on seglist\n", SegsToFlush(st, 0)););
6926 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6927 "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"););
6928 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6929 "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"););
6930
6931 PREPROC_PROFILE_START(s5TcpInsertPerfStats);
6932
6933 /* Check if we should not insert a large packet */
6934 if (IgnoreLargePkt(st, p, tdb))
6935 {
6936 // NORM should ignore large pkt be disabled for stream normalization?
6937 // if not, how to normalize ignored large packets?
6938 return ret;
6939 }
6940
6941 // NORM fast tracks are in sequence - no norms
6942 if(st->seglist_tail && SegmentFastTrack(st->seglist_tail, tdb))
6943 {
6944 /* segment fit cleanly at the end of the segment list */
6945 left = st->seglist_tail;
6946 right = NULL;
6947
6948 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
6949 "Fast tracking segment! (tail_seq %X size %d)\n",
6950 st->seglist_tail->seq, st->seglist_tail->size););
6951
6952 ret = AddStreamNode(st, p, tdb, tcpssn, len,
6953 slide /* 0 */, trunc /* 0 */, seq, left /* tail */,
6954 &ss);
6955
6956 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
6957 return ret;
6958 }
6959
6960 if (st->seglist && st->seglist_tail)
6961 {
6962 if (SEQ_GT(tdb->seq, st->seglist->seq))
6963 {
6964 dist_head = tdb->seq - st->seglist->seq;
6965 }
6966 else
6967 {
6968 dist_head = st->seglist->seq - tdb->seq;
6969 }
6970
6971 if (SEQ_GT(tdb->seq, st->seglist_tail->seq))
6972 {
6973 dist_tail = tdb->seq - st->seglist_tail->seq;
6974 }
6975 else
6976 {
6977 dist_tail = st->seglist_tail->seq - tdb->seq;
6978 }
6979 }
6980 else
6981 {
6982 dist_head = dist_tail = 0;
6983 }
6984
6985 if (SEQ_LEQ(dist_head, dist_tail))
6986 {
6987 /* Start iterating at the head (left) */
6988 for(ss = st->seglist; ss; ss = ss->next)
6989 {
6990 STREAM_DEBUG_WRAP(
6991 DebugMessage(DEBUG_STREAM_STATE,
6992 "ss: %p seq: 0x%X size: %lu delta: %d\n",
6993 ss, ss->seq, ss->size, (ss->seq-base_seq) - last);
6994 last = ss->seq-base_seq;
6995 lastptr = ss;
6996
6997 DebugMessage(DEBUG_STREAM_STATE,
6998 " lastptr: %p ss->next: %p ss->prev: %p\n",
6999 lastptr, ss->next, ss->prev);
7000 );
7001
7002 right = ss;
7003
7004 if(SEQ_GEQ(right->seq, seq))
7005 break;
7006
7007 left = right;
7008 }
7009
7010 if(ss == NULL)
7011 right = NULL;
7012 }
7013 else
7014 {
7015 /* Start iterating at the tail (right) */
7016 for(ss = st->seglist_tail; ss; ss = ss->prev)
7017 {
7018 STREAM_DEBUG_WRAP(
7019 DebugMessage(DEBUG_STREAM_STATE,
7020 "ss: %p seq: 0x%X size: %lu delta: %d\n",
7021 ss, ss->seq, ss->size, (ss->seq-base_seq) - last);
7022 last = ss->seq-base_seq;
7023 lastptr = ss;
7024
7025 DebugMessage(DEBUG_STREAM_STATE,
7026 " lastptr: %p ss->next: %p ss->prev: %p\n",
7027 lastptr, ss->next, ss->prev);
7028 );
7029
7030 left = ss;
7031
7032 if(SEQ_LT(left->seq, seq))
7033 break;
7034
7035 right = left;
7036 }
7037
7038 if(ss == NULL)
7039 left = NULL;
7040 }
7041
7042 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7043 "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"););
7044 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7045 "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"););
7046
7047 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7048 "left: %p:0x%X right: %p:0x%X\n", left,
7049 left?left->seq:0, right, right?right->seq:0););
7050
7051 /*
7052 * handle left overlaps
7053 */
7054 if(left)
7055 {
7056 // NOTE that left->seq is always less than seq, otherwise it would
7057 // be a right based on the above determination of left and right
7058
7059 /* check if the new segment overlaps on the left side */
7060 overlap = left->seq + left->size - seq;
7061
7062 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7063 "left overlap %d\n", overlap););
7064
7065 if(overlap > 0)
7066 {
7067 // NOTE that overlap will always be less than left->size since
7068 // seq is always greater than left->seq
7069 s5stats.tcp_overlaps++;
7070 st->overlap_count++;
7071
7072 switch(reassembly_policy)
7073 {
7074 case REASSEMBLY_POLICY_FIRST:
7075 case REASSEMBLY_POLICY_NOACK:
7076 case REASSEMBLY_POLICY_LINUX:
7077 case REASSEMBLY_POLICY_BSD:
7078 case REASSEMBLY_POLICY_WINDOWS:
7079 case REASSEMBLY_POLICY_WINDOWS2K3:
7080 case REASSEMBLY_POLICY_VISTA:
7081 case REASSEMBLY_POLICY_HPUX10:
7082 case REASSEMBLY_POLICY_IRIX:
7083 case REASSEMBLY_POLICY_OLD_LINUX:
7084 case REASSEMBLY_POLICY_MACOS:
7085 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7086 "left overlap, honoring old data\n"););
7087 #ifdef NORMALIZER
7088 if ( ips_data != NORM_MODE_OFF )
7089 {
7090 if (SEQ_LT(left->seq,tdb->seq) && SEQ_GT(left->seq + left->size, tdb->seq + p->dsize))
7091 {
7092 if ( ips_data == NORM_MODE_ON )
7093 {
7094 unsigned offset = tdb->seq - left->seq;
7095 memcpy((uint8_t*)p->data, left->payload+offset, p->dsize);
7096 p->packet_flags |= PKT_MODIFIED;
7097 }
7098 normStats[PC_TCP_IPS_DATA][ips_data]++;
7099 sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA][ips_data]++;
7100 }
7101 else if (SEQ_LT(left->seq, tdb->seq))
7102 {
7103 if ( ips_data == NORM_MODE_ON )
7104 {
7105 unsigned offset = tdb->seq - left->seq;
7106 unsigned length = left->seq + left->size - tdb->seq;
7107 memcpy((uint8_t*)p->data, left->payload+offset, length);
7108 p->packet_flags |= PKT_MODIFIED;
7109 }
7110 normStats[PC_TCP_IPS_DATA][ips_data]++;
7111 sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA][ips_data]++;
7112 }
7113 }
7114 #endif
7115 seq += overlap;
7116 slide = overlap;
7117 if(SEQ_LEQ(seq_end, seq))
7118 {
7119 /*
7120 * houston, we have a problem
7121 */
7122 /* flag an anomaly */
7123 EventBadSegment(st->tcp_policy);
7124 Discard();
7125 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7126 return STREAM_INSERT_ANOMALY;
7127 }
7128 break;
7129
7130 case REASSEMBLY_POLICY_SOLARIS:
7131 case REASSEMBLY_POLICY_HPUX11:
7132 if (SEQ_LT(left->seq, seq) && SEQ_GEQ(left->seq + left->size, seq + len))
7133 {
7134 /* New packet is entirely overlapped by an
7135 * existing packet on both sides. Drop the
7136 * new data. */
7137 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7138 "left overlap, honoring old data\n"););
7139 seq += overlap;
7140 slide = overlap;
7141 if(SEQ_LEQ(seq_end, seq))
7142 {
7143 /*
7144 * houston, we have a problem
7145 */
7146 /* flag an anomaly */
7147 EventBadSegment(st->tcp_policy);
7148 Discard();
7149 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7150 return STREAM_INSERT_ANOMALY;
7151 }
7152 }
7153
7154 /* Otherwise, trim the old data accordingly */
7155 left->size -= (int16_t)overlap;
7156 st->seg_bytes_logical -= overlap;
7157 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7158 "left overlap, honoring new data\n"););
7159 break;
7160 case REASSEMBLY_POLICY_LAST:
7161 /* True "Last" policy" */
7162 if (SEQ_LT(left->seq, seq) && SEQ_GT(left->seq + left->size, seq + len))
7163 {
7164 /* New data is overlapped on both sides by
7165 * existing data. Existing data needs to be
7166 * split and the new data inserted in the
7167 * middle.
7168 *
7169 * Need to duplicate left. Adjust that
7170 * seq by + (seq + len) and
7171 * size by - (seq + len - left->seq).
7172 */
7173 ret = DupStreamNode(p, st, left, &right);
7174 if (ret != STREAM_INSERT_OK)
7175 {
7176 /* No warning,
7177 * its done in StreamSeglistAddNode */
7178 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7179 return ret;
7180 }
7181 left->size -= (int16_t)overlap;
7182 st->seg_bytes_logical -= overlap;
7183
7184 right->seq = seq + len;
7185 right->size -= (int16_t)(seq + len - left->seq);
7186 right->payload += (seq + len - left->seq);
7187 st->seg_bytes_logical -= (seq + len - left->seq);
7188 }
7189 else
7190 {
7191 left->size -= (int16_t)overlap;
7192 st->seg_bytes_logical -= overlap;
7193 }
7194
7195 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7196 "left overlap, honoring new data\n"););
7197 break;
7198 }
7199
7200 if(SEQ_LEQ(seq_end, seq))
7201 {
7202 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7203 "seq_end < seq"););
7204 /*
7205 * houston, we have a problem
7206 */
7207 /* flag an anomaly */
7208 EventBadSegment(st->tcp_policy);
7209 Discard();
7210 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7211 return STREAM_INSERT_ANOMALY;
7212 }
7213 }
7214 else
7215 {
7216 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7217 "No left overlap\n"););
7218 }
7219 }
7220
7221 //(seq_end > right->seq) && (seq_end <= (right->seq+right->size))))
7222 while(right && !done && SEQ_LT(right->seq, seq_end))
7223 {
7224 bool full_retransmit = false;
7225 trunc = 0;
7226 overlap = (int)(seq_end - right->seq);
7227 //overlap = right->size - (right->seq - seq);
7228 //right->seq + right->size - seq_end;
7229
7230 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7231 "right overlap(%d): len: %d right->seq: 0x%X seq: 0x%X\n",
7232 overlap, len, right->seq, seq););
7233 /* Treat sequence number overlap as a retransmission
7234 * Only check right side since left side happens rarely
7235 */
7236 if((st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS_FTP) && (overlap == right->size) && right->next && (right->next->size > 0))
7237 {
7238 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7239 "ftp-data daq retry or rexmit, do not call RetransmitHandle as \
7240 data beyond this packet is already received\n"););
7241 }
7242 else
7243 {
7244 RetransmitHandle(p, tcpssn);
7245 }
7246
7247 if(overlap < right->size)
7248 {
7249 if (IsRetransmit(right, rdata, rsize, rseq, false, &full_retransmit))
7250 {
7251 #ifdef DAQ_PKT_FLAG_RETRY_PACKET
7252 /* If packet is identified as re-transmitted
7253 * and it is set as retry already then block the packet */
7254 if (!(p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET))
7255 p->packet_flags |= PKT_RETRANSMIT;
7256 #endif
7257 // All data was retransmitted
7258 if (IsRetransmitOfHeldSegment(p, tdb, st))
7259 {
7260 st->held_segment = NULL;
7261 p->packet_flags |= PKT_PSEUDO_FLUSH;
7262 }
7263 else
7264 {
7265 RetransmitProcess(p, tcpssn);
7266 }
7267 addthis = 0;
7268 break;
7269 }
7270 s5stats.tcp_overlaps++;
7271 st->overlap_count++;
7272
7273 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7274 "Got partial right overlap\n"););
7275
7276 switch(reassembly_policy)
7277 {
7278 /* truncate existing data */
7279 case REASSEMBLY_POLICY_LAST:
7280 case REASSEMBLY_POLICY_LINUX:
7281 case REASSEMBLY_POLICY_OLD_LINUX:
7282 case REASSEMBLY_POLICY_BSD:
7283 case REASSEMBLY_POLICY_WINDOWS:
7284 case REASSEMBLY_POLICY_WINDOWS2K3:
7285 case REASSEMBLY_POLICY_IRIX:
7286 case REASSEMBLY_POLICY_HPUX10:
7287 case REASSEMBLY_POLICY_MACOS:
7288 if (SEQ_EQ(right->seq, seq) &&
7289 (reassembly_policy != REASSEMBLY_POLICY_LAST))
7290 {
7291 slide = (right->seq + right->size - seq);
7292 seq += slide;
7293 }
7294 else
7295 {
7296 /* partial overlap */
7297 right->seq += overlap;
7298 right->payload += overlap;
7299 right->size -= (int16_t)overlap;
7300 st->seg_bytes_logical -= overlap;
7301 st->total_bytes_queued -= overlap;
7302 }
7303
7304 // right->size always > 0 since overlap < right->size
7305
7306 break;
7307
7308 case REASSEMBLY_POLICY_FIRST:
7309 case REASSEMBLY_POLICY_VISTA:
7310 case REASSEMBLY_POLICY_SOLARIS:
7311 case REASSEMBLY_POLICY_HPUX11:
7312 #ifdef NORMALIZER
7313 if ( ips_data == NORM_MODE_ON )
7314 {
7315 unsigned offset = right->seq - tdb->seq;
7316 unsigned length = tdb->seq + p->dsize - right->seq;
7317 memcpy((uint8_t*)p->data+offset, right->payload, length);
7318 p->packet_flags |= PKT_MODIFIED;
7319 }
7320 if ( ips_data != NORM_MODE_OFF )
7321 {
7322 normStats[PC_TCP_IPS_DATA][ips_data]++;
7323 sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA][ips_data]++;
7324 }
7325 #endif
7326 trunc = overlap;
7327 break;
7328
7329 case REASSEMBLY_POLICY_NOACK:
7330 // Don't normalize
7331 trunc = overlap;
7332 break;
7333 }
7334
7335 /* all done, keep me out of the loop */
7336 done = 1;
7337 }
7338 else // Full overlap
7339 {
7340 // Don't want to count retransmits as overlaps or do anything
7341 // else with them. Account for retransmits of multiple PDUs
7342 // in one segment.
7343 if (IsRetransmit(right, rdata, rsize, rseq, (rseq == tdb->seq), &full_retransmit))
7344 {
7345 if( !full_retransmit )
7346 {
7347 rdata += right->size;
7348 rsize -= right->size;
7349 rseq += right->size;
7350
7351 seq += right->size;
7352 left = right;
7353 right = right->next;
7354 }
7355 else
7356 {
7357 rsize = 0;
7358 done = 1;
7359 }
7360
7361 if (rsize == 0)
7362 {
7363 #ifdef DAQ_PKT_FLAG_RETRY_PACKET
7364 /* If packet is identified as re-transmitted
7365 * and it is set as retry already then block the packet */
7366 if (!(p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET))
7367 p->packet_flags |= PKT_RETRANSMIT;
7368 #endif
7369 // All data was retransmitted
7370 if (IsRetransmitOfHeldSegment(p, tdb, st))
7371 {
7372 st->held_segment = NULL;
7373 p->packet_flags |= PKT_PSEUDO_FLUSH;
7374 }
7375 else
7376 {
7377 RetransmitProcess(p, tcpssn);
7378 }
7379
7380 addthis = 0;
7381 }
7382 continue;
7383 }
7384
7385 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7386 "Got full right overlap\n"););
7387
7388 s5stats.tcp_overlaps++;
7389 st->overlap_count++;
7390
7391 switch(reassembly_policy)
7392 {
7393 case REASSEMBLY_POLICY_BSD:
7394 case REASSEMBLY_POLICY_LINUX:
7395 case REASSEMBLY_POLICY_WINDOWS:
7396 case REASSEMBLY_POLICY_WINDOWS2K3:
7397 case REASSEMBLY_POLICY_HPUX10:
7398 case REASSEMBLY_POLICY_IRIX:
7399 case REASSEMBLY_POLICY_MACOS:
7400 if (SEQ_GEQ(seq_end, right->seq + right->size) &&
7401 SEQ_LT(seq, right->seq))
7402 {
7403 dump_me = right;
7404
7405 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7406 "retrans, dropping old data at seq %d, size %d\n",
7407 right->seq, right->size););
7408 right = right->next;
7409 StreamSeglistDeleteNode(st, dump_me);
7410 if (left == dump_me)
7411 left = NULL;
7412 break;
7413 }
7414 else
7415 {
7416 switch (reassembly_policy)
7417 {
7418 case REASSEMBLY_POLICY_WINDOWS:
7419 case REASSEMBLY_POLICY_WINDOWS2K3:
7420 case REASSEMBLY_POLICY_BSD:
7421 case REASSEMBLY_POLICY_MACOS:
7422 /* BSD/MacOS & Windows follow a FIRST policy in the
7423 * case below... */
7424 break;
7425 default:
7426 /* All others follow a LAST policy */
7427 if (SEQ_GT(seq_end, right->seq + right->size) &&
7428 SEQ_EQ(seq, right->seq))
7429 {
7430 /* When existing data is fully overlapped by new
7431 * and sequence numbers are the same, most OSs
7432 * follow a LAST policy.
7433 */
7434 goto right_overlap_last;
7435 }
7436 break;
7437 }
7438 }
7439 /* Fall through */
7440 case REASSEMBLY_POLICY_FIRST:
7441 case REASSEMBLY_POLICY_VISTA:
7442 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7443 "Got full right overlap, truncating new\n"););
7444 #ifdef NORMALIZER
7445 if ( ips_data == NORM_MODE_ON )
7446 {
7447 unsigned offset = right->seq - tdb->seq;
7448 memcpy((uint8_t*)p->data+offset, right->payload, right->size);
7449 p->packet_flags |= PKT_MODIFIED;
7450 }
7451 if ( ips_data != NORM_MODE_OFF )
7452 {
7453 normStats[PC_TCP_IPS_DATA][ips_data]++;
7454 sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA][ips_data]++;
7455 }
7456 #endif
7457 if (SEQ_EQ(right->seq, seq))
7458 {
7459 /* Overlap is greater than or equal to right->size
7460 * slide gets set before insertion */
7461 seq += right->size;
7462 left = right;
7463 right = right->next;
7464
7465 /* Adjusted seq is fully overlapped */
7466 if (SEQ_EQ(seq, seq_end))
7467 {
7468 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7469 "StreamQueue got full right overlap with "
7470 "resulting seq too high, bad segment "
7471 "(seq: %X seq_end: %X overlap: %lu\n",
7472 seq, seq_end, overlap););
7473 EventBadSegment(st->tcp_policy);
7474 Discard();
7475 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7476 return STREAM_INSERT_ANOMALY;
7477 }
7478
7479 /* No data to add on the left of right, so continue
7480 * since some of the other non-first targets may have
7481 * fallen into this case */
7482 continue;
7483 }
7484
7485 /* seq is less than right->seq */
7486
7487 /* trunc is reset to 0 at beginning of loop */
7488 trunc = overlap;
7489
7490 /* insert this one, and see if we need to chunk it up */
7491 /* Adjust slide so that is correct relative to orig seq */
7492 slide = seq - tdb->seq;
7493 ret = AddStreamNode(st, p, tdb, tcpssn, len, slide, trunc, seq, left, &ss);
7494 if (ret != STREAM_INSERT_OK)
7495 {
7496 /* no warning, already done above */
7497 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7498 return ret;
7499 }
7500
7501 /* Set seq to end of right since overlap was greater than
7502 * or equal to right->size and inserted seq has been
7503 * truncated to beginning of right
7504 * And reset trunc to 0 since we may fall out of loop if
7505 * next right is NULL */
7506 seq = right->seq + right->size;
7507 left = right;
7508 right = right->next;
7509 trunc = 0;
7510
7511 /* Keep looping since in IPS we may need to copy old
7512 * data into packet */
7513
7514 break;
7515
7516 case REASSEMBLY_POLICY_NOACK:
7517 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7518 "Got full right overlap, truncating new\n"););
7519 if (SEQ_EQ(right->seq, seq))
7520 {
7521 /* Overlap is greater than or equal to right->size
7522 * slide gets set before insertion */
7523 seq += right->size;
7524 left = right;
7525 right = right->next;
7526
7527 /* Adjusted seq is fully overlapped */
7528 if (SEQ_EQ(seq, seq_end))
7529 {
7530 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7531 "StreamQueue got full right overlap with "
7532 "resulting seq too high, bad segment "
7533 "(seq: %X seq_end: %X overlap: %lu\n",
7534 seq, seq_end, overlap););
7535 EventBadSegment(st->tcp_policy);
7536 s5stats.tcp_discards++;
7537 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7538 return STREAM_INSERT_ANOMALY;
7539 }
7540
7541 /* No data to add on the left of right, so continue
7542 * since some of the other non-first targets may have
7543 * fallen into this case */
7544 continue;
7545 }
7546
7547 /* seq is less than right->seq */
7548
7549 /* trunc is reset to 0 at beginning of loop */
7550 trunc = overlap;
7551
7552 /* insert this one, and see if we need to chunk it up */
7553 /* Adjust slide so that is correct relative to orig seq */
7554 slide = seq - tdb->seq;
7555 ret = AddStreamNode(st, p, tdb, tcpssn, len, slide, trunc, seq, left, &ss);
7556 if (ret != STREAM_INSERT_OK)
7557 {
7558 /* no warning, already done above */
7559 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7560 return ret;
7561 }
7562
7563 /* Set seq to end of right since overlap was greater than
7564 * or equal to right->size and inserted seq has been
7565 * truncated to beginning of right
7566 * And reset trunc to 0 since we may fall out of loop if
7567 * next right is NULL */
7568 seq = right->seq + right->size;
7569 left = right;
7570 right = right->next;
7571 trunc = 0;
7572
7573 /* Keep looping since in IPS we may need to copy old
7574 * data into packet */
7575
7576 break;
7577
7578 case REASSEMBLY_POLICY_HPUX11:
7579 case REASSEMBLY_POLICY_SOLARIS:
7580 /* If this packet is wholly overlapping and the same size
7581 * as a previous one and we have not received the one
7582 * immediately preceeding, we take the FIRST. */
7583 if (SEQ_EQ(right->seq, seq) && (right->size == len) &&
7584 (left && !SEQ_EQ(left->seq + left->size, seq)))
7585 {
7586 trunc += overlap;
7587 if(SEQ_LEQ((int)(seq_end - trunc), seq))
7588 {
7589 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7590 "StreamQueue got full right overlap with "
7591 "resulting seq too high, bad segment "
7592 "(seq: %X seq_end: %X overlap: %lu\n",
7593 seq, seq_end, overlap););
7594 EventBadSegment(st->tcp_policy);
7595 Discard();
7596 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7597 return STREAM_INSERT_ANOMALY;
7598 }
7599 break;
7600 }
7601 /* Fall through */
7602 case REASSEMBLY_POLICY_OLD_LINUX:
7603 case REASSEMBLY_POLICY_LAST:
7604 right_overlap_last:
7605 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7606 "Got full right overlap of old, dropping old\n"););
7607 dump_me = right;
7608 right = right->next;
7609 StreamSeglistDeleteNode(st, dump_me);
7610 if (left == dump_me)
7611 left = NULL;
7612 break;
7613 }
7614 }
7615 }
7616
7617 if (addthis)
7618 {
7619 /* Adjust slide so that is correct relative to orig seq */
7620 slide = seq - tdb->seq;
7621 ret = AddStreamNode(st, p, tdb, tcpssn, len,
7622 slide, trunc, seq, left, &ss);
7623 }
7624 else
7625 {
7626 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7627 "Fully truncated right overlap\n"););
7628 }
7629
7630 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7631 "StreamQueue returning normally\n"););
7632
7633 PREPROC_PROFILE_END(s5TcpInsertPerfStats);
7634 return ret;
7635 }
7636
7637
ProcessTcpStream(StreamTracker * rcv,TcpSession * tcpssn,Packet * p,TcpDataBlock * tdb,StreamTcpPolicy * s5TcpPolicy)7638 static void ProcessTcpStream(StreamTracker *rcv, TcpSession *tcpssn,
7639 Packet *p, TcpDataBlock *tdb,
7640 StreamTcpPolicy *s5TcpPolicy)
7641 {
7642
7643 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7644 "In ProcessTcpStream(), %d bytes to queue\n", p->dsize););
7645
7646 if ( p->packet_flags & PKT_IGNORE )
7647 return;
7648
7649 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
7650 SetPacketHeaderFoo(tcpssn, p);
7651 #endif
7652
7653 if ((s5TcpPolicy->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY) &&
7654 !TwoWayTraffic(tcpssn->scb))
7655 {
7656 return;
7657 }
7658
7659 if ((s5TcpPolicy->max_consec_small_segs) &&
7660 /* check ignore_ports */
7661 !(s5TcpPolicy->small_seg_ignore[p->dp/8] & (1 << (p->dp %8))))
7662 {
7663 if (p->dsize >= s5TcpPolicy->max_consec_small_seg_size)
7664 {
7665 rcv->small_seg_count = 0;
7666 }
7667 else
7668 {
7669 if (++rcv->small_seg_count == s5TcpPolicy->max_consec_small_segs)
7670 {
7671 /* Above threshold, log it... requires detect_anomalies be
7672 * on in this TCP policy, action controlled by preprocessor
7673 * rule. */
7674 EventMaxSmallSegsExceeded(s5TcpPolicy);
7675 }
7676 }
7677 }
7678
7679 if (s5TcpPolicy->max_queued_bytes &&
7680 (rcv->seg_bytes_total > s5TcpPolicy->max_queued_bytes))
7681 {
7682 if (stream_session_config->prune_log_max && (TwoWayTraffic(tcpssn->scb) || s5TcpPolicy->log_asymmetric_traffic) && !(tcpssn->scb->ha_state.session_flags & SSNFLAG_LOGGED_QUEUE_FULL))
7683 {
7684 char bufc[INET6_ADDRSTRLEN], bufs[INET6_ADDRSTRLEN];
7685 sfip_ntop(&tcpssn->scb->client_ip, bufc, sizeof(bufc));
7686 sfip_ntop(&tcpssn->scb->server_ip, bufs, sizeof(bufs));
7687
7688 LogMessage("S5: Session exceeded configured max bytes to queue %d "
7689 "using %d bytes (%s). %s %d --> %s %d "
7690 #ifdef TARGET_BASED
7691 "(%d) "
7692 #endif
7693 ": LWstate 0x%x LWFlags 0x%x\n",
7694 s5TcpPolicy->max_queued_bytes, rcv->seg_bytes_total,
7695 (rcv == &tcpssn->client) ? "client queue" : "server queue",
7696 bufc,
7697 ntohs(tcpssn->scb->client_port),
7698 bufs,
7699 ntohs(tcpssn->scb->server_port),
7700 #ifdef TARGET_BASED
7701 tcpssn->scb->ha_state.application_protocol,
7702 #endif
7703 tcpssn->scb->session_state,
7704 tcpssn->scb->ha_state.session_flags);
7705
7706 /* only log this one per session */
7707 tcpssn->scb->ha_state.session_flags |= SSNFLAG_LOGGED_QUEUE_FULL;
7708 }
7709 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7710 "Ignoring segment due to too many bytes queued\n"););
7711 return;
7712 }
7713
7714 if (s5TcpPolicy->max_queued_segs &&
7715 (rcv->seg_count+1 > s5TcpPolicy->max_queued_segs))
7716 {
7717 if (stream_session_config->prune_log_max && (TwoWayTraffic(tcpssn->scb) || s5TcpPolicy->log_asymmetric_traffic) && !(tcpssn->scb->ha_state.session_flags & SSNFLAG_LOGGED_QUEUE_FULL))
7718 {
7719 char bufc[INET6_ADDRSTRLEN], bufs[INET6_ADDRSTRLEN];
7720 sfip_ntop(&tcpssn->scb->client_ip, bufc, sizeof(bufc));
7721 sfip_ntop(&tcpssn->scb->server_ip, bufs, sizeof(bufs));
7722
7723 LogMessage("S5: Session exceeded configured max segs to queue %d "
7724 "using %d segs (%s). %s %d --> %s %d "
7725 #ifdef TARGET_BASED
7726 "(%d) "
7727 #endif
7728 ": LWstate 0x%x LWFlags 0x%x\n",
7729 s5TcpPolicy->max_queued_segs, rcv->seg_count,
7730 (rcv == &tcpssn->client) ? "client queue" : "server queue",
7731 bufc,
7732 ntohs(tcpssn->scb->client_port),
7733 bufs,
7734 ntohs(tcpssn->scb->server_port),
7735 #ifdef TARGET_BASED
7736 tcpssn->scb->ha_state.application_protocol,
7737 #endif
7738 tcpssn->scb->session_state, tcpssn->scb->ha_state.session_flags);
7739
7740 /* only log this one per session */
7741 tcpssn->scb->ha_state.session_flags |= SSNFLAG_LOGGED_QUEUE_FULL;
7742 }
7743 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7744 "Ignoring segment due to too many bytes queued\n"););
7745 return;
7746 }
7747
7748 if(rcv->seg_count != 0)
7749 {
7750 if(rcv->flush_mgr.flush_policy == STREAM_FLPOLICY_IGNORE)
7751 {
7752 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7753 "Ignoring segment due to IGNORE flush_policy\n"););
7754 return;
7755 }
7756 else
7757 {
7758 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7759 "queuing segment\n"););
7760
7761 if ( SEQ_GT(rcv->r_win_base, tdb->seq) )
7762 {
7763 uint32_t offset = rcv->r_win_base - tdb->seq;
7764
7765 if ( offset < p->dsize )
7766 {
7767 tdb->seq += offset;
7768 p->data += offset;
7769 p->dsize -= (uint16_t)offset;
7770
7771 StreamQueue(rcv, p, tdb, tcpssn);
7772
7773 p->dsize += (uint16_t)offset;
7774 p->data -= offset;
7775 tdb->seq -= offset;
7776 }
7777 }
7778 else
7779 StreamQueue(rcv, p, tdb, tcpssn);
7780
7781 if ((rcv->tcp_policy->overlap_limit) &&
7782 (rcv->overlap_count > rcv->tcp_policy->overlap_limit))
7783 {
7784 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7785 "Reached the overlap limit. Flush the data "
7786 "and kill the session if configured\n"););
7787 if (p->packet_flags & PKT_FROM_CLIENT)
7788 {
7789 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7790 "Flushing data on packet from the client\n"););
7791 flush_stream(tcpssn, rcv, p,
7792 GET_SRC_IP(p), GET_DST_IP(p),
7793 p->tcph->th_sport, p->tcph->th_dport,
7794 PKT_FROM_CLIENT);
7795
7796 flush_stream(tcpssn, &tcpssn->server, p,
7797 GET_DST_IP(p), GET_SRC_IP(p),
7798 p->tcph->th_dport, p->tcph->th_sport,
7799 PKT_FROM_SERVER);
7800 }
7801 else
7802 {
7803 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7804 "Flushing data on packet from the server\n"););
7805 flush_stream(tcpssn, rcv, p,
7806 GET_SRC_IP(p), GET_DST_IP(p),
7807 p->tcph->th_sport, p->tcph->th_dport,
7808 PKT_FROM_SERVER);
7809
7810 flush_stream(tcpssn, &tcpssn->client, p,
7811 GET_DST_IP(p), GET_SRC_IP(p),
7812 p->tcph->th_dport, p->tcph->th_sport,
7813 PKT_FROM_CLIENT);
7814 }
7815 purge_all(&tcpssn->client);
7816 purge_all(&tcpssn->server);
7817
7818 /* Alert on overlap limit and reset counter */
7819 EventExcessiveOverlap(rcv->tcp_policy);
7820 rcv->overlap_count = 0;
7821 }
7822 }
7823 }
7824 else
7825 {
7826 if(rcv->flush_mgr.flush_policy == STREAM_FLPOLICY_IGNORE)
7827 {
7828 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7829 "Ignoring segment due to IGNORE flush_policy\n"););
7830 return;
7831 }
7832 else
7833 {
7834 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7835 "queuing segment\n"););
7836 NewQueue(rcv, p, tdb, tcpssn);
7837 }
7838 }
7839
7840 return;
7841 }
7842
ProcessTcpData(Packet * p,StreamTracker * listener,TcpSession * tcpssn,TcpDataBlock * tdb,StreamTcpPolicy * s5TcpPolicy)7843 static int ProcessTcpData(Packet *p, StreamTracker *listener, TcpSession *tcpssn,
7844 TcpDataBlock *tdb, StreamTcpPolicy *s5TcpPolicy)
7845 {
7846 PROFILE_VARS;
7847
7848 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7849 "In ProcessTcpData()\n"););
7850
7851 PREPROC_PROFILE_START(s5TcpDataPerfStats);
7852 if (!IsTCPFastOpenPkt(p) && (p->tcph->th_flags & TH_SYN) && (listener->os_policy != STREAM_POLICY_MACOS))
7853 {
7854 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7855 "Bailing, data on SYN, not MAC Policy!\n"););
7856 NormalTrimPayloadIfSyn(p, 0, tdb);
7857 PREPROC_PROFILE_END(s5TcpDataPerfStats);
7858 return STREAM_UNALIGNED;
7859 }
7860
7861 /* we're aligned, so that's nice anyway */
7862 if((tdb->seq == listener->r_nxt_ack) || (p->tcph->th_flags & TH_SYN))
7863 {
7864 if ( p->tcph->th_flags & TH_SYN )
7865 ++tdb->seq;
7866
7867 /* check if we're in the window */
7868 if( s5TcpPolicy->policy != STREAM_POLICY_NOACK )
7869 {
7870 if(StreamGetWindow(tcpssn->scb, listener, tdb) == 0)
7871 {
7872 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7873 "Bailing, we're out of the window!\n"););
7874 NormalTrimPayloadIfWin(p, 0, tdb);
7875 PREPROC_PROFILE_END(s5TcpDataPerfStats);
7876 return STREAM_UNALIGNED;
7877 }
7878 }
7879
7880 /* move the ack boundry up, this is the only way we'll accept data */
7881 // update r_nxt_ack for IGNORE Flush policy here. Else update in StreamSeglistAddNode
7882 if((listener->s_mgr.state_queue == TCP_STATE_NONE) &&
7883 (listener->flush_mgr.flush_policy == STREAM_FLPOLICY_IGNORE))
7884 listener->r_nxt_ack = tdb->end_seq;
7885
7886 //For IPS mode trim packet if it overwrites OOO FIN in state_queue
7887 if((listener->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT) &&
7888 (Stream_NormGetMode(listener->reassembly_policy, snort_conf, NORM_TCP_IPS) == NORM_MODE_ON))
7889 {
7890 if(SEQ_GT(tdb->end_seq, listener->s_mgr.transition_seq - 1))
7891 {
7892 uint32_t delta = tdb->end_seq - (listener->s_mgr.transition_seq - 1);
7893 if (p->dsize > delta)
7894 NormalTrimPayload(p, delta, tdb);
7895 }
7896 }
7897
7898 if(p->dsize != 0)
7899 {
7900 if (listener->flags & TF_MISSING_PKT)
7901 tcpssn->scb->ha_state.session_flags |= SSNFLAG_STREAM_ORDER_BAD;
7902
7903 if (tcpssn->scb->ha_state.session_flags & SSNFLAG_STREAM_ORDER_BAD)
7904 p->packet_flags |= PKT_STREAM_ORDER_BAD;
7905 else
7906 p->packet_flags |= PKT_STREAM_ORDER_OK;
7907
7908 ProcessTcpStream(listener, tcpssn, p, tdb, s5TcpPolicy);
7909
7910 if (SEQ_GT(listener->r_nxt_ack,tdb->end_seq))
7911 {
7912 tcpssn->scb->ha_state.session_flags |= SSNFLAG_STREAM_ORDER_BAD;
7913 }
7914
7915 PREPROC_PROFILE_END(s5TcpDataPerfStats);
7916 return STREAM_ALIGNED;
7917 }
7918 }
7919 else
7920 {
7921 /* pkt is out of order, do some target-based shizzle here */
7922
7923 /* NO, we don't want to simply bail. Some platforms
7924 * favor unack'd dup data over the original data.
7925 * Let the reassembly policy decide how to handle
7926 * the overlapping data.
7927 *
7928 * See HP, Solaris, et al. for those that favor
7929 * duplicate data over the original in some cases.
7930 */
7931 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7932 "out of order segment (tdb->seq: 0x%X "
7933 "l->r_nxt_ack: 0x%X!\n", tdb->seq, listener->r_nxt_ack););
7934
7935 if (listener->s_mgr.state_queue == TCP_STATE_NONE)
7936 {
7937 /* check if we're in the window */
7938 if( s5TcpPolicy->policy != STREAM_POLICY_NOACK )
7939 {
7940 if(StreamGetWindow(tcpssn->scb, listener, tdb) == 0)
7941 {
7942 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
7943 "Bailing, we're out of the window!\n"););
7944 NormalTrimPayloadIfWin(p, 0, tdb);
7945 PREPROC_PROFILE_END(s5TcpDataPerfStats);
7946 return STREAM_UNALIGNED;
7947 }
7948 }
7949
7950 if ((listener->s_mgr.state == TCP_STATE_ESTABLISHED) &&
7951 (listener->flush_mgr.flush_policy == STREAM_FLPOLICY_IGNORE))
7952 {
7953 if ( SEQ_GT(tdb->end_seq, listener->r_nxt_ack))
7954 {
7955 /* set next ack so we are within the window going forward on
7956 * this side. */
7957 // FIXTHIS for ips, must move all the way to first hole or right end
7958 listener->r_nxt_ack = tdb->end_seq;
7959 }
7960 }
7961 }
7962 //For IPS mode trim packet if it overwrites OOO FIN in state_queue
7963 else if((listener->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT) &&
7964 (Stream_NormGetMode(listener->reassembly_policy, snort_conf, NORM_TCP_IPS) == NORM_MODE_ON))
7965 {
7966 if(SEQ_GT(tdb->end_seq, listener->s_mgr.transition_seq - 1))
7967 {
7968 uint32_t delta = tdb->end_seq - (listener->s_mgr.transition_seq - 1);
7969 if (p->dsize > delta)
7970 NormalTrimPayload(p, delta, tdb);
7971 }
7972
7973 }
7974
7975 if(p->dsize != 0)
7976 {
7977 uint32_t r_nxt_ack_old = listener->r_nxt_ack;
7978 if (SEQ_GT(listener->r_win_base, listener->r_nxt_ack) ||
7979 (listener->flags & TF_MISSING_PKT))
7980 tcpssn->scb->ha_state.session_flags |= SSNFLAG_STREAM_ORDER_BAD;
7981
7982 if (tcpssn->scb->ha_state.session_flags & SSNFLAG_STREAM_ORDER_BAD)
7983 p->packet_flags |= PKT_STREAM_ORDER_BAD;
7984
7985 ProcessTcpStream(listener, tcpssn, p, tdb, s5TcpPolicy);
7986
7987 /* If we have moved the expected seq, overlapped segment, set BAD flag*/
7988 if (SEQ_GT(listener->r_nxt_ack, r_nxt_ack_old))
7989 {
7990 tcpssn->scb->ha_state.session_flags |= SSNFLAG_STREAM_ORDER_BAD;
7991 p->packet_flags |= PKT_STREAM_ORDER_BAD;
7992 }
7993 }
7994 }
7995
7996 PREPROC_PROFILE_END(s5TcpDataPerfStats);
7997 return STREAM_UNALIGNED;
7998 }
7999
StreamGetPolicy(SessionControlBlock * scb,StreamTcpPolicy * s5TcpPolicy,int direction)8000 uint16_t StreamGetPolicy(SessionControlBlock *scb, StreamTcpPolicy *s5TcpPolicy, int direction)
8001 {
8002 #ifdef TARGET_BASED
8003 uint16_t policy_id;
8004 /* Not caching this host_entry in the frag tracker so we can
8005 * swap the table out after processing this packet if we need
8006 * to. */
8007 HostAttributeEntry *host_entry = NULL;
8008 int ssn_dir;
8009
8010 if (!IsAdaptiveConfigured())
8011 return s5TcpPolicy->policy;
8012
8013 if (direction == FROM_CLIENT)
8014 {
8015 host_entry = SFAT_LookupHostEntryByIP(&scb->server_ip);
8016 ssn_dir = SSN_DIR_FROM_SERVER;
8017 }
8018 else
8019 {
8020 host_entry = SFAT_LookupHostEntryByIP(&scb->client_ip);
8021 ssn_dir = SSN_DIR_FROM_CLIENT;
8022 }
8023 if (host_entry && (isStreamPolicySet(host_entry) == POLICY_SET))
8024 {
8025 policy_id = getStreamPolicy(host_entry);
8026
8027 if (policy_id != SFAT_UNKNOWN_STREAM_POLICY)
8028 {
8029 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8030 "StreamGetPolicy: Policy Map Entry: %d(%s)\n",
8031 policy_id, reassembly_policy_names[policy_id]););
8032
8033 /* Since we've already done the lookup, try to get the
8034 * application protocol id with that host_entry. */
8035 setAppProtocolIdFromHostEntry(scb, host_entry, ssn_dir);
8036 return policy_id;
8037 }
8038 }
8039 #endif
8040
8041 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8042 "StreamGetPolicy: Using configured default %d(%s)\n",
8043 s5TcpPolicy->policy, reassembly_policy_names[s5TcpPolicy->policy]););
8044
8045 return s5TcpPolicy->policy;
8046 }
8047
SetTcpReassemblyPolicy(StreamTracker * st)8048 void SetTcpReassemblyPolicy(StreamTracker *st)
8049 {
8050 st->reassembly_policy = GetTcpReassemblyPolicy(st->os_policy);
8051 }
8052
SetOSPolicy(TcpSession * tcpssn)8053 static void SetOSPolicy(TcpSession *tcpssn)
8054 {
8055 if (tcpssn->client.os_policy == 0)
8056 {
8057 tcpssn->client.os_policy = StreamGetPolicy(tcpssn->scb, tcpssn->client.tcp_policy, FROM_SERVER);
8058 SetTcpReassemblyPolicy(&tcpssn->client);
8059 }
8060
8061 if (tcpssn->server.os_policy == 0)
8062 {
8063 tcpssn->server.os_policy = StreamGetPolicy(tcpssn->scb, tcpssn->server.tcp_policy, FROM_CLIENT);
8064 SetTcpReassemblyPolicy(&tcpssn->server);
8065 }
8066 }
8067
ValidMacAddress(StreamTracker * talker,StreamTracker * listener,Packet * p)8068 static inline int ValidMacAddress(StreamTracker *talker,
8069 StreamTracker *listener,
8070 Packet *p)
8071 {
8072 int i;
8073 int ret = 0;
8074
8075 if (p->eh == NULL)
8076 return 0;
8077
8078 /* Use a for loop and byte comparison, which has proven to be
8079 * faster on pipelined architectures compared to a memcmp (setup
8080 * for memcmp is slow). Not using a 4 byte and 2 byte long because
8081 * there is no guaranttee of memory alignment (and thus performance
8082 * issues similar to memcmp). */
8083 for (i=0;i<6;i++)
8084 {
8085 if ((talker->mac_addr[i] != p->eh->ether_src[i]))
8086 {
8087 if (p->packet_flags & PKT_FROM_CLIENT)
8088 ret |= EVENT_SESSION_HIJACK_CLIENT;
8089 else
8090 ret |= EVENT_SESSION_HIJACK_SERVER;
8091 }
8092
8093 if (listener->mac_addr[i] != p->eh->ether_dst[i])
8094 {
8095 if (p->packet_flags & PKT_FROM_CLIENT)
8096 ret |= EVENT_SESSION_HIJACK_SERVER;
8097 else
8098 ret |= EVENT_SESSION_HIJACK_CLIENT;
8099 }
8100 }
8101 return ret;
8102 }
8103
CopyMacAddr(Packet * p,TcpSession * tcpssn,int dir)8104 static inline void CopyMacAddr(Packet *p,
8105 TcpSession *tcpssn,
8106 int dir)
8107 {
8108 int i;
8109
8110 /* Not ethernet based, nothing to do */
8111 if (p->eh == NULL)
8112 return;
8113
8114 if (dir == FROM_CLIENT)
8115 {
8116 /* Client is SRC */
8117 for (i=0;i<6;i++)
8118 {
8119 tcpssn->client.mac_addr[i] = p->eh->ether_src[i];
8120 tcpssn->server.mac_addr[i] = p->eh->ether_dst[i];
8121 }
8122 }
8123 else
8124 {
8125 /* Server is SRC */
8126 for (i=0;i<6;i++)
8127 {
8128 tcpssn->server.mac_addr[i] = p->eh->ether_src[i];
8129 tcpssn->client.mac_addr[i] = p->eh->ether_dst[i];
8130 }
8131 }
8132 }
8133
NewTcpSession(Packet * p,SessionControlBlock * scb,TcpDataBlock * tdb,StreamTcpPolicy * dstPolicy)8134 static int NewTcpSession(Packet *p, SessionControlBlock *scb, TcpDataBlock *tdb,
8135 StreamTcpPolicy *dstPolicy)
8136 {
8137 MemBucket *tmpBucket = NULL;
8138 TcpSession *tmp = NULL;
8139 uint16_t server_port = 0;
8140 PROFILE_VARS;
8141
8142 PREPROC_PROFILE_START(s5TcpNewSessPerfStats);
8143
8144 if (TCP_ISFLAGSET(p->tcph, TH_SYN) &&
8145 !TCP_ISFLAGSET(p->tcph, TH_ACK))
8146 {
8147 /******************************************************************
8148 * start new sessions on proper SYN packets
8149 *****************************************************************/
8150 tmpBucket = session_api->alloc_protocol_session( SESSION_PROTO_TCP );
8151 if(!tmpBucket)
8152 {
8153 PREPROC_PROFILE_END(s5TcpNewSessPerfStats);
8154 return -1;
8155 }
8156 tmp = tmpBucket->data;
8157 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8158 "Creating new session tracker on SYN!\n"););
8159
8160 #ifdef DEBUG
8161 tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec;
8162 tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec;
8163 #endif
8164 scb->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT;
8165
8166 if((p->tcph->th_flags & (TH_CWR|TH_ECE)) == (TH_CWR|TH_ECE))
8167 {
8168 scb->ha_state.session_flags |= SSNFLAG_ECN_CLIENT_QUERY;
8169 }
8170
8171 /* setup the stream trackers */
8172 tmp->client.s_mgr.state = TCP_STATE_SYN_SENT;
8173 tmp->client.isn = tdb->seq;
8174 tmp->client.l_unackd = tdb->seq + 1;
8175 tmp->client.l_nxt_seq = tmp->client.l_unackd;
8176
8177 if ( tdb->seq != tdb->end_seq )
8178 tmp->client.l_nxt_seq += (tdb->end_seq - tdb->seq - 1);
8179
8180 tmp->client.l_window = tdb->win;
8181 tmp->client.ts_last_pkt = p->pkth->ts.tv_sec;
8182
8183 tmp->server.seglist_base_seq = tmp->client.l_unackd;
8184 tmp->server.r_nxt_ack = tmp->client.l_unackd;
8185 tmp->server.r_win_base = tdb->seq+1;
8186
8187 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8188 "seglist_base_seq = %X\n", tmp->server.seglist_base_seq););
8189 tmp->server.s_mgr.state = TCP_STATE_LISTEN;
8190
8191 tmp->client.flags |= StreamGetTcpTimestamp(p, &tmp->client.ts_last, 0);
8192 if (tmp->client.ts_last == 0)
8193 tmp->client.flags |= TF_TSTAMP_ZERO;
8194 tmp->client.flags |= StreamGetMss(p, &tmp->client.mss);
8195 tmp->client.flags |= StreamGetWscale(p, &tmp->client.wscale);
8196
8197
8198 /* Set the StreamTcpPolicy for each direction (pkt from client) */
8199 tmp->client.tcp_policy = StreamPolicyLookup(scb, GET_SRC_IP(p));
8200 tmp->server.tcp_policy = dstPolicy;
8201
8202 /* Server is destination */
8203 server_port = p->dp;
8204
8205 CopyMacAddr(p, tmp, FROM_CLIENT);
8206 }
8207 else if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK)))
8208 {
8209 /******************************************************************
8210 * start new sessions on SYN/ACK from server
8211 *****************************************************************/
8212 tmpBucket = session_api->alloc_protocol_session( SESSION_PROTO_TCP );
8213 if(!tmpBucket)
8214 {
8215 PREPROC_PROFILE_END(s5TcpNewSessPerfStats);
8216 return -1;
8217 }
8218 tmp = tmpBucket->data;
8219 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8220 "Creating new session tracker on SYN_ACK!\n"););
8221
8222 #ifdef DEBUG
8223 tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec;
8224 tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec;
8225 #endif
8226 scb->ha_state.session_flags |= SSNFLAG_SEEN_SERVER;
8227
8228 if((p->tcph->th_flags & (TH_CWR|TH_ECE)) == (TH_CWR|TH_ECE))
8229 {
8230 scb->ha_state.session_flags |= SSNFLAG_ECN_SERVER_REPLY;
8231 }
8232
8233 /* setup the stream trackers */
8234 tmp->server.s_mgr.state = TCP_STATE_SYN_RCVD;
8235 tmp->server.isn = tdb->seq;
8236 tmp->server.l_unackd = tdb->seq + 1;
8237 tmp->server.l_nxt_seq = tmp->server.l_unackd;
8238 tmp->server.l_window = tdb->win;
8239
8240 tmp->server.seglist_base_seq = tdb->ack;
8241 tmp->server.r_win_base = tdb->ack;
8242 tmp->server.r_nxt_ack = tdb->ack;
8243 tmp->server.ts_last_pkt = p->pkth->ts.tv_sec;
8244
8245 tmp->client.seglist_base_seq = tmp->server.l_unackd;
8246 tmp->client.r_nxt_ack = tmp->server.l_unackd;
8247 tmp->client.r_win_base = tdb->seq+1;
8248 tmp->client.l_nxt_seq = tdb->ack;
8249 tmp->client.isn = tdb->ack-1;
8250
8251 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8252 "seglist_base_seq = %X\n", tmp->client.seglist_base_seq););
8253 tmp->client.s_mgr.state = TCP_STATE_SYN_SENT;
8254
8255 tmp->server.flags |= StreamGetTcpTimestamp(p, &tmp->server.ts_last, 0);
8256 if (tmp->server.ts_last == 0)
8257 tmp->server.flags |= TF_TSTAMP_ZERO;
8258 tmp->server.flags |= StreamGetMss(p, &tmp->server.mss);
8259 tmp->server.flags |= StreamGetWscale(p, &tmp->server.wscale);
8260
8261 /* Set the StreamTcpPolicy for each direction (pkt from server) */
8262 tmp->server.tcp_policy = StreamPolicyLookup(scb, GET_SRC_IP(p));
8263 tmp->client.tcp_policy = dstPolicy;
8264 scb->proto_policy = tmp->server.tcp_policy;
8265
8266 /* Client is destination */
8267 server_port = p->sp;
8268
8269 CopyMacAddr(p, tmp, FROM_SERVER);
8270 }
8271 else if ((p->tcph->th_flags & TH_ACK) &&
8272 !(p->tcph->th_flags & TH_RST) &&
8273 (scb->session_state & STREAM_STATE_ESTABLISHED))
8274 {
8275 /******************************************************************
8276 * start new sessions on completion of 3-way (ACK only, no data)
8277 *****************************************************************/
8278 tmpBucket = session_api->alloc_protocol_session( SESSION_PROTO_TCP );
8279 if(!tmpBucket)
8280 {
8281 PREPROC_PROFILE_END(s5TcpNewSessPerfStats);
8282 return -1;
8283 }
8284 tmp = tmpBucket->data;
8285 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8286 "Creating new session tracker on ACK!\n"););
8287
8288 #ifdef DEBUG
8289 tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec;
8290 tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec;
8291 #endif
8292 scb->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT;
8293
8294 if((p->tcph->th_flags & (TH_CWR|TH_ECE)) == (TH_CWR|TH_ECE))
8295 {
8296 scb->ha_state.session_flags |= SSNFLAG_ECN_CLIENT_QUERY;
8297 }
8298
8299 /* setup the stream trackers */
8300 tmp->client.s_mgr.state = TCP_STATE_ESTABLISHED;
8301 tmp->client.isn = tdb->seq;
8302 tmp->client.l_unackd = tdb->seq + 1;
8303 tmp->client.l_nxt_seq = tmp->client.l_unackd;
8304 tmp->client.l_window = tdb->win;
8305
8306 tmp->client.ts_last_pkt = p->pkth->ts.tv_sec;
8307
8308 tmp->server.seglist_base_seq = tmp->client.l_unackd;
8309 tmp->server.r_nxt_ack = tmp->client.l_unackd;
8310 tmp->server.r_win_base = tdb->seq+1;
8311
8312 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8313 "seglist_base_seq = %X\n", tmp->server.seglist_base_seq););
8314 tmp->server.s_mgr.state = TCP_STATE_ESTABLISHED;
8315
8316 tmp->client.flags |= StreamGetTcpTimestamp(p, &tmp->client.ts_last, 0);
8317 if (tmp->client.ts_last == 0)
8318 tmp->client.flags |= TF_TSTAMP_ZERO;
8319 tmp->client.flags |= StreamGetMss(p, &tmp->client.mss);
8320 tmp->client.flags |= StreamGetWscale(p, &tmp->client.wscale);
8321
8322 /* Set the StreamTcpPolicy for each direction (pkt from client) */
8323 tmp->client.tcp_policy = StreamPolicyLookup(scb, GET_SRC_IP(p));
8324 tmp->server.tcp_policy = dstPolicy;
8325
8326 /* Server is destination */
8327 server_port = p->dp;
8328
8329 CopyMacAddr(p, tmp, FROM_CLIENT);
8330 }
8331 else if (p->dsize != 0)
8332 {
8333 /******************************************************************
8334 * start new sessions on data in packet
8335 *****************************************************************/
8336 tmpBucket = session_api->alloc_protocol_session( SESSION_PROTO_TCP );
8337 if(!tmpBucket)
8338 {
8339 PREPROC_PROFILE_END(s5TcpNewSessPerfStats);
8340 return -1;
8341 }
8342 tmp = tmpBucket->data;
8343 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8344 "Creating new session tracker on data packet (ACK|PSH)!\n"););
8345
8346 #ifdef DEBUG
8347 tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec;
8348 tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec;
8349 #endif
8350
8351 if (scb->ha_state.direction == FROM_CLIENT)
8352 {
8353 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8354 "Session direction is FROM_CLIENT\n"););
8355
8356 /* Sender is client (src port is higher) */
8357 scb->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT;
8358
8359 if((p->tcph->th_flags & (TH_CWR|TH_ECE)) == (TH_CWR|TH_ECE))
8360 {
8361 scb->ha_state.session_flags |= SSNFLAG_ECN_CLIENT_QUERY;
8362 }
8363
8364 /* setup the stream trackers */
8365 tmp->client.s_mgr.state = TCP_STATE_ESTABLISHED;
8366 tmp->client.isn = tdb->seq;
8367 tmp->client.l_unackd = tdb->seq;
8368 tmp->client.l_nxt_seq = tmp->client.l_unackd;
8369 tmp->client.l_window = tdb->win;
8370 tmp->client.r_nxt_ack = tdb->ack;
8371 tmp->client.r_win_base = tdb->ack;
8372
8373 tmp->client.ts_last_pkt = p->pkth->ts.tv_sec;
8374
8375 tmp->server.seglist_base_seq = tmp->client.l_unackd;
8376 tmp->server.r_nxt_ack = tmp->client.l_unackd;
8377 tmp->server.r_win_base = tdb->seq;
8378 tmp->server.l_window = 0; /* reset later */
8379
8380 /* Next server packet is what was ACKd */
8381 tmp->server.l_nxt_seq = tdb->ack;
8382 tmp->server.l_unackd = tdb->ack - 1;
8383
8384 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8385 "seglist_base_seq = %X\n", tmp->server.seglist_base_seq););
8386 tmp->server.s_mgr.state = TCP_STATE_ESTABLISHED;
8387
8388 tmp->client.flags |= StreamGetTcpTimestamp(p, &tmp->client.ts_last, 0);
8389 if (tmp->client.ts_last == 0)
8390 tmp->client.flags |= TF_TSTAMP_ZERO;
8391 tmp->client.flags |= StreamGetMss(p, &tmp->client.mss);
8392 tmp->client.flags |= StreamGetWscale(p, &tmp->client.wscale);
8393
8394 /* Set the StreamTcpPolicy for each direction (pkt from client) */
8395 tmp->client.tcp_policy = StreamPolicyLookup(scb, GET_SRC_IP(p));
8396 tmp->server.tcp_policy = dstPolicy;
8397
8398 /* Server is destination */
8399 server_port = p->dp;
8400
8401 CopyMacAddr(p, tmp, FROM_CLIENT);
8402 }
8403 else
8404 {
8405 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8406 "Session direction is FROM_SERVER\n"););
8407
8408 /* Sender is server (src port is lower) */
8409 scb->ha_state.session_flags |= SSNFLAG_SEEN_SERVER;
8410
8411 /* setup the stream trackers */
8412 tmp->server.s_mgr.state = TCP_STATE_ESTABLISHED;
8413 tmp->server.isn = tdb->seq;
8414 tmp->server.l_unackd = tdb->seq;
8415 tmp->server.l_nxt_seq = tmp->server.l_unackd;
8416 tmp->server.l_window = tdb->win;
8417
8418 tmp->server.seglist_base_seq = tdb->ack;
8419 tmp->server.r_win_base = tdb->ack;
8420 tmp->server.r_nxt_ack = tdb->ack;
8421 tmp->server.ts_last_pkt = p->pkth->ts.tv_sec;
8422
8423 tmp->client.seglist_base_seq = tmp->server.l_unackd;
8424 tmp->client.r_nxt_ack = tmp->server.l_unackd;
8425 tmp->client.r_win_base = tdb->seq;
8426 tmp->client.l_window = 0; /* reset later */
8427 tmp->client.isn = tdb->ack-1;
8428 tmp->client.l_nxt_seq = tdb->ack;
8429
8430 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8431 "seglist_base_seq = %X\n", tmp->client.seglist_base_seq););
8432 tmp->client.s_mgr.state = TCP_STATE_ESTABLISHED;
8433
8434 tmp->server.flags |= StreamGetTcpTimestamp(p, &tmp->server.ts_last, 0);
8435 if (tmp->server.ts_last == 0)
8436 tmp->server.flags |= TF_TSTAMP_ZERO;
8437 tmp->server.flags |= StreamGetMss(p, &tmp->server.mss);
8438 tmp->server.flags |= StreamGetWscale(p, &tmp->server.wscale);
8439
8440 /* Set the StreamTcpPolicy for each direction (pkt from server) */
8441 tmp->server.tcp_policy = StreamPolicyLookup(scb, GET_SRC_IP(p));
8442 tmp->client.tcp_policy = dstPolicy;
8443 scb->proto_policy = tmp->server.tcp_policy;
8444
8445 /* Client is destination */
8446 server_port = p->sp;
8447
8448 CopyMacAddr(p, tmp, FROM_SERVER);
8449 }
8450 }
8451
8452 if (tmp)
8453 {
8454 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8455 "adding TcpSession to lightweight session\n"););
8456 scb->proto_specific_data = tmpBucket;
8457 scb->protocol = GET_IPH_PROTO(p);
8458 tmp->scb = scb;
8459
8460 /* New session, previous was marked as reset. Clear the
8461 * reset flag. */
8462 if (scb->ha_state.session_flags & SSNFLAG_RESET)
8463 scb->ha_state.session_flags &= ~SSNFLAG_RESET;
8464
8465 SetOSPolicy(tmp);
8466
8467 if ( (scb->ha_state.session_flags & SSNFLAG_CLIENT_SWAP) &&
8468 !(scb->ha_state.session_flags & SSNFLAG_CLIENT_SWAPPED) )
8469 {
8470 StreamTracker trk = tmp->client;
8471 sfaddr_t ip = scb->client_ip;
8472 uint16_t port = scb->client_port;
8473
8474 tmp->client = tmp->server;
8475 tmp->server = trk;
8476
8477 scb->client_ip = scb->server_ip;
8478 scb->server_ip = ip;
8479
8480 scb->client_port = scb->server_port;
8481 scb->server_port = port;
8482
8483 if ( !TwoWayTraffic(scb) )
8484 {
8485 if ( scb->ha_state.session_flags & SSNFLAG_SEEN_CLIENT )
8486 {
8487 scb->ha_state.session_flags ^= SSNFLAG_SEEN_CLIENT;
8488 scb->ha_state.session_flags |= SSNFLAG_SEEN_SERVER;
8489 }
8490 else if ( scb->ha_state.session_flags & SSNFLAG_SEEN_SERVER )
8491 {
8492 scb->ha_state.session_flags ^= SSNFLAG_SEEN_SERVER;
8493 scb->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT;
8494 }
8495 }
8496 scb->ha_state.session_flags |= SSNFLAG_CLIENT_SWAPPED;
8497 }
8498 /* Set up the flush behaviour, based on the configured info
8499 * for the server and client ports.
8500 */
8501 /* Yes, the server flush manager gets the info from the
8502 * policy's server port's the flush policy from the client
8503 * and visa-versa.
8504 *
8505 * For example, when policy said 'ports client 80', that means
8506 * reassemble packets from the client side (stored in the server's
8507 * flush buffer in the session) destined for port 80. Port 80 is
8508 * the server port and we're reassembling the client side.
8509 * That should make this almost as clear as opaque mud!
8510 */
8511 #ifdef TARGET_BASED
8512 if (tmp->client.tcp_policy->flush_config_protocol[scb->ha_state.application_protocol].configured == 1)
8513 {
8514 StreamTracker* pst = &tmp->server;
8515 uint8_t flush_policy =
8516 pst->tcp_policy->flush_config_protocol[scb->ha_state.application_protocol].client.flush_policy;
8517 InitFlushMgrByService(scb, pst, scb->ha_state.application_protocol, true, flush_policy);
8518 }
8519 else
8520 #endif
8521 {
8522 StreamTracker* pst = &tmp->server;
8523 uint8_t flush_policy =
8524 pst->tcp_policy->flush_config[server_port].client.flush_policy;
8525 InitFlushMgrByPort(scb, pst, server_port, true, flush_policy, false);
8526 }
8527
8528 #ifdef TARGET_BASED
8529 if (tmp->server.tcp_policy->flush_config_protocol[scb->ha_state.application_protocol].configured == 1)
8530 {
8531 StreamTracker* pst = &tmp->client;
8532 uint8_t flush_policy =
8533 pst->tcp_policy->flush_config_protocol[scb->ha_state.application_protocol].server.flush_policy;
8534 InitFlushMgrByService(scb, pst, scb->ha_state.application_protocol, false, flush_policy);
8535 }
8536 else
8537 #endif
8538 {
8539 StreamTracker* pst = &tmp->client;
8540 uint8_t flush_policy =
8541 pst->tcp_policy->flush_config[server_port].server.flush_policy;
8542 InitFlushMgrByPort(scb, pst, server_port, false, flush_policy, false);
8543 }
8544
8545
8546 #ifdef STREAM_DEBUG_ENABLED
8547 PrintTcpSession(tmp);
8548 #endif
8549
8550 session_api->set_expire_timer(p, scb, dstPolicy->session_timeout);
8551
8552 s5stats.tcp_streamtrackers_created++;
8553
8554 AddStreamSession(&sfBase, scb->session_state & STREAM_STATE_MIDSTREAM ? SSNFLAG_MIDSTREAM : 0);
8555
8556 StreamUpdatePerfBaseState(&sfBase, tmp->scb, TCP_STATE_SYN_SENT);
8557
8558 #ifdef NORMALIZER
8559 tmp->ecn = 0;
8560 #endif
8561 tmp->session_decrypted = false;
8562 PREPROC_PROFILE_END(s5TcpNewSessPerfStats);
8563 return 1;
8564 }
8565
8566 PREPROC_PROFILE_END(s5TcpNewSessPerfStats);
8567 return 0;
8568 }
8569
8570 /* set_service_based_flush_policy
8571 *
8572 * Once appid detects the protocol, calling this api
8573 * to set the respective paf apis.
8574 * If paf function pointer already pointed to the
8575 * correct paf api, not going to set again.
8576 */
set_service_based_flush_policy(SessionControlBlock * scb)8577 void set_service_based_flush_policy(SessionControlBlock *scb)
8578 {
8579 TcpSession *tcp_session = NULL;
8580 StreamTracker* pst;
8581 uint8_t flush_policy;
8582 int ret;
8583
8584 #ifdef TARGET_BASED
8585 if (scb->proto_specific_data)
8586 tcp_session = scb->proto_specific_data->data;
8587
8588 if (tcp_session == NULL)
8589 return;
8590
8591 if (tcp_session->client.tcp_policy->flush_config_protocol[scb->ha_state.application_protocol].configured == 1)
8592 {
8593 pst = &tcp_session->server;
8594 ret = cb_mask_cmp(((StreamConfig *)scb->stream_config)->tcp_config->paf_config,
8595 scb->ha_state.application_protocol, true, pst->paf_state.cb_mask);
8596 if (ret <= 0)
8597 {
8598 return;
8599 }
8600
8601 flush_policy =
8602 pst->tcp_policy->flush_config_protocol[scb->ha_state.application_protocol].client.flush_policy;
8603 InitFlushMgrByService(scb, pst, scb->ha_state.application_protocol, true, flush_policy);
8604 }
8605
8606 if (tcp_session->server.tcp_policy->flush_config_protocol[scb->ha_state.application_protocol].configured == 1)
8607 {
8608 pst = &tcp_session->client;
8609 ret = cb_mask_cmp(((StreamConfig *)scb->stream_config)->tcp_config->paf_config,
8610 scb->ha_state.application_protocol, false, pst->paf_state.cb_mask);
8611 if (ret <= 0)
8612 {
8613 return;
8614 }
8615
8616 flush_policy =
8617 pst->tcp_policy->flush_config_protocol[scb->ha_state.application_protocol].server.flush_policy;
8618 InitFlushMgrByService(scb, pst, scb->ha_state.application_protocol, false, flush_policy);
8619 }
8620 #endif
8621 }
8622
8623
RepeatedSyn(StreamTracker * listener,StreamTracker * talker,TcpDataBlock * tdb,TcpSession * tcpssn)8624 static int RepeatedSyn(
8625 StreamTracker *listener, StreamTracker *talker,
8626 TcpDataBlock *tdb, TcpSession *tcpssn)
8627 {
8628 switch (listener->os_policy)
8629 {
8630 case STREAM_POLICY_WINDOWS:
8631 case STREAM_POLICY_WINDOWS2K3:
8632 case STREAM_POLICY_VISTA:
8633 /* Windows has some strange behaviour here. If the
8634 * sequence of the reset is the next expected sequence,
8635 * it Resets. Otherwise it ignores the 2nd SYN.
8636 */
8637 if (SEQ_EQ(tdb->seq, listener->r_nxt_ack))
8638 {
8639 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8640 "Got syn on established windows ssn, which causes Reset,"
8641 "bailing\n"););
8642 tcpssn->scb->ha_state.session_flags |= SSNFLAG_RESET;
8643 talker->s_mgr.state = TCP_STATE_CLOSED;
8644 return ACTION_RST;
8645 }
8646 else
8647 {
8648 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8649 "Got syn on established windows ssn, not causing Reset,"
8650 "bailing\n"););
8651 Discard();
8652 return ACTION_NOTHING;
8653 }
8654 break;
8655 case STREAM_POLICY_MACOS:
8656 /* MACOS ignores a 2nd SYN, regardless of the sequence number. */
8657 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8658 "Got syn on established macos ssn, not causing Reset,"
8659 "bailing\n"););
8660 Discard();
8661 return ACTION_NOTHING;
8662 break;
8663 case STREAM_POLICY_FIRST:
8664 case STREAM_POLICY_NOACK:
8665 case STREAM_POLICY_LAST:
8666 case STREAM_POLICY_LINUX:
8667 case STREAM_POLICY_OLD_LINUX:
8668 case STREAM_POLICY_BSD:
8669 case STREAM_POLICY_SOLARIS:
8670 case STREAM_POLICY_HPUX11:
8671 case STREAM_POLICY_HPUX10:
8672 case STREAM_POLICY_IRIX:
8673 /* If its not a retransmission of the actual SYN... RESET */
8674 if(!SEQ_EQ(tdb->seq,talker->isn))
8675 {
8676 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8677 "Got syn on established ssn, which causes Reset, bailing\n"););
8678 tcpssn->scb->ha_state.session_flags |= SSNFLAG_RESET;
8679 talker->s_mgr.state = TCP_STATE_CLOSED;
8680 return ACTION_RST;
8681 }
8682 else
8683 {
8684 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8685 "Got syn on established ssn, not causing Reset,"
8686 "bailing\n"););
8687 Discard();
8688 return ACTION_NOTHING;
8689 }
8690 break;
8691 }
8692 return ACTION_NOTHING;
8693 }
8694
LogTcpEvents(StreamTcpPolicy * s5TcpPolicy,int eventcode)8695 static void LogTcpEvents(StreamTcpPolicy *s5TcpPolicy, int eventcode)
8696 {
8697 if ( !eventcode )
8698 return;
8699
8700 if (eventcode & EVENT_SYN_ON_EST)
8701 EventSynOnEst(s5TcpPolicy);
8702
8703 if (eventcode & EVENT_DATA_ON_SYN)
8704 EventDataOnSyn(s5TcpPolicy);
8705
8706 if (eventcode & EVENT_DATA_ON_CLOSED)
8707 EventDataOnClosed(s5TcpPolicy);
8708
8709 if (eventcode & EVENT_BAD_TIMESTAMP)
8710 EventBadTimestamp(s5TcpPolicy);
8711
8712 if (eventcode & EVENT_BAD_SEGMENT)
8713 EventBadSegment(s5TcpPolicy);
8714
8715 if (eventcode & EVENT_WINDOW_TOO_LARGE)
8716 EventWindowTooLarge(s5TcpPolicy);
8717
8718 if (eventcode & EVENT_EXCESSIVE_TCP_OVERLAPS)
8719 EventExcessiveOverlap(s5TcpPolicy);
8720
8721 if (eventcode & EVENT_DATA_AFTER_RESET)
8722 EventDataAfterReset(s5TcpPolicy);
8723
8724 if (eventcode & EVENT_SESSION_HIJACK_CLIENT)
8725 EventSessionHijackedClient(s5TcpPolicy);
8726
8727 if (eventcode & EVENT_SESSION_HIJACK_SERVER)
8728 EventSessionHijackedServer(s5TcpPolicy);
8729
8730 if (eventcode & EVENT_DATA_WITHOUT_FLAGS)
8731 EventDataWithoutFlags(s5TcpPolicy);
8732
8733 if (eventcode & EVENT_4WHS)
8734 Event4whs(s5TcpPolicy);
8735
8736 if (eventcode & EVENT_NO_TIMESTAMP)
8737 EventNoTimestamp(s5TcpPolicy);
8738
8739 if (eventcode & EVENT_BAD_RST)
8740 EventBadReset(s5TcpPolicy);
8741
8742 if (eventcode & EVENT_BAD_FIN)
8743 EventBadFin(s5TcpPolicy);
8744
8745 if (eventcode & EVENT_BAD_ACK)
8746 EventBadAck(s5TcpPolicy);
8747
8748 if (eventcode & EVENT_DATA_AFTER_RST_RCVD)
8749 EventDataAfterRstRcvd(s5TcpPolicy);
8750
8751 if (eventcode & EVENT_WINDOW_SLAM)
8752 EventWindowSlam(s5TcpPolicy);
8753 }
8754
DisableInspection(SessionControlBlock * scb,Packet * p,char ignore)8755 static inline void DisableInspection (SessionControlBlock *scb, Packet* p, char ignore)
8756 {
8757 /* Set the directions to ignore... */
8758 scb->ha_state.ignore_direction = ignore;
8759 StreamSetReassemblyTcp(scb, STREAM_FLPOLICY_IGNORE, ignore, STREAM_FLPOLICY_SET_ABSOLUTE);
8760 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8761 "Stream: Ignoring packet from %d. Marking session marked as ignore.\n",
8762 p->packet_flags & PKT_FROM_SERVER? "server" : "client"););
8763
8764 session_api->disable_inspection(scb, p);
8765 }
8766
checkFINTransitionStatus(const Packet * p,StreamTracker * listener)8767 static inline bool checkFINTransitionStatus(const Packet* p, StreamTracker *listener)
8768 {
8769 if((p->dsize != 0) && (listener->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT) &&
8770 ((listener->s_mgr.transition_seq - 1) == listener->r_nxt_ack))
8771 return true;
8772 return false;
8773 }
8774
ProcessTcp(SessionControlBlock * scb,Packet * p,TcpDataBlock * tdb,StreamTcpPolicy * s5TcpPolicy,SFXHASH_NODE * hash_node)8775 static int ProcessTcp(SessionControlBlock *scb, Packet *p, TcpDataBlock *tdb,
8776 StreamTcpPolicy *s5TcpPolicy, SFXHASH_NODE *hash_node)
8777 {
8778 int retcode = ACTION_NOTHING;
8779 int eventcode = 0;
8780 char ignore;
8781 int got_ts = 0;
8782 int new_ssn = 0;
8783 int ts_action = ACTION_NOTHING;
8784 TcpSession *tcpssn = NULL;
8785 StreamTracker *talker = NULL;
8786 StreamTracker *listener = NULL;
8787 uint32_t require3Way = (s5TcpPolicy->flags & STREAM_CONFIG_REQUIRE_3WHS);
8788 bool process_fin = false;
8789 STREAM_DEBUG_WRAP(char *t = NULL; char *l = NULL;)
8790 PROFILE_VARS;
8791
8792 if (scb->protocol != IPPROTO_TCP)
8793 {
8794 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
8795 "Lightweight session not TCP on TCP packet\n"););
8796 return retcode;
8797 }
8798
8799 if (scb->proto_specific_data)
8800 tcpssn = (TcpSession *)scb->proto_specific_data->data;
8801
8802 PREPROC_PROFILE_START(s5TcpStatePerfStats);
8803
8804 if (tcpssn == NULL)
8805 {
8806 if ( ScPafEnabled() )
8807 {
8808 /* Check if the session is to be ignored */
8809 if (hash_node)
8810 ignore = StreamExpectProcessNode(p, scb, hash_node);
8811 else
8812 ignore = StreamExpectCheck(p, scb);
8813 if (ignore)
8814 {
8815 DisableInspection(scb, p, ignore);
8816 PREPROC_PROFILE_END(s5TcpStatePerfStats);
8817 return retcode;
8818 }
8819 }
8820
8821 if (TCP_ISFLAGSET(p->tcph, TH_SYN) && !TCP_ISFLAGSET(p->tcph, TH_ACK))
8822 {
8823 scb->session_state |= STREAM_STATE_SYN;
8824
8825 if( require3Way || ( StreamPacketHasWscale( p ) & TF_WSCALE ) ||
8826 ( ( p->dsize > 0 ) &&
8827 ( StreamGetPolicy( scb, s5TcpPolicy, FROM_CLIENT ) == STREAM_POLICY_MACOS ) ) )
8828 {
8829 /* Create TCP session if we
8830 * 1) require 3-WAY HS, OR
8831 * 2) client sent wscale option, OR
8832 * 3) have data and its a MAC OS policy -- MAC
8833 * is the only one that accepts data on SYN
8834 * (and thus requires a TCP session at this point)
8835 */
8836 if(NewTcpSession(p, scb, tdb, s5TcpPolicy)== -1 )
8837 {
8838 PREPROC_PROFILE_END(s5TcpStatePerfStats);
8839 return retcode;
8840 }
8841 tcpssn = (TcpSession *)scb->proto_specific_data->data;
8842 new_ssn = 1;
8843 NormalTrackECN(tcpssn, p->tcph, require3Way);
8844 }
8845
8846 /* Nothing left todo here */
8847 }
8848 else if( TCP_ISFLAGSET( p->tcph, ( TH_SYN | TH_ACK ) ) )
8849 {
8850 scb->session_state |= STREAM_STATE_SYN_ACK;
8851 if (!require3Way || midstream_allowed)
8852 {
8853 if(NewTcpSession(p, scb, tdb, s5TcpPolicy)== -1 )
8854 {
8855 PREPROC_PROFILE_END(s5TcpStatePerfStats);
8856 return retcode;
8857 }
8858 tcpssn = (TcpSession *)scb->proto_specific_data->data;
8859 new_ssn = 1;
8860 }
8861 NormalTrackECN(tcpssn, p->tcph, require3Way);
8862 /* Nothing left todo here */
8863 }
8864 else if( TCP_ISFLAGSET( p->tcph, TH_ACK ) && !TCP_ISFLAGSET( p->tcph, TH_RST )
8865 &&
8866 ( scb->session_state & STREAM_STATE_SYN_ACK ) )
8867 {
8868 /* TODO: do we need to verify the ACK field is >= the seq of the SYN-ACK? */
8869
8870 /* 3-way Handshake complete, create TCP session */
8871 scb->session_state |= STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED;
8872 if(NewTcpSession(p, scb, tdb, s5TcpPolicy)== -1 )
8873 {
8874 PREPROC_PROFILE_END(s5TcpStatePerfStats);
8875 return retcode;
8876 }
8877 tcpssn = (TcpSession *)scb->proto_specific_data->data;
8878 new_ssn = 1;
8879
8880 NormalTrackECN(tcpssn, p->tcph, require3Way);
8881 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_ESTABLISHED);
8882 }
8883 else if ((p->dsize > 0) && (!require3Way || midstream_allowed))
8884 {
8885 // TBD-EDM not sure we need this here...
8886 //
8887 /* need to figure out direction, etc
8888 Assume from client, can update later */
8889 if (p->sp > p->dp)
8890 {
8891 scb->ha_state.direction = FROM_CLIENT;
8892 IP_COPY_VALUE(scb->client_ip, GET_SRC_IP(p));
8893 scb->client_port = p->tcph->th_sport;
8894 IP_COPY_VALUE(scb->server_ip, GET_DST_IP(p));
8895 scb->server_port = p->tcph->th_dport;
8896 }
8897 else
8898 {
8899 scb->ha_state.direction = FROM_SERVER;
8900 IP_COPY_VALUE(scb->client_ip, GET_DST_IP(p));
8901 scb->client_port = p->tcph->th_dport;
8902 IP_COPY_VALUE(scb->server_ip, GET_SRC_IP(p));
8903 scb->server_port = p->tcph->th_sport;
8904 }
8905 scb->session_state |= STREAM_STATE_MIDSTREAM;
8906 scb->ha_state.session_flags |= SSNFLAG_MIDSTREAM;
8907
8908
8909 #ifdef STREAM_DEBUG_ENABLED
8910 if (ScReadMode())
8911 {
8912 /* If we're in readback mode... may only have one packet.
8913 * That being packet with the exploit being tested, so
8914 * mark this session as established, so rule option
8915 * 'flow:established' works correctly.
8916 */
8917 STREAM_DEBUG_WRAP(
8918 char timestamp[TIMEBUF_SIZE];
8919 char src_addr[17];
8920 char dst_addr[17];
8921 memset((char *)timestamp, 0, TIMEBUF_SIZE);
8922 ts_print((struct timeval *) &p->pkth->ts, timestamp);
8923 SnortSnprintf(src_addr, 17, "%s",
8924 inet_ntoa(GET_SRC_ADDR(p)));
8925 SnortSnprintf(dst_addr, 17, "%s",
8926 inet_ntoa(GET_DST_ADDR(p)));
8927 DebugMessage(DEBUG_STREAM_STATE, "Session not established"
8928 "on midstream-pickup of data packet. Will be marked"
8929 "as established when other side is seen. Packet Info:"
8930 "Time: %s\tSrc: %s:%d\tDst: %s:%d\n",
8931 timestamp, src_addr, p->sp, dst_addr, p->dp);
8932
8933 );
8934 #ifdef MIMIC_STREAM4_MIDSTREAM_BEHAVIOUR
8935 scb->session_state |= STREAM_STATE_ESTABLISHED;
8936 scb->ha_state.session_flags |= SSNFLAG_ESTABLISHED;
8937 #endif
8938 }
8939 #endif
8940 if(NewTcpSession(p, scb, tdb, s5TcpPolicy)== -1 )
8941 {
8942 PREPROC_PROFILE_END(s5TcpStatePerfStats);
8943 return retcode;
8944 }
8945 tcpssn = (TcpSession *)scb->proto_specific_data->data;
8946 new_ssn = 1;
8947 NormalTrackECN(tcpssn, p->tcph, require3Way);
8948
8949 if (scb->session_state & STREAM_STATE_ESTABLISHED)
8950 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_ESTABLISHED);
8951 }
8952 else if (p->dsize == 0)
8953 {
8954 /* Already have a scb, but no tcp session.
8955 * Probably just an ACK of already sent data (that
8956 * we missed).
8957 */
8958 /* Do nothing. */
8959 PREPROC_PROFILE_END(s5TcpStatePerfStats);
8960 return retcode;
8961 }
8962
8963
8964 /* This flag is set in session_expect when the event handler is set.
8965 * It is assumed that if we need to register the event handler before
8966 * analyzing the packet, we will also want to begin packet reassembly
8967 * immediately. If a preprocessor does not want to set reassembly in
8968 * both directory, it will call set_reassembly again with the correct
8969 * parameters.
8970 */
8971 if (p->packet_flags & PKT_EARLY_REASSEMBLY)
8972 {
8973 p->packet_flags &= ~PKT_EARLY_REASSEMBLY;
8974 StreamSetReassemblyTcp(scb, STREAM_FLPOLICY_FOOTPRINT,
8975 SSN_DIR_BOTH, STREAM_FLPOLICY_SET_ABSOLUTE);
8976 }
8977 }
8978 else
8979 {
8980
8981 /* If session is already marked as established */
8982 if (!(scb->session_state & STREAM_STATE_ESTABLISHED))
8983 {
8984 if (hash_node)
8985 ignore = StreamExpectProcessNode(p, scb, hash_node);
8986 else
8987 ignore = StreamExpectCheck(p, scb);
8988 if (p->packet_flags & PKT_EARLY_REASSEMBLY)
8989 {
8990 p->packet_flags &= ~PKT_EARLY_REASSEMBLY;
8991 StreamSetReassemblyTcp(scb, STREAM_FLPOLICY_FOOTPRINT,
8992 ~(ignore & SSN_DIR_BOTH) & SSN_DIR_BOTH, //Directions to not ignore
8993 STREAM_FLPOLICY_SET_ABSOLUTE);
8994 }
8995
8996 if(!require3Way || midstream_allowed)
8997 {
8998 /* If not requiring 3-way Handshake... */
8999
9000 /* TCP session created on TH_SYN above,
9001 * or maybe on SYN-ACK, or anything else */
9002
9003 /* Need to update Lightweight session state */
9004 if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK)))
9005 {
9006 /* SYN-ACK from server */
9007 if (scb->session_state != STREAM_STATE_NONE)
9008 {
9009 scb->session_state |= STREAM_STATE_SYN_ACK;
9010 }
9011 }
9012 else if (TCP_ISFLAGSET(p->tcph, TH_ACK) &&
9013 (scb->session_state & STREAM_STATE_SYN_ACK))
9014 {
9015 scb->session_state |= STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED;
9016 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_ESTABLISHED);
9017 }
9018
9019 }
9020 }
9021
9022 #ifdef NORMALIZER
9023 if (TCP_ISFLAGSET(p->tcph, TH_SYN))
9024 NormalTrackECN(tcpssn, p->tcph, require3Way);
9025 #endif
9026 }
9027
9028 two_way_traffic = TwoWayTraffic(scb);
9029 /* figure out direction of this packet */
9030 session_api->set_packet_direction_flag(p, scb);
9031
9032 if(p->packet_flags & PKT_FROM_SERVER)
9033 {
9034 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9035 "Stream: Updating on packet from server\n"););
9036 scb->ha_state.session_flags |= SSNFLAG_SEEN_SERVER;
9037 if (tcpssn)
9038 {
9039 talker = &tcpssn->server;
9040 listener = &tcpssn->client;
9041 }
9042
9043 STREAM_DEBUG_WRAP(
9044 t = "Server";
9045 l = "Client");
9046
9047 if ( talker && talker->s_mgr.state == TCP_STATE_LISTEN &&
9048 ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) )
9049 {
9050 eventcode |= EVENT_4WHS;
9051 }
9052 /* If we picked this guy up midstream, finish the initialization */
9053 if ((scb->session_state & STREAM_STATE_MIDSTREAM) &&
9054 !(scb->session_state & STREAM_STATE_ESTABLISHED))
9055 {
9056 FinishServerInit(p, tdb, tcpssn);
9057 if((p->tcph->th_flags & TH_ECE) &&
9058 scb->ha_state.session_flags & SSNFLAG_ECN_CLIENT_QUERY)
9059 {
9060 scb->ha_state.session_flags |= SSNFLAG_ECN_SERVER_REPLY;
9061 }
9062
9063 if (scb->ha_state.session_flags & SSNFLAG_SEEN_CLIENT)
9064 {
9065 // should TCP state go to established too?
9066 scb->session_state |= STREAM_STATE_ESTABLISHED;
9067 scb->ha_state.session_flags |= SSNFLAG_ESTABLISHED;
9068 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_ESTABLISHED);
9069 }
9070 }
9071 #ifdef ACTIVE_RESPONSE
9072 if ( !scb->inner_server_ttl )
9073 SetTTL(scb, p, 0);
9074 #endif
9075 }
9076 else
9077 {
9078 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9079 "Stream: Updating on packet from client\n"););
9080 /* if we got here we had to see the SYN already... */
9081 scb->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT;
9082 if (tcpssn)
9083 {
9084 talker = &tcpssn->client;
9085 listener = &tcpssn->server;
9086 }
9087
9088 STREAM_DEBUG_WRAP(
9089 t = "Client";
9090 l = "Server";);
9091
9092 if ((scb->session_state & STREAM_STATE_MIDSTREAM) &&
9093 !(scb->session_state & STREAM_STATE_ESTABLISHED))
9094 {
9095 /* Midstream and seen server. */
9096 if (scb->ha_state.session_flags & SSNFLAG_SEEN_SERVER)
9097 {
9098 scb->session_state |= STREAM_STATE_ESTABLISHED;
9099 scb->ha_state.session_flags |= SSNFLAG_ESTABLISHED;
9100 }
9101 }
9102 #ifdef ACTIVE_RESPONSE
9103 if ( !scb->inner_client_ttl )
9104 SetTTL(scb, p, 1);
9105 #endif
9106 }
9107 /* Check if there is a reload and policy is changed */
9108 if( listener && talker && listener->tcp_policy != s5TcpPolicy && talker->tcp_policy != s5TcpPolicy)
9109 {
9110 listener->tcp_policy = s5TcpPolicy;
9111 talker->tcp_policy = StreamPolicyLookup(scb, GET_SRC_IP(p));
9112 }
9113 /*
9114 * check for SYN on reset session
9115 */
9116 if ((scb->ha_state.session_flags & SSNFLAG_RESET) &&
9117 (p->tcph->th_flags & TH_SYN))
9118 {
9119 if ((!tcpssn) ||
9120 ((listener->s_mgr.state == TCP_STATE_CLOSED) ||
9121 (talker->s_mgr.state == TCP_STATE_CLOSED)))
9122 {
9123 /* Listener previously issued a reset */
9124 /* Talker is re-SYN-ing */
9125 struct session_state_cleanup_cache sscc;
9126
9127 cleanup_cache_session_state( scb, &sscc );
9128 TcpSessionCleanupWithFreeApplicationData(scb);
9129 cleanup_log_session_state( "SYN on RST ssn", &sscc );
9130
9131 if (p->tcph->th_flags & TH_RST)
9132 {
9133 /* Got SYN/RST. We're done. */
9134 NormalTrimPayloadIfSyn(p, 0, tdb);
9135 NormalTrimPayloadIfRst(p, 0, tdb);
9136 tcpssn = NULL;
9137 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9138 return retcode | ACTION_RST;
9139 }
9140 else if (TCP_ISFLAGSET(p->tcph, TH_SYN) &&
9141 !TCP_ISFLAGSET(p->tcph, TH_ACK))
9142 {
9143 scb->ha_state.direction = FROM_CLIENT;
9144 IP_COPY_VALUE(scb->client_ip, GET_SRC_IP(p));
9145 scb->client_port = p->tcph->th_sport;
9146 IP_COPY_VALUE(scb->server_ip, GET_DST_IP(p));
9147 scb->server_port = p->tcph->th_dport;
9148 scb->session_state = STREAM_STATE_SYN;
9149 #ifdef ACTIVE_RESPONSE
9150 SetTTL(scb, p, 1);
9151 #endif
9152 if(NewTcpSession(p, scb, tdb, s5TcpPolicy)== -1 )
9153 {
9154 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9155 return retcode;
9156 }
9157
9158 tcpssn = (TcpSession *)scb->proto_specific_data->data;
9159 new_ssn = 1;
9160 NormalTrackECN(tcpssn, p->tcph, require3Way);
9161
9162 if (tcpssn)
9163 {
9164 listener = &tcpssn->server;
9165 talker = &tcpssn->client;
9166 }
9167 scb->ha_state.session_flags = SSNFLAG_SEEN_CLIENT;
9168 }
9169 else if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK)))
9170 {
9171 scb->ha_state.direction = FROM_SERVER;
9172 IP_COPY_VALUE(scb->client_ip, GET_DST_IP(p));
9173 scb->client_port = p->tcph->th_dport;
9174 IP_COPY_VALUE(scb->server_ip, GET_SRC_IP(p));
9175 scb->server_port = p->tcph->th_sport;
9176 scb->session_state = STREAM_STATE_SYN_ACK;
9177 #ifdef ACTIVE_RESPONSE
9178 SetTTL(scb, p, 0);
9179 #endif
9180 if(NewTcpSession(p, scb, tdb, s5TcpPolicy)== -1 )
9181 {
9182 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9183 return retcode;
9184 }
9185 tcpssn = (TcpSession *)scb->proto_specific_data->data;
9186 new_ssn = 1;
9187 NormalTrackECN(tcpssn, p->tcph, require3Way);
9188
9189 if (tcpssn)
9190 {
9191 listener = &tcpssn->client;
9192 talker = &tcpssn->server;
9193 }
9194 scb->ha_state.session_flags = SSNFLAG_SEEN_SERVER;
9195 }
9196 }
9197 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9198 "Got SYN pkt on reset ssn, re-SYN-ing\n"););
9199 }
9200
9201 if (((p->packet_flags & PKT_FROM_SERVER) && (scb->ha_state.ignore_direction & SSN_DIR_FROM_CLIENT)) ||
9202 ((p->packet_flags & PKT_FROM_CLIENT) && (scb->ha_state.ignore_direction & SSN_DIR_FROM_SERVER)))
9203 {
9204 if (talker && (talker->flags & TF_FORCE_FLUSH))
9205 {
9206 StreamFlushTalker(p, scb);
9207 talker->flags &= ~TF_FORCE_FLUSH;
9208 }
9209
9210 if (listener && (listener->flags & TF_FORCE_FLUSH))
9211 {
9212 StreamFlushListener(p, scb);
9213 listener->flags &= ~TF_FORCE_FLUSH;
9214 }
9215 p->packet_flags |= PKT_IGNORE;
9216 retcode |= ACTION_DISABLE_INSPECTION;
9217 }
9218
9219 /* Check if the session is to be ignored */
9220 if ( !ScPafEnabled() )
9221 {
9222 if (hash_node)
9223 ignore = StreamExpectProcessNode(p, scb, hash_node);
9224 else
9225 ignore = StreamExpectCheck(p, scb);
9226 if (ignore)
9227 {
9228 DisableInspection(scb, p, ignore);
9229 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9230 return retcode;
9231 }
9232 }
9233
9234 /* Handle data on SYN */
9235 if (!IsTCPFastOpenPkt(p) && p->dsize && TCP_ISFLAGSET(p->tcph, TH_SYN))
9236 {
9237 /* MacOS accepts data on SYN, so don't alert if policy is MACOS */
9238 if (StreamGetPolicy(scb, s5TcpPolicy, FROM_CLIENT) !=
9239 STREAM_POLICY_MACOS)
9240 {
9241 #ifdef NORMALIZER
9242 NormalTrimPayloadIfSyn(p, 0, tdb); // remove data on SYN
9243 if ( Normalize_GetMode(snort_conf, NORM_TCP_TRIM_SYN) == NORM_MODE_OFF)
9244 #endif
9245 {
9246 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9247 "Got data on SYN packet, not processing it\n"););
9248 //EventDataOnSyn(s5TcpPolicy);
9249 eventcode |= EVENT_DATA_ON_SYN;
9250 retcode |= ACTION_BAD_PKT;
9251 }
9252 }
9253 }
9254
9255 if (!tcpssn)
9256 {
9257 LogTcpEvents(s5TcpPolicy, eventcode);
9258 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9259 return retcode;
9260 }
9261
9262 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9263 " %s [talker] state: %s\n", t,
9264 state_names[talker->s_mgr.state]););
9265 STREAM_DEBUG_WRAP(PrintFlushMgr(&talker->flush_mgr););
9266 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9267 " %s state: %s(%d)\n", l,
9268 state_names[listener->s_mgr.state],
9269 listener->s_mgr.state););
9270 STREAM_DEBUG_WRAP(PrintFlushMgr(&listener->flush_mgr););
9271
9272 // may find better placement to eliminate redundant flag checks
9273 if(p->tcph->th_flags & TH_SYN)
9274 talker->s_mgr.sub_state |= SUB_SYN_SENT;
9275 if(p->tcph->th_flags & TH_ACK)
9276 talker->s_mgr.sub_state |= SUB_ACK_SENT;
9277
9278 /*
9279 * process SYN ACK on unestablished sessions
9280 */
9281 if( (TCP_STATE_SYN_SENT == listener->s_mgr.state) &&
9282 (TCP_STATE_LISTEN == talker->s_mgr.state) )
9283 {
9284 if(p->tcph->th_flags & TH_ACK)
9285 {
9286 /*
9287 * make sure we've got a valid segment
9288 */
9289 if(!IsBetween(listener->l_unackd, listener->l_nxt_seq, tdb->ack))
9290 {
9291 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9292 "Pkt ack is out of bounds, bailing!\n"););
9293 Discard();
9294 NormalTrimPayloadIfWin(p, 0, tdb);
9295 LogTcpEvents(listener->tcp_policy, eventcode);
9296 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9297 return retcode | ACTION_BAD_PKT;
9298 }
9299 }
9300
9301 talker->flags |= StreamGetTcpTimestamp(p, &tdb->ts, 0);
9302 if (tdb->ts == 0)
9303 talker->flags |= TF_TSTAMP_ZERO;
9304
9305 /*
9306 * catch resets sent by server
9307 */
9308 if(p->tcph->th_flags & TH_RST)
9309 {
9310 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9311 "got RST\n"););
9312
9313 NormalTrimPayloadIfRst(p, 0, tdb);
9314
9315 /* Reset is valid when in SYN_SENT if the
9316 * ack field ACKs the SYN.
9317 */
9318 if(ValidRstSynSent(listener, tdb))
9319 {
9320 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9321 "got RST, closing talker\n"););
9322 /* Reset is valid */
9323 /* Mark session as reset... Leave it around so that any
9324 * additional data sent from one side or the other isn't
9325 * processed (and is dropped in inline mode).
9326 */
9327 scb->ha_state.session_flags |= SSNFLAG_RESET;
9328 talker->s_mgr.state = TCP_STATE_CLOSED;
9329 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_CLOSING);
9330 /* Leave listener open, data may be in transit */
9331 LogTcpEvents(listener->tcp_policy, eventcode);
9332 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9333 return retcode | ACTION_RST;
9334 }
9335 /* Reset not valid. */
9336 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9337 "bad sequence number, bailing\n"););
9338 Discard();
9339 eventcode |= EVENT_BAD_RST;
9340 NormalDropPacket(p);
9341 LogTcpEvents(listener->tcp_policy, eventcode);
9342 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9343 return retcode;
9344 }
9345
9346 /*
9347 * finish up server init
9348 */
9349 if(p->tcph->th_flags & TH_SYN)
9350 {
9351 FinishServerInit(p, tdb, tcpssn);
9352 if (talker->flags & TF_TSTAMP)
9353 {
9354 talker->ts_last_pkt = p->pkth->ts.tv_sec;
9355 talker->ts_last = tdb->ts;
9356 }
9357 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9358 "Finish server init got called!\n"););
9359 }
9360 else
9361 {
9362 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9363 "Finish server init didn't get called!\n"););
9364 }
9365
9366 if((p->tcph->th_flags & TH_ECE) &&
9367 scb->ha_state.session_flags & SSNFLAG_ECN_CLIENT_QUERY)
9368 {
9369 scb->ha_state.session_flags |= SSNFLAG_ECN_SERVER_REPLY;
9370 }
9371
9372 /*
9373 * explicitly set the state
9374 */
9375 listener->s_mgr.state = TCP_STATE_SYN_SENT;
9376 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9377 "Accepted SYN ACK\n"););
9378 }
9379
9380 /*
9381 * scale the window. Only if BOTH client and server specified
9382 * wscale option as part of 3-way handshake.
9383 * This is per RFC 1323.
9384 */
9385 if ((talker->flags & TF_WSCALE) && (listener->flags & TF_WSCALE))
9386 {
9387 tdb->win <<= talker->wscale;
9388 }
9389
9390 /* Check for session hijacking -- compare mac address to the ones
9391 * that were recorded at session startup.
9392 */
9393 #ifdef DAQ_PKT_FLAG_PRE_ROUTING
9394 if (!(p->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING) &&
9395 listener->tcp_policy->flags & STREAM_CONFIG_CHECK_SESSION_HIJACKING)
9396 #else
9397 if (listener->tcp_policy->flags & STREAM_CONFIG_CHECK_SESSION_HIJACKING)
9398 #endif
9399 {
9400 eventcode |= ValidMacAddress(talker, listener, p);
9401 }
9402
9403 /* Check timestamps */
9404 ts_action = ValidTimestamp(talker, listener, tdb, p, &eventcode, &got_ts);
9405
9406 /*
9407 * check RST validity
9408 */
9409 if(p->tcph->th_flags & TH_RST)
9410 {
9411 NormalTrimPayloadIfRst(p, 0, tdb);
9412
9413 if(ValidRst(scb, listener, tdb))
9414 {
9415 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9416 "Got RST, bailing\n"););
9417
9418 if (
9419 listener->s_mgr.state == TCP_STATE_FIN_WAIT_1 ||
9420 listener->s_mgr.state == TCP_STATE_FIN_WAIT_2 ||
9421 listener->s_mgr.state == TCP_STATE_CLOSE_WAIT ||
9422 listener->s_mgr.state == TCP_STATE_LAST_ACK ||
9423 listener->s_mgr.state == TCP_STATE_CLOSING
9424 ) {
9425 StreamFlushTalker(p, scb);
9426 StreamFlushListener(p, scb);
9427 scb->ha_state.session_flags |= SSNFLAG_FREE_APP_DATA;
9428 }
9429 scb->ha_state.session_flags |= SSNFLAG_RESET;
9430 talker->s_mgr.state = TCP_STATE_CLOSED;
9431 talker->s_mgr.sub_state |= SUB_RST_SENT;
9432 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_CLOSING);
9433
9434 #ifdef NORMALIZER
9435 if ( Normalize_GetMode(snort_conf, NORM_TCP_IPS) == NORM_MODE_ON )
9436 listener->s_mgr.state = TCP_STATE_CLOSED;
9437 /* else for ids:
9438 leave listener open, data may be in transit */
9439 #endif
9440
9441 LogTcpEvents(listener->tcp_policy, eventcode);
9442 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9443 return retcode | ACTION_RST;
9444 }
9445 /* Reset not valid. */
9446 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9447 "bad sequence number, bailing\n"););
9448 Discard();
9449 eventcode |= EVENT_BAD_RST;
9450 NormalDropPacket(p);
9451 LogTcpEvents(listener->tcp_policy, eventcode);
9452 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9453 return retcode | ts_action;
9454 }
9455 else
9456 {
9457 /* check for valid seqeuence/retrans */
9458 bool before_win_base = false;
9459 if( s5TcpPolicy->policy != STREAM_POLICY_NOACK )
9460 {
9461 if ( (listener->s_mgr.state >= TCP_STATE_ESTABLISHED) &&
9462 !ValidSeq(p, scb, listener, tdb, &before_win_base) )
9463 {
9464 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9465 "bad sequence number, bailing\n"););
9466 Discard();
9467 if(before_win_base)
9468 DisableAppPreprocessors(p);
9469 NormalTrimPayloadIfWin(p, 0, tdb);
9470 LogTcpEvents(listener->tcp_policy, eventcode);
9471 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9472 return retcode | ts_action;
9473 }
9474 }
9475 }
9476
9477 if (ts_action != ACTION_NOTHING)
9478 {
9479 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9480 "bad timestamp, bailing\n"););
9481 Discard();
9482 // this packet was normalized elsewhere
9483 LogTcpEvents(listener->tcp_policy, eventcode);
9484 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9485 return retcode | ts_action;
9486 }
9487
9488 /*
9489 * update PAWS timestamps
9490 */
9491 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9492 "PAWS update tdb->seq %lu > listener->r_win_base %lu\n",
9493 tdb->seq, listener->r_win_base););
9494 if(got_ts && SEQ_EQ(listener->r_win_base, tdb->seq))
9495 {
9496 if((int32_t)(tdb->ts - talker->ts_last) >= 0 ||
9497 (uint32_t)p->pkth->ts.tv_sec >= talker->ts_last_pkt+PAWS_24DAYS)
9498 {
9499 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9500 "updating timestamps...\n"););
9501 talker->ts_last = tdb->ts;
9502 talker->ts_last_pkt = p->pkth->ts.tv_sec;
9503 }
9504 }
9505 else
9506 {
9507 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9508 "not updating timestamps...\n"););
9509 }
9510
9511 /*
9512 * check for repeat SYNs
9513 */
9514 if ( !new_ssn &&
9515 ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) )
9516 {
9517 int action;
9518 #ifdef NORMALIZER
9519 if ( !SEQ_EQ(tdb->seq, talker->isn) &&
9520 NormalDropPacket(p) )
9521 action = ACTION_BAD_PKT;
9522 else
9523 #endif
9524 if ( talker->s_mgr.state >= TCP_STATE_ESTABLISHED )
9525 action = RepeatedSyn(listener, talker, tdb, tcpssn);
9526 else
9527 action = ACTION_NOTHING;
9528
9529 if (action != ACTION_NOTHING)
9530 {
9531 /* got a bad SYN on the session, alert! */
9532 eventcode |= EVENT_SYN_ON_EST;
9533 LogTcpEvents(listener->tcp_policy, eventcode);
9534 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9535 return retcode | action;
9536 }
9537 }
9538
9539 /*
9540 * Check that the window is within the limits
9541 */
9542 if ( s5TcpPolicy->policy != STREAM_POLICY_NOACK )
9543 {
9544 if (listener->tcp_policy->max_window && (tdb->win > listener->tcp_policy->max_window))
9545 {
9546 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9547 "Got window that was beyond the allowed policy value, bailing\n"););
9548 /* got a window too large, alert! */
9549 eventcode |= EVENT_WINDOW_TOO_LARGE;
9550 Discard();
9551 NormalDropPacket(p);
9552 LogTcpEvents(listener->tcp_policy, eventcode);
9553 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9554 return retcode | ACTION_BAD_PKT;
9555 }
9556 else if ((p->packet_flags & PKT_FROM_CLIENT)
9557 && (tdb->win <= SLAM_MAX) && (tdb->ack == listener->isn + 1)
9558 && !(p->tcph->th_flags & (TH_FIN|TH_RST))
9559 && !(scb->ha_state.session_flags & SSNFLAG_MIDSTREAM))
9560 {
9561 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9562 "Window slammed shut!\n"););
9563 /* got a window slam alert! */
9564 eventcode |= EVENT_WINDOW_SLAM;
9565 Discard();
9566
9567 #ifdef NORMALIZER
9568 if ( NormalDropPacket(p) )
9569 {
9570 LogTcpEvents(listener->tcp_policy, eventcode);
9571 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9572 return retcode | ACTION_BAD_PKT;
9573 }
9574 #endif
9575 }
9576 }
9577
9578 if(talker->s_mgr.state_queue != TCP_STATE_NONE)
9579 {
9580 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9581 "Found queued state transition on ack 0x%X, "
9582 "current 0x%X!\n", talker->s_mgr.transition_seq,
9583 tdb->ack););
9584 if(tdb->ack == talker->s_mgr.transition_seq)
9585 {
9586 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9587 "accepting transition!\n"););
9588 talker->s_mgr.state = talker->s_mgr.state_queue;
9589 talker->s_mgr.state_queue = TCP_STATE_NONE;
9590 //If ACK is received for Queued FIN before previous data is received. Process FIN transition
9591 if(listener->s_mgr.state == TCP_STATE_ESTABLISHED)
9592 {
9593 listener->l_nxt_seq++;
9594 talker->r_nxt_ack = tdb->ack;
9595 listener->s_mgr.sub_state |= SUB_FIN_SENT;
9596 listener->s_mgr.state = TCP_STATE_FIN_WAIT_1;
9597
9598 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_CLOSING);
9599 }
9600 }
9601 }
9602
9603 /*
9604 * process ACK flags
9605 */
9606 if(p->tcph->th_flags & TH_ACK)
9607 {
9608 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9609 "Got an ACK...\n"););
9610 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9611 " %s [listener] state: %s\n", l,
9612 state_names[listener->s_mgr.state]););
9613
9614 switch(listener->s_mgr.state)
9615 {
9616 case TCP_STATE_SYN_SENT:
9617 if ( !require3Way || midstream_allowed )
9618 break;
9619 // fall thru ...
9620 case TCP_STATE_SYN_RCVD:
9621 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9622 "listener state is SYN_SENT...\n"););
9623 if(IsBetween(listener->l_unackd, listener->l_nxt_seq, tdb->ack) &&
9624 ((!require3Way || midstream_allowed) ||
9625 ((talker->s_mgr.sub_state == SUB_SETUP_OK) &&
9626 (listener->s_mgr.sub_state == SUB_SETUP_OK)) ))
9627 {
9628 UpdateSsn(p, listener, talker, tdb);
9629 scb->ha_state.session_flags |= SSNFLAG_ESTABLISHED;
9630 scb->session_state |= STREAM_STATE_ESTABLISHED;
9631 listener->s_mgr.state = TCP_STATE_ESTABLISHED;
9632 talker->s_mgr.state = TCP_STATE_ESTABLISHED;
9633 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_ESTABLISHED);
9634 /* Indicate this packet completes 3-way handshake */
9635 p->packet_flags |= PKT_STREAM_TWH;
9636 }
9637
9638 talker->flags |= got_ts;
9639 if(got_ts && SEQ_EQ(listener->r_nxt_ack, tdb->seq))
9640 {
9641 talker->ts_last_pkt = p->pkth->ts.tv_sec;
9642 talker->ts_last = tdb->ts;
9643 }
9644
9645 break;
9646
9647 case TCP_STATE_ESTABLISHED:
9648 /* Handle out-of-order/OOO ACK */
9649 if ((Normalize_GetMode(snort_conf, NORM_TCP_IPS) == NORM_MODE_ON) &&
9650 (SEQ_GT(tdb->ack, listener->l_nxt_seq)))
9651 {
9652 NormalDropPacket(p);
9653 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9654 return retcode | ACTION_BAD_PKT;
9655 }
9656 UpdateSsn(p, listener, talker, tdb);
9657 break;
9658
9659 case TCP_STATE_CLOSE_WAIT:
9660 UpdateSsn(p, listener, talker, tdb);
9661 break;
9662
9663 case TCP_STATE_FIN_WAIT_1:
9664 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9665 "tdb->ack %X >= talker->r_nxt_ack %X\n",
9666 tdb->ack, talker->r_nxt_ack););
9667
9668 if ( SEQ_EQ(tdb->ack, listener->l_nxt_seq) )
9669 {
9670 if ( (listener->os_policy == STREAM_POLICY_WINDOWS) && (tdb->win == 0) )
9671 {
9672 eventcode |= EVENT_WINDOW_SLAM;
9673 Discard();
9674
9675 #ifdef NORMALIZER
9676 if ( NormalDropPacket(p) )
9677 {
9678 LogTcpEvents(listener->tcp_policy, eventcode);
9679 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9680 return retcode | ACTION_BAD_PKT;
9681 }
9682 #endif
9683 }
9684
9685 UpdateSsn(p, listener, talker, tdb);
9686 listener->s_mgr.state = TCP_STATE_FIN_WAIT_2;
9687
9688 if ( (p->tcph->th_flags & TH_FIN) )
9689 {
9690 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9691 "seq ok, setting state!\n"););
9692
9693 if (talker->s_mgr.state_queue == TCP_STATE_NONE)
9694 {
9695 talker->s_mgr.state = TCP_STATE_LAST_ACK;
9696 EndOfFileHandle(p, (TcpSession *)scb->proto_specific_data->data);
9697 }
9698 if ( scb->ha_state.session_flags & SSNFLAG_MIDSTREAM )
9699 {
9700 // FIXTHIS this should be handled below in fin section
9701 // but midstream sessions fail the seq test
9702 listener->s_mgr.state_queue = TCP_STATE_TIME_WAIT;
9703 listener->s_mgr.transition_seq = tdb->end_seq;
9704 listener->s_mgr.expected_flags = TH_ACK;
9705 }
9706 }
9707 else if (listener->s_mgr.state_queue == TCP_STATE_CLOSING)
9708 {
9709 listener->s_mgr.state_queue = TCP_STATE_TIME_WAIT;
9710 listener->s_mgr.transition_seq = tdb->end_seq;
9711 listener->s_mgr.expected_flags = TH_ACK;
9712 }
9713 }
9714 else
9715 {
9716 UpdateSsn(p, listener, talker, tdb);
9717 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9718 "bad ack!\n"););
9719 }
9720 break;
9721
9722 case TCP_STATE_FIN_WAIT_2:
9723 if ( SEQ_GT(tdb->ack, listener->l_nxt_seq) )
9724 {
9725 eventcode |= EVENT_BAD_ACK;
9726 LogTcpEvents(talker->tcp_policy, eventcode);
9727 NormalDropPacket(p);
9728 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9729 return retcode | ACTION_BAD_PKT;
9730 }
9731 UpdateSsn(p, listener, talker, tdb);
9732 break;
9733
9734 case TCP_STATE_CLOSING:
9735 UpdateSsn(p, listener, talker, tdb);
9736 if(SEQ_GEQ(tdb->end_seq, listener->r_nxt_ack))
9737 {
9738 listener->s_mgr.state = TCP_STATE_TIME_WAIT;
9739 }
9740 break;
9741
9742 case TCP_STATE_LAST_ACK:
9743 UpdateSsn(p, listener, talker, tdb);
9744
9745 if ( SEQ_EQ(tdb->ack, listener->l_nxt_seq) )
9746 {
9747 listener->s_mgr.state = TCP_STATE_CLOSED;
9748 }
9749 break;
9750
9751 default:
9752 // FIXTHIS safe to ignore when inline?
9753 break;
9754 }
9755 }
9756
9757 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
9758 tcpssn->priv_ptr = p->pkth->priv_ptr;
9759 #endif
9760 /*
9761 * handle data in the segment
9762 */
9763 if(p->dsize)
9764 {
9765 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9766 " %s state: %s(%d) getting data\n", l,
9767 state_names[listener->s_mgr.state],
9768 listener->s_mgr.state););
9769
9770 // FIN means only that sender is done talking,
9771 // other side may continue yapping.
9772 if(TCP_STATE_FIN_WAIT_2 == talker->s_mgr.state ||
9773 TCP_STATE_TIME_WAIT == talker->s_mgr.state)
9774 {
9775 /* data on a segment when we're not accepting data any more */
9776 /* alert! */
9777 //EventDataOnClosed(talker->tcp_policy);
9778 eventcode |= EVENT_DATA_ON_CLOSED;
9779 retcode |= ACTION_BAD_PKT;
9780 NormalDropPacket(p);
9781 }
9782 else if (TCP_STATE_CLOSED == talker->s_mgr.state)
9783 {
9784 /* data on a segment when we're not accepting data any more */
9785 /* alert! */
9786 if (scb->ha_state.session_flags & SSNFLAG_RESET)
9787 {
9788 // no need to run detection PPs on this packet
9789 DisableDetect( p );
9790
9791 //EventDataAfterReset(listener->tcp_policy);
9792 if ( talker->s_mgr.sub_state & SUB_RST_SENT )
9793 eventcode |= EVENT_DATA_AFTER_RESET;
9794 else
9795 eventcode |= EVENT_DATA_AFTER_RST_RCVD;
9796 }
9797 else
9798 {
9799 //EventDataOnClosed(listener->tcp_policy);
9800 eventcode |= EVENT_DATA_ON_CLOSED;
9801 }
9802 retcode |= ACTION_BAD_PKT;
9803 NormalDropPacket(p);
9804 }
9805 else if ((TCP_STATE_FIN_WAIT_1 == talker->s_mgr.state) &&
9806 SEQ_GEQ(tdb->seq, (listener->s_mgr.transition_seq - 1)))
9807 {
9808 /* Alert! : Data on a segment when we're not accepting data any more */
9809 eventcode |= EVENT_DATA_ON_CLOSED;
9810 retcode |= ACTION_BAD_PKT;
9811 NormalDropPacket(p);
9812 }
9813 else
9814 {
9815 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9816 "Queuing data on listener, t %s, l %s...\n",
9817 flush_policy_names[talker->flush_mgr.flush_policy],
9818 flush_policy_names[listener->flush_mgr.flush_policy]););
9819
9820 #ifdef NORMALIZER
9821 if( s5TcpPolicy->policy != STREAM_POLICY_NOACK )
9822 {
9823 // these normalizations can't be done if we missed setup. and
9824 // window is zero in one direction until we've seen both sides.
9825 // Avoid this normalization for Asymmetric traffic
9826 if (( !(scb->ha_state.session_flags & SSNFLAG_MIDSTREAM) ) && TwoWayTraffic(scb))
9827 {
9828 // sender of syn w/mss limits payloads from peer
9829 // since we store mss on sender side, use listener mss
9830 // same reasoning for window size
9831 StreamTracker* st = listener;
9832
9833 // trim to fit in window and mss as needed
9834 NormalTrimPayloadIfWin(p, (st->r_win_base + st->l_window) - st->r_nxt_ack, tdb);
9835 if ( st->mss )
9836 NormalTrimPayloadIfMss(p, st->mss, tdb);
9837
9838 NormalCheckECN(tcpssn, p);
9839 }
9840 }
9841 #endif
9842 /*
9843 * dunno if this is RFC but fragroute testing expects it
9844 * for the record, I've seen FTP data sessions that send
9845 * data packets with no tcp flags set
9846 */
9847 if ((p->tcph->th_flags != 0) || (s5TcpPolicy->policy == STREAM_POLICY_LINUX) || (s5TcpPolicy->policy == STREAM_POLICY_NOACK))
9848 {
9849 ProcessTcpData(p, listener, tcpssn, tdb, s5TcpPolicy);
9850 //Check if all segments are received. Process FIN transition
9851 if(checkFINTransitionStatus(p, listener))
9852 process_fin = true;
9853 }
9854 else
9855 {
9856 eventcode |= EVENT_DATA_WITHOUT_FLAGS;
9857 NormalDropPacket(p);
9858 }
9859 }
9860 }
9861
9862 if((p->tcph->th_flags & TH_FIN) || process_fin) //FIN is received or process Queued FIN
9863 {
9864 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9865 "Got an FIN...\n"););
9866 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9867 " %s state: %s(%d)\n", l,
9868 state_names[talker->s_mgr.state],
9869 talker->s_mgr.state););
9870
9871 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9872 "checking ack (0x%X) vs nxt_ack (0x%X)\n",
9873 tdb->end_seq, listener->r_win_base););
9874
9875 if(SEQ_LT(tdb->end_seq,listener->r_win_base))
9876 {
9877 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9878 "FIN inside r_win_base, bailing\n"););
9879 goto dupfin;
9880 }
9881 else
9882 {
9883 //FIN is in order or we need to process FIN from state_queue
9884 if((tdb->end_seq == listener->r_nxt_ack) || process_fin ||
9885 (talker->s_mgr.state > TCP_STATE_ESTABLISHED) ||
9886 (listener->flush_mgr.flush_policy == STREAM_FLPOLICY_IGNORE))
9887 {
9888 // need substate since we don't change state immediately
9889 if ( (talker->s_mgr.state >= TCP_STATE_ESTABLISHED) &&
9890 !(talker->s_mgr.sub_state & SUB_FIN_SENT) )
9891 {
9892 talker->l_nxt_seq++;
9893 listener->r_nxt_ack++;
9894 talker->s_mgr.sub_state |= SUB_FIN_SENT;
9895
9896 #ifdef NORMALIZER
9897 if ((listener->flush_mgr.flush_policy != STREAM_FLPOLICY_PROTOCOL) &&
9898 (listener->flush_mgr.flush_policy != STREAM_FLPOLICY_PROTOCOL_IPS) &&
9899 (listener->flush_mgr.flush_policy != STREAM_FLPOLICY_PROTOCOL_NOACK) &&
9900 Normalize_GetMode(snort_conf, NORM_TCP_IPS) == NORM_MODE_ON)
9901 {
9902 p->packet_flags |= PKT_PDU_TAIL;
9903 }
9904 #endif
9905 }
9906 switch(talker->s_mgr.state)
9907 {
9908 case TCP_STATE_SYN_RCVD:
9909 case TCP_STATE_ESTABLISHED:
9910 if (talker->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT)
9911 {
9912 talker->s_mgr.state_queue = TCP_STATE_CLOSING;
9913 }
9914 talker->s_mgr.state = TCP_STATE_FIN_WAIT_1;
9915 EndOfFileHandle(p, (TcpSession *) scb->proto_specific_data->data);
9916 #ifdef NORMALIZER
9917 if ( !p->dsize )
9918 CheckFlushPolicyOnData( ( ( StreamConfig * ) scb->stream_config )->tcp_config,
9919 tcpssn, talker, listener, tdb, p);
9920 #endif
9921 StreamUpdatePerfBaseState(&sfBase, scb, TCP_STATE_CLOSING);
9922 break;
9923
9924 case TCP_STATE_CLOSE_WAIT:
9925 talker->s_mgr.state = TCP_STATE_LAST_ACK;
9926 break;
9927
9928 case TCP_STATE_FIN_WAIT_1:
9929 if (!p->dsize)
9930 RetransmitHandle(p, tcpssn);
9931 break;
9932
9933 default:
9934 /* all other states stay where they are */
9935 break;
9936 }
9937
9938 if (!process_fin && ((talker->s_mgr.state == TCP_STATE_FIN_WAIT_1) ||
9939 (talker->s_mgr.state == TCP_STATE_LAST_ACK)))
9940 {
9941 uint32_t end_seq = ( scb->ha_state.session_flags & SSNFLAG_MIDSTREAM ) ?
9942 tdb->end_seq-1 : tdb->end_seq;
9943
9944 if ( (listener->s_mgr.expected_flags == TH_ACK) &&
9945 SEQ_GEQ(end_seq, listener->s_mgr.transition_seq) )
9946 {
9947 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9948 "FIN beyond previous, ignoring\n"););
9949 eventcode |= EVENT_BAD_FIN;
9950 LogTcpEvents(talker->tcp_policy, eventcode);
9951 NormalDropPacket(p);
9952 PREPROC_PROFILE_END(s5TcpStatePerfStats);
9953 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
9954 tcpssn->priv_ptr = NULL;
9955 #endif
9956 return retcode | ACTION_BAD_PKT;
9957 }
9958 }
9959
9960 if(!process_fin)
9961 {
9962 switch ( listener->s_mgr.state )
9963 {
9964 case TCP_STATE_ESTABLISHED:
9965 listener->s_mgr.state_queue = TCP_STATE_CLOSE_WAIT;
9966 listener->s_mgr.transition_seq = tdb->end_seq + 1;
9967 listener->s_mgr.expected_flags = TH_ACK;
9968 break;
9969
9970 case TCP_STATE_FIN_WAIT_1:
9971 listener->s_mgr.state_queue = TCP_STATE_CLOSING;
9972 listener->s_mgr.transition_seq = tdb->end_seq + 1;
9973 listener->s_mgr.expected_flags = TH_ACK;
9974 break;
9975
9976 case TCP_STATE_FIN_WAIT_2:
9977 listener->s_mgr.state_queue = TCP_STATE_TIME_WAIT;
9978 listener->s_mgr.transition_seq = tdb->end_seq + 1;
9979 listener->s_mgr.expected_flags = TH_ACK;
9980 break;
9981
9982 case TCP_STATE_CLOSED:
9983 listener->s_mgr.transition_seq = tdb->end_seq + 1;
9984 break;
9985 }
9986 }
9987 }
9988 else
9989 {
9990 //OOO FIN received
9991 if((listener->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT) && SEQ_LT(tdb->end_seq,listener->s_mgr.transition_seq))
9992 {
9993 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
9994 "FIN inside transition_seq, bailing\n"););
9995 goto dupfin;
9996 }
9997 if ((listener->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT) ||
9998 (talker->s_mgr.state == TCP_STATE_FIN_WAIT_1) ||
9999 (talker->s_mgr.state == TCP_STATE_LAST_ACK))
10000 {
10001 uint32_t end_seq = ( scb->ha_state.session_flags & SSNFLAG_MIDSTREAM ) ?
10002 tdb->end_seq-1 : tdb->end_seq;
10003
10004 if ( (listener->s_mgr.expected_flags == TH_ACK) &&
10005 SEQ_GEQ(end_seq, listener->s_mgr.transition_seq) )
10006 {
10007 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10008 "FIN beyond previous, ignoring\n"););
10009 eventcode |= EVENT_BAD_FIN;
10010 LogTcpEvents(talker->tcp_policy, eventcode);
10011 NormalDropPacket(p);
10012 PREPROC_PROFILE_END(s5TcpStatePerfStats);
10013 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
10014 tcpssn->priv_ptr = NULL;
10015 #endif
10016 return retcode | ACTION_BAD_PKT;
10017 }
10018 }
10019 switch ( listener->s_mgr.state )
10020 {
10021 case TCP_STATE_ESTABLISHED:
10022 listener->s_mgr.state_queue = TCP_STATE_CLOSE_WAIT;
10023 listener->s_mgr.transition_seq = tdb->end_seq + 1;
10024 listener->s_mgr.expected_flags = TH_ACK;
10025 break;
10026
10027 case TCP_STATE_CLOSED:
10028 listener->s_mgr.transition_seq = tdb->end_seq + 1;
10029 break;
10030 }
10031 }
10032 }
10033 }
10034
10035 dupfin:
10036
10037 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10038 " %s [talker] state: %s\n", t,
10039 state_names[talker->s_mgr.state]););
10040 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10041 " %s state: %s(%d)\n", l,
10042 state_names[listener->s_mgr.state],
10043 listener->s_mgr.state););
10044
10045 /*
10046 * handle TIME_WAIT timer stuff
10047 */
10048
10049 /* Handle Asymmetric connection closing, we will see only one
10050 * direction pkts. FIN_ACK handling.
10051 * Do not set state to closed prematurely when handling retry packets
10052 * to avoid retry loop - CSCvc08844.
10053 */
10054 if((!TwoWayTraffic(scb) &&
10055 #ifdef DAQ_PKT_FLAG_RETRY_PACKET
10056 !(p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET) &&
10057 #endif
10058 (talker->s_mgr.state >= TCP_STATE_FIN_WAIT_1 || listener->s_mgr.state >= TCP_STATE_FIN_WAIT_1)))
10059 {
10060 if (TCP_ISFLAGSET(p->tcph, (TH_FIN|TH_ACK)))
10061 {
10062 if(talker->s_mgr.state >= TCP_STATE_FIN_WAIT_1)
10063 talker->s_mgr.state = TCP_STATE_CLOSED;
10064 if(listener->s_mgr.state >= TCP_STATE_FIN_WAIT_1)
10065 listener->s_mgr.state = TCP_STATE_CLOSED;
10066 listener->flags |= TF_FORCE_FLUSH;
10067 }
10068 }
10069
10070 if((talker->s_mgr.state == TCP_STATE_TIME_WAIT && listener->s_mgr.state == TCP_STATE_CLOSED) ||
10071 (listener->s_mgr.state == TCP_STATE_TIME_WAIT && talker->s_mgr.state == TCP_STATE_CLOSED) ||
10072 (listener->s_mgr.state == TCP_STATE_TIME_WAIT && talker->s_mgr.state == TCP_STATE_TIME_WAIT)||
10073 (!TwoWayTraffic(scb)&& (talker->s_mgr.state == TCP_STATE_CLOSED || listener->s_mgr.state == TCP_STATE_CLOSED)))
10074 {
10075 //dropssn:
10076 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10077 "Session terminating, flushing session buffers\n"););
10078
10079 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
10080 tcpssn->priv_ptr = NULL;
10081 #endif
10082 if ( p->tcph->th_flags & TH_ACK )
10083 CheckFlushPolicyOnAck( ( ( StreamConfig * ) scb->stream_config )->tcp_config,
10084 tcpssn, talker, listener, tdb, p);
10085
10086 if(p->packet_flags & PKT_FROM_SERVER)
10087 {
10088 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10089 "flushing FROM_SERVER\n"););
10090 if(talker->seg_bytes_logical)
10091 {
10092 uint32_t flushed = flush_stream(tcpssn, talker, p,
10093 GET_DST_IP(p), GET_SRC_IP(p),
10094 p->tcph->th_dport, p->tcph->th_sport,
10095 PKT_FROM_CLIENT);
10096
10097 if(flushed)
10098 {
10099 // FIXTHIS - these calls redundant?
10100 purge_alerts(talker, talker->r_win_base, (void *)tcpssn->scb);
10101 purge_to_seq(tcpssn, talker, talker->seglist->seq + flushed);
10102 }
10103 }
10104
10105 if(listener->seg_bytes_logical)
10106 {
10107 uint32_t flushed = flush_stream(tcpssn, listener, p,
10108 GET_SRC_IP(p), GET_DST_IP(p),
10109 p->tcph->th_sport, p->tcph->th_dport,
10110 PKT_FROM_SERVER);
10111
10112 if(flushed)
10113 {
10114 purge_alerts(listener, listener->r_win_base, (void *)tcpssn->scb);
10115 purge_to_seq(tcpssn, listener, listener->seglist->seq + flushed);
10116 }
10117 }
10118 }
10119 else
10120 {
10121 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10122 "flushing FROM_CLIENT\n"););
10123 if(listener->seg_bytes_logical)
10124 {
10125 uint32_t flushed = flush_stream(tcpssn, listener, p,
10126 GET_SRC_IP(p), GET_DST_IP(p),
10127 p->tcph->th_sport, p->tcph->th_dport,
10128 PKT_FROM_CLIENT);
10129
10130 if(flushed)
10131 {
10132 purge_alerts(listener, listener->r_win_base, (void *)tcpssn->scb);
10133 purge_to_seq(tcpssn, listener, listener->seglist->seq + flushed);
10134 }
10135 }
10136
10137 if(talker->seg_bytes_logical)
10138 {
10139 uint32_t flushed = flush_stream(tcpssn, talker, p,
10140 GET_DST_IP(p), GET_SRC_IP(p),
10141 p->tcph->th_dport, p->tcph->th_sport,
10142 PKT_FROM_SERVER);
10143
10144 if(flushed)
10145 {
10146 purge_alerts(talker, talker->r_win_base,(void *)tcpssn->scb);
10147 purge_to_seq(tcpssn, talker, talker->seglist->seq + flushed);
10148 }
10149 }
10150 }
10151 LogTcpEvents(listener->tcp_policy, eventcode);
10152 /* The last ACK is a part of the session. Delete the session after processing is complete. */
10153 TcpSessionCleanup(scb, 0);
10154 scb->session_state |= STREAM_STATE_CLOSED;
10155 PREPROC_PROFILE_END(s5TcpStatePerfStats);
10156 return retcode | ACTION_LWSSN_CLOSED;
10157 }
10158 else if(listener->s_mgr.state == TCP_STATE_CLOSED && talker->s_mgr.state == TCP_STATE_SYN_SENT)
10159 {
10160 if(p->tcph->th_flags & TH_SYN &&
10161 !(p->tcph->th_flags & TH_ACK) &&
10162 !(p->tcph->th_flags & TH_RST))
10163 {
10164 session_api->set_expire_timer(p, scb, s5TcpPolicy->session_timeout);
10165 }
10166 }
10167
10168 if((listener->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK)
10169 || (listener->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL_NOACK))
10170 {
10171 uint32_t flushed = 0;
10172 flushed = CheckFlushPolicyOnData( ( ( StreamConfig * ) scb->stream_config )->tcp_config,
10173 tcpssn, talker, listener, tdb, p);
10174 if (flushed)
10175 {
10176 if(listener->xtradata_mask && extra_data_log)
10177 purge_alerts(listener, listener->seglist->seq + flushed, (void *)tcpssn->scb);
10178 }
10179 }
10180 #ifdef NORMALIZER
10181 else if ( p->dsize > 0 )
10182 {
10183 /* in case of Asymmetric traffic, enfore flush_policy from STREAM_FLPOLICY_FOOTPRINT to STREAM_FLPOLICY_FOOTPRINT_IPS
10184 * This will be applied on passive mode sessions, which has policy mode as STREAM_FLPOLICY_FOOTPRINT only
10185 */
10186 uint32_t flushed = 0;
10187 if (!TwoWayTraffic(scb) &&
10188 (scb->session_state & ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK)) &&
10189 !TCP_ISFLAGSET(p->tcph, TH_SYN))
10190 {
10191 if(listener->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL)
10192 listener->flush_mgr.flush_policy = STREAM_FLPOLICY_PROTOCOL_IPS;
10193 else if(listener->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT)
10194 listener->flush_mgr.flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS;
10195 }
10196
10197 flushed = CheckFlushPolicyOnData( ( ( StreamConfig * ) scb->stream_config )->tcp_config,
10198 tcpssn, talker, listener, tdb, p);
10199 if (!TwoWayTraffic(scb) && flushed &&
10200 (scb->session_state & ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK)) &&
10201 !TCP_ISFLAGSET(p->tcph, TH_SYN))
10202 {
10203 purge_to_seq(tcpssn, listener, listener->seglist->seq + flushed);
10204 }
10205 else if(flushed)
10206 {
10207 if(listener->xtradata_mask && extra_data_log)
10208 purge_alerts(listener, listener->seglist->seq + flushed, (void *)tcpssn->scb);
10209 }
10210 }
10211 #endif
10212
10213 if ( p->tcph->th_flags & TH_ACK )
10214 CheckFlushPolicyOnAck( ( ( StreamConfig * ) scb->stream_config )->tcp_config,
10215 tcpssn, talker, listener, tdb, p);
10216
10217 LogTcpEvents(listener->tcp_policy, eventcode);
10218 PREPROC_PROFILE_END(s5TcpStatePerfStats);
10219 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
10220 tcpssn->priv_ptr = NULL;
10221 #endif
10222 return retcode;
10223 }
10224
10225 // this is for post-ack flushing
GetReverseDir(const Packet * p)10226 static inline uint32_t GetReverseDir (const Packet* p)
10227 {
10228 /* Remember, one side's packets are stored in the
10229 * other side's queue. So when talker ACKs data,
10230 * we need to check if we're ready to flush.
10231 *
10232 * If we do decide to flush, the flush IP & port info
10233 * is the opposite of the packet -- again because this
10234 * is the ACK from the talker and we're flushing packets
10235 * that actually came from the listener.
10236 */
10237 if ( p->packet_flags & PKT_FROM_SERVER )
10238 return PKT_FROM_CLIENT;
10239
10240 else if ( p->packet_flags & PKT_FROM_CLIENT )
10241 return PKT_FROM_SERVER;
10242
10243 return 0;
10244 }
10245
10246 #ifdef NORMALIZER
GetForwardDir(const Packet * p)10247 static inline uint32_t GetForwardDir (const Packet* p)
10248 {
10249 if ( p->packet_flags & PKT_FROM_SERVER )
10250 return PKT_FROM_SERVER;
10251
10252 else if ( p->packet_flags & PKT_FROM_CLIENT )
10253 return PKT_FROM_CLIENT;
10254
10255 return 0;
10256 }
10257
CheckFlushCoercion(Packet * p,FlushMgr * fm,uint16_t flush_factor)10258 static inline int CheckFlushCoercion (
10259 Packet* p, FlushMgr* fm, uint16_t flush_factor
10260 ) {
10261 if ( !flush_factor )
10262 return 0;
10263
10264 if (
10265 p->dsize &&
10266 (p->dsize < fm->last_size) &&
10267 (fm->last_count >= flush_factor) )
10268 {
10269 fm->last_size = 0;
10270 fm->last_count = 0;
10271 return 1;
10272 }
10273 if ( p->dsize > fm->last_size )
10274 fm->last_size = p->dsize;
10275
10276 fm->last_count++;
10277 return 0;
10278 }
10279
CheckFTPFlushCoercion(Packet * p,FlushMgr * fm)10280 static inline int CheckFTPFlushCoercion (Packet* p, FlushMgr* fm)
10281 {
10282 #ifdef HAVE_DAQ_DECRYPTED_SSL
10283 if (p->pkth->flags & DAQ_PKT_FLAG_DECRYPTED_SSL)
10284 {
10285 if (fm->flush)
10286 return 1;
10287 else
10288 return 0;
10289 }
10290 #endif
10291 if( p->dsize && p->dsize != fm->last_size )
10292 {
10293 fm->last_size = p->dsize;
10294 return 1;
10295 }
10296 return 0;
10297 }
10298 #endif
10299
AutoDisable(StreamTracker * a,StreamTracker * b)10300 static inline bool AutoDisable (StreamTracker* a, StreamTracker* b)
10301 {
10302 if ( !a->flush_mgr.auto_disable )
10303 return false;
10304
10305 a->flush_mgr.flush_policy = STREAM_FLPOLICY_IGNORE;
10306 purge_all(a);
10307
10308 if ( b->flush_mgr.auto_disable )
10309 {
10310 b->flush_mgr.flush_policy = STREAM_FLPOLICY_IGNORE;
10311 purge_all(b);
10312 }
10313 return true;
10314 }
10315
10316 #ifdef NORMALIZER
10317 /*
10318 * In case of Pre-ACK mode, check if we need to
10319 * block packet so that the payload deos not reach endpoint without
10320 * inspection.
10321 */
check_to_hold_packet(Packet * pkt,PAF_Status paf_state,StreamTracker * trk)10322 static inline bool check_to_hold_packet(Packet *pkt, PAF_Status paf_state,
10323 StreamTracker *trk)
10324 {
10325 if (((paf_state == PAF_PSEUDO_FLUSH_SEARCH) ||
10326 (paf_state == PAF_PSEUDO_FLUSH_SKIP)) &&
10327 !(pkt->packet_flags & PKT_PSEUDO_FLUSH))
10328 {
10329 if(trk->held_segment != NULL)
10330 return FALSE;
10331
10332 return TRUE;
10333 }
10334 return FALSE;
10335 }
10336
hold_packet(Packet * pkt,StreamTracker * trk,StreamSegment * seg)10337 static inline void hold_packet(Packet *pkt, StreamTracker *trk,
10338 StreamSegment *seg)
10339 {
10340 trk->held_segment = seg;
10341 pkt->packet_flags |= PKT_FAST_BLOCK;
10342 Active_DropPacket(pkt);
10343 }
10344
10345 // see flush_pdu_ackd() for details
10346 // the key difference is that we operate on forward moving data
10347 // because we don't wait until it is acknowledged
flush_pdu_ips(StreamTcpConfig * config,TcpSession * ssn,StreamTracker * trk,Packet * pkt,uint64_t * flags)10348 static inline uint32_t flush_pdu_ips ( StreamTcpConfig *config, TcpSession *ssn,
10349 StreamTracker *trk, Packet *pkt, uint64_t *flags )
10350 {
10351 bool to_srv = ( *flags == PKT_FROM_CLIENT );
10352 uint16_t srv_port = ( to_srv ? pkt->dp : pkt->sp );
10353 uint32_t total = 0, avail;
10354 StreamSegment* seg;
10355 PROFILE_VARS;
10356
10357 PREPROC_PROFILE_START(s5TcpPAFPerfStats);
10358 avail = get_q_sequenced(trk);
10359 seg = trk->seglist_next;
10360
10361 // * must stop if gap (checked in s5_paf_check)
10362 while ( seg && *flags && (total < avail) )
10363 {
10364 uint32_t flush_pt;
10365 uint32_t size = seg->size;
10366 uint32_t end = seg->seq + seg->size;
10367 uint32_t pos = s5_paf_position(&trk->paf_state);
10368
10369 total += size;
10370
10371 if ( s5_paf_initialized(&trk->paf_state) && SEQ_LEQ(end, pos) )
10372 {
10373 if (!seg->next && pkt->packet_flags & PKT_PSEUDO_FLUSH)
10374 {
10375 *flags |= PKT_PSEUDO_FLUSH;
10376 } else {
10377 seg = seg->next;
10378 continue;
10379 }
10380 }
10381 //Used by h2_paf
10382 wire_packet = pkt;
10383 flush_policy_for_dir = trk->flush_mgr.flush_policy;
10384 flush_pt = s5_paf_check( config->paf_config, &trk->paf_state, ssn->scb,
10385 seg->payload, size, total, seg->seq, srv_port,
10386 flags, trk->flush_mgr.flush_pt);
10387
10388 if (check_to_hold_packet(pkt, trk->paf_state.paf, trk))
10389 {
10390 hold_packet(pkt, trk, seg);
10391 }
10392
10393 if (*flags & PKT_PURGE)
10394 {
10395 //For HTTP/2 case where stream doesnt flush the data
10396 //Set the seglist value to SL_BUF_FLUSHED
10397 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10398 "flush_pdu_ips and purge\n"););
10399 seg->buffered = SL_BUF_FLUSHED;
10400 return 0;
10401
10402 }
10403 if ( flush_pt > 0 )
10404 {
10405 PREPROC_PROFILE_END(s5TcpPAFPerfStats);
10406 return flush_pt;
10407 }
10408 seg = seg->next;
10409 }
10410
10411 PREPROC_PROFILE_END(s5TcpPAFPerfStats);
10412 return 0;
10413 }
10414
CheckFlushPolicyOnData(StreamTcpConfig * config,TcpSession * tcpssn,StreamTracker * talker,StreamTracker * listener,TcpDataBlock * tdb,Packet * p)10415 static inline int CheckFlushPolicyOnData( StreamTcpConfig *config, TcpSession *tcpssn,
10416 StreamTracker *talker, StreamTracker *listener,
10417 TcpDataBlock *tdb, Packet *p)
10418 {
10419 uint32_t flushed = 0;
10420 uint32_t avail;
10421
10422 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10423 "In CheckFlushPolicyOnData\n"););
10424 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10425 "Talker flush policy: %s\n",
10426 flush_policy_names[talker->flush_mgr.flush_policy]););
10427 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10428 "Listener flush policy: %s\n",
10429 flush_policy_names[listener->flush_mgr.flush_policy]););
10430
10431 switch(listener->flush_mgr.flush_policy)
10432 {
10433 case STREAM_FLPOLICY_IGNORE:
10434 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10435 "STREAM_FLPOLICY_IGNORE\n"););
10436 return 0;
10437
10438 case STREAM_FLPOLICY_FOOTPRINT_IPS_FTP:
10439 {
10440 int coerce = 0;
10441 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10442 "STREAM_FLPOLICY_FOOTPRINT-IPS_FTP\n"););
10443
10444 #ifdef NORMALIZER
10445 if ( Normalize_GetMode(snort_conf, NORM_TCP_IPS) == NORM_MODE_ON )
10446 {
10447 #ifdef DAQ_PKT_FLAG_SSL_DETECTED
10448 //Do not do FTP-Normalization for FTPS traffic
10449 if((p->pkth->flags & DAQ_PKT_FLAG_SSL_DETECTED) || (p->pkth->flags & DAQ_PKT_FLAG_SSL_SHELLO))
10450 {
10451 tcpssn->pp_flags |= PP_FTPTELNET_FTPS;
10452 listener->flush_mgr.last_size = 0;
10453 }
10454 #endif
10455 if(!(tcpssn->pp_flags & PP_FTPTELNET_FTPS))
10456 {
10457 if(!listener->flush_mgr.last_size)
10458 {
10459 //Rely on mss if it exists, else use snaplen
10460 if((tcpssn->client.mss > 0) && (tcpssn->server.mss > 0))
10461 {
10462 uint32_t ftp_data_conn_mss = (tcpssn->client.mss < tcpssn->server.mss) ? tcpssn->client.mss : tcpssn->server.mss;
10463 listener->flush_mgr.last_size = ftp_data_conn_mss - p->tcp_options_len;
10464 }
10465 else
10466 listener->flush_mgr.last_size = pkt_snaplen - (p->data - p->pkt);
10467 }
10468 coerce = CheckFTPFlushCoercion(p, &listener->flush_mgr);
10469 if(coerce)
10470 CallFTPFlushProcessor(p);
10471 listener->flush_mgr.flush = false;
10472 talker->flush_mgr.flush = false;
10473 }
10474 if(!coerce)
10475 {
10476 if(tcpssn->pp_flags & PP_FTPTELNET_FTPS)
10477 coerce = CheckFlushCoercion(p, &listener->flush_mgr, listener->tcp_policy->flush_factor);
10478 avail = get_q_sequenced(listener);
10479
10480 if (
10481 (avail > 0) &&
10482 (coerce || (avail >= listener->flush_mgr.flush_pt) ||
10483 (avail && talker->s_mgr.state == TCP_STATE_FIN_WAIT_1))
10484 ) {
10485 uint32_t dir = GetForwardDir(p);
10486
10487 if ( talker->s_mgr.state == TCP_STATE_FIN_WAIT_1 )
10488 listener->flags |= TF_FORCE_FLUSH;
10489
10490 flushed = flush_to_seq(
10491 tcpssn, listener, avail, p,
10492 GET_SRC_IP(p), GET_DST_IP(p),
10493 p->tcph->th_sport, p->tcph->th_dport, dir);
10494 }
10495 }
10496 }
10497 #endif
10498 }
10499 break;
10500
10501 case STREAM_FLPOLICY_FOOTPRINT_IPS:
10502 {
10503 int coerce;
10504 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10505 "STREAM_FLPOLICY_FOOTPRINT-IPS\n"););
10506
10507 avail = get_q_sequenced(listener);
10508 coerce = CheckFlushCoercion(
10509 p, &listener->flush_mgr, listener->tcp_policy->flush_factor);
10510
10511 if (
10512 (avail > 0) &&
10513 (coerce || (avail >= listener->flush_mgr.flush_pt) ||
10514 (avail && talker->s_mgr.state == TCP_STATE_FIN_WAIT_1))
10515 ) {
10516 uint32_t dir = GetForwardDir(p);
10517
10518 if ( talker->s_mgr.state == TCP_STATE_FIN_WAIT_1 )
10519 listener->flags |= TF_FORCE_FLUSH;
10520
10521 flushed = flush_to_seq(
10522 tcpssn, listener, avail, p,
10523 GET_SRC_IP(p), GET_DST_IP(p),
10524 p->tcph->th_sport, p->tcph->th_dport, dir);
10525 }
10526 }
10527 break;
10528
10529 case STREAM_FLPOLICY_FOOTPRINT_NOACK:
10530 {
10531 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10532 "STREAM_FLPOLICY_FOOTPRINT-NOACK\n"););
10533
10534 avail = get_q_sequenced(listener);
10535 CheckFlushCoercion(
10536 p, &listener->flush_mgr, listener->tcp_policy->flush_factor);
10537
10538 if ( avail > 0)
10539 {
10540 uint32_t dir = GetForwardDir(p);
10541
10542 if ( talker->s_mgr.state == TCP_STATE_FIN_WAIT_1 )
10543 listener->flags |= TF_FORCE_FLUSH;
10544
10545 flushed = flush_to_seq_noack(
10546 tcpssn, listener, avail, p,
10547 GET_SRC_IP(p), GET_DST_IP(p),
10548 p->tcph->th_sport, p->tcph->th_dport, dir);
10549 }
10550 }
10551 break;
10552
10553 case STREAM_FLPOLICY_PROTOCOL_IPS:
10554 case STREAM_FLPOLICY_PROTOCOL_NOACK:
10555 {
10556 uint64_t flags = GetForwardDir(p);
10557 uint32_t flush_amt = flush_pdu_ips( config, tcpssn, listener, p, &flags);
10558 uint32_t this_flush;
10559
10560 if (flush_amt == 0 && (flags & PKT_PURGE))
10561 {
10562 listener->seglist_next->buffered = SL_BUF_FLUSHED;
10563 break;
10564 }
10565 while ( flush_amt > 0 )
10566 {
10567 if( flags & PKT_IGNORE )
10568 {
10569 StreamSegment *curseg = listener->seglist_next;
10570 uint32_t size_to_flush = 0;
10571 //set these ignored segments to FLUSHED
10572 //so that these gets purged on ack
10573 while ( curseg )
10574 {
10575 if( !curseg->buffered )
10576 {
10577 size_to_flush += curseg->size;
10578 if( size_to_flush == flush_amt )
10579 {
10580 curseg->buffered = SL_BUF_FLUSHED;
10581 break;
10582 }
10583 else if( size_to_flush > flush_amt )
10584 {
10585 unsigned int bytes_to_copy = curseg->size - ( size_to_flush - flush_amt);
10586 StreamSegment *newseg = NULL;
10587
10588 if ( DupStreamNode(NULL, listener, curseg, &newseg) == STREAM_INSERT_OK )
10589 {
10590 curseg->size = bytes_to_copy;
10591 newseg->seq += bytes_to_copy;
10592 newseg->size -= bytes_to_copy;
10593 newseg->payload += bytes_to_copy + (curseg->payload - curseg->data);
10594 curseg->buffered = SL_BUF_FLUSHED;
10595 }
10596 break;
10597 }
10598 curseg->buffered = SL_BUF_FLUSHED;
10599 }
10600 curseg = curseg->next;
10601 }
10602
10603 this_flush = flush_amt;
10604 flags &= ~PKT_IGNORE;
10605 }
10606 // if this payload is exactly one pdu, don't
10607 // actually flush, just use the raw packet
10608
10609 /*
10610 * For pseudo flush case, fall back to the regular
10611 * flush routine which takes care of handling
10612 * pseudo flush case.
10613 */
10614 else if (!(p->packet_flags & PKT_PSEUDO_FLUSH) &&
10615 listener->seglist_next &&
10616 (tdb->seq == listener->seglist_next->seq) &&
10617 (flush_amt == listener->seglist_next->size) &&
10618 (flush_amt == p->dsize) )
10619 {
10620 this_flush = flush_amt;
10621 if(!listener->paf_state.fpt_eoh){
10622 listener->seglist_next->buffered = SL_BUF_FLUSHED;
10623 listener->flush_count++;
10624 }
10625 p->packet_flags |= flags & PKT_PDU_FULL;
10626 /* Raw packet with only and complete http-post header is set with PKT_EVAL_DROP,
10627 * it will be used to evalute drop/allow packet by preprocs
10628 */
10629 if (listener->paf_state.fpt_eoh)
10630 {
10631 p->packet_flags |= PKT_EVAL_DROP;
10632 }
10633 ShowRebuiltPacket(p);
10634 }
10635 else
10636 {
10637 this_flush = flush_to_seq(
10638 tcpssn, listener, flush_amt, p,
10639 GET_SRC_IP(p), GET_DST_IP(p),
10640 p->tcph->th_sport, p->tcph->th_dport, flags);
10641 }
10642 // if we didn't flush as expected, bail
10643 // (we can flush less than max dsize)
10644 if ( !this_flush )
10645 break;
10646
10647 if(listener->paf_state.fpt_eoh)
10648 {
10649 listener->paf_state.fpt_eoh = 0;
10650 tcpssn->pp_flags &= ~(PP_HTTPINSPECT_PAF_FLUSH_POST_HDR);
10651 }
10652 else
10653 flushed += this_flush;
10654 flags = GetForwardDir(p);
10655 flush_amt = flush_pdu_ips( config, tcpssn, listener, p, &flags);
10656 }
10657 if ( !flags )
10658 {
10659 if ( AutoDisable(listener, talker) )
10660 return 0;
10661
10662 if ( listener->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL_NOACK )
10663 listener->flush_mgr.flush_policy = STREAM_FLPOLICY_FOOTPRINT_NOACK;
10664 else
10665 listener->flush_mgr.flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS;
10666 listener->flush_mgr.flush_pt += ScPafMax();
10667 listener->flush_mgr.flush_type = STREAM_FT_PAF_MAX;
10668
10669 return CheckFlushPolicyOnData( config, tcpssn, talker, listener, tdb, p);
10670 }
10671 }
10672 break;
10673 }
10674 listener->paf_state.fpt_eoh = 0;
10675 tcpssn->pp_flags &= ~(PP_HTTPINSPECT_PAF_FLUSH_POST_HDR);
10676 return flushed;
10677 }
10678 #endif
10679
10680 // iterate over seglist and scan all new acked bytes
10681 // - new means not yet scanned
10682 // - must use seglist data (not packet) since this packet may plug a
10683 // hole and enable paf scanning of following segments
10684 // - if we reach a flush point
10685 // - return bytes to flush if data available (must be acked)
10686 // - return zero if not yet received or received but not acked
10687 // - if we reach a skip point
10688 // - jump ahead and resume scanning any available data
10689 // - must stop if we reach a gap
10690 // - one segment may lead to multiple checks since
10691 // it may contain multiple encapsulated PDUs
10692 // - if we partially scan a segment we must save state so we
10693 // know where we left off and can resume scanning the remainder
10694
flush_pdu_ackd(StreamTcpConfig * config,TcpSession * ssn,StreamTracker * trk,Packet * pkt,uint64_t * flags)10695 static inline uint32_t flush_pdu_ackd ( StreamTcpConfig *config, TcpSession* ssn,
10696 StreamTracker* trk, Packet* pkt, uint64_t* flags)
10697 {
10698 bool to_srv = ( *flags == PKT_FROM_CLIENT );
10699 uint16_t srv_port = ( to_srv ? pkt->sp : pkt->dp );
10700 uint32_t total = 0;
10701 StreamSegment* seg;
10702 PROFILE_VARS;
10703
10704 PREPROC_PROFILE_START(s5TcpPAFPerfStats);
10705 seg = SEQ_LT(trk->seglist_base_seq, trk->r_win_base) ? trk->seglist : NULL;
10706
10707 // * must stop if not acked
10708 // * must use adjusted size of seg if not fully acked
10709 // * must stop if gap (checked in s5_paf_check)
10710 while ( seg && *flags && SEQ_LT(seg->seq, trk->r_win_base) )
10711 {
10712 uint32_t flush_pt;
10713 uint32_t size = seg->size;
10714 uint32_t end = seg->seq + seg->size;
10715 uint32_t pos = s5_paf_position(&trk->paf_state);
10716
10717 if ( s5_paf_initialized(&trk->paf_state) && SEQ_LEQ(end, pos) )
10718 {
10719 total += size;
10720 seg = seg->next;
10721 continue;
10722 }
10723 if ( SEQ_GT(end, trk->r_win_base) )
10724 size = trk->r_win_base - seg->seq;
10725
10726 total += size;
10727
10728 wire_packet = pkt;
10729 flush_policy_for_dir = trk->flush_mgr.flush_policy;
10730 flush_pt = s5_paf_check( config->paf_config, &trk->paf_state, ssn->scb,
10731 seg->payload, size, total, seg->seq, srv_port,
10732 flags, trk->flush_mgr.flush_pt);
10733
10734 if (*flags & PKT_PURGE)
10735 {
10736 //For HTTP 2.0 case where stream doesnt flush the data
10737 //Set the seglist value to SL_BUF_FLUSHED
10738 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10739 "Flag PKT_PURGE is set"););
10740 seg->buffered = SL_BUF_FLUSHED;
10741 return 0;
10742 }
10743 if ( flush_pt > 0 )
10744 {
10745 PREPROC_PROFILE_END(s5TcpPAFPerfStats);
10746 return flush_pt;
10747 }
10748 seg = seg->next;
10749 }
10750
10751 PREPROC_PROFILE_END(s5TcpPAFPerfStats);
10752 return 0;
10753 }
10754
CheckFlushPolicyOnAck(StreamTcpConfig * config,TcpSession * tcpssn,StreamTracker * talker,StreamTracker * listener,TcpDataBlock * tdb,Packet * p)10755 static int CheckFlushPolicyOnAck( StreamTcpConfig *config, TcpSession *tcpssn,
10756 StreamTracker *talker, StreamTracker *listener,
10757 TcpDataBlock *tdb, Packet *p)
10758 {
10759 uint32_t flushed = 0;
10760
10761 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10762 "In CheckFlushPolicyOnAck\n"););
10763 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10764 "Talker flush policy: %s\n",
10765 flush_policy_names[talker->flush_mgr.flush_policy]););
10766 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10767 "Listener flush policy: %s\n",
10768 flush_policy_names[listener->flush_mgr.flush_policy]););
10769
10770 switch(talker->flush_mgr.flush_policy)
10771 {
10772 case STREAM_FLPOLICY_IGNORE:
10773 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10774 "STREAM_FLPOLICY_IGNORE\n"););
10775 return 0;
10776
10777 case STREAM_FLPOLICY_FOOTPRINT:
10778 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10779 "STREAM_FLPOLICY_FOOTPRINT\n"););
10780 {
10781 if(get_q_footprint(talker) >= talker->flush_mgr.flush_pt)
10782 {
10783 uint32_t dir = GetReverseDir(p);
10784
10785 flushed = flush_ackd(tcpssn, talker, p,
10786 GET_DST_IP(p), GET_SRC_IP(p),
10787 p->tcph->th_dport, p->tcph->th_sport, dir);
10788
10789 if(flushed)
10790 purge_flushed_ackd(tcpssn, talker);
10791 }
10792 }
10793 break;
10794
10795 case STREAM_FLPOLICY_LOGICAL:
10796 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10797 "STREAM_FLPOLICY_LOGICAL\n"););
10798 if(talker->seg_bytes_logical > talker->flush_mgr.flush_pt)
10799 {
10800 uint32_t dir = GetReverseDir(p);
10801
10802 flushed = flush_ackd(tcpssn, talker, p,
10803 GET_DST_IP(p), GET_SRC_IP(p),
10804 p->tcph->th_dport, p->tcph->th_sport, dir);
10805
10806 if(flushed)
10807 purge_flushed_ackd(tcpssn, talker);
10808 }
10809 break;
10810
10811 case STREAM_FLPOLICY_RESPONSE:
10812 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10813 "Running FLPOLICY_RESPONSE\n"););
10814 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10815 "checking l.r_win_base (0x%X) > "
10816 "t.seglist_base_seq (0x%X)\n",
10817 talker->r_win_base, talker->seglist_base_seq););
10818
10819 if(SEQ_GT(talker->r_win_base, talker->seglist_base_seq) &&
10820 IsWellFormed(p, talker))
10821 {
10822 uint32_t dir = GetReverseDir(p);
10823
10824 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10825 "flushing talker, t->sbl: %d\n",
10826 talker->seg_bytes_logical););
10827 //PrintStreamTracker(talker);
10828 //PrintStreamTracker(talker);
10829
10830 flushed = flush_ackd(tcpssn, talker, p,
10831 GET_DST_IP(p), GET_SRC_IP(p),
10832 p->tcph->th_dport, p->tcph->th_sport, dir);
10833
10834 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10835 "bye bye data...\n"););
10836
10837 if(flushed)
10838 purge_flushed_ackd(tcpssn, talker);
10839 }
10840 break;
10841
10842 case STREAM_FLPOLICY_SLIDING_WINDOW:
10843 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10844 "STREAM_FLPOLICY_SLIDING_WINDOW\n"););
10845 if(get_q_footprint(talker) >= talker->flush_mgr.flush_pt)
10846 {
10847 uint32_t dir = GetReverseDir(p);
10848
10849 flushed = flush_ackd(tcpssn, talker, p,
10850 GET_DST_IP(p), GET_SRC_IP(p),
10851 p->tcph->th_dport, p->tcph->th_sport, dir);
10852
10853 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10854 "Deleting head node for sliding window...\n"););
10855
10856 /* Base sequence for next window'd flush is the end
10857 * of the first packet. */
10858 talker->seglist_base_seq = talker->seglist->seq + talker->seglist->size;
10859 StreamSeglistDeleteNode(talker, talker->seglist);
10860
10861 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10862 "setting talker->seglist_base_seq to 0x%X\n",
10863 talker->seglist->seq););
10864
10865 }
10866 break;
10867
10868 #if 0
10869 case STREAM_FLPOLICY_CONSUMED:
10870 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10871 "STREAM_FLPOLICY_CONSUMED\n"););
10872 if(get_q_footprint(talker) >= talker->flush_mgr.flush_pt)
10873 {
10874 uint32_t dir = GetReverseDir(p);
10875
10876 flushed = flush_ackd(tcpssn, talker, p,
10877 p->iph->ip_dst.s_addr, p->iph->ip_src.s_addr,
10878 p->tcph->th_dport, p->tcph->th_sport, dir);
10879
10880 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10881 "Deleting head node for sliding window...\n"););
10882
10883 talker->seglist_base_seq = talker->seglist->seq + talker->seglist->size;
10884 /* TODO: Delete up to the consumed bytes */
10885 StreamSeglistDeleteNode(talker, talker->seglist);
10886
10887 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
10888 "setting talker->seglist_base_seq to 0x%X\n",
10889 talker->seglist->seq););
10890
10891 }
10892 break;
10893 #endif
10894 case STREAM_FLPOLICY_PROTOCOL:
10895 {
10896 uint64_t flags = GetReverseDir(p);
10897 uint32_t flush_amt = flush_pdu_ackd( config, tcpssn, talker, p, &flags);
10898
10899 while (flush_amt == 0 && (flags & PKT_PURGE))
10900 {
10901 purge_flushed_ackd(tcpssn, talker);
10902 // Need to take care of other acked segments
10903 flags = GetReverseDir(p);
10904 flush_amt = flush_pdu_ackd( config, tcpssn, talker, p, &flags);
10905 }
10906
10907
10908 while ( flush_amt > 0 )
10909 {
10910 if( flags & PKT_IGNORE )
10911 {
10912 flushed = flush_amt;
10913 flags &= ~PKT_IGNORE;
10914 }
10915 else if(talker->paf_state.fpt_eoh)
10916 {
10917 talker->paf_state.fpt_eoh = 0;
10918 tcpssn->pp_flags &= ~(PP_HTTPINSPECT_PAF_FLUSH_POST_HDR);
10919 flags = GetReverseDir(p);
10920 flush_amt = flush_pdu_ackd( config, tcpssn, talker, p, &flags);
10921 continue;
10922 }
10923 else
10924 {
10925 talker->seglist_next = talker->seglist;
10926 talker->seglist_base_seq = talker->seglist->seq;
10927
10928 // for consistency with other cases, should return total
10929 // but that breaks flushing pipelined pdus
10930 flushed = flush_to_seq(
10931 tcpssn, talker, flush_amt, p,
10932 GET_DST_IP(p), GET_SRC_IP(p),
10933 p->tcph->th_dport, p->tcph->th_sport, flags);
10934 }
10935
10936 // ideally we would purge just once after this loop
10937 // but that throws off base
10938 purge_to_seq(tcpssn, talker, talker->seglist->seq + flushed);
10939
10940 // if we didn't flush as expected, bail
10941 // (we can flush less than max dsize)
10942 if ( !flushed )
10943 break;
10944
10945 flags = GetReverseDir(p);
10946 flush_amt = flush_pdu_ackd( config, tcpssn, talker, p, &flags);
10947 }
10948 if ( !flags )
10949 {
10950 if ( AutoDisable(talker, listener) )
10951 return 0;
10952
10953 talker->flush_mgr.flush_policy = STREAM_FLPOLICY_FOOTPRINT;
10954 talker->flush_mgr.flush_pt += ScPafMax();
10955 talker->flush_mgr.flush_type = STREAM_FT_PAF_MAX;
10956
10957 return CheckFlushPolicyOnAck( config, tcpssn, talker, listener, tdb, p );
10958 }
10959 }
10960 break;
10961
10962 #ifdef NORMALIZER
10963 case STREAM_FLPOLICY_FOOTPRINT_IPS:
10964 case STREAM_FLPOLICY_FOOTPRINT_IPS_FTP:
10965 case STREAM_FLPOLICY_PROTOCOL_IPS:
10966 purge_flushed_ackd(tcpssn, talker);
10967 break;
10968 #endif
10969 case STREAM_FLPOLICY_FOOTPRINT_NOACK:
10970 case STREAM_FLPOLICY_PROTOCOL_NOACK:
10971 purge_flushed_ackd(tcpssn, talker);
10972 break;
10973 }
10974
10975 return flushed;
10976 }
10977
StreamSeglistAddNode(StreamTracker * st,StreamSegment * prev,StreamSegment * new)10978 static void StreamSeglistAddNode(StreamTracker *st, StreamSegment *prev,
10979 StreamSegment *new)
10980 {
10981 s5stats.tcp_streamsegs_created++;
10982 if(prev)
10983 {
10984 new->next = prev->next;
10985 new->prev = prev;
10986 prev->next = new;
10987 if (new->next)
10988 new->next->prev = new;
10989 else
10990 st->seglist_tail = new;
10991 }
10992 else
10993 {
10994 new->next = st->seglist;
10995 if(new->next)
10996 new->next->prev = new;
10997 else
10998 st->seglist_tail = new;
10999 st->seglist = new;
11000 }
11001 st->seg_count++;
11002 //Calculate r_nxt_ack by walking the seglist to reach first hole or right end
11003 if(SEQ_LEQ(new->seq, st->r_nxt_ack))
11004 {
11005 while ( new->next && (new->next->seq == new->seq + new->size) )
11006 {
11007 new = new->next;
11008 }
11009 if(SEQ_LT(st->r_nxt_ack, new->seq + new->size))
11010 st->r_nxt_ack = new->seq + new->size;
11011 }
11012 #ifdef DEBUG
11013 new->ordinal = st->segment_ordinal++;
11014 if (new->next && (new->next->seq == new->seq))
11015 {
11016 LogMessage("Same seq to right, check me\n");
11017 }
11018 #endif
11019 }
11020
StreamSeglistDeleteNode(StreamTracker * st,StreamSegment * seg)11021 static int StreamSeglistDeleteNode (StreamTracker* st, StreamSegment* seg)
11022 {
11023 int ret;
11024
11025 assert(st && seg);
11026
11027 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
11028 "Dropping segment at seq %X, len %d\n",
11029 seg->seq, seg->size););
11030
11031 if(seg->prev)
11032 seg->prev->next = seg->next;
11033 else
11034 st->seglist = seg->next;
11035
11036 if(seg->next)
11037 seg->next->prev = seg->prev;
11038 else
11039 st->seglist_tail = seg->prev;
11040
11041 st->seg_bytes_logical -= seg->size;
11042 st->seg_bytes_total -= seg->caplen;
11043
11044 ret = seg->caplen;
11045
11046 if (seg->buffered)
11047 {
11048 s5stats.tcp_rebuilt_seqs_used++;
11049 st->flush_count--;
11050 }
11051
11052 if ( st->seglist_next == seg )
11053 st->seglist_next = NULL;
11054
11055 SegmentFree(seg);
11056 st->seg_count--;
11057
11058 return ret;
11059 }
11060
StreamSeglistDeleteNodeTrim(StreamTracker * st,StreamSegment * seg,uint32_t flush_seq)11061 static int StreamSeglistDeleteNodeTrim (
11062 StreamTracker* st, StreamSegment* seg, uint32_t flush_seq)
11063 {
11064 assert(st && seg);
11065
11066 /*urgent data is never sent flushed to preprocessors, hence avoid trimming segment having urg_offset >=1*/
11067 if( (seg->seq + seg->size - seg->urg_offset) > flush_seq )
11068 {
11069 /* If PAF is applicable and paf_state is set, we need to trim the segment when
11070 * we receive ACK for data less than the segment size.
11071 */
11072 if( s5_paf_active(&st->paf_state) )
11073 {
11074 uint32_t delta = flush_seq - seg->seq;
11075
11076 if ( delta < seg->size )
11077 {
11078 STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
11079 "Left-Trimming segment at seq %X, len %d, delta %u\n",
11080 seg->seq, seg->size, delta););
11081
11082 seg->seq = flush_seq;
11083 seg->size -= (uint16_t)delta;
11084 seg->payload += delta;
11085 st->seg_bytes_logical -= delta;
11086 return 0;
11087 }
11088 }
11089 /* If PAF is not applicable return without trim and delete when ACK is received for data
11090 * less than segment size.
11091 */
11092 else
11093 {
11094 /* If paf_state is PAF_ABORT and we receive ACK for bytes less than the segment size,
11095 * do not trim and do not delete from queue till we recive the ACK for remaining bytes.
11096 * example - FTP Data Session is always in default state which is PAF_ABORT, because PAF
11097 * is not applicable for FTP DATA, in this case if we receive ACK for data less than the
11098 * segment size, we should not trim OR delete this node till we get the ACK for complete
11099 * segment. */
11100 return 0;
11101 }
11102 }
11103 return StreamSeglistDeleteNode(st, seg);
11104 }
11105
TcpUpdateDirection(SessionControlBlock * ssn,char dir,sfaddr_t * ip,uint16_t port)11106 void TcpUpdateDirection(SessionControlBlock *ssn, char dir,
11107 sfaddr_t* ip, uint16_t port)
11108 {
11109 TcpSession *tcpssn = (TcpSession *)ssn->proto_specific_data->data;
11110 sfaddr_t tmpIp;
11111 uint16_t tmpPort;
11112 StreamTracker tmpTracker;
11113
11114 if (IP_EQUALITY(&tcpssn->tcp_client_ip, ip) && (tcpssn->tcp_client_port == port))
11115 {
11116 if ((dir == SSN_DIR_FROM_CLIENT) && (ssn->ha_state.direction == SSN_DIR_FROM_CLIENT))
11117 {
11118 /* Direction already set as client */
11119 return;
11120 }
11121 }
11122 else if (IP_EQUALITY(&tcpssn->tcp_server_ip, ip) && (tcpssn->tcp_server_port == port))
11123 {
11124 if ((dir == SSN_DIR_FROM_SERVER) && (ssn->ha_state.direction == SSN_DIR_FROM_SERVER))
11125 {
11126 /* Direction already set as server */
11127 return;
11128 }
11129 }
11130
11131 /* Swap them -- leave ssn->ha_state.direction the same */
11132
11133 /* XXX: Gotta be a more efficient way to do this without the memcpy */
11134 tmpIp = tcpssn->tcp_client_ip;
11135 tmpPort = tcpssn->tcp_client_port;
11136 tcpssn->tcp_client_ip = tcpssn->tcp_server_ip;
11137 tcpssn->tcp_client_port = tcpssn->tcp_server_port;
11138 tcpssn->tcp_server_ip = tmpIp;
11139 tcpssn->tcp_server_port = tmpPort;
11140 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
11141 SwapPacketHeaderFoo(tcpssn);
11142 #endif
11143 memcpy(&tmpTracker, &tcpssn->client, sizeof(StreamTracker));
11144 memcpy(&tcpssn->client, &tcpssn->server, sizeof(StreamTracker));
11145 memcpy(&tcpssn->server, &tmpTracker, sizeof(StreamTracker));
11146
11147 }
11148
11149 /* Iterates through the packets that were reassembled for
11150 * logging of tagged packets.
11151 */
GetTcpRebuiltPackets(Packet * p,SessionControlBlock * ssn,PacketIterator callback,void * userdata)11152 int GetTcpRebuiltPackets(Packet *p, SessionControlBlock *ssn, PacketIterator callback, void *userdata)
11153 {
11154 int packets = 0;
11155 TcpSession *tcpssn = NULL;
11156 StreamTracker *st;
11157 StreamSegment *ss;
11158 uint32_t start_seq = ntohl(p->tcph->th_seq);
11159 uint32_t end_seq = start_seq + p->dsize;
11160
11161 if (!ssn || !ssn->proto_specific_data || !ssn->proto_specific_data->data)
11162 {
11163 return packets;
11164 }
11165
11166 tcpssn = (TcpSession *)ssn->proto_specific_data->data;
11167
11168 /* StreamTracker is the opposite of the ip of the reassembled
11169 * packet --> it came out the queue for the other side */
11170 if (IP_EQUALITY(GET_SRC_IP(p), &tcpssn->tcp_client_ip))
11171 {
11172 st = &tcpssn->server;
11173 }
11174 else
11175 {
11176 st = &tcpssn->client;
11177 }
11178
11179 // skip over segments not covered by this reassembled packet
11180 for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next);
11181
11182 // return flushed segments only
11183 // For HTTP Post request End-of-Header Flush, if alert is raised, return the segments even though they are not buffered.
11184 for (; ss && ((ss->buffered == SL_BUF_FLUSHED) || (tcpssn->pp_flags & PP_HTTPINSPECT_PAF_FLUSH_POST_HDR)); ss = ss->next)
11185 {
11186 if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq))
11187 {
11188 DAQ_PktHdr_t pkth;
11189 pkth.ts.tv_sec = ss->tv.tv_sec;
11190 pkth.ts.tv_usec = ss->tv.tv_usec;
11191 pkth.caplen = ss->caplen;
11192 pkth.pktlen = ss->pktlen;
11193
11194 callback(&pkth, ss->pkt, userdata);
11195 packets++;
11196 }
11197 else
11198 break;
11199 }
11200
11201 return packets;
11202 }
11203
11204 /* Iterates through the packets that were reassembled for
11205 * logging of tagged packets.
11206 */
GetTcpStreamSegments(Packet * p,SessionControlBlock * ssn,StreamSegmentIterator callback,void * userdata)11207 int GetTcpStreamSegments(Packet *p, SessionControlBlock *ssn, StreamSegmentIterator callback,
11208 void *userdata)
11209 {
11210 int packets = 0;
11211 TcpSession *tcpssn = NULL;
11212 StreamTracker *st;
11213 StreamSegment *ss;
11214 uint32_t start_seq = ntohl(p->tcph->th_seq);
11215 uint32_t end_seq = start_seq + p->dsize;
11216
11217 if (!ssn || !ssn->proto_specific_data || !ssn->proto_specific_data->data)
11218 return -1;
11219
11220 tcpssn = (TcpSession *)ssn->proto_specific_data->data;
11221
11222 /* StreamTracker is the opposite of the ip of the reassembled
11223 * packet --> it came out the queue for the other side */
11224 if (IP_EQUALITY(GET_SRC_IP(p), &tcpssn->tcp_client_ip))
11225 st = &tcpssn->server;
11226 else
11227 st = &tcpssn->client;
11228
11229 // skip over segments not covered by this reassembled packet
11230 for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next);
11231
11232 // return flushed segments only
11233 // For HTTP Post request End-of-Header Flush, if alert is raised, return the segments even though they are not buffered.
11234 for (; ss && ((ss->buffered == SL_BUF_FLUSHED) || (tcpssn->pp_flags & PP_HTTPINSPECT_PAF_FLUSH_POST_HDR)); ss = ss->next)
11235 {
11236 if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq))
11237 {
11238 DAQ_PktHdr_t pkth;
11239 uint32_t ajust_seq = ss->seq - (uint32_t)(ss->payload - ss->data);
11240 pkth.ts.tv_sec = ss->tv.tv_sec;
11241 pkth.ts.tv_usec = ss->tv.tv_usec;
11242 pkth.caplen = ss->caplen;
11243 pkth.pktlen = ss->pktlen;
11244
11245 if (callback(&pkth, ss->pkt, ss->data, ajust_seq, userdata) != 0)
11246 return -1;
11247
11248 packets++;
11249 }
11250 else
11251 break;
11252 }
11253
11254 return packets;
11255 }
11256
StreamAddSessionAlertTcp(SessionControlBlock * scb,Packet * p,uint32_t gid,uint32_t sid)11257 int StreamAddSessionAlertTcp( SessionControlBlock* scb, Packet* p, uint32_t gid, uint32_t sid)
11258 {
11259 TcpSession *tcpssn = NULL;
11260 StreamTracker *st;
11261 StreamAlertInfo* ai;
11262
11263 if (scb->proto_specific_data)
11264 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11265
11266 if (!tcpssn)
11267 {
11268 return 0;
11269 }
11270
11271 if (IP_EQUALITY(GET_SRC_IP(p),&tcpssn->tcp_client_ip))
11272 {
11273 st = &tcpssn->server;
11274 }
11275 else
11276 {
11277 st = &tcpssn->client;
11278 }
11279
11280 if (st->alert_count >= MAX_SESSION_ALERTS)
11281 return 0;
11282
11283 ai = st->alerts + st->alert_count;
11284 ai->gid = gid;
11285 ai->sid = sid;
11286 ai->seq = GET_PKT_SEQ(p);
11287
11288 if ( p->tcph->th_flags & TH_FIN )
11289 ai->seq--;
11290
11291 st->alert_count++;
11292
11293 return 0;
11294 }
11295
StreamCheckSessionAlertTcp(SessionControlBlock * scb,Packet * p,uint32_t gid,uint32_t sid)11296 int StreamCheckSessionAlertTcp(SessionControlBlock *scb, Packet *p, uint32_t gid, uint32_t sid)
11297 {
11298 TcpSession *tcpssn = NULL;
11299 StreamTracker *st;
11300 int i;
11301 int iRet = 0;
11302
11303 if (scb->proto_specific_data)
11304 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11305
11306 if (!tcpssn)
11307 {
11308 return 0;
11309 }
11310
11311 /* If this is not a rebuilt packet, no need to check further */
11312 if (!(p->packet_flags & PKT_REBUILT_STREAM))
11313 {
11314 return 0;
11315 }
11316
11317 if (IP_EQUALITY(GET_SRC_IP(p), &tcpssn->tcp_client_ip))
11318 {
11319 st = &tcpssn->server;
11320 }
11321 else
11322 {
11323 st = &tcpssn->client;
11324 }
11325
11326 for (i=0;i<st->alert_count;i++)
11327 {
11328 /* This is a rebuilt packet and if we've seen this alert before,
11329 * return that we have previously alerted on original packet.
11330 */
11331 if ( st->alerts[i].gid == gid &&
11332 st->alerts[i].sid == sid )
11333 {
11334 return -1;
11335 }
11336 }
11337
11338 return iRet;
11339 }
11340
StreamUpdateSessionAlertTcp(SessionControlBlock * scb,Packet * p,uint32_t gid,uint32_t sid,uint32_t event_id,uint32_t event_second)11341 int StreamUpdateSessionAlertTcp(SessionControlBlock *scb, Packet *p, uint32_t gid, uint32_t sid,
11342 uint32_t event_id, uint32_t event_second)
11343 {
11344 TcpSession *tcpssn = NULL;
11345 StreamTracker *st;
11346 int i;
11347 uint32_t seq_num;
11348
11349 if (scb->proto_specific_data)
11350 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11351
11352 if (!tcpssn)
11353 {
11354 return 0;
11355 }
11356
11357 if (IP_EQUALITY(GET_SRC_IP(p), &tcpssn->tcp_client_ip))
11358 {
11359 st = &tcpssn->server;
11360 }
11361 else
11362 {
11363 st = &tcpssn->client;
11364 }
11365
11366 seq_num = GET_PKT_SEQ(p);
11367
11368 if ( p->tcph->th_flags & TH_FIN )
11369 seq_num--;
11370
11371 for (i=0;i<st->alert_count;i++)
11372 {
11373 StreamAlertInfo* ai = st->alerts + i;
11374
11375 if ( ai->gid == gid &&
11376 ai->sid == sid && SEQ_EQ(ai->seq, seq_num))
11377 {
11378 ai->event_id = event_id;
11379 ai->event_second = event_second;
11380 return 0;
11381 }
11382 }
11383
11384 return -1;
11385 }
11386
StreamSetExtraDataTcp(SessionControlBlock * scb,Packet * p,uint32_t xid)11387 void StreamSetExtraDataTcp (SessionControlBlock* scb, Packet* p, uint32_t xid)
11388 {
11389 TcpSession *tcpssn = NULL;
11390 StreamTracker *st;
11391
11392 if (scb->proto_specific_data)
11393 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11394
11395 if (!tcpssn)
11396 return;
11397
11398 if (IP_EQUALITY(GET_SRC_IP(p),&tcpssn->tcp_client_ip))
11399 st = &tcpssn->server;
11400 else
11401 st = &tcpssn->client;
11402
11403 st->xtradata_mask |= BIT(xid);
11404 p->xtradata_mask |= BIT(xid);
11405 }
11406
StreamClearExtraDataTcp(SessionControlBlock * scb,Packet * p,uint32_t xid)11407 void StreamClearExtraDataTcp (SessionControlBlock* scb, Packet* p, uint32_t xid)
11408 {
11409 TcpSession *tcpssn = NULL;
11410 StreamTracker *st;
11411
11412 if (scb->proto_specific_data)
11413 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11414
11415 if (!tcpssn)
11416 return;
11417
11418 if (IP_EQUALITY(GET_SRC_IP(p),&tcpssn->tcp_client_ip))
11419 st = &tcpssn->server;
11420 else
11421 st = &tcpssn->client;
11422
11423 if ( xid )
11424 st->xtradata_mask &= ~BIT(xid);
11425 else
11426 st->xtradata_mask = 0;
11427 }
11428
StreamGetReassemblyDirectionTcp(SessionControlBlock * scb)11429 char StreamGetReassemblyDirectionTcp(SessionControlBlock *scb)
11430 {
11431 TcpSession *tcpssn = NULL;
11432 char dir = SSN_DIR_NONE;
11433
11434 if (!scb)
11435 return SSN_DIR_NONE;
11436
11437 if (scb->proto_specific_data)
11438 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11439
11440 if (!tcpssn)
11441 return SSN_DIR_NONE;
11442
11443 if ((tcpssn->server.flush_mgr.flush_policy != STREAM_FLPOLICY_NONE) &&
11444 (tcpssn->server.flush_mgr.flush_policy != STREAM_FLPOLICY_IGNORE))
11445 {
11446 dir |= SSN_DIR_TO_SERVER;
11447 }
11448
11449 if ((tcpssn->client.flush_mgr.flush_policy != STREAM_FLPOLICY_NONE) &&
11450 (tcpssn->client.flush_mgr.flush_policy != STREAM_FLPOLICY_IGNORE))
11451 {
11452 dir |= SSN_DIR_TO_CLIENT;
11453 }
11454
11455 return dir;
11456 }
11457
getWirePacketTcp()11458 Packet* getWirePacketTcp()
11459 {
11460 return wire_packet;
11461 }
11462
getFlushPolicyDirTcp()11463 uint8_t getFlushPolicyDirTcp()
11464 {
11465 if (flush_policy_for_dir == STREAM_FLPOLICY_FOOTPRINT_IPS ||
11466 flush_policy_for_dir == STREAM_FLPOLICY_FOOTPRINT_NOACK ||
11467 flush_policy_for_dir == STREAM_FLPOLICY_PROTOCOL_IPS ||
11468 flush_policy_for_dir == STREAM_FLPOLICY_PROTOCOL_NOACK)
11469 {
11470 return 1;
11471 }
11472 return 0;
11473 }
11474
StreamGetFlushPointTcp(SessionControlBlock * scb,char dir)11475 uint32_t StreamGetFlushPointTcp(SessionControlBlock *scb, char dir)
11476 {
11477 TcpSession *tcpssn = NULL;
11478
11479 if (scb == NULL)
11480 return 0;
11481
11482 if (scb->proto_specific_data != NULL)
11483 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11484
11485 if (tcpssn == NULL)
11486 return 0;
11487
11488 if (dir & SSN_DIR_TO_SERVER)
11489 return tcpssn->server.flush_mgr.flush_pt;
11490 else if (dir & SSN_DIR_TO_CLIENT)
11491 return tcpssn->client.flush_mgr.flush_pt;
11492
11493 return 0;
11494 }
11495
StreamSetFlushPointTcp(SessionControlBlock * scb,char dir,uint32_t flush_point)11496 void StreamSetFlushPointTcp(SessionControlBlock *scb, char dir, uint32_t flush_point)
11497 {
11498 TcpSession *tcpssn = NULL;
11499
11500 if (scb == NULL)
11501 return;
11502
11503 if (scb->proto_specific_data != NULL)
11504 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11505
11506 if (tcpssn == NULL)
11507 return;
11508
11509 if (flush_point == 0)
11510 return;
11511
11512 if (dir & SSN_DIR_TO_SERVER)
11513 {
11514 tcpssn->server.flush_mgr.flush_pt = flush_point;
11515 tcpssn->server.flush_mgr.last_size = 0;
11516 tcpssn->server.flush_mgr.last_count = 0;
11517 tcpssn->server.flush_mgr.flush_type = STREAM_FT_EXTERNAL;
11518 }
11519 else if (dir & SSN_DIR_TO_CLIENT)
11520 {
11521 tcpssn->client.flush_mgr.flush_pt = flush_point;
11522 tcpssn->client.flush_mgr.last_size = 0;
11523 tcpssn->client.flush_mgr.last_count = 0;
11524 tcpssn->client.flush_mgr.flush_type = STREAM_FT_EXTERNAL;
11525 }
11526 }
11527
StreamSetReassemblyTcp(SessionControlBlock * scb,uint8_t flush_policy,char dir,char flags)11528 char StreamSetReassemblyTcp(SessionControlBlock *scb, uint8_t flush_policy, char dir, char flags)
11529 {
11530 TcpSession *tcpssn = NULL;
11531 uint16_t tmp_flags;
11532
11533 if (!scb)
11534 return SSN_DIR_NONE;
11535
11536 if (scb->proto_specific_data)
11537 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11538
11539 if (!tcpssn)
11540 return SSN_DIR_NONE;
11541
11542 tmp_flags = (flush_policy == STREAM_FLPOLICY_IGNORE)? 0: TF_FIRST_PKT_MISSING;
11543 if (flags & STREAM_FLPOLICY_SET_APPEND)
11544 {
11545 if (dir & SSN_DIR_TO_SERVER)
11546 {
11547 if (tcpssn->server.flush_mgr.flush_policy != STREAM_FLPOLICY_NONE)
11548 {
11549 /* Changing policy with APPEND, Bad */
11550 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
11551 "Stream: Changing client flush policy using "
11552 "append is asking for trouble. Ignored\n"););
11553 }
11554 else
11555 {
11556 InitFlushMgr(snort_conf, &tcpssn->server.flush_mgr,
11557 &tcpssn->server.tcp_policy->flush_point_list,
11558 flush_policy, 0);
11559 tcpssn->server.flags |= tmp_flags;
11560 }
11561 }
11562
11563 if (dir & SSN_DIR_TO_CLIENT)
11564 {
11565 if (tcpssn->client.flush_mgr.flush_policy != STREAM_FLPOLICY_NONE)
11566 {
11567 /* Changing policy with APPEND, Bad */
11568 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
11569 "Stream: Changing server flush policy using "
11570 "append is asking for trouble. Ignored\n"););
11571 }
11572 else
11573 {
11574 InitFlushMgr(snort_conf, &tcpssn->client.flush_mgr,
11575 &tcpssn->client.tcp_policy->flush_point_list,
11576 flush_policy, 0);
11577 tcpssn->client.flags |= tmp_flags;
11578 }
11579 }
11580
11581 }
11582 else if (flags & STREAM_FLPOLICY_SET_ABSOLUTE)
11583 {
11584 if (dir & SSN_DIR_TO_SERVER)
11585 {
11586 //If the flush policy is already set to STREAM_FLPOLICY_FOOTPRINT_IPS_FTP, ssl preproc shouldn't reset the flush policy for FTPS.
11587 //Unset the pp_flags because SSL will send decrypted FTP traffic from here on
11588 if((tcpssn->pp_flags & PP_FTPTELNET_FTPS) && (tcpssn->server.flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS_FTP))
11589 {
11590 flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS_FTP;
11591 tcpssn->pp_flags &= ~PP_FTPTELNET_FTPS;
11592 }
11593
11594 InitFlushMgr(snort_conf, &tcpssn->server.flush_mgr,
11595 &tcpssn->server.tcp_policy->flush_point_list,
11596 flush_policy, 0);
11597 tcpssn->server.flags |= tmp_flags;
11598 if(tcpssn->server.flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS)
11599 {
11600 //set_application_data is done for ftp-data connection during TCPSession setup. Change the Flush policy for ftp-data only.
11601 if(session_api->get_application_data(scb, PP_FTPTELNET))
11602 {
11603 tcpssn->server.flush_mgr.flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS_FTP;
11604 tcpssn->server.flush_mgr.last_size = 0;
11605 }
11606 }
11607 }
11608
11609 if (dir & SSN_DIR_TO_CLIENT)
11610 {
11611 //If the flush policy is already set to STREAM_FLPOLICY_FOOTPRINT_IPS_FTP, ssl preproc shouldn't reset the flush policy for FTPS.
11612 //Unset the pp_flags because SSL will send decrypted FTP traffic from here on
11613 if((tcpssn->pp_flags & PP_FTPTELNET_FTPS) && (tcpssn->client.flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS_FTP))
11614 {
11615 flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS_FTP;
11616 tcpssn->pp_flags &= ~PP_FTPTELNET_FTPS;
11617 }
11618
11619 InitFlushMgr(snort_conf, &tcpssn->client.flush_mgr,
11620 &tcpssn->client.tcp_policy->flush_point_list,
11621 flush_policy, 0);
11622 tcpssn->client.flags |= tmp_flags;
11623 if(tcpssn->client.flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS)
11624 {
11625 //set_application_data is done for ftp-data connection during TCPSession setup. Change the Flush policy for ftp-data only.
11626 if(session_api->get_application_data(scb, PP_FTPTELNET))
11627 {
11628 tcpssn->client.flush_mgr.flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS_FTP;
11629 tcpssn->client.flush_mgr.last_size = 0;
11630 }
11631 }
11632 }
11633 }
11634
11635 return StreamGetReassemblyDirectionTcp(scb);
11636 }
11637
StreamGetReassemblyFlushPolicyTcp(SessionControlBlock * scb,char dir)11638 char StreamGetReassemblyFlushPolicyTcp(SessionControlBlock *scb, char dir)
11639 {
11640 TcpSession *tcpssn = NULL;
11641
11642 if (!scb)
11643 return STREAM_FLPOLICY_NONE;
11644
11645 if (scb->proto_specific_data)
11646 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11647
11648 if (!tcpssn)
11649 return STREAM_FLPOLICY_NONE;
11650
11651 if (dir & SSN_DIR_TO_SERVER)
11652 {
11653 return (char)tcpssn->server.flush_mgr.flush_policy;
11654 }
11655
11656 if (dir & SSN_DIR_TO_CLIENT)
11657 {
11658 return (char)tcpssn->client.flush_mgr.flush_policy;
11659 }
11660 return STREAM_FLPOLICY_NONE;
11661 }
11662
StreamIsStreamSequencedTcp(SessionControlBlock * scb,char dir)11663 char StreamIsStreamSequencedTcp(SessionControlBlock *scb, char dir)
11664 {
11665 TcpSession *tcpssn = NULL;
11666
11667 if (!scb)
11668 return 1;
11669
11670 if (scb->proto_specific_data)
11671 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11672
11673 if (!tcpssn)
11674 return 1;
11675
11676 if (dir & SSN_DIR_FROM_CLIENT)
11677 {
11678 if ( tcpssn->server.flags & TF_MISSING_PREV_PKT )
11679 return 0;
11680 }
11681
11682 if (dir & SSN_DIR_FROM_SERVER)
11683 {
11684 if ( tcpssn->client.flags & TF_MISSING_PREV_PKT )
11685 return 0;
11686 }
11687
11688 return 1;
11689 }
11690
11691 /* This will falsly return SSN_MISSING_BEFORE on the first reassembed
11692 * packet if reassembly for this direction was set mid-session */
StreamMissingInReassembledTcp(SessionControlBlock * scb,char dir)11693 int StreamMissingInReassembledTcp(SessionControlBlock *scb, char dir)
11694 {
11695 TcpSession *tcpssn = NULL;
11696
11697 if (!scb)
11698 return SSN_MISSING_NONE;
11699
11700 if (scb->proto_specific_data)
11701 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11702
11703 if (!tcpssn)
11704 return SSN_MISSING_NONE;
11705
11706 if (dir & SSN_DIR_FROM_CLIENT)
11707 {
11708 if (tcpssn->server.flags & TF_MISSING_PREV_PKT)
11709 return SSN_MISSING_BEFORE;
11710 }
11711 else if (dir & SSN_DIR_FROM_SERVER)
11712 {
11713 if (tcpssn->client.flags & TF_MISSING_PREV_PKT)
11714 return SSN_MISSING_BEFORE;
11715 }
11716
11717 return SSN_MISSING_NONE;
11718 }
11719
StreamPacketsMissingTcp(SessionControlBlock * scb,char dir)11720 char StreamPacketsMissingTcp(SessionControlBlock *scb, char dir)
11721 {
11722 TcpSession *tcpssn = NULL;
11723
11724 if (!scb)
11725 return 0;
11726
11727 if (scb->proto_specific_data)
11728 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11729
11730 if (!tcpssn)
11731 return 0;
11732
11733 if (dir & SSN_DIR_FROM_CLIENT)
11734 {
11735 if (tcpssn->server.flags & TF_PKT_MISSED)
11736 return 1;
11737 }
11738
11739 if (dir & SSN_DIR_FROM_SERVER)
11740 {
11741 if (tcpssn->client.flags & TF_PKT_MISSED)
11742 return 1;
11743 }
11744
11745 return 0;
11746 }
11747
11748 #define SSOD_LESS_THAN 1
11749 #define SSOD_GREATER_THAN 2
11750 #define SSOD_EQUALS 3
11751 #define SSOD_LESS_THAN_OR_EQUALS 4
11752 #define SSOD_GREATER_THAN_OR_EQUALS 5
11753 #define SSOD_NOT_EQUALS 6
11754
11755 #define SSOD_MATCH 1
11756 #define SSOD_NOMATCH 0
11757 typedef struct _StreamSizeOptionData
11758 {
11759 char operator;
11760 uint32_t size;
11761 char direction;
11762 } StreamSizeOptionData;
11763
s5TcpStreamSizeInit(struct _SnortConfig * sc,char * name,char * parameters,void ** dataPtr)11764 int s5TcpStreamSizeInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr)
11765 {
11766 char **toks;
11767 int num_toks;
11768 char *endp;
11769 StreamSizeOptionData *ssod = NULL;
11770 toks = mSplit(parameters, ",", 4, &num_toks, 0);
11771
11772 if (num_toks != 3)
11773 {
11774 FatalError("%s(%d): Invalid parameters for %s option\n",
11775 file_name, file_line, name);
11776 }
11777
11778 ssod = SnortPreprocAlloc(1, sizeof(StreamSizeOptionData), PP_STREAM,
11779 PP_MEM_CATEGORY_CONFIG);
11780
11781 if (!ssod)
11782 {
11783 FatalError("%s(%d): Failed to allocate data for %s option\n",
11784 file_name, file_line, name);
11785 }
11786
11787 /* Parse the direction.
11788 * Can be: client, server, both, either
11789 */
11790 if (!strcasecmp(toks[0], "client"))
11791 {
11792 ssod->direction = SSN_DIR_FROM_CLIENT;
11793 }
11794 else if (!strcasecmp(toks[0], "server"))
11795 {
11796 ssod->direction = SSN_DIR_FROM_SERVER;
11797 }
11798 else if (!strcasecmp(toks[0], "both"))
11799 {
11800 ssod->direction = SSN_DIR_BOTH;
11801 }
11802 else if (!strcasecmp(toks[0], "either"))
11803 {
11804 ssod->direction = SSN_DIR_NONE;
11805 }
11806 else
11807 {
11808 FatalError("%s(%d): Invalid direction: %s for option %s\n",
11809 file_name, file_line, toks[0], name);
11810 }
11811
11812 /* Parse the operator.
11813 * Can be: =, <, > , !=, <=, >=
11814 */
11815 if (!strcasecmp(toks[1], "="))
11816 {
11817 ssod->operator = SSOD_EQUALS;
11818 }
11819 else if (!strcasecmp(toks[1], "<"))
11820 {
11821 ssod->operator = SSOD_LESS_THAN;
11822 }
11823 else if (!strcasecmp(toks[1], ">"))
11824 {
11825 ssod->operator = SSOD_GREATER_THAN;
11826 }
11827 else if (!strcasecmp(toks[1], "!="))
11828 {
11829 ssod->operator = SSOD_NOT_EQUALS;
11830 }
11831 else if (!strcasecmp(toks[1], "<="))
11832 {
11833 ssod->operator = SSOD_LESS_THAN_OR_EQUALS;
11834 }
11835 else if (!strcasecmp(toks[1], ">="))
11836 {
11837 ssod->operator = SSOD_GREATER_THAN_OR_EQUALS;
11838 }
11839 else
11840 {
11841 FatalError("%s(%d): Invalid operator: %s for option %s\n",
11842 file_name, file_line, toks[1], name);
11843 }
11844
11845 ssod->size = SnortStrtoul(toks[2], &endp, 0);
11846 if ((endp == toks[2]) || (errno == ERANGE))
11847 {
11848 FatalError("%s(%d): Invalid size: %s for option %s\n",
11849 file_name, file_line, toks[2], name);
11850 }
11851
11852 *dataPtr = ssod;
11853 mSplitFree(&toks, num_toks);
11854
11855 return 1;
11856 }
11857
s5TcpStreamSizeCompare(uint32_t size1,uint32_t size2,char operator)11858 static inline int s5TcpStreamSizeCompare(uint32_t size1, uint32_t size2, char operator)
11859 {
11860 int retval = 0;
11861 switch (operator)
11862 {
11863 case SSOD_EQUALS:
11864 if (size1 == size2)
11865 retval = 1;
11866 break;
11867 case SSOD_LESS_THAN:
11868 if (size1 < size2)
11869 retval = 1;
11870 break;
11871 case SSOD_GREATER_THAN:
11872 if (size1 > size2)
11873 retval = 1;
11874 break;
11875 case SSOD_NOT_EQUALS:
11876 if (size1 != size2)
11877 retval = 1;
11878 break;
11879 case SSOD_LESS_THAN_OR_EQUALS:
11880 if (size1 <= size2)
11881 retval = 1;
11882 break;
11883 case SSOD_GREATER_THAN_OR_EQUALS:
11884 if (size1 >= size2)
11885 retval = 1;
11886 break;
11887 default:
11888 break;
11889 }
11890 return retval;
11891 }
11892
s5TcpStreamSizeEval(void * p,const uint8_t ** cursor,void * dataPtr)11893 int s5TcpStreamSizeEval(void *p, const uint8_t **cursor, void *dataPtr)
11894 {
11895 Packet *pkt = p;
11896 SessionControlBlock *scb = NULL;
11897 TcpSession *tcpssn = NULL;
11898 StreamSizeOptionData *ssod = (StreamSizeOptionData *)dataPtr;
11899 uint32_t client_size;
11900 uint32_t server_size;
11901 PROFILE_VARS;
11902
11903 if (!pkt || !pkt->ssnptr || !ssod || !pkt->tcph)
11904 return DETECTION_OPTION_NO_MATCH;
11905
11906 scb = pkt->ssnptr;
11907 if (!scb->proto_specific_data)
11908 return DETECTION_OPTION_NO_MATCH;
11909
11910 PREPROC_PROFILE_START(streamSizePerfStats);
11911
11912 tcpssn = (TcpSession *)scb->proto_specific_data->data;
11913
11914 if (tcpssn->client.l_nxt_seq > tcpssn->client.isn)
11915 {
11916 /* the normal case... */
11917 client_size = tcpssn->client.l_nxt_seq - tcpssn->client.isn;
11918 }
11919 else
11920 {
11921 /* the seq num wrapping case... */
11922 client_size = tcpssn->client.isn - tcpssn->client.l_nxt_seq;
11923 }
11924 if (tcpssn->server.l_nxt_seq > tcpssn->server.isn)
11925 {
11926 /* the normal case... */
11927 server_size = tcpssn->server.l_nxt_seq - tcpssn->server.isn;
11928 }
11929 else
11930 {
11931 /* the seq num wrapping case... */
11932 server_size = tcpssn->server.isn - tcpssn->server.l_nxt_seq;
11933 }
11934
11935 switch (ssod->direction)
11936 {
11937 case SSN_DIR_FROM_CLIENT:
11938 if (s5TcpStreamSizeCompare(client_size, ssod->size, ssod->operator)
11939 == SSOD_MATCH)
11940 {
11941 PREPROC_PROFILE_END(streamSizePerfStats);
11942 return DETECTION_OPTION_MATCH;
11943 }
11944 break;
11945 case SSN_DIR_FROM_SERVER:
11946 if (s5TcpStreamSizeCompare(server_size, ssod->size, ssod->operator)
11947 == SSOD_MATCH)
11948 {
11949 PREPROC_PROFILE_END(streamSizePerfStats);
11950 return DETECTION_OPTION_MATCH;
11951 }
11952 break;
11953 case SSN_DIR_NONE: /* overloaded. really, its an 'either' */
11954 if ((s5TcpStreamSizeCompare(client_size, ssod->size, ssod->operator)
11955 == SSOD_MATCH) ||
11956 (s5TcpStreamSizeCompare(server_size, ssod->size, ssod->operator)
11957 == SSOD_MATCH))
11958 {
11959 PREPROC_PROFILE_END(streamSizePerfStats);
11960 return DETECTION_OPTION_MATCH;
11961 }
11962 break;
11963 case SSN_DIR_BOTH:
11964 if ((s5TcpStreamSizeCompare(client_size, ssod->size, ssod->operator)
11965 == SSOD_MATCH) &&
11966 (s5TcpStreamSizeCompare(server_size, ssod->size, ssod->operator)
11967 == SSOD_MATCH))
11968 {
11969 PREPROC_PROFILE_END(streamSizePerfStats);
11970 return DETECTION_OPTION_MATCH;
11971 }
11972 break;
11973 default:
11974 break;
11975 }
11976 PREPROC_PROFILE_END(streamSizePerfStats);
11977 return DETECTION_OPTION_NO_MATCH;
11978 }
11979
s5TcpStreamSizeCleanup(void * dataPtr)11980 void s5TcpStreamSizeCleanup(void *dataPtr)
11981 {
11982 StreamSizeOptionData *ssod = dataPtr;
11983 if (ssod)
11984 {
11985 SnortPreprocFree(ssod, sizeof(StreamSizeOptionData), PP_STREAM,
11986 PP_MEM_CATEGORY_CONFIG);
11987 }
11988 }
11989
11990 typedef struct _StreamReassembleRuleOptionData
11991 {
11992 char enable;
11993 char alert;
11994 char direction;
11995 char fastpath;
11996 } StreamReassembleRuleOptionData;
11997
s5TcpStreamReassembleRuleOptionInit(struct _SnortConfig * sc,char * name,char * parameters,void ** dataPtr)11998 int s5TcpStreamReassembleRuleOptionInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr)
11999 {
12000 char **toks;
12001 int num_toks;
12002 StreamReassembleRuleOptionData *srod = NULL;
12003 toks = mSplit(parameters, ",", 4, &num_toks, 0);
12004
12005 if (num_toks < 2)
12006 {
12007 FatalError("%s(%d): Invalid parameters for %s option\n",
12008 file_name, file_line, name);
12009 }
12010
12011 srod = SnortPreprocAlloc(1, sizeof(StreamReassembleRuleOptionData), PP_STREAM,
12012 PP_MEM_CATEGORY_CONFIG);
12013
12014 if (!srod)
12015 {
12016 FatalError("%s(%d): Failed to allocate data for %s option\n",
12017 file_name, file_line, name);
12018 }
12019
12020 /* Parse the action.
12021 * Can be: enable or disable
12022 */
12023 if (!strcasecmp(toks[0], "enable"))
12024 {
12025 srod->enable = 1;
12026 }
12027 else if (!strcasecmp(toks[0], "disable"))
12028 {
12029 srod->enable = 0;
12030 }
12031 else
12032 {
12033 FatalError("%s(%d): Invalid action: %s for option %s. Valid "
12034 "parameters are 'enable' or 'disable'\n",
12035 file_name, file_line, toks[0], name);
12036 }
12037
12038 /* Parse the direction.
12039 * Can be: client, server, both
12040 */
12041 /* Need to these around, so they match the ones specified via the stream5_tcp ports
12042 * option, ie, stream5_tcp: ports client enables reassembly on client-sourced traffic. */
12043 if (!strcasecmp(toks[1], "client"))
12044 {
12045 srod->direction = SSN_DIR_FROM_SERVER;
12046 }
12047 else if (!strcasecmp(toks[1], "server"))
12048 {
12049 srod->direction = SSN_DIR_FROM_CLIENT;
12050 }
12051 else if (!strcasecmp(toks[1], "both"))
12052 {
12053 srod->direction = SSN_DIR_BOTH;
12054 }
12055 else
12056 {
12057 FatalError("%s(%d): Invalid direction: %s for option %s\n",
12058 file_name, file_line, toks[1], name);
12059 }
12060
12061 /* Parse the optional parameters:
12062 * noalert flag, fastpath flag
12063 */
12064 srod->alert = 1;
12065 if (num_toks > 2)
12066 {
12067 int i = 2;
12068 for (; i< num_toks; i++)
12069 {
12070 if (!strcasecmp(toks[i], "noalert"))
12071 {
12072 srod->alert = 0;
12073 }
12074 else if (!strcasecmp(toks[i], "fastpath"))
12075 {
12076 srod->fastpath = 1;
12077 if (srod->enable)
12078 {
12079 FatalError("%s(%d): Using 'fastpath' with 'enable' is "
12080 "not valid for %s\n", file_name, file_line, name);
12081 }
12082 }
12083 else
12084 {
12085 FatalError("%s(%d): Invalid optional parameter: %s for option %s\n",
12086 file_name, file_line, toks[i], name);
12087 }
12088 }
12089 }
12090
12091 *dataPtr = srod;
12092 mSplitFree(&toks, num_toks);
12093
12094 return 1;
12095 }
12096
s5TcpStreamReassembleRuleOptionEval(void * p,const uint8_t ** cursor,void * dataPtr)12097 int s5TcpStreamReassembleRuleOptionEval(void *p, const uint8_t **cursor, void *dataPtr)
12098 {
12099 Packet *pkt = p;
12100 SessionControlBlock *scb = NULL;
12101 StreamReassembleRuleOptionData *srod = (StreamReassembleRuleOptionData *)dataPtr;
12102 PROFILE_VARS;
12103
12104 if (!pkt || !pkt->ssnptr || !srod || !pkt->tcph)
12105 return 0;
12106
12107 PREPROC_PROFILE_START(streamReassembleRuleOptionPerfStats);
12108 scb = pkt->ssnptr;
12109
12110 if (!srod->enable) /* Turn it off */
12111 StreamSetReassemblyTcp(scb, STREAM_FLPOLICY_IGNORE, srod->direction, STREAM_FLPOLICY_SET_ABSOLUTE);
12112 else
12113 StreamSetReassemblyTcp(scb, STREAM_FLPOLICY_FOOTPRINT, srod->direction, STREAM_FLPOLICY_SET_ABSOLUTE);
12114
12115 if (srod->fastpath)
12116 {
12117 /* Turn off inspection */
12118 scb->ha_state.ignore_direction |= srod->direction;
12119 session_api->disable_inspection(scb, pkt);
12120
12121 /* TBD: Set TF_FORCE_FLUSH ? */
12122 }
12123
12124 if (srod->alert)
12125 {
12126 PREPROC_PROFILE_END(streamReassembleRuleOptionPerfStats);
12127 return DETECTION_OPTION_MATCH;
12128 }
12129
12130 PREPROC_PROFILE_END(streamReassembleRuleOptionPerfStats);
12131 return DETECTION_OPTION_NO_ALERT;
12132 }
12133
s5TcpStreamReassembleRuleOptionCleanup(void * dataPtr)12134 void s5TcpStreamReassembleRuleOptionCleanup(void *dataPtr)
12135 {
12136 StreamReassembleRuleOptionData *srod = dataPtr;
12137 if (srod)
12138 {
12139 SnortPreprocFree(srod, sizeof(StreamReassembleRuleOptionData),
12140 PP_STREAM, PP_MEM_CATEGORY_CONFIG);
12141 }
12142 }
12143
s5TcpSetPortFilterStatus(struct _SnortConfig * sc,unsigned short port,uint16_t status,tSfPolicyId policyId,int parsing)12144 void s5TcpSetPortFilterStatus(struct _SnortConfig *sc, unsigned short port,
12145 uint16_t status, tSfPolicyId policyId, int parsing)
12146 {
12147 StreamConfig *config;
12148
12149 config = getStreamPolicyConfig( policyId, parsing );
12150 if ( ( config != NULL ) && ( config->tcp_config != NULL ) )
12151 config->tcp_config->port_filter[ port ] |= status;
12152 }
12153
s5TcpUnsetPortFilterStatus(struct _SnortConfig * sc,unsigned short port,uint16_t status,tSfPolicyId policyId,int parsing)12154 void s5TcpUnsetPortFilterStatus( struct _SnortConfig *sc, unsigned short port, uint16_t status,
12155 tSfPolicyId policyId, int parsing )
12156 {
12157 StreamConfig *config;
12158
12159 config = getStreamPolicyConfig( policyId, parsing );
12160 if ( ( config != NULL ) && ( config->tcp_config != NULL ) )
12161 config->tcp_config->port_filter[ port ] &= ~status;
12162 }
12163
s5TcpGetPortFilterStatus(struct _SnortConfig * sc,unsigned short port,tSfPolicyId policyId,int parsing)12164 int s5TcpGetPortFilterStatus(struct _SnortConfig *sc, unsigned short port, tSfPolicyId policyId, int parsing)
12165 {
12166 StreamConfig *config;
12167
12168 config = getStreamPolicyConfig( policyId, parsing );
12169 if ( ( config != NULL ) && ( config->tcp_config != NULL ) )
12170 return ( int ) config->tcp_config->port_filter[ port ];
12171 else
12172 return PORT_MONITOR_NONE;
12173 }
12174
s5TcpSetSynSessionStatus(struct _SnortConfig * sc,uint16_t status,tSfPolicyId policyId,int parsing)12175 void s5TcpSetSynSessionStatus(struct _SnortConfig *sc, uint16_t status, tSfPolicyId policyId, int parsing)
12176 {
12177 StreamConfig *config;
12178
12179 if (status <= PORT_MONITOR_SESSION)
12180 return;
12181
12182 config = getStreamPolicyConfig( policyId, parsing );
12183 if ( ( config != NULL ) && ( config->tcp_config != NULL ) )
12184 config->tcp_config->session_on_syn |= status;
12185 }
12186
s5TcpUnsetSynSessionStatus(struct _SnortConfig * sc,uint16_t status,tSfPolicyId policyId,int parsing)12187 void s5TcpUnsetSynSessionStatus(struct _SnortConfig *sc, uint16_t status, tSfPolicyId policyId, int parsing)
12188 {
12189 StreamConfig *config;
12190
12191 if (status <= PORT_MONITOR_SESSION)
12192 return;
12193
12194 config = getStreamPolicyConfig( policyId, parsing );
12195 if ( ( config != NULL ) && ( config->tcp_config != NULL ) )
12196 config->tcp_config->session_on_syn &= ~status;
12197 }
12198
targetPolicyIterate(void (* callback)(int))12199 static void targetPolicyIterate(void (*callback)(int))
12200 {
12201 unsigned int i;
12202
12203 for (i = 0; i < snort_conf->num_policies_allocated; i++)
12204 {
12205 if (snort_conf->targeted_policies[i] != NULL)
12206 {
12207 callback(i);
12208 }
12209 }
12210 }
12211
policyDecoderFlagsSaveNClear(int policyId)12212 static void policyDecoderFlagsSaveNClear(int policyId)
12213 {
12214 SnortPolicy *pPolicy = snort_conf->targeted_policies[policyId];
12215
12216 if (pPolicy)
12217 {
12218 pPolicy->decoder_alert_flags_saved = pPolicy->decoder_alert_flags;
12219 pPolicy->decoder_drop_flags_saved = pPolicy->decoder_drop_flags;
12220
12221 pPolicy->decoder_alert_flags = 0;
12222 pPolicy->decoder_drop_flags = 0;
12223 }
12224 }
12225
policyDecoderFlagsRestore(int policyId)12226 static void policyDecoderFlagsRestore(int policyId)
12227 {
12228 SnortPolicy *pPolicy = snort_conf->targeted_policies[policyId];
12229
12230 if (pPolicy)
12231 {
12232 pPolicy->decoder_alert_flags = pPolicy->decoder_alert_flags_saved;
12233 pPolicy->decoder_drop_flags = pPolicy->decoder_drop_flags_saved;
12234
12235 pPolicy->decoder_alert_flags_saved = 0;
12236 pPolicy->decoder_drop_flags_saved = 0;
12237 }
12238 }
policyChecksumFlagsSaveNClear(int policyId)12239 static void policyChecksumFlagsSaveNClear(int policyId)
12240 {
12241 SnortPolicy *pPolicy = snort_conf->targeted_policies[policyId];
12242
12243 if (pPolicy)
12244 {
12245 pPolicy->checksum_flags_saved = pPolicy->checksum_flags;
12246 pPolicy->checksum_flags = 0;
12247 }
12248 }
12249
policyChecksumFlagsRestore(int policyId)12250 static void policyChecksumFlagsRestore(int policyId)
12251 {
12252 SnortPolicy *pPolicy = snort_conf->targeted_policies[policyId];
12253
12254 if (pPolicy)
12255 {
12256 pPolicy->checksum_flags = pPolicy->checksum_flags_saved;
12257 }
12258 }
12259
12260 typedef struct network_reassembly_ports
12261 {
12262 sfcidr_t *ip;
12263 uint8_t s_ports[MAXPORTS_STORAGE];
12264 uint8_t c_ports[MAXPORTS_STORAGE];
12265 } NetworkReassemblyPorts;
12266
12267 // single instance for saving ports registered with default policy...
12268 NetworkReassemblyPorts default_nrps;
12269
12270 // List head for list of networks and ports within that preprocs have requested for port
12271 // reassembly
12272 sfSDList targeted_nrps;
12273
freeNrpNode(void * data)12274 static void freeNrpNode( void *data )
12275 {
12276 if( data )
12277 {
12278 NetworkReassemblyPorts *nrp = ( NetworkReassemblyPorts * ) data;
12279 if( nrp->ip != NULL )
12280 free( nrp->ip );
12281 SnortPreprocFree( data, sizeof( NetworkReassemblyPorts ),
12282 PP_STREAM, PP_MEM_CATEGORY_CONFIG );
12283 }
12284 }
12285
StreamCreateReassemblyPortList(void)12286 static void StreamCreateReassemblyPortList( void )
12287 {
12288 //In SnortInit, we call ConfigurePreprocessors twice. The allocations done first need to be freed
12289 if(targeted_nrps.size > 0)
12290 StreamDestoryReassemblyPortList();
12291
12292 sf_sdlist_init( &targeted_nrps, &freeNrpNode );
12293 }
12294
StreamDestoryReassemblyPortList(void)12295 static void StreamDestoryReassemblyPortList( void )
12296 {
12297 sf_sdlist_purge( &targeted_nrps );
12298 }
12299
initNetworkPortReassembly(sfcidr_t * ip,unsigned short port,int ra_dir)12300 static NetworkReassemblyPorts *initNetworkPortReassembly( sfcidr_t *ip, unsigned short port, int ra_dir )
12301 {
12302 NetworkReassemblyPorts *nrp = SnortPreprocAlloc( 1, sizeof( NetworkReassemblyPorts ),
12303 PP_STREAM, PP_MEM_CATEGORY_CONFIG );
12304
12305 if( nrp == NULL )
12306 {
12307 ErrorMessage( " ERROR: Unable to allocate memory for initializing Network Reassembly Post List\n");
12308 return NULL;
12309 }
12310
12311 nrp->ip = ip;
12312 if( ra_dir & SSN_DIR_FROM_SERVER )
12313 enablePort( nrp->s_ports, port );
12314
12315 if( ra_dir & SSN_DIR_FROM_CLIENT )
12316 enablePort( nrp->c_ports, port );
12317
12318 return nrp;
12319 }
12320
registerPortForReassembly(char * network,uint16_t port,int ra_dir)12321 void registerPortForReassembly( char *network, uint16_t port, int ra_dir )
12322 {
12323 SFIP_RET status;
12324 SDListItem *net_node;
12325
12326 // if network is NULL then this is a registration for the default policy
12327 if( network == NULL )
12328 {
12329 if( ra_dir & SSN_DIR_FROM_SERVER )
12330 enablePort( default_nrps.s_ports, port );
12331 if( ra_dir & SSN_DIR_FROM_CLIENT )
12332 enablePort( default_nrps.c_ports, port );
12333
12334 return;
12335 }
12336 else
12337 {
12338 sfcidr_t *ip = sfip_alloc( network, &status );
12339 if ( status != SFIP_SUCCESS )
12340 {
12341 WarningMessage(
12342 "Invalid network ( %s ) in reassembly registration request.", network );
12343 // free ip struct allocated above...
12344 if( ip != NULL )
12345 sfip_free( ip );
12346 return;
12347 }
12348
12349 net_node = sf_sdlist_head( &targeted_nrps );
12350 while( net_node != NULL )
12351 {
12352 SFIP_RET rc;
12353
12354 NetworkReassemblyPorts *net_data = sf_sdlist_data( net_node );
12355 rc = sfip_compare( &net_data->ip->addr, &ip->addr );
12356 if( rc == SFIP_EQUAL )
12357 {
12358 // already have this network in list, add the new port...
12359 if( ra_dir & SSN_DIR_FROM_SERVER )
12360 enablePort( net_data->s_ports, port );
12361 if( ra_dir & SSN_DIR_FROM_CLIENT )
12362 enablePort( net_data->c_ports, port );
12363 break;
12364 }
12365 else if( rc == SFIP_GREATER )
12366 {
12367 // current network in list is 'greater' than network in registration request,
12368 // this means request network is not in the list, so we add it as node before
12369 // the current node...
12370 // ptr to ip struct allocated above is stored in net data so set to NULL so
12371 // we don't free it below...
12372 NetworkReassemblyPorts *new_net = initNetworkPortReassembly( ip, port, ra_dir);
12373 if( new_net != NULL)
12374 {
12375 sf_sdlist_ins_prev( &targeted_nrps, net_node, new_net );
12376 ip = NULL;
12377 }
12378 break;
12379 }
12380 else
12381 {
12382 // current network in list is 'less' than network in registration request...
12383 // move to next entry
12384 net_node = sf_sdlist_next( net_node );
12385 }
12386 }
12387
12388 // finished searching list for matching network... if net_node is NULL then we did not
12389 // find a match AND all networks in the list are 'less than' or more general than the
12390 // request network...
12391 if( net_node == NULL )
12392 {
12393 // at list end and found no match, add new network to end of list
12394 // ptr to ip struct allocated above is stored in net data so set to NULL so
12395 // we don't free it below...
12396 NetworkReassemblyPorts *new_net = initNetworkPortReassembly( ip, port, ra_dir);
12397 if( new_net != NULL)
12398 {
12399 sf_sdlist_ins_next( &targeted_nrps, sf_sdlist_tail( &targeted_nrps ), new_net );
12400 ip = NULL;
12401 }
12402 }
12403
12404 // free ip struct allocated above if not still in use...
12405 if( ip != NULL )
12406 sfip_free( ip );
12407 }
12408 }
12409
enablePortsForReassembly(NetworkReassemblyPorts * nrp_list,StreamTcpPolicy * policy)12410 static void enablePortsForReassembly( NetworkReassemblyPorts *nrp_list, StreamTcpPolicy *policy )
12411 {
12412 uint32_t port;
12413
12414 for( port = 0; port < MAXPORTS; port++)
12415 {
12416 if( isPortEnabled( nrp_list->s_ports, port ) )
12417 {
12418 #if 0
12419 // TBD-EDM
12420 InitFlushMgr(&policy->flush_config[port].server,
12421 &policy->flush_point_list,
12422 STREAM_FLPOLICY_FOOTPRINT, 0);
12423 #endif
12424 }
12425
12426 if( isPortEnabled( nrp_list->c_ports, port ) )
12427 {
12428 #if 0
12429 // TBD-EDM
12430 InitFlushMgr(&policy->flush_config[port].client,
12431 &policy->flush_point_list,
12432 STREAM_FLPOLICY_FOOTPRINT, 0);
12433 #endif
12434 }
12435 }
12436 }
12437
enableTargetedPolicyReassemblyPorts(StreamConfig * config)12438 void enableTargetedPolicyReassemblyPorts( StreamConfig *config )
12439 {
12440 SDListItem *prev_node;
12441 SDListItem *net_node = sf_sdlist_head( &targeted_nrps );
12442 while( net_node != NULL )
12443 {
12444 NetworkReassemblyPorts *nrp_list = sf_sdlist_data( net_node );
12445 StreamTcpPolicy *policy = StreamSearchTcpConfigForBoundPolicy( config->tcp_config,
12446 &nrp_list->ip->addr );
12447 if( policy == config->tcp_config->default_policy )
12448 {
12449 // no existing policy for this network...create a new one by cloning
12450 // the default policy
12451 policy = StreamTcpPolicyClone( config->tcp_config->default_policy,
12452 config );
12453 }
12454
12455 // init the ports registered specifically for this network...
12456 enablePortsForReassembly( nrp_list, policy );
12457
12458 // now look back up the list of networks and register ports from all networks
12459 // that contain the current network...
12460 prev_node = sf_sdlist_prev( net_node );
12461 while( prev_node != NULL )
12462 {
12463 NetworkReassemblyPorts *prev_nrp_list = sf_sdlist_data( prev_node );
12464
12465 if( sfip_contains( prev_nrp_list->ip, &nrp_list->ip->addr ) == SFIP_CONTAINS )
12466 enablePortsForReassembly( prev_nrp_list, policy );
12467 prev_node = sf_sdlist_prev( prev_node );
12468 }
12469
12470 net_node = sf_sdlist_next( net_node );
12471 }
12472 }
12473
enableRegisteredPortsForReassembly(struct _SnortConfig * sc)12474 void enableRegisteredPortsForReassembly( struct _SnortConfig *sc )
12475 {
12476 int idx;
12477 tSfPolicyUserContextId stream_cfg = (stream_parsing_config)? stream_parsing_config : stream_online_config;
12478 StreamConfig *config = (StreamConfig *) sfPolicyUserDataGet(stream_cfg, getParserPolicy(sc));
12479
12480 // Since stream configs are inherited from the default,
12481 // we should attempt to fetch the default policy config
12482 // if the non-default lookup failed
12483 if (!config && getParserPolicy(sc) != getDefaultPolicy())
12484 config = (StreamConfig *) sfPolicyUserDataGet(
12485 stream_cfg,
12486 getDefaultPolicy()
12487 );
12488
12489 if (!config)
12490 {
12491 WarningMessage(
12492 "Stream TCP not enabled in default configuration.\n"
12493 );
12494
12495 return;
12496 }
12497
12498
12499 // iterate thru list of networks, init'ing all ports requested from reassembly for each
12500 enableTargetedPolicyReassemblyPorts( config );
12501
12502 // ... now init ports registered with the default policy, these ports also get
12503 // registered with all targeted policies...
12504 enablePortsForReassembly( &default_nrps, config->tcp_config->default_policy );
12505
12506 // enable ports in all target policies...
12507 for (idx = 0; idx < config->tcp_config->num_policies; idx++)
12508 enablePortsForReassembly( &default_nrps, config->tcp_config->policy_list[ idx ] );
12509
12510 // all ports registered for reassembly have been enabled in all appropriate networks,
12511 // free memory used to cache the requests...
12512 StreamDestoryReassemblyPortList( );
12513 }
12514
12515
SetFTPFileLocation(void * scbptr,bool flush)12516 void SetFTPFileLocation(void *scbptr ,bool flush)
12517 {
12518 SessionControlBlock *scb = ( SessionControlBlock * ) scbptr;
12519 TcpSession * tcpssn;
12520
12521 if ( scb && scb->proto_specific_data && scb->proto_specific_data->data)
12522 {
12523 tcpssn = (TcpSession *)scb->proto_specific_data->data;
12524 tcpssn->client.flush_mgr.flush = flush;
12525 tcpssn->server.flush_mgr.flush = flush;
12526 }
12527 }
12528
12529
unregisterPortForReassembly(char * network,uint16_t port,int ra_dir)12530 void unregisterPortForReassembly( char *network, uint16_t port, int ra_dir )
12531 {
12532
12533 // TBD may not need this capability...
12534 WarningMessage( "Unregistering ports for reassembly not currently supported" );
12535 return;
12536 }
12537
StreamIsSessionHttp2Tcp(SessionControlBlock * scb)12538 bool StreamIsSessionHttp2Tcp( SessionControlBlock *scb )
12539 {
12540 if ( scb->ha_state.session_flags & SSNFLAG_HTTP_2)
12541 {
12542 return true;
12543 }
12544 return false;
12545 }
12546
StreamSetSessionHttp2Tcp(SessionControlBlock * scb)12547 void StreamSetSessionHttp2Tcp( SessionControlBlock *scb )
12548 {
12549 scb->ha_state.session_flags |= SSNFLAG_HTTP_2;
12550 }
12551
StreamIsSessionHttp2UpgTcp(SessionControlBlock * scb)12552 bool StreamIsSessionHttp2UpgTcp( SessionControlBlock *scb )
12553 {
12554 if ( scb->ha_state.session_flags & SSNFLAG_HTTP_2_UPG)
12555 {
12556 return true;
12557 }
12558 return false;
12559 }
12560
StreamSetSessionHttp2UpgTcp(SessionControlBlock * scb)12561 void StreamSetSessionHttp2UpgTcp( SessionControlBlock *scb )
12562 {
12563 scb->ha_state.session_flags |= SSNFLAG_HTTP_2_UPG;
12564 }
12565
12566 #ifdef SNORT_RELOAD
SessionTCPReload(uint32_t max_sessions,uint16_t pruningTimeout,uint16_t nominalTimeout)12567 void SessionTCPReload(uint32_t max_sessions, uint16_t pruningTimeout, uint16_t nominalTimeout)
12568 {
12569 SessionReload(tcp_lws_cache, max_sessions, pruningTimeout, nominalTimeout
12570 #ifdef REG_TEST
12571 , "TCP"
12572 #endif
12573 );
12574 }
12575
SessionTCPReloadAdjust(unsigned maxWork)12576 unsigned SessionTCPReloadAdjust(unsigned maxWork)
12577 {
12578 return SessionProtocolReloadAdjust(tcp_lws_cache, session_configuration->max_tcp_sessions,
12579 maxWork, session_configuration->memcap
12580 #ifdef REG_TEST
12581 , "TCP"
12582 #endif
12583 );
12584 }
12585 #endif
12586
12587 #ifdef HAVE_DAQ_DECRYPTED_SSL
StreamSimulatePeerTcpAckp(SessionControlBlock * scb,uint8_t dir,uint32_t tcp_payload_len)12588 int StreamSimulatePeerTcpAckp( SessionControlBlock *scb, uint8_t dir, uint32_t tcp_payload_len )
12589 {
12590
12591 StreamTracker *talker = NULL;
12592 StreamTracker *listener = NULL;
12593 TcpSession *tcpssn = NULL;
12594
12595 if ((tcp_payload_len == 0) || !scb)
12596 {
12597 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
12598 "Stream: no SCB %p or zero length %d \n", scb, tcp_payload_len););
12599 return -1;
12600 }
12601 if (scb->proto_specific_data)
12602 tcpssn = (TcpSession *)scb->proto_specific_data->data;
12603 if (!tcpssn) {
12604 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
12605 "Stream: no tcpssn \n"););
12606 return -1;
12607 }
12608
12609 if (dir == 0)
12610 {
12611 // Packet from Server. (p->packet_flags & PKT_FROM_SERVER) is TRUE.
12612 talker = &tcpssn->server;
12613 listener = &tcpssn->client;
12614 } else
12615 {
12616 talker = &tcpssn->client;
12617 listener = &tcpssn->server;
12618 }
12619 talker->l_unackd += tcp_payload_len;
12620 listener->r_win_base += tcp_payload_len;
12621 purge_flushed_ackd(tcpssn, listener);
12622
12623 return 0;
12624 }
12625 #endif
12626
get_tcp_used_mempool()12627 size_t get_tcp_used_mempool()
12628 {
12629 if (tcp_lws_cache && tcp_lws_cache->protocol_session_pool)
12630 return tcp_lws_cache->protocol_session_pool->used_memory;
12631
12632 return 0;
12633 }
12634
12635