Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

spp_stream4.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00005 ** Copyright (C) 2003-2005 Sourcefire, Inc.
00006 **
00007 ** This program is free software; you can redistribute it and/or modify
00008 ** it under the terms of the GNU General Public License as published by
00009 ** the Free Software Foundation; either version 2 of the License, or
00010 ** (at your option) any later version.
00011 **
00012 ** This program is distributed in the hope that it will be useful,
00013 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 ** GNU General Public License for more details.
00016 **
00017 ** You should have received a copy of the GNU General Public License
00018 ** along with this program; if not, write to the Free Software
00019 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 */
00021 
00022 /* spp_stream4 
00023  * 
00024  * Purpose: Stateful inspection and tcp stream reassembly in Snort
00025  *
00026  * Arguments:
00027  *   
00028  * Effect:
00029  *
00030  * Comments:
00031  *
00032  * Any comments?
00033  *
00034  */
00035 
00036 /*
00037  * 04 Feb 2005: SAS Updated to handle favor_old and favor_new options.
00038  *                  favor_new traverses the tree in the opposite
00039  *                  direction and builds the stream using newer packets.
00040  *                  Also added checks for:
00041  *                  - PAWS (Timestamp option is set and 0) on an
00042  *                  establiahed session and ACK in the packet.  Win32
00043  *                  uses 0 Timestamp on Syn-only packets.
00044  *                  - Checks for NULL TCP flags in established session.
00045  *                  After the TWHS, all packets should have at least
00046  *                  ACK, RST, or FIN.
00047  *                  - Checks for overlaps (larger than an option
00048  *                  specified overlap_limit) in the reassembled stream.
00049  *                  When the overlap limit is reached, that side of the
00050  *                  stream is flushed and an evasion alert is raised.  
00051  *
00052  * 08 Feb 2005: AJM Update ACK when server sends RST, which enables client
00053  *                  stream to be reassembled upon flush.
00054  *                  - Also enable client reassembly upon client RST.
00055  *                  - Reset session alert count after flushing rebuilt packet.
00056  *
00057  * 28 Feb 2005: SAS Update to use hash table to Session storage.  Added new
00058  *                  files snort_stream_session.{c,h} that contain the sfxhash
00059  *                  interfaces.
00060  *                  - Added max_sessions configuration option.  Impacts the
00061  *                  meaning of memcap in that memcap now only relates to the
00062  *                  memory consumed by stored packets, not memory for session
00063  *                  structure.
00064  *
00065  * 07 Mar 2005: JRB/SAS Add user configurable flushpoints.  Added options:
00066  *                  flush_behavior, flush_base, flush_seed, flush_range to
00067  *                  stream4_reassemble preproc config.
00068  *
00069  * 31 Mar 2005: SAS Added server_inspect_limit option to limit the
00070  *                  amount of data that goes through rules inspection on
00071  *                  the server side.  The counter is reset when a client
00072  *                  packet is seen (ie, a request).
00073  */
00074 
00075 /*  I N C L U D E S  ************************************************/
00076 #ifdef HAVE_CONFIG_H
00077 #include "config.h"
00078 #endif
00079 
00080 #ifndef DEBUG
00081     #ifndef INLINE
00082         #define INLINE inline
00083     #endif
00084 #else
00085     #ifdef INLINE
00086         #undef INLINE
00087     #endif
00088     #define INLINE   
00089 #endif /* DEBUG */
00090 
00091 
00092 #include <sys/types.h>
00093 #include <stdlib.h>
00094 #include <string.h>
00095 #include <errno.h>
00096 #ifndef WIN32
00097 #include <sys/socket.h>
00098 #include <netinet/in.h>
00099 #include <arpa/inet.h>
00100 #endif /* WIN32 */
00101 #include <time.h>
00102 #include <rpc/types.h>
00103 
00104 #ifdef HAVE_STRINGS_H
00105 #include <strings.h>
00106 #endif
00107 
00108 #include "bounds.h"
00109 #include "decode.h"
00110 #include "event.h"
00111 #include "debug.h"
00112 #include "util.h"
00113 #include "plugbase.h"
00114 #include "parser.h"
00115 #include "mstring.h"
00116 #include "checksum.h"
00117 #include "log.h"
00118 #include "generators.h"
00119 #include "detect.h"
00120 #include "perf.h"
00121 #include "timersub.h"
00122 #include "ubi_SplayTree.h"
00123 #include "snort.h"
00124 #include "stream.h"
00125 #include "spp_stream4.h"
00126 #include "snort_packet_header.h"
00127 #include "event_queue.h"
00128 #include "inline.h"
00129 
00130 #include "sfghash.h"
00131 #include "snort_stream4_session.h"
00132 
00133 /*  D E F I N E S  **************************************************/
00134 
00135 /* normal TCP states */
00136 #define CLOSED       0
00137 #define LISTEN       1
00138 #define SYN_RCVD     2
00139 #define SYN_SENT     3
00140 #define ESTABLISHED  4
00141 #define CLOSE_WAIT   5
00142 #define LAST_ACK     6
00143 #define FIN_WAIT_1   7
00144 #define CLOSING      8
00145 #define FIN_WAIT_2   9
00146 #define TIME_WAIT   10
00147 
00148 /* extended states for fun stuff */
00149 #define NMAP_FINGERPRINT_2S         30
00150 #define NMAP_FINGERPRINT_NULL       31
00151 #define NMAP_FINGERPRINT_UPSF       32
00152 #define NMAP_FINGERPRINT_ZERO_ACK   33
00153 
00154 #define ACTION_NOTHING                  0x00000000
00155 #define ACTION_FLUSH_SERVER_STREAM      0x00000001
00156 #define ACTION_FLUSH_CLIENT_STREAM      0x00000002
00157 #define ACTION_DROP_SESSION             0x00000004
00158 #define ACTION_ACK_SERVER_DATA          0x00000008
00159 #define ACTION_ACK_CLIENT_DATA          0x00000010
00160 #define ACTION_DATA_ON_SYN              0x00000020
00161 #define ACTION_SET_SERVER_ISN           0x00000040
00162 #define ACTION_COMPLETE_TWH             0x00000080
00163 #define ACTION_ALERT_NMAP_FINGERPRINT   0x00000100
00164 #define ACTION_INC_PORT                 0x00000200
00165 
00166 #define FROM_SERVER     0
00167 #define FROM_CLIENT     1
00168 
00169 #define PRUNE_QUANTA    30              /* seconds to timeout a session */
00170 #define STREAM4_MEMORY_CAP     8388608  /* 8MB */
00171 #define STREAM4_MAX_SESSIONS   8192     /* 8k */
00172 #define STREAM4_CLEANUP   5             /* Cleanup 5 sessions at a time */
00173 #define STREAM4_CACHE_PERCENT 0.1       /* Or cleanup 0.1 % sessions at a time */
00174 #define STREAM4_TTL_LIMIT 5             /* default for TTL Limit */
00175 #define DEFAULT_STREAM_TRACKERS 256000  /* 256k sessions by default */
00176 
00177 #define STATS_HUMAN_READABLE   1
00178 #define STATS_MACHINE_READABLE 2
00179 #define STATS_BINARY           3
00180 
00181 #define STATS_MAGIC  0xDEAD029A   /* magic for the binary stats file */
00182 
00183 #define REVERSE     0
00184 #define NO_REVERSE  1
00185 
00186 #define METHOD_FAVOR_NEW  0x01
00187 #define METHOD_FAVOR_OLD  0x02
00188 
00189 /* # of packets that we accept on an unestab conn */
00190 #define UNESTABLISHED_MAX_PCOUNT 300
00191 
00192 /* what pcap can hold is how this limit comes about -- cmg */
00193 #define MAX_STREAM_SIZE (IP_MAXPACKET - IP_HEADER_LEN - TCP_HEADER_LEN - ETHERNET_HEADER_LEN) 
00194 
00195 /* Macros to deal with sequence numbers - p810 TCP Illustrated vol 2 */
00196 #define SEQ_LT(a,b)  ((int)((a) - (b)) <  0)
00197 #define SEQ_LEQ(a,b) ((int)((a) - (b)) <= 0)
00198 #define SEQ_GT(a,b)  ((int)((a) - (b)) >  0)
00199 #define SEQ_GEQ(a,b) ((int)((a) - (b)) >= 0)
00200 #define SEQ_EQ(a,b)  ((int)((a) - (b)) == 0)
00201 
00202 #define NO_CHK_SEQ  0
00203 #define CHK_SEQ     1
00204 
00205 #define S4I
00206 
00207 /* these are needed in snort versions before 2.0build something */
00208 #ifndef SNORT_20
00209 extern char *file_name;
00210 extern int *file_line;
00211 extern int opdsize;
00212 #endif /* SNORT_20 */
00213 
00214 
00215 /* We must twiddle to align the offset the ethernet header and align
00216    the IP header on solaris -- maybe this will work on HPUX too.
00217 */
00218 #if defined (SOLARIS) || defined (SUNOS) || defined (__sparc__) || defined(__sparc64__) || defined (HPUX)
00219 #define SPARC_TWIDDLE       2
00220 #else
00221 #define SPARC_TWIDDLE       0
00222 #endif
00223 
00224 /* values for the smartbits detector/self perservation */
00225 #define SELF_PRES_THRESHOLD        50
00226 #define SELF_PRES_PERIOD           90
00227 
00228 #define SUSPEND_THRESHOLD   200
00229 #define SUSPEND_PERIOD      30
00230 
00231 #define OPS_NORMAL              0
00232 #define OPS_SELF_PRESERVATION   1
00233 #define OPS_SUSPEND             2
00234 
00235 #define MAXSIZE_IP              65535
00236 #define MAX_TRACKER_AMOUNT      (MAX_STREAM_SIZE + 4000)
00237 
00238 
00239 
00240 /* Support dynamic flush points */
00241 #define FCOUNT 64
00242 #define STREAM4_FLUSH_BASE 512
00243 #define STREAM4_FLUSH_RANGE 1213
00244 
00245 #define FLUSH_BEHAVIOR_RANDOM -1
00246 #define FLUSH_BEHAVIOR_DEFAULT 0
00247 #define FLUSH_BEHAVIOR_LARGE 1
00248 
00249 /* Old flushpoints, for backward compat.  Use flush_behavior default */
00250 static u_int32_t old_flush_points[FCOUNT] = { 128, 217, 189, 130, 240, 221, 134, 129,
00251                                                250, 232, 141, 131, 144, 177, 201, 130,
00252                                                230, 190, 177, 142, 130, 200, 173, 129,
00253                                                250, 244, 174, 151, 201, 190, 180, 198,
00254                                                220, 201, 142, 185, 219, 129, 194, 140,
00255                                                145, 191, 197, 183, 199, 220, 231, 245,
00256                                                233, 135, 143, 158, 174, 194, 200, 180,
00257                                                201, 142, 153, 187, 173, 199, 143, 201 };
00258 
00259 static u_int32_t new_flush_points[FCOUNT] = { 1280, 2176, 1895, 1303, 2402, 2211, 1340, 1298,
00260                                               2500, 2320, 1413, 1313, 1444, 1776, 2015, 1305,
00261                                               2130, 1190, 1377, 1492, 1380, 2100, 1373, 1029,
00262                                               750, 444, 874, 551, 401, 390, 1801, 1898,
00263                                               2260, 2601, 642, 485, 619, 929, 794, 340,
00264                                               445, 1911, 497, 883, 399, 2201, 2431, 2145,
00265                                               433, 735, 543, 658, 1174, 2042, 1200, 1800,
00266                                               2015, 1142, 1530, 487, 673, 899, 743, 2101 };
00267 
00268 #ifdef DEBUG
00269 static char *state_names[] = { "CLOSED",
00270                               "LISTEN",
00271                               "SYN_RCVD",
00272                               "SYN_SENT",
00273                               "ESTABLISHED",
00274                               "CLOSE_WAIT",
00275                               "LAST_ACK",
00276                               "FIN_WAIT_1",
00277                               "CLOSING",
00278                               "FIN_WAIT_2",
00279                               "TIME_WAIT"};
00280 #endif
00281 
00282 #ifdef GIDS
00283 #define STREAM4INLINE_WINDOW_SIZE       7000            /* 7 kb */
00284 #define STREAM4INLINE_CUT_OFF_PERC      33              /* a third */
00285 #define MAX_SEQ_NUM                     4294967295UL    /* used for detecting sequence number wraps */
00286 
00287 char packet_added_to_stream;
00288 #endif /* GIDS */
00289 
00290 /*  D A T A   S T R U C T U R E S  **********************************/
00291 typedef struct _OverlapData
00292 {
00293     u_int32_t seq_low;
00294     u_int32_t seq_hi;
00295 
00296 } OverlapData;
00297 
00298 typedef struct _BuildData
00299 {
00300     Stream *stream;
00301     u_int8_t *buf;
00302     u_int32_t total_size;
00303     /* u_int32_t build_flags; -- reserved for the day when we generate 1 stream event and log the stream */
00304 } BuildData;
00305 
00306 typedef struct _BinStats
00307 {
00308     u_int32_t start_time;
00309     u_int32_t end_time;
00310     u_int32_t sip;
00311     u_int32_t cip;
00312     u_int16_t sport;
00313     u_int16_t cport;
00314     u_int32_t spackets;
00315     u_int32_t cpackets;
00316     u_int32_t sbytes;
00317     u_int32_t cbytes;
00318 } BinStats;
00319 
00320 typedef struct _StatsLog
00321 {
00322     FILE *fp;
00323     char *filename;
00324 
00325 } StatsLog;
00326 
00327 typedef struct _StatsLogHeader
00328 {
00329     u_int32_t magic;
00330     u_int32_t version_major;
00331     u_int32_t version_minor;
00332     u_int32_t timezone;
00333 } StatsLogHeader;
00334 
00335 typedef struct _S4Emergency
00336 {
00337     long end_time;
00338     char old_reassemble_client;
00339     char old_reassemble_server;
00340     char old_reassembly_alerts;
00341     int old_assurance_mode;
00342     char old_stateful_mode;
00343     u_int32_t new_session_count;
00344     int status;
00345 } S4Emergency;
00346 
00347 typedef struct _StreamKey
00348 {
00349     u_int32_t sip;
00350     u_int32_t cip;
00351     u_int16_t sport;
00352     u_int16_t cport;
00353 } STREAM_KEY;
00354 
00355 typedef Session *SessionPtr;
00356 
00357 StatsLog *stats_log;
00358 
00359 /* splay tree root data */
00360 #ifndef USE_HASH_TABLE
00361 static ubi_trRoot s_cache;
00362 static ubi_trRootPtr RootPtr = &s_cache;
00363 int GetSessionCount();
00364 #endif
00365 
00366 u_int32_t safe_alloc_faults;
00367 
00368 /* we keep a stream packet queued up and ready to go for reassembly */
00369 Packet *stream_pkt;
00370 
00371 /*  G L O B A L S  **************************************************/
00372 
00373 extern int do_detect;
00374 
00375 /* external globals from rules.c */
00376 FILE *session_log;
00377 Stream4Data s4data;
00378 u_int32_t stream4_memory_usage;
00379 u_int32_t ps_memory_usage;
00380 
00381 /* stream4 emergency mode counters... */
00382 S4Emergency s4_emergency;
00383 
00384 /* List of Dynamic flushpoints */
00385 u_int32_t flush_points[FCOUNT];
00386 
00387 /*  P R O T O T Y P E S  ********************************************/
00388 void *SafeAlloc(unsigned long, int, Session *);
00389 void ParseStream4Args(char *);
00390 void Stream4InitReassembler(u_char *);
00391 void ReassembleStream4(Packet *, void *);
00392 #if !defined(USE_HASH_TABLE) && !defined(USE_SPLAY_TREE)
00393 Session *GetSession(Packet *);
00394 #endif
00395 Session *CreateNewSession(Packet *, u_int32_t, u_int32_t);
00396 void DropSession(Session *);
00397 void DeleteSession(Session *, u_int32_t);
00398 void DeleteSpd(ubi_trRootPtr);
00399 int GetDirection(Session *, Packet *);
00400 void Stream4ShutdownFunction(int, void *);
00401 void Stream4CleanExitFunction(int, void *);
00402 void Stream4RestartFunction(int, void *);
00403 void PrintSessionCache();
00404 int CheckRst(Session *, int, u_int32_t, Packet *);
00405 #ifdef GIDS
00406 void SegmentTruncTraverse(Stream *, u_int16_t);
00407 #endif /* GIDS */
00408 int PruneSessionCache(u_int32_t, int, Session *);
00409 #ifdef GIDS
00410 int StoreStreamPkt(Session *, Packet *, u_int32_t);
00411 #else
00412 void StoreStreamPkt(Session *, Packet *, u_int32_t);
00413 #endif /* GIDS */
00414 void FlushStream(Stream *, Packet *, int);
00415 #ifdef GIDS
00416 void TruncStream(Stream *s, Packet *p);
00417 #endif /* GIDS */
00418 void InitStream4Pkt();
00419 int BuildPacket(Stream *, u_int32_t, Packet *, int);
00420 int CheckPorts(u_int16_t, u_int16_t);
00421 void PortscanWatch(Session *, u_int32_t);
00422 void PortscanDeclare(Packet *);
00423 void AddNewTarget(ubi_trRootPtr, u_int32_t, u_int16_t, u_int8_t);
00424 void AddNewPort(ubi_trRootPtr, u_int16_t, u_int8_t);
00425 int LogStream(Stream *);
00426 void WriteSsnStats(BinStats *);
00427 void OpenStatsFile();
00428 static int RetransTooFast(struct timeval *old, struct timeval *new);
00429 void Stream4Init(u_char *);
00430 void PreprocFunction(Packet *);
00431 void PreprocRestartFunction(int);
00432 void PreprocCleanExitFunction(int);
00433 static INLINE int isBetween(u_int32_t low, u_int32_t high, u_int32_t cur);
00434 static INLINE int NotForStream4(Packet *p);
00435 static INLINE int SetFinSent(Packet *p, Session *ssn, int direction);
00436 static INLINE int WithinSessionLimits(Packet *p, Stream *stream);
00437 
00438  /* helpers for dealing with session byte_counters */
00439 static INLINE void StreamSegmentSub(Stream *stream, u_int16_t sub);
00440 static INLINE void StreamSegmentAdd(Stream *stream, u_int16_t add);
00441 
00442 /*
00443   Here is where we separate which functions will be called in the
00444   normal case versus in the asynchronus state
00445 
00446 */
00447    
00448 int UpdateState(Session *, Packet *, u_int32_t); 
00449 int UpdateState2(Session *, Packet *, u_int32_t); 
00450 int UpdateStateAsync(Session *, Packet *, u_int32_t);
00451 
00452 static void TcpAction(Session *ssn, Packet *p, int action, int direction, 
00453                       u_int32_t pkt_seq, u_int32_t pkt_ack);
00454 static void TcpActionAsync(Session *ssn, Packet *p, int action, int direction, 
00455                            u_int32_t pkt_seq, u_int32_t pkt_ack);
00456 int LoadStateTable(const u_int32_t thetime, const char *path);
00457 
00458 
00459 
00460 /** 
00461  * See if a sequence number is in range.
00462  * 
00463  * @param low base sequence number
00464  * @param high acknowledged sequence number
00465  * @param cur sequence number to check
00466  * 
00467  * @return 1 if we are between these sequence numbers, 0 otherwise
00468  */
00469 static INLINE int isBetween(u_int32_t low, u_int32_t high, u_int32_t cur)
00470 {
00471     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"(%u,%u,%u) = (low, high, cur)\n",
00472                 low,high,cur););
00473     return (cur - low) <= (high - low);
00474 }
00475 
00476 
00477 #ifdef USE_HASH_TABLE
00478 #else /* USE_SPLAY_TREE */
00479 int GetSessionCount()
00480 {
00481     return ubi_trCount(RootPtr);
00482 }
00483 
00484 static int CompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr)
00485 {
00486     Session *nSession;
00487     Session *iSession; 
00488 
00489     nSession = ((Session *)NodePtr);
00490     iSession = (Session *)ItemPtr;
00491 
00492     if(nSession->server.ip < iSession->server.ip) return 1;
00493     else if(nSession->server.ip > iSession->server.ip) return -1;
00494 
00495     if(nSession->client.ip < iSession->client.ip) return 1;
00496     else if(nSession->client.ip > iSession->client.ip) return -1;
00497         
00498     if(nSession->server.port < iSession->server.port) return 1;
00499     else if(nSession->server.port > iSession->server.port) return -1;
00500 
00501     if(nSession->client.port < iSession->client.port) return 1;
00502     else if(nSession->client.port > iSession->client.port) return -1;
00503 
00504     return 0;
00505 }
00506 #endif
00507 
00508 /** 
00509  * Check to if retransmissions are occuring too quickly
00510  * 
00511  * @param old previous timeval
00512  * @param cur current timeval
00513  * 
00514  * @return 1 if the Retransmission is too quick, 0 if it's ok
00515  */
00516 static int RetransTooFast(struct timeval *old, struct timeval *cur)
00517 {
00518     struct timeval diff;
00519 
00520     TIMERSUB(cur, old, &diff);
00521 
00522     /* require retransmissions wait atleast 1.1s */
00523     if(diff.tv_sec > 1)
00524         return 0;
00525     else if(diff.tv_sec == 1 && diff.tv_usec > 100)
00526         return 0;
00527         
00528     return 1;
00529 }
00530 
00531 static int DataCompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr)
00532 {
00533     StreamPacketData *nStream;
00534     StreamPacketData *iStream; 
00535 
00536     nStream = ((StreamPacketData *)NodePtr);
00537     iStream = ((StreamPacketData *)ItemPtr);
00538 
00539     if(nStream->seq_num < iStream->seq_num) return 1;
00540     else if(nStream->seq_num > iStream->seq_num) return -1;
00541 
00542     return 0;
00543 }
00544 
00545 static int OverlapCompareFunc(ubi_trItemPtr ItemPtr, void *data)
00546 {
00547     OverlapData *overlap_info = (OverlapData *)data;
00548     StreamPacketData *iStream; 
00549     iStream = ((StreamPacketData *)ItemPtr);
00550 
00551     if ((iStream->seq_num > overlap_info->seq_low) &&
00552         (iStream->seq_num < overlap_info->seq_hi))
00553         return 1;
00554 
00555     return 0;
00556 }
00557 
00558 static void KillSpd(ubi_trNodePtr NodePtr)
00559 {
00560     StreamPacketData *tmp;
00561 
00562     tmp = (StreamPacketData *)NodePtr;
00563 
00564     stream4_memory_usage -= tmp->pkt_size;
00565     free(tmp->pktOrig);
00566 
00567     stream4_memory_usage -= sizeof(StreamPacketData);
00568     free(tmp);
00569 }
00570 
00571 
00572 static void TraverseFunc(ubi_trNodePtr NodePtr, void *build_data)
00573 {
00574     Stream *s;
00575     StreamPacketData *spd;
00576     BuildData *bd;
00577     u_int8_t *buf;
00578     int trunc_size;
00579     int offset = 0;
00580 
00581     if(s4data.stop_traverse)
00582         return;
00583 
00584     spd = (StreamPacketData *) NodePtr;
00585     bd = (BuildData *) build_data;
00586     s = bd->stream;
00587     buf = bd->buf;
00588 
00589     /* Don't reassemble if there's nothing to reassemble.
00590      * The first two cases can probably never happen. I personally
00591      * prefer strong error checking (read: paranoia).
00592      */
00593     if(spd->payload_size == 0)
00594     {
00595         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "not reassembling because "
00596                     "the payload size is zero.\n"););
00597         spd->chuck = SEG_FULL;
00598         return;
00599     }
00600     else if(SEQ_EQ(s->base_seq, s->last_ack))
00601     {
00602         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "not reassembling because "
00603                     "base_seq = last_ack (%u).\n", s->base_seq););
00604         return;
00605     }
00606 
00607     /* Packet is completely before the current window. */
00608     else if(SEQ_LEQ(spd->seq_num, s->base_seq) &&
00609             SEQ_LEQ(spd->seq_num + spd->payload_size, s->base_seq))
00610     {
00611         /* ignore this segment, we've already looked at it */
00612         spd->chuck = SEG_FULL;
00613         return;
00614     }
00615     /* Packet starts outside the window and ends inside it. */
00616     else if(SEQ_LT(spd->seq_num, s->base_seq) &&
00617             isBetween(s->base_seq+1, s->last_ack, (spd->seq_num + spd->payload_size)))
00618     {
00619         /* case where we've got a segment that wasn't completely ack'd 
00620          * last time it was processed, do a partial copy into the buffer
00621          */
00622         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Incompleted segment, copying up "
00623                     "to last-ack\n"););
00624 
00625         /* calculate how much un-ack'd data to copy */
00626         trunc_size = (spd->seq_num+spd->payload_size) - s->base_seq;
00627 
00628         /* figure out where in the original data payload to start copying */
00629         offset = s->base_seq - spd->seq_num;
00630 
00631         if(trunc_size < 65500 && trunc_size > 0)
00632         {
00633             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Copying %d bytes into buffer, "
00634                         "offset %d, buf %p\n", trunc_size, offset, 
00635                         buf););
00636             SafeMemcpy(buf, spd->payload+offset, trunc_size,
00637                     stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);            
00638             pc.rebuilt_segs++;
00639             bd->total_size += trunc_size;
00640         }
00641         else
00642         {
00643             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Woah, got bad TCP segment "
00644                         "trunctation value (%d)\n", trunc_size););
00645         }
00646 
00647         spd->chuck = SEG_FULL;
00648     }
00649     /* if it's in bounds... */
00650     else if(isBetween(s->base_seq, s->last_ack-1, spd->seq_num) &&
00651             isBetween(s->base_seq, s->last_ack, (spd->seq_num + spd->payload_size)))
00652     {
00653         offset = spd->seq_num - s->base_seq;
00654 
00655         s->next_seq = spd->seq_num + spd->payload_size;
00656 
00657         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Copying %d bytes into buffer, "
00658                     "offset %d, buf %p\n", spd->payload_size, offset, 
00659                     buf););
00660 
00661         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00662                     "spd->seq_num (%u)  s->last_ack (%u) "
00663                     "s->base_seq(%u) size: (%u) s->next_seq(%u), "
00664                     "offset(%u), MAX(%u)\n",
00665                     spd->seq_num, s->last_ack, s->base_seq,
00666                     spd->payload_size, s->next_seq, offset, 
00667                     MAX_STREAM_SIZE));
00668 
00669         SafeMemcpy(buf+offset, spd->payload, spd->payload_size,
00670                 stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);
00671 
00672         pc.rebuilt_segs++;
00673 
00674         spd->chuck = SEG_FULL;
00675         bd->total_size += spd->payload_size;
00676     } 
00677     else if(isBetween(s->base_seq, s->last_ack-1, spd->seq_num) &&
00678             SEQ_GT((spd->seq_num + spd->payload_size), s->last_ack))
00679     {
00680         /*
00681          *  if it starts in bounds and hasn't been completely ack'd, 
00682          *  truncate the last piece and copy it in 
00683          */
00684         trunc_size = s->last_ack - spd->seq_num; 
00685 
00686         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Truncating overlap of %d bytes\n", 
00687                     spd->seq_num + spd->payload_size - s->last_ack);
00688                 DebugMessage(DEBUG_STREAM, "    => trunc info seq: 0x%X   "
00689                     "size: %d  last_ack: 0x%X\n", 
00690                     spd->seq_num, spd->payload_size, s->last_ack);
00691                 );
00692 
00693         offset = spd->seq_num - s->base_seq;
00694 
00695         if(trunc_size < (65500-offset) && trunc_size > 0)
00696         {
00697             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Copying %d bytes into buffer, "
00698                         "offset %d, buf %p\n", trunc_size, offset, 
00699                         buf););
00700             SafeMemcpy(buf+offset, spd->payload, trunc_size,
00701                     stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);            
00702             pc.rebuilt_segs++;
00703             bd->total_size += trunc_size;
00704             spd->chuck = SEG_PARTIAL;
00705         }
00706         else
00707         {
00708             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Woah, got bad TCP segment "
00709                         "trunctation value (%d)\n", trunc_size););
00710         }
00711     }
00712     else if(SEQ_GEQ(spd->seq_num,s->last_ack))
00713     {
00714         /* we're all done, we've walked past the end of the ACK'd data */
00715         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
00716                     "   => Segment is past last ack'd data, "
00717                     "ignoring for now...\n");
00718                 DebugMessage(DEBUG_STREAM,  "        => (%d bytes @ seq 0x%X, "
00719                     "ack: 0x%X)\n", spd->payload_size, spd->seq_num, s->last_ack);
00720                 );
00721 
00722         /* since we're reassembling in order, once we hit an overflow condition
00723          * let's stop trying for now
00724          */
00725         s4data.stop_traverse = 1;
00726         //s4data.stop_seq = spd->seq_num;
00727         s4data.stop_seq = s->last_ack;
00728     }
00729     else
00730     {
00731         /* The only case that should reach this point is if
00732          * spd->seq_num < s->base_seq &&
00733          * spd->seq_num + spd->payload_size >= s->last_ack
00734          * Can that ever happen?
00735          */
00736         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00737                     "Ended up in the default case somehow.. !\n"
00738                     "spd->seq_num(%u) spd->payload_size(%u)\n",
00739                     spd->seq_num, spd->payload_size););        
00740     }
00741 } 
00742 
00743 #ifdef GIDS
00744 /*
00745     totally modified. All packets containing data are now used in the
00746     reassembly.
00747 */
00748 static void TraverseFuncRebuildAll(ubi_trNodePtr NodePtr, void *build_data)
00749 {
00750     Stream *s;
00751     StreamPacketData *spd;
00752     BuildData *bd;
00753     u_int8_t *buf;
00754     int trunc_size = 0;
00755     int offset = 0;
00756 //    StreamPacketData *savspd;
00757 
00758     if(s4data.stop_traverse)
00759         return;
00760 
00761     spd = (StreamPacketData *) NodePtr;
00762     bd  = (BuildData *) build_data;
00763     s   = bd->stream;
00764     buf = bd->buf;
00765 
00766     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00767                 "REASS: before: spd->seq_num (%u)  s->last_ack (%u) "
00768                 "s->base_seq(%u) size: (%u) s->next_seq(%u)\n",
00769                 spd->seq_num, s->last_ack, s->base_seq,
00770                 spd->payload_size, s->next_seq));
00771 
00772 
00773     /* Packet is completely before the current window. */
00774     if(SEQ_LEQ(spd->seq_num, s->base_seq) &&
00775             SEQ_LEQ(spd->seq_num + spd->payload_size, s->base_seq))
00776     {
00777         /* ignore this segment, we've already looked at it */
00778         spd->chuck = SEG_FULL;
00779         return;
00780     }
00781     /* Packet starts outside the window and ends inside it. */
00782     else if(SEQ_LT(spd->seq_num, s->base_seq) &&
00783             isBetween(s->base_seq+1, s->last_ack, (spd->seq_num + spd->payload_size)))
00784     {
00785         /* case where we've got a segment that wasn't completely ack'd 
00786          * last time it was processed, do a partial copy into the buffer
00787          */
00788         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Incompleted segment, copying up "
00789                     "to last-ack\n"););
00790 
00791         /* calculate how much un-ack'd data to copy */
00792         trunc_size = (spd->seq_num+spd->payload_size) - s->base_seq;
00793 
00794         /* figure out where in the original data payload to start copying */
00795         offset = s->base_seq - spd->seq_num;
00796 
00797         if(trunc_size < 65500 && trunc_size > 0)
00798         {
00799             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS: starts outside ends inside: Copying %d bytes into buffer, "
00800                         "offset %d, buf %p\n", trunc_size, offset, 
00801                         buf););
00802 
00803             SafeMemcpy(buf, spd->payload+offset, trunc_size,
00804                     stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);            
00805 
00806             pc.rebuilt_segs++;
00807             bd->total_size += trunc_size;
00808         }
00809         else
00810         {
00811             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Woah, got bad TCP segment "
00812                         "trunctation value (%d)\n", trunc_size););
00813         }
00814 
00815         spd->chuck = SEG_FULL;
00816 
00817     }
00818     /* if it's in bounds... */
00819     else if(isBetween(s->base_seq, s->last_ack-1, spd->seq_num) &&
00820             isBetween(s->base_seq, s->last_ack, (spd->seq_num + spd->payload_size)))
00821     {
00822         offset = spd->seq_num - s->base_seq;
00823 
00824         s->next_seq = spd->seq_num + spd->payload_size;
00825 
00826         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS: in bounds: Copying %d bytes into buffer, "
00827                     "offset %d, buf %p\n", spd->payload_size, offset, 
00828                     buf););
00829 
00830         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00831                     "spd->seq_num (%u)  s->last_ack (%u) "
00832                     "s->base_seq(%u) size: (%u) s->next_seq(%u), "
00833                     "offset(%u), MAX(%u)\n",
00834                     spd->seq_num, s->last_ack, s->base_seq,
00835                     spd->payload_size, s->next_seq, offset, 
00836                     MAX_STREAM_SIZE));
00837 
00838         SafeMemcpy(buf+offset, spd->payload, spd->payload_size,
00839                 stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);
00840 
00841         pc.rebuilt_segs++;
00842 
00843         spd->chuck = SEG_FULL;
00844         bd->total_size += spd->payload_size;
00845     } 
00846     else if(isBetween(s->base_seq, s->last_ack-1, spd->seq_num) &&
00847             SEQ_GT((spd->seq_num + spd->payload_size), s->last_ack))
00848     {
00849         offset = spd->seq_num - s->base_seq;
00850 
00851         s->next_seq = spd->seq_num + spd->payload_size;
00852 
00853         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS: start in end out: Copying %d bytes into buffer, "
00854                     "offset %d, buf %p\n", spd->payload_size, offset, 
00855                     buf););
00856 
00857         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00858                     "spd->seq_num (%u)  s->last_ack (%u) "
00859                     "s->base_seq(%u) size: (%u) s->next_seq(%u), "
00860                     "offset(%u), MAX(%u)\n",
00861                     spd->seq_num, s->last_ack, s->base_seq,
00862                     spd->payload_size, s->next_seq, offset, 
00863                     MAX_STREAM_SIZE));
00864 
00865         SafeMemcpy(buf+offset, spd->payload, spd->payload_size,
00866                 stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);
00867 
00868         pc.rebuilt_segs++;
00869 
00870         spd->chuck = SEG_FULL;
00871         bd->total_size += spd->payload_size;
00872     }
00873     else if(SEQ_GEQ(spd->seq_num,s->last_ack))
00874     {
00875         offset = spd->seq_num - s->base_seq;
00876 
00877         if(offset >= (MAX_STREAM_SIZE - spd->payload_size) &&
00878            SEQ_GT(spd->seq_num,s->next_seq))
00879         {
00880             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS: completely out: LONER! (offset %d seq_num %u next_seq %u).", 
00881                                                     offset, spd->seq_num, s->next_seq););
00882         
00883             return;
00884         }
00885 
00886 
00887         s->next_seq = spd->seq_num + spd->payload_size;
00888 
00889         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS: completely out: Copying %d bytes into buffer, "
00890                     "offset %d, buf %p\n", spd->payload_size, offset, 
00891                     buf););
00892 
00893         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00894                     "spd->seq_num (%u)  s->last_ack (%u) "
00895                     "s->base_seq(%u) size: (%u) s->next_seq(%u), "
00896                     "offset(%u), MAX(%u)\n",
00897                     spd->seq_num, s->last_ack, s->base_seq,
00898                     spd->payload_size, s->next_seq, offset, 
00899                     MAX_STREAM_SIZE));
00900 
00901         SafeMemcpy(buf+offset, spd->payload, spd->payload_size,
00902                 stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);
00903 
00904         pc.rebuilt_segs++;
00905 
00906         spd->chuck = SEG_FULL;
00907         bd->total_size += spd->payload_size;
00908     }
00909     else
00910     {
00911         /* The only case that should reach this point is if
00912          * spd->seq_num < s->base_seq &&
00913          * spd->seq_num + spd->payload_size >= s->last_ack
00914          * Can that ever happen?
00915          */
00916         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00917                     "Ended up in the default case somehow.. !\n"
00918                     "spd->seq_num(%u) spd->payload_size(%u)\n",
00919                     spd->seq_num, spd->payload_size););        
00920     }
00921 } 
00922 
00923 
00924 
00925 /*
00926     totally modified. All packets containing data are now used in the
00927     reassembly.
00928     
00929     this function asumes that:
00930     base_seq is something like 4294967000
00931     last_ack is something like 3000
00932 */
00933 static void TraverseFuncRebuildAllWrap(ubi_trNodePtr NodePtr, void *build_data)
00934 {
00935     Stream *s;
00936     StreamPacketData *spd;
00937     BuildData *bd;
00938     u_int8_t *buf;
00939     int trunc_size = 0;
00940     int offset = 0;
00941 //    StreamPacketData *savspd;
00942     u_int32_t before_size; /* size before the wrap */
00943 //    u_int32_t after_size;
00944 
00945 
00946     if(s4data.stop_traverse)
00947         return;
00948 
00949     spd = (StreamPacketData *) NodePtr;
00950     bd  = (BuildData *) build_data;
00951     s   = bd->stream;
00952     buf = bd->buf;
00953 
00954     /* before_size is the size before the wrap */
00955     before_size = MAX_SEQ_NUM - s->base_seq;
00956 
00957 
00958     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
00959         "REASS_WRAP: before: spd->seq_num (%u, seq_num+payloadsize: %u) s->last_ack (%u) s->base_seq(%u) before(%u) size: (%u) s->next_seq(%u), offset(%u), MAX(%u)\n",
00960         spd->seq_num, spd->seq_num+spd->payload_size, s->last_ack, s->base_seq, before_size, spd->payload_size, s->next_seq, offset, MAX_STREAM_SIZE));
00961 
00962     /* Packet is completely before the current window. */
00963     if(SEQ_LEQ(spd->seq_num, s->base_seq) &&
00964             SEQ_LEQ(spd->seq_num + spd->payload_size, s->base_seq))
00965     {
00966         /* ignore this segment, we've already looked at it */
00967         spd->chuck = SEG_FULL;
00968         return;
00969     }
00970     /* Packet starts outside the window and ends inside it.
00971     
00972         this means:
00973         seq_num < base_seq AND
00974         seq_num + payload_size bigger than base_seq OR
00975         seq_num + payload_size smaller than last_ack (remember last_ack is already past the wrap)
00976 
00977         seq_num is smaller than base_seq, so offset calculation is not special
00978     */
00979     else if (SEQ_LT(spd->seq_num, s->base_seq)
00980                 &&
00981             (SEQ_GEQ((spd->seq_num + spd->payload_size), s->base_seq) ||
00982              SEQ_LEQ((spd->seq_num + spd->payload_size), s->last_ack)))
00983     {
00984         /* case where we've got a segment that wasn't completely ack'd 
00985          * last time it was processed, do a partial copy into the buffer
00986          */
00987         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: Incompleted segment, copying up to last-ack\n"););
00988         
00989         /* calculate how much un-ack'd data to copy 
00990         
00991             2 scenarios:
00992                 1. packet ends before we wrap: normal calculation
00993                 2. packet ends after we wrap: trouble =]
00994         */
00995         if((spd->seq_num+spd->payload_size) > s->base_seq)
00996         {
00997             /* normal calc */
00998             trunc_size = (spd->seq_num+spd->payload_size) - s->base_seq;
00999 
01000             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: packet ends before we wrap, "
01001                                                   "so trunc_size(%d) = (spd->seq_num+spd->payload_size(%u)) - s->base_seq(%u)\n",
01002                                                   trunc_size, (spd->seq_num+spd->payload_size), s->base_seq););
01003         }
01004         else
01005         {
01006             /* the packets ends after the wrap */
01007             
01008             /* before_size is the size before the wrap */
01009             before_size = MAX_SEQ_NUM - s->base_seq;
01010 
01011             /* spd->seq_num + spd->payload_size wraps around to a sane value. */
01012             trunc_size = before_size + (spd->seq_num+spd->payload_size);
01013 
01014             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: packet ends after we wrap, "
01015                                                   "so trunc_size(%d) = before_size(%u) + (spd->seq_num+spd->payload_size(%u))\n",
01016                                                   trunc_size, before_size, (spd->seq_num+spd->payload_size)););
01017         }
01018 
01019         /*  figure out where in the original data payload to start copying 
01020             this is unchanged for WRAP because both base_seq and seq_num are before the wrap.
01021         */
01022         offset = s->base_seq - spd->seq_num;
01023 
01024 
01025         if(trunc_size < 65500 && trunc_size > 0)
01026         {
01027             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: starts outside ends inside: Copying %d bytes into buffer, "
01028                         "offset %d, buf %p\n", trunc_size, offset, buf););
01029 
01030             SafeMemcpy(buf, spd->payload+offset, trunc_size,
01031                     stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);            
01032 
01033             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: SafeMemcpy completed\n"););
01034 
01035             pc.rebuilt_segs++;
01036             bd->total_size += trunc_size;
01037         }
01038         else
01039         {
01040             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: Woah, got bad TCP segment "
01041                         "trunctation value (%d)\n", trunc_size););
01042         }
01043 
01044         spd->chuck = SEG_FULL;
01045 
01046     }
01047     /* if it's in bounds... 
01048     
01049         the spd fits between base_seq and last_ack. The wrap can be at three places:
01050             1. before the spd
01051             2. in the spd
01052             3. after the spd
01053     
01054             Ad. 1:
01055                 base_seq is high, last_ack low, seq_num and seq_num + payload_size are < last_ack
01056             Ad. 2:
01057                 base_seq is high, last_ack low, seq_num > base_seq and seq_num + payload_size < last_ack
01058             Ad. 3:
01059                 base_seq is high, last_ack low, seq_num > base_seq and seq_num + payload_size > base_seq
01060 
01061 
01062             in bounds means:
01063                 seq_num > base_seq || seq_num < last_ack
01064                     &&
01065                 seq_num+payload_size > base_seq || seq_num+payload_size < last_ack
01066 
01067     */
01068     else if((SEQ_GT(spd->seq_num,s->base_seq) || SEQ_LT(spd->seq_num,s->last_ack-1))
01069                     &&
01070             (SEQ_GT(spd->seq_num+spd->payload_size,s->base_seq) || SEQ_LT(spd->seq_num+spd->payload_size,s->last_ack)))
01071     {
01072         /* packet is entirely before the wrap */
01073         if(SEQ_LT(spd->seq_num,s->last_ack-1) || SEQ_LT(spd->seq_num+spd->payload_size,s->last_ack))
01074         {
01075             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: packet before wrap\n"););
01076             
01077             offset = spd->seq_num - s->base_seq;
01078         }
01079         /* packet starts before the wrap, ends after it */
01080         else if(SEQ_GT(spd->seq_num,s->base_seq) || SEQ_LT(spd->seq_num+spd->payload_size,s->last_ack))
01081         {
01082             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: starts before wrap, ends after it\n"););
01083 
01084             offset = spd->seq_num - s->base_seq;
01085         }
01086         /* packet is entirely after the wrap */
01087         else
01088         {
01089             /* the part before the part + the seq_num */
01090             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: completely after the wrap\n"););
01091 
01092             offset = spd->seq_num + before_size;
01093         }
01094 
01095         /* this one will wrap if needed */
01096         s->next_seq = spd->seq_num + spd->payload_size;
01097 
01098         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: in bounds: Copying %d bytes into buffer, "
01099                     "offset %d, buf %p\n", spd->payload_size, offset, buf););
01100 
01101         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
01102                 "REASS_WRAP: spd->seq_num (%u) s->last_ack (%u) "
01103                 "s->base_seq(%u) size: (%u) s->next_seq(%u), "
01104                 "offset(%u), MAX(%u)\n",
01105                 spd->seq_num, s->last_ack, s->base_seq,
01106                 spd->payload_size, s->next_seq, offset, 
01107                 MAX_STREAM_SIZE));
01108 
01109         SafeMemcpy(buf+offset, spd->payload, spd->payload_size,
01110                 stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);
01111 
01112         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: SafeMemcpy completed\n"););
01113         
01114         pc.rebuilt_segs++;
01115 
01116         spd->chuck = SEG_FULL;
01117         bd->total_size += spd->payload_size;
01118     } 
01119     /*  packet starts inside the current window and ends outside it
01120     
01121         the wrap can be in two places:
01122             1. before the spd
01123             2. in the spd
01124             
01125             Ad.1.
01126                 base_seq is high, last_ack is low, seq_num < last_ack, seq_num+payload_size > last_ack
01127             Ad.2.
01128                 base_seq is high, last_ack is low, seq_num > base_ack, seq_num+payload_size > last_ack
01129      */
01130     else if((SEQ_GT(spd->seq_num,s->base_seq) || SEQ_LT(spd->seq_num,s->last_ack))
01131                 &&
01132              SEQ_GT(spd->seq_num+spd->payload_size,s->last_ack))
01133     {
01134         /* packet is entirely after the wrap */
01135         if(SEQ_LT(spd->seq_num,s->last_ack))
01136         {
01137             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: entirely after the wrap\n"););
01138 
01139             offset = before_size + spd->seq_num;        
01140         }
01141         /* packet starts before the wrap, ends after it */
01142         else
01143         {
01144             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: packet starts before the wrap, ends after it\n"););
01145 
01146             offset = spd->seq_num - s->base_seq;
01147         }
01148 
01149         s->next_seq = spd->seq_num + spd->payload_size;
01150 
01151         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: start in end out: Copying %d bytes into buffer, "
01152                     "offset %d, buf %p\n", spd->payload_size, offset, 
01153                     buf););
01154 
01155         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
01156                     "REASS_WRAP: spd->seq_num (%u)  s->last_ack (%u) "
01157                     "s->base_seq(%u) size: (%u) s->next_seq(%u), "
01158                     "offset(%u), MAX(%u)\n",
01159                     spd->seq_num, s->last_ack, s->base_seq,
01160                     spd->payload_size, s->next_seq, offset, 
01161                     MAX_STREAM_SIZE));
01162 
01163         SafeMemcpy(buf+offset, spd->payload, spd->payload_size,
01164                 stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);
01165 
01166         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: SafeMemcpy completed\n"););
01167 
01168         pc.rebuilt_segs++;
01169 
01170         spd->chuck = SEG_FULL;
01171         bd->total_size += spd->payload_size;
01172     }
01173     else if(SEQ_GEQ(spd->seq_num,s->last_ack))
01174     {
01175         offset = spd->seq_num + before_size;
01176 
01177         s->next_seq = spd->seq_num + spd->payload_size;
01178 
01179         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: completely out: Copying %d bytes into buffer, "
01180                     "offset %d, buf %p\n", spd->payload_size, offset, 
01181                     buf););
01182 
01183         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
01184                     "REASS_WRAP: spd->seq_num (%u)  s->last_ack (%u) "
01185                     "s->base_seq(%u) size: (%u) s->next_seq(%u), "
01186                     "offset(%u), MAX(%u)\n",
01187                     spd->seq_num, s->last_ack, s->base_seq,
01188                     spd->payload_size, s->next_seq, offset, 
01189                     MAX_STREAM_SIZE));
01190 
01191         SafeMemcpy(buf+offset, spd->payload, spd->payload_size,
01192                 stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE);
01193 
01194         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REASS_WRAP: SafeMemcpy completed\n"););
01195         
01196         pc.rebuilt_segs++;
01197 
01198         spd->chuck = SEG_FULL;
01199         bd->total_size += spd->payload_size;
01200     }
01201     else
01202     {
01203         /* The only case that should reach this point is if
01204          * spd->seq_num < s->base_seq &&
01205          * spd->seq_num + spd->payload_size >= s->last_ack
01206          * Can that ever happen?
01207          */
01208         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
01209                     "REASS_WRAP: Ended up in the default case somehow.. !\n"
01210                     "spd->seq_num(%u) spd->payload_size(%u)\n",
01211                     spd->seq_num, spd->payload_size););        
01212     }
01213 } 
01214 //#endif /* GIDS */
01215 
01216 
01217 
01218 /*
01219 
01220         loop through the splay-tree and remove spds untill we have
01221         reached bytes_to_remove
01222         
01223         extra: we also remove all pre-wrap leftover spds
01224 */
01225 void SegmentTruncTraverse(Stream *s, u_int16_t bytes_to_clear)
01226 {
01227     StreamPacketData *spd = NULL;
01228     StreamPacketData *foo = NULL;
01229     StreamPacketData *savspd = NULL;
01230     u_int16_t removed_so_far = 0;
01231     char quit_on_limit_reached = 0;
01232 
01233     //printf("%s: going to remove %u bytes\n", __FUNCTION__, bytes_to_clear);
01234 
01235     if (!s->data.root)
01236         return;
01237 
01238     spd = (StreamPacketData *) ubi_btFirst((ubi_btNodePtr)&s->data);
01239 
01240     /* leave at least one packet in the tree */
01241     while(spd != NULL && ubi_trCount(&s->data) > 1)
01242     {
01243         //printf("%s: CUR: seq %u size %u (base %u, lack %u)\n", __FUNCTION__, spd->seq_num, spd->payload_size, s->base_seq, s->last_ack);
01244 
01245         /* remove pre wrap leftovers */
01246         if((MAX_SEQ_NUM - MAX_STREAM_SIZE) < spd->seq_num &&
01247             (spd->seq_num - MAX_STREAM_SIZE) > s->last_ack &&
01248             (spd->seq_num - (MAX_STREAM_SIZE * 2)) > s->base_seq)
01249         {
01250             //printf("%s: seq %u size %u (WRAPPED)\n", __FUNCTION__, spd->seq_num, spd->payload_size);
01251 
01252             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
01253                 "TRUNC(pre-wrap leftover cleanup): spd->seq_num (%u)  s->last_ack (%u) "
01254                 "s->base_seq(%u) size: (%u) s->next_seq(%u)\n",
01255                 spd->seq_num, s->last_ack, s->base_seq,
01256                 spd->payload_size, s->next_seq));
01257 
01258             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC(pre-wrap leftover cleanup): adjusting s->bytes_tracked: %u. Going to sub %u...\n", s->bytes_tracked, spd->payload_size););
01259 
01260             /* we want to remove all pre-wrap spds this run */
01261             quit_on_limit_reached = 0;
01262         }
01263         else
01264         {
01265             quit_on_limit_reached = 1;
01266 
01267             /* check if we need to adjust s->base_seq */
01268 
01269             /* Packet is completely before the current window. */
01270             if(SEQ_LEQ(spd->seq_num, s->base_seq) &&
01271                 SEQ_LEQ(spd->seq_num + spd->payload_size, s->base_seq))
01272             {
01273                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: packet before current window, base: %u.\n", s->base_seq););
01274 
01275                 /* don't touch base */
01276             }
01277             /* Packet starts outside the window and ends inside it. */
01278             else if(SEQ_LT(spd->seq_num, s->base_seq) &&
01279                 isBetween(s->base_seq+1, s->last_ack, (spd->seq_num + spd->payload_size)))
01280             {
01281                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: Packet starts before current window, base: %u.\n", s->base_seq););
01282 
01283                 /* base fits in this packet, so set it to spd->seq_num + spd->payload_size */
01284                 s->base_seq = spd->seq_num + spd->payload_size;
01285 
01286                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: adjusted base to: %u.\n", s->base_seq););
01287             }
01288             /* if it's in bounds... */
01289             else if(isBetween(s->base_seq, s->last_ack-1, spd->seq_num) &&
01290                 isBetween(s->base_seq, s->last_ack,   (spd->seq_num + spd->payload_size)))
01291             {
01292                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: Packet in current window, base: %u.\n", s->base_seq););
01293 
01294                 /* base fits in this packet, so set it to spd->seq_num + spd->payload_size */
01295                 s->base_seq = spd->seq_num + spd->payload_size;
01296 
01297                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: adjusted base to: %u.\n", s->base_seq););
01298             }
01299             else if(isBetween(s->base_seq, s->last_ack-1, spd->seq_num) &&
01300                 SEQ_GT((spd->seq_num + spd->payload_size), s->last_ack))
01301             {
01302                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: Packet partly outside current window, base: %u.\n", s->base_seq););
01303 
01304                 /* base fits in this packet, so set it to spd->seq_num + spd->payload_size */
01305                 s->base_seq = spd->seq_num + spd->payload_size;
01306 
01307                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: adjusted base to: %u.\n", s->base_seq););
01308             }
01309             else if(SEQ_GEQ(spd->seq_num,s->last_ack))
01310             {
01311                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: Packet totally past the current window, base: %u.\n", s->base_seq););
01312 
01313                 /* set base to spd->seq_num + spd->payload_size */
01314                 s->base_seq = spd->seq_num + spd->payload_size;
01315 
01316                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"TRUNC: adjusted base to: %u.\n", s->base_seq););
01317             }
01318         }
01319 
01320         savspd = spd;
01321         spd = (StreamPacketData *) ubi_btNext((ubi_btNodePtr)spd);
01322 #ifdef DEBUG
01323         if(savspd->chuck == SEG_FULL)
01324         {
01325             DebugMessage(DEBUG_STREAM, "[sct] chucking used segment\n");
01326         }
01327         else
01328         {
01329             DebugMessage(DEBUG_STREAM, "[sct] tossing unused segment\n");
01330         }
01331 #endif /*DEBUG*/
01332 
01333         /* pull the node from the tree */
01334         foo = (StreamPacketData *) ubi_sptRemove(&s->data, 
01335                   (ubi_btNodePtr) savspd);
01336 
01337         /* update the streamsize */
01338         StreamSegmentSub(s, foo->payload_size);
01339 //        s->bytes_tracked = s->bytes_tracked - spd->payload_size;
01340 
01341         removed_so_far += foo->payload_size;
01342 
01343         /* free the memory */
01344         stream4_memory_usage -= foo->pkt_size;
01345         free(foo->pktOrig);
01346         stream4_memory_usage -= sizeof(StreamPacketData);
01347         free(foo);
01348 
01349         /* quit if we have reached our limit, but only
01350            if we are not cleaning up pre-wrap leftovers */
01351         if(quit_on_limit_reached == 1)
01352         {
01353             if(removed_so_far >= bytes_to_clear)
01354             {
01355                 //printf("%s: @exit(spd rem)was going to remove %u bytes, removed %u, %u spds in tree left\n", __FUNCTION__, bytes_to_clear, removed_so_far, ubi_trCount(&s->data));
01356                 break;
01357             }
01358         }
01359     }
01360 
01361     return;
01362 }
01363 
01364 
01365 #endif /* GIDS */
01366 
01367 
01368 void SegmentCleanTraverse(Stream *s)
01369 {
01370     StreamPacketData *spd;
01371     StreamPacketData *foo;
01372 
01373     if (!s->data.root)
01374         return;
01375 
01376     spd = (StreamPacketData *) ubi_btFirst((ubi_btNodePtr)&s->data);
01377 
01378     while(spd != NULL)
01379     {
01380         if(spd->chuck == SEG_FULL || SEQ_GEQ(s->last_ack,(spd->seq_num+spd->payload_size)))
01381         {
01382             StreamPacketData *savspd = spd;
01383             spd = (StreamPacketData *) ubi_btNext((ubi_btNodePtr)spd);
01384 #ifdef DEBUG
01385             if(savspd->chuck == SEG_FULL)
01386             {
01387                 DebugMessage(DEBUG_STREAM, "[sct] chucking used segment\n");
01388             }
01389             else
01390             {
01391                 DebugMessage(DEBUG_STREAM, "[sct] tossing unused segment\n");
01392             }
01393 #endif /*DEBUG*/
01394             foo = (StreamPacketData *) ubi_sptRemove(&s->data, 
01395                     (ubi_btNodePtr) savspd);
01396             StreamSegmentSub(s, foo->payload_size);
01397 
01398             stream4_memory_usage -= foo->pkt_size;
01399             free(foo->pktOrig);
01400             stream4_memory_usage -= sizeof(StreamPacketData);
01401             free(foo);
01402         }
01403         else
01404         {
01405             spd = (StreamPacketData *) ubi_btNext((ubi_btNodePtr)spd);
01406         }
01407     }
01408 }
01409 
01410 /* XXX: this will be removed as we clean up the modularization */
01411 void DirectLogTcpdump(struct pcap_pkthdr *, u_int8_t *);
01412 
01413 static void LogTraverse(ubi_trNodePtr NodePtr, void *foo)
01414 {
01415     StreamPacketData *spd;
01416 
01417     spd = (StreamPacketData *) NodePtr;
01418     /* XXX: modularization violation */
01419     DirectLogTcpdump((struct pcap_pkthdr *)&spd->pkth, spd->pkt); 
01420 }
01421 
01422 void *SafeAlloc(unsigned long size, int tv_sec, Session *ssn)
01423 {
01424     void *tmp;
01425 
01426     stream4_memory_usage += size;
01427 
01428     /* if we use up all of our RAM, try to free up some stale sessions */
01429     if(stream4_memory_usage > s4data.memcap)
01430     {
01431         pc.str_mem_faults++;
01432         sfPerf.sfBase.iStreamFaults++;
01433         if(!PruneSessionCache((u_int32_t)tv_sec, 0, ssn))
01434         {
01435              /* if we can't prune due to time, just nuke 5 random sessions 
01436              *  or
01437              * we try to cut of data off of 15 sessions
01438              */
01439 #ifdef GIDS
01440             if(s4data.stream4inline_mode && s4data.truncate)
01441                 TruncSessionCache((u_int32_t)tv_sec, 15, ssn);
01442             else
01443 #endif /* GIDS */
01444                 PruneSessionCache(0, 5, ssn);
01445         }
01446     }
01447 
01448     tmp = (void *) calloc(size, sizeof(char));
01449 
01450     if(tmp == NULL)
01451     {
01452         FatalError("Unable to allocate memory! (%lu bytes in use)\n", 
01453                    (unsigned long)stream4_memory_usage);
01454     }
01455 
01456     return tmp;
01457 }
01458 
01459 
01460 /*
01461  * Function: SetupStream4()
01462  *
01463  * Purpose: Registers the preprocessor keyword and initialization 
01464  *          function into the preprocessor list.  This is the function that
01465  *          gets called from InitPreprocessors() in plugbase.c.
01466  *
01467  * Arguments: None.
01468  *
01469  * Returns: void function
01470  */
01471 void SetupStream4()
01472 {
01473     /* link the preprocessor keyword to the init function in 
01474        the preproc list */
01475     RegisterPreprocessor("stream4", Stream4Init);
01476     RegisterPreprocessor("stream4_reassemble", Stream4InitReassembler);
01477 
01478     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  "Preprocessor: Stream4 is setup...\n"););
01479 }
01480 
01481 
01482 /*
01483  * Function: Stream4Init(u_char *)
01484  *
01485  * Purpose: Calls the argument parsing function, performs final setup on data
01486  *          structs, links the preproc function into the function list.
01487  *
01488  * Arguments: args => ptr to argument string
01489  *
01490  * Returns: void function
01491  */
01492 void Stream4Init(u_char *args)
01493 {
01494     char logfile[STD_BUF];
01495 
01496     s4data.stream4_active = 1;
01497     pv.stateful = 1;
01498     s4data.memcap = STREAM4_MEMORY_CAP;
01499     s4data.max_sessions = STREAM4_MAX_SESSIONS;
01500 
01501     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "log_dir is %s\n", pv.log_dir););
01502 
01503     /* initialize the self preservation counters */
01504     s4data.sp_threshold      = SELF_PRES_THRESHOLD;
01505     s4data.sp_period         = SELF_PRES_PERIOD;
01506     s4data.suspend_threshold = SUSPEND_THRESHOLD;
01507     s4data.suspend_period    = SUSPEND_PERIOD;
01508     s4data.state_protection  = 0; 
01509     
01510     s4_emergency.end_time = 0;
01511     s4_emergency.new_session_count = 0;
01512     s4_emergency.status = OPS_NORMAL;
01513    
01514     /* parse the argument list from the rules file */
01515     ParseStream4Args(args);
01516     
01517     snprintf(logfile, STD_BUF, "%s/%s", pv.log_dir, "session.log");
01518     
01519     if(s4data.track_stats_flag)
01520     {
01521         if((session_log = fopen(logfile, "a+")) == NULL)
01522         {
01523             FatalError("Unable to write to \"%s\": %s\n", logfile, 
01524                        strerror(errno));
01525         }
01526     }
01527 
01528     s4data.last_prune_time = 0;
01529     
01530     stream_pkt = (Packet *) SafeAlloc(sizeof(Packet), 0, NULL);
01531 
01532     InitStream4Pkt();
01533 
01534     /* tell the rest of the program that we're stateful */
01535     snort_runtime.capabilities.stateful_inspection = 1;
01536    
01537 #ifdef USE_HASH_TABLE
01538     InitSessionCache();
01539 #else /* USE_SPLAY_TREE */
01540     (void)ubi_trInitTree(RootPtr,       /* ptr to the tree head */
01541                          CompareFunc,   /* comparison function */
01542                          0);            /* don't allow overwrites/duplicates */
01543 #endif
01544 
01545     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  "Preprocessor: Stream4 Initialized\n"););
01546 
01547     /* Set the preprocessor function into the function list */
01548     AddFuncToPreprocList(ReassembleStream4);
01549     AddFuncToShutdownList(Stream4ShutdownFunction, NULL);
01550     AddFuncToCleanExitList(Stream4CleanExitFunction, NULL);
01551     AddFuncToRestartList(Stream4RestartFunction, NULL);    
01552 }
01553 
01554 void DisplayStream4Config(void) 
01555 {
01556     LogMessage("Stream4 config:\n");
01557     LogMessage("    Stateful inspection: %s\n", 
01558                s4data.stateful_inspection_flag ? "ACTIVE": "INACTIVE");
01559     LogMessage("    Session statistics: %s\n", 
01560                s4data.track_stats_flag ? "ACTIVE":"INACTIVE");
01561     LogMessage("    Session timeout: %d seconds\n", s4data.timeout);
01562     LogMessage("    Session memory cap: %lu bytes\n", (unsigned long)s4data.memcap);
01563     LogMessage("    Session count max: %d sessions\n", (unsigned long)s4data.max_sessions);
01564     if (s4data.cache_clean_percent != 0)
01565         LogMessage("    Session cleanup percentage: %f %%\n", s4data.cache_clean_percent);
01566     else
01567         LogMessage("    Session cleanup count: %d\n", s4data.cache_clean_sessions);
01568     LogMessage("    State alerts: %s\n", 
01569                s4data.state_alerts ? "ACTIVE":"INACTIVE");
01570     LogMessage("    Evasion alerts: %s\n", 
01571                s4data.evasion_alerts ? "ACTIVE":"INACTIVE");
01572     LogMessage("    Scan alerts: %s\n", 
01573                s4data.ps_alerts ? "ACTIVE":"INACTIVE");
01574     LogMessage("    Log Flushed Streams: %s\n",
01575                s4data.log_flushed_streams ? "ACTIVE":"INACTIVE");
01576     LogMessage("    MinTTL: %d\n", s4data.min_ttl);
01577     LogMessage("    TTL Limit: %d\n", s4data.ttl_limit);
01578     LogMessage("    Async Link: %d\n", s4data.asynchronous_link);
01579     LogMessage("    State Protection: %d\n", s4data.state_protection);
01580     LogMessage("    Self preservation threshold: %d\n", s4data.sp_threshold);
01581     LogMessage("    Self preservation period: %d\n", s4data.sp_period);
01582     LogMessage("    Suspend threshold: %d\n", s4data.suspend_threshold);
01583     LogMessage("    Suspend period: %d\n", s4data.suspend_period);
01584     LogMessage("    Enforce TCP State: %s\n",
01585             s4data.enforce_state ? "ACTIVE" : "INACTIVE");
01586     LogMessage("    Midstream Drop Alerts: %s\n",
01587             s4data.ms_inline_alerts ? "ACTIVE" : "INACTIVE");
01588     if (s4data.server_inspect_limit > 0)
01589         LogMessage("    Server Data Inspection Limit: %d\n", 
01590                     s4data.server_inspect_limit);
01591 
01592 #ifdef GIDS
01593     LogMessage("Inline-mode options:\n");
01594     LogMessage("    Inline-mode enabled? (stream4inline): %s\n", s4data.stream4inline_mode ? "Yes" : "No");
01595     LogMessage("    Sliding Windowsize (window_size): %u (max full conn: %u)\n", s4data.stream4inline_window_size, s4data.memcap / s4data.stream4inline_window_size);
01596     LogMessage("    Memcap reached method (truncate): %s\n", s4data.truncate ? "Truncate" : "Prune");
01597     LogMessage("    Truncate percentage (truncate_percentage): %d\n", s4data.truncate_cut_off_perc);
01598 
01599     LogMessage("    DROP out-of-window packets (drop_out_of_window): %s\n", s4data.drop_out_of_window ? "Yes" : "No");
01600     LogMessage("    DROP data on unestablised session state (drop_data_on_unest): %s\n", s4data.drop_data_on_unest ? "Yes" : "No");
01601     LogMessage("    DROP no tcp-flags on establised packets (drop_no_tcp_on_est): %s\n", s4data.drop_no_tcp_on_est ? "Yes" : "No");
01602     LogMessage("    DROP packet not within session limits (drop_not_in_limits): %s\n", s4data.drop_not_in_limits ? "Yes" : "No");
01603     LogMessage("    DROP ttl evasion (drop_ttl_evasion): %s\n", s4data.drop_ttl_evasion ? "Yes" : "No");
01604 
01605     LogMessage("    Store/Load state from/to disk: %s\n", s4data.store_state_to_disk ? "Yes" : "No");
01606     if(s4data.store_state_to_disk)
01607         LogMessage("    State file: %s\n", s4data.state_file);
01608 #endif /* GIDS */
01609 }
01610 
01611 
01612 /*
01613  * Function: ParseStream4Args(char *)
01614  *
01615  * Purpose: Process the preprocessor arguements from the rules file and 
01616  *          initialize the preprocessor's data struct.  This function doesn't
01617  *          have to exist if it makes sense to parse the args in the init 
01618  *          function.
01619  *
01620  * Arguments: args => argument list
01621  *
01622  * Returns: void function
01623  */
01624 void ParseStream4Args(char *args)
01625 {
01626     char **toks;
01627     int num_toks;
01628     int num_statefiletoks;
01629     int i;
01630     char *index;
01631     char **stoks = NULL;
01632     char **statefiletoks = NULL;
01633     int s_toks;
01634 
01635     s4data.timeout = PRUNE_QUANTA;
01636     s4data.memcap = STREAM4_MEMORY_CAP;
01637     s4data.max_sessions = STREAM4_MAX_SESSIONS;
01638     s4data.cache_clean_percent = 0;
01639     s4data.cache_clean_sessions = STREAM4_CLEANUP;
01640     s4data.stateful_inspection_flag = 1;
01641     s4data.state_alerts = 0;
01642     s4data.evasion_alerts = 1;
01643     s4data.ps_alerts = 0;
01644     s4data.reassemble_client = s4data.reassemble_server = 0;
01645     s4data.log_flushed_streams = 0;
01646     s4data.min_ttl = 1;
01647     s4data.path_mtu = 1460;
01648     s4data.ttl_limit = STREAM4_TTL_LIMIT;
01649     s4data.asynchronous_link = 0;
01650     s4data.flush_data_diff_size = 500; 
01651     s4data.zero_flushed_packets = 0;
01652     s4data.flush_on_alert = 0;
01653     s4data.overlap_limit = -1;
01654     s4data.server_inspect_limit = -1;
01655     
01656     /* dynamic flush points */
01657     s4data.flush_behavior = FLUSH_BEHAVIOR_DEFAULT;
01658     s4data.flush_range = STREAM4_FLUSH_RANGE;
01659     s4data.flush_base = STREAM4_FLUSH_BASE;
01660     s4data.flush_seed = getpid() + time(NULL);
01661 
01662 #ifdef GIDS
01663     /* stream4-inline default settings */
01664     s4data.stream4inline_mode = 0; /* default no */
01665     s4data.stream4inline_window_size = STREAM4INLINE_WINDOW_SIZE;
01666     s4data.truncate = 0; /* default we prune */
01667     s4data.truncate_cut_off_perc = STREAM4INLINE_CUT_OFF_PERC;
01668     s4data.drop_out_of_window = 0;
01669     s4data.drop_data_on_unest = 0;
01670     s4data.drop_data_on_unest = 0;
01671     s4data.drop_no_tcp_on_est = 0;
01672     s4data.drop_not_in_limits = 0;
01673     s4data.drop_ttl_evasion = 0;
01674     s4data.store_state_to_disk = 0;
01675     memset(s4data.state_file, 0, sizeof(s4data.state_file));
01676 #endif /* GIDS */
01677 
01678     /* if no arguments, go ahead and return */
01679     if(args == NULL || args[0] == '\0')
01680     {
01681         DisplayStream4Config();
01682         return;
01683     }
01684 
01685     i=0;
01686 
01687     toks = mSplit(args, ",", 20, &num_toks, 0);
01688     
01689     while(i < num_toks)
01690     {
01691         index = toks[i];
01692 
01693         while(isspace((int)*index)) index++;
01694 
01695         stoks = mSplit(index, " ", 4, &s_toks, 0);
01696 
01697         if(!strcasecmp(stoks[0], "noinspect"))
01698         {
01699             s4data.stateful_inspection_flag = 0;
01700         }
01701         else if(!strcasecmp(stoks[0], "asynchronous_link"))
01702         {
01703             s4data.asynchronous_link = 1;
01704         }
01705         else if(!strcasecmp(stoks[0], "keepstats"))
01706         {
01707             s4data.track_stats_flag = STATS_HUMAN_READABLE;
01708 
01709             if(s_toks > 1)
01710             {
01711                 if(!strcasecmp(stoks[1], "machine"))
01712                 {
01713                     s4data.track_stats_flag = STATS_MACHINE_READABLE;
01714                 }
01715                 else if(!strcasecmp(stoks[1], "binary"))
01716                 {
01717                     s4data.track_stats_flag = STATS_BINARY;
01718                     stats_log = (StatsLog *) calloc(sizeof(StatsLog), 
01719                                                     sizeof(char));
01720                     stats_log->filename = strdup("snort-unified.stats");
01721                     OpenStatsFile();
01722                 } 
01723                 else
01724                 {
01725                     ErrorMessage("Bad stats mode for stream4, ignoring\n");
01726                     s4data.track_stats_flag = 0;
01727                 }
01728             }
01729         }
01730         else if(!strcasecmp(stoks[0], "detect_scans"))
01731         {
01732             s4data.ps_alerts = 1;
01733         }
01734         else if(!strcasecmp(stoks[0], "log_flushed_streams"))
01735         {
01736             s4data.log_flushed_streams = 1;
01737         }
01738         else if(!strcasecmp(stoks[0], "detect_state_problems"))
01739         {
01740             s4data.state_alerts = 1;
01741         }
01742         else if(!strcasecmp(stoks[0], "disable_evasion_alerts"))
01743         {
01744             s4data.evasion_alerts = 0;
01745         }
01746         else if(!strcasecmp(stoks[0], "timeout"))
01747         {
01748             if(isdigit((int)stoks[1][0]))
01749             {
01750                 s4data.timeout = atoi(stoks[1]);
01751             }
01752             else
01753             {
01754                 LogMessage("WARNING %s(%d) => Bad timeout in config file, "
01755                            "defaulting to %d seconds\n", file_name, file_line, 
01756                            PRUNE_QUANTA);
01757 
01758                 s4data.timeout = PRUNE_QUANTA;
01759             }
01760         }
01761         else if(!strcasecmp(stoks[0], "memcap"))
01762         {
01763             if(isdigit((int)stoks[1][0]))
01764             {
01765                 s4data.memcap = atoi(stoks[1]);
01766 
01767                 if(s4data.memcap < 16384)
01768                 {
01769                     LogMessage("WARNING %s(%d) => Ludicrous (<16k) memcap "
01770                                "size, setting to default (%d bytes)\n", file_name, 
01771                                file_line, STREAM4_MEMORY_CAP);
01772                     
01773                     s4data.memcap = STREAM4_MEMORY_CAP;
01774                 }
01775             }
01776             else
01777             {
01778                 FatalError("%s(%d) => Bad memcap in config file, %d\n",
01779                            file_name, file_line);
01780             }
01781         }
01782         else if(!strcasecmp(stoks[0], "max_sessions"))
01783         {
01784             if(isdigit((int)stoks[1][0]))
01785             {
01786                 s4data.max_sessions = atoi(stoks[1]);
01787 
01788                 if(s4data.max_sessions < 8192)
01789                 {
01790                     LogMessage("WARNING %s(%d) => Ludicrous (<8k) max_sessions "
01791                                "size, setting to default (%d sessions)\n", file_name, 
01792                                file_line, STREAM4_MAX_SESSIONS);
01793                     
01794                     s4data.max_sessions = STREAM4_MAX_SESSIONS;
01795                 }
01796             }
01797             else
01798             {
01799                 FatalError("%s(%d) => Bad max_sessions in config file, %d\n",
01800                            file_name, file_line);
01801             }
01802         }
01803         else if(!strcasecmp(stoks[0], "cache_clean_percent"))
01804         {
01805             if(isdigit((int)stoks[1][0]))
01806             {
01807                 s4data.cache_clean_percent = atof(stoks[1]);
01808 
01809                 if ((s4data.cache_clean_percent < 0) ||
01810                     (s4data.cache_clean_percent > 5))
01811                 {
01812                     LogMessage("WARNING %s(%d) => Ludicrous (%f) cache cleanup "
01813                                "percentage, setting to default (%f %%)\n", 
01814                                file_name, file_line, STREAM4_CACHE_PERCENT);
01815                     
01816                     s4data.cache_clean_percent = STREAM4_CACHE_PERCENT;
01817                 }
01818             }
01819             else
01820             {
01821                 FatalError("%s(%d) => Bad cache cleanup percent in "
01822                            "config file, %d\n", file_name, file_line);
01823 
01824             }
01825         }
01826         else if(!strcasecmp(stoks[0], "cache_clean_sessions"))
01827         {
01828             if(isdigit((int)stoks[1][0]))
01829             {
01830                 s4data.cache_clean_sessions = atoi(stoks[1]);
01831             }
01832             else
01833             {
01834                 FatalError("%s(%d) => Bad cache cleanup value in "
01835                            "config file\n", file_name, file_line);
01836 
01837             }
01838         }
01839         else if(!strcasecmp(stoks[0], "ttl_limit"))
01840         {
01841             if(s_toks > 1)
01842             {
01843                 if(stoks[1] == NULL || stoks[1][0] == '\0')
01844                 {
01845                     FatalError("%s(%d) => ttl_limit requires an integer argument\n",
01846                             file_name,file_line);
01847                 }
01848             
01849                 if(isdigit((int)stoks[1][0]))
01850                 {
01851                     s4data.ttl_limit = atoi(stoks[1]);
01852                 }
01853                 else
01854                 {
01855                     LogMessage("WARNING %s(%d) => Bad TTL Limit"
01856                                "size, setting to default (%d\n", file_name, 
01857                                file_line, STREAM4_TTL_LIMIT);
01858 
01859                     s4data.ttl_limit = STREAM4_TTL_LIMIT;
01860                 }
01861             }
01862             else
01863             {
01864                 FatalError("%s(%d) => ttl_limit requires an integer argument\n",
01865                         file_name,file_line);
01866             }
01867         }
01868         else if(!strcasecmp(stoks[0], "self_preservation_threshold"))
01869         {
01870             if(isdigit((int)stoks[1][0]))
01871             {
01872                 s4data.sp_threshold = atoi(stoks[1]);
01873             }
01874             else
01875             {
01876                 LogMessage("WARNING %s(%d) => Bad sp_threshold in config file, "
01877                            "defaulting to %d new sessions/second\n", file_name, 
01878                            file_line, SELF_PRES_THRESHOLD);
01879 
01880                 s4data.sp_threshold = SELF_PRES_THRESHOLD;
01881             }
01882         }
01883         else if(!strcasecmp(stoks[0], "self_preservation_period"))
01884         {
01885             if(isdigit((int)stoks[1][0]))
01886             {
01887                 s4data.sp_period = atoi(stoks[1]);
01888             }
01889             else            {
01890                 LogMessage("WARNING %s(%d) => Bad sp_period in config file, "
01891                            "defaulting to %d seconds\n", file_name, file_line, 
01892                            SELF_PRES_PERIOD);
01893 
01894                 s4data.sp_period = SELF_PRES_PERIOD;
01895             }
01896         }
01897         else if(!strcasecmp(stoks[0], "suspend_threshold"))
01898         {
01899             if(isdigit((int)stoks[1][0]))
01900             {
01901                 s4data.suspend_threshold = atoi(stoks[1]);
01902             }
01903             else
01904             {
01905                 LogMessage("WARNING %s(%d) => Bad suspend_threshold in config "
01906                         "file, defaulting to %d new sessions/second\n", 
01907                         file_name, file_line, SUSPEND_THRESHOLD);
01908 
01909                 s4data.suspend_threshold = SUSPEND_THRESHOLD;
01910             }
01911         }
01912         else if(!strcasecmp(stoks[0], "suspend_period"))
01913         {
01914             if(isdigit((int)stoks[1][0]))
01915             {
01916                 s4data.suspend_period = atoi(stoks[1]);
01917             }
01918             else
01919             {
01920                 LogMessage("WARNING %s(%d) => Bad suspend_period in config file, "
01921                            "defaulting to %d seconds\n", file_name, file_line, 
01922                            SUSPEND_PERIOD);
01923 
01924                 s4data.suspend_period = SUSPEND_PERIOD;
01925             }
01926         }
01927         else if(!strcasecmp(stoks[0], "enforce_state"))
01928         {
01929             s4data.enforce_state = 1;
01930         }
01931         else if(!strcasecmp(stoks[0], "midstream_drop_alerts"))
01932         {
01933             s4data.ms_inline_alerts = 1;
01934         }
01935         else if(!strcasecmp(stoks[0], "state_protection"))
01936         {
01937             s4data.state_protection = 1;
01938         }
01939         else if(!strcasecmp(stoks[0], "server_inspect_limit"))
01940         {
01941             if(isdigit((int)stoks[1][0]))
01942             {
01943                 s4data.server_inspect_limit = atoi(stoks[1]);
01944             }
01945             else
01946             {
01947                 FatalError("WARNING %s(%d) => Bad server_inspect_limit in "
01948                            "config file\n", file_name, file_line);
01949             }
01950         }
01951 #ifdef GIDS
01952         else if(!strcasecmp(stoks[0], "stream4inline"))
01953         {
01954             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "stream4inline mode enabled\n"););
01955             s4data.stream4inline_mode = 1;
01956             LogMessage("stream4inline mode enabled\n");
01957         }
01958         else if(!strcasecmp(stoks[0], "truncate"))
01959         {
01960             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "truncating mode enabled\n"););
01961             s4data.truncate = 1;
01962             LogMessage("truncating mode enabled\n");
01963         }
01964         else if(!strcasecmp(stoks[0], "window_size"))
01965         {
01966             if(isdigit((int)stoks[1][0]))
01967             {
01968                 s4data.stream4inline_window_size = atoi(stoks[1]);
01969             }
01970             else
01971             {
01972                 LogMessage("WARNING %s(%d) => Bad window size in config file, "
01973                            "defaulting to %d bytes\n", file_name, file_line, 
01974                            STREAM4INLINE_WINDOW_SIZE);
01975             }
01976         }
01977         else if(!strcasecmp(stoks[0], "truncate_percentage"))
01978         {
01979             if(isdigit((int)stoks[1][0]))
01980             {
01981                 s4data.truncate_cut_off_perc = atoi(stoks[1]);
01982                 if(s4data.truncate_cut_off_perc == 0)
01983                 {
01984                     s4data.truncate_cut_off_perc = STREAM4INLINE_CUT_OFF_PERC;
01985                 }
01986                 else if(s4data.truncate_cut_off_perc > 100)
01987                 {
01988                     s4data.truncate_cut_off_perc = 100;
01989                 }
01990             }
01991             else
01992             {
01993                 LogMessage("WARNING %s(%d) => Bad cut-off percentage in config file, "
01994                            "defaulting to %d precent\n", file_name, file_line, 
01995                            STREAM4INLINE_CUT_OFF_PERC);
01996             }
01997         }
01998         else if(!strcasecmp(stoks[0], "drop_out_of_window"))
01999         {
02000             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "drop_out_of_window mode enabled\n"););
02001             s4data.drop_out_of_window = 1;
02002             LogMessage("drop_out_of_window mode enabled\n");
02003         }
02004         else if(!strcasecmp(stoks[0], "drop_data_on_unest"))
02005         {
02006             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "drop_data_on_unest mode enabled\n"););
02007             s4data.drop_data_on_unest = 1;
02008             LogMessage("drop_data_on_unest mode enabled\n");
02009         }
02010         else if(!strcasecmp(stoks[0], "drop_no_tcp_on_est"))
02011         {
02012             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "drop_no_tcp_on_est mode enabled\n"););
02013             s4data.drop_no_tcp_on_est = 1;
02014             LogMessage("drop_no_tcp_on_est mode enabled\n");
02015         }
02016         else if(!strcasecmp(stoks[0], "drop_not_in_limits"))
02017         {
02018             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "drop_no_in_limits mode enabled\n"););
02019             s4data.drop_not_in_limits = 1;
02020             LogMessage("drop_not_in_limits mode enabled\n");
02021         }
02022         else if(!strcasecmp(stoks[0], "drop_ttl_evasion"))
02023         {
02024             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "drop_ttl_evasion mode enabled\n"););
02025             s4data.drop_ttl_evasion = 1;
02026             LogMessage("drop_ttl_evasion mode enabled\n");
02027         }
02028         else if(!strncasecmp(index, "state_file", 10))
02029         {
02030             s4data.store_state_to_disk = 1;
02031 
02032             /* get the argument for the option */
02033             statefiletoks = mSplit(index, " ", 1, &num_statefiletoks, 0);
02034 
02035             /* copy it to the s4data */
02036             if(strlcpy(s4data.state_file, statefiletoks[1], sizeof(s4data.state_file)) >= sizeof(s4data.state_file))
02037             {
02038                 FatalError("The state_file location supplied in the config is too long\n");
02039             }
02040             mSplitFree(&statefiletoks, num_statefiletoks);
02041         }
02042 #endif /* GIDS */
02043         else
02044         {
02045             FatalError("%s(%d) => Unknown stream4: option: %s\n",
02046                        file_name, file_line, stoks[0]);
02047         }
02048 
02049         mSplitFree(&stoks, s_toks);
02050 
02051         i++;
02052     }
02053 
02054     mSplitFree(&toks, num_toks);
02055 
02056     DisplayStream4Config();
02057 }
02058 
02059 
02060 void Stream4InitReassembler(u_char *args)
02061 {
02062     char buf[STD_BUF+1];
02063     char **toks;
02064     char **stoks;
02065     int num_toks = 0;
02066     int num_args;
02067     int i;
02068     int j = 0;
02069     char *index;
02070     char *value;
02071 
02072     if(s4data.stream4_active == 0)
02073     {
02074         FatalError("Please activate stream4 before trying to "
02075                    "activate stream4_reassemble\n");
02076     }
02077 
02078     s4data.reassembly_alerts = 1;
02079     s4data.reassemble_client = 1; 
02080     s4data.reassemble_server = 0;
02081     s4data.flush_on_alert = 0;
02082     s4data.assemble_ports[21] = 1;
02083     s4data.assemble_ports[23] = 1;
02084     s4data.assemble_ports[25] = 1;
02085     s4data.assemble_ports[42] = 1;
02086     s4data.assemble_ports[53] = 1;
02087     s4data.assemble_ports[80] = 1;
02088     s4data.assemble_ports[110] = 1;
02089     s4data.assemble_ports[111] = 1;
02090     s4data.assemble_ports[135] = 1;
02091     s4data.assemble_ports[136] = 1;
02092     s4data.assemble_ports[137] = 1;
02093     s4data.assemble_ports[139] = 1;
02094     s4data.assemble_ports[143] = 1;
02095     s4data.assemble_ports[445] = 1;
02096     s4data.assemble_ports[513] = 1;
02097     s4data.assemble_ports[1433] = 1;
02098     s4data.assemble_ports[1521] = 1;
02099     s4data.assemble_ports[3306] = 1;
02100     s4data.reassy_method = METHOD_FAVOR_OLD;
02101 
02102     /* setup for self preservaton... */
02103     s4data.emergency_ports[21] = 1;
02104     s4data.emergency_ports[23] = 1;
02105     s4data.emergency_ports[25] = 1;
02106     s4data.emergency_ports[42] = 1;
02107     s4data.emergency_ports[53] = 1;
02108     s4data.emergency_ports[80] = 1;
02109     s4data.emergency_ports[110] = 1;
02110     s4data.emergency_ports[111] = 1;
02111     s4data.emergency_ports[135] = 1;
02112     s4data.emergency_ports[136] = 1;
02113     s4data.emergency_ports[137] = 1;
02114     s4data.emergency_ports[139] = 1;
02115     s4data.emergency_ports[143] = 1;
02116     s4data.emergency_ports[445] = 1;
02117     s4data.emergency_ports[513] = 1;
02118     s4data.emergency_ports[1433] = 1;
02119     s4data.emergency_ports[1521] = 1;
02120     s4data.emergency_ports[3306] = 1;
02121    
02122     if (args != NULL) 
02123     {
02124         toks = mSplit(args, ",", 12, &num_toks, 0);
02125     }
02126 
02127     i=0;
02128 
02129     while(i < num_toks)
02130     {
02131         index = toks[i];
02132         while(isspace((int)*index)) index++;
02133 
02134         if(!strncasecmp(index, "clientonly", 10))
02135         {
02136             s4data.reassemble_client = 1;
02137             s4data.reassemble_server = 0;
02138         }
02139         else if(!strncasecmp(index, "serveronly", 10))
02140         {
02141             s4data.reassemble_server = 1;
02142             s4data.reassemble_client = 0;
02143         }
02144         else if(!strncasecmp(index, "both", 4))
02145         {
02146             s4data.reassemble_client = 1;
02147             s4data.reassemble_server = 1;
02148         }
02149         else if(!strncasecmp(index, "noalerts", 8))
02150         {
02151             s4data.reassembly_alerts = 0;
02152         }
02153         else if(!strncasecmp(index, "favor_old", 9))
02154         {
02155             s4data.reassy_method = METHOD_FAVOR_OLD;
02156         }
02157         else if(!strncasecmp(index, "favor_new", 9))
02158         {
02159             s4data.reassy_method = METHOD_FAVOR_NEW;
02160         }
02161         else if(!strncasecmp(index, "flush_on_alert", 9))
02162         {
02163             s4data.flush_on_alert = 1;
02164         }
02165         else if(!strncasecmp(index, "overlap_limit", 9))
02166         {
02167             stoks = mSplit(index, " ", 2, &num_args, 0);
02168             value = stoks[1];
02169             if((num_args == 2) && (isdigit((int)value[0])))
02170             {
02171                 s4data.overlap_limit = atoi(value);
02172             }
02173             else
02174             {
02175                 FatalError("%s(%d) => Bad overlap_limit value in "
02176                            "config file\n", file_name, file_line);
02177             }
02178             mSplitFree(&stoks, num_args);
02179         }
02180         else if(!strncasecmp(index, "flush_behavior", 14))
02181         {
02182             stoks = mSplit(index, " ", 2, &num_args, 0);
02183             value = stoks[1];
02184             if(num_args != 2)
02185             {
02186                 FatalError("%s(%d) => Bad flush_behavior value in "
02187                            "config file\n", file_name, file_line);
02188             }
02189             if (!strncasecmp(value, "default", 7))
02190             {
02191                 s4data.flush_behavior = FLUSH_BEHAVIOR_DEFAULT;
02192             }
02193             else if (!strncasecmp(value, "random", 6))
02194             {
02195                 s4data.flush_behavior = FLUSH_BEHAVIOR_RANDOM;
02196             }
02197             else if (!strncasecmp(value, "large_window", 12))
02198             {
02199                 s4data.flush_behavior = FLUSH_BEHAVIOR_LARGE;
02200             }
02201             else
02202             {
02203                 FatalError("%s(%d) => Invalid flush_behavior value (%s) in "
02204                            "config file\n", file_name, file_line, value);
02205             }
02206 
02207             mSplitFree(&stoks, num_args);
02208         }
02209         else if(!strncasecmp(index, "flush_seed", 10))
02210         {
02211             stoks = mSplit(index, " ", 2, &num_args, 0);
02212             value = stoks[1];
02213             if((num_args == 2) && (isdigit((int)value[0])))
02214             {
02215                 s4data.flush_seed = atoi(value) + time(NULL);
02216             }
02217             else
02218             {
02219                 FatalError("%s(%d) => Unsupported flush_seed value in "
02220                            "config file\n", file_name, file_line);
02221             }
02222             mSplitFree(&stoks, num_args);
02223         }
02224         else if(!strncasecmp(index, "flush_base", 10))
02225         {
02226             stoks = mSplit(index, " ", 2, &num_args, 0);
02227             value = stoks[1];
02228             if((num_args == 2) && (isdigit((int)value[0])))
02229             {
02230                 s4data.flush_base = atoi(value);
02231             }
02232             else
02233             {
02234                 FatalError("%s(%d) => Bad flush_base value in "
02235                            "config file\n", file_name, file_line);
02236             }
02237             mSplitFree(&stoks, num_args);
02238 
02239             if((s4data.flush_base < 1) || (s4data.flush_base > 32768))
02240             {
02241                 FatalError("%s(%d) => Unsupported flush_base value (%d bytes) in "
02242                            "config file\n", 
02243                            file_name, file_line, s4data.flush_base);
02244             }
02245         }
02246         else if(!strncasecmp(index, "flush_range", 11))
02247         {
02248             stoks = mSplit(index, " ", 2, &num_args, 0);
02249             value = stoks[1];
02250             if((num_args == 2) && (isdigit((int)value[0])))
02251             {
02252                 s4data.flush_range = atoi(value);
02253             }
02254             else
02255             {
02256                 FatalError("%s(%d) => Bad flush_range in config file\n",
02257                            file_name, file_line);
02258             }
02259             mSplitFree(&stoks, num_args);
02260 
02261             if((s4data.flush_range < 512) || (s4data.flush_range > 32767))
02262             {
02263                 FatalError("%s(%d) => Unsupported flush_range value "
02264                            "(%d bytes) in config file\n",
02265                            file_name, file_line, s4data.flush_range);
02266             }
02267         }
02268         else if(!strncasecmp(index, "ports", 5))
02269         {
02270             char **ports;
02271             int num_ports;
02272             char *port;
02273             int j = 0;
02274             u_int32_t portnum;
02275 
02276             for(j = 0;j<65535;j++)
02277             {
02278                 s4data.assemble_ports[j] = 0;
02279             }
02280 
02281             ports = mSplit(index, " ", 40, &num_ports, 0);
02282 
02283             j = 1;
02284 
02285             while(j < num_ports)
02286             {
02287                 port = ports[j];
02288 
02289                 if(isdigit((int)port[0]))
02290                 {
02291                     portnum = atoi(port);
02292 
02293                     if(portnum > 65535)
02294                     {
02295                         FatalError("%s(%d) => Bad port list to "
02296                                    "reassembler\n", file_name, file_line);
02297                     }
02298 
02299                     s4data.assemble_ports[portnum] = 1;
02300                 }
02301                 else if(!strncasecmp(port, "all", 3))
02302                 {
02303                     memset(&s4data.assemble_ports, 1, 65536);
02304                 }
02305                 else if(!strncasecmp(port, "default", 7))
02306                 {
02307                     s4data.assemble_ports[21] = 1;
02308                     s4data.assemble_ports[23] = 1;
02309                     s4data.assemble_ports[25] = 1;
02310                     s4data.assemble_ports[42] = 1;
02311                     s4data.assemble_ports[53] = 1;
02312                     s4data.assemble_ports[80] = 1;
02313                     s4data.assemble_ports[110] = 1;
02314                     s4data.assemble_ports[111] = 1;
02315                     s4data.assemble_ports[135] = 1;
02316                     s4data.assemble_ports[136] = 1;
02317                     s4data.assemble_ports[137] = 1;
02318                     s4data.assemble_ports[139] = 1;
02319                     s4data.assemble_ports[143] = 1;
02320                     s4data.assemble_ports[445] = 1;
02321                     s4data.assemble_ports[513] = 1;
02322                     s4data.assemble_ports[1433] = 1;
02323                     s4data.assemble_ports[1521] = 1;
02324                     s4data.assemble_ports[3306] = 1;
02325                 }
02326 
02327                 j++;
02328             }
02329 
02330             mSplitFree(&ports, num_ports);
02331         }
02332         else if(!strncasecmp(index, "emergency_ports", 15))
02333         {
02334             char **ports;
02335             int num_ports;
02336             char *port;
02337             int j = 0;
02338             u_int32_t portnum;
02339 
02340             for(j = 0;j<65535;j++)
02341             {
02342                 s4data.emergency_ports[j] = 0;
02343             }
02344 
02345             ports = mSplit(args, " ", 40, &num_ports, 0);
02346 
02347             j = 0;
02348 
02349             while(j < num_ports)
02350             {
02351                 port = ports[j];
02352 
02353                 if(isdigit((int)port[0]))
02354                 {
02355                     portnum = atoi(port);
02356 
02357                     if(portnum > 65535)
02358                     {
02359                         FatalError("%s(%d) => Bad port list to "
02360                                    "reassembler\n", file_name, file_line);
02361                     }
02362 
02363                     s4data.emergency_ports[portnum] = 1;
02364                 }
02365                 else if(!strncasecmp(port, "all", 3))
02366                 {
02367                     memset(&s4data.emergency_ports, 1, 65536);
02368                 }
02369                 else if(!strncasecmp(port, "default", 7))
02370                 {
02371                     s4data.emergency_ports[21] = 1;
02372                     s4data.emergency_ports[23] = 1;
02373                     s4data.emergency_ports[25] = 1;
02374                     s4data.emergency_ports[42] = 1;
02375                     s4data.emergency_ports[53] = 1;
02376                     s4data.emergency_ports[80] = 1;
02377                     s4data.emergency_ports[110] = 1;
02378                     s4data.emergency_ports[111] = 1;
02379                     s4data.emergency_ports[135] = 1;
02380                     s4data.emergency_ports[136] = 1;
02381                     s4data.emergency_ports[137] = 1;
02382                     s4data.emergency_ports[139] = 1;
02383                     s4data.emergency_ports[143] = 1;
02384                     s4data.emergency_ports[445] = 1;
02385                     s4data.emergency_ports[513] = 1;
02386                     s4data.emergency_ports[1433] = 1;
02387                     s4data.emergency_ports[1521] = 1;
02388                     s4data.emergency_ports[3306] = 1;
02389                 }
02390 
02391                 j++;
02392             }
02393 
02394             mSplitFree(&ports, num_ports);
02395         }
02396         else if(!strcasecmp(index, "zero_flushed_packets"))
02397         {
02398             s4data.zero_flushed_packets = 1;
02399         }
02400         else if(!strncasecmp(index, "flush_data_diff_size", 
02401                     strlen("flush_data_diff_size")))
02402         {
02403             /* using strncasecmp since it will be flush_data_diff_size <int> */
02404             char *number_str;
02405             number_str = strrchr(index,' '); /* find the last ' ' */
02406 
02407             if(number_str && *number_str != '\0')
02408             {
02409                 number_str++; 
02410             }
02411 
02412             if(number_str && *number_str != '\0' && (isdigit((int)*number_str)))
02413             {
02414                 s4data.flush_data_diff_size = atoi(number_str);
02415                 
02416                 if(s4data.flush_data_diff_size < 0)
02417                 {
02418                     FatalError("%s(%d) => Bad flush_data_diff_size in "
02419                             "config file\n", file_name, file_line);
02420                 }
02421             }
02422             else
02423             {
02424                 FatalError("%s(%d) => Bad flush_data_diff_size in config file\n",
02425                            file_name, file_line);
02426             }
02427         }
02428         else
02429         {
02430             FatalError("%s(%d) => Bad stream4_reassemble option "
02431                        "specified: \"%s\"\n", file_name, file_line, toks[i]);
02432         }
02433 
02434         i++;
02435     }
02436 
02437     if (num_toks)
02438         mSplitFree(&toks, num_toks);
02439 
02440     /* Setup flushpoints, per config */
02441     if ( s4data.flush_behavior == FLUSH_BEHAVIOR_LARGE )
02442     {
02443         /* Default, larger static flushpoints */
02444         int elm;
02445         for( elm = 0; elm < FCOUNT; elm += 1 )
02446         {
02447             flush_points[elm] = new_flush_points[elm];
02448             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Setting new static "
02449                       "flush value of (%d bytes) at index %d\n",
02450                       flush_points[elm],elm););
02451 
02452         }
02453         LogMessage("WARNING %s(%d) => flush_behavior set in "
02454                    "config file, using new static flushpoints (%d)\n",
02455                    file_name, file_line, s4data.flush_behavior);
02456 
02457     }
02458     else if ( s4data.flush_behavior == FLUSH_BEHAVIOR_RANDOM )
02459     {
02460         /* set up random flush points */
02461         int elm;
02462         int rfp;
02463         srand(s4data.flush_seed);
02464         for( elm = 0; elm < FCOUNT; elm += 1 )
02465         {
02466             rfp = rand() % s4data.flush_range;
02467             flush_points[elm] = rfp + s4data.flush_base;
02468             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Setting random "
02469                     "flush value of (%d bytes) at index %d\n",
02470                     flush_points[elm],elm););
02471         }
02472     }
02473     else
02474     {
02475         /* Use the old flushpoints -- default behavior */
02476         int elm;
02477         for( elm = 0; elm < FCOUNT; elm += 1 )
02478         {
02479             flush_points[elm] = old_flush_points[elm];
02480             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Setting old static "
02481                        "flush value of %d bytes) at index %d\n",
02482                        flush_points[elm],elm););
02483         }
02484         LogMessage("WARNING %s(%d) => flush_behavior set in "
02485                    "config file, using old static flushpoints (%d)\n",
02486                    file_name, file_line, s4data.flush_behavior);
02487     }
02488 
02489 
02490     /* load the state table */
02491     if(s4data.store_state_to_disk == 1)
02492     {
02493         struct timeval t;
02494         memset(&t, 0, sizeof(struct timeval));
02495         gettimeofday(&t, NULL);
02496 
02497         LoadStateTable(t.tv_sec,s4data.state_file);
02498     }
02499 
02500 
02501     LogMessage("Stream4_reassemble config:\n");
02502     LogMessage("    Server reassembly: %s\n", 
02503                s4data.reassemble_server ? "ACTIVE": "INACTIVE");
02504     LogMessage("    Client reassembly: %s\n", 
02505                s4data.reassemble_client ? "ACTIVE": "INACTIVE");
02506     LogMessage("    Reassembler alerts: %s\n", 
02507                s4data.reassembly_alerts ? "ACTIVE": "INACTIVE");
02508     LogMessage("    Zero out flushed packets: %s\n", 
02509                s4data.zero_flushed_packets ? "ACTIVE": "INACTIVE");
02510     LogMessage("    Flush stream on alert: %s\n", 
02511                s4data.flush_on_alert ? "ACTIVE": "INACTIVE");
02512     LogMessage("    flush_data_diff_size: %d\n", 
02513                s4data.flush_data_diff_size);
02514     LogMessage("    Reassembler Packet Preferance : %s\n", 
02515                s4data.reassy_method == METHOD_FAVOR_NEW ?
02516                "Favor New" : "Favor Old");
02517     LogMessage("    Packet Sequence Overlap Limit: %d\n", 
02518                s4data.overlap_limit);
02519     LogMessage("    Flush behavior: %s\n", 
02520                s4data.flush_behavior == FLUSH_BEHAVIOR_DEFAULT ? "Small (<255 bytes)":
02521                 (s4data.flush_behavior == FLUSH_BEHAVIOR_LARGE ? "Large (<2550 bytes)" :
02522                 "random"));
02523     if (s4data.flush_behavior == FLUSH_BEHAVIOR_RANDOM)
02524     {
02525         LogMessage("    Flush base: %d\n", s4data.flush_base);
02526         LogMessage("    Flush seed: %d\n", s4data.flush_seed);
02527         LogMessage("    Flush range: %d\n", s4data.flush_range);
02528     }
02529 
02530     memset(buf, 0, STD_BUF+1);
02531     snprintf(buf, STD_BUF, "    Ports: ");       
02532 
02533     for(i=0;i<65536;i++)
02534     {
02535         if(s4data.assemble_ports[i])
02536         {
02537             sfsnprintfappend(buf, STD_BUF, "%d ", i);
02538             j++;
02539         }
02540 
02541         if(j > 20)
02542         { 
02543             LogMessage("%s...\n", buf);
02544             return;
02545         }
02546     }
02547 
02548     LogMessage("%s\n", buf);
02549     memset(buf, 0, STD_BUF+1);
02550     snprintf(buf, STD_BUF, "    Emergency Ports: "); 
02551     j=0;
02552 
02553     for(i=0;i<65536;i++)
02554     {
02555         if(s4data.emergency_ports[i])
02556         {
02557             sfsnprintfappend(buf, STD_BUF, "%d ", i);
02558             j++;
02559         }
02560 
02561         if(j > 20)
02562         { 
02563             LogMessage("%s...\n", buf);
02564             return;
02565         }
02566     }
02567 
02568     LogMessage("%s\n", buf);
02569 
02570     return;
02571 }
02572 
02573 /** 
02574  * Set that this side of the session has sent a fin.
02575  *
02576  * This overloads the next_seq variable to also be used to tell how
02577  * far forward we can acknowledge data.
02578  * 
02579  * @param p packet to grab the session from
02580  * @param s stream to set the next_seq on 
02581  * 
02582  * @return 0 if everything went ok
02583  */
02584 static INLINE int SetFinSent(Packet *p, Session *ssn, int direction)
02585 {
02586     Stream *stream;
02587 
02588     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "SetFinSet() called for %s\n",
02589                             direction ? "FROM_CLIENT":"FROM_SERVER"););
02590 
02591     if(direction == FROM_SERVER)
02592     {
02593         stream = &ssn->server;
02594         ssn->session_flags |= SSNFLAG_SERVER_FIN;
02595     }
02596     else
02597     {
02598         stream = &ssn->client;
02599         ssn->session_flags |= SSNFLAG_CLIENT_FIN;
02600     }
02601     
02602     stream->next_seq = ntohl(p->tcph->th_seq);
02603 
02604     return 0;
02605 }
02606 
02607 /** 
02608  * See if we can get ignore this packet
02609  *
02610  * The Emergency Status stuff is taken care of here.
02611  * 
02612  * @param p Packet
02613  * 
02614  * @return 1 if this packet isn't destined to be processeed, 0 otherwise
02615  */
02616 static INLINE int NotForStream4(Packet *p)
02617 {
02618     if(!(p->preprocessors & PP_STREAM4))
02619     {
02620         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
02621                     "p->preprocessors does not have STREAM4\n"););
02622         return 1;
02623     }
02624 
02625     if(p->tcph == NULL)
02626     {
02627         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "p->tcph is null, returning\n"););
02628         return 1;
02629     }
02630     
02631     if(p->packet_flags & PKT_REBUILT_STREAM)
02632     {
02633         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "REBUILT_STREAM returning\n"););
02634         return 1;
02635     }
02636 
02637     if(s4_emergency.status != OPS_NORMAL)
02638     {
02639         /* Check to see if we should return to our non-emergency mode.
02640          * If we happen to stay in SUSPSEND mode, exit out
02641          */
02642 
02643         if(p->pkth->ts.tv_sec >= s4_emergency.end_time)
02644         {
02645             s4_emergency.status = OPS_NORMAL;
02646             s4_emergency.end_time = 0;
02647             s4_emergency.new_session_count = 0;
02648             s4data.reassembly_alerts = s4_emergency.old_reassembly_alerts;
02649             s4data.reassemble_client = s4_emergency.old_reassemble_client; 
02650             s4data.reassemble_server = s4_emergency.old_reassemble_server;
02651             pv.assurance_mode = s4_emergency.old_assurance_mode;
02652             pv.stateful = s4_emergency.old_stateful_mode;
02653         }
02654 
02655         if(s4_emergency.status == OPS_SUSPEND)
02656         {
02657             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "OPS_SUSPEND returning\n"););
02658             return 1;
02659         }
02660     }
02661     
02662     /* don't accept packets w/ bad checksums */
02663     if(p->csum_flags & CSE_IP || p->csum_flags & CSE_TCP)
02664     {
02665         DEBUG_WRAP(
02666                    u_int8_t c1 = (p->csum_flags & CSE_IP);
02667                    u_int8_t c2 = (p->csum_flags & CSE_TCP);
02668                    DebugMessage(DEBUG_STREAM, "IP CHKSUM: %d, CSE_TCP: %d",
02669                                 c1,c2);
02670                    DebugMessage(DEBUG_STREAM, "Bad checksum returning\n");
02671                    );
02672         
02673         p->packet_flags |= PKT_STREAM_UNEST_UNI;
02674         return 1;
02675     }
02676 
02677     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Packet is for stream4...\n"););
02678     return 0;
02679 }
02680 
02681 
02682 /** 
02683  * Subtract from the byte counters for the stream session
02684  * 
02685  * @param stream Stream to adjust the byte counters on
02686  * @param sub amount to subtract from the byte_counters
02687  */
02688 static INLINE void StreamSegmentSub(Stream *stream, u_int16_t sub)
02689 {
02690     /* don't allow us to overflow */
02691 #ifdef _DEBUG_SEGMENTS
02692     DebugMessage(DEBUG_STREAM, "[sss] %u -> %u (mem: %u)\n,",
02693             stream->bytes_tracked,
02694             stream->bytes_tracked - sub,
02695             stream4_memory_usage);
02696 #endif /* DEBUG_SEGMENTS */
02697 
02698     if((stream->bytes_tracked - sub) > stream->bytes_tracked)
02699     {
02700         stream->bytes_tracked = 0;
02701     }
02702     else
02703     {
02704         stream->bytes_tracked -= sub;
02705     }
02706 
02707 }
02708 
02709 
02710 /** 
02711  * Add to the byte counters for the stream session
02712  * 
02713  * @param stream Stream to adjust the byte counters on
02714  * @param add amount to add to the byte_counters
02715  */
02716 static INLINE void StreamSegmentAdd(Stream *stream, u_int16_t add)
02717 {
02718     /* don't allow us to overflow */
02719 #ifdef _DEBUG_SEGMENTS
02720     DebugMessage(DEBUG_STREAM, "[ssa] %u -> %u (mem: %u)\n,",
02721             stream->bytes_tracked,
02722             stream->bytes_tracked + add,
02723             stream4_memory_usage);
02724 #endif /* _DEBUG_SEGMENTS */
02725 
02726     /* don't allow us to overflow */
02727     if((stream->bytes_tracked + add) < stream->bytes_tracked)
02728     {
02729         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"[E] How'd we get this high?\n"););
02730         return;
02731     }
02732     else
02733     {
02734         stream->bytes_tracked += add;
02735         stream->bytes_sent += add;
02736         stream->pkts_sent++;
02737     }
02738 
02739 }
02740 
02741 
02742 
02743 /** 
02744  * Make sure that we do not log
02745  * 
02746  * @param p Packet to evaluate
02747  * @param stream Stream to compare against
02748  * 
02749  * @return 1 if we are within established limits, 0 otherwise.
02750  */
02751 static INLINE int WithinSessionLimits(Packet *p, Stream *stream)
02752 {
02753     u_int32_t limit; 
02754 
02755     return 1;
02756     /* use a different limit if the session was picked up midstream
02757      * rather than having a full 3whs */
02758 
02759     if(((Session *)(p->ssnptr))->session_flags & SSNFLAG_MIDSTREAM)
02760     {
02761         limit = 5000;
02762     }
02763     else
02764     {
02765         limit = (MAX_STREAM_SIZE + 5000);
02766     }
02767 
02768     if((stream->bytes_tracked + p->dsize) >= limit)
02769     {
02770         /* Go ahead and remove these statistics since we're not going to
02771          * store the packet
02772          */
02773         StreamSegmentSub(stream, p->dsize);
02774         return 0;
02775     }
02776 
02777     return 1;
02778 }
02779 
02780 /**
02781  * Prune The state machine if we need to
02782  *
02783  * Also updates all variables related to pruning that only have to
02784  * happen at initialization
02785  *
02786  * For want of packet time at plugin initialization. (It only happens once.)
02787  * It wood be nice to get the first packet and do a little extra before
02788  * getting into the main snort processing loop.
02789  *   -- cpw
02790  * 
02791  * @param p Packet ptr
02792  */
02793 static INLINE void PruneCheck(Packet *p)
02794 {
02795 
02796     if (!s4data.last_prune_time)
02797     {
02798         s4data.last_prune_time = p->pkth->ts.tv_sec;
02799         return;
02800     }
02801 
02802     if( (u_int)(p->pkth->ts.tv_sec) > s4data.last_prune_time + s4data.timeout)
02803     {
02804         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Prune time quanta exceeded, pruning "
02805                     "stream cache\n"););
02806 
02807         sfPerf.sfBase.iStreamTimeouts++;
02808 
02809         PruneSessionCache(p->pkth->ts.tv_sec, 0, NULL);
02810         s4data.last_prune_time = p->pkth->ts.tv_sec;
02811 
02812         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Pruned for timeouts, %lu sessions "
02813                     "active, %lu bytes " "in use\n", 
02814                     (unsigned long int) GetSessionCount(), stream4_memory_usage);
02815                 DebugMessage(DEBUG_STREAM, "Stream4 memory cap hit %lu times\n", 
02816                     safe_alloc_faults););
02817     }
02818 
02819 }
02820 
02821 /*
02822  * Function: PreprocFunction(Packet *)
02823  *
02824  * Purpose: Perform the preprocessor's intended function.  This can be
02825  *          simple (statistics collection) or complex (IP defragmentation)
02826  *          as you like.  Try not to destroy the performance of the whole
02827  *          system by trying to do too much....
02828  *
02829  * Arguments: p => pointer to the current packet data struct 
02830  *
02831  * Returns: void function
02832  */
02833 void ReassembleStream4(Packet *p, void *context)
02834 {
02835     Session *ssn = NULL;
02836     int action;
02837     int reassemble = 0;
02838     u_int32_t pkt_seq;
02839     u_int32_t pkt_ack;
02840     int direction;
02841     static int alert_once_emerg   = 0;
02842     static int alert_once_suspend = 0;
02843 #ifdef GIDS
02844 //    u_int32_t base_adjust = 0;
02845     Stream *s;
02846     int stream_size = 0;
02847     opdsize = 0;
02848 #endif /* GIDS */
02849 #ifdef DEBUG
02850     static int pcount = 0;
02851     char flagbuf[9];
02852 
02853     pcount++;
02854 
02855     DebugMessage(DEBUG_STREAM, "pcount stream packet %d\n",pcount);
02856 #endif
02857 
02858     if(NotForStream4(p))
02859         return;
02860 
02861     pc.tcp_stream_pkts++;
02862 
02863     reassemble = CheckPorts(p->sp, p->dp);
02864 
02865     /* if we're not doing stateful inspection... */
02866     if(s4data.stateful_inspection_flag == 0 && !reassemble)
02867     {
02868         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
02869                     "No stateful inspection on this port, returning"););
02870         return;
02871     }
02872 
02873     DEBUG_WRAP(
02874             CreateTCPFlagString(p, flagbuf);
02875             DebugMessage((DEBUG_STREAM|DEBUG_STREAM_STATE), 
02876                 "Got Packet 0x%X:%d(%d) ->  0x%X:%d(%d) %s\nseq: 0x%X   ack:0x%X\n",
02877                 p->iph->ip_src.s_addr,
02878                 p->sp, p->tcph->th_sport,
02879                 p->iph->ip_dst.s_addr,
02880                 p->dp, p->tcph->th_dport,
02881                 flagbuf,
02882                 ntohl(p->tcph->th_seq), ntohl(p->tcph->th_ack));
02883             );
02884 
02885     pkt_seq = ntohl(p->tcph->th_seq);
02886     pkt_ack = ntohl(p->tcph->th_ack);
02887 
02888     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"pkt_seq: %u, pkt_ack: %u\n", 
02889                 pkt_seq, pkt_ack););
02890 
02891     /* see if we have a stream for this packet */
02892     ssn = GetSession(p);
02893     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"ssn == %p\n", ssn);
02894                DumpStateTable(NULL););
02895     
02896     /*
02897     **  Let's leave this out for now until we figure out if we're going
02898     **  to make the rule language handle this type of policy (a.k.a
02899     **  not_established).
02900     */
02901     if(!ssn && s4data.enforce_state)
02902     {
02903         /*
02904         **  We treat IDS and IPS mode differently, because in IDS mode
02905         **  we are just monitoring so we pick up all legitimate traffic
02906         **  connections, which in this case (thanks to linux) is any
02907         **  flag combination (except RST) is valid as an initiator as
02908         **  long as the SYN flag is included.
02909         **
02910         **  In InlineMode, we WILL enforce the correct flag combinations
02911         **  or else we'll drop it.
02912         */
02913         if(!InlineMode())
02914         {
02915             if((p->tcph->th_flags & (TH_SYN|TH_RST)) != TH_SYN)
02916             {
02917                 do_detect = 0;
02918                 p->preprocessors = 0;
02919 
02920                 return;
02921             }
02922         }
02923         else
02924         {
02925             /*
02926             **  We're in inline mode
02927             */
02928             if((p->tcph->th_flags & (TH_SYN|TH_ACK|TH_PUSH|TH_FIN|TH_RST)) 
02929                     != TH_SYN)
02930             {
02931                 do_detect = 0;
02932                 p->preprocessors = 0;
02933 
02934                 InlineDrop();
02935             
02936                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
02937                         "Lets drop this its not a synner\n"););
02938 
02939                 return;
02940             }
02941         }
02942     }
02943 
02944     if(ssn == NULL)
02945     {
02946         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Calling CreateNewSession()\n"););
02947 
02948         p->packet_flags |= PKT_FROM_CLIENT;
02949 
02950         /*
02951          * If we are in "emergency mode", we become much more picky
02952          * about what we will accept as a session initiator.  Since
02953          * our goal is to regain 0 packet loss, we move to only accept
02954          * new sessions that begin with a SYN flag.  Note that we do
02955          * ignore the reserved bits on a session initiator as required
02956          * by ECN. --cmg
02957          */
02958         if((s4_emergency.status == OPS_NORMAL) ||
02959                 ((p->tcph->th_flags & TH_NORESERVED) == TH_SYN))
02960         {
02961             ssn = CreateNewSession(p, pkt_seq, pkt_ack);
02962 
02963             if(ssn != NULL && ((p->tcph->th_flags & TH_NORESERVED) != TH_SYN))
02964             {
02965                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
02966                             "Picking up session midstream\n"););
02967 
02968                 ssn->session_flags |= SSNFLAG_MIDSTREAM;
02969             }
02970 
02971 
02972             /* 
02973              * keep track of how many sessions per second we're creating 
02974              * vs. the number of data packets per second we get on 
02975              * those sessions
02976              */
02977             if(s4data.state_protection)
02978                 ++s4_emergency.new_session_count;
02979 
02980             /* perfstats */
02981             if(ssn != NULL)
02982             {
02983                 AddStreamSession(&sfPerf.sfBase);
02984             }
02985         } 
02986         else 
02987         {
02988             ssn = NULL;
02989         }
02990 
02991         if(s4data.state_protection)
02992         {
02993             if(s4_emergency.new_session_count >= s4data.suspend_threshold)
02994             {
02995                 s4_emergency.status = OPS_SUSPEND;
02996                 s4_emergency.end_time = p->pkth->ts.tv_sec + s4data.suspend_period;            
02997                 pv.assurance_mode = ASSURE_ALL;
02998                 pv.stateful = 0;
02999 
03000                 if(alert_once_suspend == 0)
03001                 {
03002                     SnortEventqAdd(GENERATOR_SPP_STREAM4,
03003                             STREAM4_SUSPEND,
03004                             1,
03005                             0,
03006                             3,
03007                             STREAM4_SUSPEND_STR,
03008                             0);
03009 
03010                     alert_once_suspend = 1;
03011                 }
03012             }
03013             else if(s4_emergency.new_session_count >= s4data.sp_threshold)
03014             {
03015                 s4_emergency.status = OPS_SELF_PRESERVATION;
03016                 s4_emergency.end_time = p->pkth->ts.tv_sec + s4data.sp_period;
03017                 s4_emergency.old_reassembly_alerts = s4data.reassembly_alerts;
03018                 s4_emergency.old_reassemble_client = s4data.reassemble_client; 
03019                 s4_emergency.old_reassemble_server = s4data.reassemble_server;
03020                 s4_emergency.old_assurance_mode = pv.assurance_mode;
03021                 s4_emergency.old_stateful_mode = pv.stateful;
03022 
03023                 if(alert_once_emerg == 0)
03024                 {
03025                     SnortEventqAdd(GENERATOR_SPP_STREAM4,
03026                             STREAM4_EMERGENCY,
03027                             1,
03028                             0,
03029                             3,
03030                             STREAM4_EMERGENCY_STR,
03031                             0);
03032                     
03033                     alert_once_emerg = 1;
03034                 }
03035             }
03036         }
03037 
03038         p->packet_flags = PKT_STREAM_UNEST_UNI;
03039 
03040         if(ssn == NULL)
03041         {
03042             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"NULL SSN, maybe in emergency in "
03043                         "CreateNewSession, returning\n"););
03044 
03045             /*
03046              * Mark that this packet isn't worth doing IDS on.  This
03047              * is self preservation because either our system is under
03048              * session trashing attacks.  This will be the case under
03049              * super rapid tools like tcpisc that are generating
03050              * bogus TCP datagrams all the time  
03051              */
03052             if(s4_emergency.status != OPS_NORMAL)
03053             {
03054                 DisableDetect(p);
03055             }
03056 
03057             return;
03058         }           
03059     }    
03060     else
03061     {
03062         if(p->dsize != 0 && s4_emergency.status == OPS_NORMAL)
03063             s4_emergency.new_session_count = 0;
03064     }
03065 
03066 
03067     p->ssnptr = ssn;
03068 
03069     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
03070                 "[i] Tracked Bytes: (client: %d, server: %d)\n",
03071                 ssn->client.bytes_tracked,
03072                 ssn->server.bytes_tracked););
03073 
03074     /* update the stream window size */
03075     if((direction = GetDirection(ssn, p)) == FROM_SERVER)
03076     {
03077         p->packet_flags |= PKT_FROM_SERVER;
03078         ssn->client.win_size = ntohs(p->tcph->th_win);
03079         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  "server packet: %s\n", flagbuf););
03080     }
03081     else
03082     {
03083         p->packet_flags |= PKT_FROM_CLIENT;
03084         ssn->server.win_size = ntohs(p->tcph->th_win);
03085         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  "client packet: %s\n", flagbuf););
03086     }
03087 
03088     if (p->dsize > 0)
03089     {
03090         if ((p->packet_flags & PKT_FROM_SERVER) &&
03091             (s4data.server_inspect_limit > 0))
03092         {
03093             /* Server packet, check if we should ignore the rest of the
03094              * server data until we see a client packet again.
03095              */
03096 
03097             /* A configurable threshold */
03098             if (ssn->server.bytes_inspected > s4data.server_inspect_limit)
03099             {
03100                 p->bytes_to_inspect = -1;
03101             }
03102             else
03103             {
03104                 if (p->dsize + ssn->server.bytes_inspected >
03105                                 s4data.server_inspect_limit)
03106                 {
03107                     /* We've already inspected some portion of the
03108                      * server stream and this packet puts us over the
03109                      * threshold.  Only inspect the difference.
03110                      */
03111                     /* Can't simply change dsize, since other preprocs,
03112                      * like change dsize based on their own configs
03113                      * (like HttpInspect FlowDepth).  We don't want
03114                      * to break that functionality.
03115                      */
03116         
03117                     p->bytes_to_inspect = s4data.server_inspect_limit -
03118                                            ssn->server.bytes_inspected;
03119                 }
03120             }
03121             ssn->server.bytes_inspected += p->dsize;
03122         }
03123         else
03124         {
03125             ssn->server.bytes_inspected = 0;
03126         }
03127     }
03128 
03129     /* update the time for this session */
03130     ssn->last_session_time = p->pkth->ts.tv_sec;
03131 
03132     /* go into the FSM to maintain stream state for this packet */    
03133     if(s4data.asynchronous_link)
03134     {
03135         action = UpdateStateAsync(ssn, p, pkt_seq);
03136     }
03137     else
03138     {
03139         action = UpdateState2(ssn, p, pkt_seq);
03140     }
03141 
03142     packet_added_to_stream = 0;
03143 
03144     /* if this packet has data, maybe we should store it */
03145     if(p->dsize && reassemble)
03146     {
03147 #ifdef GIDS
03148         if(!s4data.stream4inline_mode)
03149         {
03150 #endif /* GIDS */
03151 
03152             StoreStreamPkt(ssn, p, pkt_seq);
03153 #ifdef GIDS
03154         }
03155         else
03156         {
03157             /* get the sessions for the server and the client */
03158             if(direction == FROM_SERVER)
03159                 s = &ssn->server;
03160             else
03161                 s = &ssn->client;
03162 
03163             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"P: %5d -> %5d %s: ", p->sp, p->dp, flagbuf););
03164             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Going to try to store packet size %d, count: %lu...\n", p->dsize, ubi_trCount(&s->data)););
03165 
03166             /*  now really try to store...
03167              *
03168              *  if the function returns 0 we have to remove the p->dsize of the stream
03169              *  note that if the function returns 1 it doesn't nessisarily mean the
03170              *  storing was successfull, it can also have failed. The difference is that
03171              *  when it returns 1 the stream_size is already adjusted by StoreStreamPkt.
03172              */
03173             if(!(StoreStreamPkt(ssn, p, pkt_seq)))
03174             {
03175                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"P: %5d -> %5d %s: ", p->sp, p->dp, flagbuf););
03176                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"WARNING: the storing failed: count: %lu, s->bytes_tracked: %u, going to sub...\n", ubi_trCount(&s->data), s->bytes_tracked););
03177 
03178                 /* Since we're not storing the packet on this session, let's
03179                  * decrement the bytes tracked */
03180                 if(direction == FROM_SERVER)
03181                     StreamSegmentSub(&ssn->server, p->dsize);
03182                 else
03183                     StreamSegmentSub(&ssn->client, p->dsize);
03184 
03185                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"P: %5d -> %5d %s: ", p->sp, p->dp, flagbuf););
03186                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"WARNING: the storing failed: after sub: s->bytes_tracked: %u...\n", s->bytes_tracked););
03187             }
03188         }
03189 #endif /* GIDS */
03190     }
03191     else
03192     {
03193         /* Since we're not storing the packet on this session, let's
03194          * decrement the bytes tracked */
03195         if(direction == FROM_SERVER)
03196             StreamSegmentSub(&ssn->server, p->dsize);        
03197         else
03198             StreamSegmentSub(&ssn->client, p->dsize);
03199     }
03200 
03201     if ((s4data.overlap_limit > 0) &&
03202         (ssn->client.overlap_pkts > s4data.overlap_limit))
03203     {
03204         /* We reached the overlap limit.  Kill the session */
03205         /* But flush it first */
03206         action |= ACTION_FLUSH_CLIENT_STREAM;
03207 
03208         if(s4data.evasion_alerts)
03209         {
03210             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
03211                 STREAM4_OVERLAP_LIMIT, /* SID */
03212                 1,                      /* Rev */
03213                 0,                      /* classification */
03214                 3,                      /* priority (low) */
03215                 STREAM4_OVERLAP_LIMIT_STR, /* msg string */
03216                 0);
03217         }
03218     }
03219 
03220     if ((s4data.overlap_limit > 0) &&
03221         (ssn->server.overlap_pkts > s4data.overlap_limit))
03222     {
03223         /* We reached the overlap limit.  Kill the session */
03224         /* But flush it first */
03225         action |= ACTION_FLUSH_SERVER_STREAM;
03226 
03227         if(s4data.evasion_alerts)
03228         {
03229             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
03230                 STREAM4_OVERLAP_LIMIT, /* SID */
03231                 1,                      /* Rev */
03232                 0,                      /* classification */
03233                 3,                      /* priority (low) */
03234                 STREAM4_OVERLAP_LIMIT_STR, /* msg string */
03235                 0);
03236         }
03237     }
03238 
03239     /* 
03240      * resolve actions to be taken as indicated by state transitions or
03241      * normal traffic
03242      */
03243     if(s4data.asynchronous_link)
03244     {
03245         TcpActionAsync(ssn, p, action, direction, pkt_seq, pkt_ack);
03246     }
03247     else
03248     {
03249         TcpAction(ssn, p, action, direction, pkt_seq, pkt_ack);
03250     }
03251 
03252     /*
03253      * Kludge:  Sometime's we can drop a bad session
03254      *
03255      * Only try and mark the stream as established if we still have a
03256      * valid session AFTER the stream is done
03257      *
03258      * p->ssnptr == NULL when the action indicates we should have
03259      * dropped the session
03260      */
03261     if(p->ssnptr == ssn)  /* this is not true when the session is dropped */
03262     {
03263         /* mark this packet is part of an established stream if possible */
03264         if(((s4data.asynchronous_link == 0) &&
03265            (((ssn->session_flags & (SSNFLAG_SEEN_SERVER|SSNFLAG_SEEN_CLIENT))
03266               == (SSNFLAG_SEEN_SERVER|SSNFLAG_SEEN_CLIENT)) && 
03267            (ssn->server.state >= ESTABLISHED) && 
03268            (ssn->client.state >= ESTABLISHED))) ||
03269            ((s4data.asynchronous_link == 1) &&
03270            ((((ssn->session_flags & SSNFLAG_SEEN_CLIENT)) &&
03271            (ssn->client.state >= ESTABLISHED)) ||
03272            (((ssn->session_flags & SSNFLAG_SEEN_SERVER)) &&
03273            (ssn->server.state >= ESTABLISHED)))))
03274         {
03275             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
03276                         "Stream is established!,ssnflags = 0x%x\n",
03277                         ssn->session_flags););
03278 
03279             ssn->session_flags |= SSNFLAG_ESTABLISHED;
03280         }
03281         else
03282         {
03283             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Stream is not established!\n"););
03284 
03285             if((ssn->session_flags & (SSNFLAG_SEEN_SERVER|SSNFLAG_SEEN_CLIENT))
03286                     == (SSNFLAG_SEEN_SERVER|SSNFLAG_SEEN_CLIENT)) 
03287             {
03288                 /*
03289                  * we've seen packets in this stream from both the client and 
03290                  * the server, but we haven't gotten through the three way
03291                  * handshake
03292                  */
03293                 p->packet_flags |= PKT_STREAM_UNEST_BI;
03294             }
03295             else
03296             {
03297                 /* 
03298                  * this is the first time we've seen a packet 
03299                  * from this stream
03300                  */
03301                 p->packet_flags |= PKT_STREAM_UNEST_UNI;
03302             }
03303         }
03304 
03305         if(ssn->session_flags  & SSNFLAG_ESTABLISHED)
03306         {
03307             /* we know this stream is established, lets skip the other checks
03308              * otherwise we get into clobbering our flags in the check below
03309              */
03310             p->packet_flags |= PKT_STREAM_EST;
03311 
03312             if(p->packet_flags & PKT_STREAM_UNEST_UNI)
03313             {
03314                 p->packet_flags ^= PKT_STREAM_UNEST_UNI;
03315             }
03316 
03317             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
03318                         "Marking stream as established\n"););
03319 #ifdef DEBUG
03320             if(p->packet_flags & PKT_FROM_CLIENT)
03321             {
03322                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
03323                             "pkt is from client\n"););
03324             } 
03325 
03326             if(p->packet_flags & PKT_FROM_SERVER)
03327             {
03328                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
03329                             "pkt is from server\n"););
03330             } 
03331 #endif /*DEBUG*/
03332         }
03333     }
03334 
03335 
03336     PrintSessionCache();
03337 
03338     /* see if we need to prune the session cache */
03339     PruneCheck(p);
03340 
03341 #ifdef GIDS
03342     /* stream4inline part starts here, so bail out when not in inline mode */
03343     if(!s4data.stream4inline_mode)
03344         return;
03345 
03346     /* an empty packet means that the reassembled stream wont be
03347      * changed.
03348      */
03349     if(p->dsize == 0)
03350         return;
03351 
03352     if(packet_added_to_stream == 0)
03353     {
03354         //printf("scan single packet\n");
03355         return;
03356     }
03357     //printf("scan ressembled stream\n");
03358 
03359     /* get the sessions for the server and the client */
03360     if(direction == FROM_SERVER)
03361         s = &ssn->server;
03362     else
03363         s = &ssn->client;
03364 
03365     /* set stream_size */
03366     stream_size = s->bytes_tracked;
03367 
03368     /* safety net: sometimes (i noticed it when scp-ing between two linux boxes)
03369      * the stream gets real big without truncating in time... here we check that.
03370      */
03371     if(stream_size > (s4data.stream4inline_window_size * 2) || stream_size > MAX_STREAM_SIZE)
03372     {
03373         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Truncating stream that is out of control...(stream_size %d (max %d or %d)).\n",
03374                                                 stream_size, s4data.stream4inline_window_size * 2, MAX_STREAM_SIZE););
03375         TruncStream(s, p);
03376 
03377         /* set stream_size */
03378         stream_size = s->bytes_tracked;
03379     }
03380 
03381     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"P: %5d -> %5d %s:\n", p->sp, p->dp, flagbuf););
03382     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"p->dsize: %5d, seq_num: %u stream_size: %d (pkts %u, bytes %u, btracked: %u), stream_size_last_ack: %d, count: %lu\n", p->dsize, p->tcph->th_seq, stream_size, s->pkts_sent, s->bytes_sent, s->bytes_tracked, s->last_ack - s->base_seq + p->dsize, ubi_trCount(&s->data)););
03383 
03384 
03385     /* build the reassembled stream */
03386     if(stream_size > 0 && ubi_trCount(&s->data))
03387     {
03388         /* fix direction on NO_REVERSE since i have no idea what it does */
03389         direction = NO_REVERSE;
03390 
03391         /* put the stream together into a packet or something */
03392         if(BuildPacket(s, stream_size, p, direction))
03393         {
03394             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"P: %5d -> %5d %s: ", p->sp, p->dp, flagbuf););
03395             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Passing large packet on 0 size stream cache (after BP)\n"););
03396         }
03397         else
03398         {
03399 
03400             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"P: %5d -> %5d %s: ", p->sp, p->dp, flagbuf););
03401             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"stream_pkt->dsize: %5d, p->dsize: %5d, stream_size: %d (pkts %u, bytes %u, btracked: %u)\n\n", stream_pkt->dsize, p->dsize, stream_size, s->pkts_sent, s->bytes_sent, s->bytes_tracked););
03402 
03403             /* set the data and dsize pointers to the stream_pkt, so we will
03404              * scan the reassembled buffer from now on. */
03405             opdsize = p->dsize;
03406             p->data  = stream_pkt->data;
03407             p->dsize = stream_pkt->dsize;
03408             p->packet_flags = stream_pkt->packet_flags;
03409             p->streamptr = stream_pkt->streamptr;
03410         }
03411     }
03412     else
03413     {
03414         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"P: %5d -> %5d %s: ", p->sp, p->dp, flagbuf););
03415         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Passing large packet on 0 size stream cache\n"););
03416     }
03417 
03418     /* debug print */
03419     //print_data(p->data, p->dsize);
03420     //printf("P: %5d -> %5d %s: ", p->sp, p->dp, flagbuf);
03421     //printf("Sessions: %3d, Memory used: %6u (avg. %5d).\n", ubi_trCount(RootPtr), stream4_memory_usage, stream4_memory_usage / ubi_trCount(RootPtr));
03422 
03423 #endif /* GIDS */
03424 
03425     return;
03426 }
03427 
03428 
03429 
03430 /**
03431  * Queues a state transition for UpdateState2
03432  * 
03433  * @param transition the state to transition to
03434  * @param sptr pointer to the stream to queue the transition for
03435  * @param expected_flags flag we need to see to accept the transition
03436  * @param seq_num sequence number of the packet initiating the transition
03437  * @param chk_seq flag to indicate if the seq number actually needs to be
03438  * checked
03439  *
03440  * @return void function
03441  */
03442 void INLINE QueueState(u_int8_t transition, Stream *sptr, 
03443         u_int8_t expected_flags, u_int32_t seq_num, u_int8_t chk_seq)
03444 {
03445     DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
03446                 "[^^] Queing transition to %s, flag 0x%X, seq: 0x%X\n", 
03447                 state_names[transition], expected_flags, seq_num););
03448 
03449     sptr->state_queue = transition;
03450     sptr->expected_flags = expected_flags;
03451     sptr->stq_chk_seq = chk_seq;
03452     sptr->trans_seq = seq_num;
03453     return;
03454 }
03455 
03456 /**
03457  * Evaluate queued state transitions for completion criteria
03458  *
03459  * @param sptr pointer to the stream to be evaluated
03460  * @param flags flags of the current packet
03461  * @param ack ack number of the current packet
03462  *
03463  * @returns 1 on successful state transition, 0 on no transition
03464  */
03465 int INLINE EvalStateQueue(Stream *sptr, u_int8_t flags, u_int32_t ack)
03466 {
03467     if(sptr->expected_flags != 0)
03468     {
03469         if((flags & sptr->expected_flags) != 0)
03470         {
03471             if(sptr->stq_chk_seq && (SEQ_GEQ(ack, sptr->trans_seq)))
03472             {
03473 
03474                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
03475                             "[^^] Accepting %s state transition\n", 
03476                             state_names[sptr->state_queue]););
03477                 sptr->state = sptr->state_queue;
03478                 sptr->expected_flags = 0;
03479                 sptr->trans_seq = 0;
03480                 return 1;
03481             }
03482             else if(!sptr->stq_chk_seq)
03483             {
03484                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
03485                             "[^^] Accepting %s state transition\n", 
03486                             state_names[sptr->state_queue]););
03487                 sptr->state = sptr->state_queue;
03488                 sptr->expected_flags = 0;
03489                 sptr->trans_seq = 0;
03490                 return 1;
03491 
03492             }
03493             else
03494             {
03495                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, 
03496                             "[!!] sptr->stq_chk_seq: %d  "
03497                             "[ack: 0x%X expected: 0x%X]\n", sptr->stq_chk_seq, 
03498                             ack, sptr->trans_seq););
03499             }
03500         }
03501         else
03502         {
03503             DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, 
03504                         "[!!] flags: 0x%X  expected: 0x%X, bitwise: 0x%X\n", 
03505                         flags, sptr->expected_flags, 
03506                         (flags&sptr->expected_flags)););
03507         }
03508     }
03509 
03510     return 0;
03511 }
03512 
03513 
03514 
03515 int UpdateState2(Session *ssn, Packet *p, u_int32_t pkt_seq)
03516 {
03517     int direction;
03518     int retcode = 0;
03519     Stream *talker = NULL;
03520     Stream *listener = NULL;
03521     DEBUG_WRAP(
03522             char *t = NULL;
03523             char *l = NULL;
03524             );
03525 
03526     direction = GetDirection(ssn, p);
03527 
03528     if(p->tcph->th_flags & TH_FIN)
03529     {
03530         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
03531                     "Marking that a fin was was sent %s\n",
03532                     (direction ? "FROM_CLIENT" : "FROM_SERVER")););
03533         SetFinSent(p, ssn, direction);
03534     }
03535 
03536     if(direction == FROM_SERVER)
03537     {
03538         ssn->session_flags |= SSNFLAG_SEEN_SERVER;
03539         talker = &ssn->server;
03540         listener = &ssn->client;
03541 
03542         DEBUG_WRAP(
03543                 t = strdup("Server");
03544                 l = strdup("Client"););
03545     }
03546     else
03547     {
03548         ssn->session_flags |= SSNFLAG_SEEN_CLIENT;
03549         talker = &ssn->client;
03550         listener = &ssn->server;
03551 
03552         DEBUG_WRAP(
03553                 t = strdup("Client");
03554                 l = strdup("Server"););
03555     }
03556 
03557     EvalStateQueue(talker, p->tcph->th_flags, ntohl(p->tcph->th_ack));
03558 
03559     if(talker->state != ESTABLISHED)
03560     {
03561         DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, 
03562                     "   %s [talker] state: %s\n", t, state_names[talker->state]););
03563     }
03564     if(listener->state != ESTABLISHED)
03565     {
03566         DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, 
03567                     "   %s state: %s\n", l, state_names[listener->state]););
03568     }
03569 
03570     StreamSegmentAdd(talker, p->dsize); 
03571 
03572     if(talker->state == ESTABLISHED)
03573     {
03574         listener->win_size = ntohs(p->tcph->th_win);
03575     }
03576 
03577     if(p->tcph->th_flags & TH_RST)
03578     {
03579         /* check to make sure the RST is in window */
03580         if(CheckRst(ssn, direction, pkt_seq, p))
03581         {
03582             int action = ACTION_FLUSH_CLIENT_STREAM | 
03583                          ACTION_FLUSH_SERVER_STREAM | 
03584                          ACTION_DROP_SESSION; 
03585             
03586             ssn->client.state = CLOSED;
03587             ssn->server.state = CLOSED;
03588 
03589             DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
03590                         "   Client Transition: CLOSED\n");
03591                     DebugMessage(DEBUG_STREAM_STATE,  
03592                         "   Server Transision: CLOSED\n");
03593                     if(l) free(l);
03594                     if(t) free(t););
03595 
03596             if ( p->tcph->th_flags & TH_ACK )
03597             {
03598                 if ( direction == FROM_SERVER )
03599                 {
03600                     action |= ACTION_ACK_CLIENT_DATA;
03601                 }
03602                 else
03603                 {
03604                     action |= ACTION_ACK_SERVER_DATA;
03605                 }
03606             }
03607 
03608             return action;
03609         }
03610     }
03611 
03612     switch(listener->state)
03613     {
03614         case LISTEN:
03615             /* only valid packet for this state is a SYN...
03616              *  or SYN + ECN crap.
03617              *
03618              * Revised: As long as it's got a SYN and not a
03619              * RST, Lets try to make the session start.  It
03620              * may just timeout -- cmg
03621              */
03622             if((p->tcph->th_flags & TH_SYN) &&
03623                     !(p->tcph->th_flags & TH_RST))
03624             {
03625                 QueueState(SYN_RCVD, listener, TH_SYN| TH_ACK, 0, NO_CHK_SEQ);
03626 
03627                 if(talker->state != SYN_SENT)
03628                 {
03629                     talker->state = SYN_SENT;
03630                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
03631                                 "   %s Transition: SYN_SENT\n", t););
03632                 }
03633             }
03634 
03635             if(p->dsize != 0)
03636                 retcode |= ACTION_DATA_ON_SYN;
03637             break;
03638 
03639         case SYN_SENT:
03640             if((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK))
03641             {
03642                 if(talker->state != SYN_RCVD)
03643                 {
03644                     talker->state = SYN_RCVD;
03645 
03646                     DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,  
03647                                 "   %s Transition: SYN_RCVD\n", t););
03648                 }
03649 
03650                 QueueState(ESTABLISHED, listener, TH_ACK, pkt_seq, CHK_SEQ);
03651 
03652                 /* ECN response */
03653                 if((p->tcph->th_flags & TH_RES2) && 
03654                         ssn->session_flags & SSNFLAG_ECN_CLIENT_QUERY)
03655                 {
03656                     ssn->session_flags |= SSNFLAG_ECN_SERVER_REPLY;
03657                 }
03658 
03659                 retcode |= ACTION_SET_SERVER_ISN;
03660             }
03661 
03662             break;
03663 
03664         case SYN_RCVD:
03665             if(p->tcph->th_flags & TH_ACK)
03666             {
03667                 listener->state = ESTABLISHED;
03668                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
03669                             "   %s Transition: ESTABLISHED\n", l););
03670                 retcode |= ACTION_COMPLETE_TWH;
03671             }
03672 
03673             break;
03674 
03675         case ESTABLISHED:
03676             if(p->tcph->th_flags & TH_ACK)
03677             {
03678                 if(direction == FROM_CLIENT)
03679                     retcode |= ACTION_ACK_SERVER_DATA;
03680                 else
03681                     retcode |= ACTION_ACK_CLIENT_DATA;
03682             }
03683 
03684             if((p->tcph->th_flags & TH_FIN) == TH_FIN)
03685             {
03686                 talker->state = FIN_WAIT_1;
03687                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
03688                             "   %s Transition: FIN_WAIT_1\n", t););
03689                 QueueState(CLOSE_WAIT, listener, TH_ACK, pkt_seq, CHK_SEQ);
03690             }
03691 
03692             break;
03693 
03694         case CLOSE_WAIT:
03695             QueueState(LAST_ACK, talker, TH_FIN, pkt_seq, NO_CHK_SEQ);
03696 
03697             if(p->tcph->th_flags == TH_ACK)
03698             {
03699                 if(direction == FROM_CLIENT)
03700                     retcode |= ACTION_ACK_SERVER_DATA;
03701                 else
03702                     retcode |= ACTION_ACK_CLIENT_DATA;
03703             }
03704 
03705             break;
03706 
03707         case LAST_ACK:
03708             if(p->tcph->th_flags & TH_ACK)
03709             {
03710                 listener->state = CLOSED;
03711                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
03712                             "   %s Transition: CLOSED\n", l););
03713 
03714                 if(talker->state == TIME_WAIT)
03715                 {
03716                     talker->state = CLOSED;
03717                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
03718                                 "   %s Transition: CLOSED\n", t););
03719                 }
03720 
03721                 retcode |= (ACTION_FLUSH_CLIENT_STREAM | 
03722                         ACTION_FLUSH_SERVER_STREAM | 
03723                         ACTION_DROP_SESSION);
03724             }
03725 
03726             break;
03727 
03728         case FIN_WAIT_1:
03729             if((p->tcph->th_flags & (TH_ACK|TH_FIN)) == (TH_ACK|TH_FIN))
03730             {
03731                 talker->state = LAST_ACK;
03732                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
03733                             "   %s Transition: LAST_ACK\n", t););
03734                 QueueState(TIME_WAIT, listener, TH_ACK, pkt_seq, CHK_SEQ);
03735 
03736                 if(direction == FROM_CLIENT)
03737                     retcode |= ACTION_ACK_SERVER_DATA;
03738                 else
03739                     retcode |= ACTION_ACK_CLIENT_DATA;
03740             }
03741             else if(p->tcph->th_flags == TH_ACK)
03742             {
03743                 QueueState(LAST_ACK, talker, TH_FIN, pkt_seq, NO_CHK_SEQ);
03744                 listener->state = FIN_WAIT_2;
03745                 DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,  
03746                             "   %s Transition: FIN_WAIT_2\n", l););
03747 
03748                 if(direction == FROM_CLIENT)
03749                     retcode |= ACTION_ACK_SERVER_DATA;
03750                 else
03751                     retcode |= ACTION_ACK_CLIENT_DATA;
03752             }
03753 
03754             break;
03755 
03756         case FIN_WAIT_2:
03757             if(p->tcph->th_flags == (TH_FIN|TH_ACK))
03758             {
03759                 talker->state = LAST_ACK;
03760                 QueueState(TIME_WAIT, listener, TH_ACK, pkt_seq, CHK_SEQ);
03761 
03762                 if(direction == FROM_CLIENT)
03763                     retcode |= ACTION_FLUSH_CLIENT_STREAM | ACTION_ACK_SERVER_DATA;
03764                 else
03765                     retcode |= ACTION_FLUSH_SERVER_STREAM | ACTION_ACK_CLIENT_DATA;
03766             }
03767             else if(p->tcph->th_flags == TH_FIN)
03768             {
03769                 talker->state = LAST_ACK;
03770                 DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE,  
03771                             "   %s Transition: LAST_ACK\n", t););
03772 
03773                 QueueState(TIME_WAIT, listener, TH_ACK, pkt_seq, CHK_SEQ);
03774 
03775                 if(direction == FROM_CLIENT)
03776                     retcode |= ACTION_FLUSH_SERVER_STREAM;
03777                 else
03778                     retcode |= ACTION_FLUSH_CLIENT_STREAM;
03779             }
03780 
03781             break;
03782 
03783         case TIME_WAIT:
03784         case CLOSED:    
03785             return ACTION_FLUSH_CLIENT_STREAM | ACTION_DROP_SESSION;    
03786     }
03787 
03788     DEBUG_WRAP(
03789             if(l) free(l);
03790             if(t) free(t););
03791 
03792     return retcode;
03793 }
03794 
03795 
03796 /* int UpdateStateAsync(Session *ssn, Packet *p, u_int32_t pkt_seq)
03797  * 
03798  * Purpose: Do the state transition table for packets based solely on
03799  * one-sided converstations
03800  *
03801  * Returns:  which ACTIONS need to be taken on this state
03802  */
03803  
03804 int UpdateStateAsync(Session *ssn, Packet *p, u_int32_t pkt_seq)
03805 {
03806     int direction;
03807 
03808     direction = GetDirection(ssn, p);
03809 
03810     switch(direction)
03811     {
03812         case FROM_SERVER:  /* packet came from the server */
03813             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03814                         "Client State: SYN_SENT\n"););
03815 
03816             StreamSegmentAdd(&ssn->server, p->dsize); 
03817 
03818             ssn->session_flags |= SSNFLAG_SEEN_SERVER;
03819 
03820             switch(ssn->server.state)
03821             {
03822                 case SYN_RCVD:
03823                     /* This is the first state the reassembler can stick in
03824                        in the Asynchronus state */
03825 
03826                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03827                                 "Server state: SYN_RCVD\n"););
03828                     if((p->tcph->th_flags & TH_NORESERVED) == (TH_SYN|TH_ACK))
03829                     {
03830                         ssn->server.state = ESTABLISHED;
03831                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03832                                     "   Server Transition: ESTABLISHED\n"););
03833                         return ACTION_COMPLETE_TWH;
03834                     }
03835                     return ACTION_NOTHING;
03836 
03837                 case ESTABLISHED:
03838                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
03839                                 "Server state: ESTABLISHED\n"););
03840                     if(p->tcph->th_flags & TH_FIN)
03841                     {
03842                         ssn->server.state = CLOSED;
03843                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03844                                     "   Client Transition: FIN_WAIT_1\n"););
03845 
03846                         return ACTION_FLUSH_SERVER_STREAM|ACTION_DROP_SESSION;
03847                     }
03848                     else if(p->tcph->th_flags & TH_RST)
03849                     {
03850                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
03851                                     "Got RST (0x%X)\n", 
03852                                     p->tcph->th_flags););
03853                         ssn->server.state = CLOSED;
03854                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03855                                     "   Server Transition: CLOSED\n"););
03856 
03857                         return ACTION_FLUSH_SERVER_STREAM | ACTION_DROP_SESSION;
03858                     }
03859 
03860                     return ACTION_NOTHING;
03861             }
03862 
03863         case FROM_CLIENT:
03864 
03865             StreamSegmentAdd(&ssn->client, p->dsize);
03866 
03867             ssn->session_flags |= SSNFLAG_SEEN_CLIENT;
03868 
03869             switch(ssn->client.state)
03870             {
03871                 case SYN_SENT:
03872                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
03873                                 "Client State: SYN_SENT\n"););
03874                     if(p->tcph->th_flags & TH_RST)
03875                     {
03876                         ssn->client.state = CLOSED;
03877 
03878                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03879                                     "   Client Transition: CLOSED -- RESET\n"););
03880 
03881                         return ACTION_FLUSH_CLIENT_STREAM | ACTION_DROP_SESSION;
03882                     }
03883                     else if(p->tcph->th_flags & TH_ACK)
03884                     {
03885                         ssn->client.state = ESTABLISHED;
03886 
03887                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03888                                     "   Client Transition: ESTABLISHED\n"););
03889 
03890                         return ACTION_NOTHING;
03891                     }
03892 
03893 
03894                     return ACTION_NOTHING;
03895 
03896 
03897                 case ESTABLISHED:
03898                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
03899                                 "Client state: ESTABLISHED\n"););
03900 
03901                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
03902                                 "Session State: ESTABLISHED\n"););
03903                     ssn->session_flags |= SSNFLAG_ESTABLISHED;
03904 
03905 
03906                     if(p->tcph->th_flags & TH_FIN)
03907                     {
03908                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
03909                                     "Got FIN (0x%X)\n", 
03910                                     p->tcph->th_flags););
03911                         ssn->client.state = CLOSED;
03912                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03913                                     "   Client Transition: CLOSEd\n"););
03914 
03915                         return ACTION_FLUSH_CLIENT_STREAM|ACTION_DROP_SESSION;
03916                     }
03917                     else if(p->tcph->th_flags & TH_RST)
03918                     {
03919                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
03920                                     "Got RST (0x%X)\n", 
03921                                     p->tcph->th_flags););
03922                         ssn->client.state = CLOSED;
03923                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  
03924                                     "   Client Transition: Closed\n"););
03925 
03926                         return ACTION_FLUSH_CLIENT_STREAM | ACTION_DROP_SESSION;
03927                     }
03928                     break;
03929             }
03930     }
03931 
03932     return ACTION_NOTHING;
03933 }
03934 
03935 
03936 
03937 Session *CreateNewSession(Packet *p, u_int32_t pkt_seq, u_int32_t pkt_ack)
03938 {
03939     Session *idx = NULL;
03940     static u_int8_t savedfpi; /* current flush point index */
03941     u_int8_t fpi;            /* flush point index */
03942 
03943 
03944     /* assign a psuedo random flush point */
03945     savedfpi++;
03946     fpi = savedfpi % FCOUNT;    
03947     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Using flush value of "
03948                 "(%d bytes) at index %d\n", flush_points[fpi],fpi););
03949     /* This would be a lot better but could be a big performance hit
03950      * since the flush point values should be fully random at this
03951      * point it should be ok.
03952     srand(savedfpi + p->pkth->ts.tv_sec);
03953     fpi = rand() % FCOUNT;
03954     */
03955 
03956     switch(p->tcph->th_flags)
03957     {
03958         case TH_RES1|TH_RES2|TH_SYN: /* possible ECN traffic */
03959             if(p->iph->ip_tos == 0x02)
03960             {
03961                 /* it is ECN traffic */
03962                 p->packet_flags |= PKT_ECN;
03963             }
03964 
03965             /* fall through */
03966 
03967         case TH_SYN:  /* setup session on first packet of TWH */
03968             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[A] initializing new session "
03969                         "(%d bytes)\n", sizeof(Session)););
03970 
03971 #ifdef USE_HASH_TABLE
03972             idx = GetNewSession(p);
03973 #else /* USE_SPLAY_TREE */
03974             idx = (Session *) SafeAlloc(sizeof(Session), p->pkth->ts.tv_sec,
03975                     NULL);
03976 #endif
03977 
03978             if(s4data.reassemble_server)
03979                 (void)ubi_trInitTree(&idx->server.data, /* ptr to the tree head */
03980                                      DataCompareFunc, /* comparison function */
03981                                      ubi_trDUPKEY);   /* allow duplicate keys */
03982             else
03983                 idx->server.data.root = NULL;
03984 
03985             if(s4data.reassemble_client)
03986                 (void)ubi_trInitTree(&idx->client.data, /* ptr to the tree head */
03987                                      DataCompareFunc, /* comparison function */
03988                                      ubi_trDUPKEY);   /* allow duplicate keys */
03989             else
03990                 idx->client.data.root = NULL;
03991 
03992             idx->server.state = LISTEN;        
03993             idx->server.ip = p->iph->ip_dst.s_addr;
03994             idx->server.port = p->dp;
03995 
03996             idx->client.state = SYN_SENT;
03997             idx->client.ip = p->iph->ip_src.s_addr;
03998             idx->client.port = p->sp;
03999             idx->client.isn = pkt_seq;
04000             idx->server.win_size = ntohs(p->tcph->th_win);
04001 
04002             idx->start_time = p->pkth->ts.tv_sec;
04003             idx->last_session_time = p->pkth->ts.tv_sec;
04004 
04005             idx->session_flags |= SSNFLAG_SEEN_CLIENT;
04006 
04007             if(p->packet_flags & PKT_ECN)
04008             {
04009                 idx->session_flags |= SSNFLAG_ECN_CLIENT_QUERY;
04010             }
04011 
04012             idx->flush_point = flush_points[fpi];
04013             break;
04014 
04015         case TH_RES2|TH_SYN|TH_ACK:
04016             if(p->iph->ip_tos == 0x02)
04017             {
04018                 p->packet_flags |= PKT_ECN;
04019             }
04020             else
04021             {
04022                 if(s4data.ps_alerts)
04023                 {
04024                     SnortEventqAdd(GENERATOR_SPP_STREAM4,
04025                             STREAM4_STEALTH_ACTIVITY,
04026                             1,
04027                             0,
04028                             3,
04029                             STREAM4_STEALTH_ACTIVITY_STR,
04030                             0);
04031 
04032                     break;
04033                 }
04034 
04035                 return NULL;
04036             }
04037 
04038             /* fall through */
04039 
04040         case TH_SYN|TH_ACK: /* maybe we missed the SYN packet... */
04041             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[A] initializing new session "
04042                         "(%d bytes)\n", sizeof(Session)););
04043 
04044 #ifdef USE_HASH_TABLE
04045             idx = GetNewSession(p);
04046 #else /* USE_SPLAY_TREE */
04047             idx = (Session *) SafeAlloc(sizeof(Session), p->pkth->ts.tv_sec, 
04048                     NULL);
04049 #endif
04050 
04051             if(s4data.reassemble_server)
04052                 (void)ubi_trInitTree(&idx->server.data, /* ptr to the tree head */
04053                                      DataCompareFunc, /* comparison function */
04054                                      ubi_trDUPKEY);   /* allow duplicate keys */
04055             else
04056                 idx->server.data.root = NULL;
04057 
04058             if(s4data.reassemble_client)
04059                 (void)ubi_trInitTree(&idx->client.data, /* ptr to the tree head */
04060                                      DataCompareFunc, /* comparison function */
04061                                      ubi_trDUPKEY);   /* allow duplicate keys */
04062             else
04063                 idx->client.data.root = NULL;
04064 
04065             idx->server.state = SYN_RCVD;
04066             idx->client.state = SYN_SENT;
04067 
04068             idx->server.ip = p->iph->ip_src.s_addr;
04069             idx->server.port = p->sp;
04070             idx->server.isn = pkt_seq;
04071             idx->client.win_size = ntohs(p->tcph->th_win);
04072 
04073             idx->client.ip = p->iph->ip_dst.s_addr;
04074             idx->client.port = p->dp;
04075             idx->client.isn = pkt_ack-1;
04076 
04077             idx->start_time = p->pkth->ts.tv_sec;
04078             idx->last_session_time = p->pkth->ts.tv_sec;
04079             idx->session_flags = SSNFLAG_SEEN_SERVER;
04080             idx->flush_point = flush_points[fpi];
04081             break;
04082 
04083         case TH_ACK: 
04084         case TH_ACK|TH_PUSH: 
04085         case TH_FIN|TH_ACK:
04086         case TH_ACK|TH_URG:
04087         case TH_ACK|TH_PUSH|TH_URG:
04088         case TH_FIN|TH_ACK|TH_URG:
04089         case TH_ACK|TH_PUSH|TH_FIN:
04090         case TH_ACK|TH_PUSH|TH_FIN|TH_URG:
04091             /* 
04092              * missed the TWH or just got the last packet of the 
04093              * TWH, or we're catching this session in the middle
04094              */
04095 
04096             /* 
04097              * this traffic could also be bogus SmartBits bullshit, in which case
04098              * the person testing this NIDS with the smartbits should be flogged
04099              * to death with a limp noodle
04100              */
04101             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[A] initializing new session "
04102                         "(%d bytes)\n", sizeof(Session)););
04103 
04104 #ifdef USE_HASH_TABLE
04105             idx = GetNewSession(p);
04106 #else /* USE_SPLAY_TREE */
04107             idx = (Session *) SafeAlloc(sizeof(Session), p->pkth->ts.tv_sec,
04108                     NULL);
04109 #endif
04110 
04111             if(s4data.reassemble_server)
04112                 (void)ubi_trInitTree(&idx->server.data, /* ptr to the tree head */
04113                                      DataCompareFunc, /* comparison function */
04114                                      ubi_trDUPKEY);   /* allow duplicate keys */
04115             else
04116                 idx->server.data.root = NULL;
04117 
04118             if(s4data.reassemble_client)
04119                 (void)ubi_trInitTree(&idx->client.data, /* ptr to the tree head */
04120                                      DataCompareFunc, /* comparison function */
04121                                      ubi_trDUPKEY);   /* allow duplicate keys */
04122             else
04123                 idx->client.data.root = NULL;
04124 
04125             idx->server.state = ESTABLISHED;
04126             idx->client.state = ESTABLISHED;
04127 
04128             if ( p->dp <= p->sp )  /* guess this is a client packet */
04129             {
04130                 idx->server.ip = p->iph->ip_dst.s_addr;
04131                 idx->server.port = p->dp;
04132                 idx->server.isn = pkt_ack-1;
04133                 idx->server.last_ack = pkt_ack;
04134                 idx->server.base_seq = idx->server.last_ack;
04135                 idx->server.win_size = ntohs(p->tcph->th_win);
04136 
04137                 idx->client.ip = p->iph->ip_src.s_addr;
04138                 idx->client.port = p->sp;
04139                 idx->client.isn = pkt_seq-1;
04140                 idx->client.last_ack = pkt_seq;
04141                 idx->client.base_seq = idx->client.last_ack;
04142                 idx->session_flags = SSNFLAG_SEEN_CLIENT;
04143             }
04144             else  /*  sp > dp, guess this is a server packet */
04145             {
04146                 idx->client.ip = p->iph->ip_dst.s_addr;
04147                 idx->client.port = p->dp;
04148                 idx->client.isn = pkt_ack-1;
04149                 idx->client.last_ack = pkt_ack;
04150                 idx->client.base_seq = idx->client.last_ack;
04151                 idx->client.win_size = ntohs(p->tcph->th_win);
04152 
04153                 idx->server.ip = p->iph->ip_src.s_addr;
04154                 idx->server.port = p->sp;
04155                 idx->server.isn = pkt_seq-1;
04156                 idx->server.last_ack = pkt_seq;
04157                 idx->server.base_seq = idx->server.last_ack;
04158                 idx->session_flags = SSNFLAG_SEEN_SERVER;
04159             }
04160             idx->start_time = p->pkth->ts.tv_sec;
04161             idx->last_session_time = p->pkth->ts.tv_sec;
04162             idx->flush_point = flush_points[fpi];
04163             break;
04164 
04165         case TH_RES2|TH_SYN: /* nmap fingerprint packet */
04166             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[A] initializing new session "
04167                         "(%d bytes)\n", sizeof(Session));
04168                     DebugMessage(DEBUG_STREAM,
04169                         "nmap fingerprint scan 2SYN packet!\n"););
04170 #ifdef USE_HASH_TABLE
04171             idx = GetNewSession(p);
04172 #else /* USE_SPLAY_TREE */
04173             idx = (Session *) SafeAlloc(sizeof(Session), p->pkth->ts.tv_sec, NULL);
04174 #endif
04175 
04176             if(s4data.reassemble_server)
04177                 (void)ubi_trInitTree(&idx->server.data, /* ptr to the tree head */
04178                                      DataCompareFunc, /* comparison function */
04179                                      ubi_trDUPKEY);   /* allow duplicate keys */
04180             else
04181                 idx->server.data.root = NULL;
04182 
04183             if(s4data.reassemble_client)
04184                 (void)ubi_trInitTree(&idx->client.data, /* ptr to the tree head */
04185                                      DataCompareFunc, /* comparison function */
04186                                      ubi_trDUPKEY);   /* allow duplicate keys */
04187             else
04188                 idx->client.data.root = NULL;
04189 
04190             idx->server.state = NMAP_FINGERPRINT_2S;
04191             idx->client.state = NMAP_FINGERPRINT_2S;
04192 
04193             idx->server.ip = p->iph->ip_dst.s_addr;
04194             idx->server.port = p->dp;
04195 
04196             idx->client.ip = p->iph->ip_src.s_addr;
04197             idx->client.port = p->sp; /* cp incs by one for each packet */
04198             idx->client.port++;
04199             idx->client.isn = pkt_seq;
04200             idx->server.win_size = ntohs(p->tcph->th_win);
04201 
04202             idx->start_time = p->pkth->ts.tv_sec;
04203             idx->last_session_time = p->pkth->ts.tv_sec;
04204 
04205             idx->session_flags = SSNFLAG_SEEN_CLIENT|SSNFLAG_NMAP;
04206             idx->flush_point = flush_points[fpi];
04207 
04208             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"init nmap for sip: 0x%X sp: %d  "
04209                         "cip: 0x%X cp: %d\n", 
04210                         idx->server.ip, idx->server.port, 
04211                         idx->client.ip, idx->client.port););
04212 
04213             break;
04214         case TH_SYN|TH_RST|TH_ACK|TH_FIN|TH_PUSH|TH_URG:
04215             if(s4data.ps_alerts)
04216             {
04217                 /* Full XMAS scan */
04218                 SnortEventqAdd(GENERATOR_SPP_STREAM4,
04219                         STREAM4_STEALTH_FULL_XMAS,
04220                         1,
04221                         0,
04222                         3,
04223                         STREAM4_STEALTH_FULL_XMAS_STR,
04224                         0);
04225             }
04226 
04227             break;
04228 
04229         case TH_SYN|TH_ACK|TH_URG|TH_PUSH:
04230             if(s4data.ps_alerts)
04231             {
04232                 SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04233                         STREAM4_STEALTH_SAPU, /* SID */
04234                         1,                      /* Rev */
04235                         0,                      /* classification */
04236                         3,                      /* priority (low) */
04237                         STREAM4_STEALTH_SAPU_STR, /* msg string */
04238                         0);
04239             }
04240 
04241             break;
04242 
04243         case TH_FIN:
04244             if(s4data.ps_alerts)
04245             {
04246                 SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04247                         STREAM4_STEALTH_FIN_SCAN, /* SID */
04248                         1,                      /* Rev */
04249                         0,                      /* classification */
04250                         3,                      /* priority (low) */
04251                         STREAM4_STEALTH_FIN_SCAN_STR, /* msg string */
04252                         0);
04253             }
04254 
04255             break;
04256 
04257         case TH_SYN|TH_FIN:
04258             if(s4data.ps_alerts)
04259             {
04260                 SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04261                         STREAM4_STEALTH_SYN_FIN_SCAN, /* SID */
04262                         1,                      /* Rev */
04263                         0,                      /* classification */
04264                         3,                      /* priority (low) */
04265                         STREAM4_STEALTH_SYN_FIN_SCAN_STR, /* msg string */
04266                         0);
04267             }
04268 
04269             break;
04270 
04271         case 0:
04272             if(s4data.ps_alerts)
04273             {
04274                 SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04275                         STREAM4_STEALTH_NULL_SCAN, /* SID */
04276                         1,                      /* Rev */
04277                         0,                      /* classification */
04278                         3,                      /* priority (low) */
04279                         STREAM4_STEALTH_NULL_SCAN_STR, /* msg string */
04280                         0);
04281             }
04282 
04283             break;
04284 
04285         case TH_FIN|TH_PUSH|TH_URG:
04286             if(s4data.ps_alerts)
04287             {
04288                 SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04289                         STREAM4_STEALTH_NMAP_XMAS_SCAN, /* SID */
04290                         1,                      /* Rev */
04291                         0,                      /* classification */
04292                         3,                      /* priority (low) */
04293                         STREAM4_STEALTH_NMAP_XMAS_SCAN_STR, /* msg string */
04294                         0);
04295             }
04296 
04297             break;
04298 
04299         case TH_URG:
04300         case TH_PUSH:
04301         case TH_FIN|TH_URG:
04302         case TH_PUSH|TH_FIN:
04303         case TH_URG|TH_PUSH:
04304             if(s4data.ps_alerts)
04305             {
04306                 SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04307                         STREAM4_STEALTH_VECNA_SCAN, /* SID */
04308                         1,                      /* Rev */
04309                         0,                      /* classification */
04310                         3,                      /* priority (low) */
04311                         STREAM4_STEALTH_VECNA_SCAN_STR, /* msg string */
04312                         0);
04313             }
04314             
04315             break;
04316 
04317         case TH_RST:
04318         case TH_RST|TH_ACK:
04319             break;
04320 
04321         default: /* 
04322                   * some kind of non-kosher activity occurred, drop the node 
04323                   * and flag a portscan
04324                   */
04325             if(s4data.ps_alerts)
04326             {
04327                 SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04328                         STREAM4_STEALTH_ACTIVITY, /* SID */
04329                         1,                      /* Rev */
04330                         0,                      /* classification */
04331                         3,                      /* priority (low) */
04332                         STREAM4_STEALTH_ACTIVITY_STR, /* msg string */
04333                         0);
04334 
04335                 break;
04336             }
04337 
04338             return NULL;
04339     }
04340 
04341     if(idx)
04342     {
04343 #ifdef USE_HASH_TABLE
04344 #else /* USE_SPLAY_TREE */
04345         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
04346                     "Inserting session into session tree...\n"););
04347         if(ubi_sptInsert(RootPtr,(ubi_btNodePtr)idx,(ubi_btNodePtr)idx, NULL)
04348                 == ubi_trFALSE)
04349         {
04350             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
04351                         "sptInsert failed, that's going to "
04352                         "make life difficult\n"););
04353 
04354             stream4_memory_usage -= sizeof(Session);
04355             free(idx);
04356             return NULL;
04357         }
04358 #endif
04359         pc.tcp_streams++;
04360     }
04361 
04362     return idx;
04363 }
04364 
04365 
04366 
04367 void DeleteSession(Session *ssn, u_int32_t time)
04368 {
04369     struct in_addr foo;
04370     register int s;
04371     struct tm *lt;
04372     struct tm *et;
04373     Session *killme;
04374 
04375     RemoveStreamSession(&sfPerf.sfBase);
04376     
04377     if(ssn == NULL)
04378         return;
04379     
04380     if(s4data.track_stats_flag == STATS_HUMAN_READABLE)
04381     {
04382         lt = localtime((time_t *) &ssn->start_time);
04383         s = (ssn->start_time + thiszone) % 86400;
04384 
04385         fprintf(session_log, "[*] Session stats:\n   Start Time: ");
04386         fprintf(session_log, "%02d/%02d/%02d-%02d:%02d:%02d", lt->tm_mon+1,
04387                 lt->tm_mday, lt->tm_year - 100, s/3600, (s%3600)/60, s%60);
04388 
04389         et = localtime((time_t *) &ssn->last_session_time);
04390         s = (ssn->last_session_time + thiszone) % 86400;
04391         fprintf(session_log, "   End Time: %02d/%02d/%02d-%02d:%02d:%02d\n", 
04392                 et->tm_mon+1, et->tm_mday, et->tm_year - 100, s/3600, 
04393                 (s%3600)/60, s%60);
04394 
04395         foo.s_addr = ssn->server.ip;
04396         fprintf(session_log, "   Server IP: %s  ", inet_ntoa(foo));
04397         fprintf(session_log, "port: %d  pkts: %u  bytes: %u\n", 
04398                 ssn->server.port, ssn->server.pkts_sent, 
04399                 ssn->server.bytes_sent);
04400         foo.s_addr = ssn->client.ip;
04401         fprintf(session_log, "   Client IP: %s  ", inet_ntoa(foo));
04402         fprintf(session_log, "port: %d  pkts: %u  bytes: %u\n", 
04403                 ssn->client.port, ssn->client.pkts_sent, 
04404                 ssn->client.bytes_sent);
04405 
04406     }
04407     else if(s4data.track_stats_flag == STATS_MACHINE_READABLE)
04408     {
04409         lt = localtime((time_t *) &ssn->start_time);
04410         s = (ssn->start_time + thiszone) % 86400;
04411 
04412         fprintf(session_log, "[*] Session => Start: ");
04413         fprintf(session_log, "%02d/%02d/%02d-%02d:%02d:%02d", lt->tm_mon+1,
04414                 lt->tm_mday, lt->tm_year - 100, s/3600, (s%3600)/60, s%60);
04415 
04416         et = localtime((time_t *) &ssn->last_session_time);
04417         s = (ssn->last_session_time + thiszone) % 86400;
04418         fprintf(session_log, " End Time: %02d/%02d/%02d-%02d:%02d:%02d", 
04419                 et->tm_mon+1, et->tm_mday, et->tm_year - 100, s/3600, 
04420                 (s%3600)/60, s%60);
04421 
04422         foo.s_addr = ssn->server.ip;
04423         fprintf(session_log, "[Server IP: %s  ", inet_ntoa(foo));
04424         fprintf(session_log, "port: %d  pkts: %u  bytes: %u]", 
04425                 ssn->server.port, ssn->server.pkts_sent, 
04426                 ssn->server.bytes_sent);
04427         foo.s_addr = ssn->client.ip;
04428         fprintf(session_log, " [Client IP: %s  ", inet_ntoa(foo));
04429         fprintf(session_log, "port: %d  pkts: %u  bytes: %u]\n", 
04430                 ssn->client.port, ssn->client.pkts_sent, 
04431                 ssn->client.bytes_sent);
04432     }
04433     else if(s4data.track_stats_flag == STATS_BINARY)
04434     {
04435         BinStats bs;  /* lets generate some BS */
04436 
04437         bs.start_time = ssn->start_time;
04438         bs.end_time = ssn->last_session_time;
04439         bs.sip = ssn->server.ip;
04440         bs.cip = ssn->client.ip;
04441         bs.sport = ssn->server.port;
04442         bs.cport = ssn->client.port;
04443         bs.spackets = ssn->server.pkts_sent;
04444         bs.cpackets = ssn->client.pkts_sent;
04445         bs.sbytes = ssn->server.bytes_sent;
04446         bs.cbytes = ssn->client.bytes_sent;
04447 
04448         WriteSsnStats(&bs);
04449     }
04450 
04451 #ifdef USE_HASH_TABLE
04452     killme = RemoveSession(ssn);
04453 
04454     DropSession(killme);
04455 #else /* USE_SPLAY_TREE */
04456     if(ubi_trCount(RootPtr))
04457     {
04458         killme = (Session *) ubi_sptRemove(RootPtr, (ubi_btNodePtr) ssn);
04459 
04460         DropSession(killme);
04461     }
04462 #endif
04463 }
04464 
04465 
04466 
04467 /*
04468  * RST 
04469  *
04470  * Snort/IDS safe handling of TCP Resets
04471  *  
04472  * ignore rules
04473  *      if stream tracking is off, ignore resets.
04474  *      if stream reassembly is off in the direction of flow, ignore resets.
04475  *      if the rst sequence is a duplicate sequence number, ignore it.
04476  *      if the rst is on a flow where we have unack'd data, ignore it.
04477  *  if there is no ack with the reset, ignore it.
04478  *  if the sequence is > the next expected sequence but still within 
04479  *      the window , queue it, and ignore it for now.
04480  *  if the last ack we received is less than our next sequence, we have 
04481  *      outstanding acks - ignore the reset.
04482  *      
04483  *  ignoring a reset does the following:
04484  *      the session is not closed.
04485  *      if the session is closed by the receiver of the reset, the session will 
04486  *      time out.
04487  *      if the session is not closed by the receiver, than data will continue to 
04488  *      be tracked.
04489  * 
04490  * Includes Fix for bug 2161  
04491  * 9/2/2003
04492  *
04493  * 'go to the river called state, eat any of it's acks - but fear the 
04494  * reset, for it can be poisonous' - man
04495  * 
04496  * 
04497  */
04498 int CheckRst(Session *ssn, int direction, u_int32_t pkt_seq, Packet *p)
04499 {
04500     Stream *s;
04501     static StreamPacketData spd;
04502     spd.seq_num = pkt_seq;
04503 
04504     /* If not tracking state ignore it */
04505     if( !s4data.stateful_inspection_flag )
04506         return 0;
04507 
04508     if(direction == FROM_SERVER)
04509     {        
04510         s = &ssn->server;
04511         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"--RST From Server!\n"););
04512     }
04513     else
04514     {        
04515         s = &ssn->client;
04516         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"--RST From Client!\n"););
04517     }
04518 
04519     {
04520         DEBUG_WRAP(struct in_addr foo;);
04521         DEBUG_WRAP(foo.s_addr=s->ip; 
04522                 DebugMessage(DEBUG_STREAM, 
04523                     "--RST packet from %s!\n",inet_ntoa(foo));
04524                 DebugMessage(DEBUG_STREAM, 
04525                     "--pkt seq: %u   last_ack: %u base-seq: %u next-seq: %u "
04526                     "bytes-sent: %u bytes-tracked: %u win: %u \n",
04527                     pkt_seq,s->last_ack,s->base_seq,s->next_seq,s->bytes_sent,
04528                     s->bytes_tracked,s->win_size););
04529     }
04530 
04531     /*
04532      *  We want to make sure the RST has the next valid sequence that 
04533      *  this side should be sending 
04534      *  If the pkt_seq < next_seq it's essentially a duplicate 
04535      *  sequence, and is probably going to be discarded, it certainly 
04536      *  should be. Also, the base sequence includes the SYN sequence count.
04537      *  If the packet seq is after the next seq than we should queue the 
04538      *  packet for later, in case an out of order packet arrives. We 
04539      *  should also honor the RST-ACK requirements.. but I have to research 
04540      *  that more.
04541      *
04542      *  Ignoring a RST implies we won't shutdown this session due to it.
04543      *  
04544      *  This is a standard TCP/IP stack 'in the window' check, but it's 
04545      *  not always the way stacks handle RST's:
04546      *  
04547      *  if(SEQ_LT(pkt_seq,s->base_seq+s->bytes_sent) || 
04548      *     SEQ_GEQ(pkt_seq,(s->last_ack+s->win_size))) 
04549      *  
04550      *  We use a tighter constraint...
04551      */
04552     if( !SEQ_EQ(pkt_seq,s->base_seq+s->bytes_sent) )
04553     {
04554         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
04555                     "Bad RST packet, bad sequence or no ack, no cookie!\n");
04556                 DebugMessage(DEBUG_STREAM, "pkt seq: 0x%X   last_ack: 0x%X   "
04557                     "win: 0x%X\n", pkt_seq, s->last_ack, s->win_size););
04558 
04559         /* we should probably alert here */
04560         if(s4data.evasion_alerts)
04561         {
04562             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04563                     STREAM4_EVASIVE_RST, /* SID */
04564                     1,                      /* Rev */
04565                     0,                      /* classification */
04566                     3,                      /* priority (low) */
04567                     STREAM4_EVASIVE_RST_STR, /* msg string */
04568                     0);
04569         }
04570 
04571         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
04572                     "Ignoring a RST (1)...pkt_seq=%u\n",pkt_seq););
04573         return 0;
04574     }
04575 
04576     /* At this point if the reset seq + ack flags are ok, we still must not 
04577      * have any data waiting for an ack to honor the reset right now...
04578      *
04579      * 9/2/2003 -  bug 2161
04580      * 
04581      * Do not return 1 so fast. This RST might be a retransmission of
04582      * data that was not acked yet.  If it is, most hosts will reject
04583      * the RST. Future work should explore this futher.
04584      *
04585      * Shai Rubin <shai@cs.wisc.edu>
04586      */
04587     if( ubi_sptFind(&s->data,(ubi_btItemPtr)(&spd)) && 
04588             SEQ_LT(s->last_ack,s->base_seq+s->bytes_sent) )
04589     {
04590         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
04591                     "Ignoring a RST (2)...pkt_seq=%u\n",pkt_seq););
04592         return 0;
04593     }
04594 
04595     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
04596                 "Not Ignoring a RST...pkt_seq=%u\n",pkt_seq););
04597 
04598     return 1;
04599 }
04600 
04601 void FlushDeletedStream(Session *ssn, Stream *s)
04602 {
04603     Packet p;
04604     StreamPacketData *spd;
04605     if (s)
04606     {
04607         if (ubi_trCount((ubi_btNodePtr)&s->data))
04608         {
04609             /* Grab the last packet that was stored to use as the 'reason
04610              * for flushing'. */
04611             ubi_btRootPtr RootPtr = &s->data;
04612             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
04613                 "Dropping session... reassembling before purge\n"););
04614             spd = (StreamPacketData *)ubi_trLast(RootPtr->root);
04615             /* Uggh, hate to have do this, but we don't store the original
04616              * packet data.  Eth, IP & TCP headers are required for
04617              * rebuilding a stream.
04618              */
04619             (*grinder)(&p, (struct pcap_pkthdr *)&spd->pkth, spd->pkt);
04620             p.ssnptr = ssn;
04621             p.streamptr = s;
04622             FlushStream(s, &p, NO_REVERSE);
04623         }
04624     }
04625 }
04626 
04627 void DropSession(Session *ssn)
04628 {
04629     Stream *s;
04630     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,  "Dropping session %p\n", ssn););
04631 
04632     if(ssn == NULL)
04633         return;
04634     
04635     if (s4data.reassemble_server)
04636     {
04637         s = &ssn->server;
04638         FlushDeletedStream(ssn, s);
04639     }
04640 
04641     if (s4data.reassemble_client)
04642     {
04643         s = &ssn->client;
04644         FlushDeletedStream(ssn, s);
04645     }
04646 
04647     DeleteSpd((ubi_trRootPtr)&ssn->server.data);
04648 
04649     DeleteSpd((ubi_trRootPtr)&ssn->client.data);
04650 
04651     if (ssn->preproc_free)
04652     {
04653         ssn->preproc_free(ssn->preproc_data);
04654         ssn->preproc_data = NULL;
04655         ssn->preproc_free = NULL;
04656     }
04657 
04658     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[F] Freeing %d byte session\n", 
04659                             sizeof(Session)););
04660    
04661 #ifdef USE_HASH_TABLE 
04662 #else /* USE_SPLAY_TREE */
04663     stream4_memory_usage -= sizeof(Session);
04664     free(ssn);
04665 #endif
04666 }
04667 
04668 
04669 
04670 void DeleteSpd(ubi_trRootPtr Root)
04671 {    
04672     (void)ubi_trKillTree(Root, KillSpd);
04673 }
04674 
04675 
04676 int GetDirection(Session *ssn, Packet *p)
04677 {
04678     if(p->iph->ip_src.s_addr == ssn->client.ip)
04679     {
04680         return FROM_CLIENT;
04681     }
04682     else if(((p->tcph->th_flags & TH_NORESERVED) == TH_SYN) &&
04683             !(ssn->session_flags & SSNFLAG_ESTABLISHED))
04684     {
04685         ssn->client.port = p->sp;
04686         ssn->client.ip   = p->iph->ip_src.s_addr;
04687         ssn->server.port = p->dp;
04688         ssn->server.ip   = p->iph->ip_dst.s_addr;
04689         return FROM_CLIENT;
04690     }
04691         
04692     return FROM_SERVER;
04693 }
04694 
04695 #ifdef USE_HASH_TABLE
04696 #elif defined(USE_SPLAY_TREE)
04697 #else
04698 Session *GetSession(Packet *p)
04699 {
04700     Session idx;
04701     Session *returned;
04702 #ifdef DEBUG
04703     char flagbuf[9];
04704     CreateTCPFlagString(p, flagbuf);
04705 #endif
04706 
04707     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Trying to get session...\n"););
04708     idx.server.ip = p->iph->ip_src.s_addr;
04709     idx.client.ip = p->iph->ip_dst.s_addr;
04710     idx.server.port = p->sp;
04711     idx.client.port = p->dp;
04712 
04713     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Looking for sip: 0x%X sp: %d  cip: "
04714                 "0x%X cp: %d flags: %s\n", idx.server.ip, idx.server.port, 
04715                 idx.client.ip, idx.client.port, flagbuf););
04716 
04717     returned = (Session *) ubi_sptFind(RootPtr, (ubi_btItemPtr)&idx);
04718 
04719     if(returned == NULL)
04720     {
04721         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "GetSession forward didn't work, "
04722                     "trying backwards...\n"););
04723         idx.server.ip = p->iph->ip_dst.s_addr;
04724         idx.client.ip = p->iph->ip_src.s_addr;
04725         idx.server.port = p->dp;
04726         idx.client.port = p->sp;
04727         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Looking for sip: 0x%X sp: %d  "
04728                                 "cip: 0x%X cp: %d flags: %s\n", idx.server.ip, 
04729                                 idx.server.port, idx.client.ip, idx.client.port,
04730                                 flagbuf););
04731         returned = (Session *) ubi_sptFind(RootPtr, (ubi_btItemPtr)&idx);
04732     }
04733 
04734     if(returned == NULL)
04735     {
04736         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Unable to find session\n"););
04737     }
04738     else
04739     {
04740         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Found session\n"););
04741     }
04742 
04743     return returned;
04744 
04745 }
04746 #endif
04747 
04748 void Stream4ShutdownFunction(int signal, void *foo)
04749 {
04750     /* save connections on a shutdown of snort */
04751     if(s4data.store_state_to_disk == 1)
04752     {
04753         DumpStateTable(s4data.state_file);
04754     }
04755 
04756     PurgeSessionCache();
04757 }
04758 
04759 void Stream4CleanExitFunction(int signal, void *foo)
04760 {
04761     if(s4data.track_stats_flag)
04762     {
04763         if(s4data.track_stats_flag != STATS_BINARY)
04764             fclose(session_log);
04765         else
04766             if(stats_log != NULL)
04767                 fclose(stats_log->fp);
04768     }
04769 }
04770 
04771 
04772 void Stream4RestartFunction(int signal, void *foo)
04773 {
04774     /* save connections on a restart of snort */
04775     if(s4data.store_state_to_disk == 1)
04776     {
04777         DumpStateTable(s4data.state_file);
04778     }
04779 
04780     if(s4data.track_stats_flag)
04781     {
04782         if(s4data.track_stats_flag != STATS_BINARY)
04783             fclose(session_log);
04784         else
04785             if(stats_log != NULL)
04786                 fclose(stats_log->fp);
04787     }
04788 }
04789 
04790 
04791 static u_int32_t GetTcpTimestamp(Packet *p, u_int32_t *ts)
04792 {
04793     u_int32_t i = 0;
04794     
04795     DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
04796         "Getting timestamp...\n"););
04797     while(i < p->tcp_option_count && i < 40)
04798     {
04799         if(p->tcp_options[i].code == TCPOPT_TIMESTAMP)
04800         {
04801             *ts = EXTRACT_32BITS(p->tcp_options[i].data);
04802             DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
04803                 "Found timestamp %lu\n", *ts););
04804             return 1;
04805         }
04806         
04807         i++;
04808     }
04809     
04810     *ts = 0;
04811     
04812     DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
04813         "No timestamp...\n"););
04814     
04815     return 0;
04816 }
04817 
04818 
04819 
04820 /* XXX this function should be reworked so that we don't alloc until
04821  * we've decided we're actually going to store the packet!
04822  *
04823  * VJ made this an int function so we can check it's result, and
04824  * if it didn't store our data, adjust s->bytes_tracked at the
04825  * caller.
04826  *
04827  * returns:
04828  * 1: data stored.
04829  * 0: not stored.
04830  */
04831 #ifdef GIDS
04832 int StoreStreamPkt(Session *ssn, Packet *p, u_int32_t pkt_seq)
04833 #else
04834 void StoreStreamPkt(Session *ssn, Packet *p, u_int32_t pkt_seq)
04835 #endif /* GIDS */
04836 {
04837     Stream *s;
04838     StreamPacketData *spd;
04839     StreamPacketData *returned;
04840     StreamPacketData *foo;
04841     ubi_btNodePtr oldNode;
04842 
04843     int direction = GetDirection(ssn, p);
04844 
04845     /* select the right stream */
04846     if(direction == FROM_CLIENT)
04847     {
04848         if(!s4data.reassemble_client)
04849         {
04850 #ifdef GIDS
04851             packet_added_to_stream = 0;
04852             return 0;
04853 #else
04854             return;
04855 #endif /* GIDS */
04856         }
04857 
04858         s = &ssn->client;
04859 
04860         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Storing client packet (%d bytes)\n", 
04861                     p->pkth->caplen););
04862 
04863         /* Go ahead and detect ttl attacks if we already have one
04864            ttl from the stream
04865 
04866            since fragroute does this a lot, perhaps we should have a
04867            counter to avoid false positives.. -- cmg
04868          */
04869 
04870         if(s4data.ttl_limit)
04871         {
04872             if(ssn->ttl && p->iph->ip_ttl < 10)
04873             { /* have we already set a client ttl? */
04874                 if(abs(ssn->ttl - p->iph->ip_ttl) >= s4data.ttl_limit) 
04875                 {
04876                     SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04877                             STREAM4_TTL_EVASION, /* SID */
04878                             1,                      /* Rev */
04879                             0,                      /* classification */
04880                             3,                      /* priority (low) */
04881                             STREAM4_TTL_EVASION_STR, /* msg string */
04882                             0);
04883 #ifdef GIDS
04884                     packet_added_to_stream = 0;
04885                     
04886                     if(s4data.drop_ttl_evasion == 1)
04887                     {
04888                         //printf("DROP: TTL EVASION\n");
04889                         InlineDrop();
04890                     }
04891                     return 0;
04892 #else
04893                     return;
04894 #endif /* GIDS */
04895                 }
04896             } 
04897             else 
04898             {
04899                 ssn->ttl = p->iph->ip_ttl; /* first packet we've seen,
04900                                               lets go ahead and set it. */
04901             }
04902         }
04903     }
04904     else
04905     {
04906         if(!s4data.reassemble_server)
04907         {
04908 #ifdef GIDS
04909             packet_added_to_stream = 0;
04910             return 0;
04911 #else
04912             return;
04913 #endif /* GIDS */
04914         }
04915 
04916         s = &ssn->server;
04917 
04918         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Storing server packet (%d bytes)\n", 
04919                                 p->pkth->caplen););
04920     }
04921 
04922     if ((p->tcph->th_flags == 0) &&
04923         (ssn->session_flags & SSNFLAG_ESTABLISHED))
04924     {
04925         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Dropping packet in established session "
04926                     "(%d bytes) without TCP Flags\n", p->pkth->caplen););
04927 
04928         if(s4data.evasion_alerts)
04929         {
04930             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04931                     STREAM4_TCP_NO_ACK, /* SID */
04932                     1,                      /* Rev */
04933                     0,                      /* classification */
04934                     3,                      /* priority (low) */
04935                     STREAM4_TCP_NO_ACK_STR,/*msg string */
04936                     0);
04937         }
04938 
04939 #ifdef GIDS
04940         packet_added_to_stream = 0;
04941 
04942         if(s4data.drop_no_tcp_on_est == 1)
04943         {
04944                 //printf("DROP: NO TCP Flags in established session\n");
04945                 InlineDrop();
04946         }
04947         return 0;
04948 #else
04949         return;
04950 #endif /* GIDS */
04951     }
04952 
04953     /* check for retransmissions of data that's already been ack'd */
04954     if((pkt_seq < s->last_ack) && (s->last_ack > 0) && 
04955        (direction == FROM_CLIENT))
04956     {
04957         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"EVASIVE RETRANS: pkt seq: 0x%X "
04958                                 "stream->last_ack: 0x%X\n", pkt_seq, s->last_ack););
04959 
04960         if(s4data.state_alerts)
04961         {
04962             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04963                     STREAM4_EVASIVE_RETRANS, /* SID */
04964                     1,                      /* Rev */
04965                     0,                      /* classification */
04966                     3,                      /* priority (low) */
04967                     STREAM4_EVASIVE_RETRANS_STR, /* msg string */
04968                     0);
04969         }
04970 
04971 #ifdef GIDS
04972         packet_added_to_stream = 0;
04973         return 0;
04974 #else
04975         return;
04976 #endif /* GIDS */
04977     }
04978 
04979     /* check for people trying to write outside the window */
04980     if(((pkt_seq + p->dsize - s->last_ack) > s->win_size) && 
04981        (s->win_size > 0) && direction == FROM_CLIENT)
04982     {
04983 
04984         /*
04985          * got data out of the window, someone is FUCKING around or you've got
04986          * a really crappy IP stack implementaion (hello microsoft!)
04987          */
04988         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "WINDOW VIOLATION: seq: 0x%X  "
04989                                 "last_ack: 0x%X  dsize: %d  " "window: 0x%X\n", 
04990                                 pkt_seq, s->last_ack, p->dsize, s->win_size););
04991 
04992         if(s4data.state_alerts)
04993         {
04994             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
04995                     STREAM4_WINDOW_VIOLATION, /* SID */
04996                     1,                      /* Rev */
04997                     0,                      /* classification */
04998                     3,                      /* priority (low) */
04999                     STREAM4_WINDOW_VIOLATION_STR, /* msg string */
05000                     0);
05001         }
05002 
05003 #ifdef GIDS
05004         packet_added_to_stream = 0;
05005         
05006         if(s4data.drop_out_of_window == 1)
05007         {
05008             InlineDrop();
05009         }
05010         return 0;
05011 #else
05012         return;
05013 #endif /* GIDS */
05014     }
05015 
05016     if(!WithinSessionLimits(p, s))
05017     {
05018         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[S4] Not within session limits!\n"););
05019 #ifdef GIDS
05020         packet_added_to_stream = 0;
05021         if(s4data.drop_not_in_limits == 1)
05022         {
05023                 //printf("DROP: Not within session limits\n");
05024                 InlineDrop();
05025         }
05026         return 0;
05027 #else
05028         return;
05029 #endif /* GIDS */
05030     }
05031 
05032     
05033     /* prepare a place to put the data */
05034     if(s->state >= ESTABLISHED)
05035     {
05036         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[A] Allocating %d bytes for "
05037                                 "StreamPacketData\n", sizeof(StreamPacketData)););
05038 
05039         spd = (StreamPacketData *) SafeAlloc(sizeof(StreamPacketData), 
05040                                              p->pkth->ts.tv_sec, ssn);
05041 
05042         spd->seq_num = pkt_seq;
05043         spd->payload_size = p->dsize;
05044         spd->cksum = p->tcph->th_sum;
05045 
05046         /* attach the packet here */
05047         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[A] Allocating %u bytes for packet\n", 
05048                                 p->pkth->caplen););
05049 
05050         spd->pktOrig = spd->pkt = (u_int8_t *) SafeAlloc(p->pkth->caplen + SPARC_TWIDDLE,
05051                                           p->pkth->ts.tv_sec, ssn);
05052         spd->pkt += SPARC_TWIDDLE;
05053         spd->pkt_size = p->pkth->caplen + SPARC_TWIDDLE;
05054 
05055         /* copy the packet */
05056         memcpy(spd->pkt, p->pkt, p->pkth->caplen);
05057 
05058         /* copy the packet header */
05059         memcpy(&spd->pkth, p->pkth, sizeof(SnortPktHeader));
05060 
05061         /* set the pointer to the stored packet payload */
05062         spd->payload = spd->pkt + (p->data - p->pkt);
05063     }
05064     else
05065     {
05066         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "WARNING: Data on unestablished "
05067                     "session state: %d)!\n", s->state););
05068 #ifdef GIDS
05069         packet_added_to_stream = 0;
05070         
05071         if(s4data.drop_data_on_unest == 1)
05072         {
05073                 //printf("DROP: data on unestablished session state\n");
05074                 InlineDrop();
05075         }
05076         return 0;
05077 #else
05078         return;
05079 #endif /* GIDS */
05080     }
05081 
05082     /* check for retransmissions */
05083     returned = (StreamPacketData *) ubi_sptFind(&s->data, (ubi_btItemPtr)spd);
05084 
05085     if(returned != NULL)
05086     {
05087         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
05088                     "WARNING: returned packet not null\n"););
05089         if(returned->payload_size == p->dsize)
05090         {
05091             /* check to see if the data has been ack'd */
05092             if(s->last_ack < pkt_seq + p->dsize)
05093             {
05094                 /* retransmission of un-ack'd packet, chuck the old one 
05095                  * and put in the new one
05096                  * --------------------------------------------------
05097                  * We have to be aware of two packets sent one right
05098                  * after the other
05099                  *
05100                  * One packet sends us the data they want the remote
05101                  * host to recieve, the next sends us the data they
05102                  * want the IDS to incorrectly pick up.
05103                  *
05104                  * This gets us into the *nasty* problem of how to
05105                  * detect differing data.
05106                  *
05107                  * Hopefully this doesn't occur too much in real life
05108                  * because this check will make life slow in the
05109                  * normal case.  Of course it will just be an extra
05110                  * check on port 80 check for pattern matching which
05111                  * already hurts us enough as is :-)
05112                  *
05113                  */
05114 
05115                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05116                             "Checking Packet Contents versus Packet Store\n"););
05117 
05118                 if(returned->cksum != p->tcph->th_sum)
05119                 {
05120                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "TCP Checksums not equal\n"););
05121 
05122                     if (s4data.reassy_method == METHOD_FAVOR_NEW)
05123                     {
05124                         /* Remove the old guy from the tree */
05125                         foo = (StreamPacketData *) ubi_sptRemove(&s->data, 
05126                                 (ubi_btNodePtr) returned);                
05127 
05128                         StreamSegmentSub(s, foo->payload_size);
05129 
05130                         stream4_memory_usage -= foo->pkt_size;
05131                         free(foo->pktOrig);
05132 
05133                         stream4_memory_usage -= sizeof(StreamPacketData);
05134                         free(foo);
05135 
05136 
05137                         if(s4data.evasion_alerts)
05138                         {
05139                             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
05140                                     STREAM4_EVASIVE_RETRANS_DATA, /* SID */
05141                                     1,                      /* Rev */
05142                                     0,                      /* classification */
05143                                     3,                      /* priority (low) */
05144                                     STREAM4_EVASIVE_RETRANS_DATA_STR,/*msg string */
05145                                     0);
05146                         }
05147                         /* New packet will be inserted below */
05148                     }
05149                     else
05150                     {
05151                         /* keep the old data, free up the mem we just alloc'd */
05152                         stream4_memory_usage -= spd->pkt_size;
05153                         free(spd->pktOrig);
05154 
05155                         stream4_memory_usage -= sizeof(StreamPacketData);
05156                         free(spd);
05157 
05158                         if(s4data.evasion_alerts)
05159                         {
05160                             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
05161                                     STREAM4_EVASIVE_RETRANS_DATA, /* SID */
05162                                     1,                      /* Rev */
05163                                     0,                      /* classification */
05164                                     3,                      /* priority (low) */
05165                                     STREAM4_EVASIVE_RETRANS_DATA_STR,/*msg string */
05166                                     0);
05167                         }
05168 
05169                         /* And, we're done */
05170 #ifdef GIDS
05171                         packet_added_to_stream = 0;
05172                         return 0;
05173 #else
05174                         return;
05175 #endif /* GIDS */
05176                     }
05177                 } 
05178                 else 
05179                 {
05180                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05181                                 "TCP Checksums equal..."
05182                                 " returning; see comment in src\n"););
05183                     /*
05184                      * Possible Research chance:
05185                      *
05186                      *  How easy is it to fool IDSes with differening
05187                      *  payloads that have the same checksums to the
05188                      *  same IPs
05189                      */
05190 
05191                     stream4_memory_usage -= spd->pkt_size;
05192                     free(spd->pktOrig);
05193 
05194                     stream4_memory_usage -= sizeof(StreamPacketData);
05195                     free(spd);
05196 
05197 #ifdef GIDS
05198                     packet_added_to_stream = 0;
05199                     return 0;
05200 #else
05201                     return;
05202 #endif /* GIDS */
05203                 }
05204             }
05205             else
05206             {
05207                 /* screw it, we already ack'd this data */
05208                 StreamSegmentSub(s, spd->payload_size);
05209 
05210                 stream4_memory_usage -= spd->pkt_size;
05211                 free(spd->pktOrig);
05212 
05213                 stream4_memory_usage -= sizeof(StreamPacketData);
05214                 free(spd);
05215 
05216                 if(s4data.state_alerts)
05217                 {
05218                     SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
05219                             STREAM4_EVASIVE_RETRANS, /* SID */
05220                             1,                      /* Rev */
05221                             0,                      /* classification */
05222                             3,                      /* priority (low) */
05223                             STREAM4_EVASIVE_RETRANS_STR, /* msg string */
05224                             0);
05225                 }
05226 #ifdef GIDS
05227                 packet_added_to_stream = 0;
05228                 return 1; /* StreamSegmentSub is called */
05229 #else
05230                 return;
05231 #endif /* GIDS */
05232             }
05233         }
05234         else if(returned->payload_size < p->dsize)
05235         {
05236             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05237                         "Duplicate packet with forward overlap\n"););
05238 
05239             /* check to see if this one's been ack'd */
05240             if(s->last_ack > pkt_seq + p->dsize)
05241             {
05242                 StreamSegmentSub(s, spd->payload_size);
05243 
05244                 /* screw it, we already ack'd this data */
05245                 stream4_memory_usage -= spd->pkt_size;
05246                 free(spd->pktOrig);
05247 
05248                 stream4_memory_usage -= sizeof(StreamPacketData);
05249                 free(spd);
05250 
05251                 if(s4data.evasion_alerts)
05252                 {
05253                     SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
05254                             STREAM4_FORWARD_OVERLAP, /* SID */
05255                             1,                      /* Rev */
05256                             0,                      /* classification */
05257                             3,                      /* priority (low) */
05258                             STREAM4_FORWARD_OVERLAP_STR, /* msg string */
05259                             0);
05260                 }
05261 
05262 #ifdef GIDS
05263                 packet_added_to_stream = 0;
05264                 return 1; /* StreamSegmentSub is called */
05265 #else
05266                 return;
05267 #endif /* GIDS */
05268             }
05269             else
05270             {
05271                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05272                             "Adding un-ack'd duplicate packet with forward overlap\n"););
05273 
05274                 s->overlap_pkts++;
05275 #if 0
05276                 foo = (StreamPacketData *) ubi_sptRemove(&s->data, 
05277                         (ubi_btNodePtr) returned);                
05278 
05279                 StreamSegmentSub(s, foo->payload_size);
05280 
05281 
05282                 stream4_memory_usage -= foo->pkt_size;
05283                 free(foo->pkt);
05284 
05285                 stream4_memory_usage -= sizeof(StreamPacketData);
05286                 free(foo);
05287 #endif
05288             }
05289         }
05290         else if(returned->payload_size > p->dsize)
05291         {
05292             /* check to see if this one's been ack'd */
05293             if(s->last_ack > pkt_seq + p->dsize)
05294             {
05295                 StreamSegmentSub(s, spd->payload_size);
05296 
05297                 /* screw it, we already ack'd this data */
05298                 stream4_memory_usage -= spd->pkt_size;
05299                 free(spd->pktOrig);
05300 
05301                 stream4_memory_usage -= sizeof(StreamPacketData);
05302                 free(spd);
05303 
05304                 if(s4data.state_alerts)
05305                 {
05306                     SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
05307                             STREAM4_EVASIVE_RETRANS, /* SID */
05308                             1,                      /* Rev */
05309                             0,                      /* classification */
05310                             3,                      /* priority (low) */
05311                             STREAM4_EVASIVE_RETRANS_STR, /* msg string */
05312                             0);
05313                 }
05314 #ifdef GIDS
05315                 packet_added_to_stream = 0;
05316                 return 1; /* StreamSegmentSub is called */
05317 #else
05318                 return;
05319 #endif /* GIDS */
05320             }
05321             else
05322             {
05323                 /* Some tool will probably have the following scenario one day.
05324                  * send a bunch of 1 byte packets that the remote host should 
05325                  * see and start acking and then follow that up with one 
05326                  * big packet
05327                  *
05328                  * To defeat this, we have to see if the contents of
05329                  * the big packet match up with the ton of dinky packets...
05330                  *
05331                  * Instead of just going to look for every damn one of
05332                  * the packets, lets just compare the timestamp of our
05333                  * current packet versus the retransmitted one.
05334                  *
05335                  * We could probably detect all the fun retransmission
05336                  * games this way.
05337                  */
05338 
05339                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05340                             "Checking if we are retranmitting too fast\n"););
05341                 if(RetransTooFast(&returned->pkth.ts, 
05342                             (struct timeval *) &p->pkth->ts))
05343                 {
05344                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05345                                 "Generating packets retranmissions "
05346                                 "faster than we should\n"););
05347 
05348                     stream4_memory_usage -= spd->pkt_size;
05349                     free(spd->pktOrig);
05350 
05351                     stream4_memory_usage -= sizeof(StreamPacketData);
05352                     free(spd);
05353 
05354                     if(s4data.evasion_alerts)
05355                     {
05356                         SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
05357                                 STREAM4_EVASIVE_RETRANS_DATASPLIT, /* SID */
05358                                 1,                      /* Rev */
05359                                 0,                      /* classification */
05360                                 3,                      /* priority (low) */
05361                                 STREAM4_EVASIVE_RETRANS_DATASPLIT_STR, /* msg string */
05362                                 0);
05363 
05364                     }
05365 #ifdef GIDS
05366                     packet_added_to_stream = 0;
05367                     return 0;
05368 #else
05369                     return;
05370 #endif /* GIDS */
05371                 } 
05372 #if 0
05373                 else 
05374                 {
05375                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05376                                 "Replacing un-ack'd segment in Packet Store\n"););
05377 
05378                     foo = (StreamPacketData *) ubi_sptRemove(&s->data, 
05379                             (ubi_btNodePtr) returned);
05380 
05381                     stream4_memory_usage -= foo->pkt_size;
05382                     free(foo->pkt);
05383 
05384                     stream4_memory_usage -= sizeof(StreamPacketData);
05385                     free(foo);
05386                 }
05387 #endif
05388                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05389                             "Adding un-ack'd duplicate packet with backwards overlap\n"););
05390                 s->overlap_pkts++;
05391 
05392             }
05393         }
05394     }
05395     else
05396     {
05397         /* Nothing with that sequence number... Check if there is
05398          * an overlapping node already in the tree. */
05399         OverlapData overlapData;
05400         overlapData.seq_low = pkt_seq;
05401         overlapData.seq_hi = pkt_seq + spd->pkt_size;
05402         if (ubi_trCheck(&s->data, OverlapCompareFunc, (void *)&overlapData))
05403         {
05404             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05405                             "Adding non-duplicate packet with overlap\n"););
05406             s->overlap_pkts++;
05407         }
05408     }
05409 
05410     /* check for timestamp of 0, ACK set (not SYN) in packet, and session
05411      * is established.  This should resolve problems with PAWs. */
05412     {
05413         u_int32_t timestamp;
05414         if (GetTcpTimestamp(p, &timestamp) == 1)
05415         {
05416             if ((timestamp == 0) &&
05417                 (ssn->session_flags & SSNFLAG_ESTABLISHED) &&
05418                 ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == TH_ACK))
05419             {
05420                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
05421                             "Not inserting packet with 0 timestamp\n"););
05422 
05423                 stream4_memory_usage -= spd->pkt_size;
05424                 free(spd->pktOrig);
05425 
05426                 stream4_memory_usage -= sizeof(StreamPacketData);
05427                 free(spd);
05428 
05429                 if(s4data.state_alerts)
05430                 {
05431                     SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
05432                             STREAM4_ZERO_TIMESTAMP, /* SID */
05433                             1,                      /* Rev */
05434                             0,                      /* classification */
05435                             3,                      /* priority (low) */
05436                             STREAM4_ZERO_TIMESTAMP_STR, /* msg string */
05437                             0);
05438                 }
05439 
05440 #ifdef GIDS
05441                 packet_added_to_stream = 0;
05442                 printf("DROP: ZERO TIMESTAMP\n");
05443                 InlineDrop();
05444                 return 0;
05445 #else
05446                 return;
05447 #endif /* GIDS */
05448             }
05449         }
05450     }
05451 
05452     if(ubi_sptInsert(&s->data,(ubi_btNodePtr)spd,(ubi_btNodePtr)spd, &oldNode)
05453        == ubi_trFALSE)
05454     {
05455         LogMessage("sptInsert failed, that sucks\n");
05456 
05457         /* Might as well free up the memory that we couldn't insert */
05458         stream4_memory_usage -= spd->pkt_size;
05459         free(spd->pktOrig);
05460 
05461         stream4_memory_usage -= sizeof(StreamPacketData);
05462         free(spd);
05463 #ifdef GIDS
05464         packet_added_to_stream = 0;
05465         return 0;
05466 #else
05467         return;
05468 #endif /* GIDS */
05469     }
05470 
05471     p->packet_flags |= PKT_STREAM_INSERT;
05472 
05473 #ifdef GIDS
05474     packet_added_to_stream = 1;
05475     return 1;
05476 #else
05477     return;
05478 #endif /* GIDS */
05479 }
05480 
05481 
05482 void FlushStream(Stream *s, Packet *p, int direction)
05483 {
05484     int stream_size;
05485 
05486     int gotevent = 0;
05487 
05488     sfPerf.sfBase.iStreamFlushes++;
05489 
05490     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "FlushStream Entered:"
05491                 "last_ack(%u) base_seq(%u) trCount(%u)\ng",
05492                 s->last_ack, s->base_seq, ubi_trCount(&s->data)););
05493 
05494 #ifdef GIDS
05495     if(!s4data.stream4inline_mode)
05496     {
05497 #endif /* GIDS */
05498     stream_size = s->last_ack - s->base_seq;
05499 
05500     /* 
05501      ** FINs consume one byte, but they have no data.
05502      **
05503      ** NOTE:
05504      **   This already appears to be compensated for when we receive FINS,
05505      **   and this causes an off-by-one bug when implemented.
05506      */
05507     /*if(s->state == FIN_WAIT_2 || s->state == TIME_WAIT) stream_size--;*/
05508 
05509     if(stream_size >= MAX_STREAM_SIZE)
05510     {
05511 #ifdef DEBUG        
05512         DebugMessage(DEBUG_STREAM,
05513                 "stream_size(%u) > MAX_STREAM_SIZE(%u)\n",
05514                 stream_size, MAX_STREAM_SIZE);
05515 
05516         DebugMessage(DEBUG_STREAM,
05517                 "Adjusting s->base_seq(%u) -> %u %u\n",
05518                 s->base_seq, s->last_ack - MAX_STREAM_SIZE,
05519                 s->last_ack - (MAX_STREAM_SIZE));
05520 
05521 #endif /* DEBUG */
05522         stream_size = MAX_STREAM_SIZE - 1;
05523         s->base_seq = s->last_ack - stream_size;
05524     }
05525 
05526     if(stream_size > 0 && ubi_trCount(&s->data))
05527     {
05528         /* put the stream together into a packet or something */
05529         if(BuildPacket(s, stream_size, p, direction))
05530         {
05531             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Passing large packet "
05532                         "on 0 size stream cache\n"););
05533             return;
05534         }
05535 
05536         /* If we aren't within session limits, we can try to build a
05537          * packet and end up with no data */
05538         if(stream_pkt->dsize > 0)
05539         {
05540             gotevent = Preprocess(stream_pkt);
05541 
05542             if(s4data.zero_flushed_packets)
05543                 bzero(stream_pkt->data, stream_pkt->dsize);
05544 
05545             if ( p->ssnptr )
05546             {
05547                 /* Reset alert tracking after flushing rebuilt packet */
05548                 Session *ssn = p->ssnptr;
05549 
05550                 ssn->alert_count = 0;
05551             }
05552 
05553             if(gotevent)
05554             {
05555                 LogStream(s);
05556             }
05557         }
05558 
05559         SegmentCleanTraverse(s);
05560         return;
05561     }
05562     else
05563     {
05564         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"Passing large packet on "
05565                     "0 size stream cache\n"););
05566     }
05567 
05568 #ifdef GIDS
05569     }
05570 #endif /* GIDS */
05571 
05572     s->bytes_tracked = 0;
05573     s->overlap_pkts = 0;
05574     DeleteSpd(&s->data);
05575 }
05576 
05577 
05578 #ifdef GIDS
05579 /*  Truncate a part of the stream.
05580  *
05581  */
05582 void TruncStream(Stream *s, Packet *p)
05583 {
05584     u_int16_t bytes_to_clear = 0;
05585 #ifdef DEBUG
05586     char flagbuf[9];
05587 #endif /* DEBUG */
05588 
05589     /* setup things for TraverseFuncTruncate */
05590     s4data.stop_traverse = 0;
05591 
05592     if(s->bytes_tracked && ubi_trCount(&s->data))
05593     {
05594         /* here we determine what we want to cut off */
05595         bytes_to_clear = s->bytes_tracked - s4data.stream4inline_window_size;
05596 
05597 #ifdef DEBUG
05598         CreateTCPFlagString(p, flagbuf);
05599         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"P: %5d -> %5d %s: ", p->sp, p->dp, flagbuf););
05600         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"stream_size: %5d: Going to try to truncate %d bytes\n", s->bytes_tracked, bytes_to_clear););
05601 #endif /* DEBUG */
05602 
05603         /* walk the packet tree (in order) and try to cut off the
05604          * ammount of bytes_to_clear */
05605         SegmentTruncTraverse(s, bytes_to_clear);
05606     }
05607 }
05608 #endif /* GIDS */
05609 
05610 
05611 /**
05612  * Flush the side of the TCP stream that just caused an alert.
05613  *
05614  * This function is exported for the detection engine.
05615  *
05616  * This routine takes a packet, logs out the stream packets ( so that
05617  * we have original payloads around ), and then updates the stream
05618  * tracking sequence numbers so that
05619  * 
05620  * @param p Packet to flush the stream reassembler on
05621  * 
05622  * @return the number of packets that have been flushed from the stream reassembler
05623  */
05624 int AlertFlushStream(Packet *p)
05625 {
05626     Session *ssn;
05627     Stream *stream;
05628     int nodecount = 0;
05629 
05630     if (!p->ssnptr)
05631         return 0;
05632 
05633     ssn = p->ssnptr;
05634 
05635     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Flushing stream due to an alert!\n"););
05636 
05637 #ifdef GIDS
05638     /* if we are in inline mode, enforce state and drop or reject and have tcp packet
05639      * we try to drop the session beloning to the packet.
05640      *
05641      * The check for the tcp packet is done because we run before NotForStream4()...
05642      */
05643     if(s4data.stream4inline_mode && s4data.enforce_state && iv.drop && p->tcph != NULL)
05644     {
05645         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "okay, try to drop the session.\n"););
05646 
05647         if(ssn == NULL)
05648         {
05649             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Nothing to Flush!\n"););
05650             return 0;
05651         }
05652         DeleteSession(ssn, p->pkth->ts.tv_sec);
05653         return(0);
05654     }
05655 #endif /* GIDS */
05656 
05657     if(NotForStream4(p))
05658     {
05659         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Don't Flush a Rebuilt Stream\n"););
05660         return 0;
05661     }
05662 
05663     if(!s4data.flush_on_alert)
05664     {
05665         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Don't Flush a Rebuilt Stream on Alert from indviidual packet\n"););
05666         return 0;
05667     }
05668 
05669     if(ssn == NULL)
05670     {
05671         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Nothing to Flush!\n"););
05672         return 0;
05673     }
05674 
05675     if(GetDirection(ssn, p) == FROM_SERVER)
05676     {
05677         stream = &ssn->server;
05678 
05679         if(s4data.reassemble_server)
05680         {
05681             FlushStream(stream, p, NO_REVERSE);
05682         }
05683         else
05684         { 
05685             /*
05686             **  We handle this part of deleting the stream, because
05687             **  FlushStream() didn't handle it for us.
05688             */
05689             DeleteSpd(&stream->data);
05690             stream->bytes_tracked = 0;
05691             stream->overlap_pkts = 0;
05692         }
05693     }
05694     else
05695     {
05696         stream = &ssn->client;
05697 
05698         if(s4data.reassemble_client)
05699         {
05700             FlushStream(stream, p, NO_REVERSE);
05701         }
05702         else
05703         { 
05704             /*
05705             **  We handle this part of deleting the stream, because
05706             **  FlushStream() didn't handle it for us.
05707             */
05708             DeleteSpd(&stream->data);
05709             stream->bytes_tracked = 0;
05710             stream->overlap_pkts = 0;
05711         }
05712     }
05713 
05714     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[AFS] Bytes Tracked: %u\n", 
05715                 stream->bytes_tracked););
05716     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[AFS] Bytes Tracked: %u\n", 
05717                 stream->bytes_tracked););
05718 
05719     if(p->tcph)
05720     {
05721 #ifdef GIDS
05722         /* dont touch base_seq in stream4inline mode, since we
05723            dont drop the session */
05724         if(!s4data.stream4inline_mode)
05725         {
05726 #endif /* GIDS */
05727         stream->base_seq = ntohl(p->tcph->th_seq) + p->dsize;
05728         stream->last_ack = stream->base_seq;
05729 #ifdef GIDS
05730         }
05731 #endif /* GIDS */
05732     }
05733 
05734     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Moved the base_seq to %u!\n",
05735                 stream->base_seq););
05736 
05737     return nodecount;
05738 }
05739 
05740 /** 
05741  * Log out the Stream if possible
05742  *
05743  * only works with pcap currently
05744  *
05745  * @todo make this work with a newer output subsystem
05746  * 
05747  * @param s stream to log the data from
05748  * 
05749  * @return number of nodes in the data
05750  */
05751 int LogStream(Stream *s)
05752 {
05753     int nodecount = 0;
05754     
05755     if((pv.log_bitmap & LOG_TCPDUMP) && s4data.log_flushed_streams)
05756     {
05757         nodecount = ubi_trCount(&s->data);
05758         if (s4data.reassy_method == METHOD_FAVOR_OLD)
05759         {
05760             (void)ubi_trTraverse(&s->data, LogTraverse, s);
05761         }
05762         else
05763         {
05764             (void)ubi_trTraverseReverse(&s->data, LogTraverse, s);
05765         }
05766     }
05767 
05768     return nodecount;
05769 }
05770 
05771 
05772 
05773 void InitStream4Pkt()
05774 {
05775     stream_pkt->pkth = calloc(sizeof(SnortPktHeader)+
05776                               ETHERNET_HEADER_LEN +
05777                               SPARC_TWIDDLE + IP_MAXPACKET,
05778                               sizeof(char));
05779 
05780     stream_pkt->pkt = ((u_int8_t *)stream_pkt->pkth) + sizeof(SnortPktHeader);
05781     stream_pkt->eh = (EtherHdr *)((u_int8_t *)stream_pkt->pkt + SPARC_TWIDDLE);
05782     stream_pkt->iph =
05783         (IPHdr *)((u_int8_t *)stream_pkt->eh + ETHERNET_HEADER_LEN);
05784     stream_pkt->tcph = (TCPHdr *)((u_int8_t *)stream_pkt->iph + IP_HEADER_LEN);    
05785 
05786     stream_pkt->data = (u_int8_t *)stream_pkt->tcph + TCP_HEADER_LEN;
05787 
05788     /* stream_pkt->data is now pkt +
05789      *  IPMAX_PACKET - (IP_HEADER_LEN + TCP_HEADER_LEN + ETHERNET_HEADER_LEN)
05790      *  in size
05791      *
05792      * This is MAX_STREAM_SIZE
05793      */
05794 
05795     stream_pkt->eh->ether_type = htons(0x0800);
05796     SET_IP_VER(stream_pkt->iph, 0x4);
05797     SET_IP_HLEN(stream_pkt->iph, 0x5);
05798     stream_pkt->iph->ip_proto = IPPROTO_TCP;
05799     stream_pkt->iph->ip_ttl   = 0xF0;
05800     stream_pkt->iph->ip_len = 0x5;
05801     stream_pkt->iph->ip_tos = 0x10;
05802 
05803     SET_TCP_OFFSET(stream_pkt->tcph,0x5);
05804     stream_pkt->tcph->th_flags = TH_PUSH|TH_ACK;
05805 }
05806 
05807 
05808 
05809 /** 
05810  * Build a new stream packet from 
05811  * 
05812  * @param s Stream storage variables
05813  * @param stream_size size of the newly assembled stream ( should be less than 2^16 - 41
05814  * @param p packet that caused us to flush
05815  * @param direction which are we flushing
05816  *
05817  * @returns 0 on success, -1 if we didn't get enough data to create the packet
05818  */
05819 int BuildPacket(Stream *s, u_int32_t stream_size, Packet *p, int direction)
05820 {
05821     BuildData bd;
05822     unsigned short zero_size = 1500;
05823     Session *ssn;
05824     u_int32_t ip_len; /* total length of the IP datagram */
05825     ip_len = stream_size + IP_HEADER_LEN + TCP_HEADER_LEN;
05826 
05827     stream_pkt->pkth->ts.tv_sec = p->pkth->ts.tv_sec;
05828     stream_pkt->pkth->ts.tv_usec = p->pkth->ts.tv_usec;
05829 
05830     stream_pkt->pkth->caplen = ip_len + ETHERNET_HEADER_LEN;
05831     stream_pkt->pkth->len    = stream_pkt->pkth->caplen;
05832 
05833     stream_pkt->iph->ip_len = htons((u_short) ip_len);
05834 
05835     if(direction == REVERSE)
05836     {
05837         if(p->eh != NULL)
05838         {
05839             memcpy(stream_pkt->eh->ether_dst, p->eh->ether_src, 6);
05840             memcpy(stream_pkt->eh->ether_src, p->eh->ether_dst, 6);
05841         }
05842 
05843         stream_pkt->tcph->th_sport = p->tcph->th_dport;
05844         stream_pkt->tcph->th_dport = p->tcph->th_sport;
05845         stream_pkt->iph->ip_src.s_addr = p->iph->ip_dst.s_addr;
05846         stream_pkt->iph->ip_dst.s_addr = p->iph->ip_src.s_addr;
05847         stream_pkt->sp = p->dp;
05848         stream_pkt->dp = p->sp;
05849     }
05850     else
05851     {
05852         if(p->eh != NULL)
05853         {
05854             memcpy(stream_pkt->eh->ether_dst, p->eh->ether_dst, 6);
05855             memcpy(stream_pkt->eh->ether_src, p->eh->ether_src, 6);
05856         }
05857 
05858         stream_pkt->tcph->th_sport = p->tcph->th_sport;
05859         stream_pkt->tcph->th_dport = p->tcph->th_dport;
05860         stream_pkt->iph->ip_src.s_addr = p->iph->ip_src.s_addr;
05861         stream_pkt->iph->ip_dst.s_addr = p->iph->ip_dst.s_addr;
05862         stream_pkt->sp = p->sp;
05863         stream_pkt->dp = p->dp;
05864     }
05865 
05866     stream_pkt->tcph->th_seq = p->tcph->th_seq;
05867     stream_pkt->tcph->th_ack = p->tcph->th_ack;
05868     stream_pkt->tcph->th_win = p->tcph->th_win;
05869 
05870     s4data.stop_traverse = 0;
05871 
05872     bd.stream = s;
05873     bd.buf = stream_pkt->data;
05874     bd.total_size = 0;
05875 
05876     /* walk the packet tree (in order) and rebuild the app layer data */
05877 #ifdef GIDS
05878     if(!s4data.stream4inline_mode)
05879 #endif /* GIDS */
05880         if (s4data.reassy_method == METHOD_FAVOR_OLD)
05881         {
05882             (void)ubi_trTraverse(&s->data, TraverseFunc, &bd);
05883         }
05884         else
05885         {
05886             (void)ubi_trTraverseReverse(&s->data, TraverseFunc, &bd);
05887         }
05888 #ifdef GIDS
05889     else
05890     {
05891         if (s4data.reassy_method == METHOD_FAVOR_OLD)
05892         {
05893                 /* see if we are wrapping */
05894                 if(s->base_seq > s->last_ack
05895                         &&
05896                 ((s->base_seq - s->last_ack) > (MAX_STREAM_SIZE * 2)))
05897                 {
05898                         (void)ubi_trTraverse(&s->data, TraverseFuncRebuildAllWrap, &bd);
05899                 }
05900                 else
05901                 {
05902                         (void)ubi_trTraverse(&s->data, TraverseFuncRebuildAll, &bd);
05903                 }
05904         }
05905         else
05906         {
05907                 /* see if we are wrapping */
05908                 if(s->base_seq > s->last_ack
05909                         &&
05910                 ((s->base_seq - s->last_ack) > (MAX_STREAM_SIZE * 2)))
05911                 {
05912                         (void)ubi_trTraverseReverse(&s->data, TraverseFuncRebuildAllWrap, &bd);
05913                 }
05914                 else
05915                 {
05916                         (void)ubi_trTraverseReverse(&s->data, TraverseFuncRebuildAll, &bd);
05917                 }
05918         }
05919     }
05920 #endif /* GIDS */
05921 
05922     if(bd.total_size < stream_size)
05923     {
05924         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "bd.total_size(%u) < stream_size(%u):"
05925                     "Incomplete segment -- packet loss or weird\n",
05926                     bd.total_size, stream_size););
05927 
05928         /* This is probably because we were past our session limits --
05929            there's nothing of value in this packet */
05930         if(bd.total_size == 0)
05931         {
05932             stream_pkt->dsize = 0;
05933             return -1;
05934         }
05935     }
05936     else if(bd.total_size > stream_size)
05937     {
05938         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "stream_size(%u) < bd.total_size(%u):"
05939                     "Overlapping segments -- packet loss or weird\n",
05940                     stream_size, bd.total_size););
05941     }
05942 
05943     /* This is set in TraverseFunc when we reach a point that we
05944      * haven't ack'd to yet. Let's just go catch it next time.
05945      */
05946     if(s4data.stop_traverse)
05947     {
05948         if(s4data.stop_seq < s->base_seq)
05949         {
05950             stream_size = s->base_seq - s4data.stop_seq;
05951         }
05952         else
05953         {
05954             stream_size = s4data.stop_seq - s->base_seq;
05955         }
05956 
05957         /*
05958         **  Final sanity check for stream_size.  Make sure that the stream_size is
05959         **  not bigger than our buffer.
05960         */
05961         if(stream_size >= MAX_STREAM_SIZE)
05962         {
05963             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Truncating %d bytes from stream",
05964                         stream_size - MAX_STREAM_SIZE););
05965 
05966             stream_size = MAX_STREAM_SIZE - 1;
05967         }
05968 
05969         ip_len = IP_HEADER_LEN + TCP_HEADER_LEN + stream_size;
05970 
05971         stream_pkt->dsize = (unsigned short)stream_size;
05972 
05973         stream_pkt->pkth->caplen = ETHERNET_HEADER_LEN + ip_len;
05974         stream_pkt->pkth->len = stream_pkt->pkth->caplen;
05975 
05976         stream_pkt->iph->ip_len = htons( (u_short) ip_len );
05977     }
05978     else
05979     {
05980         stream_pkt->dsize = (unsigned short)stream_size;
05981     }
05982 
05983     s4data.stop_traverse = 0;
05984 
05985     stream_pkt->tcp_option_count = 0;
05986     stream_pkt->tcp_lastopt_bad = 0;
05987     stream_pkt->packet_flags = (PKT_REBUILT_STREAM|PKT_STREAM_EST);
05988 
05989     ssn = p->ssnptr;
05990     stream_pkt->ssnptr = p->ssnptr;
05991 
05992     stream_pkt->streamptr = (void *) s;
05993 
05994     if(stream_pkt->sp == ssn->client.port)
05995     {
05996         stream_pkt->packet_flags |= PKT_FROM_CLIENT;
05997     }
05998     else
05999     {
06000         stream_pkt->packet_flags |= PKT_FROM_SERVER;
06001     }
06002 
06003     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
06004                 "Built packet to %s from %x with %u byte payload, "
06005                 "Direction: %s\n",
06006                 inet_ntoa(stream_pkt->iph->ip_src),
06007                 stream_pkt->iph->ip_dst,
06008                 stream_pkt->dsize,
06009                 (stream_pkt->packet_flags & PKT_FROM_SERVER)
06010                 ? "from_server" : "from_client"););
06011 
06012     pc.rebuilt_tcp++;
06013 
06014 #ifdef DEBUG
06015     if(stream_pkt->packet_flags & PKT_FROM_CLIENT)
06016     {
06017         DebugMessage(DEBUG_STREAM, "packet is from client!\n");
06018     }
06019 
06020     if(stream_pkt->packet_flags & PKT_FROM_SERVER)
06021     {
06022         DebugMessage(DEBUG_STREAM, "packet is from server!\n");
06023     }
06024 
06025     if (DEBUG_STREAM & GetDebugLevel())
06026     {
06027         ClearDumpBuf();
06028         printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
06029         PrintIPPkt(stdout, IPPROTO_TCP, stream_pkt);
06030         printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
06031         ClearDumpBuf();
06032         /*printf("Printing app buffer at %p, size %d\n", 
06033           stream_pkt->data, stream_pkt->dsize);
06034           PrintNetData(stdout, stream_pkt->data, stream_pkt->dsize);
06035           ClearDumpBuf();*/
06036     }
06037 #endif
06038 
06039     /* are we within our data loss limits? */
06040     if(abs(stream_pkt->dsize - bd.total_size) >= s4data.flush_data_diff_size)
06041     {
06042         /* leave a null packet if we tried to reassemble and failed */
06043         if(s4data.zero_flushed_packets)
06044         {
06045             /* stream_size is uint so can't be negative */
06046             if(stream_size && stream_size < zero_size)
06047             {
06048                 zero_size = (unsigned short)stream_size;
06049             }
06050 
06051             if(zero_size > 0)
06052                 bzero(stream_pkt->data, zero_size);
06053         }
06054     }
06055 
06056     return 0;
06057 }
06058 
06059 
06060 int CheckPorts(u_int16_t port1, u_int16_t port2)
06061 {
06062     switch(s4_emergency.status)
06063     {
06064         case OPS_NORMAL:
06065             if(s4data.assemble_ports[port1] || s4data.assemble_ports[port2])
06066             {
06067                 return 1;
06068             }
06069             break;
06070 
06071         case OPS_SELF_PRESERVATION:
06072             if(s4data.emergency_ports[port1] || s4data.emergency_ports[port2])
06073             {
06074                 return 1;
06075             }
06076             break;
06077     }
06078 
06079     return 0;
06080 }
06081 
06082 
06083 void OpenStatsFile()
06084 {
06085     time_t curr_time;      /* place to stick the clock data */
06086     char logdir[STD_BUF];
06087     int value;
06088     StatsLogHeader hdr;
06089 
06090     bzero(logdir, STD_BUF);
06091     curr_time = time(NULL);
06092 
06093     if(stats_log->filename[0] == '/')
06094         value = snprintf(logdir, STD_BUF, "%s.%lu", stats_log->filename, 
06095                          (unsigned long)curr_time);
06096     else
06097         value = snprintf(logdir, STD_BUF, "%s/%s.%lu", pv.log_dir, 
06098                          stats_log->filename, (unsigned long)curr_time);
06099 
06100     if(value == -1)
06101     {
06102         FatalError("ERROR: log file logging path and file name are "
06103                    "too long, aborting!\n");
06104     }
06105 
06106     printf("stream4:OpenStatsFile() Opening %s\n", logdir);
06107 
06108     if((stats_log->fp=fopen(logdir, "w+")) == NULL)
06109     {
06110         FatalError("stream4:OpenStatsFile(%s): %s\n", logdir, strerror(errno));
06111     }
06112 
06113     hdr.magic = STATS_MAGIC;
06114     hdr.version_major = 1;
06115     hdr.version_minor = 81;
06116     hdr.timezone = 1;
06117 
06118     if(fwrite((char *)&hdr, sizeof(hdr), 1, stats_log->fp) != 1)
06119     {
06120         FatalError("stream4:OpenStatsFile(): %s\n", strerror(errno));
06121     }
06122         
06123     fflush(stats_log->fp);
06124 
06125     /* keep a copy of the filename for later reference */
06126     if(stats_log->filename != NULL)
06127     {
06128         free(stats_log->filename);
06129 
06130         stats_log->filename = strdup(logdir);
06131     }
06132 
06133     return;
06134 }
06135 
06136 
06137 
06138 void WriteSsnStats(BinStats *bs)
06139 {
06140     fwrite(bs, sizeof(BinStats), 1, stats_log->fp);
06141     fflush(stats_log->fp);
06142     return;
06143 }
06144 
06145 static void TcpAction(Session *ssn, Packet *p, int action, int direction, 
06146                       u_int32_t pkt_seq, u_int32_t pkt_ack)
06147 {
06148     if(action == ACTION_NOTHING)
06149     {
06150         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "returning -- action nothing\n"););
06151         return;
06152     }
06153     else 
06154     {
06155         if((action & ACTION_SET_SERVER_ISN) &&
06156                 (ssn->session_flags & SSNFLAG_MIDSTREAM))
06157         {
06158             /* Someone convinced us the session was going and then is
06159              * trying to convince us that we should be tracking this
06160              * session -- the server has the best chance of knowing
06161              * what it's really seeing.
06162              */
06163 
06164             DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
06165                         "Midstream session SYN-ACK; setting seqs;" 
06166                         "removing midstream notification\n"););
06167             ssn->client.last_ack = pkt_ack;
06168             ssn->server.last_ack = pkt_seq;
06169 
06170             ssn->server.base_seq = ssn->server.last_ack;
06171             ssn->client.base_seq = ssn->client.last_ack;
06172 
06173             /* Once we reach here, the session is no longer a
06174                midstream session */
06175 
06176             //ssn->session_flags &= (SSNFLAG_ALL ^ SSNFLAG_MIDSTREAM);
06177         }      
06178         else if(action & ACTION_SET_SERVER_ISN)
06179         {
06180             ssn->server.isn = pkt_seq;
06181             ssn->client.win_size = ntohs(p->tcph->th_win);
06182 
06183             if(pkt_ack == (ssn->client.isn+1))
06184             {
06185                 ssn->client.last_ack = ssn->client.isn+1;
06186             }
06187             else
06188             {
06189                 /* we got a messed up response from the server */
06190                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06191                             "WARNING: Got unexpected SYN ACK from server!\n");
06192                         DebugMessage(DEBUG_STREAM, 
06193                             "expected: 0x%X   received: 0x%X\n"););
06194                 ssn->client.last_ack = pkt_ack;
06195             }
06196         }
06197 
06198         /* complete a three way handshake */
06199         if(action & ACTION_COMPLETE_TWH)
06200         {
06201             /*
06202             **  Set a packet flag to say that the TWH has been
06203             **  completed.
06204             */
06205             p->packet_flags |= PKT_STREAM_TWH;
06206 
06207             /* this should be isn+1 */
06208             if(pkt_ack == ssn->server.isn+1)
06209             {
06210                 ssn->server.last_ack = ssn->server.isn+1;
06211             }
06212             else
06213             {
06214                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "WARNING: Fishy TWH from client "
06215                             "(0x%X:%d->0x%X:%d) (ack: 0x%X  isn: 0x%X)\n", 
06216                             p->iph->ip_src.s_addr, p->sp, p->iph->ip_dst.s_addr, 
06217                             p->dp, pkt_ack, ssn->server.isn););
06218 
06219                 ssn->server.last_ack = pkt_ack;
06220             }
06221 
06222             ssn->server.base_seq = ssn->server.last_ack;
06223             ssn->client.base_seq = ssn->client.last_ack;
06224         }
06225 
06226         /* 
06227          * someone sent data in their SYN packet, classic sign of someone
06228          * doing bad things (or a bad ip stack/piece of equipment)
06229          */
06230         if(action & ACTION_DATA_ON_SYN)
06231         {
06232             if(p->tcph->th_flags & TH_SYN)
06233             {
06234                 /* alert... */
06235                 if(s4data.evasion_alerts)
06236                 {
06237                     SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
06238                             STREAM4_DATA_ON_SYN, /* SID */
06239                             1,                      /* Rev */
06240                             0,                      /* classification */
06241                             3,                      /* priority (low) */
06242                             STREAM4_DATA_ON_SYN_STR, /* msg string */
06243                             0);
06244                 }
06245 
06246                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06247                             "WARNING: Data on SYN packet!\n"););
06248                 return;
06249             }
06250         }
06251 
06252         if(action & ACTION_INC_PORT)
06253         {
06254             ssn->client.port++;
06255         }
06256 
06257         /* client sent some data */
06258         if(action & ACTION_ACK_CLIENT_DATA)
06259         {
06260             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06261                         "client.base_seq(%u) client.last_ack(%u) offset(%u)\n",
06262                         ssn->client.base_seq,ssn->client.last_ack,
06263                         (ssn->client.last_ack - ssn->client.base_seq)););
06264 
06265             if((p->tcph->th_flags & TH_RST) && pkt_ack == 0)
06266             {
06267                 /* Do not change where the side has seen upon a
06268                  * "nonestablished reset" */
06269                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[R] Reset Handled\n"););
06270             }
06271             /* Going way out of our way to avoid an off by 1. */
06272             else if((ssn->session_flags & SSNFLAG_CLIENT_FIN) && 
06273                     (ssn->client.next_seq + 1 == pkt_ack))
06274             {
06275                 /* the fin consumes one byte of the sequence that
06276                  * really doesn't posses data */                
06277                 ssn->client.last_ack = pkt_ack - 1;
06278             }
06279             else if(SEQ_LT(ssn->client.last_ack, pkt_ack))
06280             {
06281                 /*
06282                  **   This assumes that the server is not malicious,
06283                  **   since it could fake large acks so we would ignore
06284                  **   data later on.
06285                  */
06286                 ssn->client.last_ack = pkt_ack;
06287             }
06288 
06289             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "client.base_seq(%u) "
06290                         "client.last_ack(%u) client.next_seq(%u)\n",
06291                         ssn->client.base_seq,ssn->client.last_ack, 
06292                         ssn->client.next_seq););
06293 
06294             if(ssn->session_flags & SSNFLAG_ESTABLISHED)
06295             {
06296                 Stream *s;
06297 
06298                 s = &ssn->client;
06299 
06300 #ifdef GIDS
06301                 if((!s4data.stream4inline_mode && /* normal mode */
06302                         (ssn->client.last_ack - ssn->client.base_seq) > ssn->flush_point &&
06303                         ubi_trCount(&s->data) > 1) ||
06304                    (s4data.stream4inline_mode  && /* inline mode */
06305                         (ssn->client.bytes_tracked > (ssn->flush_point + s4data.stream4inline_window_size)) &&
06306                         ubi_trCount(&s->data) > 1))
06307 #else
06308                 if((ssn->client.last_ack - ssn->client.base_seq) > ssn->flush_point 
06309                         && ubi_trCount(&s->data) > 1)
06310 #endif /* GIDS */
06311                 {
06312                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06313                                 "Flushing Client packet buffer "
06314                                 "(%d bytes a: 0x%X b: 0x%X pkts: %d)\n",
06315                                 (ssn->client.last_ack - ssn->client.base_seq), 
06316                                 ssn->client.last_ack, ssn->client.base_seq,
06317                                 ubi_trCount(&s->data)););
06318 
06319                     if(s4data.reassemble_client)
06320                     {
06321 #ifdef GIDS
06322                         if(!s4data.stream4inline_mode)
06323                         {
06324 #endif /* GIDS */
06325                                 FlushStream(&ssn->client, p, REVERSE);
06326                                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "after truncate: ssn->client.base_seq(%u) = ssn->client.last_ack = %u\n", ssn->client.base_seq, ssn->client.last_ack););
06327                                 ssn->client.base_seq = ssn->client.last_ack;
06328 #ifdef GIDS
06329                         }
06330                         else
06331                                 TruncStream(&ssn->client, p);
06332 #endif /* GIDS */
06333                     }
06334                 } 
06335                 else 
06336                 {
06337                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
06338                                 "%d (%d) bytes to go before we flush: "
06339                                 "(%d) segments stored\n",
06340                                 (ssn->flush_point-
06341                                     (ssn->client.last_ack - ssn->client.base_seq)),
06342                                 (ssn->client.last_ack - ssn->client.base_seq),
06343                                 ubi_trCount(&ssn->client.data)););
06344                 }
06345             }
06346 #ifdef GIDS
06347             if(s4data.stream4inline_mode)
06348             {
06349                 if(ssn->client.last_ack > ssn->client.base_seq)
06350                 {
06351                     if((ssn->client.last_ack - ssn->client.base_seq) >= (2 * s4data.stream4inline_window_size))
06352                     {
06353                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,   "BASE_SEQ: client: adjusting base_seq because last_ack(%u) "
06354                                                                 "is way larger than base_seq(%u): > 2 * window_size(%d)\n",
06355                                                                 ssn->client.last_ack, ssn->client.base_seq,
06356                                                                 s4data.stream4inline_window_size););
06357 
06358                         ssn->client.base_seq = ssn->client.last_ack - s4data.stream4inline_window_size;
06359 
06360                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,   "BASE_SEQ: base_seq is now %u\n",
06361                                                                 ssn->client.base_seq););
06362                     }
06363                 }
06364                 /*      if:
06365                         
06366                         base_seq > last_ack
06367                                 &&
06368                         diff more than MAX_STREAM_SIZE (because base_seq can be higher
06369                         than last_ack if we have a lot of un-acked packets in our buffer)
06370 
06371                         then we assume sequence have wrapped, but base is not yet wrapped
06372 
06373                         adjust base_seq by setting it to last_ack - sliding window size, or
06374                         less if s->bytes_tracked is smaller than window size
06375                 */
06376                 /* wrap */
06377                 else if(ssn->client.base_seq > ssn->client.last_ack)
06378                 {
06379                     /* this should only be true in case of a sequence number wrap */
06380                     if((ssn->client.base_seq - ssn->client.last_ack) > (MAX_STREAM_SIZE * 2))
06381                     {
06382                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "BASE_SEQ:(client) base_seq %u > last_ack %u, diff (%u)\n", ssn->client.base_seq, ssn->client.last_ack, ssn->client.base_seq - ssn->client.last_ack););
06383 
06384                         if(((MAX_SEQ_NUM - ssn->client.base_seq) + ssn->client.last_ack) >= (2 * s4data.stream4inline_window_size))
06385                         {
06386                             /* adjust base_seq to get passed the wrap */
06387                             ssn->client.base_seq = ssn->client.last_ack - s4data.stream4inline_window_size;
06388 
06389                             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "BASE_SEQ:(client) base_seq is now %u\n", ssn->client.base_seq););
06390                         }
06391                         else
06392                         {
06393                             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "BASE_SEQ:(client, no wrap) base_seq %u > last_ack %u, diff (%u)\n", ssn->client.base_seq, ssn->client.last_ack, ssn->client.base_seq - ssn->client.last_ack););
06394                         }
06395                     }
06396                     else
06397                     {
06398                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "BASE_SEQ:(client) base_seq %u > last_ack %u\n", ssn->client.base_seq, ssn->client.last_ack););
06399                     }
06400                 }
06401             }
06402 #endif /* GIDS */
06403         }
06404 
06405         /* server sent some data */
06406         if(action & ACTION_ACK_SERVER_DATA)
06407         {
06408             if((p->tcph->th_flags & TH_RST) && pkt_ack == 0)
06409             {
06410                 /* Do not change where the side has seen upon a
06411                  * "nonestablished reset" */
06412                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[R] Reset Handled\n"););
06413             }
06414             else if((ssn->session_flags & SSNFLAG_CLIENT_FIN) &&
06415                     (ssn->server.next_seq + 1 == pkt_ack))
06416             {
06417                 /* Going way out of our way to avoid an off by 1. */
06418                 ssn->server.last_ack = pkt_ack - 1;
06419             }
06420             else if(SEQ_LT(ssn->server.last_ack, pkt_ack))
06421             {
06422                 ssn->server.last_ack = pkt_ack;
06423             }
06424 
06425             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "server.base_seq(%u) "
06426                         "server.last_ack(%u) server.next_seq(%u)\n",
06427                         ssn->server.base_seq,ssn->server.last_ack, 
06428                         ssn->server.next_seq););
06429 
06430             if(ssn->session_flags & SSNFLAG_ESTABLISHED)
06431             {
06432                 Stream *s;
06433 
06434                 s = &ssn->server;
06435 
06436 #ifdef GIDS
06437                 if((!s4data.stream4inline_mode && /* normal mode */
06438                         ((ssn->server.last_ack - ssn->server.base_seq) > ssn->flush_point &&
06439                         ubi_trCount(&s->data) > 1)) ||
06440                    (s4data.stream4inline_mode &&  /* inline mode */
06441                         (ssn->server.bytes_tracked > (ssn->flush_point + s4data.stream4inline_window_size)) &&
06442                         ubi_trCount(&s->data) > 1))
06443 #else
06444                 if((ssn->server.last_ack - ssn->server.base_seq) > ssn->flush_point
06445                         && ubi_trCount(&s->data) > 1)
06446 #endif /* GIDS */
06447                 {
06448                     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06449                                 "Flushing Server packet buffer "
06450                                 "(%d bytes a: 0x%X b: 0x%X)\n",
06451                                 (ssn->server.last_ack - ssn->server.base_seq),
06452                                 ssn->server.last_ack, ssn->server.base_seq););
06453 
06454                     if(s4data.reassemble_server)
06455                     {
06456 #ifdef GIDS
06457                         if(!s4data.stream4inline_mode)
06458                         {
06459 #endif /* GIDS */
06460                                 FlushStream(&ssn->server, p, REVERSE);
06461                                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "after trunc: ssn->server.base_seq(%u) = ssn->server.last_ack = %u\n", ssn->server.base_seq, ssn->server.last_ack););
06462                                 ssn->server.base_seq = ssn->server.last_ack;
06463 #ifdef GIDS
06464                         }
06465                         else
06466                                 TruncStream(&ssn->server, p);
06467 #endif /* GIDS */
06468                     }
06469                 }
06470             }
06471 #ifdef GIDS
06472             if(s4data.stream4inline_mode)
06473             {
06474                 if(ssn->server.last_ack > ssn->server.base_seq)
06475                 {
06476                     if((ssn->server.last_ack - ssn->server.base_seq) >= (2 * s4data.stream4inline_window_size))
06477                     {
06478                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,   "BASE_SEQ: server: adjusting base_seq because last_ack(%u)"
06479                                                                 "is way larger than base_seq(%u): > 2 * window_size(%d)\n",
06480                                                                 ssn->server.last_ack, ssn->server.base_seq,
06481                                                                 s4data.stream4inline_window_size););
06482 
06483                         ssn->server.base_seq = ssn->server.last_ack - s4data.stream4inline_window_size;
06484 
06485                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM,   "BASE_SEQ: base_seq is now %u\n",
06486                                                                 ssn->server.base_seq););
06487                     }
06488                 }
06489                 /* detect wrap */
06490                 else if(ssn->server.base_seq > ssn->server.last_ack)
06491                 {
06492                     /* this should only be true in case of a sequence number wrap */
06493                     if((ssn->server.base_seq - ssn->server.last_ack) > (MAX_STREAM_SIZE * 2))
06494                     {
06495                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "BASE_SEQ:(server) base_seq %u > last_ack %u, diff (%u)\n", ssn->server.base_seq, ssn->server.last_ack, ssn->server.base_seq - ssn->server.last_ack););
06496 
06497                         /* adjust base_seq to get passed the wrap */
06498                         if(((MAX_SEQ_NUM - ssn->server.base_seq) + ssn->server.last_ack) >= (2 * s4data.stream4inline_window_size))
06499                         {
06500                             ssn->server.base_seq = ssn->server.last_ack - s4data.stream4inline_window_size;
06501 
06502                             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "BASE_SEQ: base_seq is now %u\n", ssn->server.base_seq););
06503                         }
06504                         else
06505                         {
06506                             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "BASE_SEQ:(server, no wrap) base_seq %u > last_ack %u, diff (%u)\n", ssn->server.base_seq, ssn->server.last_ack, ssn->server.base_seq - ssn->server.last_ack););
06507                         }
06508                     }
06509                     else
06510                     {
06511                         DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "BASE_SEQ:(server) base_seq %u > last_ack %u\n", ssn->server.base_seq, ssn->server.last_ack););
06512                     }
06513                 }
06514             }
06515 #endif /* GIDS */
06516         }
06517 
06518         if(s4data.ps_alerts && (action & ACTION_ALERT_NMAP_FINGERPRINT))
06519         {
06520             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
06521                     STREAM4_STEALTH_NMAP_FINGERPRINT, /* SID */
06522                     1,                      /* Rev */
06523                     0,                      /* classification */
06524                     3,                      /* priority (low) */
06525                     STREAM4_STEALTH_NMAP_FINGERPRINT_STR, /* msg string */
06526                     0);
06527             return;
06528         }
06529 
06530         if(action & ACTION_FLUSH_SERVER_STREAM)
06531         {
06532             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "flushing server stream, ending "
06533                         "session: %d\n", s4data.reassemble_server););
06534 
06535             if(s4data.reassemble_server)
06536             {
06537                 if(direction == FROM_SERVER)
06538                 {
06539                     FlushStream(&ssn->server, p, NO_REVERSE);
06540                 }
06541                 else
06542                 {
06543                     FlushStream(&ssn->server, p, REVERSE);
06544                 }
06545             }
06546 
06547             p->packet_flags |= PKT_STREAM_EST;
06548         }
06549 
06550         if(action & ACTION_FLUSH_CLIENT_STREAM)
06551         {
06552             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "flushing client stream, ending "
06553                         "session\n"););
06554 
06555             if(s4data.reassemble_client)
06556             {
06557                 if(direction == FROM_CLIENT)
06558                 {
06559                     FlushStream(&ssn->client, p, NO_REVERSE);
06560                 }
06561                 else
06562                 {
06563                     FlushStream(&ssn->client, p, REVERSE);
06564                 }
06565             }
06566 
06567             p->packet_flags |= PKT_STREAM_EST;
06568         }
06569 
06570         if(action & ACTION_DROP_SESSION)
06571         {
06572             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Dumping session\n"););
06573             DeleteSession(ssn, p->pkth->ts.tv_sec);
06574             p->ssnptr = NULL;
06575         }
06576     }
06577 }
06578 
06579 static void TcpActionAsync(Session *ssn, Packet *p, int action, int direction, 
06580                            u_int32_t pkt_seq, u_int32_t pkt_ack)
06581 {
06582     if(direction == FROM_CLIENT)
06583     {
06584         if(!ssn->client.isn)
06585         {
06586             ssn->client.isn = pkt_seq;
06587         }
06588 
06589         ssn->client.last_ack = pkt_seq;
06590 
06591     }
06592     else
06593     {
06594         if(!ssn->server.isn)
06595         {
06596             ssn->server.isn = pkt_seq;
06597         }
06598 
06599         ssn->server.last_ack = pkt_seq;
06600     }
06601 
06602 
06603     if(action == ACTION_NOTHING)
06604     {
06605         return;
06606     }
06607     else 
06608     {
06609         if(action & ACTION_SET_SERVER_ISN)
06610         {
06611             ssn->server.isn = pkt_seq;
06612             ssn->client.win_size = ntohs(p->tcph->th_win);
06613 
06614             if(pkt_ack == (ssn->client.isn+1))
06615             {
06616                 ssn->client.last_ack = ssn->client.isn+1;
06617             }
06618             else
06619             {
06620                 /* we got a messed up response from the server */
06621                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06622                             "WARNING: Got unexpected SYN ACK from server!\n");
06623                         DebugMessage(DEBUG_STREAM, 
06624                             "expected: 0x%X   received: 0x%X\n"););
06625                 ssn->client.last_ack = pkt_ack;
06626             }
06627         }
06628 
06629         /* complete a three way handshake */
06630         if(action & ACTION_COMPLETE_TWH)
06631         {
06632             /*
06633             **  Set a packet flag to say that the TWH has been
06634             **  completed.
06635             */
06636             p->packet_flags |= PKT_STREAM_TWH;
06637 
06638             /* this should be isn+1 */
06639             if(pkt_ack == ssn->server.isn+1)
06640             {
06641                 ssn->server.last_ack = ssn->server.isn+1;
06642             }
06643             else
06644             {
06645                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06646                             "WARNING: Fishy TWH from client "
06647                             "(0x%X:%d->0x%X:%d) (ack: 0x%X  isn: 0x%X)\n", 
06648                             p->iph->ip_src.s_addr, p->sp, p->iph->ip_dst.s_addr, 
06649                             p->dp, pkt_ack, ssn->server.isn););
06650 
06651                 ssn->server.last_ack = pkt_ack;
06652             }
06653 
06654             ssn->server.base_seq = ssn->server.last_ack;
06655             ssn->client.base_seq = ssn->client.last_ack;
06656         }
06657 
06658         /* 
06659          * someone sent data in their SYN packet, classic sign of someone
06660          * doing bad things (or a bad ip stack/piece of equipment)
06661          */
06662         if(action & ACTION_DATA_ON_SYN)
06663         {
06664             if(p->tcph->th_flags & TH_SYN)
06665             {
06666                 /* alert... */
06667                 if(s4data.evasion_alerts)
06668                 {
06669                     SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
06670                             STREAM4_DATA_ON_SYN, /* SID */
06671                             1,                      /* Rev */
06672                             0,                      /* classification */
06673                             3,                      /* priority (low) */
06674                             STREAM4_DATA_ON_SYN_STR, /* msg string */
06675                             0);
06676                 }
06677 
06678                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06679                             "WARNING: Data on SYN packet!\n"););
06680                 return;
06681             }
06682         }
06683 
06684         if(action & ACTION_INC_PORT)
06685         {
06686             ssn->client.port++;
06687         }
06688 
06689         /* client sent some data */
06690         if(action & ACTION_ACK_CLIENT_DATA)
06691         {
06692             Stream *s;
06693 
06694             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06695                         "client.base_seq(%u) client.last_ack(%u)\n",
06696                         ssn->client.base_seq,ssn->client.last_ack););
06697 
06698             if((p->tcph->th_flags & TH_RST) && pkt_ack == 0)
06699             {
06700                 /* Do not change where the side has seen upon a
06701                  * "nonestablished reset" */
06702                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[R] Reset Handled\n"););
06703             }
06704             /* Going way out of our way to avoid an off by 1. */
06705             else if((ssn->session_flags & SSNFLAG_CLIENT_FIN) && 
06706                     (ssn->client.next_seq + 1 == pkt_ack))
06707             {
06708                 /* the fin consumes one byte of the sequence that
06709                  * really doesn't posses data */                
06710                 ssn->client.last_ack = pkt_ack - 1;
06711             }
06712             else
06713             {
06714                 ssn->client.last_ack = pkt_ack;
06715             }
06716 
06717             s = &ssn->client;
06718 
06719             if((ssn->client.last_ack - ssn->client.base_seq) > ssn->flush_point 
06720                     && ubi_trCount(&s->data) > 1)
06721             {
06722                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06723                             "Flushing Client packet buffer "
06724                             "(%d bytes a: 0x%X b: 0x%X pkts: %d)\n",
06725                             (ssn->client.last_ack - ssn->client.base_seq), 
06726                             ssn->client.last_ack, ssn->client.base_seq,
06727                             ubi_trCount(&s->data)););
06728 
06729                 if(s4data.reassemble_client)
06730                 {
06731                     FlushStream(&ssn->client, p, REVERSE);
06732                 }
06733 
06734                 ssn->client.base_seq = ssn->client.last_ack;
06735             }
06736         }
06737 
06738         /* server sent some data */
06739         if(action & ACTION_ACK_SERVER_DATA)
06740         {
06741             Stream *s;
06742 
06743             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06744                         "server.base_seq(%u) server.last_ack(%u)\n",
06745                         ssn->server.base_seq,ssn->server.last_ack););
06746 
06747             if((p->tcph->th_flags & TH_RST) && pkt_ack == 0)
06748             {
06749                 /* Do not change where the side has seen upon a
06750                  * "nonestablished reset" */
06751                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[R] Reset Handled\n"););
06752             }
06753             else if((ssn->session_flags & SSNFLAG_CLIENT_FIN) &&
06754                     (ssn->server.next_seq + 1 == pkt_ack))
06755             {
06756                 /* Going way out of our way to avoid an off by 1. */
06757                 ssn->server.last_ack = pkt_ack - 1;
06758             }
06759             else
06760             {
06761                 ssn->server.last_ack = pkt_ack;
06762             }
06763 
06764 
06765             s = &ssn->server;
06766 
06767             if((ssn->server.last_ack - ssn->server.base_seq) > ssn->flush_point
06768                     && ubi_trCount(&s->data) > 1)
06769             {
06770                 DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
06771                             "Flushing Server packet buffer "
06772                             "(%d bytes a: 0x%X b: 0x%X)\n",
06773                             (ssn->server.last_ack - ssn->server.base_seq),
06774                             ssn->server.last_ack, ssn->server.base_seq););
06775 
06776                 if(s4data.reassemble_server)
06777                 {
06778                     FlushStream(&ssn->server, p, REVERSE);
06779                 }
06780 
06781                 ssn->server.base_seq = ssn->server.last_ack;
06782             }
06783         }
06784 
06785         if(s4data.ps_alerts && (action & ACTION_ALERT_NMAP_FINGERPRINT))
06786         {
06787             SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
06788                     STREAM4_STEALTH_NMAP_FINGERPRINT, /* SID */
06789                     1,                      /* Rev */
06790                     0,                      /* classification */
06791                     3,                      /* priority (low) */
06792                     STREAM4_STEALTH_NMAP_FINGERPRINT_STR, /* msg string */
06793                     0);
06794             return;
06795         }
06796 
06797         if(action & ACTION_FLUSH_SERVER_STREAM)
06798         {
06799             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "flushing server stream, ending "
06800                         "session: %d\n", s4data.reassemble_server););
06801 
06802             if(s4data.reassemble_server)
06803             {
06804                 if(direction == FROM_SERVER)
06805                 {
06806                     FlushStream(&ssn->server, p, NO_REVERSE);
06807                 }
06808                 else
06809                 {
06810                     FlushStream(&ssn->server, p, REVERSE);
06811                 }
06812             }
06813         }
06814 
06815         if(action & ACTION_FLUSH_CLIENT_STREAM)
06816         {
06817             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "flushing client stream, ending "
06818                         "session\n"););
06819 
06820             if(s4data.reassemble_client)
06821             {
06822                 if(direction == FROM_CLIENT)
06823                 {
06824                     FlushStream(&ssn->client, p, NO_REVERSE);
06825                 }
06826                 else
06827                 {
06828                     FlushStream(&ssn->client, p, REVERSE);
06829                 }
06830             }
06831         }
06832 
06833         if(action & ACTION_DROP_SESSION)
06834         {
06835             DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Dumping session\n"););
06836             DeleteSession(ssn, p->pkth->ts.tv_sec);
06837             p->ssnptr = NULL;
06838         }
06839     }
06840 }
06841 
06842 /* version 1 is currently the only version, but hey, who knows. Maybe
06843    we need a version 2 soon. */
06844 struct parse_v1_file
06845 {
06846     char statestr[16]; /* changes should also be done in the below sscanf line */
06847 
06848     /* session */
06849     u_int32_t session_flags;
06850 
06851     u_int32_t start_time;
06852     u_int32_t last_session_time;
06853 
06854     /* client */
06855     u_int32_t c_ip;
06856     u_int16_t c_port;
06857     u_int32_t c_isn;
06858     u_int32_t c_base_seq;
06859     u_int32_t c_last_ack;
06860     u_int16_t c_win_size;
06861     u_int32_t c_pkts_sent;
06862     u_int32_t c_bytes_sent;
06863 
06864     /* server */
06865     u_int32_t s_ip;
06866     u_int16_t s_port;
06867     u_int32_t s_isn;
06868     u_int32_t s_base_seq;
06869     u_int32_t s_last_ack;
06870     u_int16_t s_win_size;
06871     u_int32_t s_pkts_sent;
06872     u_int32_t s_bytes_sent;
06873 };
06874 
06875 
06876 /* for creating a new session based on the information in the
06877    file we need to fill a Packet structure with data and pass
06878    that to GetNewSession(). */
06879 static void InitFakePkt(Packet *p)
06880 {
06881     p->pkth = calloc(sizeof(SnortPktHeader)+
06882                               ETHERNET_HEADER_LEN +
06883                               SPARC_TWIDDLE + IP_MAXPACKET,
06884                               sizeof(char));
06885 
06886     p->pkt = ((u_int8_t *)p->pkth) + sizeof(SnortPktHeader);
06887     p->eh = (EtherHdr *)((u_int8_t *)p->pkt + SPARC_TWIDDLE);
06888     p->iph =
06889         (IPHdr *)((u_int8_t *)p->eh + ETHERNET_HEADER_LEN);
06890     p->tcph = (TCPHdr *)((u_int8_t *)p->iph + IP_HEADER_LEN);
06891 
06892     p->data = (u_int8_t *)p->tcph + TCP_HEADER_LEN;
06893 
06894     /* stream_pkt->data is now pkt +
06895      *  IPMAX_PACKET - (IP_HEADER_LEN + TCP_HEADER_LEN + ETHERNET_HEADER_LEN)
06896      *  in size
06897      *
06898      * This is MAX_STREAM_SIZE
06899      */
06900 
06901     p->eh->ether_type = htons(0x0800);
06902     SET_IP_VER(p->iph, 0x4);
06903     SET_IP_HLEN(p->iph, 0x5);
06904     p->iph->ip_proto = IPPROTO_TCP;
06905     p->iph->ip_ttl   = 0xF0;
06906     p->iph->ip_len = 0x5;
06907     p->iph->ip_tos = 0x10;
06908 
06909     SET_TCP_OFFSET(p->tcph,0x5);
06910     p->tcph->th_flags = TH_PUSH|TH_ACK;
06911 }
06912 
06913 
06914 /* return 1 if parsed correctly and within timeout limit
06915    else 0
06916  */
06917 static char parse_one_v1(u_int32_t thetime, Packet *fakep, struct parse_v1_file *parse)
06918 {
06919     Session *ssn;
06920     static u_int8_t savedfpi; /* current flush point index */
06921     u_int8_t fpi;            /* flush point index */
06922 
06923     /* first check for the timeout value, so we
06924        don't add sessions that have already timed
06925        out */
06926     if(parse->last_session_time + s4data.timeout < thetime)
06927     {
06928         return 0;
06929     }
06930 
06931     parse->session_flags |= SSNFLAG_SEEN_CLIENT;
06932     parse->session_flags |= SSNFLAG_SEEN_SERVER;
06933 
06934     if(strcmp(parse->statestr, "ESTABLISHED") == 0)
06935         parse->session_flags |= SSNFLAG_ESTABLISHED;
06936     else if(strcmp(parse->statestr, "MIDSTREAM") == 0)
06937         parse->session_flags |= SSNFLAG_MIDSTREAM;
06938 
06939 #ifdef DEBUG
06940     /* status */
06941     if(parse->session_flags & SSNFLAG_ESTABLISHED)
06942         fprintf(stdout, "ESTABLISHED ");
06943     else if(parse->session_flags & SSNFLAG_MIDSTREAM)
06944         fprintf(stdout, "MIDSTREAM ");
06945     else
06946     {
06947         return 0;
06948     }
06949 
06950     /* timeout */
06951     fprintf(stdout, "%u %u ", (u_int)parse->start_time,
06952                               (u_int)parse->last_session_time);
06953 
06954     /* client */
06955     fprintf(stdout, "%u %u %u %u %u %u %u %u ",
06956         parse->c_ip, parse->c_port,
06957         parse->c_isn, parse->c_base_seq, parse->c_last_ack,
06958         parse->c_win_size, parse->c_pkts_sent, parse->c_bytes_sent);
06959 
06960     /* server */
06961     fprintf(stdout, "%u %u %u %u %u %u %u %u ",
06962         parse->s_ip, parse->s_port,
06963         parse->s_isn, parse->s_base_seq, parse->s_last_ack,
06964         parse->s_win_size, parse->s_pkts_sent, parse->s_bytes_sent);
06965 
06966     fprintf(stdout, "\n");
06967 #endif
06968 
06969     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"cip: 0x%X cp: %d sip: 0x%X sp: %d\n", 
06970         parse->c_ip, parse->c_port, parse->s_ip, parse->s_port););
06971 
06972     /* setup the fake packet so GetNewSession can create a 
06973        hash key from it.
06974                
06975        Note: we don't set the time since a the time is only
06976        used in CleanHashTable. Since we operate in a empty hash
06977        the time is not needed.
06978      */
06979     fakep->iph->ip_src.s_addr = parse->c_ip;
06980     fakep->iph->ip_dst.s_addr = parse->s_ip;
06981     fakep->tcph->th_sport = htons(parse->c_port);
06982     fakep->tcph->th_dport = htons(parse->s_port);
06983     fakep->pkth->ts.tv_sec = 0;
06984 
06985     /* Get the session and set it up. */
06986     ssn = GetNewSession(fakep);
06987 
06988     if(s4data.reassemble_server)
06989         (void)ubi_trInitTree(&ssn->server.data, /* ptr to the tree head */
06990                                DataCompareFunc, /* comparison function */
06991                                ubi_trDUPKEY);   /* allow duplicate keys */
06992     else
06993         ssn->server.data.root = NULL;
06994 
06995     if(s4data.reassemble_client)
06996         (void)ubi_trInitTree(&ssn->client.data, /* ptr to the tree head */
06997                                    DataCompareFunc, /* comparison function */
06998                                    ubi_trDUPKEY);   /* allow duplicate keys */
06999     else
07000         ssn->client.data.root = NULL;
07001 
07002     /* session */
07003     ssn->session_flags = parse->session_flags;
07004     ssn->start_time = parse->start_time;
07005     ssn->last_session_time = parse->last_session_time;
07006     /* assign a psuedo random flush point */
07007     savedfpi++;
07008     fpi = savedfpi % FCOUNT;
07009     ssn->flush_point = flush_points[fpi];
07010 
07011     /* client */
07012     ssn->client.state = ESTABLISHED;
07013     ssn->client.ip = parse->c_ip;
07014     ssn->client.port = parse->c_port;
07015     ssn->client.isn = parse->c_isn;
07016     ssn->client.base_seq = parse->c_base_seq;
07017     ssn->client.last_ack = parse->c_last_ack;
07018     ssn->client.win_size = parse->c_win_size;
07019     ssn->client.pkts_sent = parse->c_pkts_sent;
07020     ssn->client.bytes_sent = parse->c_bytes_sent;
07021 
07022     /* server */
07023     ssn->server.state = ESTABLISHED;
07024     ssn->server.ip = parse->s_ip;
07025     ssn->server.port = parse->s_port;
07026     ssn->server.isn = parse->s_isn;
07027     ssn->server.base_seq = parse->s_base_seq;
07028     ssn->server.last_ack = parse->s_last_ack;
07029     ssn->server.win_size = parse->s_win_size;
07030     ssn->server.pkts_sent = parse->s_pkts_sent;
07031     ssn->server.bytes_sent = parse->s_bytes_sent;
07032 
07033     return 1;
07034 }
07035 
07036 
07037 int LoadStateTable(const u_int32_t thetime, const char *path)
07038 {
07039     FILE *fp = NULL;
07040     char buf[512]  = "", version[16] = ""; /* if you change the length of
07041                                               version, also change it in the
07042                                               sscanf string below */
07043     int res = 0;
07044     struct parse_v1_file parse;
07045     u_int32_t loadcnt = 0;
07046     u_int32_t skipcnt = 0;
07047     Packet fakepkt;
07048 
07049     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"start\n"););
07050 
07051     /* initialization */
07052     InitFakePkt(&fakepkt);
07053     memset(&parse, 0, sizeof(parse));
07054 
07055     /* open the file. No fatal error, because the first time this option
07056        is enabled we dont have a file yet. */
07057     fp = fopen(path, "r");
07058     if(fp == NULL)
07059     {
07060         printf("Opening '%s' failed: %s.\n", path, strerror(errno));
07061         return 0;
07062     }
07063 
07064     while(fgets(buf, sizeof(buf), fp) != NULL)
07065     {
07066         if(buf[0] != '#')
07067         {
07068             /* Session part
07069                1. string state flag: ESTABLISHED or MIDSTREAM
07070                2. session start time
07071                3. session last_session_time
07072 
07073                Client part
07074                4. ip  5. port  6. isn  7. base_seq  8. last_ack  9. win_size
07075                    10. pkts_sent  11. bytes_sent
07076 
07077                Server part
07078                12. ip  13. port  14. isn  15. base_seq  16. last_ack  17. win_size
07079                    18. pkts_sent  19. bytes_sent
07080 
07081                                1    2  3  4  5   6  7  8  9   10 11 12 13  14 15 16 17  18 19 */
07082             res = sscanf(buf, "%15s %u %u %u %hu %u %u %u %hu %u %u %u %hu %u %u %u %hu %u %u",
07083                               parse.statestr, &parse.start_time, &parse.last_session_time,
07084                                   &parse.c_ip, &parse.c_port, &parse.c_isn, &parse.c_base_seq,
07085                                   &parse.c_last_ack, &parse.c_win_size, &parse.c_pkts_sent,
07086                                   &parse.c_bytes_sent,
07087 
07088                                   &parse.s_ip, &parse.s_port, &parse.s_isn, &parse.s_base_seq,
07089                                   &parse.s_last_ack, &parse.s_win_size, &parse.s_pkts_sent,
07090                                   &parse.s_bytes_sent);
07091             if(res == 19)
07092             {
07093                 if(parse_one_v1(thetime, &fakepkt, &parse) == 1)
07094                 {
07095                     pc.tcp_streams++;
07096                     loadcnt++;
07097                 }
07098                 else
07099                 {
07100                     skipcnt++;
07101                 }
07102             }
07103             else
07104             {
07105                 res = sscanf(buf, "%15s", version);
07106                 if(res == 1)
07107                 {
07108                     if(strncmp(version,"version", 7) == 0)
07109                     {
07110                         /* we dont do anything with it, but dont want
07111                            to increase skipcnt for it either */
07112                     }
07113                     else
07114                     {
07115                         skipcnt++;
07116                     }
07117                 }
07118                 else
07119                 {
07120                     skipcnt++;
07121                 }
07122             }
07123         }
07124     }
07125 
07126     fclose(fp);
07127 
07128     LogMessage("Loaded %u connections from the state file.\n", loadcnt); 
07129     
07130     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"end: loadcnt %u, skipcnt: %u, total: %u\n",
07131                             loadcnt, skipcnt, loadcnt+skipcnt););
07132     return 0;
07133 }

Generated on Sun May 14 14:51:17 2006 by  doxygen 1.4.2