"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/preprocessors/Stream6/snort_stream_tcp.c" (16 Oct 2020, 435343 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "snort_stream_tcp.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /* $Id$ */
    2 /****************************************************************************
    3  *
    4  * Copyright (C) 2014-2020 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 "parser/IpAddrSet.h"
   70 
   71 #include "decode.h"
   72 #include "encode.h"
   73 #include "log.h"
   74 #include "active.h"
   75 #include "spp_normalize.h"
   76 
   77 #include "sf_sdlist.h"
   78 
   79 #include "spp_session.h"
   80 #include "session_api.h"
   81 #include "snort_session.h"
   82 
   83 #include "stream_common.h"
   84 #include "snort_stream_tcp.h"
   85 #include "stream_api.h"
   86 #include "session_expect.h"
   87 #include "stream_paf.h"
   88 #include "stream5_ha.h"
   89 
   90 #ifdef TARGET_BASED
   91 #include "sftarget_protocol_reference.h"
   92 #include "sftarget_hostentry.h"
   93 #endif
   94 
   95 #include "profiler.h"
   96 
   97 #include "ipv6_port.h"
   98 #include "sf_iph.h"
   99 
  100 #include "sp_preprocopt.h"
  101 #include "sfPolicy.h"
  102 #include "sfActionQueue.h"
  103 #include "detection_util.h"
  104 #include "file_api.h"
  105 
  106 #ifdef REG_TEST
  107 #include "reg_test.h"
  108 #include <stdio.h>
  109 #endif
  110 
  111 // port reassembly registration utils
  112 static void StreamCreateReassemblyPortList( void );
  113 static void StreamDestoryReassemblyPortList( void );
  114 
  115 #ifdef PERF_PROFILING
  116 PreprocStats s5TcpPerfStats;
  117 PreprocStats s5TcpNewSessPerfStats;
  118 PreprocStats s5TcpStatePerfStats;
  119 PreprocStats s5TcpDataPerfStats;
  120 PreprocStats s5TcpInsertPerfStats;
  121 PreprocStats s5TcpPAFPerfStats;
  122 PreprocStats s5TcpFlushPerfStats;
  123 PreprocStats s5TcpBuildPacketPerfStats;
  124 PreprocStats s5TcpProcessRebuiltPerfStats;
  125 
  126 PreprocStats streamSizePerfStats;
  127 PreprocStats streamReassembleRuleOptionPerfStats;
  128 extern PreprocStats preprocRuleOptionPerfStats;
  129 
  130 #endif
  131 
  132 /*  M A C R O S  **************************************************/
  133 
  134 /* TCP flags */
  135 #define TH_FIN  0x01
  136 #define TH_SYN  0x02
  137 #define TH_RST  0x04
  138 #define TH_PUSH 0x08
  139 #define TH_ACK  0x10
  140 #define TH_URG  0x20
  141 #define TH_ECE  0x40
  142 #define TH_CWR  0x80
  143 #define TH_NORESERVED (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG)
  144 
  145 /* TCP states */
  146 #define TCP_STATE_NONE         0
  147 #define TCP_STATE_LISTEN       1
  148 #define TCP_STATE_SYN_RCVD     2
  149 #define TCP_STATE_SYN_SENT     3
  150 #define TCP_STATE_ESTABLISHED  4
  151 #define TCP_STATE_CLOSE_WAIT   5
  152 #define TCP_STATE_LAST_ACK     6
  153 #define TCP_STATE_FIN_WAIT_1   7
  154 #define TCP_STATE_CLOSING      8
  155 #define TCP_STATE_FIN_WAIT_2   9
  156 #define TCP_STATE_TIME_WAIT   10
  157 #define TCP_STATE_CLOSED      11
  158 
  159 #ifndef MIN
  160 # define MIN(a,b)  (((a)<(b)) ? (a):(b))
  161 #endif
  162 #ifndef MAX
  163 # define MAX(a,b)  (((a)>(b)) ? (a):(b))
  164 #endif
  165 
  166 #define PAWS_WINDOW         60
  167 #define PAWS_24DAYS         2147483647  /*  2^ 31 -1 - approx 24 days in milli secs*/
  168 
  169 /* for state transition queuing */
  170 #define CHK_SEQ         0
  171 #define NO_CHK_SEQ      1
  172 
  173 #define STREAM_UNALIGNED       0
  174 #define STREAM_ALIGNED         1
  175 
  176 /* actions */
  177 #define ACTION_NOTHING                  0x00000000
  178 #define ACTION_FLUSH_SENDER_STREAM      0x00000001
  179 #define ACTION_FLUSH_RECEIVER_STREAM    0x00000002
  180 #define ACTION_DROP_SESSION             0x00000004
  181 #define ACTION_ACK_SENDER_DATA          0x00000008
  182 #define ACTION_ACK_RECEIVER_DATA        0x00000010
  183 #define ACTION_SET_SSN                  0x00000040
  184 #define ACTION_COMPLETE_TWH             0x00000080
  185 #define ACTION_RST                      0x00000100
  186 #define ACTION_BAD_SEQ                  0x00000200
  187 #define ACTION_BAD_PKT                  0x00000400
  188 #define ACTION_LWSSN_CLOSED             0x00000800
  189 #define ACTION_DISABLE_INSPECTION       0x00001000
  190 
  191 /* events */
  192 #define EVENT_SYN_ON_EST                0x00000001
  193 #define EVENT_DATA_ON_SYN               0x00000002
  194 #define EVENT_DATA_ON_CLOSED            0x00000004
  195 #define EVENT_BAD_TIMESTAMP             0x00000008
  196 #define EVENT_BAD_SEGMENT               0x00000010
  197 #define EVENT_WINDOW_TOO_LARGE          0x00000020
  198 #define EVENT_EXCESSIVE_TCP_OVERLAPS    0x00000040
  199 #define EVENT_DATA_AFTER_RESET          0x00000080
  200 #define EVENT_SESSION_HIJACK_CLIENT     0x00000100
  201 #define EVENT_SESSION_HIJACK_SERVER     0x00000200
  202 #define EVENT_DATA_WITHOUT_FLAGS        0x00000400
  203 #define EVENT_4WHS                      0x00000800
  204 #define EVENT_NO_TIMESTAMP              0x00001000
  205 #define EVENT_BAD_RST                   0x00002000
  206 #define EVENT_BAD_FIN                   0x00004000
  207 #define EVENT_BAD_ACK                   0x00008000
  208 #define EVENT_DATA_AFTER_RST_RCVD       0x00010000
  209 #define EVENT_WINDOW_SLAM               0x00020000
  210 
  211 #define TF_NONE                     0x0000
  212 #define TF_WSCALE                   0x0001
  213 #define TF_TSTAMP                   0x0002
  214 #define TF_TSTAMP_ZERO              0x0004
  215 #define TF_MSS                      0x0008
  216 #define TF_FORCE_FLUSH              0x0010
  217 #define TF_PKT_MISSED               0x0020  // sticky
  218 #define TF_MISSING_PKT              0x0040  // used internally
  219 #define TF_MISSING_PREV_PKT         0x0080  // reset for each reassembled
  220 #define TF_FIRST_PKT_MISSING        0x0100
  221 #define TF_ALL                      0xFFFF
  222 
  223 #define STREAM_INSERT_OK            0
  224 #define STREAM_INSERT_ANOMALY       1
  225 #define STREAM_INSERT_TIMEOUT       2
  226 #define STREAM_INSERT_FAILED        3
  227 
  228 #define STREAM_DEFAULT_TCP_PACKET_MEMCAP  8388608  /* 8MB */
  229 #define STREAM_MIN_OVERLAP_LIMIT 0
  230 #define STREAM_MAX_OVERLAP_LIMIT 255
  231 #define STREAM_MAX_FLUSH_FACTOR 2048
  232 
  233 #define REASSEMBLY_POLICY_FIRST     1
  234 #define REASSEMBLY_POLICY_LINUX     2
  235 #define REASSEMBLY_POLICY_BSD       3
  236 #define REASSEMBLY_POLICY_OLD_LINUX 4
  237 #define REASSEMBLY_POLICY_LAST      5
  238 #define REASSEMBLY_POLICY_WINDOWS   6
  239 #define REASSEMBLY_POLICY_SOLARIS   7
  240 #define REASSEMBLY_POLICY_HPUX11    8
  241 #define REASSEMBLY_POLICY_IRIX      9
  242 #define REASSEMBLY_POLICY_MACOS     10
  243 #define REASSEMBLY_POLICY_HPUX10    11
  244 #define REASSEMBLY_POLICY_VISTA     12
  245 #define REASSEMBLY_POLICY_WINDOWS2K3 13
  246 #define REASSEMBLY_POLICY_NOACK      14
  247 #define REASSEMBLY_POLICY_DEFAULT   REASSEMBLY_POLICY_BSD
  248 
  249 #define SUB_SYN_SENT  0x01
  250 #define SUB_ACK_SENT  0x02
  251 #define SUB_SETUP_OK  0x03
  252 #define SUB_RST_SENT  0x04
  253 #define SUB_FIN_SENT  0x08
  254 
  255 // flush types
  256 #define STREAM_FT_INTERNAL  0  // normal s5 "footprint"
  257 #define STREAM_FT_EXTERNAL  1  // set by other preprocessor
  258 #define STREAM_FT_PAF_MAX   2  // paf_max + footprint fp
  259 
  260 #define SLAM_MAX 4
  261 
  262 /* Only track a maximum number of alerts per session */
  263 #define MAX_SESSION_ALERTS 8
  264 
  265 //#define STREAM_DEBUG_ENABLED
  266 #ifdef STREAM_DEBUG_ENABLED
  267 #define STREAM_DEBUG_WRAP(x) DEBUG_WRAP(x)
  268 #else
  269 #define STREAM_DEBUG_WRAP(x)
  270 #endif
  271 
  272 /* client/server ip/port dereference */
  273 #define tcp_client_ip scb->client_ip
  274 #define tcp_client_port scb->client_port
  275 #define tcp_server_ip scb->server_ip
  276 #define tcp_server_port scb->server_port
  277 
  278 static uint32_t pkt_snaplen = 0;
  279 #define PKT_SNAPLEN 1514
  280 
  281 /*  D A T A  S T R U C T U R E S  ***********************************/
  282 typedef struct _TcpDataBlock
  283 {
  284     uint32_t   seq;
  285     uint32_t   ack;
  286     uint32_t   win;
  287     uint32_t   end_seq;
  288     uint32_t   ts;
  289 } TcpDataBlock;
  290 
  291 typedef struct _StateMgr
  292 {
  293     uint8_t    state;
  294     uint8_t    sub_state;
  295     uint8_t    state_queue;
  296     uint8_t    expected_flags;
  297     uint32_t   transition_seq;
  298     uint32_t   stq_get_seq;
  299 } StateMgr;
  300 
  301 #define RAND_FLUSH_POINTS 64
  302 
  303 //-------------------------------------------------------------------------
  304 // extra, extra - read all about it!
  305 // -- u2 is the only output plugin that currently supports extra data
  306 // -- extra data may be captured before or after alerts
  307 // -- extra data may be per packet or persistent (saved on session)
  308 //
  309 // -- per packet extra data is logged iff we alert on the packet
  310 //    containing the extra data - u2 drives this
  311 // -- an extra data mask is added to Packet to indicate when per packet
  312 //    extra data is available
  313 //
  314 // -- persistent extra data must be logged exactly once for each alert
  315 //    regardless of capture/alert ordering - s5 purge_alerts drives this
  316 // -- an extra data mask is added to the session trackers to indicate that
  317 //    persistent extra data is available
  318 //
  319 // -- event id and second are added to the session alert trackers so that
  320 //    the extra data can be correlated with events
  321 // -- event id and second are not available when StreamAddSessionAlertTcp
  322 //    is called; u2 calls StreamUpdateSessionAlertTcp as events are logged
  323 //    to set these fields
  324 //-------------------------------------------------------------------------
  325 
  326 typedef struct _StreamAlertInfo
  327 {
  328     /* For storing alerts that have already been seen on the session */
  329     uint32_t sid;
  330     uint32_t gid;
  331     uint32_t seq;
  332     // if we log extra data, event_* is used to correlate with alert
  333     uint32_t event_id;
  334     uint32_t event_second;
  335 } StreamAlertInfo;
  336 
  337 //-----------------------------------------------------------------
  338 // we make a lot of StreamSegments, StreamTrackers, and TcpSessions
  339 // so they are organized by member size/alignment requirements to
  340 // minimize unused space in the structs.
  341 // ... however, use of padding below is critical, adjust if needed
  342 //-----------------------------------------------------------------
  343 
  344 typedef struct _StreamSegment
  345 {
  346     uint8_t    *data;
  347     uint8_t    *payload;
  348 
  349     struct _StreamSegment *prev;
  350     struct _StreamSegment *next;
  351 
  352 #ifdef DEBUG
  353     int ordinal;
  354 #endif
  355     struct timeval tv;
  356     uint32_t caplen;
  357     uint32_t pktlen;
  358 
  359     uint32_t   ts;
  360     uint32_t   seq;
  361 
  362     uint16_t   orig_dsize;
  363     uint16_t   size;
  364 
  365     uint16_t   urg_offset;
  366 
  367     uint8_t    buffered;
  368 
  369     // this sequence ensures 4-byte alignment of iph in pkt
  370     // (only significant if we call the grinder)
  371     uint8_t    pad1;
  372     uint16_t   pad2;
  373     uint8_t    pkt[1];  // variable length
  374 
  375 } StreamSegment;
  376 
  377 typedef struct _StreamTracker
  378 {
  379     StateMgr  s_mgr;        /* state tracking goodies */
  380     FlushMgr  flush_mgr;    /* please flush twice, it's a long way to
  381                              * the bitbucket... */
  382 
  383     // this is intended to be private to s5_paf but is included
  384     // directly to avoid the need for allocation; do not directly
  385     // manipulate within this module.
  386     PAF_State paf_state;    // for tracking protocol aware flushing
  387 
  388     StreamAlertInfo alerts[MAX_SESSION_ALERTS]; /* history of alerts */
  389 
  390     StreamTcpPolicy *tcp_policy;
  391     StreamSegment *seglist;       /* first queued segment */
  392     StreamSegment *seglist_tail;  /* last queued segment */
  393 
  394     // TBD move out of here since only used per packet?
  395     StreamSegment* seglist_next;  /* next queued segment to flush */
  396 
  397     StreamSegment *held_segment;  /* blocked segment of http connection */
  398 #ifdef DEBUG
  399     int segment_ordinal;
  400 #endif
  401     /* Local in the context of these variables means the local part
  402      * of the connection.  For example, if this particular StreamTracker
  403      * was tracking the client side of a connection, the l_unackd value
  404      * would represent the client side of the connection's last unacked
  405      * sequence number
  406      */
  407     uint32_t l_unackd;     /* local unack'd seq number */
  408     uint32_t l_nxt_seq;    /* local next expected sequence */
  409     uint32_t l_window;     /* local receive window */
  410 
  411     uint32_t r_nxt_ack;    /* next expected ack from remote side */
  412     uint32_t r_win_base;   /* remote side window base sequence number
  413                             * (i.e. the last ack we got) */
  414     uint32_t isn;          /* initial sequence number */
  415     uint32_t ts_last;      /* last timestamp (for PAWS) */
  416     uint32_t ts_last_pkt;  /* last packet timestamp we got */
  417 
  418     uint32_t seglist_base_seq;   /* seq of first queued segment */
  419     uint32_t seg_count;          /* number of current queued segments */
  420     uint32_t seg_bytes_total;    /* total bytes currently queued */
  421     uint32_t seg_bytes_logical;  /* logical bytes queued (total - overlaps) */
  422     uint32_t total_bytes_queued; /* total bytes queued (life of session) */
  423     uint32_t total_segs_queued;  /* number of segments queued (life) */
  424     uint32_t overlap_count;      /* overlaps encountered */
  425     uint32_t small_seg_count;
  426     uint32_t flush_count;        /* number of flushed queued segments */
  427     uint32_t xtradata_mask;      /* extra data available to log */
  428 
  429     uint16_t os_policy;
  430     uint16_t reassembly_policy;
  431 
  432     uint16_t wscale;       /* window scale setting */
  433     uint16_t mss;          /* max segment size */
  434     uint16_t  flags;        /* bitmap flags (TF_xxx) */
  435 
  436     uint8_t  mac_addr[6];
  437 
  438     uint8_t  alert_count;  /* number alerts stored (up to MAX_SESSION_ALERTS) */
  439 
  440 } StreamTracker;
  441 
  442 typedef struct _TcpSession
  443 {
  444     StreamTracker client;
  445     StreamTracker server;
  446     SessionControlBlock *scb;
  447 
  448 #ifdef DEBUG
  449     struct timeval ssn_time;
  450 #endif
  451 
  452 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
  453     int32_t ingress_index;  /* Index of the inbound interface. */
  454     int32_t egress_index;   /* Index of the outbound interface. */
  455     int32_t ingress_group;  /* Index of the inbound group. */
  456     int32_t egress_group;   /* Index of the outbound group. */
  457     uint32_t daq_flags;     /* Flags for the packet (DAQ_PKT_FLAG_*) */
  458     void *priv_ptr;         /* private data pointer. used in pinhole */
  459 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
  460     uint16_t address_space_id_src;
  461     uint16_t address_space_id_dst;
  462 #else
  463     uint16_t address_space_id;
  464 #endif
  465 #ifdef HAVE_DAQ_FLOW_ID
  466     uint32_t daq_flow_id;
  467 #endif
  468 #endif
  469     uint8_t ecn;
  470     bool session_decrypted;
  471     uint8_t pp_flags;
  472 } TcpSession;
  473 
  474 #define SL_BUF_FLUSHED 1
  475 
  476 static inline int SetupOK (const StreamTracker* st)
  477 {
  478     return ( (st->s_mgr.sub_state & SUB_SETUP_OK) == SUB_SETUP_OK );
  479 }
  480 
  481 static inline int Stream_NormGetMode(uint16_t reassembly_policy, const SnortConfig* sc, NormFlags nf)
  482 {
  483     if ( reassembly_policy == REASSEMBLY_POLICY_NOACK )
  484         return NORM_MODE_OFF;
  485     return Normalize_GetMode(sc, nf);
  486 }
  487 
  488 static inline uint32_t SegsToFlush (const StreamTracker* st, unsigned max)
  489 {
  490     uint32_t n = st->seg_count - st->flush_count;
  491     StreamSegment* s;
  492 
  493     if ( !n || max == 1 )
  494         return n;
  495 
  496     n = 0;
  497     s = st->seglist;
  498 
  499     while ( s )
  500     {
  501         if ( !s->buffered && SEQ_LT(s->seq, st->r_win_base) )
  502             n++;
  503 
  504         if ( max && n == max )
  505             return n;
  506 
  507         s = s->next;
  508     }
  509     return n;
  510 }
  511 
  512 static inline bool DataToFlush (const StreamTracker* st)
  513 {
  514     if ( (st->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL)
  515 #ifdef NORMALIZER
  516             || (st->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL_IPS)
  517 #endif
  518             || st->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL_NOACK
  519             || st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK
  520        )
  521         return ( SegsToFlush(st, 1) > 0 );
  522 
  523 #ifdef NORMALIZER
  524     if ((st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS) || (st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS_FTP))
  525         return ( SegsToFlush(st, 1) > 1 );
  526 #endif
  527 
  528     return ( SegsToFlush(st, 2) > 1 );
  529 }
  530 
  531 #ifdef REG_TEST
  532 int default_ports[] =
  533 {
  534     21, 23, 25, 42, 53, 80, 110, 111, 135, 136, 137, 139, 143, 445,
  535     513, 514, 1433, 1521, 2401, 3306
  536 };
  537 #define DEFAULT_PORTS_SIZE (int)(sizeof(default_ports)/sizeof(int))
  538 #else
  539 int *default_ports = 0;
  540 #define DEFAULT_PORTS_SIZE 0
  541 #endif
  542 
  543 #ifdef TARGET_BASED
  544 char *default_protocols[] =
  545 {
  546     "ftp", "telnet", "smtp", "nameserver", "dns", "http", "pop3", "sunrpc",
  547     "dcerpc", "netbios-ssn", "imap", "login", "shell", "mssql", "oracle", "cvs",
  548     "mysql"
  549 };
  550 #endif
  551 
  552 FlushConfig ignore_flush_policy[MAX_PORTS];
  553 #ifdef TARGET_BASED
  554 FlushConfig ignore_flush_policy_protocol[MAX_PROTOCOL_ORDINAL];
  555 #endif
  556 
  557 /*  P R O T O T Y P E S  ********************************************/
  558 static void StreamParseTcpArgs(struct _SnortConfig *, StreamTcpConfig *, char *, StreamTcpPolicy *);
  559 static void StreamPrintTcpConfig(StreamTcpPolicy *);
  560 
  561 static void StreamInitPacket();
  562 static inline void SetupTcpDataBlock(TcpDataBlock *, Packet *);
  563 static int ProcessTcp(SessionControlBlock *, Packet *, TcpDataBlock *,
  564         StreamTcpPolicy *, SFXHASH_NODE *);
  565 #if OLD_CODE_NOLONGER_USED_DEPENDS_ON_CURRENT_STATE
  566 static inline void QueueState(uint8_t, StreamTracker*, uint8_t,
  567         uint32_t, uint8_t);
  568 static inline int EvalStateQueue(StreamTracker *, uint8_t, uint32_t);
  569 #endif
  570 static inline int CheckFlushPolicyOnData(
  571         StreamTcpConfig *config, TcpSession *, StreamTracker *,
  572         StreamTracker *, TcpDataBlock *, Packet *);
  573 static inline int CheckFlushPolicyOnAck(
  574         StreamTcpConfig *config, TcpSession *, StreamTracker *,
  575         StreamTracker *, TcpDataBlock *, Packet *);
  576 static void StreamSeglistAddNode(StreamTracker *, StreamSegment *,
  577         StreamSegment *);
  578 static int StreamSeglistDeleteNode(StreamTracker *, StreamSegment *);
  579 static int StreamSeglistDeleteNodeTrim(StreamTracker*, StreamSegment*, uint32_t flush_seq);
  580 static int AddStreamNode(StreamTracker *st, Packet *p,
  581         TcpDataBlock*,
  582         TcpSession *tcpssn,
  583         uint16_t len,
  584         uint32_t slide,
  585         uint32_t trunc,
  586         uint32_t seq,
  587         StreamSegment *left,
  588         StreamSegment **retSeg);
  589 static int DupStreamNode(
  590         Packet*,
  591         StreamTracker*,
  592         StreamSegment* left,
  593         StreamSegment** retSeg);
  594 
  595 static uint32_t StreamGetWscale(Packet *, uint16_t *);
  596 static uint32_t StreamPacketHasWscale(Packet *);
  597 static uint32_t StreamGetMss(Packet *, uint16_t *);
  598 static uint32_t StreamGetTcpTimestamp(Packet *, uint32_t *, int strip);
  599 static int FlushStream(
  600         Packet*, StreamTracker *st, uint32_t toSeq, uint8_t *flushbuf,
  601         const uint8_t *flushbuf_end);
  602 static void TcpSessionCleanup(SessionControlBlock *ssn, int freeApplicationData);
  603 static void TcpSessionCleanupWithFreeApplicationData(void *ssn);
  604 static void FlushQueuedSegs(SessionControlBlock *ssn, TcpSession *tcpssn);
  605 
  606 int s5TcpStreamSizeInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr);
  607 int s5TcpStreamSizeEval(void *p, const uint8_t **cursor, void *dataPtr);
  608 void s5TcpStreamSizeCleanup(void *dataPtr);
  609 int s5TcpStreamReassembleRuleOptionInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr);
  610 int s5TcpStreamReassembleRuleOptionEval(void *p, const uint8_t **cursor, void *dataPtr);
  611 void s5TcpStreamReassembleRuleOptionCleanup(void *dataPtr);
  612 static inline void ResetFlushMgrs(void);
  613 static void targetPolicyIterate(void (*callback)(int));
  614 static void policyDecoderFlagsSaveNClear(int policyId);
  615 static void policyDecoderFlagsRestore(int policyId);
  616 static void policyChecksumFlagsSaveNClear(int policyId);
  617 static void policyChecksumFlagsRestore(int policyId);
  618 static inline uint16_t GetTcpReassemblyPolicy(int os_policy);
  619 
  620 /*  G L O B A L S  **************************************************/
  621 static SessionCache* tcp_lws_cache = NULL;
  622 static Packet *s5_pkt = NULL;
  623 static Packet *tcp_cleanup_pkt = NULL;
  624 static const uint8_t *s5_pkt_end = NULL;
  625 static char midstream_allowed = 0;
  626 static Packet *wire_packet = NULL;
  627 static uint8_t flush_policy_for_dir = 0;
  628 
  629 /* enum for policy names */
  630 static char *reassembly_policy_names[] = {
  631     "no policy!",
  632     "FIRST",
  633     "LINUX",
  634     "BSD",
  635     "OLD LINUX",
  636     "LAST",
  637     "WINDOWS",
  638     "SOLARIS",
  639     "HPUX11",
  640     "IRIX",
  641     "MACOS",
  642     "HPUX10",
  643     "WINDOWS VISTA",
  644     "WINDOWS 2003"
  645         "IPS"
  646 };
  647 
  648 #ifdef STREAM_DEBUG_ENABLED
  649 static char *state_names[] = {
  650     "NONE",
  651     "LISTEN",
  652     "SYN_RCVD",
  653     "SYN_SENT",
  654     "ESTABLISHED",
  655     "CLOSE_WAIT",
  656     "LAST_ACK",
  657     "FIN_WAIT_1",
  658     "CLOSING",
  659     "FIN_WAIT_2",
  660     "TIME_WAIT",
  661     "CLOSED"
  662 };
  663 #endif
  664 
  665 static char *flush_policy_names[] = {
  666     "None",
  667     "Footprint",
  668     "Logical",
  669     "Response",
  670     "Sliding Window",
  671 #if 0
  672     "Consumed",
  673 #endif
  674     "Ignore",
  675     "Protocol",
  676     "Footprint-IPS",
  677     "Protocol-IPS",
  678     "Footprint-NOACK",
  679     "Protocol-NOACK",
  680     "Footprint-IPS-FTP",
  681     "Disabled"
  682 };
  683 
  684 static int s5_tcp_cleanup = 0;
  685 
  686 static uint32_t g_static_points[RAND_FLUSH_POINTS] =
  687 { 128, 217, 189, 130, 240, 221, 134, 129,
  688     250, 232, 141, 131, 144, 177, 201, 130,
  689     230, 190, 177, 142, 130, 200, 173, 129,
  690     250, 244, 174, 151, 201, 190, 180, 198,
  691     220, 201, 142, 185, 219, 129, 194, 140,
  692     145, 191, 197, 183, 199, 220, 231, 245,
  693     233, 135, 143, 158, 174, 194, 200, 180,
  694     201, 142, 153, 187, 173, 199, 143, 201 };
  695 
  696 /*  F U N C T I O N S  **********************************************/
  697 static inline uint32_t GenerateFlushPoint(FlushPointList *flush_point_list)
  698 {
  699     return (rand() % flush_point_list->flush_range) + flush_point_list->flush_base;
  700 }
  701 
  702 static inline void InitFlushPointList(FlushPointList *flush_point_list, uint32_t value, uint32_t range, int use_static)
  703 {
  704     uint32_t i;
  705     uint32_t flush_range = range;
  706     uint32_t flush_base = value - range/2;
  707 
  708     if (!flush_point_list)
  709         return;
  710 
  711     if (!flush_point_list->initialized)
  712     {
  713 #ifdef REG_TEST
  714         const char* sfp = getenv("S5_FPT");
  715         // no error checking required - atoi() is sufficient
  716         uint32_t cfp = sfp ? atoi(sfp) : 0;
  717         if ( cfp < 128 || cfp > 255 ) cfp = 192;
  718 #else
  719         const uint32_t cfp = 192;
  720 #endif
  721 
  722         flush_point_list->flush_range = flush_range;
  723         flush_point_list->flush_base = flush_base;
  724 #ifndef DYNAMIC_RANDOM_FLUSH_POINTS
  725         flush_point_list->current = 0;
  726 
  727         flush_point_list->flush_points = SnortAlloc(sizeof(uint32_t) * RAND_FLUSH_POINTS);
  728         for (i=0;i<RAND_FLUSH_POINTS;i++)
  729         {
  730             if (snort_conf->run_flags & RUN_FLAG__STATIC_HASH)
  731             {
  732                 if ( i == 0 )
  733                     LogMessage("WARNING:  using constant flush point = %u!\n", cfp);
  734                 flush_point_list->flush_points[i] = cfp;
  735 
  736             }
  737             else if (use_static)
  738             {
  739                 if ( i == 0 )
  740                     LogMessage("WARNING: using static flush points.\n");
  741                 flush_point_list->flush_points[i] = g_static_points[i];
  742             }
  743             else
  744             {
  745                 flush_point_list->flush_points[i] = GenerateFlushPoint(flush_point_list);
  746             }
  747         }
  748 #endif
  749         flush_point_list->initialized = 1;
  750     }
  751 }
  752 
  753 static inline void UpdateFlushMgr( SnortConfig *sc,
  754         FlushMgr *mgr, FlushPointList *flush_point_list, uint32_t flags)
  755 {
  756     if ( mgr->flush_type == STREAM_FT_EXTERNAL )
  757         return;
  758 
  759     switch (mgr->flush_policy)
  760     {
  761         case STREAM_FLPOLICY_FOOTPRINT:
  762         case STREAM_FLPOLICY_LOGICAL:
  763             break;
  764 
  765         case STREAM_FLPOLICY_PROTOCOL:
  766             if ( flags & TF_PKT_MISSED )
  767             {
  768                 mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT;
  769                 mgr->flush_type = STREAM_FT_PAF_MAX;
  770             }
  771             break;
  772 
  773 #ifdef NORMALIZER
  774         case STREAM_FLPOLICY_FOOTPRINT_IPS:
  775         case STREAM_FLPOLICY_FOOTPRINT_IPS_FTP:
  776             break;
  777 
  778         case STREAM_FLPOLICY_PROTOCOL_IPS:
  779             if ( flags & TF_PKT_MISSED )
  780             {
  781                 mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS;
  782                 mgr->flush_type = STREAM_FT_PAF_MAX;
  783             }
  784             break;
  785 #endif
  786         case STREAM_FLPOLICY_FOOTPRINT_NOACK:
  787             break;
  788         case STREAM_FLPOLICY_PROTOCOL_NOACK:
  789             if ( flags & TF_PKT_MISSED )
  790             {
  791                 mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT_NOACK;
  792                 mgr->flush_type = STREAM_FT_PAF_MAX;
  793             }
  794             break;
  795         default:
  796             return;
  797     }
  798     /* Ideally, we would call rand() each time, but that
  799      * is a performance headache waiting to happen. */
  800 #ifdef DYNAMIC_RANDOM_FLUSH_POINTS
  801     mgr->flush_pt = GenerateFlushPoint();
  802 #else
  803     if (flush_point_list)
  804     {
  805         /* Handle case where it wasn't initialized... */
  806         if (flush_point_list->initialized == 0)
  807         {
  808             InitFlushPointList(flush_point_list, 192, 128, 0);
  809         }
  810         mgr->flush_pt = flush_point_list->flush_points[flush_point_list->current];
  811         flush_point_list->current = (flush_point_list->current+1) % RAND_FLUSH_POINTS;
  812     }
  813 #endif
  814     //Do not reset the last_size for FTP flush policy
  815     if(mgr->flush_policy != STREAM_FLPOLICY_FOOTPRINT_IPS_FTP)
  816     {
  817         mgr->last_size = 0;
  818         mgr->last_count = 0;
  819     }
  820 
  821     if ( mgr->flush_type == STREAM_FT_PAF_MAX )
  822         mgr->flush_pt += ScPafMaxNewConf(sc);
  823 }
  824 
  825 static inline void InitFlushMgr( SnortConfig *sc, FlushMgr *mgr, FlushPointList *flush_point_list,
  826         uint8_t policy, uint8_t auto_disable)
  827 {
  828     // if policy is to disable reassembly just set policy in flush manager and
  829     // return
  830     if( policy == STREAM_FLPOLICY_DISABLED )
  831     {
  832         mgr->flush_policy = policy;
  833         return;
  834     }
  835     else if ( mgr->flush_policy == STREAM_FLPOLICY_DISABLED )
  836     {
  837         WarningMessage( "Stream policy has disabled reassembly on this port." );
  838         return;
  839     }
  840 
  841     mgr->flush_policy = policy;
  842     mgr->flush_type = STREAM_FT_INTERNAL;
  843     mgr->auto_disable = auto_disable;
  844 
  845     UpdateFlushMgr(sc, mgr, flush_point_list, 0);
  846 
  847 #ifdef NORMALIZER
  848     if ( Normalize_GetMode(sc, NORM_TCP_IPS) == NORM_MODE_ON)
  849     {
  850         if ( policy == STREAM_FLPOLICY_FOOTPRINT )
  851             mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS;
  852 
  853         else if ( policy == STREAM_FLPOLICY_PROTOCOL )
  854             mgr->flush_policy = STREAM_FLPOLICY_PROTOCOL_IPS;
  855     }
  856 #endif
  857 }
  858 
  859 static inline void InitFlushMgrByPort (
  860         SessionControlBlock* scb, StreamTracker* pst,
  861         uint16_t port, bool c2s, uint8_t flush_policy, bool all_services)
  862 {
  863     uint16_t registration, auto_disable = 0;
  864     bool flush = (flush_policy != STREAM_FLPOLICY_IGNORE);
  865 
  866 #if 0
  867     // this check required if PAF doesn't abort
  868     if ( scb->session_state & STREAM_STATE_MIDSTREAM )
  869         registration = 0;
  870     else
  871 #endif
  872         if(all_services)
  873         {
  874             registration = s5_paf_port_registration_all(
  875                     ( ( StreamConfig * ) scb->stream_config )->tcp_config->paf_config, port, c2s, flush);
  876         }
  877         else
  878         {
  879             registration = s5_paf_port_registration(
  880                     ( ( StreamConfig * ) scb->stream_config )->tcp_config->paf_config, port, c2s, flush);
  881         }
  882 
  883     if ( registration )
  884     {
  885         if( flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK )
  886             flush_policy = STREAM_FLPOLICY_PROTOCOL_NOACK;
  887         else
  888             flush_policy = STREAM_FLPOLICY_PROTOCOL;
  889         s5_paf_setup(&pst->paf_state, registration);
  890         auto_disable = !flush;
  891     }
  892     InitFlushMgr(snort_conf, &pst->flush_mgr,
  893             &pst->tcp_policy->flush_point_list, flush_policy, auto_disable);
  894 }
  895 
  896 static inline void InitFlushMgrByService (
  897         SessionControlBlock* scb, StreamTracker* pst,
  898         int16_t service, bool c2s, uint8_t flush_policy)
  899 {
  900     uint16_t registration, auto_disable = 0;
  901     bool flush = (flush_policy != STREAM_FLPOLICY_IGNORE);
  902 
  903 #if 0
  904     // this check required if PAF doesn't abort
  905     if ( scb->session_state & STREAM_STATE_MIDSTREAM )
  906         registration = 0;
  907     else
  908 #endif
  909         registration = s5_paf_service_registration(
  910                 ( ( StreamConfig * ) scb->stream_config )->tcp_config->paf_config, service, c2s, flush);
  911 
  912     if ( registration )
  913     {
  914         if( flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK )
  915             flush_policy = STREAM_FLPOLICY_PROTOCOL_NOACK;
  916         else
  917             flush_policy = STREAM_FLPOLICY_PROTOCOL;
  918         s5_paf_setup(&pst->paf_state, registration);
  919         auto_disable = !flush;
  920     }
  921     InitFlushMgr(snort_conf, &pst->flush_mgr,
  922             &pst->tcp_policy->flush_point_list, flush_policy, auto_disable);
  923 }
  924 
  925 static int ResetFlushMgrsPolicy(
  926         tSfPolicyUserContextId config,
  927         tSfPolicyId policyId,
  928         void* pData
  929         )
  930 {
  931     int i;
  932     StreamConfig *pPolicyConfig = (StreamConfig *)pData;
  933 
  934     //do any housekeeping before freeing StreamConfig
  935     if (pPolicyConfig->tcp_config == NULL)
  936         return 0;
  937 
  938     for (i = 0; i < pPolicyConfig->tcp_config->num_policies; i++)
  939     {
  940         int j;
  941         StreamTcpPolicy *policy = pPolicyConfig->tcp_config->policy_list[i];
  942         FlushPointList *fpl = &policy->flush_point_list;
  943         FlushMgr *client, *server;
  944         uint8_t flush_policy;
  945 
  946         fpl->current = 0;
  947 
  948         for (j = 0; j < MAX_PORTS; j++)
  949         {
  950             client = &policy->flush_config[j].client;
  951             flush_policy = policy->flush_config[j].client.flush_policy;
  952             InitFlushMgr(snort_conf, client, fpl, flush_policy, 0);
  953 
  954             server = &policy->flush_config[j].server;
  955             flush_policy = policy->flush_config[j].server.flush_policy;
  956             InitFlushMgr(snort_conf, server, fpl, flush_policy, 0);
  957         }
  958 #ifdef TARGET_BASED
  959         /* protocol 0 is the unknown case. skip it */
  960         for (j = 1; j < MAX_PROTOCOL_ORDINAL; j++)
  961         {
  962             client = &policy->flush_config_protocol[j].client;
  963             flush_policy = policy->flush_config_protocol[j].client.flush_policy;
  964             InitFlushMgr(snort_conf, client, fpl, flush_policy, 0);
  965 
  966             server = &policy->flush_config_protocol[j].server;
  967             flush_policy = policy->flush_config_protocol[j].server.flush_policy;
  968             InitFlushMgr(snort_conf, server, fpl, flush_policy, 0);
  969         }
  970 #endif
  971     }
  972 
  973     return 0;
  974 }
  975 
  976 static inline void ResetFlushMgrs( void )
  977 {
  978     if( stream_online_config == NULL )
  979         return;
  980 
  981     sfPolicyUserDataFreeIterate( stream_online_config, ResetFlushMgrsPolicy );
  982 }
  983 
  984 void **StreamGetPAFUserDataTcp( SessionControlBlock* scb, bool to_server, uint8_t id )
  985 {
  986     TcpSession* tcpssn;
  987     PAF_State *ps;
  988     int8_t i;
  989 
  990     if(!id)
  991        return NULL;
  992 
  993     if( !scb->proto_specific_data )
  994         return NULL;
  995 
  996     tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
  997 
  998     if ( !tcpssn )
  999         return NULL;
 1000 
 1001     ps = ( to_server ) ? &tcpssn->server.paf_state
 1002        :
 1003        &tcpssn->client.paf_state;
 1004 
 1005     i = s5_paf_get_user_data_index( ps, id );
 1006 
 1007     if( i >= 0 )
 1008        return &ps->user[i];
 1009     else
 1010        return NULL;
 1011 }
 1012 
 1013 bool StreamIsPafActiveTcp( SessionControlBlock *scb, bool to_server )
 1014 {
 1015     TcpSession *tcpssn;
 1016     FlushMgr *fm;
 1017 
 1018     if( !scb->proto_specific_data )
 1019         return false;
 1020 
 1021     tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
 1022 
 1023     if( !tcpssn )
 1024         return false;
 1025 
 1026     fm = ( to_server ) ? &tcpssn->server.flush_mgr : &tcpssn->client.flush_mgr;
 1027 
 1028     return ( ( fm->flush_policy == STREAM_FLPOLICY_PROTOCOL )
 1029 #ifdef NORMALIZER
 1030             || ( fm->flush_policy == STREAM_FLPOLICY_PROTOCOL_IPS )
 1031 #endif
 1032             || (fm->flush_policy == STREAM_FLPOLICY_PROTOCOL_NOACK)
 1033            );
 1034 }
 1035 
 1036 bool StreamActivatePafTcp (SessionControlBlock *scb, int dir, int16_t service_port, uint8_t type)
 1037 {
 1038     TcpSession *tcpssn;
 1039     StreamTracker *trk;
 1040     FlushMgr *fm;
 1041     uint8_t flush_policy;
 1042 
 1043     if( !scb->proto_specific_data )
 1044         return false;
 1045 
 1046     tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
 1047 
 1048     if( !tcpssn || !ScPafEnabled() )
 1049         return false;
 1050 
 1051     // must have valid stream config for this session, may need to reset after a reload
 1052     if( scb->stream_config == NULL )
 1053     {
 1054         WarningMessage("Stream Configuration NULL For In Progress Session, Reinitializing.\n");
 1055         scb->stream_config = sfPolicyUserDataGet( stream_online_config, getNapRuntimePolicy() );
 1056         if( scb->stream_config == NULL )
 1057         {
 1058             ErrorMessage("No Valid Stream Configurations, Stream Processing Terminated For This Packet.\n");
 1059             return false;
 1060         }
 1061     }
 1062 
 1063     switch ( dir )
 1064     {
 1065         case SSN_DIR_TO_CLIENT:
 1066             {
 1067                 trk = &tcpssn->client;
 1068                 fm = &tcpssn->client.flush_mgr;
 1069                 flush_policy = fm->flush_policy;
 1070                 if ( flush_policy == STREAM_FLPOLICY_IGNORE )
 1071                     flush_policy = STREAM_FLPOLICY_PROTOCOL;
 1072 
 1073                 if ( type == PAF_TYPE_SERVICE )
 1074                 {
 1075                     InitFlushMgrByService(scb, trk, service_port, false, flush_policy);
 1076                 }
 1077                 else
 1078                 {
 1079                     InitFlushMgrByPort(scb, trk, service_port, false, flush_policy, true);
 1080                 }
 1081             }
 1082             break;
 1083         case SSN_DIR_TO_SERVER:
 1084             {
 1085                 trk = &tcpssn->server;
 1086                 fm = &tcpssn->server.flush_mgr;
 1087                 flush_policy = fm->flush_policy;
 1088                 if ( flush_policy == STREAM_FLPOLICY_IGNORE )
 1089                     flush_policy = STREAM_FLPOLICY_PROTOCOL;
 1090 
 1091                 if ( type == PAF_TYPE_SERVICE )
 1092                 {
 1093                     InitFlushMgrByService(scb, trk, service_port, true, flush_policy);
 1094                 }
 1095                 else
 1096                 {
 1097                     InitFlushMgrByPort(scb, trk, service_port, true, flush_policy, true );
 1098                 }
 1099             }
 1100             break;
 1101         case SSN_DIR_BOTH:
 1102             {
 1103                 trk = &tcpssn->server;
 1104                 fm = &tcpssn->server.flush_mgr;
 1105                 flush_policy = fm->flush_policy;
 1106                 if ( flush_policy == STREAM_FLPOLICY_IGNORE )
 1107                     flush_policy = STREAM_FLPOLICY_PROTOCOL;
 1108 
 1109                 if ( type == PAF_TYPE_SERVICE )
 1110                 {
 1111                     InitFlushMgrByService(scb, trk, service_port, true, flush_policy);
 1112                 }
 1113                 else
 1114                 {
 1115                     InitFlushMgrByPort(scb, trk, service_port, true, flush_policy, true );
 1116                 }
 1117             }
 1118             {
 1119                 trk = &tcpssn->client;
 1120                 fm = &tcpssn->client.flush_mgr;
 1121                 flush_policy = fm->flush_policy;
 1122                 if ( flush_policy == STREAM_FLPOLICY_IGNORE )
 1123                     flush_policy = STREAM_FLPOLICY_PROTOCOL;
 1124 
 1125                 if ( type == PAF_TYPE_SERVICE )
 1126                 {
 1127                     InitFlushMgrByService(scb, trk, service_port, false, flush_policy);
 1128                 }
 1129                 else
 1130                 {
 1131                     InitFlushMgrByPort(scb, trk, service_port, false, flush_policy, true);
 1132                 }
 1133             }
 1134             break;
 1135 
 1136         default:
 1137             return false;
 1138     }
 1139 
 1140     return true;
 1141 }
 1142 
 1143 static inline void StreamResetPolicyPerTrk( StreamTracker* trk, uint16_t policy, uint16_t mss )
 1144 {
 1145     trk->tcp_policy->policy = trk->os_policy = policy;
 1146     trk->reassembly_policy = GetTcpReassemblyPolicy( policy );
 1147     trk->mss = mss;
 1148 }
 1149 
 1150 void StreamResetPolicyTcp ( SessionControlBlock *scb, int dir, uint16_t policy, uint16_t mss)
 1151 {
 1152     TcpSession *tcpssn;
 1153 
 1154     if( !scb->proto_specific_data )
 1155         return;
 1156 
 1157     tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
 1158 
 1159     if( !tcpssn )
 1160         return;
 1161 
 1162     switch( dir )
 1163     {
 1164         case SSN_DIR_TO_CLIENT:
 1165             StreamResetPolicyPerTrk( &tcpssn->client, policy, mss );
 1166             break;
 1167 
 1168         case SSN_DIR_TO_SERVER:
 1169             StreamResetPolicyPerTrk( &tcpssn->server, policy, mss );
 1170             break;
 1171 
 1172         case SSN_DIR_BOTH:
 1173             StreamResetPolicyPerTrk( &tcpssn->server, policy, mss );
 1174             StreamResetPolicyPerTrk( &tcpssn->client, policy, mss );
 1175             break;
 1176 
 1177         default:
 1178             break;
 1179     }
 1180 }
 1181 
 1182 void StreamSetSessionDecryptedTcp( SessionControlBlock *scb, bool enable )
 1183 {
 1184     TcpSession *tcpssn;
 1185 
 1186     if( !scb->proto_specific_data )
 1187         return;
 1188 
 1189     tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
 1190 
 1191     if ( !tcpssn )
 1192         return;
 1193 
 1194     if((SegsToFlush(&tcpssn->server, 1) > 0) || (SegsToFlush(&tcpssn->client, 1) > 0))
 1195     {
 1196         FlushQueuedSegs(scb, tcpssn);
 1197         Active_Reset();
 1198     }
 1199 
 1200     tcpssn->session_decrypted = enable;
 1201 }
 1202 
 1203 bool StreamIsSessionDecryptedTcp( SessionControlBlock *scb )
 1204 {
 1205     TcpSession *tcpssn;
 1206 
 1207     if( !scb->proto_specific_data )
 1208         return false;
 1209 
 1210     tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
 1211 
 1212     if ( !tcpssn )
 1213         return false;
 1214 
 1215     return ( tcpssn->session_decrypted == true );
 1216 }
 1217 
 1218 uint32_t StreamGetPreprocFlagsTcp(SessionControlBlock *scb)
 1219 {
 1220     TcpSession *tcpssn;
 1221 
 1222     if( !scb->proto_specific_data )
 1223         return 0;
 1224 
 1225     tcpssn = ( TcpSession * ) scb->proto_specific_data->data;
 1226 
 1227     if ( !tcpssn )
 1228         return 0;
 1229 
 1230     return tcpssn->pp_flags;
 1231 }
 1232 
 1233 //-------------------------------------------------------------------------
 1234 // tcp ha stuff
 1235 
 1236 #ifdef ENABLE_HA
 1237 static SessionControlBlock *StreamTCPCreateSession( const SessionKey *key )
 1238 {
 1239     setNapRuntimePolicy( getDefaultPolicy() );
 1240 
 1241     /* TODO: Set the TCP policy to something here? */
 1242     return session_api->create_session( tcp_lws_cache, NULL, key );
 1243 }
 1244 
 1245 static void StreamTCPDeactivateSession( SessionControlBlock *scb )
 1246 {
 1247     if( scb->proto_specific_data )
 1248     {
 1249         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 1250                     "Cleaning up the TCP session associated with the session being put into standby.\n"););
 1251         TcpSessionCleanup( scb, 0 );
 1252     }
 1253 
 1254     scb->session_state &= ~( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK |
 1255             STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED );
 1256     scb->ha_state.session_flags &= ~( SSNFLAG_SEEN_CLIENT | SSNFLAG_SEEN_SERVER );
 1257 }
 1258 
 1259 static int StreamTCPDeleteSession( const SessionKey *key )
 1260 {
 1261     SessionControlBlock *scb = session_api->get_session_by_key( tcp_lws_cache, key );
 1262 
 1263     if( scb != NULL )
 1264     {
 1265         if( StreamSetRuntimeConfiguration( scb, scb->protocol ) == 0 )
 1266         {
 1267             if (!session_api->delete_session( tcp_lws_cache, scb, "ha sync", false ))
 1268                s5stats.active_tcp_sessions--;
 1269         }
 1270         else
 1271             WarningMessage(" WARNING: Attempt to delete a TCP Session when no valid runtime configuration.\n" );
 1272     }
 1273 
 1274     return 0;
 1275 }
 1276 #endif
 1277 
 1278 SessionControlBlock *GetLWTcpSession( const SessionKey *key )
 1279 {
 1280     return session_api->get_session_by_key( tcp_lws_cache, key );
 1281 }
 1282 
 1283 #ifdef ENABLE_HA
 1284 
 1285 static HA_Api ha_tcp_api = {
 1286     /*.get_lws = */ GetLWTcpSession,
 1287 
 1288     /*.create_session = */ StreamTCPCreateSession,
 1289     /*.deactivate_session = */ StreamTCPDeactivateSession,
 1290     /*.delete_session = */ StreamTCPDeleteSession,
 1291 };
 1292 
 1293 #endif
 1294 
 1295 void setTcpDirectionAndPorts( Packet *p, SessionControlBlock *scb )
 1296 {
 1297     if( TCP_ISFLAGSET( p->tcph, TH_SYN ) && !TCP_ISFLAGSET( p->tcph, TH_ACK ) )
 1298     {
 1299         STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 1300                     "Stream SYN PACKET, establishing lightweight session direction.\n"););
 1301         /* SYN packet from client */
 1302         scb->ha_state.direction = FROM_CLIENT;
 1303         IP_COPY_VALUE( scb->client_ip, GET_SRC_IP( p ) );
 1304         scb->client_port = p->tcph->th_sport;
 1305         IP_COPY_VALUE( scb->server_ip, GET_DST_IP( p ) );
 1306         scb->server_port = p->tcph->th_dport;
 1307     }
 1308     else if( TCP_ISFLAGSET( p->tcph, ( TH_SYN | TH_ACK ) ) )
 1309     {
 1310         scb->ha_state.direction = FROM_SERVER;
 1311         IP_COPY_VALUE( scb->client_ip, GET_DST_IP( p ) );
 1312         scb->client_port = p->tcph->th_dport;
 1313         IP_COPY_VALUE( scb->server_ip, GET_SRC_IP( p ) );
 1314         scb->server_port = p->tcph->th_sport;
 1315     }
 1316     else
 1317     {
 1318         /* Assume from client, can update later */
 1319         if( p->sp > p->dp )
 1320         {
 1321             scb->ha_state.direction = FROM_CLIENT;
 1322             IP_COPY_VALUE( scb->client_ip, GET_SRC_IP( p ) );
 1323             scb->client_port = p->tcph->th_sport;
 1324             IP_COPY_VALUE( scb->server_ip, GET_DST_IP( p ) );
 1325             scb->server_port = p->tcph->th_dport;
 1326         }
 1327         else
 1328         {
 1329             scb->ha_state.direction = FROM_SERVER;
 1330             IP_COPY_VALUE( scb->client_ip, GET_DST_IP( p ) );
 1331             scb->client_port = p->tcph->th_dport;
 1332             IP_COPY_VALUE( scb->server_ip, GET_SRC_IP( p ) );
 1333             scb->server_port = p->tcph->th_sport;
 1334         }
 1335     }
 1336 }
 1337 void StreamInitTcp( void )
 1338 {
 1339     if( tcp_lws_cache == NULL )
 1340     {
 1341         tcp_lws_cache = session_api->init_session_cache( SESSION_PROTO_TCP,
 1342                 sizeof( TcpSession ),
 1343                 &TcpSessionCleanupWithFreeApplicationData );
 1344         StreamTcpRegisterPreprocProfiles();
 1345     }
 1346 #ifdef ENABLE_HA
 1347     ha_set_api( IPPROTO_TCP, &ha_tcp_api );
 1348 #endif
 1349 
 1350     pkt_snaplen = (snort_conf->pkt_snaplen > 0) ? snort_conf->pkt_snaplen : PKT_SNAPLEN;
 1351 }
 1352 
 1353 void StreamTcpRegisterPreprocProfiles( void )
 1354 {
 1355 #ifdef PERF_PROFILING
 1356     RegisterPreprocessorProfile( "s5TcpNewSess", &s5TcpNewSessPerfStats, 2, &s5TcpPerfStats , NULL);
 1357     RegisterPreprocessorProfile( "s5TcpState", &s5TcpStatePerfStats, 2, &s5TcpPerfStats , NULL);
 1358     RegisterPreprocessorProfile( "s5TcpData", &s5TcpDataPerfStats, 3, &s5TcpStatePerfStats , NULL);
 1359     RegisterPreprocessorProfile( "s5TcpPktInsert", &s5TcpInsertPerfStats, 4, &s5TcpDataPerfStats , NULL);
 1360     RegisterPreprocessorProfile( "s5TcpPAF", &s5TcpPAFPerfStats, 3, &s5TcpStatePerfStats , NULL);
 1361     RegisterPreprocessorProfile( "s5TcpFlush", &s5TcpFlushPerfStats, 3, &s5TcpStatePerfStats , NULL);
 1362     RegisterPreprocessorProfile( "s5TcpBuildPacket", &s5TcpBuildPacketPerfStats, 4, &s5TcpFlushPerfStats , NULL);
 1363     RegisterPreprocessorProfile( "s5TcpProcessRebuilt", &s5TcpProcessRebuiltPerfStats,
 1364             4, &s5TcpFlushPerfStats, NULL );
 1365 #endif
 1366 }
 1367 
 1368 void StreamTcpRegisterRuleOptions( struct _SnortConfig *sc )
 1369 {
 1370     /* Register the 'stream_size' rule option */
 1371     RegisterPreprocessorRuleOption( sc, "stream_size", &s5TcpStreamSizeInit,
 1372             &s5TcpStreamSizeEval, &s5TcpStreamSizeCleanup,
 1373             NULL, NULL, NULL, NULL );
 1374 
 1375     RegisterPreprocessorRuleOption( sc, "stream_reassemble", &s5TcpStreamReassembleRuleOptionInit,
 1376             &s5TcpStreamReassembleRuleOptionEval,
 1377             &s5TcpStreamReassembleRuleOptionCleanup,
 1378             NULL, NULL, NULL, NULL );
 1379 #ifdef PERF_PROFILING
 1380     RegisterPreprocessorProfile( "stream_size", &streamSizePerfStats, 4, &preprocRuleOptionPerfStats , NULL);
 1381     RegisterPreprocessorProfile( "reassemble", &streamReassembleRuleOptionPerfStats,
 1382             4, &preprocRuleOptionPerfStats, NULL);
 1383 #endif
 1384 }
 1385 
 1386 void StreamTcpInitFlushPoints( void )
 1387 {
 1388     int i;
 1389 
 1390     /* Seed the flushpoint random generator */
 1391     srand( ( unsigned int ) sizeof( default_ports ) + ( unsigned int ) time( NULL ) );
 1392 
 1393     /* Default is to ignore, for all ports */
 1394     for( i = 0; i < MAX_PORTS; i++ )
 1395     {
 1396         ignore_flush_policy[i].client.flush_policy = STREAM_FLPOLICY_IGNORE;
 1397         ignore_flush_policy[i].server.flush_policy = STREAM_FLPOLICY_IGNORE;
 1398     }
 1399 #ifdef TARGET_BASED
 1400     for( i = 0; i < MAX_PROTOCOL_ORDINAL; i++)
 1401     {
 1402         ignore_flush_policy_protocol[i].client.flush_policy = STREAM_FLPOLICY_IGNORE;
 1403         ignore_flush_policy_protocol[i].server.flush_policy = STREAM_FLPOLICY_IGNORE;
 1404     }
 1405 #endif
 1406 }
 1407 
 1408 static void addStreamTcpPolicyToList( StreamTcpConfig *config, StreamTcpPolicy *policy )
 1409 {
 1410     config->num_policies++;
 1411 
 1412     /* Now add this context to the internal list */
 1413     if( config->policy_list == NULL )
 1414     {
 1415         config->policy_list = ( StreamTcpPolicy ** ) SnortAlloc( sizeof( StreamTcpPolicy * ) );
 1416     }
 1417     else
 1418     {
 1419         uint32_t policyListSize = sizeof( StreamTcpPolicy * ) * ( config->num_policies );
 1420         StreamTcpPolicy **tmpPolicyList = ( StreamTcpPolicy ** ) SnortAlloc( policyListSize );
 1421 
 1422         // copy the existing policies to new list, free old list and point to new...
 1423         memcpy( tmpPolicyList, config->policy_list, policyListSize - sizeof( StreamTcpPolicy * ) );
 1424         free( config->policy_list );
 1425         config->policy_list = tmpPolicyList;
 1426     }
 1427 
 1428     // add new policy to end of the list
 1429     config->policy_list[config->num_policies - 1] = policy;
 1430 }
 1431 
 1432 StreamTcpPolicy *initTcpPolicyInstance( void )
 1433 {
 1434     StreamTcpPolicy *tcp_policy = (StreamTcpPolicy *) SnortAlloc(sizeof(StreamTcpPolicy));
 1435 
 1436     /* Initialize flush policy to Ignore */
 1437     memcpy(&tcp_policy->flush_config, ignore_flush_policy,
 1438             sizeof(FlushConfig) * MAX_PORTS);
 1439 #ifdef TARGET_BASED
 1440     memcpy(&tcp_policy->flush_config_protocol, ignore_flush_policy_protocol,
 1441             sizeof(FlushConfig) * MAX_PROTOCOL_ORDINAL);
 1442 #endif
 1443 
 1444     return tcp_policy;
 1445 }
 1446 
 1447 StreamTcpPolicy *StreamTcpPolicyClone( StreamTcpPolicy *master )
 1448 {
 1449     StreamConfig *config;
 1450     StreamTcpPolicy *clone = initTcpPolicyInstance( );
 1451 
 1452     clone->policy = master->policy;
 1453     clone->reassembly_policy = master->reassembly_policy;
 1454     clone->flags = master->flags;
 1455     clone->flush_factor = master->flush_factor;
 1456     clone->session_timeout = master->session_timeout;
 1457     clone->max_window = master->max_window;
 1458     clone->overlap_limit = master->overlap_limit;
 1459     clone->hs_timeout = master->hs_timeout;
 1460     clone->max_queued_bytes = master->max_queued_bytes;
 1461     clone->max_queued_segs = master->max_queued_segs;
 1462     clone->max_consec_small_segs = master->max_consec_small_segs;
 1463     clone->max_consec_small_seg_size = master->max_consec_small_seg_size;
 1464     memcpy(clone->small_seg_ignore, master->small_seg_ignore, sizeof(master->small_seg_ignore));
 1465 
 1466     config = (StreamConfig *) sfPolicyUserDataGet(stream_online_config, getParserPolicy( snort_conf ));
 1467     addStreamTcpPolicyToList( config->tcp_config, clone );
 1468 
 1469     return clone;
 1470 }
 1471 
 1472 void StreamTcpPolicyInit(struct _SnortConfig *sc, StreamTcpConfig *config, char *args)
 1473 {
 1474     StreamTcpPolicy *s5TcpPolicy;
 1475 
 1476     if (config == NULL)
 1477         return;
 1478 
 1479     // create list for caching port reassembly requests...
 1480     StreamCreateReassemblyPortList( );
 1481 
 1482     s5TcpPolicy = initTcpPolicyInstance( );
 1483     StreamParseTcpArgs(sc, config, args, s5TcpPolicy);
 1484     addStreamTcpPolicyToList( config, s5TcpPolicy );
 1485 
 1486     if ( ScPafEnabledNewConf(sc) && !config->paf_config )
 1487         config->paf_config = s5_paf_new();
 1488 
 1489     // register callback with Session that determines direction and client/server ports
 1490     registerDirectionPortCallback( SESSION_PROTO_TCP, setTcpDirectionAndPorts );
 1491 
 1492     StreamPrintTcpConfig(s5TcpPolicy);
 1493 
 1494 #ifdef REG_TEST
 1495     LogMessage("    TCP Session Size: %lu\n", (long unsigned int)sizeof(TcpSession));
 1496 #endif
 1497 }
 1498 
 1499 static inline uint16_t StreamPolicyIdFromName(char *name)
 1500 {
 1501     if (!name)
 1502     {
 1503         return STREAM_POLICY_DEFAULT;
 1504     }
 1505 
 1506     if(!strcasecmp(name, "bsd"))
 1507     {
 1508         return STREAM_POLICY_BSD;
 1509     }
 1510     else if(!strcasecmp(name, "old-linux"))
 1511     {
 1512         return STREAM_POLICY_OLD_LINUX;
 1513     }
 1514     else if(!strcasecmp(name, "linux"))
 1515     {
 1516         return STREAM_POLICY_LINUX;
 1517     }
 1518     else if(!strcasecmp(name, "first"))
 1519     {
 1520         return STREAM_POLICY_FIRST;
 1521     }
 1522     else if(!strcasecmp(name, "noack"))
 1523     {
 1524         return STREAM_POLICY_NOACK;
 1525     }
 1526     else if(!strcasecmp(name, "last"))
 1527     {
 1528         return STREAM_POLICY_LAST;
 1529     }
 1530     else if(!strcasecmp(name, "windows"))
 1531     {
 1532         return STREAM_POLICY_WINDOWS;
 1533     }
 1534     else if(!strcasecmp(name, "solaris"))
 1535     {
 1536         return STREAM_POLICY_SOLARIS;
 1537     }
 1538     else if(!strcasecmp(name, "win2003") ||
 1539             !strcasecmp(name, "win2k3"))
 1540     {
 1541         return STREAM_POLICY_WINDOWS2K3;
 1542     }
 1543     else if(!strcasecmp(name, "vista"))
 1544     {
 1545         return STREAM_POLICY_VISTA;
 1546     }
 1547     else if(!strcasecmp(name, "hpux") ||
 1548             !strcasecmp(name, "hpux11"))
 1549     {
 1550         return STREAM_POLICY_HPUX11;
 1551     }
 1552     else if(!strcasecmp(name, "hpux10"))
 1553     {
 1554         return STREAM_POLICY_HPUX10;
 1555     }
 1556     else if(!strcasecmp(name, "irix"))
 1557     {
 1558         return STREAM_POLICY_IRIX;
 1559     }
 1560     else if(!strcasecmp(name, "macos") ||
 1561             !strcasecmp(name, "grannysmith"))
 1562     {
 1563         return STREAM_POLICY_MACOS;
 1564     }
 1565     return STREAM_POLICY_DEFAULT; /* BSD is the default */
 1566 }
 1567 
 1568 static inline uint16_t GetTcpReassemblyPolicy(int os_policy)
 1569 {
 1570     switch (os_policy)
 1571     {
 1572         case STREAM_POLICY_FIRST:
 1573             return REASSEMBLY_POLICY_FIRST;
 1574         case STREAM_POLICY_LINUX:
 1575             return REASSEMBLY_POLICY_LINUX;
 1576         case STREAM_POLICY_BSD:
 1577             return REASSEMBLY_POLICY_BSD;
 1578         case STREAM_POLICY_OLD_LINUX:
 1579             return REASSEMBLY_POLICY_OLD_LINUX;
 1580         case STREAM_POLICY_LAST:
 1581             return REASSEMBLY_POLICY_LAST;
 1582         case STREAM_POLICY_WINDOWS:
 1583             return REASSEMBLY_POLICY_WINDOWS;
 1584         case STREAM_POLICY_SOLARIS:
 1585             return REASSEMBLY_POLICY_SOLARIS;
 1586         case STREAM_POLICY_WINDOWS2K3:
 1587             return REASSEMBLY_POLICY_WINDOWS2K3;
 1588         case STREAM_POLICY_VISTA:
 1589             return REASSEMBLY_POLICY_VISTA;
 1590         case STREAM_POLICY_HPUX11:
 1591             return REASSEMBLY_POLICY_HPUX11;
 1592         case STREAM_POLICY_HPUX10:
 1593             return REASSEMBLY_POLICY_HPUX10;
 1594         case STREAM_POLICY_IRIX:
 1595             return REASSEMBLY_POLICY_IRIX;
 1596         case STREAM_POLICY_MACOS:
 1597             return REASSEMBLY_POLICY_MACOS;
 1598         case STREAM_POLICY_NOACK:
 1599             return REASSEMBLY_POLICY_NOACK;
 1600         default:
 1601             return REASSEMBLY_POLICY_DEFAULT;
 1602     }
 1603 }
 1604 
 1605 #define STATIC_FP ((s5TcpPolicy->flags & STREAM_CONFIG_STATIC_FLUSHPOINTS)?1:0)
 1606 
 1607 static void StreamParseTcpArgs(struct _SnortConfig *sc, StreamTcpConfig *config, char *args, StreamTcpPolicy *s5TcpPolicy)
 1608 {
 1609     char **toks;
 1610     int num_toks;
 1611     int i;
 1612     char **stoks = NULL;
 1613     int s_toks;
 1614     char *endPtr = NULL;
 1615     char set_flush_policy = 0;
 1616 #ifdef TARGET_BASED
 1617     char set_target_flush_policy = 0;
 1618 #endif
 1619     int reassembly_direction = SSN_DIR_FROM_CLIENT;
 1620     int32_t long_val = 0;
 1621 
 1622     s5TcpPolicy->policy = STREAM_POLICY_DEFAULT;
 1623     s5TcpPolicy->reassembly_policy = REASSEMBLY_POLICY_DEFAULT;
 1624     s5TcpPolicy->session_timeout = STREAM_DEFAULT_SSN_TIMEOUT;
 1625     s5TcpPolicy->max_window = 0;
 1626     s5TcpPolicy->flags = 0;
 1627     s5TcpPolicy->max_queued_bytes = STREAM_DEFAULT_MAX_QUEUED_BYTES;
 1628     s5TcpPolicy->max_queued_segs = STREAM_DEFAULT_MAX_QUEUED_SEGS;
 1629 
 1630     s5TcpPolicy->max_consec_small_segs = STREAM_DEFAULT_CONSEC_SMALL_SEGS;
 1631     s5TcpPolicy->max_consec_small_seg_size = STREAM_DEFAULT_MAX_SMALL_SEG_SIZE;
 1632     s5TcpPolicy->log_asymmetric_traffic = false;
 1633 
 1634     if(args != NULL && strlen(args) != 0)
 1635     {
 1636         toks = mSplit(args, ",", 0, &num_toks, 0);
 1637 
 1638         for (i = 0; i < num_toks; i++)
 1639         {
 1640             if(!strcasecmp(toks[i], "use_static_footprint_sizes"))
 1641                 s5TcpPolicy->flags |= STREAM_CONFIG_STATIC_FLUSHPOINTS;
 1642         }
 1643 
 1644         for (i = 0; i < num_toks; i++)
 1645         {
 1646             int max_s_toks = 1;  // set to 0 to disable check
 1647             stoks = mSplit(toks[i], " ", 3, &s_toks, 0);
 1648 
 1649             if (s_toks == 0)
 1650             {
 1651                 FatalError("%s(%d) => Missing parameter in Stream TCP config.\n",
 1652                         file_name, file_line);
 1653             }
 1654 
 1655             if(!strcasecmp(stoks[0], "timeout"))
 1656             {
 1657                 if(stoks[1])
 1658                 {
 1659                     s5TcpPolicy->session_timeout = strtoul(stoks[1], &endPtr, 10);
 1660                 }
 1661 
 1662                 if (!stoks[1] || (endPtr == &stoks[1][0]) || *endPtr)
 1663                 {
 1664                     FatalError("%s(%d) => Invalid timeout in config file.  "
 1665                             "Integer parameter required.\n",
 1666                             file_name, file_line);
 1667                 }
 1668 
 1669                 if ((s5TcpPolicy->session_timeout > STREAM_MAX_SSN_TIMEOUT) ||
 1670                         (s5TcpPolicy->session_timeout < STREAM_MIN_SSN_TIMEOUT))
 1671                 {
 1672                     FatalError("%s(%d) => Invalid timeout in config file.  "
 1673                             "Must be between %d and %d\n",
 1674                             file_name, file_line,
 1675                             STREAM_MIN_SSN_TIMEOUT, STREAM_MAX_SSN_TIMEOUT);
 1676                 }
 1677                 max_s_toks = 2;
 1678             }
 1679             else if(!strcasecmp(stoks[0], "log_asymmetric_traffic"))
 1680             {
 1681                 if(stoks[1])
 1682                 {
 1683                     if(!strcasecmp(stoks[1], "no"))
 1684                            s5TcpPolicy->log_asymmetric_traffic = false;
 1685                     else if(!strcasecmp(stoks[1], "yes"))
 1686                            s5TcpPolicy->log_asymmetric_traffic = true;
 1687                     else
 1688                            FatalError("%s(%d) => invalid: value must be 'yes' or 'no'\n", file_name, file_line);
 1689                 }
 1690                 else
 1691                 {
 1692                     FatalError("%s(%d) => 'log_asymmetric_traffic' missing option\n", file_name, file_line);
 1693                 }
 1694                 max_s_toks = 2;
 1695             }
 1696             else if(!strcasecmp(stoks[0], "overlap_limit"))
 1697             {
 1698                 if(stoks[1])
 1699                 {
 1700                     long_val = SnortStrtol(stoks[1], &endPtr, 10);
 1701                     if (errno == ERANGE)
 1702                     {
 1703                         errno = 0;
 1704                         long_val = -1;
 1705                     }
 1706                     s5TcpPolicy->overlap_limit = (uint8_t)long_val;
 1707                 }
 1708 
 1709                 if (!stoks[1] || (endPtr == &stoks[1][0]))
 1710                 {
 1711                     FatalError("%s(%d) => Invalid overlap limit in config file."
 1712                             "Integer parameter required\n",
 1713                             file_name, file_line);
 1714                 }
 1715 
 1716                 if ((long_val > STREAM_MAX_OVERLAP_LIMIT) ||
 1717                         (long_val < STREAM_MIN_OVERLAP_LIMIT))
 1718                 {
 1719                     FatalError("%s(%d) => Invalid overlap limit in config file."
 1720                             "  Must be between %d and %d\n",
 1721                             file_name, file_line,
 1722                             STREAM_MIN_OVERLAP_LIMIT, STREAM_MAX_OVERLAP_LIMIT);
 1723                 }
 1724                 max_s_toks = 2;
 1725             }
 1726             else if(!strcasecmp(stoks[0], "detect_anomalies"))
 1727             {
 1728                 s5TcpPolicy->flags |=  STREAM_CONFIG_ENABLE_ALERTS;
 1729             }
 1730             else if(!strcasecmp(stoks[0], "policy"))
 1731             {
 1732                 if(s_toks != 2)
 1733                     ParseError("Invalid Stream TCP policy option");
 1734                 s5TcpPolicy->policy = StreamPolicyIdFromName(stoks[1]);
 1735 
 1736                 if ((s5TcpPolicy->policy == STREAM_POLICY_DEFAULT) &&
 1737                         (strcasecmp(stoks[1], "bsd")))
 1738                 {
 1739                     /* Default is BSD.  If we don't have "bsd", its
 1740                      * the default and invalid.
 1741                      */
 1742                     FatalError("%s(%d) => Bad policy name \"%s\"\n",
 1743                             file_name, file_line, stoks[1]);
 1744                 }
 1745                 s5TcpPolicy->reassembly_policy =
 1746                     GetTcpReassemblyPolicy(s5TcpPolicy->policy);
 1747 
 1748                 max_s_toks = 2;
 1749             }
 1750             else if(!strcasecmp(stoks[0], "require_3whs"))
 1751             {
 1752                 s5TcpPolicy->flags |= STREAM_CONFIG_REQUIRE_3WHS;
 1753 
 1754                 if (s_toks > 1)
 1755                 {
 1756                     s5TcpPolicy->hs_timeout = SnortStrtoul(stoks[1], &endPtr, 10);
 1757 
 1758                     if ((endPtr == &stoks[1][0]) || (*endPtr != '\0') || (errno == ERANGE))
 1759                     {
 1760                         FatalError("%s(%d) => Invalid 3Way Handshake allowable.  Integer parameter required.\n",
 1761                                 file_name, file_line);
 1762                     }
 1763 
 1764                     if (s5TcpPolicy->hs_timeout > STREAM_MAX_SSN_TIMEOUT)
 1765                     {
 1766                         FatalError("%s(%d) => Invalid handshake timeout in "
 1767                                 "config file.  Must be between %d and %d\n",
 1768                                 file_name, file_line,
 1769                                 STREAM_MIN_ALT_HS_TIMEOUT, STREAM_MAX_SSN_TIMEOUT);
 1770                     }
 1771                 }
 1772 
 1773                 max_s_toks = 2;
 1774             }
 1775             else if(!strcasecmp(stoks[0], "bind_to"))
 1776             {
 1777                 if (s_toks < 2)
 1778                 {
 1779                     FatalError("%s(%d) => Invalid Stream TCP Policy option - "
 1780                             "\"bind_to\" option requires an argument.\n",
 1781                             file_name, file_line);
 1782                 }
 1783 
 1784                 if(strstr(stoks[1], "["))
 1785                 {
 1786                     FatalError("%s(%d) => Invalid Stream TCP Policy option.  IP lists are not allowed.\n",
 1787                             file_name, file_line);
 1788                 }
 1789 
 1790                 s5TcpPolicy->bound_addrs = IpAddrSetParse(sc, stoks[1]);
 1791                 max_s_toks = 2;
 1792             }
 1793             else if(!strcasecmp(stoks[0], "max_window"))
 1794             {
 1795                 if(stoks[1])
 1796                 {
 1797                     long_val = SnortStrtol(stoks[1], &endPtr, 10);
 1798                     if (errno == ERANGE)
 1799                     {
 1800                         errno = 0;
 1801                         FatalError("%s(%d) => Invalid Max Window size.  Integer parameter required.\n",
 1802                                 file_name, file_line);
 1803                     }
 1804                     s5TcpPolicy->max_window = (uint32_t)long_val;
 1805                 }
 1806 
 1807                 if (!stoks[1] || (endPtr == &stoks[1][0]))
 1808                 {
 1809                     FatalError("%s(%d) => Invalid Max Window size.  Integer parameter required.\n",
 1810                             file_name, file_line);
 1811                 }
 1812 
 1813                 if ((long_val > STREAM_MAX_MAX_WINDOW) ||
 1814                         (long_val < STREAM_MIN_MAX_WINDOW))
 1815                 {
 1816                     FatalError("%s(%d) => Invalid Max Window size."
 1817                             "  Must be between %d and %d\n",
 1818                             file_name, file_line,
 1819                             STREAM_MIN_MAX_WINDOW, STREAM_MAX_MAX_WINDOW);
 1820                 }
 1821                 max_s_toks = 2;
 1822             }
 1823             else if(!strcasecmp(stoks[0], "use_static_footprint_sizes"))
 1824             {
 1825                 // we already handled this one above
 1826             }
 1827             else if(!strcasecmp(stoks[0], "flush_factor"))
 1828             {
 1829                 if (stoks[1])
 1830                 {
 1831                     s5TcpPolicy->flush_factor = (uint16_t)SnortStrtoulRange(
 1832                             stoks[1], &endPtr, 10, 0, STREAM_MAX_FLUSH_FACTOR);
 1833                 }
 1834                 if (
 1835                         (!stoks[1] || (endPtr == &stoks[1][0])) ||
 1836                         (s5TcpPolicy->flush_factor > STREAM_MAX_FLUSH_FACTOR))
 1837                 {
 1838                     FatalError("%s(%d) => 'flush_factor %d' invalid: "
 1839                             "value must be between 0 and %d segments.\n",
 1840                             file_name, file_line, s5TcpPolicy->flush_factor,
 1841                             STREAM_MAX_FLUSH_FACTOR);
 1842                 }
 1843                 max_s_toks = 2;
 1844             }
 1845             else if(!strcasecmp(stoks[0], "dont_store_large_packets"))
 1846             {
 1847                 s5TcpPolicy->flags |= STREAM_CONFIG_PERFORMANCE;
 1848             }
 1849             else if(!strcasecmp(stoks[0], "check_session_hijacking"))
 1850             {
 1851                 s5TcpPolicy->flags |= STREAM_CONFIG_CHECK_SESSION_HIJACKING;
 1852             }
 1853             else if(!strcasecmp(stoks[0], "ignore_any_rules"))
 1854             {
 1855                 s5TcpPolicy->flags |= STREAM_CONFIG_IGNORE_ANY;
 1856             }
 1857             else if(!strcasecmp(stoks[0], "dont_reassemble_async"))
 1858             {
 1859                 s5TcpPolicy->flags |= STREAM_CONFIG_NO_ASYNC_REASSEMBLY;
 1860             }
 1861             else if(!strcasecmp(stoks[0], "max_queued_bytes"))
 1862             {
 1863                 if(stoks[1])
 1864                 {
 1865                     long_val = SnortStrtol(stoks[1], &endPtr, 10);
 1866                     if (errno == ERANGE)
 1867                     {
 1868                         errno = 0;
 1869                         FatalError("%s(%d) => Invalid Max Queued Bytes.  Integer parameter required.\n",
 1870                                 file_name, file_line);
 1871                     }
 1872                     s5TcpPolicy->max_queued_bytes = (uint32_t)long_val;
 1873                 }
 1874 
 1875                 if (!stoks[1] || (endPtr == &stoks[1][0]))
 1876                 {
 1877                     FatalError("%s(%d) => Invalid Max Queued Bytes.  Integer parameter required.\n",
 1878                             file_name, file_line);
 1879                 }
 1880                 if (((long_val > STREAM_MAX_MAX_QUEUED_BYTES) ||
 1881                             (long_val < STREAM_MIN_MAX_QUEUED_BYTES)) &&
 1882                         (long_val != 0))
 1883                 {
 1884                     FatalError("%s(%d) => Invalid Max Queued Bytes."
 1885                             "  Must be 0 (disabled) or between %d and %d\n",
 1886                             file_name, file_line,
 1887                             STREAM_MIN_MAX_QUEUED_BYTES, STREAM_MAX_MAX_QUEUED_BYTES);
 1888                 }
 1889                 max_s_toks = 2;
 1890             }
 1891             else if(!strcasecmp(stoks[0], "max_queued_segs"))
 1892             {
 1893                 if(stoks[1])
 1894                 {
 1895                     long_val = SnortStrtol(stoks[1], &endPtr, 10);
 1896                     if (errno == ERANGE)
 1897                     {
 1898                         errno = 0;
 1899                         FatalError("%s(%d) => Invalid Max Queued Bytes.  Integer parameter required.\n",
 1900                                 file_name, file_line);
 1901                     }
 1902                     s5TcpPolicy->max_queued_segs = (uint32_t)long_val;
 1903                 }
 1904 
 1905                 if (!stoks[1] || (endPtr == &stoks[1][0]))
 1906                 {
 1907                     FatalError("%s(%d) => Invalid Max Queued Bytes.  Integer parameter required.\n",
 1908                             file_name, file_line);
 1909                 }
 1910 
 1911                 if (((long_val > STREAM_MAX_MAX_QUEUED_SEGS) ||
 1912                             (long_val < STREAM_MIN_MAX_QUEUED_SEGS)) &&
 1913                         (long_val != 0))
 1914                 {
 1915                     FatalError("%s(%d) => Invalid Max Queued Bytes."
 1916                             "  Must be 0 (disabled) or between %d and %d\n",
 1917                             file_name, file_line,
 1918                             STREAM_MIN_MAX_QUEUED_SEGS, STREAM_MAX_MAX_QUEUED_SEGS);
 1919                 }
 1920                 max_s_toks = 2;
 1921             }
 1922             else if (!strcasecmp(stoks[0], "small_segments"))
 1923             {
 1924                 char **ptoks;
 1925                 int num_ptoks;
 1926 
 1927                 /* Small segments takes at least 3 parameters... */
 1928                 if (s_toks < 3)
 1929                 {
 1930                     FatalError("%s(%d) => Insufficient parameters to small "
 1931                             "segments configuration.  Syntax is: "
 1932                             "<number> bytes <number> ignore_ports p1 p2, "
 1933                             "with ignore_ports being an optional parameter\n",
 1934                             file_name, file_line);
 1935                 }
 1936 
 1937                 /* first the number of consecutive segments */
 1938                 long_val = SnortStrtol(stoks[1], &endPtr, 10);
 1939                 if (errno == ERANGE)
 1940                 {
 1941                     errno = 0;
 1942                     FatalError("%s(%d) => Invalid Small Segment number.  Integer parameter required.\n",
 1943                             file_name, file_line);
 1944                 }
 1945                 s5TcpPolicy->max_consec_small_segs = (uint32_t)long_val;
 1946 
 1947                 if ((long_val > STREAM_MAX_CONSEC_SMALL_SEGS) ||
 1948                         (long_val < STREAM_MIN_CONSEC_SMALL_SEGS))
 1949                 {
 1950                     FatalError("%s(%d) => Invalid Small Segments."
 1951                             "  Must be integer between %d and %d, inclusive\n",
 1952                             file_name, file_line,
 1953                             STREAM_MIN_CONSEC_SMALL_SEGS, STREAM_MAX_CONSEC_SMALL_SEGS);
 1954                 }
 1955 
 1956                 ptoks = mSplit(stoks[2], " ", MAX_PORTS + 3, &num_ptoks, 0);
 1957 
 1958                 /* the bytes keyword */
 1959                 if (strcasecmp(ptoks[0], "bytes") || (num_ptoks < 2))
 1960                 {
 1961                     FatalError("%s(%d) => Insufficient parameters to small "
 1962                             "segments configuration.  Syntax is: "
 1963                             "<number> bytes <number> ignore_ports p1 p2, "
 1964                             "with ignore_ports being an optional parameter\n",
 1965                             file_name, file_line);
 1966                 }
 1967 
 1968                 /* the minimum bytes for a segment to be considered "small" */
 1969                 long_val = SnortStrtol(ptoks[1], &endPtr, 10);
 1970                 if (errno == ERANGE)
 1971                 {
 1972                     errno = 0;
 1973                     FatalError("%s(%d) => Invalid Small Segment bytes.  Integer parameter required.\n",
 1974                             file_name, file_line);
 1975                 }
 1976                 s5TcpPolicy->max_consec_small_seg_size = (uint32_t)long_val;
 1977 
 1978                 if ((long_val > STREAM_MAX_MAX_SMALL_SEG_SIZE) ||
 1979                         (long_val < STREAM_MIN_MAX_SMALL_SEG_SIZE))
 1980                 {
 1981                     FatalError("%s(%d) => Invalid Small Segments bytes."
 1982                             "  Must be integer between %d and %d, inclusive\n",
 1983                             file_name, file_line,
 1984                             STREAM_MIN_MAX_SMALL_SEG_SIZE, STREAM_MAX_MAX_SMALL_SEG_SIZE);
 1985                 }
 1986 
 1987                 /* and the optional ignore_ports */
 1988                 if (num_ptoks > 2)
 1989                 {
 1990                     int j;
 1991                     unsigned short port = 0;
 1992                     long long_port = 0;
 1993                     if (strcasecmp(ptoks[2], "ignore_ports") || (num_ptoks < 4))
 1994                     {
 1995                         FatalError("%s(%d) => Insufficient parameters to small "
 1996                                 "segments configuration.  Syntax is: "
 1997                                 "<number> bytes <number> ignore_ports p1 p2, "
 1998                                 "with ignore_ports being an optional parameter\n",
 1999                                 file_name, file_line);
 2000                     }
 2001 
 2002                     for (j=3; j<num_ptoks;j++)
 2003                     {
 2004                         if (ptoks[j])
 2005                         {
 2006                             long_port = strtol(ptoks[j], &endPtr, 10);
 2007                         }
 2008                         if (!ptoks[j] || (endPtr == &ptoks[j][0]))
 2009                         {
 2010                             FatalError("%s(%d) => Invalid Port for small segments ignore_ports parameter.  Integer parameter required.\n",
 2011                                     file_name, file_line);
 2012                         }
 2013 
 2014                         if ((long_port < 0) || (long_port > MAX_PORTS-1))
 2015                         {
 2016                             FatalError(
 2017                                     "%s(%d) => Invalid port %ld for small segments ignore_ports "
 2018                                     "parameter, must be between 0 and %d, inclusive\n",
 2019                                     file_name, file_line, long_port, MAX_PORTS-1);
 2020                         }
 2021                         port = (unsigned short)long_port;
 2022 
 2023                         s5TcpPolicy->small_seg_ignore[port/8] |= (1 << (port %8));
 2024                     }
 2025                 }
 2026                 max_s_toks = 0; // we already checked all tokens
 2027                 mSplitFree(&ptoks, num_ptoks);
 2028             }
 2029             else if (!strcasecmp(stoks[0], "ports"))
 2030             {
 2031                 if (s_toks > 1)
 2032                 {
 2033                     if(!strcasecmp(stoks[1], "client"))
 2034                     {
 2035                         reassembly_direction = SSN_DIR_FROM_CLIENT;
 2036                     }
 2037                     else if(!strcasecmp(stoks[1], "server"))
 2038                     {
 2039                         reassembly_direction = SSN_DIR_FROM_SERVER;
 2040                     }
 2041                     else if(!strcasecmp(stoks[1], "both"))
 2042                     {
 2043                         reassembly_direction = SSN_DIR_BOTH;
 2044                     }
 2045                     else
 2046                     {
 2047                         FatalError(
 2048                                 "%s(%d) => Invalid direction for reassembly "
 2049                                 "configuration \"%s\".  Valid values are 'client', "
 2050                                 "'server', or 'both'.\n",
 2051                                 file_name, file_line, stoks[1]);
 2052                     }
 2053                 }
 2054 
 2055                 if (s_toks > 2)
 2056                 {
 2057                     char **ptoks;
 2058                     int num_ptoks;
 2059                     int j;
 2060                     unsigned short port = 0;
 2061                     long long_port = 0;
 2062 
 2063                     /* Initialize it if not already... */
 2064                     InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP);
 2065 
 2066                     if (!strcasecmp(stoks[2], "all"))
 2067                     {
 2068                         for (j=0; j<MAX_PORTS; j++)
 2069                         {
 2070                             if (reassembly_direction & SSN_DIR_FROM_CLIENT)
 2071                             {
 2072                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].client;
 2073                                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2074                                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2075                             }
 2076                             if (reassembly_direction & SSN_DIR_FROM_SERVER)
 2077                             {
 2078                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].server;
 2079                                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2080                                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2081                             }
 2082                         }
 2083                     }
 2084                     else if (!strcasecmp(stoks[2], "none"))
 2085                     {
 2086                         for (j=0; j<MAX_PORTS; j++)
 2087                         {
 2088                             if (reassembly_direction & SSN_DIR_FROM_CLIENT)
 2089                             {
 2090                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].client;
 2091                                 flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE;
 2092                             }
 2093                             if (reassembly_direction & SSN_DIR_FROM_SERVER)
 2094                             {
 2095                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].server;
 2096                                 flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE;
 2097                             }
 2098                         }
 2099                     }
 2100                     else
 2101                     {
 2102                         ptoks = mSplit(stoks[2], " ", MAX_PORTS, &num_ptoks, 0);
 2103 
 2104                         for (j=0; j < num_ptoks; j++)
 2105                         {
 2106                             FlushPolicy flush_policy = STREAM_FLPOLICY_FOOTPRINT;
 2107 
 2108                             if (ptoks[j])
 2109                             {
 2110                                 // check for '!' not port syntax used to disable reassembly on a port
 2111                                 // even if requested later by a preproc...
 2112                                 if ( ptoks[j][0] == '!' )
 2113                                 {
 2114                                     flush_policy = STREAM_FLPOLICY_DISABLED;
 2115                                     long_port = strtol(&ptoks[j][1], &endPtr, 10);
 2116                                 }
 2117                                 else
 2118                                 {
 2119                                     long_port = strtol(ptoks[j], &endPtr, 10);
 2120                                 }
 2121                             }
 2122 
 2123                             if (!ptoks[j] || (endPtr == &ptoks[j][0]))
 2124                             {
 2125                                 FatalError("%s(%d) => Invalid Port list.  Integer parameter required.\n",
 2126                                         file_name, file_line);
 2127                             }
 2128 
 2129                             if ((long_port < 0) || (long_port > MAX_PORTS-1))
 2130                             {
 2131                                 FatalError(
 2132                                         "%s(%d) => Invalid port %ld, must be between 0 and %d, "
 2133                                         "inclusive\n",
 2134                                         file_name, file_line, long_port, MAX_PORTS-1);
 2135                             }
 2136                             port = (unsigned short)long_port;
 2137 
 2138                             if (reassembly_direction & SSN_DIR_FROM_CLIENT)
 2139                             {
 2140                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[port].client;
 2141                                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2142                                 InitFlushMgr(sc, flush_mgr, flush_point_list, flush_policy, 0);
 2143                             }
 2144                             if (reassembly_direction & SSN_DIR_FROM_SERVER)
 2145                             {
 2146                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[port].server;
 2147                                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2148                                 InitFlushMgr(sc, flush_mgr, flush_point_list, flush_policy, 0);
 2149                             }
 2150                         }
 2151                         mSplitFree(&ptoks, num_ptoks);
 2152                     }
 2153                     set_flush_policy = 1;
 2154                 }
 2155                 max_s_toks = 0;  // we already checked all tokens
 2156             }
 2157 #ifdef TARGET_BASED
 2158             else if (!strcasecmp(stoks[0], "protocol"))
 2159             {
 2160                 if (s_toks > 1)
 2161                 {
 2162                     if(!strcasecmp(stoks[1], "client"))
 2163                     {
 2164                         reassembly_direction = SSN_DIR_FROM_CLIENT;
 2165                     }
 2166                     else if(!strcasecmp(stoks[1], "server"))
 2167                     {
 2168                         reassembly_direction = SSN_DIR_FROM_SERVER;
 2169                     }
 2170                     else if(!strcasecmp(stoks[1], "both"))
 2171                     {
 2172                         reassembly_direction = SSN_DIR_BOTH;
 2173                     }
 2174                     else
 2175                     {
 2176                         FatalError(
 2177                                 "%s(%d) => Invalid direction for reassembly "
 2178                                 "configuration \"%s\".  Valid values are 'client', "
 2179                                 "'server', or 'both'.\n",
 2180                                 file_name, file_line, stoks[1]);
 2181                     }
 2182                 }
 2183 
 2184                 if (s_toks > 2)
 2185                 {
 2186                     char **ptoks;
 2187                     int num_ptoks;
 2188                     int j;
 2189 
 2190                     /* Initialize it if not already... */
 2191                     InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP);
 2192 
 2193                     if (!strcasecmp(stoks[2], "all"))
 2194                     {
 2195                         for (j=1; j<MAX_PROTOCOL_ORDINAL; j++)
 2196                         {
 2197                             if (reassembly_direction & SSN_DIR_FROM_CLIENT)
 2198                             {
 2199                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].client;
 2200                                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2201                                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2202                             }
 2203                             if (reassembly_direction & SSN_DIR_FROM_SERVER)
 2204                             {
 2205                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].server;
 2206                                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2207                                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2208                             }
 2209                             s5TcpPolicy->flush_config_protocol[j].configured = 1;
 2210                         }
 2211                     }
 2212                     else if (!strcasecmp(stoks[2], "none"))
 2213                     {
 2214                         for (j=1; j<MAX_PROTOCOL_ORDINAL; j++)
 2215                         {
 2216                             if (reassembly_direction & SSN_DIR_FROM_CLIENT)
 2217                             {
 2218                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].client;
 2219                                 flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE;
 2220                             }
 2221                             if (reassembly_direction & SSN_DIR_FROM_SERVER)
 2222                             {
 2223                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].server;
 2224                                 flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE;
 2225                             }
 2226                             s5TcpPolicy->flush_config_protocol[j].configured = 1;
 2227                         }
 2228                     }
 2229                     else
 2230                     {
 2231                         ptoks = mSplit(stoks[2], " ", MAX_PROTOCOL_ORDINAL, &num_ptoks, 0);
 2232 
 2233                         for (j=0;j<num_ptoks;j++)
 2234                         {
 2235                             int16_t proto_ordinal;
 2236                             if (!ptoks[j])
 2237                             {
 2238                                 FatalError("%s(%d) => Invalid Protocol Name.  Protocol name must be specified.\n",
 2239                                         file_name, file_line);
 2240                             }
 2241                             /* First look it up */
 2242                             proto_ordinal = FindProtocolReference(ptoks[j]);
 2243                             if (proto_ordinal == SFTARGET_UNKNOWN_PROTOCOL)
 2244                             {
 2245                                 /* Not known -- add it */
 2246                                 proto_ordinal = AddProtocolReference(ptoks[j]);
 2247                                 if (proto_ordinal == SFTARGET_UNKNOWN_PROTOCOL)
 2248                                 {
 2249                                     FatalError("%s(%d) => Failed to find protocol reference for '%s'\n",
 2250                                             file_name, file_line, ptoks[j]);
 2251                                 }
 2252                             }
 2253 
 2254                             if (reassembly_direction & SSN_DIR_FROM_CLIENT)
 2255                             {
 2256                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[proto_ordinal].client;
 2257                                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2258                                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2259                             }
 2260                             if (reassembly_direction & SSN_DIR_FROM_SERVER)
 2261                             {
 2262                                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[proto_ordinal].server;
 2263                                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2264                                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2265                             }
 2266                             s5TcpPolicy->flush_config_protocol[proto_ordinal].configured = 1;
 2267                         }
 2268                         mSplitFree(&ptoks, num_ptoks);
 2269                     }
 2270                     set_target_flush_policy = 1;
 2271                 }
 2272                 max_s_toks = 0;  // we already checked all tokens
 2273             }
 2274 #endif
 2275             else
 2276             {
 2277                 FatalError("%s(%d) => Invalid Stream TCP policy option\n",
 2278                         file_name, file_line);
 2279             }
 2280 
 2281             if ( max_s_toks && (s_toks > max_s_toks) )
 2282             {
 2283                 FatalError("%s(%d) => Invalid Stream TCP Policy option.  Missing comma?\n",
 2284                         file_name, file_line);
 2285             }
 2286             mSplitFree(&stoks, s_toks);
 2287         }
 2288 
 2289         mSplitFree(&toks, num_toks);
 2290     }
 2291 
 2292     if (s5TcpPolicy->bound_addrs == NULL)
 2293     {
 2294         if (config->default_policy != NULL)
 2295         {
 2296             FatalError("%s(%d) => Default Stream TCP Policy already set. "
 2297                     "This policy must be bound to a specific host or "
 2298                     "network.\n", file_name, file_line);
 2299         }
 2300 
 2301         config->default_policy = s5TcpPolicy;
 2302     }
 2303     else
 2304     {
 2305         if (s5TcpPolicy->flags & STREAM_CONFIG_IGNORE_ANY)
 2306         {
 2307             FatalError("%s(%d) => \"ignore_any_rules\" option can be used only"
 2308                     " with Default Stream TCP Policy\n", file_name, file_line);
 2309         }
 2310     }
 2311 
 2312     if (!set_flush_policy)
 2313     {
 2314         /* Initialize it if not already... */
 2315         InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP);
 2316         for (i=0; i<DEFAULT_PORTS_SIZE; i++)
 2317         {
 2318             if (reassembly_direction & SSN_DIR_FROM_CLIENT)
 2319             {
 2320                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[default_ports[i]].client;
 2321                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2322                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2323             }
 2324             if (reassembly_direction & SSN_DIR_FROM_SERVER)
 2325             {
 2326                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[default_ports[i]].server;
 2327                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2328                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2329             }
 2330         }
 2331     }
 2332 
 2333 #ifdef TARGET_BASED
 2334     if (!set_target_flush_policy)
 2335     {
 2336         int app_id;
 2337         /* Initialize it if not already... */
 2338         InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP);
 2339         for (i=0; i<(int)(sizeof(default_protocols)/sizeof(char *)); i++)
 2340         {
 2341             /* Look up the protocol by name. Add it if it doesn't exist. */
 2342             app_id = FindProtocolReference(default_protocols[i]);
 2343             if (app_id == SFTARGET_UNKNOWN_PROTOCOL)
 2344             {
 2345                 app_id = AddProtocolReference(default_protocols[i]);
 2346             }
 2347 
 2348             /* While this should never happen, I don't feel guilty adding this
 2349              * logic as it executes at parse time. */
 2350             if (app_id == SFTARGET_UNKNOWN_PROTOCOL)
 2351                 continue;
 2352 
 2353             /* Set flush managers. */
 2354             if (reassembly_direction & SSN_DIR_FROM_CLIENT)
 2355             {
 2356                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[app_id].client;
 2357                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2358                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2359             }
 2360             if (reassembly_direction & SSN_DIR_FROM_SERVER)
 2361             {
 2362                 FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[app_id].server;
 2363                 FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list;
 2364                 InitFlushMgr(sc, flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0);
 2365             }
 2366             s5TcpPolicy->flush_config_protocol[app_id].configured = 1;
 2367         }
 2368     }
 2369 #endif
 2370 }
 2371 
 2372 static void StreamPrintTcpConfig(StreamTcpPolicy *s5TcpPolicy)
 2373 {
 2374     int i=0, j=0;
 2375     LogMessage("Stream TCP Policy config:\n");
 2376     if (s5TcpPolicy->bound_addrs != NULL)
 2377     {
 2378         IpAddrSetPrint("    Bound Addresses: ", s5TcpPolicy->bound_addrs);
 2379     }
 2380     else
 2381     {
 2382         LogMessage("    Bound Address: default\n");
 2383     }
 2384     LogMessage("    Reassembly Policy: %s\n",
 2385             reassembly_policy_names[s5TcpPolicy->reassembly_policy]);
 2386     LogMessage("    Timeout: %d seconds\n", s5TcpPolicy->session_timeout);
 2387     if (s5TcpPolicy->max_window != 0)
 2388         LogMessage("    Max TCP Window: %u\n", s5TcpPolicy->max_window);
 2389     if (s5TcpPolicy->overlap_limit)
 2390         LogMessage("    Limit on TCP Overlaps: %d\n", s5TcpPolicy->overlap_limit);
 2391     if (s5TcpPolicy->max_queued_bytes != 0)
 2392     {
 2393         LogMessage("    Maximum number of bytes to queue per session: %d\n",
 2394                 s5TcpPolicy->max_queued_bytes);
 2395     }
 2396     if (s5TcpPolicy->max_queued_segs != 0)
 2397     {
 2398         LogMessage("    Maximum number of segs to queue per session: %d\n",
 2399                 s5TcpPolicy->max_queued_segs);
 2400     }
 2401     if (s5TcpPolicy->flags)
 2402     {
 2403         LogMessage("    Options:\n");
 2404         if (s5TcpPolicy->flags & STREAM_CONFIG_REQUIRE_3WHS)
 2405         {
 2406             LogMessage("        Require 3-Way Handshake: YES\n");
 2407             if (s5TcpPolicy->hs_timeout != 0)
 2408             {
 2409                 LogMessage("        3-Way Handshake Timeout: %d\n",
 2410                         s5TcpPolicy->hs_timeout);
 2411             }
 2412         }
 2413         if (s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS)
 2414         {
 2415             LogMessage("        Detect Anomalies: YES\n");
 2416         }
 2417         if (s5TcpPolicy->flags & STREAM_CONFIG_STATIC_FLUSHPOINTS)
 2418         {
 2419             LogMessage("        Static Flushpoint Sizes: YES\n");
 2420         }
 2421         if (s5TcpPolicy->flags & STREAM_CONFIG_PERFORMANCE)
 2422         {
 2423             LogMessage("        Don't Queue Large Packets for Reassembly: YES\n");
 2424         }
 2425         if (s5TcpPolicy->flags & STREAM_CONFIG_CHECK_SESSION_HIJACKING)
 2426         {
 2427             LogMessage("        Check for TCP Session Hijacking: YES\n");
 2428         }
 2429         if (s5TcpPolicy->flags & STREAM_CONFIG_IGNORE_ANY)
 2430         {
 2431             LogMessage("        Ignore Any -> Any Rules: YES\n");
 2432         }
 2433         if (s5TcpPolicy->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY)
 2434         {
 2435             LogMessage("        Don't queue packets on one-sided sessions: YES\n");
 2436         }
 2437     }
 2438     LogMessage("    Reassembly Ports:\n");
 2439     for (i=0; i<MAX_PORTS; i++)
 2440     {
 2441         int direction = 0;
 2442         int client_flushpolicy = s5TcpPolicy->flush_config[i].client.flush_policy;
 2443         int server_flushpolicy = s5TcpPolicy->flush_config[i].server.flush_policy;
 2444         char client_policy_str[STD_BUF];
 2445         char server_policy_str[STD_BUF];
 2446         client_policy_str[0] = server_policy_str[0] = '\0';
 2447 
 2448         if (client_flushpolicy != STREAM_FLPOLICY_IGNORE)
 2449         {
 2450             direction |= SSN_DIR_FROM_CLIENT;
 2451 
 2452             if (client_flushpolicy < STREAM_FLPOLICY_MAX)
 2453                 SnortSnprintf(client_policy_str, STD_BUF, "client (%s)",
 2454                         flush_policy_names[client_flushpolicy]);
 2455         }
 2456         if (server_flushpolicy != STREAM_FLPOLICY_IGNORE)
 2457         {
 2458             direction |= SSN_DIR_FROM_SERVER;
 2459 
 2460             if (server_flushpolicy < STREAM_FLPOLICY_MAX)
 2461                 SnortSnprintf(server_policy_str, STD_BUF, "server (%s)",
 2462                         flush_policy_names[server_flushpolicy]);
 2463         }
 2464         if (direction)
 2465         {
 2466             if (j<MAX_PORTS_TO_PRINT)
 2467             {
 2468                 LogMessage("      %d %s %s\n", i,
 2469                         client_policy_str, server_policy_str);
 2470             }
 2471             j++;
 2472         }
 2473     }
 2474 
 2475     if (j > MAX_PORTS_TO_PRINT)
 2476     {
 2477         LogMessage("      additional ports configured but not printed.\n");
 2478     }
 2479 }
 2480 
 2481 #ifdef TARGET_BASED
 2482 int StreamPolicyIdFromHostAttributeEntry(HostAttributeEntry *host_entry)
 2483 {
 2484     if (!host_entry)
 2485         return 0;
 2486 
 2487     host_entry->hostInfo.streamPolicy = StreamPolicyIdFromName(host_entry->hostInfo.streamPolicyName);
 2488     host_entry->hostInfo.streamPolicySet = 1;
 2489 
 2490     STREAM_DEBUG_WRAP(
 2491             DebugMessage(DEBUG_STREAM_STATE,
 2492                 "STREAM INIT: %s(%d) for Entry %s\n",
 2493                 reassembly_policy_names[host_entry->hostInfo.streamPolicy],
 2494                 host_entry->hostInfo.streamPolicy,
 2495                 host_entry->hostInfo.streamPolicyName););
 2496     return 0;
 2497 }
 2498 #endif
 2499 
 2500 void StreamPostConfigTcp (struct _SnortConfig *sc, void* pv)
 2501 {
 2502     // enable all ports registered by preprocessors for reassembly
 2503     enableRegisteredPortsForReassembly( sc );
 2504 }
 2505 
 2506 void s5TcpPrintPortFilter();
 2507 
 2508 /**
 2509  * StreamVerifyTcpConfig is is called after all preprocs (static & dynamic)
 2510  * are inited.
 2511  */
 2512 int StreamVerifyTcpConfig(struct _SnortConfig *sc, StreamTcpConfig *config, tSfPolicyId policy_id)
 2513 {
 2514     if (config == NULL)
 2515         return -1;
 2516 
 2517     if (!tcp_lws_cache)
 2518     {
 2519         LogMessage("WARNING: Stream TCP Session Cache not initialized.\n");
 2520         return -1;
 2521     }
 2522 
 2523     if (config->num_policies == 0)
 2524     {
 2525         LogMessage("WARNING: Stream TCP no policies specified in configuration.\n");
 2526         return -1;
 2527     }
 2528 
 2529     if (config->default_policy == NULL)
 2530     {
 2531         LogMessage("WARNING: Stream TCP default policy not specified in configuration.\n");
 2532         return -1;
 2533     }
 2534 
 2535     /* Do this now
 2536      * verify config is called after all preprocs (static & dynamic)
 2537      * are inited.  Gives us the correct number of bits for
 2538      * p->preprocessor_bits
 2539      */
 2540     if (!s5_pkt)
 2541         StreamInitPacket();
 2542 
 2543 #ifdef TARGET_BASED
 2544     SFAT_SetPolicyIds(StreamPolicyIdFromHostAttributeEntry, policy_id);
 2545 #endif
 2546 
 2547     /* Post-process TCP rules to establish TCP ports to inspect. */
 2548     setPortFilterList(sc, config->port_filter, IPPROTO_TCP,
 2549             (config->default_policy->flags & STREAM_CONFIG_IGNORE_ANY), policy_id);
 2550 
 2551     //printf ("TCP Ports with Inspection/Monitoring\n");
 2552     //s5PrintPortFilter(config->tcpPortFilter);
 2553     return 0;
 2554 }
 2555 
 2556 
 2557 uint32_t StreamGetTcpPrunes(void)
 2558 {
 2559     if( tcp_lws_cache )
 2560         return session_api->get_session_prune_count( SESSION_PROTO_TCP );
 2561     else
 2562         return s5stats.tcp_prunes;
 2563 }
 2564 
 2565 void StreamResetTcpPrunes(void)
 2566 {
 2567     session_api->reset_session_prune_count( SESSION_PROTO_TCP );
 2568 }
 2569 
 2570 void StreamResetTcp(void)
 2571 {
 2572     if (snort_conf == NULL)
 2573     {
 2574         ErrorMessage("Snort configuration is NULL.\n");
 2575         return;
 2576     }
 2577 
 2578     /* Unset decoder flags for the purge */
 2579     targetPolicyIterate(policyDecoderFlagsSaveNClear);
 2580 
 2581     s5_tcp_cleanup = 1;
 2582     session_api->purge_session_cache(tcp_lws_cache);
 2583     s5_tcp_cleanup = 0;
 2584     session_api->clean_protocol_session_pool( SESSION_PROTO_TCP );
 2585 
 2586     /* Set decoder flags back to original */
 2587     targetPolicyIterate(policyDecoderFlagsRestore);
 2588 
 2589     ResetFlushMgrs();
 2590 }
 2591 
 2592 
 2593 void StreamCleanTcp(void)
 2594 {
 2595     if (snort_conf == NULL)
 2596     {
 2597         ErrorMessage("Snort configuration is NULL.\n");
 2598         return;
 2599     }
 2600 
 2601     s5stats.tcp_prunes = session_api->get_session_prune_count( SESSION_PROTO_TCP );
 2602 
 2603     /* Turn off decoder alerts since we're decoding stored
 2604      * packets that we already alerted on. */
 2605     targetPolicyIterate(policyDecoderFlagsSaveNClear);
 2606 
 2607     /* Set s5_tcp_cleanup to force a flush of all queued data */
 2608     s5_tcp_cleanup = 1;
 2609     /* Clean up session cache */
 2610     session_api->delete_session_cache( SESSION_PROTO_TCP );
 2611     tcp_lws_cache = NULL;
 2612 
 2613     /* Cleanup the rebuilt packet */
 2614     if (s5_pkt)
 2615     {
 2616         Encode_Delete(s5_pkt);
 2617         s5_pkt = NULL;
 2618     }
 2619 
 2620     /* Cleanup TCP session cleanup packet */
 2621     if (tcp_cleanup_pkt)
 2622     {
 2623         DeleteGrinderPkt(tcp_cleanup_pkt);
 2624         tcp_cleanup_pkt = NULL;
 2625     }
 2626 
 2627     /* cleanup is over... */
 2628     s5_tcp_cleanup = 0;
 2629 
 2630     /* And turn decoder alerts back on (or whatever they were set to) */
 2631     targetPolicyIterate(policyDecoderFlagsRestore);
 2632 }
 2633 
 2634 void StreamTcpConfigFree(StreamTcpConfig *config)
 2635 {
 2636     int i;
 2637 
 2638     if (config == NULL)
 2639         return;
 2640 
 2641     /* Cleanup TCP Policies and the list */
 2642     for (i = 0; i < config->num_policies; i++)
 2643     {
 2644         StreamTcpPolicy *policy = config->policy_list[i];
 2645 
 2646         free(policy->flush_point_list.flush_points);
 2647 
 2648         if (policy->bound_addrs != NULL)
 2649             sfvar_free(policy->bound_addrs);
 2650         free(policy);
 2651     }
 2652 
 2653     if ( config->paf_config )
 2654         s5_paf_delete(config->paf_config);
 2655 
 2656     free(config->policy_list);
 2657     free(config);
 2658 }
 2659 
 2660 #ifdef STREAM_DEBUG_ENABLED
 2661 static void PrintStateMgr(StateMgr *s)
 2662 {
 2663     LogMessage("StateMgr:\n");
 2664     LogMessage("    state:          %s\n", state_names[s->state]);
 2665     LogMessage("    state_queue:    %s\n", state_names[s->state_queue]);
 2666     LogMessage("    expected_flags: 0x%X\n", s->expected_flags);
 2667     LogMessage("    transition_seq: 0x%X\n", s->transition_seq);
 2668     LogMessage("    stq_get_seq:    %d\n", s->stq_get_seq);
 2669 }
 2670 
 2671 static void PrintStreamTracker(StreamTracker *s)
 2672 {
 2673     LogMessage(" + StreamTracker +\n");
 2674     LogMessage("    isn:                0x%X\n", s->isn);
 2675     LogMessage("    ts_last:            %u\n", s->ts_last);
 2676     LogMessage("    wscale:             %u\n", s->wscale);
 2677     LogMessage("    mss:                0x%08X\n", s->mss);
 2678     LogMessage("    l_unackd:           %X\n", s->l_unackd);
 2679     LogMessage("    l_nxt_seq:          %X\n", s->l_nxt_seq);
 2680     LogMessage("    l_window:           %u\n", s->l_window);
 2681     LogMessage("    r_nxt_ack:          %X\n", s->r_nxt_ack);
 2682     LogMessage("    r_win_base:         %X\n", s->r_win_base);
 2683     LogMessage("    seglist_base_seq:   %X\n", s->seglist_base_seq);
 2684     LogMessage("    seglist:            %p\n", (void*)s->seglist);
 2685     LogMessage("    seglist_tail:       %p\n", (void*)s->seglist_tail);
 2686     LogMessage("    seg_count:          %d\n", s->seg_count);
 2687     LogMessage("    seg_bytes_total:    %d\n", s->seg_bytes_total);
 2688     LogMessage("    seg_bytes_logical:  %d\n", s->seg_bytes_logical);
 2689 
 2690     PrintStateMgr(&s->s_mgr);
 2691 }
 2692 
 2693 static void PrintTcpSession(TcpSession *ts)
 2694 {
 2695     char buf[64];
 2696 
 2697     LogMessage("TcpSession:\n");
 2698 #ifdef DEBUG
 2699     LogMessage("    ssn_time:           %lu\n", ts->ssn_time.tv_sec);
 2700 #endif
 2701     sfip_ntop(&ts->tcp_server_ip, buf, sizeof(buf));
 2702     LogMessage("    server IP:          %s\n", buf);
 2703     sfip_ntop(&ts->tcp_client_ip, buf, sizeof(buf));
 2704     LogMessage("    client IP:          %s\n", buf);
 2705 
 2706     LogMessage("    server port:        %d\n", ts->tcp_server_port);
 2707     LogMessage("    client port:        %d\n", ts->tcp_client_port);
 2708 
 2709     LogMessage("    flags:              0x%X\n", ts->scb->ha_state.session_flags);
 2710 
 2711     LogMessage("Client Tracker:\n");
 2712     PrintStreamTracker(&ts->client);
 2713     LogMessage("Server Tracker:\n");
 2714     PrintStreamTracker(&ts->server);
 2715 }
 2716 
 2717 static void PrintTcpDataBlock(TcpDataBlock *tdb)
 2718 {
 2719     LogMessage("TcpDataBlock:\n");
 2720     LogMessage("    seq:    0x%08X\n", tdb->seq);
 2721     LogMessage("    ack:    0x%08X\n", tdb->ack);
 2722     LogMessage("    win:    %d\n", tdb->win);
 2723     LogMessage("    end:    0x%08X\n", tdb->end_seq);
 2724 }
 2725 
 2726 #ifdef STREAM_DEBUG_ENABLED
 2727 static void PrintFlushMgr(FlushMgr *fm)
 2728 {
 2729     if(fm == NULL)
 2730         return;
 2731 
 2732     switch(fm->flush_policy)
 2733     {
 2734         case STREAM_FLPOLICY_NONE:
 2735             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 2736                         "    NONE\n"););
 2737             break;
 2738         case STREAM_FLPOLICY_FOOTPRINT:
 2739             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 2740                         "    FOOTPRINT %d\n", fm->flush_pt););
 2741             break;
 2742         case STREAM_FLPOLICY_LOGICAL:
 2743             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 2744                         "    LOGICAL %d\n", fm->flush_pt););
 2745             break;
 2746         case STREAM_FLPOLICY_RESPONSE:
 2747             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 2748                         "    RESPONSE\n"););
 2749             break;
 2750         case STREAM_FLPOLICY_SLIDING_WINDOW:
 2751             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 2752                         "    SLIDING_WINDOW %d\n", fm->flush_pt););
 2753             break;
 2754 #if 0
 2755         case STREAM_FLPOLICY_CONSUMED:
 2756             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 2757                         "          CONSUMED %d\n", fm->flush_pt););
 2758             break;
 2759 #endif
 2760         case STREAM_FLPOLICY_IGNORE:
 2761             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 2762                         "    IGNORE\n"););
 2763             break;
 2764 
 2765         case STREAM_FLPOLICY_PROTOCOL:
 2766             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 2767                         "    PROTOCOL\n"););
 2768             break;
 2769     }
 2770 }
 2771 #endif  // DEBUG
 2772 #endif  // STREAM_DEBUG_ENABLED
 2773 
 2774 static inline void Discard ()
 2775 {
 2776     s5stats.tcp_discards++;
 2777 }
 2778 static inline void EventSynOnEst(StreamTcpPolicy *s5TcpPolicy)
 2779 {
 2780     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2781         return;
 2782 
 2783     s5stats.events++;
 2784 
 2785     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2786             STREAM_SYN_ON_EST,                 /* SID */
 2787             1,                                  /* rev */
 2788             0,                                  /* class */
 2789             3,                                  /* priority */
 2790             STREAM_SYN_ON_EST_STR,             /* event msg */
 2791             NULL);                              /* rule info ptr */
 2792 }
 2793 
 2794 static inline void EventExcessiveOverlap(StreamTcpPolicy *s5TcpPolicy)
 2795 {
 2796     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2797         return;
 2798 
 2799     s5stats.events++;
 2800 
 2801     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2802             STREAM_EXCESSIVE_TCP_OVERLAPS,     /* SID */
 2803             1,                                  /* rev */
 2804             0,                                  /* class */
 2805             3,                                  /* priority */
 2806             STREAM_EXCESSIVE_TCP_OVERLAPS_STR, /* event msg */
 2807             NULL);                              /* rule info ptr */
 2808 }
 2809 
 2810 static inline void EventBadTimestamp(StreamTcpPolicy *s5TcpPolicy)
 2811 {
 2812     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2813         return;
 2814 
 2815     s5stats.events++;
 2816 
 2817     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2818             STREAM_BAD_TIMESTAMP,              /* SID */
 2819             1,                                  /* rev */
 2820             0,                                  /* class */
 2821             3,                                  /* priority */
 2822             STREAM_BAD_TIMESTAMP_STR,          /* event msg */
 2823             NULL);                              /* rule info ptr */
 2824 }
 2825 
 2826 static inline void EventWindowTooLarge(StreamTcpPolicy *s5TcpPolicy)
 2827 {
 2828     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2829         return;
 2830 
 2831     s5stats.events++;
 2832 
 2833     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2834             STREAM_WINDOW_TOO_LARGE,           /* SID */
 2835             1,                                  /* rev */
 2836             0,                                  /* class */
 2837             3,                                  /* priority */
 2838             STREAM_WINDOW_TOO_LARGE_STR,       /* event msg */
 2839             NULL);                              /* rule info ptr */
 2840 }
 2841 
 2842 static inline void EventDataOnSyn(StreamTcpPolicy *s5TcpPolicy)
 2843 {
 2844     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2845         return;
 2846 
 2847     s5stats.events++;
 2848 
 2849     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2850             STREAM_DATA_ON_SYN,                /* SID */
 2851             1,                                  /* rev */
 2852             0,                                  /* class */
 2853             3,                                  /* priority */
 2854             STREAM_DATA_ON_SYN_STR,            /* event msg */
 2855             NULL);                              /* rule info ptr */
 2856 }
 2857 
 2858 static inline void EventDataOnClosed(StreamTcpPolicy *s5TcpPolicy)
 2859 {
 2860     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2861         return;
 2862 
 2863     s5stats.events++;
 2864 
 2865     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2866             STREAM_DATA_ON_CLOSED,             /* SID */
 2867             1,                                  /* rev */
 2868             0,                                  /* class */
 2869             3,                                  /* priority */
 2870             STREAM_DATA_ON_CLOSED_STR,         /* event msg */
 2871             NULL);                              /* rule info ptr */
 2872 }
 2873 
 2874 static inline void EventDataAfterReset(StreamTcpPolicy *s5TcpPolicy)
 2875 {
 2876     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2877         return;
 2878 
 2879     s5stats.events++;
 2880 
 2881     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2882             STREAM_DATA_AFTER_RESET,           /* SID */
 2883             1,                                  /* rev */
 2884             0,                                  /* class */
 2885             3,                                  /* priority */
 2886             STREAM_DATA_AFTER_RESET_STR,       /* event msg */
 2887             NULL);                              /* rule info ptr */
 2888 }
 2889 
 2890 static inline void EventBadSegment(StreamTcpPolicy *s5TcpPolicy)
 2891 {
 2892     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2893         return;
 2894 
 2895     s5stats.events++;
 2896 
 2897     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2898             STREAM_BAD_SEGMENT,                /* SID */
 2899             1,                                  /* rev */
 2900             0,                                  /* class */
 2901             3,                                  /* priority */
 2902             STREAM_BAD_SEGMENT_STR,            /* event msg */
 2903             NULL);                              /* rule info ptr */
 2904 }
 2905 
 2906 static inline void EventSessionHijackedClient(StreamTcpPolicy *s5TcpPolicy)
 2907 {
 2908     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2909         return;
 2910 
 2911     s5stats.events++;
 2912 
 2913     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2914             STREAM_SESSION_HIJACKED_CLIENT,    /* SID */
 2915             1,                                  /* rev */
 2916             0,                                  /* class */
 2917             3,                                  /* priority */
 2918             STREAM_SESSION_HIJACKED_CLIENT_STR, /* event msg */
 2919             NULL);                              /* rule info ptr */
 2920 }
 2921 static inline void EventSessionHijackedServer(StreamTcpPolicy *s5TcpPolicy)
 2922 {
 2923     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2924         return;
 2925 
 2926     s5stats.events++;
 2927 
 2928     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2929             STREAM_SESSION_HIJACKED_SERVER,    /* SID */
 2930             1,                                  /* rev */
 2931             0,                                  /* class */
 2932             3,                                  /* priority */
 2933             STREAM_SESSION_HIJACKED_SERVER_STR, /* event msg */
 2934             NULL);                              /* rule info ptr */
 2935 }
 2936 
 2937 static inline void EventDataWithoutFlags(StreamTcpPolicy *s5TcpPolicy)
 2938 {
 2939     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2940         return;
 2941 
 2942     s5stats.events++;
 2943 
 2944     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2945             STREAM_DATA_WITHOUT_FLAGS,         /* SID */
 2946             1,                                  /* rev */
 2947             0,                                  /* class */
 2948             3,                                  /* priority */
 2949             STREAM_DATA_WITHOUT_FLAGS_STR,     /* event msg */
 2950             NULL);                              /* rule info ptr */
 2951 }
 2952 
 2953 static inline void EventMaxSmallSegsExceeded(StreamTcpPolicy *s5TcpPolicy)
 2954 {
 2955     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2956         return;
 2957 
 2958     s5stats.events++;
 2959 
 2960     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2961             STREAM_SMALL_SEGMENT,              /* SID */
 2962             1,                                  /* rev */
 2963             0,                                  /* class */
 2964             3,                                  /* priority */
 2965             STREAM_SMALL_SEGMENT_STR,          /* event msg */
 2966             NULL);                              /* rule info ptr */
 2967 }
 2968 
 2969 static inline void Event4whs(StreamTcpPolicy *s5TcpPolicy)
 2970 {
 2971     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2972         return;
 2973 
 2974     s5stats.events++;
 2975 
 2976     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2977             STREAM_4WAY_HANDSHAKE,             /* SID */
 2978             1,                                  /* rev */
 2979             0,                                  /* class */
 2980             3,                                  /* priority */
 2981             STREAM_4WAY_HANDSHAKE_STR,         /* event msg */
 2982             NULL);                              /* rule info ptr */
 2983 }
 2984 
 2985 static inline void EventNoTimestamp(StreamTcpPolicy *s5TcpPolicy)
 2986 {
 2987     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 2988         return;
 2989 
 2990     s5stats.events++;
 2991 
 2992     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 2993             STREAM_NO_TIMESTAMP,               /* SID */
 2994             1,                                  /* rev */
 2995             0,                                  /* class */
 2996             3,                                  /* priority */
 2997             STREAM_NO_TIMESTAMP_STR,           /* event msg */
 2998             NULL);                              /* rule info ptr */
 2999 }
 3000 
 3001 static inline void EventBadReset(StreamTcpPolicy *s5TcpPolicy)
 3002 {
 3003     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 3004         return;
 3005 
 3006     s5stats.events++;
 3007 
 3008     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 3009             STREAM_BAD_RST,                    /* SID */
 3010             1,                                  /* rev */
 3011             0,                                  /* class */
 3012             3,                                  /* priority */
 3013             STREAM_BAD_RST_STR,                /* event msg */
 3014             NULL);                              /* rule info ptr */
 3015 }
 3016 
 3017 static inline void EventBadFin(StreamTcpPolicy *s5TcpPolicy)
 3018 {
 3019     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 3020         return;
 3021 
 3022     s5stats.events++;
 3023 
 3024     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 3025             STREAM_BAD_FIN,                    /* SID */
 3026             1,                                  /* rev */
 3027             0,                                  /* class */
 3028             3,                                  /* priority */
 3029             STREAM_BAD_FIN_STR,                /* event msg */
 3030             NULL);                              /* rule info ptr */
 3031 }
 3032 
 3033 static inline void EventBadAck(StreamTcpPolicy *s5TcpPolicy)
 3034 {
 3035     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 3036         return;
 3037 
 3038     s5stats.events++;
 3039 
 3040     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 3041             STREAM_BAD_ACK,                    /* SID */
 3042             1,                                  /* rev */
 3043             0,                                  /* class */
 3044             3,                                  /* priority */
 3045             STREAM_BAD_ACK_STR,                /* event msg */
 3046             NULL);                              /* rule info ptr */
 3047 }
 3048 
 3049 static inline void EventDataAfterRstRcvd(StreamTcpPolicy *s5TcpPolicy)
 3050 {
 3051     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 3052         return;
 3053 
 3054     s5stats.events++;
 3055 
 3056     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 3057             STREAM_DATA_AFTER_RST_RCVD,        /* SID */
 3058             1,                                  /* rev */
 3059             0,                                  /* class */
 3060             3,                                  /* priority */
 3061             STREAM_DATA_AFTER_RST_RCVD_STR,    /* event msg */
 3062             NULL);                              /* rule info ptr */
 3063 }
 3064 
 3065 static inline void EventInternal (uint32_t eventSid)
 3066 {
 3067     if ( !InternalEventIsEnabled(snort_conf->rate_filter_config, eventSid) )
 3068         return;
 3069 
 3070     s5stats.internalEvents++;
 3071 
 3072     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3073                 "Stream raised internal event %d\n", eventSid););
 3074 
 3075     SnortEventqAdd(
 3076         GENERATOR_INTERNAL,             /* GID */
 3077         eventSid,                       /* SID */
 3078         1,                              /* rev */
 3079         0,                              /* class */
 3080         3,                              /* priority */
 3081         STREAM_INTERNAL_EVENT_STR,      /* event msg*/
 3082         NULL                            /* rule info ptr */
 3083         );
 3084 }
 3085 
 3086 static inline void EventWindowSlam (StreamTcpPolicy *s5TcpPolicy)
 3087 {
 3088     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 3089         return;
 3090 
 3091     s5stats.events++;
 3092 
 3093     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 3094             STREAM_WINDOW_SLAM,                /* SID */
 3095             1,                                  /* rev */
 3096             0,                                  /* class */
 3097             3,                                  /* priority */
 3098             STREAM_WINDOW_SLAM_STR,            /* event msg */
 3099             NULL);                              /* rule info ptr */
 3100 }
 3101 
 3102 static inline void EventNo3whs (StreamTcpPolicy *s5TcpPolicy)
 3103 {
 3104     if(!(s5TcpPolicy->flags & STREAM_CONFIG_ENABLE_ALERTS))
 3105         return;
 3106 
 3107     s5stats.events++;
 3108 
 3109     SnortEventqAdd(GENERATOR_SPP_STREAM,       /* GID */
 3110             STREAM_NO_3WHS,                    /* SID */
 3111             1,                                  /* rev */
 3112             0,                                  /* class */
 3113             3,                                  /* priority */
 3114             STREAM_NO_3WHS_STR,                /* event msg */
 3115             NULL);                              /* rule info ptr */
 3116 }
 3117 
 3118 /*
 3119  *  Utility functions for TCP stuff
 3120  */
 3121 #ifdef NORMALIZER
 3122 typedef enum {
 3123     PC_TCP_ECN_SSN,
 3124     PC_TCP_TS_NOP,
 3125     PC_TCP_IPS_DATA,
 3126     PC_TCP_BLOCK,
 3127     PC_TCP_TRIM_SYN,
 3128     PC_TCP_TRIM_RST,
 3129     PC_TCP_TRIM_WIN,
 3130     PC_TCP_TRIM_MSS,
 3131     PC_MAX
 3132 } PegCounts;
 3133 
 3134 static uint64_t normStats[PC_MAX][NORM_MODE_MAX];
 3135 
 3136 static const char* pegName[PC_MAX] = {
 3137     "tcp::ecn_ssn",
 3138     "tcp::ts_nop",
 3139     "tcp::ips_data",
 3140     "tcp::block",
 3141     "tcp::trim_syn",
 3142     "tcp::trim_rst",
 3143     "tcp::trim_win",
 3144     "tcp::trim_mss",
 3145 };
 3146 
 3147 void Stream_PrintNormalizationStats (void)
 3148 {
 3149     int i;
 3150     // header output by normalizer
 3151 
 3152     for ( i = 0; i < PC_MAX; i++ )
 3153     {
 3154         // same alignment as in Norm_PrintStats()
 3155         LogMessage("%23s: " STDu64 "\n", pegName[i], normStats[i][NORM_MODE_ON]);
 3156         LogMessage("Would %17s: " STDu64 "\n", pegName[i], normStats[i][NORM_MODE_WOULDA]);
 3157     }
 3158 }
 3159 
 3160 void Stream_ResetNormalizationStats (void)
 3161 {
 3162     memset(normStats, 0, sizeof(normStats));
 3163 }
 3164 
 3165 //-----------------------------------------------------------------------
 3166 // instead of centralizing all these normalizations so that
 3167 // Normalize_GetMode() is called only once, the checks and
 3168 // normalizations are localized.  this should lead to many
 3169 // fewer total checks.  however, it is best to minimize
 3170 // configuration checks on a per packet basis so there is
 3171 // still room for improvement.
 3172 
 3173 static inline bool NormalDropPacket (Packet* p)
 3174 {
 3175     NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_BLOCK);
 3176     if ( mode != NORM_MODE_OFF )
 3177     {
 3178             normStats[PC_TCP_BLOCK][mode]++;
 3179             sfBase.iPegs[PERF_COUNT_TCP_BLOCK][mode]++;
 3180             if ( mode == NORM_MODE_ON )
 3181             {
 3182                 Active_NapDropPacket(p);
 3183                 if (pkt_trace_enabled)
 3184                 {
 3185                     addPktTraceData(VERDICT_REASON_STREAM, snprintf(trace_line, MAX_TRACE_LINE,
 3186                        "Stream: TCP normalization error in timestamp, window, seq, ack, fin, flags, or unexpected data, %s\n",
 3187                        getPktTraceActMsg()));
 3188                 }
 3189                 else addPktTraceData(VERDICT_REASON_STREAM, 0);
 3190                 return true;
 3191             }
 3192     }
 3193     return false;
 3194 }
 3195 
 3196 static inline bool NormalStripTimeStamp (Packet* p, int i)
 3197 {
 3198     uint8_t* opt;
 3199     NormMode mode =  Normalize_GetMode(snort_conf, NORM_TCP_OPT);
 3200 
 3201     if ( mode != NORM_MODE_OFF )
 3202     {
 3203         if ( i < 0 )
 3204         {
 3205             for ( i = 0; i < p->tcp_option_count; i++ )
 3206                 if ( p->tcp_options[i].code == TCPOPT_TIMESTAMP )
 3207                     break;
 3208             if ( i == p->tcp_option_count )
 3209                 return false;
 3210         }
 3211 
 3212         normStats[PC_TCP_TS_NOP][mode]++;
 3213         sfBase.iPegs[PERF_COUNT_TCP_TS_NOP][mode]++;
 3214         if ( mode == NORM_MODE_ON )
 3215         {
 3216             // first set raw option bytes to nops
 3217             opt = (uint8_t*)p->tcp_options[i].data - 2;
 3218             memset(opt, TCPOPT_NOP, TCPOLEN_TIMESTAMP);
 3219 
 3220             // then nop decoded option code only
 3221             p->tcp_options[i].code = TCPOPT_NOP;
 3222 
 3223             p->packet_flags |= PKT_MODIFIED;
 3224             return true;
 3225         }
 3226     }
 3227     return false;
 3228 }
 3229 
 3230 static inline void NormalTrimPayload (Packet* p, uint32_t max, TcpDataBlock* tdb)
 3231 {
 3232     uint16_t fat = p->dsize - max;
 3233     p->dsize = max;
 3234     p->packet_flags |= (PKT_MODIFIED|PKT_RESIZED);
 3235     tdb->end_seq -= fat;
 3236 }
 3237 
 3238 static inline bool NormalTrimPayloadIfSyn ( Packet *p, uint32_t max, TcpDataBlock *tdb )
 3239 {
 3240     NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_TRIM_SYN);
 3241     if ( mode != NORM_MODE_OFF && p->dsize > max )
 3242     {
 3243         normStats[PC_TCP_TRIM_SYN][mode]++;
 3244         sfBase.iPegs[PERF_COUNT_TCP_TRIM_SYN][mode]++;
 3245         if( mode == NORM_MODE_ON )
 3246         {
 3247             NormalTrimPayload(p, max, tdb);
 3248             return true;
 3249         }
 3250     }
 3251     return false;
 3252 }
 3253 
 3254 static inline bool NormalTrimPayloadIfRst ( Packet *p, uint32_t max, TcpDataBlock *tdb )
 3255 {
 3256     NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_TRIM_RST);
 3257     if ( mode != NORM_MODE_OFF && p->dsize > max )
 3258     {
 3259         normStats[PC_TCP_TRIM_RST][mode]++;
 3260         sfBase.iPegs[PERF_COUNT_TCP_TRIM_RST][mode]++;
 3261         if( mode == NORM_MODE_ON )
 3262         {
 3263             NormalTrimPayload(p, max, tdb);
 3264             return true;
 3265         }
 3266     }
 3267     return false;
 3268 }
 3269 
 3270 static inline bool NormalTrimPayloadIfWin ( Packet *p, uint32_t max, TcpDataBlock *tdb )
 3271 {
 3272     NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_TRIM_WIN);
 3273     if ( mode != NORM_MODE_OFF && p->dsize > max )
 3274     {
 3275         normStats[PC_TCP_TRIM_WIN][mode]++;
 3276         sfBase.iPegs[PERF_COUNT_TCP_TRIM_WIN][mode]++;
 3277         if( mode == NORM_MODE_ON )
 3278         {
 3279             NormalTrimPayload(p, max, tdb);
 3280             return true;
 3281         }
 3282     }
 3283     return false;
 3284 }
 3285 
 3286 static inline bool NormalTrimPayloadIfMss ( Packet *p, uint32_t max, TcpDataBlock *tdb )
 3287 {
 3288     NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_TRIM_MSS);
 3289     if ( mode != NORM_MODE_OFF && p->dsize > max )
 3290     {
 3291         normStats[PC_TCP_TRIM_MSS][mode]++;
 3292         sfBase.iPegs[PERF_COUNT_TCP_TRIM_MSS][mode]++;
 3293         if( mode == NORM_MODE_ON )
 3294         {
 3295             NormalTrimPayload(p, max, tdb);
 3296             return true;
 3297         }
 3298     }
 3299     return false;
 3300 }
 3301 
 3302 static inline void NormalTrackECN (TcpSession* s, const TCPHdr* tcph, int req3way)
 3303 {
 3304     if ( !s )
 3305         return;
 3306 
 3307     if ( TCP_ISFLAGSET(tcph, TH_SYN|TH_ACK) )
 3308     {
 3309         if ( !req3way || s->ecn )
 3310             s->ecn = ((tcph->th_flags & (TH_ECE|TH_CWR)) == TH_ECE);
 3311     }
 3312     else if ( TCP_ISFLAGSET(tcph, TH_SYN) )
 3313         s->ecn = TCP_ISFLAGSET(tcph, (TH_ECE|TH_CWR));
 3314 }
 3315 
 3316 static inline void NormalCheckECN (TcpSession* s, Packet* p)
 3317 {
 3318     NormMode mode = Normalize_GetMode(snort_conf, NORM_TCP_ECN_STR);
 3319     if ( mode != NORM_MODE_OFF )
 3320     {
 3321         if ( !s->ecn && (p->tcph->th_flags & (TH_ECE|TH_CWR)) )
 3322         {
 3323             normStats[PC_TCP_ECN_SSN][mode]++;
 3324             sfBase.iPegs[PERF_COUNT_TCP_ECN_SSN][mode]++;
 3325             if ( mode == NORM_MODE_ON )
 3326             {
 3327                 ((TCPHdr*)p->tcph)->th_flags &= ~(TH_ECE|TH_CWR);
 3328                 p->packet_flags |= PKT_MODIFIED;
 3329             }
 3330         }
 3331     }
 3332 }
 3333 #else
 3334 #define NormalDropPacket(p)
 3335 #define NormalTrackECN(s, h, r)
 3336 #endif
 3337 
 3338 void StreamUpdatePerfBaseState(SFBASE *sf_base,
 3339         SessionControlBlock *scb,
 3340         char newState)
 3341 {
 3342     if (!scb)
 3343     {
 3344         return;
 3345     }
 3346 
 3347     switch (newState)
 3348     {
 3349         case TCP_STATE_SYN_SENT:
 3350             if (!(scb->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE))
 3351             {
 3352                 sf_base->iSessionsInitializing++;
 3353                 scb->ha_state.session_flags |= SSNFLAG_COUNTED_INITIALIZE;
 3354             }
 3355             break;
 3356         case TCP_STATE_ESTABLISHED:
 3357             if (!(scb->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH))
 3358             {
 3359                 sf_base->iSessionsEstablished++;
 3360                 EventInternal(INTERNAL_EVENT_SESSION_ADD);
 3361 
 3362                 if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP))
 3363                     UpdateFlowIPState(&sfFlow, IP_ARG(scb->client_ip), IP_ARG(scb->server_ip), SFS_STATE_TCP_ESTABLISHED);
 3364 
 3365                 scb->ha_state.session_flags |= SSNFLAG_COUNTED_ESTABLISH;
 3366 
 3367                 if ((scb->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE) &&
 3368                         !(scb->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING))
 3369                 {
 3370                     assert(sf_base->iSessionsInitializing);
 3371                     sf_base->iSessionsInitializing--;
 3372                 }
 3373             }
 3374             break;
 3375         case TCP_STATE_CLOSING:
 3376             if (!(scb->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING))
 3377             {
 3378                 sf_base->iSessionsClosing++;
 3379                 scb->ha_state.session_flags |= SSNFLAG_COUNTED_CLOSING;
 3380                 if (scb->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH)
 3381                 {
 3382                     assert(sf_base->iSessionsEstablished);
 3383                     sf_base->iSessionsEstablished--;
 3384 
 3385                     if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP))
 3386                         UpdateFlowIPState(&sfFlow, IP_ARG(scb->client_ip), IP_ARG(scb->server_ip), SFS_STATE_TCP_CLOSED);
 3387                 }
 3388                 else if (scb->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE)
 3389                 {
 3390                     assert(sf_base->iSessionsInitializing);
 3391                     sf_base->iSessionsInitializing--;
 3392                 }
 3393             }
 3394             break;
 3395         case TCP_STATE_CLOSED:
 3396             if (scb->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING)
 3397             {
 3398                 assert(sf_base->iSessionsClosing);
 3399                 sf_base->iSessionsClosing--;
 3400             }
 3401             else if (scb->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH)
 3402             {
 3403                 assert(sf_base->iSessionsEstablished);
 3404                 sf_base->iSessionsEstablished--;
 3405 
 3406                 if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP))
 3407                     UpdateFlowIPState(&sfFlow, IP_ARG(scb->client_ip), IP_ARG(scb->server_ip), SFS_STATE_TCP_CLOSED);
 3408             }
 3409             else if (scb->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE)
 3410             {
 3411                 assert(sf_base->iSessionsInitializing);
 3412                 sf_base->iSessionsInitializing--;
 3413             }
 3414             break;
 3415         default:
 3416             break;
 3417     }
 3418     sf_base->stream5_mem_in_use = session_mem_in_use;
 3419 }
 3420 
 3421 //-------------------------------------------------------------------------
 3422 // ssn ingress is client; ssn egress is server
 3423 
 3424 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
 3425 static inline void SetPacketHeaderFoo (TcpSession* tcpssn, const Packet* p)
 3426 {
 3427     if ( ( p->packet_flags & PKT_FROM_CLIENT ) || p->pkth->egress_index == DAQ_PKTHDR_UNKNOWN )
 3428     {
 3429         tcpssn->ingress_index = p->pkth->ingress_index;
 3430         tcpssn->ingress_group = p->pkth->ingress_group;
 3431         // ssn egress may be unknown, but will be correct
 3432         tcpssn->egress_index = p->pkth->egress_index;
 3433         tcpssn->egress_group = p->pkth->egress_group;
 3434     }
 3435     else
 3436     {
 3437         if ( p->pkth->egress_index != DAQ_PKTHDR_FLOOD )
 3438         {
 3439             tcpssn->ingress_index = p->pkth->egress_index;
 3440             tcpssn->ingress_group = p->pkth->egress_group;
 3441         }
 3442         tcpssn->egress_index = p->pkth->ingress_index;
 3443         tcpssn->egress_group = p->pkth->ingress_group;
 3444     }
 3445 #ifdef HAVE_DAQ_FLOW_ID
 3446     tcpssn->daq_flow_id = p->pkth->flow_id;
 3447 #endif
 3448     tcpssn->daq_flags = p->pkth->flags;
 3449 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
 3450     tcpssn->address_space_id_dst = p->pkth->address_space_id_dst;
 3451     tcpssn->address_space_id_src = p->pkth->address_space_id_src;
 3452 #else
 3453     tcpssn->address_space_id = p->pkth->address_space_id;
 3454 #endif
 3455 }
 3456 
 3457 static inline void GetPacketHeaderFoo (
 3458         const TcpSession* tcpssn, const DAQ_PktHdr_t* phdr, EncodeFlags fwd,
 3459         DAQ_PktHdr_t* pkth, uint32_t dir)
 3460 {
 3461     if ( (dir & PKT_FROM_CLIENT) || tcpssn->egress_index == DAQ_PKTHDR_UNKNOWN )
 3462     {
 3463         pkth->ingress_index = tcpssn->ingress_index;
 3464         pkth->ingress_group = tcpssn->ingress_group;
 3465         pkth->egress_index = tcpssn->egress_index;
 3466         pkth->egress_group = tcpssn->egress_group;
 3467     }
 3468     else
 3469     {
 3470         pkth->ingress_index = tcpssn->egress_index;
 3471         pkth->ingress_group = tcpssn->egress_group;
 3472         pkth->egress_index = tcpssn->ingress_index;
 3473         pkth->egress_group = tcpssn->ingress_group;
 3474     }
 3475 #ifdef HAVE_DAQ_FLOW_ID
 3476     pkth->flow_id = tcpssn->daq_flow_id;
 3477 #endif
 3478     pkth->flags = tcpssn->daq_flags;
 3479     pkth->priv_ptr = tcpssn->priv_ptr;
 3480 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
 3481     pkth->address_space_id_dst = tcpssn->address_space_id_dst;
 3482     pkth->address_space_id_src = tcpssn->address_space_id_src;
 3483 #else
 3484     pkth->address_space_id = tcpssn->address_space_id;
 3485 #endif
 3486 #if defined(DAQ_VERSION) && DAQ_VERSION > 8
 3487     pkth->proto = phdr->proto;
 3488 #endif
 3489 
 3490 #if !defined(SFLINUX) && defined(DAQ_CAPA_CARRIER_ID)
 3491     pkth->carrier_id = phdr->carrier_id;
 3492 #endif
 3493 
 3494 #ifdef HAVE_DAQ_REAL_ADDRESSES
 3495     if (phdr->flags & DAQ_PKT_FLAG_REAL_ADDRESSES)
 3496     {
 3497         pkth->flags &= ~(DAQ_PKT_FLAG_REAL_SIP_V6 | DAQ_PKT_FLAG_REAL_DIP_V6);
 3498         if (fwd)
 3499         {
 3500             pkth->flags |= phdr->flags & (DAQ_PKT_FLAG_REAL_SIP_V6 | DAQ_PKT_FLAG_REAL_DIP_V6);
 3501             pkth->n_real_sPort = phdr->n_real_sPort;
 3502             pkth->n_real_dPort = phdr->n_real_dPort;
 3503             pkth->real_sIP = phdr->real_sIP;
 3504             pkth->real_dIP = phdr->real_dIP;
 3505         }
 3506         else
 3507         {
 3508             if (phdr->flags & DAQ_PKT_FLAG_REAL_SIP_V6)
 3509                 pkth->flags |= DAQ_PKT_FLAG_REAL_DIP_V6;
 3510             if (phdr->flags & DAQ_PKT_FLAG_REAL_DIP_V6)
 3511                 pkth->flags |= DAQ_PKT_FLAG_REAL_SIP_V6;
 3512             pkth->n_real_sPort = phdr->n_real_dPort;
 3513             pkth->n_real_dPort = phdr->n_real_sPort;
 3514             pkth->real_sIP = phdr->real_dIP;
 3515             pkth->real_dIP = phdr->real_sIP;
 3516         }
 3517     }
 3518 #endif
 3519 }
 3520 
 3521 static inline void SwapPacketHeaderFoo (TcpSession* tcpssn)
 3522 {
 3523     if ( tcpssn->egress_index != DAQ_PKTHDR_UNKNOWN )
 3524     {
 3525         int32_t ingress_index;
 3526         int32_t ingress_group;
 3527 
 3528         ingress_index = tcpssn->ingress_index;
 3529         ingress_group = tcpssn->ingress_group;
 3530         tcpssn->ingress_index = tcpssn->egress_index;
 3531         tcpssn->ingress_group = tcpssn->egress_group;
 3532         tcpssn->egress_index = ingress_index;
 3533         tcpssn->egress_group = ingress_group;
 3534     }
 3535 }
 3536 #endif
 3537 
 3538 
 3539 //-------------------------------------------------------------------------
 3540 
 3541 static inline int IsBetween(uint32_t low, uint32_t high, uint32_t cur)
 3542 {
 3543     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3544                 "(%X, %X, %X) = (low, high, cur)\n", low,high,cur););
 3545 
 3546     /* If we haven't seen anything, ie, low & high are 0, return true */
 3547     if ((low == 0) && (low == high))
 3548         return 1;
 3549 
 3550     return (SEQ_GEQ(cur, low) && SEQ_LEQ(cur, high));
 3551 }
 3552 
 3553 static inline bool TwoWayTraffic (SessionControlBlock *scb)
 3554 {
 3555     return ( (scb->ha_state.session_flags & SSNFLAG_SEEN_BOTH) == SSNFLAG_SEEN_BOTH );
 3556 }
 3557 
 3558 static inline uint32_t StreamGetWindow(
 3559         SessionControlBlock *scb, StreamTracker* st, TcpDataBlock* tdb)
 3560 {
 3561     int32_t window;
 3562 
 3563     if ( st->l_window )
 3564     {
 3565         // don't use the window if we may have missed scaling
 3566         if ( !(scb->session_state & STREAM_STATE_MIDSTREAM) )
 3567             return st->l_window;
 3568     }
 3569     // one way zero window is unitialized
 3570     // two way zero window is actually closed (regardless of scaling)
 3571     else if ( TwoWayTraffic(scb) )
 3572         return st->l_window;
 3573 
 3574     // ensure the data is in the window
 3575     window = tdb->end_seq - st->r_win_base;
 3576 
 3577     if(window <  0)
 3578         window = 0;
 3579 
 3580     return (uint32_t) window;
 3581 }
 3582 
 3583 // ack number must ack syn
 3584 static inline int ValidRstSynSent(StreamTracker *st, TcpDataBlock *tdb)
 3585 {
 3586     return tdb->ack == st->l_unackd;
 3587 }
 3588 
 3589 // per rfc 793 a rst is valid if the seq number is in window
 3590 // for all states but syn-sent (handled above).  however, we
 3591 // validate here based on how various implementations actually
 3592 // handle a rst.
 3593 static inline int ValidRst(
 3594         SessionControlBlock *scb, StreamTracker *st, TcpDataBlock *tdb)
 3595 {
 3596     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3597                 "Checking end_seq (%X) > r_win_base (%X) && "
 3598                 "seq (%X) < r_nxt_ack(%X)\n",
 3599                 tdb->end_seq, st->r_win_base, tdb->seq,
 3600                 st->r_nxt_ack+StreamGetWindow(scb, st, tdb)););
 3601 
 3602     switch (st->os_policy)
 3603     {
 3604         case STREAM_POLICY_HPUX11:
 3605             if (SEQ_GEQ(tdb->seq, st->r_nxt_ack))
 3606             {
 3607                 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3608                             "rst is valid seq (>= next seq)!\n"););
 3609                 return 1;
 3610             }
 3611             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3612                         "rst is not valid seq (>= next seq)!\n"););
 3613             return 0;
 3614             break;
 3615         case STREAM_POLICY_FIRST:
 3616         case STREAM_POLICY_NOACK:
 3617         case STREAM_POLICY_LAST:
 3618         case STREAM_POLICY_MACOS:
 3619         case STREAM_POLICY_WINDOWS:
 3620         case STREAM_POLICY_VISTA:
 3621         case STREAM_POLICY_WINDOWS2K3:
 3622         case STREAM_POLICY_HPUX10:
 3623         case STREAM_POLICY_IRIX:
 3624             if (SEQ_EQ(tdb->seq, st->r_nxt_ack))
 3625             {
 3626                 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3627                             "rst is valid seq (next seq)!\n"););
 3628                 return 1;
 3629             }
 3630             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3631                         "rst is not valid seq (next seq)!\n"););
 3632             return 0;
 3633             break;
 3634         case STREAM_POLICY_BSD:
 3635         case STREAM_POLICY_LINUX:
 3636         case STREAM_POLICY_OLD_LINUX:
 3637         case STREAM_POLICY_SOLARIS:
 3638             if(SEQ_GEQ(tdb->end_seq, st->r_win_base))
 3639             {
 3640                 // reset must be admitted when window closed
 3641                 if ( SEQ_LEQ(tdb->seq, st->r_win_base+StreamGetWindow(scb, st, tdb)) )
 3642                 {
 3643                     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3644                                 "rst is valid seq (within window)!\n"););
 3645                     return 1;
 3646                 }
 3647             }
 3648 
 3649             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3650                         "rst is not valid seq (within window)!\n"););
 3651             return 0;
 3652             break;
 3653     }
 3654 
 3655     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3656                 "rst is not valid!\n"););
 3657     return 0;
 3658 }
 3659 
 3660 static inline int ValidTimestamp(StreamTracker *talker, StreamTracker *listener, TcpDataBlock *tdb,
 3661         Packet *p, int *eventcode, int *got_ts)
 3662 {
 3663     if((p->tcph->th_flags & TH_RST) || (listener->tcp_policy->policy == STREAM_POLICY_NOACK))
 3664         return ACTION_NOTHING;
 3665 
 3666 #ifdef NORMALIZER
 3667 #if 0
 3668     if ( p->tcph->th_flags & TH_ACK &&
 3669             Normalize_GetMode(snort_conf, NORM_TCP_OPT) != NORM_MODE_OFF)
 3670     {
 3671         // FIXTHIS validate tsecr here (check that it was previously sent)
 3672         // checking for the most recent ts is easy enough must check if
 3673         // ts are up to date in retransmitted packets
 3674     }
 3675 #endif
 3676 #endif
 3677     /*
 3678      * check PAWS
 3679      */
 3680     if((talker->flags & TF_TSTAMP) && (listener->flags & TF_TSTAMP))
 3681     {
 3682         char validate_timestamp = 1;
 3683         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3684                     "Checking timestamps for PAWS\n"););
 3685 
 3686         *got_ts = StreamGetTcpTimestamp(p, &tdb->ts, 0);
 3687 
 3688         if (*got_ts)
 3689         {
 3690             if (listener->tcp_policy->policy == STREAM_POLICY_HPUX11)
 3691             {
 3692                 /* HPUX 11 ignores timestamps for out of order segments */
 3693                 if ((listener->flags & TF_PKT_MISSED) ||
 3694                         !SEQ_EQ(listener->r_nxt_ack, tdb->seq))
 3695                 {
 3696                     validate_timestamp = 0;
 3697                 }
 3698             }
 3699 
 3700             if (talker->flags & TF_TSTAMP_ZERO)
 3701             {
 3702                 /* Handle the case where the 3whs used a 0 timestamp.  Next packet
 3703                  * from that endpoint should have a valid timestamp... */
 3704                 if ((listener->tcp_policy->policy == STREAM_POLICY_LINUX) ||
 3705                         (listener->tcp_policy->policy == STREAM_POLICY_WINDOWS2K3))
 3706                 {
 3707                     /* Linux, Win2k3 et al.  do not support timestamps if
 3708                      * the 3whs used a 0 timestamp. */
 3709                     talker->flags &= ~TF_TSTAMP;
 3710                     listener->flags &= ~TF_TSTAMP;
 3711                     validate_timestamp = 0;
 3712                 }
 3713                 else if ((listener->tcp_policy->policy == STREAM_POLICY_OLD_LINUX) ||
 3714                         (listener->tcp_policy->policy == STREAM_POLICY_WINDOWS) ||
 3715                         (listener->tcp_policy->policy == STREAM_POLICY_VISTA))
 3716                 {
 3717                     /* Older Linux (2.2 kernel & earlier), Win32 (non 2K3)
 3718                      * allow the 3whs to use a 0 timestamp. */
 3719                     talker->flags &= ~TF_TSTAMP_ZERO;
 3720                     if(SEQ_EQ(listener->r_nxt_ack, tdb->seq))
 3721                     {
 3722                         talker->ts_last = tdb->ts;
 3723                         validate_timestamp = 0; /* Ignore the timestamp for this
 3724                                                  * first packet, next one will
 3725                                                  * checked. */
 3726                     }
 3727                 }
 3728             }
 3729 
 3730             if (validate_timestamp)
 3731             {
 3732                 int result = 0;
 3733                 if (listener->tcp_policy->policy == STREAM_POLICY_LINUX)
 3734                 {
 3735                     /* Linux 2.6 accepts timestamp values that are off
 3736                      * by one. */
 3737                     result = (int)((tdb->ts - talker->ts_last) + 1);
 3738                 }
 3739                 else
 3740                 {
 3741                     result = (int)(tdb->ts - talker->ts_last);
 3742                 }
 3743 
 3744 #ifdef DAQ_PKT_FLAG_RETRY_PACKET
 3745                 if(result < 0 && (p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET))
 3746                 {
 3747                     //  Retry packets can legitimately have old timestamps
 3748                     //  in TCP options (if a re-transmit comes in before
 3749                     //  the retry) so don't consider it an error.
 3750                     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3751                                 "Retry packet had old timestamp.  Reseting to last timestamp seen.\n"););
 3752                     tdb->ts = talker->ts_last;
 3753                 }
 3754                 else
 3755 #endif
 3756                 if( (talker->ts_last != 0) && result < 0)
 3757                 {
 3758                     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3759                                 "Packet outside PAWS window, dropping\n"););
 3760                     /* bail, we've got a packet outside the PAWS window! */
 3761                     //Discard();
 3762                     *eventcode |= EVENT_BAD_TIMESTAMP;
 3763                     NormalDropPacket(p);
 3764                     return ACTION_BAD_PKT;
 3765                 }
 3766                 else if ((talker->ts_last != 0) &&
 3767                         ((uint32_t)p->pkth->ts.tv_sec > talker->ts_last_pkt+PAWS_24DAYS))
 3768                 {
 3769                     /* this packet is from way too far into the future */
 3770                     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3771                                 "packet PAWS timestamp way too far ahead of"
 3772                                 "last packet %d %d...\n", p->pkth->ts.tv_sec,
 3773                                 talker->ts_last_pkt););
 3774                     //Discard();
 3775                     *eventcode |= EVENT_BAD_TIMESTAMP;
 3776                     NormalDropPacket(p);
 3777                     return ACTION_BAD_PKT;
 3778                 }
 3779                 else
 3780                 {
 3781                     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3782                                 "packet PAWS ok...\n"););
 3783                 }
 3784             }
 3785         }
 3786         else
 3787         {
 3788             /* we've got a packet with no timestamp, but 3whs indicated talker
 3789              * was doing timestamps.  This breaks protocol, however, some servers
 3790              * still ack the packet with the missing timestamp.  Log an alert,
 3791              * but continue to process the packet
 3792              */
 3793             *eventcode |= EVENT_NO_TIMESTAMP;
 3794             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3795                         "packet no timestamp, had one earlier from this side...ok for now...\n"););
 3796 
 3797             if (listener->tcp_policy->policy == STREAM_POLICY_SOLARIS)
 3798             {
 3799                 /* Solaris stops using timestamps if it receives a packet
 3800                  * without a timestamp and there were timestamps in use.
 3801                  */
 3802                 listener->flags &= ~TF_TSTAMP;
 3803             }
 3804             NormalDropPacket(p);
 3805         }
 3806     }
 3807     else if ( TCP_ISFLAGSET(p->tcph, TH_SYN) &&
 3808             !TCP_ISFLAGSET(p->tcph, TH_ACK) )
 3809     {
 3810         *got_ts = StreamGetTcpTimestamp(p, &tdb->ts, 0);
 3811         if ( *got_ts ) {
 3812             talker->flags |= TF_TSTAMP;
 3813             // In case of SYN, there is no ts_last is 0
 3814             // set it to the current value, so that computation of 
 3815             // ts_last is correct for subsequent packets.
 3816             talker->ts_last = tdb->ts;
 3817             talker->ts_last_pkt = p->pkth->ts.tv_sec;
 3818         }
 3819     }
 3820     else
 3821     {
 3822 #ifdef NORMALIZER
 3823         // if we are not handling timestamps, and this isn't a syn
 3824         // (only), and we have seen a valid 3way setup, then we strip
 3825         // (nop) the timestamp option.  this includes the cases where
 3826         // we disable timestamp handling.
 3827         int strip = ( SetupOK(talker) && SetupOK(listener) );
 3828 #else
 3829         int strip = 0;
 3830 #endif
 3831         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3832                     "listener not doing timestamps...\n"););
 3833         *got_ts = StreamGetTcpTimestamp(p, &tdb->ts, strip);
 3834 
 3835         if (*got_ts)
 3836         {
 3837             if (!(talker->flags & TF_TSTAMP))
 3838             {
 3839                 /* Since we skipped the SYN, may have missed the talker's
 3840                  * timestamp there, so set it now.
 3841                  */
 3842                 talker->flags |= TF_TSTAMP;
 3843                 if (tdb->ts == 0)
 3844                 {
 3845                     talker->flags |= TF_TSTAMP_ZERO;
 3846                 }
 3847             }
 3848 
 3849             /* Only valid to test this if listener is using timestamps.
 3850              * Otherwise, timestamp in this packet is not used, regardless
 3851              * of its value. */
 3852             if ((tdb->ts == 0) && (listener->flags & TF_TSTAMP))
 3853             {
 3854                 switch (listener->os_policy)
 3855                 {
 3856                     case STREAM_POLICY_WINDOWS:
 3857                     case STREAM_POLICY_VISTA:
 3858                     case STREAM_POLICY_WINDOWS2K3:
 3859                     case STREAM_POLICY_OLD_LINUX:
 3860                     case STREAM_POLICY_SOLARIS:
 3861                         /* Old Linux & Windows allows a 0 timestamp value. */
 3862                         break;
 3863                     default:
 3864                         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3865                                     "Packet with 0 timestamp, dropping\n"););
 3866                         //Discard();
 3867                         /* bail */
 3868                         *eventcode |= EVENT_BAD_TIMESTAMP;
 3869                         return ACTION_BAD_PKT;
 3870                 }
 3871             }
 3872         }
 3873     }
 3874     return ACTION_NOTHING;
 3875 }
 3876 
 3877 #ifdef S5_PEDANTIC
 3878 // From RFC 793:
 3879 //
 3880 //    Segment Receive  Test
 3881 //    Length  Window
 3882 //    ------- -------  -------------------------------------------
 3883 //
 3884 //       0       0     SEG.SEQ = RCV.NXT
 3885 //
 3886 //       0      >0     RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
 3887 //
 3888 //      >0       0     not acceptable
 3889 //
 3890 //      >0      >0     RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
 3891 //                     or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
 3892 //
 3893 static inline int ValidSeq(
 3894         const Packet* p, SessionControlBlock *scb, StreamTracker *st, TcpDataBlock *tdb, bool *before_win_base)
 3895 {
 3896     uint32_t win = StreamGetWindow(scb, st, tdb);
 3897 
 3898     if ( !p->dsize )
 3899     {
 3900         if ( !win )
 3901         {
 3902             return ( tdb->seq == st->r_win_base );
 3903         }
 3904         return SEQ_LEQ(st->r_win_base, tdb->seq) &&
 3905             SEQ_LT(tdb->seq, st->r_win_base+win);
 3906     }
 3907     if ( !win )
 3908         return 0;
 3909 
 3910     if ( SEQ_LEQ(st->r_win_base, tdb->seq) &&
 3911             SEQ_LT(tdb->seq, st->r_win_base+win) )
 3912         return 1;
 3913 
 3914     return SEQ_LEQ(st->r_win_base, tdb->end_seq) &&
 3915         SEQ_LT(tdb->end_seq, st->r_win_base+win);
 3916 }
 3917 #else
 3918 static inline int ValidSeq(
 3919         const Packet* p, SessionControlBlock *scb, StreamTracker *st, TcpDataBlock *tdb, bool *before_win_base)
 3920 {
 3921     int right_ok;
 3922     uint32_t left_seq;
 3923 
 3924     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3925                 "Checking end_seq (%X) > r_win_base (%X) && "
 3926                 "seq (%X) < r_nxt_ack(%X)\n",
 3927                 tdb->end_seq, st->r_win_base, tdb->seq,
 3928                 st->r_nxt_ack+StreamGetWindow(scb, st, tdb)););
 3929 
 3930     if ( SEQ_LT(st->r_nxt_ack, st->r_win_base) )
 3931         left_seq = st->r_nxt_ack;
 3932     else
 3933         left_seq = st->r_win_base;
 3934 
 3935     if ( p->dsize )
 3936         right_ok = SEQ_GT(tdb->end_seq, left_seq);
 3937     else
 3938         right_ok = SEQ_GEQ(tdb->end_seq, left_seq);
 3939 
 3940     if ( right_ok )
 3941     {
 3942         uint32_t win = StreamGetWindow(scb, st, tdb);
 3943 
 3944         if( SEQ_LEQ(tdb->seq, st->r_win_base+win) )
 3945         {
 3946             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3947                         "seq is within window!\n"););
 3948             return 1;
 3949         }
 3950         else
 3951         {
 3952             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3953                         "seq is past the end of the window!\n"););
 3954         }
 3955     }
 3956     else
 3957     {
 3958         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 3959                     "end_seq is before win_base\n"););
 3960         *before_win_base = true;
 3961     }
 3962     return 0;
 3963 }
 3964 #endif
 3965 
 3966 static inline void UpdateSsn(Packet* p, StreamTracker *rcv, StreamTracker *snd, TcpDataBlock *tdb)
 3967 {
 3968 #if 0
 3969 #ifdef NORMALIZER
 3970     if (
 3971             // FIXTHIS these checks are a hack to avoid off by one normalization
 3972             // due to FIN ... if last segment filled a hole, r_nxt_ack is not at
 3973             // end of data, FIN is ignored so sequence isn't bumped, and this
 3974             // forces seq-- on ACK of FIN.  :(
 3975         rcv->s_mgr.state == TCP_STATE_ESTABLISHED &&
 3976             rcv->s_mgr.state_queue == TCP_STATE_NONE &&
 3977             Normalize_GetMode(snort_conf, NORM_TCP_IPS) )
 3978             {
 3979             // walk the seglist until a gap or tdb->ack whichever is first
 3980             // if a gap exists prior to ack, move ack back to start of gap
 3981             StreamSegment* seg = snd->seglist;
 3982 
 3983             // FIXTHIS must check ack oob with empty seglist
 3984             // FIXTHIS add lower gap bound to tracker for efficiency?
 3985             while ( seg )
 3986             {
 3987             uint32_t seq = seg->seq + seg->size;
 3988             if ( SEQ_LEQ(tdb->ack, seq) )
 3989             break;
 3990 
 3991             seg = seg->next;
 3992 
 3993             if ( !seg || seg->seq > seq )
 3994             {
 3995                 // normalize here
 3996                 tdb->ack = seq;
 3997                 ((TCPHdr*)p->tcph)->th_ack = htonl(seq);
 3998                 p->packet_flags |= PKT_MODIFIED;
 3999                 break;
 4000             }
 4001             }
 4002             }
 4003 #endif
 4004 #endif
 4005     // ** if we don't see a segment, we can't track seq at ** below
 4006     // so we update the seq by the ack if it is beyond next expected
 4007     if(SEQ_GT(tdb->ack, rcv->l_unackd))
 4008         rcv->l_unackd = tdb->ack;
 4009 
 4010     // ** this is how we track the last seq number sent
 4011     // as is l_unackd is the "last left" seq recvd
 4012     snd->l_unackd = tdb->seq;
 4013 
 4014     if (SEQ_GT(tdb->end_seq, snd->l_nxt_seq))
 4015         snd->l_nxt_seq = tdb->end_seq;
 4016 
 4017 #ifdef S5_PEDANTIC
 4018     if ( SEQ_GT(tdb->ack, snd->r_win_base) &&
 4019             SEQ_LEQ(tdb->ack, snd->r_nxt_ack) )
 4020 #else
 4021         if ( SEQ_GT(tdb->ack, snd->r_win_base) )
 4022 #endif
 4023             snd->r_win_base = tdb->ack;
 4024 
 4025     snd->l_window = tdb->win;
 4026 }
 4027 
 4028 static void StreamInitPacket(void)
 4029 {
 4030     s5_pkt = Encode_New();
 4031 }
 4032 
 4033 static inline void SetupTcpDataBlock(TcpDataBlock *tdb, Packet *p)
 4034 {
 4035     tdb->seq = ntohl(p->tcph->th_seq);
 4036     tdb->ack = ntohl(p->tcph->th_ack);
 4037     tdb->win = ntohs(p->tcph->th_win);
 4038     tdb->end_seq = tdb->seq + (uint32_t) p->dsize;
 4039     tdb->ts = 0;
 4040 
 4041     if(p->tcph->th_flags & TH_SYN)
 4042     {
 4043         tdb->end_seq++;
 4044     }
 4045     // don't bump end_seq for fin here
 4046     // we will bump if/when fin is processed
 4047 
 4048     return;
 4049 }
 4050 
 4051 static void SegmentFree (StreamSegment *seg)
 4052 {
 4053     unsigned dropped = sizeof(StreamSegment);
 4054 
 4055     STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 4056                 "Dumping segment at seq %X, size %d, caplen %d\n",
 4057                 seg->seq, seg->size, seg->caplen););
 4058 
 4059     if ( seg->caplen > 0 )
 4060         dropped += seg->caplen - 1;  // seg contains 1st byte
 4061 
 4062     session_mem_in_use -= dropped;
 4063     free(seg);
 4064     s5stats.tcp_streamsegs_released++;
 4065 
 4066     STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 4067                 "SegmentFree dropped %d bytes\n", dropped););
 4068 }
 4069 
 4070 static void DeleteSeglist(StreamSegment *listhead)
 4071 {
 4072     StreamSegment *idx = listhead;
 4073     StreamSegment *dump_me;
 4074     int i = 0;
 4075 
 4076     STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 4077                 "In DeleteSeglist\n"););
 4078     while(idx)
 4079     {
 4080         i++;
 4081         dump_me = idx;
 4082         idx = idx->next;
 4083         SegmentFree(dump_me);
 4084     }
 4085 
 4086     STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 4087                 "Dropped %d segments\n", i););
 4088 }
 4089 
 4090 static inline int purge_alerts(StreamTracker *st, uint32_t flush_seq, void *ssnptr)
 4091 {
 4092     int i;
 4093     int new_count = 0;
 4094 
 4095     for (i=0;i<st->alert_count;i++)
 4096     {
 4097         StreamAlertInfo* ai = st->alerts + i;
 4098 
 4099         if (SEQ_LT(ai->seq, flush_seq) )
 4100         {
 4101             if(st->xtradata_mask && extra_data_log)
 4102             {
 4103                 extra_data_log(
 4104                         ssnptr, extra_data_config, xtradata_map,
 4105                         xtradata_func_count, st->xtradata_mask,
 4106                         ai->event_id, ai->event_second);
 4107             }
 4108             memset(ai, 0, sizeof(*ai));
 4109         }
 4110         else
 4111         {
 4112             if (new_count != i)
 4113             {
 4114                 st->alerts[new_count] = st->alerts[i];
 4115             }
 4116             new_count++;
 4117         }
 4118     }
 4119     st->alert_count = new_count;
 4120 
 4121     return new_count;
 4122 }
 4123 
 4124 static inline int purge_to_seq(TcpSession *tcpssn, StreamTracker *st, uint32_t flush_seq)
 4125 {
 4126     StreamSegment *ss = NULL;
 4127     StreamSegment *dump_me = NULL;
 4128     int purged_bytes = 0;
 4129     uint32_t last_ts = 0;
 4130 
 4131     if(st->seglist == NULL)
 4132     {
 4133         if ( SEQ_LT(st->seglist_base_seq, flush_seq) )
 4134         {
 4135             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4136                         "setting st->seglist_base_seq to 0x%X\n", flush_seq););
 4137             st->seglist_base_seq = flush_seq;
 4138         }
 4139         return 0;
 4140     }
 4141 
 4142     ss = st->seglist;
 4143 
 4144     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4145                 "In purge_to_seq, start seq = 0x%X end seq = 0x%X delta %d\n",
 4146                 ss->seq, flush_seq, flush_seq-ss->seq););
 4147     while(ss)
 4148     {
 4149         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4150                     "s: %X  sz: %d\n", ss->seq, ss->size););
 4151         dump_me = ss;
 4152 
 4153         ss = ss->next;
 4154         if(SEQ_LT(dump_me->seq, flush_seq))
 4155         {
 4156             if (dump_me->ts > last_ts)
 4157             {
 4158                 last_ts = dump_me->ts;
 4159             }
 4160             purged_bytes += StreamSeglistDeleteNodeTrim(st, dump_me, flush_seq);
 4161         }
 4162         else
 4163             break;
 4164     }
 4165 
 4166     if ( SEQ_LT(st->seglist_base_seq, flush_seq) )
 4167     {
 4168         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4169                     "setting st->seglist_base_seq to 0x%X\n", flush_seq););
 4170         st->seglist_base_seq = flush_seq;
 4171     }
 4172     if ( SEQ_LT(st->r_nxt_ack, flush_seq) )
 4173         st->r_nxt_ack = flush_seq;
 4174 
 4175     purge_alerts(st, flush_seq, (void *)tcpssn->scb);
 4176 
 4177     if (st->seglist == NULL)
 4178     {
 4179         st->seglist_tail = NULL;
 4180     }
 4181 
 4182     /* Update the "last" time stamp seen from the other side
 4183      * to be the most recent timestamp (largest) that was removed
 4184      * from the queue.  This will ensure that as we go forward,
 4185      * last timestamp is the highest one that we had stored and
 4186      * purged and handle the case when packets arrive out of order,
 4187      * such as:
 4188      * P1: seq 10, length 10, timestamp 10
 4189      * P3: seq 30, length 10, timestamp 30
 4190      * P2: seq 20, length 10, timestamp 20
 4191      *
 4192      * Without doing it this way, the timestamp would be 20.  With
 4193      * the next packet to arrive (P4, seq 40), the ts_last value
 4194      * wouldn't be updated for the talker in ProcessTcp() since that
 4195      * code specificially looks for the NEXT sequence number.
 4196      */
 4197     if ( !last_ts )
 4198         return purged_bytes;
 4199 
 4200     if (st == &tcpssn->client)
 4201     {
 4202         int32_t delta = last_ts - tcpssn->server.ts_last;
 4203         if (delta > 0)
 4204             tcpssn->server.ts_last = last_ts;
 4205     }
 4206     else if (st == &tcpssn->server)
 4207     {
 4208         int32_t delta = last_ts - tcpssn->client.ts_last;
 4209         if (delta > 0)
 4210             tcpssn->client.ts_last = last_ts;
 4211     }
 4212 
 4213     return purged_bytes;
 4214 }
 4215 
 4216 static inline void purge_all (StreamTracker *st)
 4217 {
 4218     DeleteSeglist(st->seglist);
 4219     st->seglist = st->seglist_tail = st->seglist_next = NULL;
 4220     st->seg_count = st->flush_count = 0;
 4221     st->seg_bytes_total = st->seg_bytes_logical = 0;
 4222 }
 4223 
 4224 // purge_flushed_ackd():
 4225 // * must only purge flushed and acked bytes
 4226 // * we may flush partial segments
 4227 // * must adjust seq->seq and seg->size when a flush gets only the
 4228 //   initial part of a segment
 4229 // * FIXTHIS need flag to mark any reassembled packets that have a gap
 4230 //   (if we reassemble such)
 4231 static inline int purge_flushed_ackd (TcpSession *tcpssn, StreamTracker *st)
 4232 {
 4233     StreamSegment* seg = st->seglist;
 4234     uint32_t seq;
 4235 
 4236     if ( !st->seglist )
 4237         return 0;
 4238 
 4239     seq = st->seglist->seq;
 4240 
 4241     while ( seg && seg->buffered )
 4242     {
 4243         uint32_t end = seg->seq + seg->size;
 4244 
 4245         if ( SEQ_GT(end, st->r_win_base) )
 4246         {
 4247             seq = st->r_win_base;
 4248             break;
 4249         }
 4250         seq = end;
 4251         seg = seg->next;
 4252     }
 4253     if ( seq != st->seglist->seq )
 4254         return purge_to_seq(tcpssn, st, seq);
 4255 
 4256     return 0;
 4257 }
 4258 
 4259 static void ShowRebuiltPacket (Packet* p)
 4260 {
 4261     if(stream_session_config->flags & STREAM_CONFIG_SHOW_PACKETS)
 4262     {
 4263         //ClearDumpBuf();
 4264         printf("+++++++++++++++++++Stream Packet+++++++++++++++++++++\n");
 4265         PrintIPPkt(stdout, IPPROTO_TCP, p);
 4266         printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
 4267         //ClearDumpBuf();
 4268     }
 4269 }
 4270 
 4271 static inline int _flush_to_seq_noack( TcpSession *tcpssn, StreamTracker *st, uint32_t bytes,
 4272         Packet *p, sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir )
 4273 {
 4274     uint32_t stop_seq;
 4275     uint32_t footprint = 0;
 4276     uint32_t bytes_processed = 0;
 4277     PROFILE_VARS;
 4278 
 4279     PREPROC_PROFILE_START(s5TcpFlushPerfStats);
 4280 
 4281     if(p->dsize == 0)
 4282         return bytes_processed;
 4283 
 4284     // if not specified, set bytes to flush to what was acked
 4285     if ( !bytes && SEQ_GT(st->r_win_base, st->seglist_base_seq) )
 4286         bytes = st->r_win_base - st->seglist_base_seq;
 4287 
 4288     stop_seq = st->seglist_base_seq + bytes;
 4289 
 4290     {
 4291         footprint = stop_seq - st->seglist_base_seq;
 4292 
 4293         if(footprint == 0)
 4294         {
 4295             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4296                         "Negative footprint, bailing %d (0x%X - 0x%X)\n",
 4297                         footprint, stop_seq, st->seglist_base_seq););
 4298             PREPROC_PROFILE_END(s5TcpFlushPerfStats);
 4299 
 4300             return bytes_processed;
 4301         }
 4302 
 4303 #if 0
 4304         //Might not need this as we are not buffering the packets??
 4305 #ifdef DEBUG_STREAM
 4306         if(footprint < st->seg_bytes_logical)
 4307         {
 4308             STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4309                         "Footprint less than queued bytes, "
 4310                         "win_base: 0x%X base_seq: 0x%X\n",
 4311                         stop_seq, st->seglist_base_seq););
 4312         }
 4313 #endif
 4314 #endif
 4315 
 4316 #if 0
 4317         //Won't need this as we are not buffering the packets
 4318         if(footprint > p->max_dsize)
 4319         {
 4320             /* this is as much as we can pack into a stream buffer */
 4321             footprint = p->max_dsize;
 4322             stop_seq = st->seglist_base_seq + footprint;
 4323         }
 4324 #endif
 4325 
 4326         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4327                     "Attempting to flush %lu bytes\n", footprint););
 4328 
 4329         st->seglist_base_seq = stop_seq;
 4330         st->seglist_next->buffered = SL_BUF_FLUSHED;
 4331         st->flush_count++;
 4332         p->packet_flags &= ~PKT_STREAM_INSERT;
 4333         p->packet_flags |= (PKT_REBUILT_STREAM|PKT_STREAM_EST);
 4334         bytes_processed = p->dsize;
 4335 
 4336         sfBase.iStreamFlushes++;
 4337         ShowRebuiltPacket(p);
 4338         s5stats.tcp_rebuilt_packets++;
 4339         UpdateStreamReassStats(&sfBase, bytes_processed);
 4340 
 4341     }
 4342 
 4343     if ( st->tcp_policy )
 4344         UpdateFlushMgr(snort_conf, &st->flush_mgr, &st->tcp_policy->flush_point_list, st->flags);
 4345 
 4346     /* tell them how many bytes we processed */
 4347     PREPROC_PROFILE_END(s5TcpFlushPerfStats);
 4348     return bytes_processed;
 4349 }
 4350 
 4351 static inline unsigned int getSegmentFlushSize(
 4352         StreamTracker* st,
 4353         StreamSegment *ss,
 4354         uint32_t to_seq,
 4355         unsigned int flushBufSize
 4356         )
 4357 {
 4358     unsigned int flushSize = ss->size;
 4359 
 4360     //copy only till flush buffer gets full
 4361     if ( flushSize > flushBufSize )
 4362         flushSize = flushBufSize;
 4363 
 4364     // copy only to flush point
 4365     if ( s5_paf_active(&st->paf_state) && SEQ_GT(ss->seq + flushSize, to_seq) )
 4366         flushSize = to_seq - ss->seq;
 4367 
 4368     return flushSize;
 4369 }
 4370 
 4371 static int PseudoFlushStream(
 4372    Packet* p, StreamTracker *st, uint32_t toSeq,
 4373    uint8_t *flushbuf, const uint8_t *flushbuf_end)
 4374 {
 4375     StreamSegment *ss = NULL, *seglist;
 4376     uint16_t bytes_flushed = 0;
 4377     uint32_t flushbuf_size, bytes_to_copy;
 4378     int ret;
 4379     PROFILE_VARS;
 4380 
 4381     if ( st->seglist == NULL || st->seglist_tail == NULL )
 4382         return -1;
 4383 
 4384     PREPROC_PROFILE_START(s5TcpBuildPacketPerfStats);
 4385 
 4386     // skip over previously pseudo flushed segments
 4387     seglist = st->seglist_next;
 4388 
 4389     for(ss = seglist; ss && SEQ_LT(ss->seq,  toSeq); ss = ss->next)
 4390     {
 4391         flushbuf_size = flushbuf_end - flushbuf;
 4392         bytes_to_copy = getSegmentFlushSize(st, ss, toSeq, flushbuf_size);
 4393 
 4394         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4395                    "Copying %u bytes for pseudo flushing from %X\n",
 4396                    bytes_to_copy, ss->seq););
 4397 
 4398         ret = SafeMemcpy(flushbuf, ss->payload,
 4399                     bytes_to_copy, flushbuf, flushbuf_end);
 4400 
 4401         if (ret == SAFEMEM_ERROR)
 4402         {
 4403             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4404                             "ERROR writing flushbuf while pseudo flushing."
 4405                             "Attempting to write flushbuf out of range!\n"););
 4406         }
 4407         else
 4408         {
 4409             flushbuf += bytes_to_copy;
 4410         }
 4411 
 4412         bytes_flushed += bytes_to_copy;
 4413         if (ss->next)
 4414         {
 4415             st->seglist_next = ss->next;
 4416         }
 4417 
 4418         if ( flushbuf >= flushbuf_end )
 4419             break;
 4420 
 4421         if ( SEQ_EQ(ss->seq + bytes_to_copy,  toSeq) )
 4422             break;
 4423 
 4424     }
 4425 
 4426     PREPROC_PROFILE_END(s5TcpBuildPacketPerfStats);
 4427     return bytes_flushed;
 4428 }
 4429 
 4430 static inline void pseudo_flush(
 4431 TcpSession *tcpssn, StreamTracker *st, uint32_t bytes, Packet *p,
 4432         sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
 4433 {
 4434     uint32_t start_seq;
 4435     uint32_t stop_seq;
 4436     uint32_t footprint = 0;
 4437     uint32_t bytes_processed = 0;
 4438     int32_t flushed_bytes;
 4439     StreamSegment *ss = NULL;
 4440 
 4441 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
 4442     DAQ_PktHdr_t pkth;
 4443 #endif
 4444     EncodeFlags enc_flags = 0;
 4445     PROFILE_VARS;
 4446 
 4447     if (!bytes)
 4448     {
 4449         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4450                "No bytes to pseudo flush\n"););
 4451         return;
 4452     }
 4453     PREPROC_PROFILE_START(s5TcpFlushPerfStats);
 4454 
 4455     if ( !p->packet_flags || (dir & p->packet_flags) )
 4456         enc_flags = ENC_FLAG_FWD;
 4457 
 4458 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
 4459     GetPacketHeaderFoo(tcpssn, p->pkth, enc_flags, &pkth, dir);
 4460     Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, &pkth, 0);
 4461 #elif defined(HAVE_DAQ_ACQUIRE_WITH_META)
 4462     Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, 0);
 4463 #else
 4464     Encode_Format(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP);
 4465 #endif
 4466 
 4467     s5_pkt_end = s5_pkt->data + s5_pkt->max_dsize;
 4468 
 4469     ss = st->seglist_next;
 4470     stop_seq = st->seglist_next->seq + bytes;
 4471     do
 4472     {
 4473         footprint = bytes;
 4474         if(footprint > s5_pkt->max_dsize)
 4475         {
 4476             /* this is as much as we can pack into a stream buffer */
 4477             footprint = s5_pkt->max_dsize;
 4478             stop_seq = st->seglist_next->seq + footprint;
 4479         }
 4480 
 4481         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4482                     "Attempting to pseudo flush %lu bytes\n", footprint););
 4483         /* Capture the seq of the first octet before flush changes the sequence numbers */
 4484         start_seq = htonl(st->seglist_next->seq);
 4485 
 4486         /* setup the pseudopacket payload */
 4487         flushed_bytes = PseudoFlushStream(p, st, stop_seq, (uint8_t *)s5_pkt->data, s5_pkt_end);
 4488 
 4489         if(flushed_bytes == -1)
 4490         {
 4491             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4492                     "Failed to pseudo flush the stream\n"););
 4493             return;
 4494         }
 4495         if (flushed_bytes == 0)
 4496         {
 4497             /* No more ACK'd data... bail */
 4498             break;
 4499         }
 4500 
 4501         bytes_processed += flushed_bytes;
 4502 
 4503         ((TCPHdr *)s5_pkt->tcph)->th_seq = start_seq;
 4504         s5_pkt->packet_flags |= (PKT_REBUILT_STREAM|PKT_STREAM_EST);
 4505         s5_pkt->dsize = (uint16_t)flushed_bytes;
 4506 
 4507         s5_pkt->packet_flags |= PKT_PDU_TAIL;
 4508         s5_pkt->packet_flags |= PKT_PSEUDO_FLUSH;
 4509 
 4510         Encode_Update(s5_pkt);
 4511 
 4512         if(IS_IP4(s5_pkt))
 4513         {
 4514             s5_pkt->inner_ip4h.ip_len = s5_pkt->iph->ip_len;
 4515         }
 4516         else
 4517         {
 4518             IP6RawHdr* ip6h = (IP6RawHdr*)s5_pkt->raw_ip6h;
 4519             if ( ip6h ) s5_pkt->inner_ip6h.len = ip6h->ip6plen;
 4520         }
 4521 
 4522         ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_sec = st->seglist_next->tv.tv_sec;
 4523         ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_usec = st->seglist_next->tv.tv_usec;
 4524 
 4525         s5_pkt->packet_flags |= dir;
 4526         s5_pkt->ssnptr = (void *) tcpssn->scb;
 4527 #ifdef TARGET_BASED
 4528         s5_pkt->application_protocol_ordinal = p->application_protocol_ordinal;
 4529 #endif
 4530         PREPROC_PROFILE_TMPEND(s5TcpFlushPerfStats);
 4531         {
 4532             int tmp_do_detect, tmp_do_detect_content;
 4533             PROFILE_VARS;
 4534 
 4535             PREPROC_PROFILE_START(s5TcpProcessRebuiltPerfStats);
 4536             tmp_do_detect = do_detect;
 4537             tmp_do_detect_content = do_detect_content;
 4538 
 4539             SnortEventqPush();
 4540             Preprocess(s5_pkt);
 4541             SnortEventqPop();
 4542             DetectReset(s5_pkt->data, s5_pkt->dsize);
 4543 
 4544             do_detect = tmp_do_detect;
 4545             do_detect_content = tmp_do_detect_content;
 4546             PREPROC_PROFILE_END(s5TcpProcessRebuiltPerfStats);
 4547         }
 4548         PREPROC_PROFILE_TMPSTART(s5TcpFlushPerfStats);
 4549     } while(bytes_processed < bytes);
 4550 
 4551     st->seglist_next = ss;
 4552     PREPROC_PROFILE_END(s5TcpFlushPerfStats);
 4553 }
 4554 
 4555 static inline int _flush_to_seq (
 4556 
 4557         TcpSession *tcpssn, StreamTracker *st, uint32_t bytes, Packet *p,
 4558         sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
 4559 {
 4560     uint32_t start_seq;
 4561     uint32_t stop_seq;
 4562     uint32_t footprint = 0;
 4563     uint32_t bytes_processed = 0;
 4564     int32_t flushed_bytes;
 4565 
 4566 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
 4567     DAQ_PktHdr_t pkth;
 4568 #endif
 4569     EncodeFlags enc_flags = 0;
 4570     PROFILE_VARS;
 4571 
 4572     PREPROC_PROFILE_START(s5TcpFlushPerfStats);
 4573 
 4574     if(st->paf_state.fpt_eoh)
 4575         tcpssn->pp_flags |= PP_HTTPINSPECT_PAF_FLUSH_POST_HDR;
 4576     else
 4577         tcpssn->pp_flags &= ~PP_HTTPINSPECT_PAF_FLUSH_POST_HDR;
 4578 
 4579     if ( !p->packet_flags || (dir & p->packet_flags) )
 4580         enc_flags = ENC_FLAG_FWD;
 4581 
 4582 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
 4583     GetPacketHeaderFoo(tcpssn, p->pkth, enc_flags, &pkth, dir);
 4584     Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, &pkth, 0);
 4585 #elif defined(HAVE_DAQ_ACQUIRE_WITH_META)
 4586     Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, 0);
 4587 #else
 4588     Encode_Format(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP);
 4589 #endif
 4590 
 4591     s5_pkt_end = s5_pkt->data + s5_pkt->max_dsize;
 4592 
 4593     // TBD in ips mode, these should be coming from current packet (tdb)
 4594     ((TCPHdr *)s5_pkt->tcph)->th_ack = htonl(st->l_unackd);
 4595     ((TCPHdr *)s5_pkt->tcph)->th_win = htons((uint16_t)st->l_window);
 4596 
 4597     // if not specified, set bytes to flush to what was acked
 4598     if ( !bytes && SEQ_GT(st->r_win_base, st->seglist_base_seq) )
 4599         bytes = st->r_win_base - st->seglist_base_seq;
 4600 
 4601     stop_seq = st->seglist_base_seq + bytes;
 4602 
 4603     do
 4604     {
 4605         footprint = stop_seq - st->seglist_base_seq;
 4606 
 4607         if(footprint == 0)
 4608         {
 4609             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4610                         "Negative footprint, bailing %d (0x%X - 0x%X)\n",
 4611                         footprint, stop_seq, st->seglist_base_seq););
 4612             PREPROC_PROFILE_END(s5TcpFlushPerfStats);
 4613 
 4614             return bytes_processed;
 4615         }
 4616 
 4617 #ifdef STREAM_DEBUG_ENABLED
 4618         if(footprint < st->seg_bytes_logical)
 4619         {
 4620             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4621                         "Footprint less than queued bytes, "
 4622                         "win_base: 0x%X base_seq: 0x%X\n",
 4623                         stop_seq, st->seglist_base_seq););
 4624         }
 4625 #endif
 4626 
 4627         if(footprint > s5_pkt->max_dsize)
 4628         {
 4629             /* this is as much as we can pack into a stream buffer */
 4630             footprint = s5_pkt->max_dsize;
 4631             stop_seq = st->seglist_base_seq + footprint;
 4632         }
 4633 
 4634         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4635                     "Attempting to flush %lu bytes\n", footprint););
 4636 
 4637         /* Capture the seq of the first octet before flush changes the sequence numbers */
 4638         start_seq = htonl(st->seglist_next->seq);
 4639 
 4640         /* setup the pseudopacket payload */
 4641         flushed_bytes = FlushStream(p, st, stop_seq, (uint8_t *)s5_pkt->data, s5_pkt_end);
 4642 
 4643         if(flushed_bytes == -1)
 4644         {
 4645             /* couldn't put a stream together for whatever reason
 4646              * should probably clean the seglist and bail...
 4647              */
 4648             if(st->seglist)
 4649             {
 4650                 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4651                             "dumping entire seglist!\n"););
 4652                 purge_all(st);
 4653             }
 4654 
 4655             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4656                         "setting st->seglist_base_seq to 0x%X\n", stop_seq););
 4657             st->seglist_base_seq = stop_seq;
 4658 
 4659             PREPROC_PROFILE_END(s5TcpFlushPerfStats);
 4660             return bytes_processed;
 4661         }
 4662 
 4663         if (flushed_bytes == 0)
 4664         {
 4665             /* No more ACK'd data... bail */
 4666             break;
 4667         }
 4668 
 4669         ((TCPHdr *)s5_pkt->tcph)->th_seq = start_seq;
 4670         s5_pkt->packet_flags |= (PKT_REBUILT_STREAM|PKT_STREAM_EST);
 4671         s5_pkt->dsize = (uint16_t)flushed_bytes;
 4672 
 4673         if ((p->packet_flags & PKT_PDU_TAIL))
 4674             s5_pkt->packet_flags |= PKT_PDU_TAIL;
 4675 
 4676         Encode_Update(s5_pkt);
 4677 
 4678         if(IS_IP4(s5_pkt))
 4679         {
 4680             s5_pkt->inner_ip4h.ip_len = s5_pkt->iph->ip_len;
 4681         }
 4682         else
 4683         {
 4684             IP6RawHdr* ip6h = (IP6RawHdr*)s5_pkt->raw_ip6h;
 4685             if ( ip6h ) s5_pkt->inner_ip6h.len = ip6h->ip6plen;
 4686         }
 4687 
 4688         ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_sec = st->seglist_next->tv.tv_sec;
 4689         ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_usec = st->seglist_next->tv.tv_usec;
 4690 
 4691         sfBase.iStreamFlushes++;
 4692         bytes_processed += s5_pkt->dsize;
 4693 
 4694         s5_pkt->packet_flags |= dir;
 4695         s5_pkt->ssnptr = (void *) tcpssn->scb;
 4696 #ifdef TARGET_BASED
 4697         s5_pkt->application_protocol_ordinal = p->application_protocol_ordinal;
 4698 #endif
 4699         ShowRebuiltPacket(s5_pkt);
 4700         s5stats.tcp_rebuilt_packets++;
 4701         UpdateStreamReassStats(&sfBase, flushed_bytes);
 4702 
 4703         PREPROC_PROFILE_TMPEND(s5TcpFlushPerfStats);
 4704         {
 4705             int tmp_do_detect, tmp_do_detect_content;
 4706             PROFILE_VARS;
 4707 
 4708             PREPROC_PROFILE_START(s5TcpProcessRebuiltPerfStats);
 4709             tmp_do_detect = do_detect;
 4710             tmp_do_detect_content = do_detect_content;
 4711 
 4712             SnortEventqPush();
 4713             Preprocess(s5_pkt);
 4714             SnortEventqPop();
 4715             DetectReset(s5_pkt->data, s5_pkt->dsize);
 4716 
 4717             do_detect = tmp_do_detect;
 4718             do_detect_content = tmp_do_detect_content;
 4719             PREPROC_PROFILE_END(s5TcpProcessRebuiltPerfStats);
 4720         }
 4721         PREPROC_PROFILE_TMPSTART(s5TcpFlushPerfStats);
 4722 
 4723         // TBD abort should be by PAF callback only since
 4724         // recovery may be possible in some cases
 4725         if ( st->flags & TF_MISSING_PKT )
 4726         {
 4727             st->flags |= TF_MISSING_PREV_PKT;
 4728             st->flags |= TF_PKT_MISSED;
 4729             st->flags &= ~TF_MISSING_PKT;
 4730             s5stats.tcp_gaps++;
 4731         }
 4732         else
 4733         {
 4734             st->flags &= ~TF_MISSING_PREV_PKT;
 4735         }
 4736     } while ( DataToFlush(st) );
 4737 
 4738     if ( st->tcp_policy )
 4739         UpdateFlushMgr(snort_conf, &st->flush_mgr, &st->tcp_policy->flush_point_list, st->flags);
 4740 
 4741     /* tell them how many bytes we processed */
 4742     PREPROC_PROFILE_END(s5TcpFlushPerfStats);
 4743     return bytes_processed;
 4744 }
 4745 
 4746 static inline int flush_to_seq_noack( TcpSession *tcpssn, StreamTracker *st, uint32_t bytes,
 4747         Packet *p, sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir )
 4748 {
 4749     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4750                 "In flush_to_seq_noack()\n"););
 4751 
 4752     if ( !bytes )
 4753     {
 4754         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4755                     "bailing, no data\n"););
 4756         return 0;
 4757     }
 4758 
 4759     if ( !st->seglist_next )
 4760     {
 4761         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4762                     "bailing, bad seglist ptr\n"););
 4763         return 0;
 4764     }
 4765 
 4766 #if 0
 4767     //Might not need this. Check with Russ.
 4768     if (!DataToFlush(st) && !(st->flags & TF_FORCE_FLUSH))
 4769     {
 4770         STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4771                     "only 1 packet in seglist no need to flush\n"););
 4772         return 0;
 4773     }
 4774 #endif
 4775 
 4776     st->flags &= ~TF_MISSING_PKT;
 4777     st->flags &= ~TF_MISSING_PREV_PKT;
 4778 
 4779     /* This will set this flag on the first reassembly
 4780      * if reassembly for this direction was set midstream */
 4781     if ( SEQ_LT(st->seglist_base_seq, st->seglist_next->seq) )
 4782     {
 4783         uint32_t missed = st->seglist_next->seq - st->seglist_base_seq;
 4784 
 4785         if ( missed <= bytes )
 4786             bytes -= missed;
 4787 
 4788         st->flags |= TF_MISSING_PREV_PKT;
 4789         st->flags |= TF_PKT_MISSED;
 4790         s5stats.tcp_gaps++;
 4791         st->seglist_base_seq = st->seglist_next->seq;
 4792 
 4793         if ( !bytes )
 4794             return 0;
 4795     }
 4796 
 4797     return _flush_to_seq_noack(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
 4798 
 4799 }
 4800 /*
 4801  * flush a seglist up to the given point, generate a pseudopacket,
 4802  * and fire it thru the system.
 4803  */
 4804 static inline int flush_to_seq(
 4805         TcpSession *tcpssn, StreamTracker *st, uint32_t bytes, Packet *p,
 4806         sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
 4807 {
 4808     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4809                 "In flush_to_seq()\n"););
 4810 
 4811     if ( !bytes )
 4812     {
 4813         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4814                     "bailing, no data\n"););
 4815         return 0;
 4816     }
 4817 
 4818     if ( !st->seglist_next )
 4819     {
 4820         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4821                     "bailing, bad seglist ptr\n"););
 4822         return 0;
 4823     }
 4824 
 4825     if (!DataToFlush(st) && !(st->flags & TF_FORCE_FLUSH))
 4826     {
 4827         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4828                     "only 1 packet in seglist no need to flush\n"););
 4829         return 0;
 4830     }
 4831 
 4832     st->flags &= ~TF_MISSING_PREV_PKT;
 4833 
 4834     /* This will set this flag on the first reassembly
 4835      * if reassembly for this direction was set midstream */
 4836     if ( SEQ_LT(st->seglist_base_seq, st->seglist_next->seq) &&
 4837             !(st->flags & TF_FIRST_PKT_MISSING) )
 4838     {
 4839         uint32_t missed = st->seglist_next->seq - st->seglist_base_seq;
 4840 
 4841         if ( missed <= bytes )
 4842             bytes -= missed;
 4843 
 4844         st->flags |= TF_MISSING_PREV_PKT;
 4845         st->flags |= TF_PKT_MISSED;
 4846         s5stats.tcp_gaps++;
 4847         st->seglist_base_seq = st->seglist_next->seq;
 4848 
 4849         if ( !bytes )
 4850             return 0;
 4851     }
 4852     st->flags &= ~TF_FIRST_PKT_MISSING;
 4853 
 4854     if (p->packet_flags & PKT_PSEUDO_FLUSH)
 4855     {
 4856          pseudo_flush(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
 4857          return 0;
 4858     }
 4859  
 4860     return _flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
 4861 
 4862 }
 4863 
 4864 /*
 4865  * get the footprint for the current seglist, the difference
 4866  * between our base sequence and the last ack'd sequence we
 4867  * received
 4868  */
 4869 static inline uint32_t get_q_footprint(StreamTracker *st)
 4870 {
 4871     uint32_t fp;
 4872 
 4873     if (st == NULL)
 4874     {
 4875         return 0;
 4876     }
 4877 
 4878     fp = st->r_win_base - st->seglist_base_seq;
 4879 
 4880     if(fp <= 0)
 4881         return 0;
 4882 
 4883     st->seglist_next = st->seglist;
 4884     return fp;
 4885 }
 4886 
 4887 static bool two_way_traffic=true;
 4888 // FIXTHIS get_q_sequenced() performance could possibly be
 4889 // boosted by tracking sequenced bytes as seglist is updated
 4890 // to avoid the while loop, etc. below.
 4891 static inline uint32_t get_q_sequenced(StreamTracker *st)
 4892 {
 4893     uint32_t len;
 4894     StreamSegment* seg = st ? st->seglist : NULL;
 4895     StreamSegment* base = NULL;
 4896 
 4897     if ( !seg )
 4898         return 0;
 4899 
 4900     if ( two_way_traffic && SEQ_LT(st->r_win_base, seg->seq) )
 4901         return 0;
 4902 
 4903     while ( seg->next && (seg->next->seq == seg->seq + seg->size) )
 4904     {
 4905         if ( !seg->buffered && !base )
 4906             base = seg;
 4907         seg = seg->next;
 4908     }
 4909     if ( !seg->buffered && !base )
 4910         base = seg;
 4911 
 4912     if ( !base )
 4913         return 0;
 4914 
 4915     st->seglist_next = base;
 4916     st->seglist_base_seq = base->seq;
 4917     len = seg->seq + seg->size - base->seq;
 4918 
 4919     return ( len > 0 ) ? len : 0;
 4920 }
 4921 
 4922 static inline int flush_ackd(
 4923         TcpSession *tcpssn, StreamTracker *st, Packet *p,
 4924         sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
 4925 {
 4926     uint32_t bytes = get_q_footprint(st);
 4927     return flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
 4928 }
 4929 
 4930 // FIXTHIS flush_stream() calls should be replaced with calls to
 4931 // CheckFlushPolicyOn*() with the exception that for the *OnAck() case,
 4932 // any available ackd data must be flushed in both directions.
 4933 static inline int flush_stream(
 4934         TcpSession *tcpssn, StreamTracker *st, Packet *p,
 4935         sfaddr_t* sip, sfaddr_t* dip, uint16_t sp, uint16_t dp, uint32_t dir)
 4936 {
 4937     FlushMgr* fm;
 4938 #ifdef NORMALIZER
 4939     if ( Stream_NormGetMode(st->reassembly_policy, snort_conf, NORM_TCP_IPS) == NORM_MODE_ON )
 4940     {
 4941         uint32_t bytes = get_q_sequenced(st);
 4942         return flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
 4943     }
 4944 #endif
 4945     fm = &tcpssn->server.flush_mgr;
 4946     if(fm->flush_policy == STREAM_FLPOLICY_PROTOCOL_NOACK)
 4947     {
 4948         uint32_t bytes = get_q_sequenced(st);
 4949         return flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
 4950     }
 4951     else if (fm->flush_policy == STREAM_FLPOLICY_FOOTPRINT_NOACK)
 4952     {
 4953         uint32_t bytes = get_q_sequenced(st);
 4954         return flush_to_seq_noack(tcpssn, st, bytes, p, sip, dip, sp, dp, dir);
 4955     }
 4956     return flush_ackd(tcpssn, st, p, sip, dip, sp, dp, dir);
 4957 }
 4958 
 4959 static int FlushStream(
 4960         Packet* p, StreamTracker *st, uint32_t toSeq, uint8_t *flushbuf,
 4961         const uint8_t *flushbuf_end)
 4962 {
 4963     StreamSegment *ss = NULL, *seglist, *sr;
 4964     uint16_t bytes_flushed = 0;
 4965     uint16_t bytes_skipped = 0;
 4966     uint32_t bytes_queued = st->seg_bytes_logical;
 4967     uint32_t segs = 0;
 4968     int ret;
 4969     PROFILE_VARS;
 4970 
 4971     if ( st->seglist == NULL || st->seglist_tail == NULL )
 4972         return -1;
 4973 
 4974     PREPROC_PROFILE_START(s5TcpBuildPacketPerfStats);
 4975 
 4976     // skip over previously flushed segments
 4977     seglist = st->seglist_next;
 4978 
 4979     for(ss = seglist; ss && SEQ_LT(ss->seq,  toSeq); ss = ss->next)
 4980     {
 4981         unsigned int flushbuf_size = flushbuf_end - flushbuf;
 4982         unsigned int bytes_to_copy = getSegmentFlushSize(st, ss, toSeq, flushbuf_size);
 4983 
 4984         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 4985                     "Flushing %u bytes from %X\n", bytes_to_copy, ss->seq));
 4986 
 4987         if(ss->urg_offset >= 1)
 4988         {
 4989             /* if urg_offset is set, seq + urg_offset is seq # of octet
 4990              * in stream following the last urgent octet.  all preceding
 4991              * octets in segment are considered urgent.  this code will
 4992              * skip over the urgent data when flushing.
 4993              */
 4994 
 4995             unsigned int non_urgent_bytes =
 4996                 ss->urg_offset < bytes_to_copy ? (bytes_to_copy - ss->urg_offset) : 0;
 4997 
 4998             if ( non_urgent_bytes )
 4999             {
 5000                 ret = SafeMemcpy(flushbuf, ss->payload+ss->urg_offset,
 5001                         non_urgent_bytes, flushbuf, flushbuf_end);
 5002 
 5003                 if (ret == SAFEMEM_ERROR)
 5004                 {
 5005                     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 5006                                 "ERROR writing flushbuf attempting to "
 5007                                 "write flushbuf out of range!\n"););
 5008                 }
 5009                 else
 5010                     flushbuf += non_urgent_bytes;
 5011 
 5012                 bytes_skipped += ss->urg_offset;
 5013             }
 5014             else
 5015             {
 5016                 ss->urg_offset = 0;
 5017             }
 5018         }
 5019         else
 5020         {
 5021             ret = SafeMemcpy(flushbuf, ss->payload,
 5022                     bytes_to_copy, flushbuf, flushbuf_end);
 5023 
 5024             if (ret == SAFEMEM_ERROR)
 5025             {
 5026                 STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 5027                             "ERROR writing flushbuf attempting to "
 5028                             "write flushbuf out of range!\n"););
 5029             }
 5030             else
 5031                 flushbuf += bytes_to_copy;
 5032         }
 5033 
 5034         if ( !st->paf_state.fpt_eoh &&
 5035                 bytes_to_copy < ss->size &&
 5036                 DupStreamNode(NULL, st, ss, &sr) == STREAM_INSERT_OK )
 5037         {
 5038             ss->size = bytes_to_copy;
 5039             sr->seq += bytes_to_copy;
 5040             sr->size -= bytes_to_copy;
 5041             sr->payload += bytes_to_copy + (ss->payload - ss->data);
 5042         }
 5043 
 5044         bytes_flushed += bytes_to_copy;
 5045         if(!st->paf_state.fpt_eoh){
 5046             ss->buffered = SL_BUF_FLUSHED;
 5047             st->flush_count++;
 5048             segs++;
 5049         }
 5050 
 5051         if ( flushbuf >= flushbuf_end )
 5052             break;
 5053 
 5054         if ( SEQ_EQ(ss->seq + bytes_to_copy,  toSeq) )
 5055             break;
 5056 
 5057         /* Check for a gap/missing packet */
 5058         // FIXTHIS PAF should account for missing data and resume
 5059         // scanning at the start of next PDU instead of aborting.
 5060         // FIXTHIS FIN may be in toSeq causing bogus gap counts.
 5061         if ( ((ss->next && (ss->seq + ss->size != ss->next->seq)) ||
 5062                     (!ss->next && (ss->seq + ss->size < toSeq))) &&
 5063                 !(st->flags & TF_FIRST_PKT_MISSING) )
 5064         {
 5065             if ( ss->next )
 5066             {
 5067                 toSeq = ss->next->seq;
 5068                 st->seglist_next = ss->next;
 5069             }
 5070             st->flags |= TF_MISSING_PKT;
 5071             break;
 5072         }
 5073     }
 5074 
 5075     st->seglist_base_seq = toSeq;
 5076 
 5077     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 5078                 "setting st->seglist_base_seq to 0x%X\n", st->seglist_base_seq););
 5079 
 5080     bytes_queued -= bytes_flushed;
 5081 
 5082     STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 5083                 "flushed %d bytes / %d segs on stream, "
 5084                 "skipped %d bytes, %d still queued\n",
 5085                 bytes_flushed, segs, bytes_skipped, bytes_queued););
 5086 
 5087     PREPROC_PROFILE_END(s5TcpBuildPacketPerfStats);
 5088     return bytes_flushed - bytes_skipped;
 5089 }
 5090 
 5091 int StreamFlushServer(Packet *p, SessionControlBlock *scb)
 5092 {
 5093     int flushed;
 5094     TcpSession *tcpssn = NULL;
 5095     StreamTracker *flushTracker = NULL;
 5096 
 5097     if (scb->proto_specific_data)
 5098         tcpssn = (TcpSession *)scb->proto_specific_data->data;
 5099 
 5100     if (!tcpssn)
 5101         return 0;
 5102 
 5103     flushTracker = &tcpssn->server;
 5104 
 5105     flushTracker->flags |= TF_FORCE_FLUSH;
 5106 
 5107     /* If this is a rebuilt packet, don't flush now because we'll
 5108      * overwrite the packet being processed.
 5109      */
 5110     if (p->packet_flags & PKT_REBUILT_STREAM)
 5111     {
 5112         /* We'll check & clear the TF_FORCE_FLUSH next time through */
 5113         return 0;
 5114     }
 5115 
 5116     /* Need to convert the addresses to network order */
 5117     flushed = flush_stream(tcpssn, flushTracker, p,
 5118             &tcpssn->tcp_server_ip,
 5119             &tcpssn->tcp_client_ip,
 5120             tcpssn->tcp_server_port,
 5121             tcpssn->tcp_client_port,
 5122             PKT_FROM_SERVER);
 5123     if (flushed)
 5124         purge_flushed_ackd(tcpssn, flushTracker);
 5125 
 5126     flushTracker->flags &= ~TF_FORCE_FLUSH;
 5127 
 5128     return flushed;
 5129 }
 5130 
 5131 int StreamFlushClient(Packet *p, SessionControlBlock *scb)
 5132 {
 5133     int flushed;
 5134     TcpSession *tcpssn = NULL;
 5135     StreamTracker *flushTracker = NULL;
 5136 
 5137     if (scb->proto_specific_data)
 5138         tcpssn = (TcpSession *)scb->proto_specific_data->data;
 5139 
 5140     if (!tcpssn)
 5141         return 0;
 5142 
 5143     flushTracker = &tcpssn->client;
 5144 
 5145     flushTracker->flags |= TF_FORCE_FLUSH;
 5146 
 5147     /* If this is a rebuilt packet, don't flush now because we'll
 5148      * overwrite the packet being processed.
 5149      */
 5150     if (p->packet_flags & PKT_REBUILT_STREAM)
 5151     {
 5152         /* We'll check & clear the TF_FORCE_FLUSH next time through */
 5153         return 0;
 5154     }
 5155 
 5156     /* Need to convert the addresses to network order */
 5157     flushed = flush_stream(tcpssn, flushTracker, p,
 5158             &tcpssn->tcp_client_ip,
 5159             &tcpssn->tcp_server_ip,
 5160             tcpssn->tcp_client_port,
 5161             tcpssn->tcp_server_port,
 5162             PKT_FROM_CLIENT);
 5163     if (flushed)
 5164         purge_flushed_ackd(tcpssn, flushTracker);
 5165 
 5166     flushTracker->flags &= ~TF_FORCE_FLUSH;
 5167 
 5168     return flushed;
 5169 }
 5170 
 5171 int StreamFlushListener(Packet *p, SessionControlBlock *scb)
 5172 {
 5173     TcpSession *tcpssn = NULL;
 5174     StreamTracker *listener = NULL;
 5175     int dir = 0;
 5176     int flushed = 0;
 5177 
 5178     if (scb->proto_specific_data)
 5179         tcpssn = (TcpSession *)scb->proto_specific_data->data;
 5180 
 5181     if (!tcpssn)
 5182         return 0;
 5183 
 5184     /* figure out direction of this packet -- we should've already
 5185      * looked at it, so the packet_flags are already set. */
 5186     if(p->packet_flags & PKT_FROM_SERVER)
 5187     {
 5188         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 5189                     "Flushing listener on packet from server\n"););
 5190         listener = &tcpssn->client;
 5191         /* dir of flush is the data from the opposite side */
 5192         dir = PKT_FROM_SERVER;
 5193     }
 5194     else if (p->packet_flags & PKT_FROM_CLIENT)
 5195     {
 5196         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 5197                     "Flushing listener on packet from client\n"););
 5198         listener = &tcpssn->server;
 5199         /* dir of flush is the data from the opposite side */
 5200         dir = PKT_FROM_CLIENT;
 5201     }
 5202 
 5203     if (dir != 0)
 5204     {
 5205         listener->flags |= TF_FORCE_FLUSH;
 5206         flushed = flush_stream(tcpssn, listener, p,
 5207                 GET_SRC_IP(p), GET_DST_IP(p),
 5208                 p->tcph->th_sport, p->tcph->th_dport, dir);
 5209         if (flushed)
 5210             purge_flushed_ackd(tcpssn, listener);
 5211 
 5212         listener->flags &= ~TF_FORCE_FLUSH;
 5213     }
 5214 
 5215     return flushed;
 5216 }
 5217 
 5218 int StreamFlushTalker(Packet *p, SessionControlBlock *scb)
 5219 {
 5220     TcpSession *tcpssn = NULL;
 5221     StreamTracker *talker = NULL;
 5222     int dir = 0;
 5223     int flushed = 0;
 5224 
 5225     if (scb->proto_specific_data)
 5226         tcpssn = (TcpSession *)scb->proto_specific_data->data;
 5227 
 5228     if (!tcpssn)
 5229     {
 5230         return 0;
 5231     }
 5232 
 5233     /* figure out direction of this packet -- we should've already
 5234      * looked at it, so the packet_flags are already set. */
 5235     if(p->packet_flags & PKT_FROM_SERVER)
 5236     {
 5237         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 5238                     "Flushing talker on packet from server\n"););
 5239         talker = &tcpssn->server;
 5240         /* dir of flush is the data from the opposite side */
 5241         dir = PKT_FROM_CLIENT;
 5242     }
 5243     else if (p->packet_flags & PKT_FROM_CLIENT)
 5244     {
 5245         STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
 5246                     "Flushing talker on packet from client\n"););
 5247         talker = &tcpssn->client;
 5248         /* dir of flush is the data from the opposite side */
 5249         dir = PKT_FROM_SERVER;
 5250     }
 5251 
 5252     if (dir != 0)
 5253     {
 5254         talker->flags |= TF_FORCE_FLUSH;
 5255         flushed = flush_stream(tcpssn, talker, p,
 5256                 GET_DST_IP(p), GET_SRC_IP(p),
 5257                 p->tcph->th_dport, p->tcph->th_sport, dir);
 5258         if (flushed)
 5259             purge_flushed_ackd(tcpssn, talker);
 5260 
 5261         talker->flags &= ~TF_FORCE_FLUSH;
 5262     }
 5263 
 5264     return flushed;
 5265 }
 5266 
 5267 static void TcpSessionClear (SessionControlBlock* scb, TcpSession* tcpssn, int freeApplicationData)
 5268 {
 5269     STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 5270                 "In TcpSessionClear, %lu bytes in use\n", session_mem_in_use););
 5271     STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 5272                 "client has %d segs queued\n", tcpssn->client.seg_count););
 5273     STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 5274                 "server has %d segs queued\n", tcpssn->server.seg_count););
 5275 
 5276     // update stats
 5277     s5stats.tcp_streamtrackers_released++;
 5278     if (s5stats.active_tcp_sessions > 0 )
 5279         s5stats.active_tcp_sessions--;
 5280     StreamUpdatePerfBaseState(&sfBase, tcpssn->scb, TCP_STATE_CLOSED);
 5281     RemoveStreamSession(&sfBase);
 5282 
 5283     if (scb->ha_state.session_flags & SSNFLAG_PRUNED)
 5284         CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED);
 5285     else if (scb->ha_state.session_flags & SSNFLAG_TIMEDOUT)
 5286         CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED | SESSION_CLOSED_TIMEDOUT);
 5287     else
 5288         CloseStreamSession(&sfBase, SESSION_CLOSED_NORMALLY);
 5289 
 5290 
 5291     // release external state
 5292     if (freeApplicationData)
 5293         session_api->free_application_data(scb);
 5294     StreamResetFlowBits(scb);
 5295 
 5296     // release internal protocol specific state
 5297     purge_all(&tcpssn->client);
 5298     purge_all(&tcpssn->server);
 5299 
 5300     s5_paf_clear(&tcpssn->client.paf_state);
 5301     s5_paf_clear(&tcpssn->server.paf_state);
 5302 
 5303     session_api->free_protocol_session_pool( SESSION_PROTO_TCP, scb );
 5304     scb->proto_specific_data = NULL;
 5305 
 5306     // update light-weight state
 5307     scb->ha_state.session_flags = SSNFLAG_NONE;
 5308     scb->session_state = STREAM_STATE_NONE;
 5309     scb->expire_time = 0;
 5310     scb->ha_state.ignore_direction = 0;
 5311 
 5312     // generate event for rate filtering
 5313     EventInternal(INTERNAL_EVENT_SESSION_DEL);
 5314 
 5315     STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,
 5316                 "After cleaning, %lu bytes in use\n", session_mem_in_use););
 5317 }
 5318 static StreamTcpPolicy *StreamSearchTcpConfigForBoundPolicy(StreamTcpConfig *tcp_config, sfaddr_t *ip)
 5319 {
 5320     int policyIndex;
 5321     StreamTcpPolicy *policy = NULL;
 5322 
 5323     for (policyIndex = 0; policyIndex < tcp_config->num_policies; policyIndex++)
 5324     {
 5325         policy = tcp_config->policy_list[policyIndex];
 5326 
 5327         if (policy->bound_addrs == NULL)
 5328             continue;
 5329 
 5330         /*
 5331          * Does this policy handle packets to this IP address?
 5332          */
 5333         if(sfvar_ip_in(policy->bound_addrs, ip))
 5334         {
 5335             STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
 5336                         "[Stream] Found tcp policy in IpAddrSet\n"););
 5337             break;
 5338         }
 5339     }
 5340 
 5341     if (policyIndex == tcp_config->num_policies)
 5342         policy = tcp_config->default_policy;
 5343 
 5344     return policy;
 5345 }
 5346 
 5347 static inline StreamTcpPolicy *StreamPolicyLookup( SessionControlBlock *scb, sfaddr_t *ip)
 5348 {
 5349     StreamTcpConfig *tcp_config = ( ( StreamConfig * ) scb->stream_config )->tcp_config;
 5350 
 5351     if( tcp_config != NULL )
 5352         return StreamSearchTcpConfigForBoundPolicy( tcp_config, ip );
 5353     else
 5354         return NULL;
 5355 }
 5356 
 5357 static void FlushQueuedSegs(SessionControlBlock *scb, TcpSession *tcpssn)
 5358 {
 5359     DAQ_PktHdr_t tmp_pcap_hdr;
 5360 
 5361 #ifdef REG_TEST
 5362     if (getRegTestFlags() & REG_TEST_FLAG_STREAM_DECODE)
 5363         printf("\nFlushQueuedSegs | ");
 5364 #endif
 5365 
 5366     /* Flush ack'd data on both sides as necessary */
 5367     {
 5368         Packet *p = NewGrinderPkt(tcp_cleanup_pkt, NULL, NULL);
 5369 
 5370         int flushed;
 5371 
 5372         tcp_cleanup_pkt = p;
 5373 
 5374         if (!s5_tcp_cleanup)
 5375         {
 5376             /* Turn off decoder alerts since we're decoding stored
 5377              * packets that we already alerted on. */
 5378             policyDecoderFlagsSaveNClear(scb->napPolicyId);
 5379         }
 5380         policyChecksumFlagsSaveNClear(scb->napPolicyId);
 5381 
 5382         /* Flush the client */
 5383         if (tcpssn->client.seglist && !(scb->ha_state.ignore_direction & SSN_DIR_FROM_SERVER) )
 5384         {
 5385             pc.s5tcp1++;
 5386             /* Do each field individually because of size differences on 64bit OS */
 5387             memset(&tmp_pcap_hdr, 0, sizeof(tmp_pcap_hdr));
 5388             tmp_pcap_hdr.ts.tv_sec = tcpssn->client.seglist->tv.tv_sec;