From 6ee81bdd7b1d9457b1b27748153c6e376b31c3c7 Mon Sep 17 00:00:00 2001 From: robiscool Date: Fri, 21 Jan 2011 14:04:42 -0800 Subject: snort-dev, add my patches as requested by the head pfsense devs --- config/snort-dev/patches/SnortSam/TODAO.txt | 1 + .../patches/SnortSam/snortsam-2.8.6.1.diff | 3021 ++++++++++++++++++ .../snort-dev/patches/inlinemode_options_flags.txt | 0 .../patches/spoink_patch/2.8.6/Makefile.am | 17 + .../patches/spoink_patch/2.8.6/Makefile.in | 445 +++ .../patches/spoink_patch/2.8.6/plugbase.c | 1544 ++++++++++ config/snort-dev/patches/spoink_patch/2.8.6/util.c | 3233 ++++++++++++++++++++ config/snort-dev/patches/spoink_patch/spo_pf.c | 462 +++ config/snort-dev/patches/spoink_patch/spo_pf.h | 60 + 9 files changed, 8783 insertions(+) create mode 100644 config/snort-dev/patches/SnortSam/TODAO.txt create mode 100644 config/snort-dev/patches/SnortSam/snortsam-2.8.6.1.diff create mode 100644 config/snort-dev/patches/inlinemode_options_flags.txt create mode 100644 config/snort-dev/patches/spoink_patch/2.8.6/Makefile.am create mode 100644 config/snort-dev/patches/spoink_patch/2.8.6/Makefile.in create mode 100644 config/snort-dev/patches/spoink_patch/2.8.6/plugbase.c create mode 100644 config/snort-dev/patches/spoink_patch/2.8.6/util.c create mode 100644 config/snort-dev/patches/spoink_patch/spo_pf.c create mode 100644 config/snort-dev/patches/spoink_patch/spo_pf.h (limited to 'config/snort-dev/patches') diff --git a/config/snort-dev/patches/SnortSam/TODAO.txt b/config/snort-dev/patches/SnortSam/TODAO.txt new file mode 100644 index 00000000..3abf0303 --- /dev/null +++ b/config/snort-dev/patches/SnortSam/TODAO.txt @@ -0,0 +1 @@ +Patch current snort 2.9 \ No newline at end of file diff --git a/config/snort-dev/patches/SnortSam/snortsam-2.8.6.1.diff b/config/snort-dev/patches/SnortSam/snortsam-2.8.6.1.diff new file mode 100644 index 00000000..983165e1 --- /dev/null +++ b/config/snort-dev/patches/SnortSam/snortsam-2.8.6.1.diff @@ -0,0 +1,3021 @@ +Index: snort-2.8.6.1/src/twofish.c +=================================================================== +--- snort-2.8.6.1/src/twofish.c (Revision 0) ++++ snort-2.8.6.1/src/twofish.c (Revision 3) +@@ -0,0 +1,971 @@ ++/* $Id: twofish.c,v 2.1 2008/12/15 20:36:05 fknobbe Exp $ ++ * ++ * ++ * Copyright (C) 1997-2000 The Cryptix Foundation Limited. ++ * Copyright (C) 2000 Farm9. ++ * Copyright (C) 2001 Frank Knobbe. ++ * All rights reserved. ++ * ++ * For Cryptix code: ++ * Use, modification, copying and distribution of this software is subject ++ * the terms and conditions of the Cryptix General Licence. You should have ++ * received a copy of the Cryptix General Licence along with this library; ++ * if not, you can download a copy from http://www.cryptix.org/ . ++ * ++ * For Farm9: ++ * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and ++ * ciphertext stealing technique, added AsciiTwofish class for easy encryption ++ * decryption of text strings ++ * ++ * Frank Knobbe : ++ * --- April 2001, converted from C++ to C, prefixed global variables ++ * with TwoFish, substituted some defines, changed functions to make use of ++ * variables supplied in a struct, modified and added routines for modular calls. ++ * Cleaned up the code so that defines are used instead of fixed 16's and 32's. ++ * Created two general purpose crypt routines for one block and multiple block ++ * encryption using Joh's CBC code. ++ * Added crypt routines that use a header (with a magic and data length). ++ * (Basically a major rewrite). ++ * ++ * Note: Routines labeled _TwoFish are private and should not be used ++ * (or with extreme caution). ++ * ++ */ ++ ++#ifndef __TWOFISH_LIBRARY_SOURCE__ ++#define __TWOFISH_LIBRARY_SOURCE__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef WIN32 ++ ++#ifndef u_long ++typedef unsigned long u_long; ++#endif ++#ifndef u_int32_t ++typedef unsigned long u_int32_t; ++#endif ++#ifndef u_word ++typedef unsigned short u_word; ++#endif ++#ifndef u_int16_t ++typedef unsigned short u_int16_t; ++#endif ++#ifndef u_char ++typedef unsigned char u_char; ++#endif ++#ifndef u_int8_t ++typedef unsigned char u_int8_t; ++#endif ++ ++#endif /* WIN32 */ ++ ++#include "twofish.h" ++ ++ ++bool TwoFish_srand=TRUE; /* if TRUE, first call of TwoFishInit will seed rand(); */ ++ /* of TwoFishInit */ ++ ++/* Fixed 8x8 permutation S-boxes */ ++static const u_int8_t TwoFish_P[2][256] = ++{ ++ { /* p0 */ ++ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, ++ 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, ++ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, ++ 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, ++ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, ++ 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, ++ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, ++ 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, ++ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, ++ 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, ++ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, ++ 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, ++ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, ++ 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, ++ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, ++ 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, ++ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, ++ 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, ++ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, ++ 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, ++ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, ++ 0x4A, 0x5E, 0xC1, 0xE0 ++ }, ++ { /* p1 */ ++ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, ++ 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, ++ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, ++ 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, ++ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, ++ 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, ++ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, ++ 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, ++ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, ++ 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, ++ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, ++ 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, ++ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, ++ 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, ++ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, ++ 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, ++ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, ++ 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, ++ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, ++ 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, ++ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, ++ 0x55, 0x09, 0xBE, 0x91 ++ } ++}; ++ ++static bool TwoFish_MDSready=FALSE; ++static u_int32_t TwoFish_MDS[4][256]; /* TwoFish_MDS matrix */ ++ ++ ++#define TwoFish_LFSR1(x) (((x)>>1)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/2:0)) ++#define TwoFish_LFSR2(x) (((x)>>2)^(((x)&0x02)?TwoFish_MDS_GF_FDBK/2:0)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/4:0)) ++ ++#define TwoFish_Mx_1(x) ((u_int32_t)(x)) /* force result to dword so << will work */ ++#define TwoFish_Mx_X(x) ((u_int32_t)((x)^TwoFish_LFSR2(x))) /* 5B */ ++#define TwoFish_Mx_Y(x) ((u_int32_t)((x)^TwoFish_LFSR1(x)^TwoFish_LFSR2(x))) /* EF */ ++#define TwoFish_RS_rem(x) { u_int8_t b=(u_int8_t)(x>>24); u_int32_t g2=((b<<1)^((b&0x80)?TwoFish_RS_GF_FDBK:0))&0xFF; u_int32_t g3=((b>>1)&0x7F)^((b&1)?TwoFish_RS_GF_FDBK>>1:0)^g2; x=(x<<8)^(g3<<24)^(g2<<16)^(g3<<8)^b; } ++ ++/*#define TwoFish__b(x,N) (((u_int8_t *)&x)[((N)&3)^TwoFish_ADDR_XOR])*/ /* pick bytes out of a dword */ ++ ++#define TwoFish_b0(x) TwoFish__b(x,0) /* extract LSB of u_int32_t */ ++#define TwoFish_b1(x) TwoFish__b(x,1) ++#define TwoFish_b2(x) TwoFish__b(x,2) ++#define TwoFish_b3(x) TwoFish__b(x,3) /* extract MSB of u_int32_t */ ++ ++u_int8_t TwoFish__b(u_int32_t x,int n) ++{ n&=3; ++ while(n-->0) ++ x>>=8; ++ return (u_int8_t)x; ++} ++ ++ ++/* TwoFish Initialization ++ * ++ * This routine generates a global data structure for use with TwoFish, ++ * initializes important values (such as subkeys, sBoxes), generates subkeys ++ * and precomputes the MDS matrix if not already done. ++ * ++ * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!') ++ * ++ * Output: Pointer to TWOFISH structure. This data structure contains key dependent data. ++ * This pointer is used with all other crypt functions. ++ */ ++ ++TWOFISH *TwoFishInit(char *userkey) ++{ TWOFISH *tfdata; ++ int i,x,m; ++ char tkey[TwoFish_KEY_LENGTH+40]; ++ ++ tfdata=malloc(sizeof(TWOFISH)); /* allocate the TwoFish structure */ ++ if(tfdata!=NULL) ++ { if(*userkey) ++ { strncpy(tkey,userkey,TwoFish_KEY_LENGTH); /* use first 32 chars of user supplied password */ ++ tkey[TwoFish_KEY_LENGTH]=0; /* make sure it wasn't more */ ++ } ++ else ++ strcpy(tkey,TwoFish_DEFAULT_PW); /* if no key defined, use default password */ ++ for(i=0,x=0,m=strlen(tkey);ikey[i]=tkey[x++]; /* fill the whole keyspace with repeating key. */ ++ if(x==m) ++ x=0; ++ } ++ ++ if(!TwoFish_MDSready) ++ _TwoFish_PrecomputeMDSmatrix(); /* "Wake Up, Neo" */ ++ _TwoFish_MakeSubKeys(tfdata); /* generate subkeys */ ++ _TwoFish_ResetCBC(tfdata); /* reset the CBC */ ++ tfdata->output=NULL; /* nothing to output yet */ ++ tfdata->dontflush=FALSE; /* reset decrypt skip block flag */ ++ if(TwoFish_srand) ++ { TwoFish_srand=FALSE; ++ srand(time(NULL)); ++ } ++ } ++ return tfdata; /* return the data pointer */ ++} ++ ++ ++void TwoFishDestroy(TWOFISH *tfdata) ++{ if(tfdata!=NULL) ++ free(tfdata); ++} ++ ++ ++/* en/decryption with CBC mode */ ++unsigned long _TwoFish_CryptRawCBC(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata) ++{ unsigned long rl; ++ ++ rl=len; /* remember how much data to crypt. */ ++ while(len>TwoFish_BLOCK_SIZE) /* and now we process block by block. */ ++ { _TwoFish_BlockCrypt(in,out,TwoFish_BLOCK_SIZE,decrypt,tfdata); /* de/encrypt it. */ ++ in+=TwoFish_BLOCK_SIZE; /* adjust pointers. */ ++ out+=TwoFish_BLOCK_SIZE; ++ len-=TwoFish_BLOCK_SIZE; ++ } ++ if(len>0) /* if we have less than a block left... */ ++ _TwoFish_BlockCrypt(in,out,len,decrypt,tfdata); /* ...then we de/encrypt that too. */ ++ if(tfdata->qBlockDefined && !tfdata->dontflush) /* in case len was exactly one block... */ ++ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); /* ...we need to write the... */ ++ /* ...remaining bytes of the buffer */ ++ return rl; ++} ++ ++/* en/decryption on one block only */ ++unsigned long _TwoFish_CryptRaw16(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata) ++{ /* qBlockPlain already zero'ed through ResetCBC */ ++ memcpy(tfdata->qBlockPlain,in,len); /* toss the data into it. */ ++ _TwoFish_BlockCrypt16(tfdata->qBlockPlain,tfdata->qBlockCrypt,decrypt,tfdata); /* encrypt just that block without CBC. */ ++ memcpy(out,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE); /* and return what we got */ ++ return TwoFish_BLOCK_SIZE; ++} ++ ++/* en/decryption without reset of CBC and output assignment */ ++unsigned long _TwoFish_CryptRaw(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata) ++{ ++ if(in!=NULL && out!=NULL && len>0 && tfdata!=NULL) /* if we have valid data, then... */ ++ { if(len>TwoFish_BLOCK_SIZE) /* ...check if we have more than one block. */ ++ return _TwoFish_CryptRawCBC(in,out,len,decrypt,tfdata); /* if so, use the CBC routines... */ ++ else ++ return _TwoFish_CryptRaw16(in,out,len,decrypt,tfdata); /* ...otherwise just do one block. */ ++ } ++ return 0; ++} ++ ++ ++/* TwoFish Raw Encryption ++ * ++ * Does not use header, but does use CBC (if more than one block has to be encrypted). ++ * ++ * Input: Pointer to the buffer of the plaintext to be encrypted. ++ * Pointer to the buffer receiving the ciphertext. ++ * The length of the plaintext buffer. ++ * The TwoFish structure. ++ * ++ * Output: The amount of bytes encrypted if successful, otherwise 0. ++ */ ++ ++unsigned long TwoFishEncryptRaw(char *in, ++ char *out, ++ unsigned long len, ++ TWOFISH *tfdata) ++{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */ ++ tfdata->output=out; /* output straight into output buffer. */ ++ return _TwoFish_CryptRaw(in,out,len,FALSE,tfdata); /* and go for it. */ ++} ++ ++/* TwoFish Raw Decryption ++ * ++ * Does not use header, but does use CBC (if more than one block has to be decrypted). ++ * ++ * Input: Pointer to the buffer of the ciphertext to be decrypted. ++ * Pointer to the buffer receiving the plaintext. ++ * The length of the ciphertext buffer (at least one cipher block). ++ * The TwoFish structure. ++ * ++ * Output: The amount of bytes decrypted if successful, otherwise 0. ++ */ ++ ++unsigned long TwoFishDecryptRaw(char *in, ++ char *out, ++ unsigned long len, ++ TWOFISH *tfdata) ++{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */ ++ tfdata->output=out; /* output straight into output buffer. */ ++ return _TwoFish_CryptRaw(in,out,len,TRUE,tfdata); /* and go for it. */ ++} ++ ++/* TwoFish Free ++ * ++ * Free's the allocated buffer. ++ * ++ * Input: Pointer to the TwoFish structure ++ * ++ * Output: (none) ++ */ ++ ++void TwoFishFree(TWOFISH *tfdata) ++{ if(tfdata->output!=NULL) /* if a valid buffer is present... */ ++ { free(tfdata->output); /* ...then we free it for you... */ ++ tfdata->output=NULL; /* ...and mark as such. */ ++ } ++} ++ ++/* TwoFish Set Output ++ * ++ * If you want to allocate the output buffer yourself, ++ * then you can set it with this function. ++ * ++ * Input: Pointer to your output buffer ++ * Pointer to the TwoFish structure ++ * ++ * Output: (none) ++ */ ++ ++void TwoFishSetOutput(char *outp,TWOFISH *tfdata) ++{ tfdata->output=outp; /* (do we really need a function for this?) */ ++} ++ ++/* TwoFish Alloc ++ * ++ * Allocates enough memory for the output buffer that would be required ++ * ++ * Input: Length of the plaintext. ++ * Boolean flag for BinHex Output. ++ * Pointer to the TwoFish structure. ++ * ++ * Output: Returns a pointer to the memory allocated. ++ */ ++ ++void *TwoFishAlloc(unsigned long len,bool binhex,bool decrypt,TWOFISH *tfdata) ++{ ++/* TwoFishFree(tfdata); */ /* (don't for now) discard whatever was allocated earlier. */ ++ if(decrypt) /* if decrypting... */ ++ { if(binhex) /* ...and input is binhex encoded... */ ++ len/=2; /* ...use half as much for output. */ ++ len-=TwoFish_BLOCK_SIZE; /* Also, subtract the size of the header. */ ++ } ++ else ++ { len+=TwoFish_BLOCK_SIZE; /* the size is just increased by the header... */ ++ if(binhex) ++ len*=2; /* ...and doubled if output is to be binhexed. */ ++ } ++ tfdata->output=malloc(len+TwoFish_BLOCK_SIZE);/* grab some memory...plus some extra (it's running over somewhere, crashes without extra padding) */ ++ ++ return tfdata->output; /* ...and return to caller. */ ++} ++ ++/* bin2hex and hex2bin conversion */ ++void _TwoFish_BinHex(u_int8_t *buf,unsigned long len,bool bintohex) ++{ u_int8_t *pi,*po,c; ++ ++ if(bintohex) ++ { for(pi=buf+len-1,po=buf+(2*len)-1;len>0;pi--,po--,len--) /* let's start from the end of the bin block. */ ++ { c=*pi; /* grab value. */ ++ c&=15; /* use lower 4 bits. */ ++ if(c>9) /* convert to ascii. */ ++ c+=('a'-10); ++ else ++ c+='0'; ++ *po--=c; /* set the lower nibble. */ ++ c=*pi; /* grab value again. */ ++ c>>=4; /* right shift 4 bits. */ ++ c&=15; /* make sure we only have 4 bits. */ ++ if(c>9) /* convert to ascii. */ ++ c+=('a'-10); ++ else ++ c+='0'; ++ *po=c; /* set the higher nibble. */ ++ } /* and keep going. */ ++ } ++ else ++ { for(pi=buf,po=buf;len>0;pi++,po++,len-=2) /* let's start from the beginning of the hex block. */ ++ { c=tolower(*pi++)-'0'; /* grab higher nibble. */ ++ if(c>9) /* convert to value. */ ++ c-=('0'-9); ++ *po=c<<4; /* left shit 4 bits. */ ++ c=tolower(*pi)-'0'; /* grab lower nibble. */ ++ if(c>9) /* convert to value. */ ++ c-=('0'-9); ++ *po|=c; /* and add to value. */ ++ } ++ } ++} ++ ++ ++/* TwoFish Encryption ++ * ++ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, ++ * this routine will alloc the memory. In addition, it will include a small 'header' ++ * containing the magic and some salt. That way the decrypt routine can check if the ++ * packet got decrypted successfully, and return 0 instead of garbage. ++ * ++ * Input: Pointer to the buffer of the plaintext to be encrypted. ++ * Pointer to the pointer to the buffer receiving the ciphertext. ++ * The pointer either points to user allocated output buffer space, or to NULL, in which case ++ * this routine will set the pointer to the buffer allocated through the struct. ++ * The length of the plaintext buffer. ++ * Can be -1 if the input is a null terminated string, in which case we'll count for you. ++ * Boolean flag for BinHex Output (if used, output will be twice as large as input). ++ * Note: BinHex conversion overwrites (converts) input buffer! ++ * The TwoFish structure. ++ * ++ * Output: The amount of bytes encrypted if successful, otherwise 0. ++ */ ++ ++unsigned long TwoFishEncrypt(char *in, ++ char **out, ++ signed long len, ++ bool binhex, ++ TWOFISH *tfdata) ++{ unsigned long ilen,olen; ++ ++ ++ if(len== -1) /* if we got -1 for len, we'll assume IN is a... */ ++ ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */ ++ else ++ ilen=len; /* ...otherwise we trust you supply a correct length. */ ++ ++ if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */ ++ { if(*out==NULL) /* if OUT points to a NULL pointer... */ ++ *out=TwoFishAlloc(ilen,binhex,FALSE,tfdata); /* ...we'll (re-)allocate buffer space. */ ++ if(*out!=NULL) ++ { tfdata->output=*out; /* set output buffer. */ ++ tfdata->header.salt=rand()*65536+rand(); /* toss in some salt. */ ++ tfdata->header.length[0]= (u_int8_t)(ilen); ++ tfdata->header.length[1]= (u_int8_t)(ilen>>8); ++ tfdata->header.length[2]= (u_int8_t)(ilen>>16); ++ tfdata->header.length[3]= (u_int8_t)(ilen>>24); ++ memcpy(tfdata->header.magic,TwoFish_MAGIC,TwoFish_MAGIC_LEN); /* set the magic. */ ++ olen=TwoFish_BLOCK_SIZE; /* set output counter. */ ++ _TwoFish_ResetCBC(tfdata); /* reset the CBC flag */ ++ _TwoFish_BlockCrypt((u_int8_t *)&(tfdata->header),*out,olen,FALSE,tfdata); /* encrypt first block (without flush on 16 byte boundary). */ ++ olen+=_TwoFish_CryptRawCBC(in,*out+TwoFish_BLOCK_SIZE,ilen,FALSE,tfdata); /* and encrypt the rest (we do not reset the CBC flag). */ ++ if(binhex) /* if binhex... */ ++ { _TwoFish_BinHex(*out,olen,TRUE); /* ...convert output to binhex... */ ++ olen*=2; /* ...and size twice as large. */ ++ } ++ tfdata->output=*out; ++ return olen; ++ } ++ } ++ return 0; ++} ++ ++/* TwoFish Decryption ++ * ++ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, ++ * this routine will alloc the memory. In addition, it will check the small 'header' ++ * containing the magic. If magic does not match we return 0. Otherwise we return the ++ * amount of bytes decrypted (should be the same as the length in the header). ++ * ++ * Input: Pointer to the buffer of the ciphertext to be decrypted. ++ * Pointer to the pointer to the buffer receiving the plaintext. ++ * The pointer either points to user allocated output buffer space, or to NULL, in which case ++ * this routine will set the pointer to the buffer allocated through the struct. ++ * The length of the ciphertext buffer. ++ * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you. ++ * Boolean flag for BinHex Input (if used, plaintext will be half as large as input). ++ * Note: BinHex conversion overwrites (converts) input buffer! ++ * The TwoFish structure. ++ * ++ * Output: The amount of bytes decrypted if successful, otherwise 0. ++ */ ++ ++unsigned long TwoFishDecrypt(char *in, ++ char **out, ++ signed long len, ++ bool binhex, ++ TWOFISH *tfdata) ++{ unsigned long ilen,elen,olen; ++ const u_int8_t cmagic[TwoFish_MAGIC_LEN]=TwoFish_MAGIC; ++ u_int8_t *tbuf; ++ ++ ++ ++ if(len== -1) /* if we got -1 for len, we'll assume IN is... */ ++ ilen=strlen(in); /* ...\0 terminated binhex and figure len out ourselves... */ ++ else ++ ilen=len; /* ...otherwise we trust you supply a correct length. */ ++ ++ if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */ ++ { if(*out==NULL) /* if OUT points to a NULL pointer... */ ++ *out=TwoFishAlloc(ilen,binhex,TRUE,tfdata); /* ...we'll (re-)allocate buffer space. */ ++ if(*out!=NULL) ++ { if(binhex) /* if binhex... */ ++ { _TwoFish_BinHex(in,ilen,FALSE); /* ...convert input to values... */ ++ ilen/=2; /* ...and size half as much. */ ++ } ++ _TwoFish_ResetCBC(tfdata); /* reset the CBC flag. */ ++ ++ tbuf=(u_int8_t *)malloc(ilen+TwoFish_BLOCK_SIZE); /* get memory for data and header. */ ++ if(tbuf==NULL) ++ return 0; ++ tfdata->output=tbuf; /* set output to temp buffer. */ ++ ++ olen=_TwoFish_CryptRawCBC(in,tbuf,ilen,TRUE,tfdata)-TwoFish_BLOCK_SIZE; /* decrypt the whole thing. */ ++ memcpy(&(tfdata->header),tbuf,TwoFish_BLOCK_SIZE); /* copy first block into header. */ ++ tfdata->output=*out; ++ for(elen=0;elenheader.magic[elen]!=cmagic[elen]) ++ break; ++ if(elen==TwoFish_MAGIC_LEN) /* if magic matches then... */ ++ { elen=(tfdata->header.length[0]) | ++ (tfdata->header.length[1])<<8 | ++ (tfdata->header.length[2])<<16 | ++ (tfdata->header.length[3])<<24; /* .. we know how much to expect. */ ++ if(elen>olen) /* adjust if necessary. */ ++ elen=olen; ++ memcpy(*out,tbuf+TwoFish_BLOCK_SIZE,elen); /* copy data into intended output. */ ++ free(tbuf); ++ return elen; ++ } ++ free(tbuf); ++ } ++ } ++ return 0; ++} ++ ++void _TwoFish_PrecomputeMDSmatrix(void) /* precompute the TwoFish_MDS matrix */ ++{ u_int32_t m1[2]; ++ u_int32_t mX[2]; ++ u_int32_t mY[2]; ++ u_int32_t i, j; ++ ++ for (i = 0; i < 256; i++) ++ { j = TwoFish_P[0][i] & 0xFF; /* compute all the matrix elements */ ++ m1[0] = j; ++ mX[0] = TwoFish_Mx_X( j ) & 0xFF; ++ mY[0] = TwoFish_Mx_Y( j ) & 0xFF; ++ ++ j = TwoFish_P[1][i] & 0xFF; ++ m1[1] = j; ++ mX[1] = TwoFish_Mx_X( j ) & 0xFF; ++ mY[1] = TwoFish_Mx_Y( j ) & 0xFF; ++ ++ TwoFish_MDS[0][i] = m1[TwoFish_P_00] | /* fill matrix w/ above elements */ ++ mX[TwoFish_P_00] << 8 | ++ mY[TwoFish_P_00] << 16 | ++ mY[TwoFish_P_00] << 24; ++ TwoFish_MDS[1][i] = mY[TwoFish_P_10] | ++ mY[TwoFish_P_10] << 8 | ++ mX[TwoFish_P_10] << 16 | ++ m1[TwoFish_P_10] << 24; ++ TwoFish_MDS[2][i] = mX[TwoFish_P_20] | ++ mY[TwoFish_P_20] << 8 | ++ m1[TwoFish_P_20] << 16 | ++ mY[TwoFish_P_20] << 24; ++ TwoFish_MDS[3][i] = mX[TwoFish_P_30] | ++ m1[TwoFish_P_30] << 8 | ++ mY[TwoFish_P_30] << 16 | ++ mX[TwoFish_P_30] << 24; ++ } ++ TwoFish_MDSready=TRUE; ++} ++ ++ ++void _TwoFish_MakeSubKeys(TWOFISH *tfdata) /* Expand a user-supplied key material into a session key. */ ++{ u_int32_t k64Cnt = TwoFish_KEY_LENGTH / 8; ++ u_int32_t k32e[4]; /* even 32-bit entities */ ++ u_int32_t k32o[4]; /* odd 32-bit entities */ ++ u_int32_t sBoxKey[4]; ++ u_int32_t offset,i,j; ++ u_int32_t A, B, q=0; ++ u_int32_t k0,k1,k2,k3; ++ u_int32_t b0,b1,b2,b3; ++ ++ /* split user key material into even and odd 32-bit entities and */ ++ /* compute S-box keys using (12, 8) Reed-Solomon code over GF(256) */ ++ ++ ++ for (offset=0,i=0,j=k64Cnt-1;i<4 && offsetkey[offset++]; ++ k32e[i]|= tfdata->key[offset++]<<8; ++ k32e[i]|= tfdata->key[offset++]<<16; ++ k32e[i]|= tfdata->key[offset++]<<24; ++ k32o[i] = tfdata->key[offset++]; ++ k32o[i]|= tfdata->key[offset++]<<8; ++ k32o[i]|= tfdata->key[offset++]<<16; ++ k32o[i]|= tfdata->key[offset++]<<24; ++ sBoxKey[j] = _TwoFish_RS_MDS_Encode( k32e[i], k32o[i] ); /* reverse order */ ++ } ++ ++ /* compute the round decryption subkeys for PHT. these same subkeys */ ++ /* will be used in encryption but will be applied in reverse order. */ ++ i=0; ++ while(i < TwoFish_TOTAL_SUBKEYS) ++ { A = _TwoFish_F32( k64Cnt, q, k32e ); /* A uses even key entities */ ++ q += TwoFish_SK_BUMP; ++ ++ B = _TwoFish_F32( k64Cnt, q, k32o ); /* B uses odd key entities */ ++ q += TwoFish_SK_BUMP; ++ ++ B = B << 8 | B >> 24; ++ ++ A += B; ++ tfdata->subKeys[i++] = A; /* combine with a PHT */ ++ ++ A += B; ++ tfdata->subKeys[i++] = A << TwoFish_SK_ROTL | A >> (32-TwoFish_SK_ROTL); ++ } ++ ++ /* fully expand the table for speed */ ++ k0 = sBoxKey[0]; ++ k1 = sBoxKey[1]; ++ k2 = sBoxKey[2]; ++ k3 = sBoxKey[3]; ++ ++ for (i = 0; i < 256; i++) ++ { b0 = b1 = b2 = b3 = i; ++ switch (k64Cnt & 3) ++ { case 1: /* 64-bit keys */ ++ tfdata->sBox[ 2*i ] = TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0]) ^ TwoFish_b0(k0)]; ++ tfdata->sBox[ 2*i+1] = TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1]) ^ TwoFish_b1(k0)]; ++ tfdata->sBox[0x200+2*i ] = TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2]) ^ TwoFish_b2(k0)]; ++ tfdata->sBox[0x200+2*i+1] = TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3]) ^ TwoFish_b3(k0)]; ++ break; ++ case 0: /* 256-bit keys (same as 4) */ ++ b0 = (TwoFish_P[TwoFish_P_04][b0]) ^ TwoFish_b0(k3); ++ b1 = (TwoFish_P[TwoFish_P_14][b1]) ^ TwoFish_b1(k3); ++ b2 = (TwoFish_P[TwoFish_P_24][b2]) ^ TwoFish_b2(k3); ++ b3 = (TwoFish_P[TwoFish_P_34][b3]) ^ TwoFish_b3(k3); ++ case 3: /* 192-bit keys */ ++ b0 = (TwoFish_P[TwoFish_P_03][b0]) ^ TwoFish_b0(k2); ++ b1 = (TwoFish_P[TwoFish_P_13][b1]) ^ TwoFish_b1(k2); ++ b2 = (TwoFish_P[TwoFish_P_23][b2]) ^ TwoFish_b2(k2); ++ b3 = (TwoFish_P[TwoFish_P_33][b3]) ^ TwoFish_b3(k2); ++ case 2: /* 128-bit keys */ ++ tfdata->sBox[ 2*i ]= ++ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0]) ^ ++ TwoFish_b0(k1)]) ^ TwoFish_b0(k0)]; ++ ++ tfdata->sBox[ 2*i+1]= ++ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1]) ^ ++ TwoFish_b1(k1)]) ^ TwoFish_b1(k0)]; ++ ++ tfdata->sBox[0x200+2*i ]= ++ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2]) ^ ++ TwoFish_b2(k1)]) ^ TwoFish_b2(k0)]; ++ ++ tfdata->sBox[0x200+2*i+1]= ++ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3]) ^ ++ TwoFish_b3(k1)]) ^ TwoFish_b3(k0)]; ++ } ++ } ++} ++ ++ ++/** ++ * Encrypt or decrypt exactly one block of plaintext in CBC mode. ++ * Use "ciphertext stealing" technique described on pg. 196 ++ * of "Applied Cryptography" to encrypt the final partial ++ * (i.e. <16 byte) block if necessary. ++ * ++ * jojo: the "ciphertext stealing" requires we read ahead and have ++ * special handling for the last two blocks. Because of this, the ++ * output from the TwoFish algorithm is handled internally here. ++ * It would be better to have a higher level handle this as well as ++ * CBC mode. Unfortunately, I've mixed the two together, which is ++ * pretty crappy... The Java version separates these out correctly. ++ * ++ * fknobbe: I have reduced the CBC mode to work on memory buffer only. ++ * Higher routines should use an intermediate buffer and handle ++ * their output seperately (mainly so the data can be flushed ++ * in one chunk, not seperate 16 byte blocks...) ++ * ++ * @param in The plaintext. ++ * @param out The ciphertext ++ * @param size how much to encrypt ++ * @param tfdata: Pointer to the global data structure containing session keys. ++ * @return none ++ */ ++void _TwoFish_BlockCrypt(u_int8_t *in,u_int8_t *out,unsigned long size,int decrypt,TWOFISH *tfdata) ++{ u_int8_t PnMinusOne[TwoFish_BLOCK_SIZE]; ++ u_int8_t CnMinusOne[TwoFish_BLOCK_SIZE]; ++ u_int8_t CBCplusCprime[TwoFish_BLOCK_SIZE]; ++ u_int8_t Pn[TwoFish_BLOCK_SIZE]; ++ u_int8_t *p,*pout; ++ unsigned long i; ++ ++ /* here is where we implement CBC mode and cipher block stealing */ ++ if(size==TwoFish_BLOCK_SIZE) ++ { /* if we are encrypting, CBC means we XOR the plain text block with the */ ++ /* previous cipher text block before encrypting */ ++ if(!decrypt && tfdata->qBlockDefined) ++ { for(p=in,i=0;iqBlockCrypt[i]; /* FK: I'm copying the xor'ed input into Pn... */ ++ } ++ else ++ memcpy(Pn,in,TwoFish_BLOCK_SIZE); /* FK: same here. we work of Pn all the time. */ ++ ++ /* TwoFish block level encryption or decryption */ ++ _TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata); ++ ++ /* if we are decrypting, CBC means we XOR the result of the decryption */ ++ /* with the previous cipher text block to get the resulting plain text */ ++ if(decrypt && tfdata->qBlockDefined) ++ { for (p=out,i=0;iqBlockPlain[i]; ++ } ++ ++ /* save the input and output blocks, since CBC needs these for XOR */ ++ /* operations */ ++ _TwoFish_qBlockPush(Pn,out,tfdata); ++ } ++ else ++ { /* cipher block stealing, we are at Pn, */ ++ /* but since Cn-1 must now be replaced with CnC' */ ++ /* we pop it off, and recalculate Cn-1 */ ++ ++ if(decrypt) ++ { /* We are on an odd block, and had to do cipher block stealing, */ ++ /* so the PnMinusOne has to be derived differently. */ ++ ++ /* First we decrypt it into CBC and C' */ ++ _TwoFish_qBlockPop(CnMinusOne,PnMinusOne,tfdata); ++ _TwoFish_BlockCrypt16(CnMinusOne,CBCplusCprime,decrypt,tfdata); ++ ++ /* we then xor the first few bytes with the "in" bytes (Cn) */ ++ /* to recover Pn, which we put in out */ ++ for(p=in,pout=out,i=0;iprevCipher[i]; ++ ++ /* So at this point, out has PnMinusOne */ ++ _TwoFish_qBlockPush(CnMinusOne,PnMinusOne,tfdata); ++ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); ++ _TwoFish_FlushOutput(out,size,tfdata); ++ } ++ else ++ { _TwoFish_qBlockPop(PnMinusOne,CnMinusOne,tfdata); ++ memset(Pn,0,TwoFish_BLOCK_SIZE); ++ memcpy(Pn,in,size); ++ for(i=0;iqBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); ++ _TwoFish_FlushOutput(CnMinusOne,size,tfdata); /* old Cn-1 becomes new partial Cn */ ++ } ++ tfdata->qBlockDefined=FALSE; ++ } ++} ++ ++void _TwoFish_qBlockPush(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata) ++{ if(tfdata->qBlockDefined) ++ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); ++ memcpy(tfdata->prevCipher,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE); ++ memcpy(tfdata->qBlockPlain,p,TwoFish_BLOCK_SIZE); ++ memcpy(tfdata->qBlockCrypt,c,TwoFish_BLOCK_SIZE); ++ tfdata->qBlockDefined=TRUE; ++} ++ ++void _TwoFish_qBlockPop(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata) ++{ memcpy(p,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE ); ++ memcpy(c,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE ); ++ tfdata->qBlockDefined=FALSE; ++} ++ ++/* Reset's the CBC flag and zero's PrevCipher (through qBlockPlain) (important) */ ++void _TwoFish_ResetCBC(TWOFISH *tfdata) ++{ tfdata->qBlockDefined=FALSE; ++ memset(tfdata->qBlockPlain,0,TwoFish_BLOCK_SIZE); ++} ++ ++void _TwoFish_FlushOutput(u_int8_t *b,unsigned long len,TWOFISH *tfdata) ++{ unsigned long i; ++ ++ for(i=0;idontflush;i++) ++ *tfdata->output++ = *b++; ++ tfdata->dontflush=FALSE; ++} ++ ++void _TwoFish_BlockCrypt16(u_int8_t *in,u_int8_t *out,bool decrypt,TWOFISH *tfdata) ++{ u_int32_t x0,x1,x2,x3; ++ u_int32_t k,t0,t1,R; ++ ++ ++ x0=*in++; ++ x0|=(*in++ << 8 ); ++ x0|=(*in++ << 16); ++ x0|=(*in++ << 24); ++ x1=*in++; ++ x1|=(*in++ << 8 ); ++ x1|=(*in++ << 16); ++ x1|=(*in++ << 24); ++ x2=*in++; ++ x2|=(*in++ << 8 ); ++ x2|=(*in++ << 16); ++ x2|=(*in++ << 24); ++ x3=*in++; ++ x3|=(*in++ << 8 ); ++ x3|=(*in++ << 16); ++ x3|=(*in++ << 24); ++ ++ if(decrypt) ++ { x0 ^= tfdata->subKeys[4]; /* swap input and output whitening keys when decrypting */ ++ x1 ^= tfdata->subKeys[5]; ++ x2 ^= tfdata->subKeys[6]; ++ x3 ^= tfdata->subKeys[7]; ++ ++ k = 7+(TwoFish_ROUNDS*2); ++ for (R = 0; R < TwoFish_ROUNDS; R += 2) ++ { t0 = _TwoFish_Fe320( tfdata->sBox, x0); ++ t1 = _TwoFish_Fe323( tfdata->sBox, x1); ++ x3 ^= t0 + (t1<<1) + tfdata->subKeys[k--]; ++ x3 = x3 >> 1 | x3 << 31; ++ x2 = x2 << 1 | x2 >> 31; ++ x2 ^= t0 + t1 + tfdata->subKeys[k--]; ++ ++ t0 = _TwoFish_Fe320( tfdata->sBox, x2); ++ t1 = _TwoFish_Fe323( tfdata->sBox, x3); ++ x1 ^= t0 + (t1<<1) + tfdata->subKeys[k--]; ++ x1 = x1 >> 1 | x1 << 31; ++ x0 = x0 << 1 | x0 >> 31; ++ x0 ^= t0 + t1 + tfdata->subKeys[k--]; ++ } ++ ++ x2 ^= tfdata->subKeys[0]; ++ x3 ^= tfdata->subKeys[1]; ++ x0 ^= tfdata->subKeys[2]; ++ x1 ^= tfdata->subKeys[3]; ++ } ++ else ++ { x0 ^= tfdata->subKeys[0]; ++ x1 ^= tfdata->subKeys[1]; ++ x2 ^= tfdata->subKeys[2]; ++ x3 ^= tfdata->subKeys[3]; ++ ++ k = 8; ++ for (R = 0; R < TwoFish_ROUNDS; R += 2) ++ { t0 = _TwoFish_Fe320( tfdata->sBox, x0); ++ t1 = _TwoFish_Fe323( tfdata->sBox, x1); ++ x2 ^= t0 + t1 + tfdata->subKeys[k++]; ++ x2 = x2 >> 1 | x2 << 31; ++ x3 = x3 << 1 | x3 >> 31; ++ x3 ^= t0 + (t1<<1) + tfdata->subKeys[k++]; ++ ++ t0 = _TwoFish_Fe320( tfdata->sBox, x2); ++ t1 = _TwoFish_Fe323( tfdata->sBox, x3); ++ x0 ^= t0 + t1 + tfdata->subKeys[k++]; ++ x0 = x0 >> 1 | x0 << 31; ++ x1 = x1 << 1 | x1 >> 31; ++ x1 ^= t0 + (t1<<1) + tfdata->subKeys[k++]; ++ } ++ ++ x2 ^= tfdata->subKeys[4]; ++ x3 ^= tfdata->subKeys[5]; ++ x0 ^= tfdata->subKeys[6]; ++ x1 ^= tfdata->subKeys[7]; ++ } ++ ++ *out++ = (u_int8_t)(x2 ); ++ *out++ = (u_int8_t)(x2 >> 8); ++ *out++ = (u_int8_t)(x2 >> 16); ++ *out++ = (u_int8_t)(x2 >> 24); ++ ++ *out++ = (u_int8_t)(x3 ); ++ *out++ = (u_int8_t)(x3 >> 8); ++ *out++ = (u_int8_t)(x3 >> 16); ++ *out++ = (u_int8_t)(x3 >> 24); ++ ++ *out++ = (u_int8_t)(x0 ); ++ *out++ = (u_int8_t)(x0 >> 8); ++ *out++ = (u_int8_t)(x0 >> 16); ++ *out++ = (u_int8_t)(x0 >> 24); ++ ++ *out++ = (u_int8_t)(x1 ); ++ *out++ = (u_int8_t)(x1 >> 8); ++ *out++ = (u_int8_t)(x1 >> 16); ++ *out++ = (u_int8_t)(x1 >> 24); ++} ++ ++/** ++ * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box ++ * 32-bit entity from two key material 32-bit entities. ++ * ++ * @param k0 1st 32-bit entity. ++ * @param k1 2nd 32-bit entity. ++ * @return Remainder polynomial generated using RS code ++ */ ++u_int32_t _TwoFish_RS_MDS_Encode(u_int32_t k0,u_int32_t k1) ++{ u_int32_t i,r; ++ ++ for(r=k1,i=0;i<4;i++) /* shift 1 byte at a time */ ++ TwoFish_RS_rem(r); ++ r ^= k0; ++ for(i=0;i<4;i++) ++ TwoFish_RS_rem(r); ++ ++ return r; ++} ++ ++u_int32_t _TwoFish_F32(u_int32_t k64Cnt,u_int32_t x,u_int32_t *k32) ++{ u_int8_t b0,b1,b2,b3; ++ u_int32_t k0,k1,k2,k3,result = 0; ++ ++ b0=TwoFish_b0(x); ++ b1=TwoFish_b1(x); ++ b2=TwoFish_b2(x); ++ b3=TwoFish_b3(x); ++ k0=k32[0]; ++ k1=k32[1]; ++ k2=k32[2]; ++ k3=k32[3]; ++ ++ switch (k64Cnt & 3) ++ { case 1: /* 64-bit keys */ ++ result = ++ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0] & 0xFF) ^ TwoFish_b0(k0)] ^ ++ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1] & 0xFF) ^ TwoFish_b1(k0)] ^ ++ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2] & 0xFF) ^ TwoFish_b2(k0)] ^ ++ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3] & 0xFF) ^ TwoFish_b3(k0)]; ++ break; ++ case 0: /* 256-bit keys (same as 4) */ ++ b0 = (TwoFish_P[TwoFish_P_04][b0] & 0xFF) ^ TwoFish_b0(k3); ++ b1 = (TwoFish_P[TwoFish_P_14][b1] & 0xFF) ^ TwoFish_b1(k3); ++ b2 = (TwoFish_P[TwoFish_P_24][b2] & 0xFF) ^ TwoFish_b2(k3); ++ b3 = (TwoFish_P[TwoFish_P_34][b3] & 0xFF) ^ TwoFish_b3(k3); ++ ++ case 3: /* 192-bit keys */ ++ b0 = (TwoFish_P[TwoFish_P_03][b0] & 0xFF) ^ TwoFish_b0(k2); ++ b1 = (TwoFish_P[TwoFish_P_13][b1] & 0xFF) ^ TwoFish_b1(k2); ++ b2 = (TwoFish_P[TwoFish_P_23][b2] & 0xFF) ^ TwoFish_b2(k2); ++ b3 = (TwoFish_P[TwoFish_P_33][b3] & 0xFF) ^ TwoFish_b3(k2); ++ case 2: /* 128-bit keys (optimize for this case) */ ++ result = ++ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0] & 0xFF) ^ TwoFish_b0(k1)] & 0xFF) ^ TwoFish_b0(k0)] ^ ++ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1] & 0xFF) ^ TwoFish_b1(k1)] & 0xFF) ^ TwoFish_b1(k0)] ^ ++ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2] & 0xFF) ^ TwoFish_b2(k1)] & 0xFF) ^ TwoFish_b2(k0)] ^ ++ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3] & 0xFF) ^ TwoFish_b3(k1)] & 0xFF) ^ TwoFish_b3(k0)]; ++ break; ++ } ++ return result; ++} ++ ++u_int32_t _TwoFish_Fe320(u_int32_t *lsBox,u_int32_t x) ++{ return lsBox[ TwoFish_b0(x)<<1 ]^ ++ lsBox[ ((TwoFish_b1(x)<<1)|1)]^ ++ lsBox[0x200+ (TwoFish_b2(x)<<1) ]^ ++ lsBox[0x200+((TwoFish_b3(x)<<1)|1)]; ++} ++ ++u_int32_t _TwoFish_Fe323(u_int32_t *lsBox,u_int32_t x) ++{ return lsBox[ (TwoFish_b3(x)<<1) ]^ ++ lsBox[ ((TwoFish_b0(x)<<1)|1)]^ ++ lsBox[0x200+ (TwoFish_b1(x)<<1) ]^ ++ lsBox[0x200+((TwoFish_b2(x)<<1)|1)]; ++} ++ ++u_int32_t _TwoFish_Fe32(u_int32_t *lsBox,u_int32_t x,u_int32_t R) ++{ return lsBox[ 2*TwoFish__b(x,R ) ]^ ++ lsBox[ 2*TwoFish__b(x,R+1)+1]^ ++ lsBox[0x200+2*TwoFish__b(x,R+2) ]^ ++ lsBox[0x200+2*TwoFish__b(x,R+3)+1]; ++} ++ ++ ++#endif + +Index: snort-2.8.6.1/src/twofish.h +=================================================================== +--- snort-2.8.6.1/src/twofish.h (Revision 0) ++++ snort-2.8.6.1/src/twofish.h (Revision 3) +@@ -0,0 +1,276 @@ ++/* $Id: twofish.h,v 2.1 2008/12/15 20:36:05 fknobbe Exp $ ++ * ++ * ++ * Copyright (C) 1997-2000 The Cryptix Foundation Limited. ++ * Copyright (C) 2000 Farm9. ++ * Copyright (C) 2001 Frank Knobbe. ++ * All rights reserved. ++ * ++ * For Cryptix code: ++ * Use, modification, copying and distribution of this software is subject ++ * the terms and conditions of the Cryptix General Licence. You should have ++ * received a copy of the Cryptix General Licence along with this library; ++ * if not, you can download a copy from http://www.cryptix.org/ . ++ * ++ * For Farm9: ++ * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and ++ * ciphertext stealing technique, added AsciiTwofish class for easy encryption ++ * decryption of text strings ++ * ++ * Frank Knobbe : ++ * --- April 2001, converted from C++ to C, prefixed global variables ++ * with TwoFish, substituted some defines, changed functions to make use of ++ * variables supplied in a struct, modified and added routines for modular calls. ++ * Cleaned up the code so that defines are used instead of fixed 16's and 32's. ++ * Created two general purpose crypt routines for one block and multiple block ++ * encryption using Joh's CBC code. ++ * Added crypt routines that use a header (with a magic and data length). ++ * (Basically a major rewrite). ++ * ++ * Note: Routines labeled _TwoFish are private and should not be used ++ * (or with extreme caution). ++ * ++ */ ++ ++#ifndef __TWOFISH_LIBRARY_HEADER__ ++#define __TWOFISH_LIBRARY_HEADER__ ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++#ifndef TRUE ++#define TRUE !FALSE ++#endif ++#ifndef bool ++#define bool int ++#endif ++ ++ ++/* Constants */ ++ ++#define TwoFish_DEFAULT_PW "SnortHas2FishEncryptionRoutines!" /* default password (not more than 32 chars) */ ++#define TwoFish_MAGIC "TwoFish" /* to indentify a successful decryption */ ++ ++enum ++{ TwoFish_KEY_SIZE = 256, /* Valid values: 64, 128, 192, 256 */ ++ /* User 256, other key sizes have not been tested. */ ++ /* (But should work. I substituted as much as */ ++ /* I could with this define.) */ ++ TwoFish_ROUNDS = 16, ++ TwoFish_BLOCK_SIZE = 16, /* bytes in a data-block */ ++ TwoFish_KEY_LENGTH = TwoFish_KEY_SIZE/8, /* 32= 256-bit key */ ++ TwoFish_TOTAL_SUBKEYS = 4+4+2*TwoFish_ROUNDS, ++ TwoFish_MAGIC_LEN = TwoFish_BLOCK_SIZE-8, ++ TwoFish_SK_BUMP = 0x01010101, ++ TwoFish_SK_ROTL = 9, ++ TwoFish_P_00 = 1, ++ TwoFish_P_01 = 0, ++ TwoFish_P_02 = 0, ++ TwoFish_P_03 = TwoFish_P_01 ^ 1, ++ TwoFish_P_04 = 1, ++ TwoFish_P_10 = 0, ++ TwoFish_P_11 = 0, ++ TwoFish_P_12 = 1, ++ TwoFish_P_13 = TwoFish_P_11 ^ 1, ++ TwoFish_P_14 = 0, ++ TwoFish_P_20 = 1, ++ TwoFish_P_21 = 1, ++ TwoFish_P_22 = 0, ++ TwoFish_P_23 = TwoFish_P_21 ^ 1, ++ TwoFish_P_24 = 0, ++ TwoFish_P_30 = 0, ++ TwoFish_P_31 = 1, ++ TwoFish_P_32 = 1, ++ TwoFish_P_33 = TwoFish_P_31 ^ 1, ++ TwoFish_P_34 = 1, ++ TwoFish_GF256_FDBK = 0x169, ++ TwoFish_GF256_FDBK_2 = 0x169 / 2, ++ TwoFish_GF256_FDBK_4 = 0x169 / 4, ++ TwoFish_RS_GF_FDBK = 0x14D, /* field generator */ ++ TwoFish_MDS_GF_FDBK = 0x169 /* primitive polynomial for GF(256) */ ++}; ++ ++ ++/* Global data structure for callers */ ++ ++typedef struct ++{ u_int32_t sBox[4 * 256]; /* Key dependent S-box */ ++ u_int32_t subKeys[TwoFish_TOTAL_SUBKEYS]; /* Subkeys */ ++ u_int8_t key[TwoFish_KEY_LENGTH]; /* Encryption Key */ ++ u_int8_t *output; /* Pointer to output buffer */ ++ u_int8_t qBlockPlain[TwoFish_BLOCK_SIZE]; /* Used by CBC */ ++ u_int8_t qBlockCrypt[TwoFish_BLOCK_SIZE]; ++ u_int8_t prevCipher[TwoFish_BLOCK_SIZE]; ++ struct /* Header for crypt functions. Has to be at least one block long. */ ++ { u_int32_t salt; /* Random salt in first block (will salt the rest through CBC) */ ++ u_int8_t length[4]; /* The amount of data following the header */ ++ u_int8_t magic[TwoFish_MAGIC_LEN]; /* Magic to identify successful decryption */ ++ } header; ++ bool qBlockDefined; ++ bool dontflush; ++} TWOFISH; ++ ++#ifndef __TWOFISH_LIBRARY_SOURCE__ ++ ++extern bool TwoFish_srand; /* if set to TRUE (default), first call of TwoFishInit will seed rand(); */ ++ /* call of TwoFishInit */ ++#endif ++ ++ ++/**** Public Functions ****/ ++ ++/* TwoFish Initialization ++ * ++ * This routine generates a global data structure for use with TwoFish, ++ * initializes important values (such as subkeys, sBoxes), generates subkeys ++ * and precomputes the MDS matrix if not already done. ++ * ++ * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!') ++ * ++ * Output: Pointer to TWOFISH structure. This data structure contains key dependent data. ++ * This pointer is used with all other crypt functions. ++ */ ++TWOFISH *TwoFishInit(char *userkey); ++ ++ ++/* TwoFish Destroy ++ * ++ * Nothing else but a free... ++ * ++ * Input: Pointer to the TwoFish structure. ++ * ++ */ ++void TwoFishDestroy(TWOFISH *tfdata); ++ ++ ++/* TwoFish Alloc ++ * ++ * Allocates enough memory for the output buffer as required. ++ * ++ * Input: Length of the plaintext. ++ * Boolean flag for BinHex Output. ++ * Pointer to the TwoFish structure. ++ * ++ * Output: Returns a pointer to the memory allocated. ++ */ ++void *TwoFishAlloc(unsigned long len,bool binhex,bool decrypt,TWOFISH *tfdata); ++ ++ ++/* TwoFish Free ++ * ++ * Free's the allocated buffer. ++ * ++ * Input: Pointer to the TwoFish structure ++ * ++ * Output: (none) ++ */ ++void TwoFishFree(TWOFISH *tfdata); ++ ++ ++/* TwoFish Set Output ++ * ++ * If you want to allocate the output buffer yourself, ++ * then you can set it with this function. ++ * ++ * Input: Pointer to your output buffer ++ * Pointer to the TwoFish structure ++ * ++ * Output: (none) ++ */ ++void TwoFishSetOutput(char *outp,TWOFISH *tfdata); ++ ++ ++/* TwoFish Raw Encryption ++ * ++ * Does not use header, but does use CBC (if more than one block has to be encrypted). ++ * ++ * Input: Pointer to the buffer of the plaintext to be encrypted. ++ * Pointer to the buffer receiving the ciphertext. ++ * The length of the plaintext buffer. ++ * The TwoFish structure. ++ * ++ * Output: The amount of bytes encrypted if successful, otherwise 0. ++ */ ++unsigned long TwoFishEncryptRaw(char *in,char *out,unsigned long len,TWOFISH *tfdata); ++ ++/* TwoFish Raw Decryption ++ * ++ * Does not use header, but does use CBC (if more than one block has to be decrypted). ++ * ++ * Input: Pointer to the buffer of the ciphertext to be decrypted. ++ * Pointer to the buffer receiving the plaintext. ++ * The length of the ciphertext buffer (at least one cipher block). ++ * The TwoFish structure. ++ * ++ * Output: The amount of bytes decrypted if successful, otherwise 0. ++ */ ++unsigned long TwoFishDecryptRaw(char *in,char *out,unsigned long len,TWOFISH *tfdata); ++ ++ ++/* TwoFish Encryption ++ * ++ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, ++ * this routine will alloc the memory. In addition, it will include a small 'header' ++ * containing the magic and some salt. That way the decrypt routine can check if the ++ * packet got decrypted successfully, and return 0 instead of garbage. ++ * ++ * Input: Pointer to the buffer of the plaintext to be encrypted. ++ * Pointer to the pointer to the buffer receiving the ciphertext. ++ * The pointer either points to user allocated output buffer space, or to NULL, in which case ++ * this routine will set the pointer to the buffer allocated through the struct. ++ * The length of the plaintext buffer. ++ * Can be -1 if the input is a null terminated string, in which case we'll count for you. ++ * Boolean flag for BinHex Output (if used, output will be twice as large as input). ++ * Note: BinHex conversion overwrites (converts) input buffer! ++ * The TwoFish structure. ++ * ++ * Output: The amount of bytes encrypted if successful, otherwise 0. ++ */ ++unsigned long TwoFishEncrypt(char *in,char **out,signed long len,bool binhex,TWOFISH *tfdata); ++ ++ ++/* TwoFish Decryption ++ * ++ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, ++ * this routine will alloc the memory. In addition, it will check the small 'header' ++ * containing the magic. If magic does not match we return 0. Otherwise we return the ++ * amount of bytes decrypted (should be the same as the length in the header). ++ * ++ * Input: Pointer to the buffer of the ciphertext to be decrypted. ++ * Pointer to the pointer to the buffer receiving the plaintext. ++ * The pointer either points to user allocated output buffer space, or to NULL, in which case ++ * this routine will set the pointer to the buffer allocated through the struct. ++ * The length of the ciphertext buffer. ++ * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you. ++ * Boolean flag for BinHex Input (if used, plaintext will be half as large as input). ++ * Note: BinHex conversion overwrites (converts) input buffer! ++ * The TwoFish structure. ++ * ++ * Output: The amount of bytes decrypted if successful, otherwise 0. ++ */ ++unsigned long TwoFishDecrypt(char *in,char **out,signed long len,bool binhex,TWOFISH *tfdata); ++ ++ ++/**** Private Functions ****/ ++ ++u_int8_t TwoFish__b(u_int32_t x,int n); ++void _TwoFish_BinHex(u_int8_t *buf,unsigned long len,bool bintohex); ++unsigned long _TwoFish_CryptRawCBC(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata); ++unsigned long _TwoFish_CryptRaw16(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata); ++unsigned long _TwoFish_CryptRaw(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata); ++void _TwoFish_PrecomputeMDSmatrix(void); ++void _TwoFish_MakeSubKeys(TWOFISH *tfdata); ++void _TwoFish_qBlockPush(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata); ++void _TwoFish_qBlockPop(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata); ++void _TwoFish_ResetCBC(TWOFISH *tfdata); ++void _TwoFish_FlushOutput(u_int8_t *b,unsigned long len,TWOFISH *tfdata); ++void _TwoFish_BlockCrypt(u_int8_t *in,u_int8_t *out,unsigned long size,int decrypt,TWOFISH *tfdata); ++void _TwoFish_BlockCrypt16(u_int8_t *in,u_int8_t *out,bool decrypt,TWOFISH *tfdata); ++u_int32_t _TwoFish_RS_MDS_Encode(u_int32_t k0,u_int32_t k1); ++u_int32_t _TwoFish_F32(u_int32_t k64Cnt,u_int32_t x,u_int32_t *k32); ++u_int32_t _TwoFish_Fe320(u_int32_t *lsBox,u_int32_t x); ++u_int32_t _TwoFish_Fe323(u_int32_t *lsBox,u_int32_t x); ++u_int32_t _TwoFish_Fe32(u_int32_t *lsBox,u_int32_t x,u_int32_t R); ++ ++ ++#endif + +Index: snort-2.8.6.1/src/plugin_enum.h +=================================================================== +--- snort-2.8.6.1/src/plugin_enum.h (Revision 1) ++++ snort-2.8.6.1/src/plugin_enum.h (Revision 3) +@@ -60,6 +60,7 @@ + PLUGIN_URILEN_CHECK, + PLUGIN_DYNAMIC, + PLUGIN_FLOWBIT, ++ PLUGIN_FWSAM, + PLUGIN_MAX /* sentinel value */ + }; + +Index: snort-2.8.6.1/src/fatal.h +=================================================================== +--- snort-2.8.6.1/src/fatal.h (Revision 0) ++++ snort-2.8.6.1/src/fatal.h (Revision 3) +@@ -0,0 +1,40 @@ ++/* $Id$ */ ++/* ++** Copyright (C) 2002-2008 Sourcefire, Inc. ++** Copyright (C) 1998-2002 Martin Roesch ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License Version 2 as ++** published by the Free Software Foundation. You may not use, modify or ++** distribute this program under any other version of the GNU General ++** Public License. ++** ++** This program is distributed in the hope that it will be useful, ++** but WITHOUT ANY WARRANTY; without even the implied warranty of ++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++** GNU General Public License for more details. ++** ++** You should have received a copy of the GNU General Public License ++** along with this program; if not, write to the Free Software ++** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++*/ ++ ++#ifndef __FATAL_H__ ++#define __FATAL_H__ ++ ++ ++/* ++ * in debugging mode print out the filename and the line number where the ++ * failure have occured ++ */ ++ ++ ++#ifdef DEBUG ++ #define FATAL(msg) { printf("%s:%d: ", __FILE__, __LINE__); FatalError( (char *) msg); } ++#else ++ #define FATAL(msg) FatalError( (char *) msg) ++#endif ++ ++ ++ ++#endif /* __FATAL_H__ */ + +Index: snort-2.8.6.1/src/output-plugins/spo_alert_fwsam.c +=================================================================== +--- snort-2.8.6.1/src/output-plugins/spo_alert_fwsam.c (Revision 0) ++++ snort-2.8.6.1/src/output-plugins/spo_alert_fwsam.c (Revision 3) +@@ -0,0 +1,1380 @@ ++/* $id: snortpatchb,v 1.2 2002/10/26 03:32:35 fknobbe Exp $ ++** ++** spo_alert_fwsam.c ++** ++** Copyright (c) 2001-2004 Frank Knobbe ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** ++** This program is distributed in the hope that it will be useful, ++** but WITHOUT ANY WARRANTY; without even the implied warranty of ++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++** GNU General Public License for more details. ++** ++** You should have received a copy of the GNU General Public License ++** along with this program; if not, write to the Free Software ++** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++*/ ++ ++/* ++ * Purpose: ++ * ++ * This module sends alerts to a remote service on a host running SnortSam ++ * (the agent) which will block the intruding IP address on a variety of ++ * host and network firewalls. ++ * ++ * SnortSam also performs checks against a white-list of never-to-be-blocked IP addresses, ++ * can override block durations (for example for known proxies), and can detect attack conditions ++ * where too many blocks are received within a defined interval. If an attack is detected ++ * it will unblock the last x blocks and wait for the attack to end. ++ * ++ * See the SnortSam documentation for more information. ++ * ++ * ++ * Output Plugin Parameters: ++ *************************** ++ * ++ * output alert_fwsam: :/ ++ * ++ * : The IP address or host name of the host running SnortSam. ++ * : The port the remote SnortSam service listens on (default 898). ++ * : The key used for authentication (encryption really) ++ * of the communication to the remote service. ++ * ++ * Examples: ++ * ++ * output alert_fwsam: snortsambox/idspassword ++ * output alert_fwsam: fw1.domain.tld:898/mykey ++ * output alert_fwsam: 192.168.0.1/borderfw 192.168.1.254/wanfw ++ * ++ * ++ * Rule Options: ++ *************** ++ * ++ * fwsam: who[how],time; ++ * ++ * who: src, source, dst, dest, destination ++ * IP address to be blocked according to snort rule (some rules ++ * are reversed, i.e. homenet -> any [and you want to block any]). ++ * src denotes IP to the left of -> and dst denotes IP to the right ++ * ++ * how: Optional. In, out, src, dest, either, both, this, conn, connection ++ * Tells FW-1 to block packets INcoming from host, OUTgoing to host, ++ * EITHERway, or only THIS connection (IP/Service pair). ++ * See 'fw sam' for more information. May be ignored by other plugins. ++ * ++ * time: Duration of block in seconds. (Accepts 'days', 'months', 'weeks', ++ * 'years', 'minutes', 'seconds', 'hours'. Alternatively, a value of ++ * 0, or the keyword PERManent, INFinite, or ALWAYS, will block the ++ * host permanently. Be careful with this! ++ * Tells FW-1 (and others) how long to inhibit packets from the host. ++ * ++ * Examples: ++ * ++ * fwsam: src[either],15min; ++ * or dst[in], 2 days 4 hours ++ * or src, 1 hour ++ * ++ * (default: src[either],5min) ++ * ++ * ++ * Effect: ++ * ++ * Alerts are sent to the remote SnortSam services on Firewall-1 Management Stations ++ * or other hosts running SnortSam (as required for Cisco Routers and PIX). ++ * The remote services will invoke the SAM configuration via the fw sam ++ * command line, or by sending a packet to the SAM port 18183, or by using the official ++ * OPSEC API calls, or by telnetting into Cisco routers or PIX firewalls. ++ * The communication over the network is encrypted using two-fish. ++ * (Implementation ripped from CryptCat by Farm9 with permission.) ++ * ++ * Future Plans: ++ * ++ * - Custom alert trigger per rule (x alerts in y secs) --> Seems to exist in Snort 1.9 now. ++ * - Enable/Allow tagged fwsam: arguments to provide different values to ++ * different stations. --> Seems to be accomplished with custom rule-types ++ * ++ * ++ * Comments: ++ * ++ * It seem that above wishes can be implemented with todays setup. Feedback concerning ++ * these is greatly appreciated. ++ * ++*/ ++ ++ ++#include "spo_alert_fwsam.h" ++#include "twofish.h" ++/* external globals from rules.c */ ++extern char *file_name; ++extern int file_line; ++extern OptTreeNode *otn_tmp; ++extern char *snort_conf_dir; /* extern PV pv; */ ++ ++ ++/* my globals */ ++ ++FWsamList *FWsamStationList=NULL; /* Global (for all alert-types) list of snortsam stations */ ++FWsamOptions *FWsamOptionField=NULL; ++unsigned long FWsamMaxOptions=0; ++ ++ ++/* ++ * Function: AlertFWsamSetup() ++ * ++ * Purpose: Registers the output plugin keyword and initialization ++ * function into the output plugin list. This is the function that ++ * gets called from InitOutputPlugins() in plugbase.c. ++ * It also registers itself as a plugin in order to parse every rule ++ * and to set the appropiate flags from fwsam: option. ++ * ++ * Arguments: None. ++ * ++ * Returns: void function ++ * ++*/ ++void AlertFWsamSetup(void) ++{ ++ /* link the preprocessor keyword to the init function in ++ the preproc list */ ++ RegisterOutputPlugin("alert_fwsam", OUTPUT_TYPE_FLAG__ALERT, AlertFWsamInit); ++ RegisterRuleOption("fwsam", AlertFWsamOptionInit, NULL, OPT_TYPE_ACTION, NULL); ++ ++#ifdef FWSAMDEBUG /* This allows debugging of fwsam only */ ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamSetup) Output plugin is plugged in...\n"); ++#endif ++} ++ ++ ++/* This function checks if a given snortsam station is already in ++ * a given list. ++*/ ++int FWsamStationExists(FWsamStation *who,FWsamList *list) ++{ ++ while(list) ++ { ++ if(list->station) { ++// if( who->stationip.s_addr==list->station->stationip.s_addr && ++ if(IP_EQUALITY(&who->stationip, &list->station->stationip) && ++ who->stationport==list->station->stationport) ++ return TRUE; ++ } ++ list=list->next; ++ } ++ return FALSE; ++} ++ ++/* ++ * Function: AlertFWsamInit(char *args) ++ * ++ * Purpose: Calls the argument parsing function, performs final setup on data ++ * structs, links the preproc function into the function list. ++ * ++ * Arguments: args => ptr to argument string ++ * ++ * Returns: void function ++ * ++*/ ++void AlertFWsamInit(char *args) ++{ char *ap; ++ unsigned long statip,cnt,again,i; ++ char *stathost,*statport,*statpass; ++ FWsamStation *station; ++ FWsamList *fwsamlist=NULL; /* alert-type dependent list of snortsam stations */ ++ FWsamList *listp,*newlistp; ++ struct hostent *hoste; ++ char buf[1024]=""; ++ FILE *fp; ++ FWsamOptions tempopt; ++ ++#ifdef FWSAMDEBUG ++ unsigned long hostcnt=0; ++ ++ ++ ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Output plugin initializing...\n"); ++#endif ++ ++ /* pv.alert_plugin_active = 1; */ ++ ++ /* parse the argument list from the rules file */ ++ ++ if(args == NULL) ++ FatalError("ERROR %s (%d) => [Alert_FWsam](AlertFWsamInit) No arguments to alert_fwsam preprocessor!\n", file_name, file_line); ++ ++ if(!FWsamOptionField && !FWsamMaxOptions) ++ { strncpy(buf,snort_conf_dir,sizeof(buf)-1); ++ strncpy(buf+strlen(buf),SID_MAPFILE,sizeof(buf)-strlen(buf)-1); ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamSetup) Using file: %s\n",buf); ++#endif ++ fp=fopen(buf,"rt"); ++ if(!fp) ++ { strncpy(buf,snort_conf_dir,sizeof(buf)-1); ++ strncpy(buf+strlen(buf),SID_ALT_MAPFILE,sizeof(buf)-strlen(buf)-1); ++ fp=fopen(buf,"rt"); ++ } ++ if(fp) /* Check for presence of map file and read those in, sorted. */ ++ { LogMessage("INFO => [Alert_FWsam](AlertFWsamSetup) Using sid-map file: %s\n",buf); ++ ++ while(FWsamReadLine(buf,sizeof(buf),fp)) ++ if(*buf) ++ FWsamMaxOptions++; ++ if(FWsamMaxOptions) ++ { if((FWsamOptionField=(FWsamOptions *)malloc(sizeof(FWsamOptions)*FWsamMaxOptions))==NULL) ++ FatalError("ERROR => [Alert_FWsam](AlertFWsamSetup) malloc failed for OptionField!\n"); ++ fseek(fp,0,SEEK_SET); ++ for(cnt=0;cnt1) ++ { for(again=TRUE,cnt=FWsamMaxOptions-1;cnt>=1 && again;cnt--) ++ { for(again=FALSE,i=0;iFWsamOptionField[i+1].sid) ++ { memcpy(&tempopt,&(FWsamOptionField[i]),sizeof(FWsamOptions)); ++ memcpy(&(FWsamOptionField[i]),&(FWsamOptionField[i+1]),sizeof(FWsamOptions)); ++ memcpy(&(FWsamOptionField[i+1]),&tempopt,sizeof(FWsamOptions)); ++ again=TRUE; ++ } ++ } ++ } ++ } ++ } ++ else ++ FWsamMaxOptions=1; ++ fclose(fp); ++ } ++ else ++ FWsamMaxOptions=1; ++ } ++ ++ ++ ap=args; /* start at the beginning of the argument */ ++ while(*ap && isspace(*ap)) ap++; ++ while(*ap) ++ { stathost=ap; /* first argument should be host */ ++ statport=NULL; ++ statpass=NULL; ++ while(*ap && *ap!=':' && *ap!='/' && !isspace(*ap)) ap++; /* find token */ ++ switch(*ap) ++ { case ':': *ap++=0; /* grab the port */ ++ statport=ap; ++ while(*ap && *ap!='/' && !isspace(*ap)) ap++; ++ if(*ap!='/') ++ break; ++ case '/': *ap++=0; /* grab the key */ ++ statpass=ap; ++ while(*ap && !isspace(*ap)) ap++; ++ default: break; ++ } ++ if(*ap) ++ { *ap++=0; ++ while(isspace(*ap)) ap++; ++ } ++ /* now we have the first host with port and password (key) */ ++ /* next we check for valid/blank password/port */ ++ if(statpass!=NULL) ++ if(!*statpass) ++ statpass=NULL; ++ if(statport!=NULL) ++ if(!*statport) ++ statport=NULL; ++ statip=0; ++ /* now we check if a valid host was specified */ ++ if(inet_addr(stathost)==INADDR_NONE) ++ { hoste=gethostbyname(stathost); ++ if (!hoste) ++ LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWsamInit) Unable to resolve host '%s'!\n",file_name,file_line,stathost); ++ else ++ statip=*(unsigned long *)hoste->h_addr; ++ } ++ else ++ { statip=inet_addr(stathost); ++ if(!statip) ++ LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWsamInit) Invalid host address '%s'!\n",file_name,file_line,stathost); ++ } ++ if(statip) ++ { /* groovie, a valid host. Let's alloc and assemble the structure for it. */ ++ if((station=(FWsamStation *)malloc(sizeof(FWsamStation)))==NULL) ++ FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for station!\n"); ++ ++// station->stationip.s_addr=statip; /* the IP address */ ++ station->stationip.ip32[0] = statip; /* the IP address */ ++ if(statport!=NULL && atoi(statport)>0) /* if the user specified one */ ++ station->stationport=atoi(statport); /* use users setting */ ++ else ++ station->stationport=FWSAM_DEFAULTPORT; /* set the default port */ ++ ++ if(statpass!=NULL) /* if specified by user */ ++ strncpy(station->stationkey,statpass,TwoFish_KEY_LENGTH); /* use defined key */ ++ else ++ station->stationkey[0]=0; ++ station->stationkey[TwoFish_KEY_LENGTH]=0; /* make sure it's terminated. (damn strncpy...) */ ++ ++ strcpy(station->initialkey,station->stationkey); ++ station->stationfish=TwoFishInit(station->stationkey); ++ ++ station->localsocketaddr.sin_port=htons(0); /* let's use dynamic ports for now */ ++ station->localsocketaddr.sin_addr.s_addr=0; ++ station->localsocketaddr.sin_family=AF_INET; ++ station->stationsocketaddr.sin_port=htons(station->stationport); ++ //station->stationsocketaddr.sin_addr=station->stationip; ++ station->stationsocketaddr.sin_addr.s_addr=station->stationip.ip32[0]; ++ station->stationsocketaddr.sin_family=AF_INET; /* load all socket crap and keep for later */ ++ ++ do ++ station->myseqno=rand(); /* the seqno this host will use */ ++ while(station->myseqno<20 || station->myseqno>65500); ++ station->mykeymod[0]=rand(); ++ station->mykeymod[1]=rand(); ++ station->mykeymod[2]=rand(); ++ station->mykeymod[3]=rand(); ++ station->stationseqno=0; /* peer hasn't answered yet. */ ++ ++ ++ if(!FWsamStationExists(station,FWsamStationList)) /* If we don't have the station already in global list....*/ ++ { if(FWsamCheckIn(station)) /* ...and we can talk to the agent... */ ++ { if((newlistp=(FWsamList *)malloc(sizeof(FWsamList)))==NULL) ++ FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for global newlistp!\n"); ++ newlistp->station=station; ++ newlistp->next=NULL; ++ ++ if(!FWsamStationList) /* ... add it to the global list/ */ ++ FWsamStationList=newlistp; ++ else ++ { listp=FWsamStationList; ++ while(listp->next) ++ listp=listp->next; ++ listp->next=newlistp; ++ } ++ } ++ else ++ { TwoFishDestroy(station->stationfish); /* if not, we trash it. */ ++ free(station); ++ station=NULL; ++ } ++ } ++#ifdef FWSAMDEBUG ++ else ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Host %s:%i already in global list, skipping CheckIn.\n", sfip_ntoa(&station->stationip),station->stationport); ++#endif ++ ++ if(station) ++ { if(!FWsamStationExists(station,fwsamlist)) /* If we don't have the station already in local list....*/ ++ { if((newlistp=(FWsamList *)malloc(sizeof(FWsamList)))==NULL) ++ FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for local newlistp!\n"); ++ newlistp->station=station; ++ newlistp->next=NULL; ++ ++ if(!fwsamlist) /* ... add it to the local list/ */ ++ fwsamlist=newlistp; ++ else ++ { listp=fwsamlist; ++ while(listp->next) ++ listp=listp->next; ++ listp->next=newlistp; ++ } ++ } ++ ++#ifdef FWSAMDEBUG ++ else ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Host %s:%i already in local list, skipping.\n",sfip_ntoa(&station->stationip),station->stationport); ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) #%i: Host %s [%s] port %i password %s\n",++hostcnt,stathost,sfip_ntoa(&station->stationip),station->stationport,station->stationkey); ++#endif ++ } ++ ++ } ++ } /* next one */ ++ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Linking fwsam alert function to call list...\n"); ++#endif ++ ++ /* Set the preprocessor function into the function list */ ++ AddFuncToOutputList(AlertFWsam, OUTPUT_TYPE_FLAG__ALERT, fwsamlist); ++ AddFuncToCleanExitList(AlertFWsamCleanExitFunc, fwsamlist); ++ AddFuncToRestartList(AlertFWsamRestartFunc, fwsamlist); ++} ++ ++ ++/* This routine reads in a str from a file, snips white-spaces ++ * off the front and back, removes comments, and pretties the ++ * string. Returns true or false if a line was read or not. ++*/ ++int FWsamReadLine(char *buf,unsigned long bufsize,FILE *fp) ++{ char *p; ++ ++ if(fgets(buf,bufsize-1,fp)) ++ { buf[bufsize-1]=0; ++ ++#ifdef FWSAMDEBUG_off ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamReadLine) Line: %s\n",buf); ++#endif ++ ++ p=buf; ++ while(isspace(*p)) ++ p++; ++ if(p>buf); ++ strcpy(buf,p); ++ if(*buf) ++ { p=buf+strlen(buf)-1; /* remove leading and trailing spaces */ ++ while(isspace(*p)) ++ *p-- =0; ++ } ++ p=buf; ++ if(*p=='#' || *p==';') ++ *p=0; ++ else ++ p++; ++ while(*p) /* remove inline comments (except escaped #'s and ;'s) */ ++ { if(*p=='#' || *p==';') ++ { if(*(p-1)=='\\') ++ strcpy(p-1,p); ++ else ++ *p=0; ++ } ++ else ++ p++; ++ } ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++ ++/* Parses the duration of the argument, recognizing minutes, hours, etc.. ++*/ ++unsigned long FWsamParseDuration(char *p) ++{ unsigned long dur=0,tdu; ++ char *tok,c1,c2; ++ ++ while(*p) ++ { tok=p; ++ while(*p && isdigit(*p)) ++ p++; ++ if(*p) ++ { c1=tolower(*p); ++ *p=0; ++ p++; ++ if(*p && !isdigit(*p)) ++ { c2=tolower(*p++); ++ while(*p && !isdigit(*p)) ++ p++; ++ } ++ else ++ c2=0; ++ tdu=atol(tok); ++ switch(c1) ++ { case 'm': if(c2=='o') /* month */ ++ tdu*=(60*60*24*30); /* use 30 days */ ++ else ++ tdu*=60; /* minutes */ ++ case 's': break; /* seconds */ ++ case 'h': tdu*=(60*60); /* hours */ ++ break; ++ case 'd': tdu*=(60*60*24); /* days */ ++ break; ++ case 'w': tdu*=(60*60*24*7); /* week */ ++ break; ++ case 'y': tdu*=(60*60*24*365); /* year */ ++ break; ++ } ++ dur+=tdu; ++ } ++ else ++ dur+=atol(tok); ++ } ++ ++ return dur; ++} ++ ++ ++/* This routine parses an option line. It is called by FWsamParseLine, ++ * which parses the sid-block.map file, and also by AlertFWsamOptionInit, ++ * which is called by Snort when processing fwsam: options in rules. ++ * It returns TRUE it there is a possible option problem, otherwise FALSE. ++*/ ++int FWsamParseOption(FWsamOptions *optp,char *ap) ++{ int possprob=FALSE; ++ ++ /* set defaults */ ++ ++ optp->duration=300; /* default of 5 minute block */ ++ optp->how=FWSAM_HOW_INOUT; /* inbound and outbound block */ ++ optp->who=FWSAM_WHO_SRC; /* the source */ ++ optp->loglevel=FWSAM_LOG_LONGALERT; /* the log level default */ ++ /* parse the fwsam keywords */ ++ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWamOptionInit) Parse Options Args: %s\n",ap); ++#endif ++ ++ if(*ap) /* should be dst/src (the WHO) or duration */ ++ { if(isdigit(*ap)) ++ optp->duration=FWsamParseDuration(ap); ++ else ++ { switch(*ap) /* yeah, we're lazy and check only the first character */ ++ { case 'p': ; /* permanent, perm */ ++ case 'f': ; /* forever */ ++ case 'i': optp->duration=0; /* infinite, inf */ ++ break; ++ case 'd': optp->who=FWSAM_WHO_DST; /* destination, dest, dst */ ++ break; ++ case 's': optp->who=FWSAM_WHO_SRC; /* source, src */ ++ break; ++ default: possprob=TRUE; ++ } ++ while(*ap && *ap!=',' && *ap!='[') ++ ap++; ++ if(*ap=='[') ++ { ap++; /* now we have the HOW */ ++ switch(*ap) ++ { case 'i': ; /* in */ ++ case 's': optp->how=FWSAM_HOW_IN; /* source, src */ ++ break; ++ case 'o': ; /* out */ ++ case 'd': optp->how=FWSAM_HOW_OUT; /* destination, dest, dst */ ++ break; ++ case 'b': ; /* both */ ++ case 'e': optp->how=FWSAM_HOW_INOUT; /* either */ ++ break; ++ case 't': ; /* this */ ++ case 'c': optp->how=FWSAM_HOW_THIS; /* connection, conn */ ++ break; ++ default: possprob=TRUE; ++ } ++ while(*ap && *ap!=',') ++ ap++; ++ } ++ if(*ap==',') ++ { ap++; ++ if(isdigit(*ap)) /* and figure out how long to block */ ++ optp->duration=FWsamParseDuration(ap); ++ else if(*ap=='p' || *ap=='f' || *ap=='i') ++ optp->duration=0; ++ else ++ possprob=TRUE; ++ } ++ else if(!*ap) ++ possprob=TRUE; ++ } ++ } ++ else ++ possprob=TRUE; ++ ++ return possprob; ++} ++ ++ ++/* This goes through the lines of sid-block.map and sets the ++ * options for fwsam if the file is being used. ++*/ ++void FWsamParseLine(FWsamOptions *optp,char *buf) ++{ char *ap; ++ ++ ap=buf; /* start at the beginning of the argument */ ++ ++ while(*ap) ++ { if(isspace(*ap)) /* normalize spaces (tabs into space, etc) */ ++ *ap=' '; ++ if(isupper(*ap)) /* and set to lower case */ ++ *ap=tolower(*ap); ++ ap++; ++ } ++ while((ap=strrchr(buf,' '))!=NULL) /* remove spaces */ ++ strcpy(ap,ap+1); ++ ++ ap=buf; ++ if(*ap) ++ { while(*ap && *ap!=':' && *ap!='|') ++ ap++; ++ *ap++ =0; ++ while(*ap && (*ap==':' || *ap=='|')) ++ ap++; ++ ++ optp->sid=(unsigned long)atol(buf); ++ ++ if(FWsamParseOption(optp,ap)) ++ LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWamOptionInit) Possible option problem. Using %s[%s],%lu.\n",file_name,file_line,(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration); ++ } ++ else ++ optp->sid=0; ++} ++ ++ ++ ++/* ++ * Function: AlertFWsamOptionInit(char *data, OptTreeNode *otn, int protocol) ++ * ++ * Purpose: Parses each rule and sets the option flags in the tree. ++ * ++ * Arguments: args => ptr to argument string ++ * ++ * Returns: void function ++ * ++*/ ++void AlertFWsamOptionInit(char *args,OptTreeNode *otn,int protocol) ++{ ++ FWsamOptions *optp; ++ char *ap; ++ ++ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWamOptionInit) FWsamOptionInit is parsing...\n"); ++#endif ++ ++ if((optp=(FWsamOptions *)malloc(sizeof(FWsamOptions)))==NULL) ++ FatalError("ERROR => [Alert_FWsam](AlertFWamOptionInit) malloc failed for opt!\n"); ++ ++ ++ ap=args; /* start at the beginning of the argument */ ++ ++ while(*ap) ++ { if(isspace(*ap)) /* normalize spaces (tabs into space, etc) */ ++ *ap=' '; ++ if(isupper(*ap)) /* and set to lower case */ ++ *ap=tolower(*ap); ++ ap++; ++ } ++ while((ap=strrchr(args,' '))!=NULL) /* remove spaces */ ++ strcpy(ap,ap+1); ++ ++ ++ if(FWsamParseOption(optp,args)) ++ LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWamOptionInit) Possible option problem. Using %s[%s],%lu.\n",file_name,file_line,(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration); ++ ++ otn->ds_list[PLUGIN_FWSAM]=(FWsamOptions *)optp; ++} ++ ++ ++/* Generates a new encryption key for TwoFish based on seq numbers and a random that ++ * the SnortSam agents send on checkin (in protocol) ++*/ ++void FWsamNewStationKey(FWsamStation *station,FWsamPacket *packet) ++{ ++ //unsigned char newkey[TwoFish_KEY_LENGTH+2]; ++ char newkey[TwoFish_KEY_LENGTH+2]; ++ int i; ++ ++ newkey[0]=packet->snortseqno[0]; /* current snort seq # (which both know) */ ++ newkey[1]=packet->snortseqno[1]; ++ newkey[2]=packet->fwseqno[0]; /* current SnortSam seq # (which both know) */ ++ newkey[3]=packet->fwseqno[1]; ++ newkey[4]=packet->protocol[0]; /* the random SnortSam chose */ ++ newkey[5]=packet->protocol[1]; ++ ++ strncpy(newkey+6,station->stationkey,TwoFish_KEY_LENGTH-6); /* append old key */ ++ newkey[TwoFish_KEY_LENGTH]=0; ++ ++ newkey[0]^=station->mykeymod[0]; /* modify key with key modifiers which were */ ++ newkey[1]^=station->mykeymod[1]; /* exchanged during the check-in handshake. */ ++ newkey[2]^=station->mykeymod[2]; ++ newkey[3]^=station->mykeymod[3]; ++ newkey[4]^=station->fwkeymod[0]; ++ newkey[5]^=station->fwkeymod[1]; ++ newkey[6]^=station->fwkeymod[2]; ++ newkey[7]^=station->fwkeymod[3]; ++ ++ for(i=0;i<=7;i++) ++ if(newkey[i]==0) ++ newkey[i]++; ++ ++ strcpy(station->stationkey,newkey); ++ TwoFishDestroy(station->stationfish); ++ station->stationfish=TwoFishInit(newkey); ++} ++ ++ ++/* This routine will search the option list as defined ++ * by the sid-block.map file and return a pointer ++ * to the matching record. ++*/ ++FWsamOptions *FWsamGetOption(unsigned long sid) ++{ signed long i,step,diff,o,o2; ++ ++#ifdef FWSAM_FANCYFETCH /* Fancy-fetch jumps in decreasing n/2 steps and takes much less lookups */ ++ o=o2= -1; ++ i=step=FWsamMaxOptions>>1; ++ while(i>=0 && i1) ++ step=step>>1; ++ o2=o; ++ o=i; ++ if(diff>0) ++ i+=step; ++ else ++ i-=step; ++ } ++#else /* This is just a sequential list lookup */ ++ for(i=0;i pointer to the packet data struct ++ * msg => the message to print in the alert ++ * ++ * Returns: void function ++ * ++ ***************************************************************************/ ++void AlertFWsam(Packet *p, char *msg, void *arg, Event *event) ++{ FWsamOptions *optp; ++ FWsamPacket sampacket; ++ FWsamStation *station=NULL; ++ FWsamList *fwsamlist; ++ SOCKET stationsocket; ++ int i,len,deletestation,stationtry=0; ++ //unsigned char *encbuf,*decbuf; ++ char *encbuf,*decbuf; ++ static unsigned long lastbsip[FWSAM_REPET_BLOCKS],lastbdip[FWSAM_REPET_BLOCKS], ++ lastbduration[FWSAM_REPET_BLOCKS],lastbtime[FWSAM_REPET_BLOCKS]; ++ static unsigned short lastbsp[FWSAM_REPET_BLOCKS],lastbdp[FWSAM_REPET_BLOCKS], ++ lastbproto[FWSAM_REPET_BLOCKS],lastbpointer; ++ static unsigned char lastbmode[FWSAM_REPET_BLOCKS]; ++ static unsigned long btime=0; ++ ++ ++ if(otn_tmp==NULL) ++ { ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] NULL otn_tmp!\n"); ++#endif ++ return; ++ } ++ if(p == NULL) ++ { ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] NULL packet!\n"); ++#endif ++ return; ++ } ++ if(arg == NULL) ++ { ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] NULL arg!\n"); ++#endif ++ return; ++ } ++ ++ /* SnortSam does no IPv6 */ ++ if (!IS_IP4(p)) { ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] not acting on non-IP4 packet!\n"); ++#endif ++ return; ++ } ++ ++ optp=NULL; ++ ++ if(FWsamOptionField) /* If using the file (field present), let's use that */ ++ optp=FWsamGetOption(event->sig_id); ++ ++ if(!optp) /* If file not present, check if an fwsam option was defined on the triggering rule */ ++ optp=otn_tmp->ds_list[PLUGIN_FWSAM]; ++ ++ if(optp) /* if options specified for this rule */ ++ { if(!btime) /* if this is the first time this function is */ ++ { for(i=0;i [Alert_FWsam] Alert -> Msg=\"%s\"\n",msg); ++ ++ LogMessage("DEBUG => [Alert_FWsam] Alert -> Option: %s[%s],%lu.\n",(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration); ++#endif ++ ++ len=TRUE; ++ btime=(unsigned long)time(NULL); /* get current time */ ++ /* This is a cheap check to see if the blocking request matches any of the previous requests. */ ++ for(i=0;ihow==FWSAM_HOW_THIS)? /* if blocking mode SERVICE, check for src and dst */ ++ ( lastbsip[i]==p->iph->ip_src.s_addr && lastbdip[i]==p->iph->ip_dst.s_addr &&lastbproto[i]==p->iph->ip_proto && ++ ((p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP)? /* check port only of TCP or UDP */ ++/* ((optp->who==FWSAM_WHO_SRC)?(lastbsp[i]==p->sp):(lastbdp[i]==p->dp)):TRUE) ): */ ++ lastbdp[i]==p->dp:TRUE) ): ++ ((optp->who==FWSAM_WHO_SRC)?(lastbsip[i]==p->iph->ip_src.s_addr):(lastbdip[i]==p->iph->ip_dst.s_addr))) && /* otherwise if we block source, only compare source. Same for dest. */ ++ lastbduration[i]==optp->duration && ++ (lastbmode[i]&(FWSAM_HOW|FWSAM_WHO))==(optp->how|optp->who) && ++ (btime-lastbtime[i]<((optp->duration>FWSAM_REPET_TIME)?FWSAM_REPET_TIME:optp->duration))) ++ { len=FALSE; /* If so, we don't need to block again. */ ++ } ++ } ++ if(len) ++ { if(++lastbpointer>=FWSAM_REPET_BLOCKS) /* increase repetitive check pointer */ ++ lastbpointer=0; ++ lastbsip[lastbpointer]=p->iph->ip_src.s_addr; /* and note packet details */ ++ lastbdip[lastbpointer]=p->iph->ip_dst.s_addr; ++ lastbduration[lastbpointer]=optp->duration; ++ lastbmode[lastbpointer]=optp->how|optp->who|optp->loglevel; ++ lastbproto[lastbpointer]=p->iph->ip_proto; ++ if(p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP) ++ { lastbsp[lastbpointer]=p->sp; /* set ports if TCP or UDP */ ++ lastbdp[lastbpointer]=p->dp; ++ } ++ lastbtime[lastbpointer]=btime; ++ ++ ++ while(fwsamlist!=NULL) ++ { station=fwsamlist->station; ++ //if(station->stationip.s_addr) ++ if(station->stationip.ip32[0]) ++ { deletestation=FALSE; ++ stationtry++; /* first try */ ++ /* create a socket for the station */ ++ stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); ++ if(stationsocket==INVALID_SOCKET) ++ FatalError("ERROR => [Alert_FWsam] Funky socket error (socket)!\n"); ++ if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr))) ++ FatalError("ERROR => [Alert_FWsam] Could not bind socket!\n"); ++ ++ /* let's connect to the agent */ ++ if(connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr))) ++ { ++ LogMessage("WARNING => [Alert_FWsam] Could not send block to host %s. Will try later.\n",sfip_ntoa(&station->stationip)); ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++ stationtry=0; ++ } ++ else ++ { ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] Connected to host %s.\n",sfip_ntoa(&station->stationip)); ++#endif ++ /* now build the packet */ ++ station->myseqno+=station->stationseqno; /* increase my seqno by adding agent seq no */ ++ sampacket.endiancheck=1; /* This is an endian indicator for Snortsam */ ++ sampacket.snortseqno[0]=(char)station->myseqno; ++ sampacket.snortseqno[1]=(char)(station->myseqno>>8); ++ sampacket.fwseqno[0]=(char)station->stationseqno;/* fill station seqno */ ++ sampacket.fwseqno[1]=(char)(station->stationseqno>>8); ++ sampacket.status=FWSAM_STATUS_BLOCK; /* set block mode */ ++ sampacket.version=FWSAM_PACKETVERSION; /* set packet version */ ++ sampacket.duration[0]=(char)optp->duration; /* set duration */ ++ sampacket.duration[1]=(char)(optp->duration>>8); ++ sampacket.duration[2]=(char)(optp->duration>>16); ++ sampacket.duration[3]=(char)(optp->duration>>24); ++ sampacket.fwmode=optp->how|optp->who|optp->loglevel; /* set the mode */ ++ sampacket.dstip[0]=(char)p->iph->ip_dst.s_addr; /* destination IP */ ++ sampacket.dstip[1]=(char)(p->iph->ip_dst.s_addr>>8); ++ sampacket.dstip[2]=(char)(p->iph->ip_dst.s_addr>>16); ++ sampacket.dstip[3]=(char)(p->iph->ip_dst.s_addr>>24); ++ sampacket.srcip[0]=(char)p->iph->ip_src.s_addr; /* source IP */ ++ sampacket.srcip[1]=(char)(p->iph->ip_src.s_addr>>8); ++ sampacket.srcip[2]=(char)(p->iph->ip_src.s_addr>>16); ++ sampacket.srcip[3]=(char)(p->iph->ip_src.s_addr>>24); ++ sampacket.protocol[0]=(char)p->iph->ip_proto; /* protocol */ ++ sampacket.protocol[1]=(char)(p->iph->ip_proto>>8);/* protocol */ ++ ++ if(p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP) ++ { sampacket.srcport[0]=(char)p->sp; /* set ports */ ++ sampacket.srcport[1]=(char)(p->sp>>8); ++ sampacket.dstport[0]=(char)p->dp; ++ sampacket.dstport[1]=(char)(p->dp>>8); ++ } ++ else ++ sampacket.srcport[0]=sampacket.srcport[1]=sampacket.dstport[0]=sampacket.dstport[1]=0; ++ ++ sampacket.sig_id[0]=(char)event->sig_id; /* set signature ID */ ++ sampacket.sig_id[1]=(char)(event->sig_id>>8); ++ sampacket.sig_id[2]=(char)(event->sig_id>>16); ++ sampacket.sig_id[3]=(char)(event->sig_id>>24); ++ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] Sending BLOCK\n"); ++ LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo: %x\n",station->myseqno); ++ LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo : %x\n",station->stationseqno); ++ LogMessage("DEBUG => [Alert_FWsam] Status : %i\n",FWSAM_STATUS_BLOCK); ++ LogMessage("DEBUG => [Alert_FWsam] Mode : %i\n",optp->how|optp->who|optp->loglevel); ++ LogMessage("DEBUG => [Alert_FWsam] Duration : %li\n",optp->duration); ++ LogMessage("DEBUG => [Alert_FWsam] Protocol : %i\n",GET_IPH_PROTO(p)); ++#ifdef SUP_IP6 ++ LogMessage("DEBUG => [Alert_FWsam] Src IP : %s\n",sfip_ntoa(GET_SRC_IP(p))); ++ LogMessage("DEBUG => [Alert_FWsam] Dest IP : %s\n",sfip_ntoa(GET_DST_IP(p))); ++#else ++ LogMessage("DEBUG => [Alert_FWsam] Src IP : %s\n",inet_ntoa(p->iph->ip_src)); ++ LogMessage("DEBUG => [Alert_FWsam] Dest IP : %s\n",inet_ntoa(p->iph->ip_dst)); ++#endif ++ LogMessage("DEBUG => [Alert_FWsam] Src Port : %i\n",p->sp); ++ LogMessage("DEBUG => [Alert_FWsam] Dest Port : %i\n",p->dp); ++ LogMessage("DEBUG => [Alert_FWsam] Sig_ID : %lu\n",event->sig_id); ++ ++#endif ++ ++ encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get the encryption buffer */ ++ len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt the packet with current key */ ++ ++ if(send(stationsocket,encbuf,len,0)!=len) /* weird...could not send */ ++ { LogMessage("WARNING => [Alert_FWsam] Could not send to host %s. Will try again later.\n",sfip_ntoa(&station->stationip)); ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++ stationtry=0; ++ } ++ else ++ { i=FWSAM_NETWAIT; ++#ifdef WIN32 ++ ioctlsocket(stationsocket,FIONBIO,&i); /* set non blocking and wait for */ ++#else ++ ioctl(stationsocket,FIONBIO,&i); /* set non blocking and wait for */ ++#endif ++ while(i-- >1) /* the response packet */ ++ { waitms(10); /* wait for response (default maximum 3 secs */ ++ if(recv(stationsocket,encbuf,len,0)==len) ++ i=0; /* if we received packet we set the counter to 0. */ ++ /* by the time we check with if, it's already dec'ed to -1 */ ++ } ++ if(!i) /* id we timed out (i was one, then dec'ed)... */ ++ { LogMessage("WARNING => [Alert_FWsam] Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip)); ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++ stationtry=0; ++ } ++ else /* got a packet */ ++ { decbuf=(char *)&sampacket; /* get the pointer to the packet struct */ ++ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt the packet with current key */ ++ ++ if(len!=sizeof(FWsamPacket)) /* invalid decryption */ ++ { strcpy(station->stationkey,station->initialkey); /* try the intial key */ ++ TwoFishDestroy(station->stationfish); ++ station->stationfish=TwoFishInit(station->stationkey); /* re-initialize the TwoFish with the intial key */ ++ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try again to decrypt */ ++ LogMessage("INFO => [Alert_FWsam] Had to use initial key!\n"); ++ } ++ if(len==sizeof(FWsamPacket)) /* valid decryption */ ++ { if(sampacket.version==FWSAM_PACKETVERSION)/* master speaks my language */ ++ { if(sampacket.status==FWSAM_STATUS_OK || sampacket.status==FWSAM_STATUS_NEWKEY ++ || sampacket.status==FWSAM_STATUS_RESYNC || sampacket.status==FWSAM_STATUS_HOLD) ++ { station->stationseqno=sampacket.fwseqno[0] | (sampacket.fwseqno[1]<<8); /* get stations seqno */ ++ station->lastcontact=(unsigned long)time(NULL); /* set the last contact time (not used yet) */ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK": ++ sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY": ++ sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC": ++ sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR"); ++ LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo: %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8)); ++ LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo : %x\n",station->stationseqno); ++ LogMessage("DEBUG => [Alert_FWsam] Status : %i\n",sampacket.status); ++ LogMessage("DEBUG => [Alert_FWsam] Version : %i\n",sampacket.version); ++#endif ++ if(sampacket.status==FWSAM_STATUS_HOLD) ++ { i=FWSAM_NETHOLD; /* Stay on hold for a maximum of 60 secs (default) */ ++ while(i-- >1) /* the response packet */ ++ { waitms(10); /* wait for response */ ++ if(recv(stationsocket,encbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,0)==sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE) ++ i=0; /* if we received packet we set the counter to 0. */ ++ } ++ if(!i) /* id we timed out (i was one, then dec'ed)... */ ++ { LogMessage("WARNING => [Alert_FWsam] Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip)); ++ stationtry=0; ++ sampacket.status=FWSAM_STATUS_ERROR; ++ } ++ else /* got a packet */ ++ { decbuf=(char *)&sampacket; /* get the pointer to the packet struct */ ++ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt the packet with current key */ ++ ++ if(len!=sizeof(FWsamPacket)) /* invalid decryption */ ++ { strcpy(station->stationkey,station->initialkey); /* try the intial key */ ++ TwoFishDestroy(station->stationfish); ++ station->stationfish=TwoFishInit(station->stationkey); /* re-initialize the TwoFish with the intial key */ ++ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try again to decrypt */ ++ LogMessage("INFO => [Alert_FWsam] Had to use initial key again!\n"); ++ } ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK": ++ sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY": ++ sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC": ++ sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR"); ++ LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo: %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8)); ++ LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo : %x\n",station->stationseqno); ++ LogMessage("DEBUG => [Alert_FWsam] Status : %i\n",sampacket.status); ++ LogMessage("DEBUG => [Alert_FWsam] Version : %i\n",sampacket.version); ++#endif ++ if(len!=sizeof(FWsamPacket)) /* invalid decryption */ ++ { ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++ deletestation=TRUE; ++ sampacket.status=FWSAM_STATUS_ERROR; ++ } ++ else if(sampacket.version!=FWSAM_PACKETVERSION) /* invalid protocol version */ ++ { ErrorMessage("ERROR => [Alert_FWsam] Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++ deletestation=TRUE; ++ sampacket.status=FWSAM_STATUS_ERROR; ++ } ++ else if(sampacket.status!=FWSAM_STATUS_OK && sampacket.status!=FWSAM_STATUS_NEWKEY && sampacket.status!=FWSAM_STATUS_RESYNC) ++ { ErrorMessage("ERROR => [Alert_FWsam] Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++ deletestation=TRUE; ++ sampacket.status=FWSAM_STATUS_ERROR; ++ } ++ } ++ } ++ if(sampacket.status==FWSAM_STATUS_RESYNC) /* if station want's to resync... */ ++ { strcpy(station->stationkey,station->initialkey); /* ...we use the intial key... */ ++ memcpy(station->fwkeymod,sampacket.duration,4); /* and note the random key modifier */ ++ } ++ if(sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC) ++ { ++ FWsamNewStationKey(station,&sampacket); /* generate new TwoFish keys */ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] Generated new encryption key...\n"); ++#endif ++ } ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++ stationtry=0; ++ } ++ else if(sampacket.status==FWSAM_STATUS_ERROR) /* if SnortSam reports an error on second try, */ ++ { ++#ifdef WIN32 ++ closesocket(stationsocket); /* something is messed up and ... */ ++#else ++ close(stationsocket); ++#endif ++ if(stationtry>1) /* we ignore that station. */ ++ { deletestation=TRUE; /* flag for deletion */ ++ ErrorMessage("ERROR => [Alert_FWsam] Could not renegotiate key! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++ } ++ else /* if we get an error on the first try, */ ++ { if(!FWsamCheckIn(station)) /* we first try to check in again. */ ++ { deletestation=TRUE; ++ ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++ } ++ } ++ } ++ else /* an unknown status means trouble... */ ++ { ErrorMessage("ERROR => [Alert_FWsam] Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++ deletestation=TRUE; ++ } ++ } ++ else /* if the SnortSam agent uses a different packet version, we have no choice but to ignore it. */ ++ { ErrorMessage("ERROR => [Alert_FWsam] Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++ deletestation=TRUE; ++ } ++ } ++ else /* if the intial key failed to decrypt as well, the keys are not configured the same, and we ignore that SnortSam station. */ ++ { ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++ deletestation=TRUE; ++ } ++ } ++ } ++ free(encbuf); /* release of the TwoFishAlloc'ed encryption buffer */ ++ } ++ if(stationtry==0 || deletestation) /* if everything went real well, or real bad... */ ++ { if(deletestation){ /* If it went bad, we remove the station from the list by marking the IP */ ++// station->stationip.s_addr=0; ++ station->stationip.ip32[0]=0; ++ } ++ fwsamlist=fwsamlist->next; ++ } ++ } ++ else ++ fwsamlist=fwsamlist->next; ++ } ++ } ++ else ++ { ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam] Skipping repetitive block.\n"); ++#endif ++ } ++ } ++} ++ ++/* FWsamCheckOut will be called when Snort exists. It de-registeres this snort sensor ++ * from the list of sensor that the SnortSam agent keeps. ++ */ ++void FWsamCheckOut(FWsamStation *station) ++{ FWsamPacket sampacket; ++ SOCKET stationsocket; ++ int i,len; ++ char *encbuf,*decbuf; ++ //unsigned char *encbuf,*decbuf; ++ ++ ++ stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); ++ if(stationsocket==INVALID_SOCKET) ++ FatalError("ERROR => [Alert_FWsam](FWsamCheckOut) Funky socket error (socket)!\n"); ++ if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr))) ++ FatalError("ERROR => [Alert_FWsam](FWsamCheckOut) Could not bind socket!\n"); ++ ++ /* let's connect to the agent */ ++ if(!connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr))) ++ { LogMessage("INFO => [Alert_FWsam](FWsamCheckOut) Disconnecting from host %s.\n",sfip_ntoa(&station->stationip)); ++ /* now build the packet */ ++ station->myseqno+=station->stationseqno; /* increase my seqno */ ++ sampacket.endiancheck=1; ++ sampacket.snortseqno[0]=(char)station->myseqno; ++ sampacket.snortseqno[1]=(char)(station->myseqno>>8); ++ sampacket.fwseqno[0]=(char)station->stationseqno; /* fill station seqno */ ++ sampacket.fwseqno[1]=(char)(station->stationseqno>>8); ++ sampacket.status=FWSAM_STATUS_CHECKOUT; /* checking out... */ ++ sampacket.version=FWSAM_PACKETVERSION; ++ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Sending CHECKOUT\n"); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Snort SeqNo: %x\n",station->myseqno); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Mgmt SeqNo : %x\n",station->stationseqno); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Status : %i\n",sampacket.status); ++ ++#endif ++ ++ encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get encryption buffer */ ++ len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt packet with current key */ ++ ++ if(send(stationsocket,encbuf,len,0)==len) ++ { i=FWSAM_NETWAIT; ++#ifdef WIN32 ++ ioctlsocket(stationsocket,FIONBIO,&i); /* set non blocking and wait for */ ++#else ++ ioctl(stationsocket,FIONBIO,&i); /* set non blocking and wait for */ ++#endif ++ while(i-- >1) ++ { waitms(10); /* ...wait a maximum of 3 secs for response... */ ++ if(recv(stationsocket,encbuf,len,0)==len) /* ... for the status packet */ ++ i=0; ++ } ++ if(i) /* if we got the packet */ ++ { decbuf=(char *)&sampacket; ++ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); ++ ++ if(len!=sizeof(FWsamPacket)) /* invalid decryption */ ++ { strcpy(station->stationkey,station->initialkey); /* try initial key */ ++ TwoFishDestroy(station->stationfish); /* toss this fish */ ++ station->stationfish=TwoFishInit(station->stationkey); /* re-initialze TwoFish with initial key */ ++ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* and try to decrypt again */ ++ LogMessage("INFO => [Alert_FWsam](FWsamCheckOut) Had to use initial key!\n"); ++ } ++ if(len==sizeof(FWsamPacket)) /* valid decryption */ ++ { if(sampacket.version!=FWSAM_PACKETVERSION) /* but don't really care since we are on the way out */ ++ ErrorMessage("WARNING => [Alert_FWsam](FWsamCheckOut) Protocol version error! What the hell, we're quitting anyway! :)\n"); ++ } ++ else ++ ErrorMessage("WARNING => [Alert_FWsam](FWsamCheckOut) Password mismatch! What the hell, we're quitting anyway! :)\n"); ++ } ++ } ++ free(encbuf); /* release TwoFishAlloc'ed buffer */ ++ } ++ else ++ LogMessage("WARNING => [Alert_FWsam] Could not connect to host %s for CheckOut. What the hell, we're quitting anyway! :)\n",sfip_ntoa(&station->stationip)); ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++} ++ ++ ++/* FWSamFree: Disconnects all FW-1 management stations, ++ * closes sockets, and frees the structures. ++ */ ++void FWsamFree(FWsamList *list) ++{ ++ FWsamList *next; ++ ++ while(list) /* Free pointer list for rule type */ ++ { ++ next=list->next; ++ free(list); ++ list=next; ++ } ++ list=FWsamStationList; ++ ++ while(list) /* Free global pointer list and stations */ ++ { ++ next=list->next; ++ if (list->station) ++ { ++ if(list->station->stationip.ip32[0]) ++ //if(list->station->stationip.s_addr) ++ FWsamCheckOut(list->station); /* Send a Check-Out to SnortSam, */ ++ ++ TwoFishDestroy(list->station->stationfish); /* toss the fish, */ ++ free(list->station); /* free station, */ ++ } ++ free(list); /* free pointer, */ ++ list=next; /* and move to next. */ ++ } ++ FWsamStationList=NULL; ++ if(FWsamOptionField) ++ free(FWsamOptionField); ++} ++ ++void AlertFWsamCleanExitFunc(int signal, void *arg) ++{ FWsamList *fwsamlist; ++ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamCleanExitFunc) Exiting...\n"); ++#endif ++ ++ fwsamlist=(FWsamList *)arg; ++ FWsamFree(fwsamlist); /* Free all elements */ ++} ++ ++void AlertFWsamRestartFunc(int signal, void *arg) ++{ FWsamList *fwsamlist; ++ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamRestartFunc) Restarting...\n"); ++#endif ++ ++ fwsamlist=(FWsamList *)arg; ++ FWsamFree(fwsamlist); /* Free all elements */ ++} ++ ++/* This routine registers this Snort sensor with SnortSam. ++ * It will also change the encryption key based on some variables. ++ */ ++int FWsamCheckIn(FWsamStation *station) ++{ int i,len,stationok=TRUE; ++ FWsamPacket sampacket; ++ char *encbuf,*decbuf; ++ //unsigned char *encbuf,*decbuf; ++ SOCKET stationsocket; ++ ++ ++ /* create a socket for the station */ ++ stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); ++ if(stationsocket==INVALID_SOCKET) ++ FatalError("ERROR => [Alert_FWsam](FWsamCheckIn) Funky socket error (socket)!\n"); ++ if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr))) ++ FatalError("ERROR => [Alert_FWsam](FWsamCheckIn) Could not bind socket!\n"); ++ ++ i=TRUE; ++ /* let's connect to the agent */ ++ if(connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr))) ++ LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Could not connect to host %s. Will try later.\n",sfip_ntoa(&station->stationip)); ++ else ++ { LogMessage("INFO => [Alert_FWsam](FWsamCheckIn) Connected to host %s.\n",sfip_ntoa(&station->stationip)); ++ /* now build the packet */ ++ sampacket.endiancheck=1; ++ sampacket.snortseqno[0]=(char)station->myseqno; /* fill my sequence number number */ ++ sampacket.snortseqno[1]=(char)(station->myseqno>>8); /* fill my sequence number number */ ++ sampacket.status=FWSAM_STATUS_CHECKIN; /* let's check in */ ++ sampacket.version=FWSAM_PACKETVERSION; /* set the packet version */ ++ memcpy(sampacket.duration,station->mykeymod,4); /* we'll send SnortSam our key modifier in the duration slot */ ++ /* (the checkin packet is just the plain initial key) */ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Sending CheckIn\n"); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Snort SeqNo: %x\n",station->myseqno); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Mode : %i\n",sampacket.status); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Version : %i\n",sampacket.version); ++#endif ++ encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get buffer for encryption */ ++ len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt with initial key */ ++ if(send(stationsocket,encbuf,len,0)!=len) /* weird...could not send */ ++ LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Could not send to host %s. Will try again later.\n",sfip_ntoa(&station->stationip)); ++ else ++ { i=FWSAM_NETWAIT; ++#ifdef WIN32 ++ ioctlsocket(stationsocket,FIONBIO,&i); /* set non blocking and wait for */ ++#else ++ ioctl(stationsocket,FIONBIO,&i); /* set non blocking and wait for */ ++#endif ++ while(i-- >1) ++ { waitms(10); /* wait a maximum of 3 secs for response */ ++ if(recv(stationsocket,encbuf,len,0)==len) ++ i=0; ++ } ++ if(!i) /* time up? */ ++ LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip)); ++ else ++ { decbuf=(char *)&sampacket; /* got status packet */ ++ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt with initial key */ ++ if(len==sizeof(FWsamPacket)) /* valid decryption */ ++ { ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK": ++ sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY": ++ sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC": ++ sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR"); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Snort SeqNo: %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8)); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Mgmt SeqNo : %x\n",sampacket.fwseqno[0]|(sampacket.fwseqno[1]<<8)); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Status : %i\n",sampacket.status); ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Version : %i\n",sampacket.version); ++#endif ++ if(sampacket.version==FWSAM_PACKETVERSION) /* master speaks my language */ ++ { if(sampacket.status==FWSAM_STATUS_OK || sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC) ++ { station->stationseqno=sampacket.fwseqno[0]|(sampacket.fwseqno[1]<<8); /* get stations seqno */ ++ station->lastcontact=(unsigned long)time(NULL); ++ ++ if(sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC) /* generate new keys */ ++ { memcpy(station->fwkeymod,sampacket.duration,4); /* note the key modifier */ ++ FWsamNewStationKey(station,&sampacket); /* and generate new TwoFish keys (with key modifiers) */ ++#ifdef FWSAMDEBUG ++ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Generated new encryption key...\n"); ++#endif ++ } ++ } ++ else /* weird, got a strange status back */ ++ { ErrorMessage("ERROR => [Alert_FWsam](FWsamCheckIn) Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++ stationok=FALSE; ++ } ++ } ++ else /* packet version does not match */ ++ { ErrorMessage("ERROR =>[Alert_FWsam](FWsamCheckIn) Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++ stationok=FALSE; ++ } ++ } ++ else /* key does not match */ ++ { ErrorMessage("ERROR => [Alert_FWsam](FWsamCheckIn) Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip)); ++ stationok=FALSE; ++ } ++ } ++ } ++ free(encbuf); /* release TwoFishAlloc'ed buffer */ ++ } ++#ifdef WIN32 ++ closesocket(stationsocket); ++#else ++ close(stationsocket); ++#endif ++ return stationok; ++} ++#undef FWSAMDEBUG ++ + +Index: snort-2.8.6.1/src/output-plugins/spo_alert_fwsam.h +=================================================================== +--- snort-2.8.6.1/src/output-plugins/spo_alert_fwsam.h (Revision 0) ++++ snort-2.8.6.1/src/output-plugins/spo_alert_fwsam.h (Revision 3) +@@ -0,0 +1,216 @@ ++/* $Id: snortpatchb,v 1.5 2005/10/06 08:50:39 fknobbe Exp $ ++** ++** spo_alert_fwsam.h ++** ++** Copyright (c) 2001-2004 Frank Knobbe ++** ++** This program is free software; you can redistribute it and/or modify ++** it under the terms of the GNU General Public License as published by ++** the Free Software Foundation; either version 2 of the License, or ++** (at your option) any later version. ++** ++** This program is distributed in the hope that it will be useful, ++** but WITHOUT ANY WARRANTY; without even the implied warranty of ++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++** GNU General Public License for more details. ++** ++** You should have received a copy of the GNU General Public License ++** along with this program; if not, write to the Free Software ++** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++*/ ++ ++/* This file gets included in plugbase.c when it is integrated into the rest ++ * of the program. ++ * ++ * For more info, see the beginning of spo_alert_fwsam.c ++ * ++ */ ++ ++#ifndef __SPO_FWSAM_H__ ++#define __SPO_FWSAM_H__ ++ ++#include "snort.h" ++#include "rules.h" ++#include "plugbase.h" ++#include "plugin_enum.h" ++#include "fatal.h" ++#include "util.h" ++#include "twofish.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* just some compatibility stuff */ ++#ifdef WIN32 ++#if !defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++#include ++#endif ++#define waitms(x) Sleep(x) ++ ++#else ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef SOLARIS ++#include ++#endif ++ ++typedef int SOCKET; ++ ++#ifndef INVALID_SOCKET ++#define INVALID_SOCKET -1 ++#endif ++ ++#define waitms(x) usleep((x)*1000) ++ ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++#ifndef TRUE ++#define TRUE !FALSE ++#endif ++#ifndef bool ++#define bool int ++#endif ++ ++ ++#if defined(_DEBUG) || defined(DEBUG) ++#ifndef FWSAMDEBUG ++#define FWSAMDEBUG ++#endif ++#else ++#endif ++ ++ ++/* Official Snort PlugIn Number has been moved into plugin_enum.h */ ++ ++ ++/* fixed defines */ ++ ++#define FWSAM_DEFAULTPORT 898 /* Default port if user does not specify one in snort.conf */ ++ /* (Was unused last time I checked...) */ ++#define FWSAM_PACKETVERSION 14 /* version of the packet. Will increase with enhancements. */ ++ ++#define FWSAM_STATUS_CHECKIN 1 /* snort to fw */ ++#define FWSAM_STATUS_CHECKOUT 2 ++#define FWSAM_STATUS_BLOCK 3 ++#define FWSAM_STATUS_UNBLOCK 9 ++ ++#define FWSAM_STATUS_OK 4 /* fw to snort */ ++#define FWSAM_STATUS_ERROR 5 ++#define FWSAM_STATUS_NEWKEY 6 ++#define FWSAM_STATUS_RESYNC 7 ++#define FWSAM_STATUS_HOLD 8 ++ ++#define FWSAM_LOG_NONE 0 ++#define FWSAM_LOG_SHORTLOG 1 ++#define FWSAM_LOG_SHORTALERT 2 ++#define FWSAM_LOG_LONGLOG 3 ++#define FWSAM_LOG_LONGALERT 4 ++#define FWSAM_LOG (FWSAM_LOG_SHORTLOG|FWSAM_LOG_SHORTALERT|FWSAM_LOG_LONGLOG|FWSAM_LOG_LONGALERT) ++#define FWSAM_WHO_DST 8 ++#define FWSAM_WHO_SRC 16 ++#define FWSAM_WHO (FWSAM_WHO_DST|FWSAM_WHO_SRC) ++#define FWSAM_HOW_IN 32 ++#define FWSAM_HOW_OUT 64 ++#define FWSAM_HOW_INOUT (FWSAM_HOW_IN|FWSAM_HOW_OUT) ++#define FWSAM_HOW_THIS 128 ++#define FWSAM_HOW (FWSAM_HOW_IN|FWSAM_HOW_OUT|FWSAM_HOW_THIS) ++ ++ ++/* user adjustable defines */ ++ ++#define FWSAM_REPET_BLOCKS 10 /* Snort remembers this amount of last blocks and... */ ++#define FWSAM_REPET_TIME 20 /* ...checks if they fall within this time. If so,... */ ++ /* ...the blocking request is not send. */ ++ ++#define FWSAM_NETWAIT 300 /* 100th of a second. 3 sec timeout for network connections */ ++#define FWSAM_NETHOLD 6000 /* 100th of a second. 60 sec timeout for holding */ ++ ++#define SID_MAPFILE "sid-block.map" ++#define SID_ALT_MAPFILE "sid-fwsam.map" ++ ++#define FWSAM_FANCYFETCH /* This will invoke a fast sid lookup routine */ ++ ++ ++/* vars */ ++ ++typedef struct _FWsamstation /* structure of a mgmt station */ ++{ unsigned short myseqno; ++ unsigned short stationseqno; ++ unsigned char mykeymod[4]; ++ unsigned char fwkeymod[4]; ++ unsigned short stationport; ++ //struct in_addr stationip; ++ sfip_t stationip; ++ struct sockaddr_in localsocketaddr; ++ struct sockaddr_in stationsocketaddr; ++ TWOFISH *stationfish; ++ char initialkey[TwoFish_KEY_LENGTH+2]; ++ char stationkey[TwoFish_KEY_LENGTH+2]; ++ time_t lastcontact; ++/* time_t sleepstart; */ ++} FWsamStation; ++ ++typedef struct _FWsampacket /* 2 blocks (3rd block is header from TwoFish) */ ++{ unsigned short endiancheck; /* 0 */ ++ unsigned char srcip[4]; /* 2 */ ++ unsigned char dstip[4]; /* 6 */ ++ unsigned char duration[4]; /* 10 */ ++ unsigned char snortseqno[2]; /* 14 */ ++ unsigned char fwseqno[2]; /* 16 */ ++ unsigned char srcport[2]; /* 18 */ ++ unsigned char dstport[2]; /* 20 */ ++ unsigned char protocol[2]; /* 22 */ ++ unsigned char fwmode; /* 24 */ ++ unsigned char version; /* 25 */ ++ unsigned char status; /* 26 */ ++ unsigned char sig_id[4]; /* 27 */ ++ unsigned char fluff; /* 31 */ ++} FWsamPacket; /* 32 bytes in size */ ++ ++typedef struct _FWsamoptions /* snort rule options */ ++{ unsigned long sid; ++ unsigned long duration; ++ unsigned char who; ++ unsigned char how; ++ unsigned char loglevel; ++} FWsamOptions; ++ ++typedef struct _FWsamlistpointer ++{ FWsamStation *station; ++ struct _FWsamlistpointer *next; ++} FWsamList; ++ ++ ++/* functions */ ++void AlertFWsamSetup(void); ++void AlertFWsamInit(char *args); ++void AlertFWsamOptionInit(char *args,OptTreeNode *otn,int protocol); ++void AlertFWsamCleanExitFunc(int signal, void *arg); ++void AlertFWsamRestartFunc(int signal, void *arg); ++void AlertFWsam(Packet *p, char *msg, void *arg, Event *event); ++int FWsamCheckIn(FWsamStation *station); ++void FWsamCheckOut(FWsamStation *station); ++void FWsamNewStationKey(FWsamStation *station,FWsamPacket *packet); ++void FWsamFixPacketEndian(FWsamPacket *p); ++unsigned long FWsamParseDuration(char *p); ++void FWsamFree(FWsamList *fwsamlist); ++int FWsamStationExists(FWsamStation *who,FWsamList *list); ++int FWsamReadLine(char *,unsigned long,FILE *); ++void FWsamParseLine(FWsamOptions *,char *); ++FWsamOptions *FWsamGetOption(unsigned long); ++int FWsamParseOption(FWsamOptions *,char *); ++ ++#endif /* __SPO_FWSAM_H__ */ + +Index: snort-2.8.6.1/src/output-plugins/Makefile.am +=================================================================== +--- snort-2.8.6.1/src/output-plugins/Makefile.am (Revision 1) ++++ snort-2.8.6.1/src/output-plugins/Makefile.am (Revision 3) +@@ -11,6 +11,7 @@ + spo_log_tcpdump.h spo_unified.c spo_unified2.c spo_unified.h spo_unified2.h \ + spo_log_ascii.c spo_log_ascii.h spo_alert_sf_socket.h spo_alert_sf_socket.c \ + spo_alert_prelude.c spo_alert_prelude.h spo_alert_arubaaction.c spo_alert_arubaaction.h \ ++spo_alert_fwsam.c spo_alert_fwsam.h \ + spo_alert_test.c spo_alert_test.h + + INCLUDES = @INCLUDES@ +Index: snort-2.8.6.1/src/plugbase.c +=================================================================== +--- snort-2.8.6.1/src/plugbase.c (Revision 1) ++++ snort-2.8.6.1/src/plugbase.c (Revision 3) +@@ -125,6 +125,7 @@ + #endif + + #include "output-plugins/spo_alert_test.h" ++#include "output-plugins/spo_alert_fwsam.h" + + extern ListHead *head_tmp; + extern PreprocConfigFuncNode *preproc_config_funcs; +@@ -1240,6 +1241,7 @@ + #endif + + AlertTestSetup(); ++ AlertFWsamSetup(); + } + + /**************************************************************************** +Index: snort-2.8.6.1/src/Makefile.am +=================================================================== +--- snort-2.8.6.1/src/Makefile.am (Revision 1) ++++ snort-2.8.6.1/src/Makefile.am (Revision 3) +@@ -52,7 +52,8 @@ + detection_filter.c detection_filter.h \ + rate_filter.c rate_filter.h \ + obfuscation.c obfuscation.h \ +-rule_option_types.h ++rule_option_types.h \ ++twofish.c twofish.h + + snort_LDADD = output-plugins/libspo.a \ + detection-plugins/libspd.a \ +Index: snort-2.8.6.1/autojunk.sh +=================================================================== +--- snort-2.8.6.1/autojunk.sh (Revision 0) ++++ snort-2.8.6.1/autojunk.sh (Revision 3) +@@ -0,0 +1,7 @@ ++#!/bin/sh ++# the list of commands that need to run before we do a compile ++libtoolize --automake --copy ++aclocal -I m4 ++autoheader ++automake --add-missing --copy ++autoconf + +Index: snort-2.8.6.1/etc/snort.conf +=================================================================== +--- snort-2.8.6.1/etc/snort.conf (Revision 1) ++++ snort-2.8.6.1/etc/snort.conf (Revision 3) +@@ -277,6 +277,32 @@ + # prelude + # output alert_prelude + ++# snortsam ++# In order to cause Snort to send a blocking request to the SnortSam agent, ++# that agent has to be listed, including the port it listens on, ++# and the encryption key it is using. The statement for that is: ++# ++# output alert_fwsam: {SnortSam Station}:{port}/{password} ++# ++# {SnortSam Station}: IP address or host name of the host where SnortSam is running. ++# {port}: The port the remote SnortSam agent listens on. ++# {password}: The password, or key, used for encryption of the ++# communication to the remote agent. ++# ++# At the very least, the IP address or host name of the host running SnortSam ++# needs to be specified. If the port is omitted, it defaults to TCP port 898. ++# If the password is omitted, it defaults to a preset password. ++# (In which case it needs to be omitted on the SnortSam agent as well) ++# ++# More than one host can be specified, but has to be done on the same line. ++# Just separate them with one or more spaces. ++# ++# Examples: ++# ++# output alert_fwsam: firewall/idspassword ++# output alert_fwsam: fw1.domain.tld:898/mykey ++# output alert_fwsam: 192.168.0.1/borderfw 192.168.1.254/wanfw ++ + # metadata reference data. do not modify these lines + include classification.config + include reference.config diff --git a/config/snort-dev/patches/inlinemode_options_flags.txt b/config/snort-dev/patches/inlinemode_options_flags.txt new file mode 100644 index 00000000..e69de29b diff --git a/config/snort-dev/patches/spoink_patch/2.8.6/Makefile.am b/config/snort-dev/patches/spoink_patch/2.8.6/Makefile.am new file mode 100644 index 00000000..0879c6e3 --- /dev/null +++ b/config/snort-dev/patches/spoink_patch/2.8.6/Makefile.am @@ -0,0 +1,17 @@ +## $Id +AUTOMAKE_OPTIONS=foreign no-dependencies + +noinst_LIBRARIES = libspo.a + +libspo_a_SOURCES = spo_alert_fast.c spo_alert_fast.h \ +spo_alert_full.c spo_alert_full.h \ +spo_alert_syslog.c spo_alert_syslog.h spo_alert_unixsock.c \ +spo_alert_unixsock.h spo_csv.c spo_csv.h spo_database.c spo_database.h \ +spo_log_null.c spo_log_null.h spo_log_tcpdump.c \ +spo_log_tcpdump.h spo_unified.c spo_unified2.c spo_unified.h spo_unified2.h \ +spo_log_ascii.c spo_log_ascii.h spo_alert_sf_socket.h spo_alert_sf_socket.c \ +spo_alert_prelude.c spo_alert_prelude.h spo_alert_arubaaction.c spo_alert_arubaaction.h \ +spo_alert_test.c spo_alert_test.h \ +spo_pf.h spo_pf.c + +INCLUDES = @INCLUDES@ diff --git a/config/snort-dev/patches/spoink_patch/2.8.6/Makefile.in b/config/snort-dev/patches/spoink_patch/2.8.6/Makefile.in new file mode 100644 index 00000000..3f06cc31 --- /dev/null +++ b/config/snort-dev/patches/spoink_patch/2.8.6/Makefile.in @@ -0,0 +1,445 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/output-plugins +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libspo_a_AR = $(AR) $(ARFLAGS) +libspo_a_LIBADD = +am_libspo_a_OBJECTS = spo_alert_fast.$(OBJEXT) \ + spo_alert_full.$(OBJEXT) spo_alert_syslog.$(OBJEXT) \ + spo_alert_unixsock.$(OBJEXT) spo_csv.$(OBJEXT) \ + spo_database.$(OBJEXT) spo_log_null.$(OBJEXT) \ + spo_log_tcpdump.$(OBJEXT) spo_unified.$(OBJEXT) \ + spo_unified2.$(OBJEXT) spo_log_ascii.$(OBJEXT) \ + spo_alert_sf_socket.$(OBJEXT) spo_alert_prelude.$(OBJEXT) \ + spo_alert_arubaaction.$(OBJEXT) spo_alert_test.$(OBJEXT) \ + spo_pf.$(OBJEXT) +libspo_a_OBJECTS = $(am_libspo_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libspo_a_SOURCES) +DIST_SOURCES = $(libspo_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_DYNAMIC_EXAMPLES_FALSE = @BUILD_DYNAMIC_EXAMPLES_FALSE@ +BUILD_DYNAMIC_EXAMPLES_TRUE = @BUILD_DYNAMIC_EXAMPLES_TRUE@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +HAVE_DYNAMIC_PLUGINS_FALSE = @HAVE_DYNAMIC_PLUGINS_FALSE@ +HAVE_DYNAMIC_PLUGINS_TRUE = @HAVE_DYNAMIC_PLUGINS_TRUE@ +HAVE_SUP_IP6_FALSE = @HAVE_SUP_IP6_FALSE@ +HAVE_SUP_IP6_TRUE = @HAVE_SUP_IP6_TRUE@ +HAVE_TARGET_BASED_FALSE = @HAVE_TARGET_BASED_FALSE@ +HAVE_TARGET_BASED_TRUE = @HAVE_TARGET_BASED_TRUE@ +HAVE_ZLIB_FALSE = @HAVE_ZLIB_FALSE@ +HAVE_ZLIB_TRUE = @HAVE_ZLIB_TRUE@ +INCLUDES = @INCLUDES@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LIBOBJS = @LIBOBJS@ +LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ +LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ +LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ +LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ +LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ +LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ +LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +extra_incl = @extra_incl@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AUTOMAKE_OPTIONS = foreign no-dependencies +noinst_LIBRARIES = libspo.a +libspo_a_SOURCES = spo_alert_fast.c spo_alert_fast.h \ +spo_alert_full.c spo_alert_full.h \ +spo_alert_syslog.c spo_alert_syslog.h spo_alert_unixsock.c \ +spo_alert_unixsock.h spo_csv.c spo_csv.h spo_database.c spo_database.h \ +spo_log_null.c spo_log_null.h spo_log_tcpdump.c \ +spo_log_tcpdump.h spo_unified.c spo_unified2.c spo_unified.h spo_unified2.h \ +spo_log_ascii.c spo_log_ascii.h spo_alert_sf_socket.h spo_alert_sf_socket.c \ +spo_alert_prelude.c spo_alert_prelude.h spo_alert_arubaaction.c spo_alert_arubaaction.h \ +spo_alert_test.c spo_alert_test.h \ +spo_pf.h spo_pf.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/output-plugins/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/output-plugins/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libspo.a: $(libspo_a_OBJECTS) $(libspo_a_DEPENDENCIES) + -rm -f libspo.a + $(libspo_a_AR) libspo.a $(libspo_a_OBJECTS) $(libspo_a_LIBADD) + $(RANLIB) libspo.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/config/snort-dev/patches/spoink_patch/2.8.6/plugbase.c b/config/snort-dev/patches/spoink_patch/2.8.6/plugbase.c new file mode 100644 index 00000000..31f381a8 --- /dev/null +++ b/config/snort-dev/patches/spoink_patch/2.8.6/plugbase.c @@ -0,0 +1,1544 @@ +/* $Id$ */ +/* +** Copyright (C) 2002-2010 Sourcefire, Inc. +** Copyright (C) 1998-2002 Martin Roesch +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License Version 2 as +** published by the Free Software Foundation. You may not use, modify or +** distribute this program under any other version of the GNU General +** Public License. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_STRINGS_H +#include +#endif + +#ifndef WIN32 +#include +#include +#include +#endif /* !WIN32 */ +#include +#include + +#include "sf_types.h" +#include "plugbase.h" +#include "spo_plugbase.h" +#include "snort.h" +#include "debug.h" +#include "util.h" +#include "log.h" +#include "detect.h" + +/* built-in preprocessors */ +#include "preprocessors/spp_rpc_decode.h" +#include "preprocessors/spp_bo.h" +#include "preprocessors/spp_stream5.h" +#include "preprocessors/spp_arpspoof.h" +#include "preprocessors/spp_perfmonitor.h" +#include "preprocessors/spp_httpinspect.h" +#include "preprocessors/spp_sfportscan.h" +#include "preprocessors/spp_frag3.h" + +/* built-in detection plugins */ +#include "detection-plugins/sp_pattern_match.h" +#include "detection-plugins/sp_tcp_flag_check.h" +#include "detection-plugins/sp_icmp_type_check.h" +#include "detection-plugins/sp_icmp_code_check.h" +#include "detection-plugins/sp_ttl_check.h" +#include "detection-plugins/sp_ip_id_check.h" +#include "detection-plugins/sp_tcp_ack_check.h" +#include "detection-plugins/sp_tcp_seq_check.h" +#include "detection-plugins/sp_dsize_check.h" +#include "detection-plugins/sp_ipoption_check.h" +#include "detection-plugins/sp_rpc_check.h" +#include "detection-plugins/sp_icmp_id_check.h" +#include "detection-plugins/sp_icmp_seq_check.h" +#include "detection-plugins/sp_session.h" +#include "detection-plugins/sp_ip_tos_check.h" +#include "detection-plugins/sp_ip_fragbits.h" +#include "detection-plugins/sp_tcp_win_check.h" +#include "detection-plugins/sp_ip_same_check.h" +#include "detection-plugins/sp_ip_proto.h" +#include "detection-plugins/sp_ip_same_check.h" +#include "detection-plugins/sp_clientserver.h" +#include "detection-plugins/sp_byte_check.h" +#include "detection-plugins/sp_byte_jump.h" +#include "detection-plugins/sp_isdataat.h" +#include "detection-plugins/sp_pcre.h" +#include "detection-plugins/sp_flowbits.h" +#include "detection-plugins/sp_file_data.h" +#include "detection-plugins/sp_asn1.h" +#ifdef ENABLE_REACT +#include "detection-plugins/sp_react.h" +#endif +#ifdef ENABLE_RESPOND +#include "detection-plugins/sp_respond.h" +#endif +#include "detection-plugins/sp_ftpbounce.h" +#include "detection-plugins/sp_urilen_check.h" +#include "detection-plugins/sp_cvs.h" + +/* built-in output plugins */ +#include "output-plugins/spo_alert_syslog.h" +#include "output-plugins/spo_log_tcpdump.h" +#include "output-plugins/spo_database.h" +#include "output-plugins/spo_alert_fast.h" +#include "output-plugins/spo_alert_full.h" +#include "output-plugins/spo_alert_unixsock.h" +#include "output-plugins/spo_csv.h" +#include "output-plugins/spo_unified.h" +#include "output-plugins/spo_log_null.h" +#include "output-plugins/spo_log_ascii.h" +#include "output-plugins/spo_unified2.h" +#include "output-plugins/spo_pf.h" + +#ifdef ARUBA +#include "output-plugins/spo_alert_arubaaction.h" +#endif + +#ifdef HAVE_LIBPRELUDE +#include "output-plugins/spo_alert_prelude.h" +#endif + +#ifdef LINUX +#include "output-plugins/spo_alert_sf_socket.h" +#endif + +#include "output-plugins/spo_alert_test.h" + +extern ListHead *head_tmp; +extern PreprocConfigFuncNode *preproc_config_funcs; +extern OutputConfigFuncNode *output_config_funcs; +extern RuleOptConfigFuncNode *rule_opt_config_funcs; +extern RuleOptOverrideInitFuncNode *rule_opt_override_init_funcs; +extern RuleOptParseCleanupNode *rule_opt_parse_cleanup_list; +extern PreprocSignalFuncNode *preproc_restart_funcs; +extern PreprocSignalFuncNode *preproc_clean_exit_funcs; +extern PreprocSignalFuncNode *preproc_shutdown_funcs; +extern PreprocSignalFuncNode *preproc_reset_funcs; +extern PreprocSignalFuncNode *preproc_reset_stats_funcs; +extern PreprocStatsFuncNode *preproc_stats_funcs; +extern PluginSignalFuncNode *plugin_shutdown_funcs; +extern PluginSignalFuncNode *plugin_clean_exit_funcs; +extern PluginSignalFuncNode *plugin_restart_funcs; +extern OutputFuncNode *AlertList; +extern OutputFuncNode *LogList; + + +/**************************** Detection Plugin API ****************************/ +/* For translation from enum to char* */ +#ifdef DEBUG +static const char *optTypeMap[OPT_TYPE_MAX] = +{ + "action", + "logging", + "detection" +}; + +#define ENUM2STR(num, map) \ + ((num < sizeof(map)/sizeof(map[0])) ? map[num] : "undefined") +#endif + + +void RegisterRuleOptions(void) +{ + LogMessage("Initializing Plug-ins!\n"); + + SetupPatternMatch(); + SetupTCPFlagCheck(); + SetupIcmpTypeCheck(); + SetupIcmpCodeCheck(); + SetupTtlCheck(); + SetupIpIdCheck(); + SetupTcpAckCheck(); + SetupTcpSeqCheck(); + SetupDsizeCheck(); + SetupIpOptionCheck(); + SetupRpcCheck(); + SetupIcmpIdCheck(); + SetupIcmpSeqCheck(); + SetupSession(); + SetupIpTosCheck(); + SetupFragBits(); + SetupFragOffset(); + SetupTcpWinCheck(); + SetupIpProto(); + SetupIpSameCheck(); + SetupClientServer(); + SetupByteTest(); + SetupByteJump(); + SetupIsDataAt(); + SetupFileData(); + SetupPcre(); + SetupFlowBits(); + SetupAsn1(); +#ifdef ENABLE_REACT + SetupReact(); +#endif +#ifdef ENABLE_RESPOND + SetupRespond(); +#endif + SetupFTPBounce(); + SetupUriLenCheck(); + SetupCvs(); +} + +/**************************************************************************** + * + * Function: RegisterRuleOption(char *, void (*func)(), enum OptionType) + * + * Purpose: Associates a rule option keyword with an option setup/linking + * function. + * + * Arguments: keyword => The option keyword to associate with the option + * handler + * *func => function pointer to the handler + * type => used to determine where keyword is allowed + * + * Returns: void function + * + ***************************************************************************/ +void RegisterRuleOption(char *opt_name, RuleOptConfigFunc config_func, + RuleOptOverrideInitFunc override_init_func, + RuleOptType opt_type, + RuleOptOtnHandler otn_handler) +{ + RuleOptConfigFuncNode *node; + + DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Registering keyword:func => %s/%s:%p\n", + ENUM2STR(opt_type, optTypeMap), opt_name, config_func);); + + node = (RuleOptConfigFuncNode *)SnortAlloc(sizeof(RuleOptConfigFuncNode)); + + if (rule_opt_config_funcs == NULL) + { + rule_opt_config_funcs = node; + } + else + { + RuleOptConfigFuncNode *tmp = rule_opt_config_funcs; + RuleOptConfigFuncNode *last; + + do + { + if (strcasecmp(tmp->keyword, opt_name) == 0) + { + free(node); + FatalError("Duplicate detection plugin keyword: %s.\n", + file_line, opt_name); + } + + last = tmp; + tmp = tmp->next; + + } while (tmp != NULL); + + last->next = node; + } + + node->keyword = SnortStrdup(opt_name); + node->type = opt_type; + node->func = config_func; + node->otn_handler = otn_handler; + + if (override_init_func != NULL) + { + RuleOptOverrideInitFuncNode *node_override = + (RuleOptOverrideInitFuncNode *)SnortAlloc(sizeof(RuleOptOverrideInitFuncNode)); + + if (rule_opt_override_init_funcs == NULL) + { + rule_opt_override_init_funcs = node_override; + } + else + { + RuleOptOverrideInitFuncNode *tmp = rule_opt_override_init_funcs; + RuleOptOverrideInitFuncNode *last; + + do + { + if (strcasecmp(tmp->keyword, opt_name) == 0) + { + free(node_override); + FatalError("RegisterRuleOption: Duplicate detection plugin keyword:" + " (%s) (%s)!\n", tmp->keyword, opt_name); + } + + last = tmp; + tmp = tmp->next; + + } while (tmp != NULL); + + last->next = node_override; + } + + node_override->keyword = SnortStrdup(opt_name); + node_override->type = opt_type; + node_override->func = override_init_func; + node_override->otn_handler = otn_handler; + } +} + +void RegisterOverrideKeyword(char *keyword, char *option, RuleOptOverrideFunc func) +{ + RuleOptOverrideInitFuncNode *node = rule_opt_override_init_funcs; + + while (node != NULL) + { + if (strcasecmp(node->keyword, keyword) == 0) + { + node->func(keyword, option, func); + break; + } + + node = node->next; + } +} + +/**************************************************************************** + * + * Function: DumpPlugIns() + * + * Purpose: Prints the keyword->function list + * + * Arguments: None. + * + * Returns: void function + * + ***************************************************************************/ +void DumpRuleOptions(void) +{ + RuleOptConfigFuncNode *node; + + node = rule_opt_config_funcs; + + LogMessage("-------------------------------------------------\n"); + LogMessage(" Keyword | Plugin Registered @\n"); + LogMessage("-------------------------------------------------\n"); + + while (node != NULL) + { + LogMessage("%-13s: %p\n", node->keyword, node->func); + node = node->next; + } + + LogMessage("-------------------------------------------------\n"); + LogMessage("\n"); +} + + +/**************************************************************************** + * + * Function: AddOptFuncToList(int (*func)(), OptTreeNode *) + * + * Purpose: Links the option detection module to the OTN + * + * Arguments: (*func)() => function pointer to the detection module + * otn => pointer to the current OptTreeNode + * + * Returns: void function + * + ***************************************************************************/ +OptFpList * AddOptFuncToList(RuleOptEvalFunc func, OptTreeNode *otn) +{ + OptFpList *ofp = (OptFpList *)SnortAlloc(sizeof(OptFpList)); + + DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n");); + + /* if there are no nodes on the function list... */ + if (otn->opt_func == NULL) + { + otn->opt_func = ofp; + } + else + { + OptFpList *tmp = otn->opt_func; + + /* walk to the end of the list */ + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = ofp; + } + + DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Set OptTestFunc to %p\n", func);); + + ofp->OptTestFunc = func; + + return ofp; +} + +/**************************************************************************** + * + * Function: AddRspFuncToList(int (*func)(), OptTreeNode *) + * + * Purpose: Adds Response function to OTN + * + * Arguments: (*func)() => function pointer to the response module + * otn => pointer to the current OptTreeNode + * + * Returns: void function + * + ***************************************************************************/ +void AddRspFuncToList(ResponseFunc func, OptTreeNode *otn, void *params) +{ + RspFpList *rsp = (RspFpList *)SnortAlloc(sizeof(RspFpList)); + + DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding response to list\n");); + + /* if there are no nodes on the function list... */ + if (otn->rsp_func == NULL) + { + otn->rsp_func = rsp; + } + else + { + RspFpList *tmp = otn->rsp_func; + + /* walk to the end of the list */ + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = rsp; + } + + DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Set ResponseFunc to %p\n", func);); + + rsp->func = func; + rsp->params = params; +} + +void PostConfigInitPlugins(PluginSignalFuncNode *post_config_funcs) +{ + while (post_config_funcs != NULL) + { + post_config_funcs->func(0, post_config_funcs->arg); + post_config_funcs = post_config_funcs->next; + } +} + +void FreeRuleOptConfigFuncs(RuleOptConfigFuncNode *head) +{ + + while (head != NULL) + { + RuleOptConfigFuncNode *tmp = head; + + head = head->next; + + if (tmp->keyword != NULL) + free(tmp->keyword); + + free(tmp); + } +} + +void FreeRuleOptOverrideInitFuncs(RuleOptOverrideInitFuncNode *head) +{ + + while (head != NULL) + { + RuleOptOverrideInitFuncNode *tmp = head; + + head = head->next; + + if (tmp->keyword != NULL) + free(tmp->keyword); + + free(tmp); + } +} + +void FreePluginSigFuncs(PluginSignalFuncNode *head) +{ + while (head != NULL) + { + PluginSignalFuncNode *tmp = head; + + head = head->next; + + /* don't free sig->arg, that's free'd by the CleanExit/Restart func */ + free(tmp); + } +} + + +/************************** Preprocessor Plugin API ***************************/ +static void AddFuncToPreprocSignalList(PreprocSignalFunc, void *, + PreprocSignalFuncNode **, uint16_t, uint32_t); + + +void RegisterPreprocessors(void) +{ + LogMessage("Initializing Preprocessors!\n"); + + SetupARPspoof(); + SetupFrag3(); + SetupStream5(); + SetupRpcDecode(); + SetupBo(); + SetupHttpInspect(); + SetupPerfMonitor(); + SetupSfPortscan(); +} + +/**************************************************************************** + * + * Function: RegisterPreprocessor(char *, void (*)(char *)) + * + * Purpose: Associates a preprocessor statement with its function. + * + * Arguments: keyword => The option keyword to associate with the + * preprocessor + * *func => function pointer to the handler + * + * Returns: void function + * + ***************************************************************************/ +#ifndef SNORT_RELOAD +void RegisterPreprocessor(char *keyword, PreprocConfigFunc func) +#else +void RegisterPreprocessor(char *keyword, PreprocConfigFunc func, + PreprocReloadFunc rfunc, PreprocReloadSwapFunc sfunc, + PreprocReloadSwapFreeFunc ffunc) +#endif +{ + PreprocConfigFuncNode *node = + (PreprocConfigFuncNode *)SnortAlloc(sizeof(PreprocConfigFuncNode)); + + DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Registering keyword:preproc => %s:%p\n", keyword, func);); + + if (preproc_config_funcs == NULL) + { + preproc_config_funcs = node; + } + else + { + PreprocConfigFuncNode *tmp = preproc_config_funcs; + PreprocConfigFuncNode *last; + + do + { + if (strcasecmp(tmp->keyword, keyword) == 0) + { + free(node); + FatalError("Duplicate preprocessor keyword: %s.\n", keyword); + } + + last = tmp; + tmp = tmp->next; + + } while (tmp != NULL); + + last->next = node; + } + + node->keyword = SnortStrdup(keyword); + node->config_func = func; + +#ifdef SNORT_RELOAD + node->reload_func = rfunc; + node->reload_swap_func = sfunc; + node->reload_swap_free_func = ffunc; +#endif +} + +PreprocConfigFuncNode * GetPreprocConfig(char *keyword) +{ + PreprocConfigFuncNode *head = preproc_config_funcs; + + if (keyword == NULL) + return NULL; + + while (head != NULL) + { + if (strcasecmp(head->keyword, keyword) == 0) + return head; + + head = head->next; + } + + return NULL; +} + +PreprocConfigFunc GetPreprocConfigFunc(char *keyword) +{ + PreprocConfigFuncNode *head = preproc_config_funcs; + + if (keyword == NULL) + return NULL; + + while (head != NULL) + { + if (strcasecmp(head->keyword, keyword) == 0) + return head->config_func; + + head = head->next; + } + + return NULL; +} + +/**************************************************************************** + * + * Function: RegisterPreprocStats(char *keyword, void (*func)(int)) + * + * Purpose: Registers a function for printing preprocessor final stats + * (or other if it has a use for printing final stats) + * + * Arguments: keyword => keyword (preprocessor) whose stats will print + * func => function pointer to the handler + * + * Returns: void function + * + ***************************************************************************/ +void RegisterPreprocStats(char *keyword, PreprocStatsFunc func) +{ + PreprocStatsFuncNode *node; + + DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Registering final stats function: " + "preproc => %s:%p\n", keyword, func);); + + node = (PreprocStatsFuncNode *)SnortAlloc(sizeof(PreprocStatsFuncNode)); + + if (preproc_stats_funcs == NULL) + { + preproc_stats_funcs = node; + } + else + { + PreprocStatsFuncNode *tmp = preproc_stats_funcs; + PreprocStatsFuncNode *last; + + do + { + if (strcasecmp(tmp->keyword, keyword) == 0) + { + free(node); + FatalError("Duplicate preprocessor keyword: %s.\n", keyword); + } + + last = tmp; + tmp = tmp->next; + + } while (tmp != NULL); + + last->next = node; + } + + node->keyword = SnortStrdup(keyword); + node->func = func; +} + +/**************************************************************************** + * + * Function: DumpPreprocessors() + * + * Purpose: Prints the keyword->preprocess list + * + * Arguments: None. + * + * Returns: void function + * + ***************************************************************************/ +void DumpPreprocessors(void) +{ + PreprocConfigFuncNode *node = preproc_config_funcs; + + LogMessage("-------------------------------------------------\n"); + LogMessage(" Keyword | Preprocessor @ \n"); + LogMessage("-------------------------------------------------\n"); + + while (node != NULL) + { + LogMessage("%-13s: %p\n", node->keyword, node->config_func); + node = node->next; + } + + LogMessage("-------------------------------------------------\n\n"); +} + +int IsPreprocEnabled(uint32_t preproc_id) +{ + PreprocEvalFuncNode *node; + SnortConfig *sc = snort_conf_for_parsing; + tSfPolicyId policy_id = getParserPolicy(); + SnortPolicy *p; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config for parsing is NULL.\n", + __FILE__, __LINE__); + } + + p = sc->targeted_policies[policy_id]; + if (p == NULL) + return 0; + + for (node = p->preproc_eval_funcs; node != NULL; node = node->next) + { + if (node->preproc_id == preproc_id) + return 1; + } + + return 0; +} + +PreprocEvalFuncNode * AddFuncToPreprocList(PreprocEvalFunc func, uint16_t priority, + uint32_t preproc_id, uint32_t proto_mask) +{ + PreprocEvalFuncNode *node; + SnortConfig *sc = snort_conf_for_parsing; + tSfPolicyId policy_id = getParserPolicy(); + SnortPolicy *p; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config for parsing is NULL.\n", + __FILE__, __LINE__); + } + + p = sc->targeted_policies[policy_id]; + if (p == NULL) + return NULL; + + DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, + "Adding preprocessor function ID %d/bit %d/pri %d to list\n", + preproc_id, p->num_preprocs, priority);); + + node = (PreprocEvalFuncNode *)SnortAlloc(sizeof(PreprocEvalFuncNode)); + + if (p->preproc_eval_funcs == NULL) + { + p->preproc_eval_funcs = node; + } + else + { + PreprocEvalFuncNode *tmp = p->preproc_eval_funcs; + PreprocEvalFuncNode *last = NULL; + + do + { + if (tmp->preproc_id == preproc_id) + { + free(node); + FatalError("Preprocessor already registered with ID %d\n", + preproc_id); + } + + /* Insert higher priority preprocessors first. Lower priority + * number means higher priority */ + if (priority < tmp->priority) + break; + + last = tmp; + tmp = tmp->next; + + } while (tmp != NULL); + + /* Priority higher than first item in list */ + if (last == NULL) + { + node->next = tmp; + p->preproc_eval_funcs = node; + } + else + { + node->next = tmp; + last->next = node; + } + } + + node->func = func; + node->priority = priority; + node->preproc_id = preproc_id; + node->preproc_bit = (1 << preproc_id); + node->proto_mask = proto_mask; + + p->num_preprocs++; + p->preproc_proto_mask |= proto_mask; + p->preproc_bit_mask |= node->preproc_bit; + + return node; +} + +void AddFuncToPreprocPostConfigList(PreprocPostConfigFunc func, void *data) +{ + PreprocPostConfigFuncNode *node; + SnortConfig *sc = snort_conf_for_parsing; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config for parsing is NULL.\n", + __FILE__, __LINE__); + } + + node = (PreprocPostConfigFuncNode *)SnortAlloc(sizeof(PreprocPostConfigFuncNode)); + + if (sc->preproc_post_config_funcs == NULL) + { + sc->preproc_post_config_funcs = node; + } + else + { + PreprocPostConfigFuncNode *tmp = sc->preproc_post_config_funcs; + + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = node; + } + + node->data = data; + node->func = func; +} + +void PostConfigPreprocessors(SnortConfig *sc) +{ + PreprocPostConfigFuncNode *list; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config is NULL.\n", + __FILE__, __LINE__); + } + + snort_conf_for_parsing = sc; + + list = sc->preproc_post_config_funcs; + + for (; list != NULL; list = list->next) + { + if (list->func != NULL) + list->func(list->data); + } + + snort_conf_for_parsing = NULL; +} + +#ifdef SNORT_RELOAD +void SwapPreprocConfigurations(void) +{ + PreprocConfigFuncNode *node = preproc_config_funcs; + + for (; node != NULL; node = node->next) + { + if (node->reload_swap_func != NULL) + node->swap_free_data = node->reload_swap_func(); + } +} + +void FreeSwappedPreprocConfigurations(void) +{ + PreprocConfigFuncNode *node = preproc_config_funcs; + + for (; node != NULL; node = node->next) + { + if ((node->reload_swap_free_func != NULL) && + (node->swap_free_data != NULL)) + { + node->reload_swap_free_func(node->swap_free_data); + node->swap_free_data = NULL; + } + } +} + +void AddFuncToPreprocReloadVerifyList(PreprocReloadVerifyFunc func) +{ + PreprocReloadVerifyFuncNode *node; + SnortConfig *sc = snort_conf_for_parsing; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config for parsing is NULL.\n", + __FILE__, __LINE__); + } + + node = (PreprocReloadVerifyFuncNode *)SnortAlloc(sizeof(PreprocReloadVerifyFuncNode)); + + if (sc->preproc_reload_verify_funcs == NULL) + { + sc->preproc_reload_verify_funcs = node; + } + else + { + PreprocReloadVerifyFuncNode *tmp = sc->preproc_reload_verify_funcs; + + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = node; + } + + node->func = func; +} + +void FreePreprocReloadVerifyFuncList(PreprocReloadVerifyFuncNode *head) +{ + while (head != NULL) + { + PreprocReloadVerifyFuncNode *tmp = head; + + head = head->next; + free(tmp); + } +} +#endif + +void AddFuncToConfigCheckList(PreprocCheckConfigFunc func) +{ + PreprocCheckConfigFuncNode *node; + SnortConfig *sc = snort_conf_for_parsing; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config for parsing is NULL.\n", + __FILE__, __LINE__); + } + + node = (PreprocCheckConfigFuncNode *)SnortAlloc(sizeof(PreprocCheckConfigFuncNode)); + + if (sc->preproc_config_check_funcs == NULL) + { + sc->preproc_config_check_funcs = node; + } + else + { + PreprocCheckConfigFuncNode *tmp = sc->preproc_config_check_funcs; + + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = node; + } + + node->func = func; +} + +/* functions to aid in cleaning up after plugins */ +void AddFuncToPreprocRestartList(PreprocSignalFunc func, void *arg, + uint16_t priority, uint32_t preproc_id) +{ + AddFuncToPreprocSignalList(func, arg, &preproc_restart_funcs, priority, preproc_id); +} + +void AddFuncToPreprocCleanExitList(PreprocSignalFunc func, void *arg, + uint16_t priority, uint32_t preproc_id) +{ + AddFuncToPreprocSignalList(func, arg, &preproc_clean_exit_funcs, priority, preproc_id); +} + +void AddFuncToPreprocShutdownList(PreprocSignalFunc func, void *arg, + uint16_t priority, uint32_t preproc_id) +{ + AddFuncToPreprocSignalList(func, arg, &preproc_shutdown_funcs, priority, preproc_id); +} + +void AddFuncToPreprocResetList(PreprocSignalFunc func, void *arg, + uint16_t priority, uint32_t preproc_id) +{ + AddFuncToPreprocSignalList(func, arg, &preproc_reset_funcs, priority, preproc_id); +} + +void AddFuncToPreprocResetStatsList(PreprocSignalFunc func, void *arg, + uint16_t priority, uint32_t preproc_id) +{ + AddFuncToPreprocSignalList(func, arg, &preproc_reset_stats_funcs, priority, preproc_id); +} + +static void AddFuncToPreprocSignalList(PreprocSignalFunc func, void *arg, + PreprocSignalFuncNode **list, + uint16_t priority, uint32_t preproc_id) +{ + PreprocSignalFuncNode *node; + + if (list == NULL) + return; + + node = (PreprocSignalFuncNode *)SnortAlloc(sizeof(PreprocSignalFuncNode)); + + if (*list == NULL) + { + *list = node; + } + else + { + PreprocSignalFuncNode *tmp = *list; + PreprocSignalFuncNode *last = NULL; + + do + { + /* Insert higher priority stuff first. Lower priority + * number means higher priority */ + if (priority < tmp->priority) + break; + + last = tmp; + tmp = tmp->next; + + } while (tmp != NULL); + + /* Priority higher than first item in list */ + if (last == NULL) + { + node->next = tmp; + *list = node; + } + else + { + node->next = tmp; + last->next = node; + } + } + + node->func = func; + node->arg = arg; + node->preproc_id = preproc_id; + node->priority = priority; +} + +void AddFuncToPreprocReassemblyPktList(PreprocReassemblyPktFunc func, uint32_t preproc_id) +{ + PreprocReassemblyPktFuncNode *node; + SnortConfig *sc = snort_conf_for_parsing; + tSfPolicyId policy_id = getParserPolicy(); + SnortPolicy *p; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config for parsing is NULL.\n", + __FILE__, __LINE__); + } + + p = sc->targeted_policies[policy_id]; + if (p == NULL) + return; + + node = (PreprocReassemblyPktFuncNode *)SnortAlloc(sizeof(PreprocReassemblyPktFuncNode)); + + if (p->preproc_reassembly_pkt_funcs == NULL) + { + p->preproc_reassembly_pkt_funcs = node; + } + else + { + PreprocReassemblyPktFuncNode *tmp = p->preproc_reassembly_pkt_funcs; + + /* just insert at front of list */ + p->preproc_reassembly_pkt_funcs = node; + node->next = tmp; + } + + node->func = func; + node->preproc_id = preproc_id; +} + +void FreePreprocConfigFuncs(void) +{ + PreprocConfigFuncNode *head = preproc_config_funcs; + PreprocConfigFuncNode *tmp; + + while (head != NULL) + { + tmp = head->next; + if (head->keyword != NULL) + free(head->keyword); + free(head); + head = tmp; + } +} + +void FreePreprocCheckConfigFuncs(PreprocCheckConfigFuncNode *head) +{ + PreprocCheckConfigFuncNode *tmp; + + while (head != NULL) + { + tmp = head->next; + free(head); + head = tmp; + } +} + +void FreePreprocPostConfigFuncs(PreprocPostConfigFuncNode *head) +{ + PreprocPostConfigFuncNode *tmp; + + while (head != NULL) + { + tmp = head->next; + free(head); + head = tmp; + } +} + +void FreePreprocStatsFuncs(PreprocStatsFuncNode *head) +{ + PreprocStatsFuncNode *tmp; + + while (head != NULL) + { + tmp = head->next; + if (head->keyword != NULL) + free(head->keyword); + free(head); + head = tmp; + } +} + +void FreePreprocEvalFuncs(PreprocEvalFuncNode *head) +{ + PreprocEvalFuncNode *tmp; + + while (head != NULL) + { + tmp = head->next; + //if (head->context) + // free(head->context); + free(head); + head = tmp; + } +} + +void FreePreprocReassemblyPktFuncs(PreprocReassemblyPktFuncNode *head) +{ + PreprocReassemblyPktFuncNode *tmp; + + while (head != NULL) + { + tmp = head->next; + free(head); + head = tmp; + } +} + +void FreePreprocSigFuncs(PreprocSignalFuncNode *head) +{ + PreprocSignalFuncNode *tmp; + + while (head != NULL) + { + tmp = head->next; + /* don't free sig->arg, that's free'd by the CleanExit/Restart func */ + free(head); + head = tmp; + } +} + +void CheckPreprocessorsConfig(SnortConfig *sc) +{ + PreprocCheckConfigFuncNode *idx; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config is NULL.\n", + __FILE__, __LINE__); + } + + snort_conf_for_parsing = sc; + + idx = sc->preproc_config_check_funcs; + + LogMessage("Verifying Preprocessor Configurations!\n"); + + while(idx != NULL) + { + idx->func(); + idx = idx->next; + } + + snort_conf_for_parsing = NULL; +} + +#ifdef SNORT_RELOAD +int VerifyReloadedPreprocessors(SnortConfig *sc) +{ + PreprocReloadVerifyFuncNode *node; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config is NULL.\n", + __FILE__, __LINE__); + } + + snort_conf_for_parsing = sc; + + node = sc->preproc_reload_verify_funcs; + while (node != NULL) + { + if (node->func != NULL) + { + if (node->func() == -1) + return -1; + } + + node = node->next; + } + + snort_conf_for_parsing = NULL; + + return 0; +} +#endif + + +/***************************** Output Plugin API *****************************/ +extern OutputConfigFuncNode *output_config_funcs; + +static void AppendOutputFuncList(OutputFunc, void *, OutputFuncNode **); + +void RegisterOutputPlugins(void) +{ + LogMessage("Initializing Output Plugins!\n"); + + AlertSyslogSetup(); + LogTcpdumpSetup(); + DatabaseSetup(); + AlertFastSetup(); + AlertFullSetup(); + AlertPfSetup(); +#ifndef WIN32 + /* Win32 doesn't support AF_UNIX sockets */ + AlertUnixSockSetup(); +#endif /* !WIN32 */ + AlertCSVSetup(); + LogNullSetup(); + UnifiedSetup(); + Unified2Setup(); + LogAsciiSetup(); + +#ifdef ARUBA + AlertArubaActionSetup(); +#endif + +#ifdef LINUX + /* This uses linux only capabilities */ + AlertSFSocket_Setup(); +#endif + +#ifdef HAVE_LIBPRELUDE + AlertPreludeSetup(); +#endif + + AlertTestSetup(); +} + +/**************************************************************************** + * + * Function: RegisterOutputPlugin(char *, void (*func)(Packet *, u_char *)) + * + * Purpose: Associates an output statement with its function. + * + * Arguments: keyword => The output keyword to associate with the + * output processor + * type => alert or log types + * *func => function pointer to the handler + * + * Returns: void function + * + ***************************************************************************/ +void RegisterOutputPlugin(char *keyword, int type_flags, OutputConfigFunc func) +{ + OutputConfigFuncNode *node = (OutputConfigFuncNode *)SnortAlloc(sizeof(OutputConfigFuncNode)); + + DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Registering keyword:output => %s:%p\n", + keyword, func);); + + if (output_config_funcs == NULL) + { + output_config_funcs = node; + } + else + { + OutputConfigFuncNode *tmp = output_config_funcs; + OutputConfigFuncNode *last; + + do + { + if (strcasecmp(tmp->keyword, keyword) == 0) + { + free(node); + FatalError("Duplicate output keyword: %s\n", keyword); + } + + last = tmp; + tmp = tmp->next; + + } while (tmp != NULL); + + last->next = node; + } + + node->keyword = SnortStrdup(keyword); + node->func = func; + node->output_type_flags = type_flags; +} + +OutputConfigFunc GetOutputConfigFunc(char *keyword) +{ + OutputConfigFuncNode *head = output_config_funcs; + + if (keyword == NULL) + return NULL; + + while (head != NULL) + { + if (strcasecmp(head->keyword, keyword) == 0) + return head->func; + + head = head->next; + } + + return NULL; +} + +int GetOutputTypeFlags(char *keyword) +{ + OutputConfigFuncNode *head = output_config_funcs; + + if (keyword == NULL) + return 0; + + while (head != NULL) + { + if (strcasecmp(head->keyword, keyword) == 0) + return head->output_type_flags; + + head = head->next; + } + + return 0; +} + +void FreeOutputConfigFuncs(void) +{ + OutputConfigFuncNode *head = output_config_funcs; + OutputConfigFuncNode *tmp; + + while (head != NULL) + { + tmp = head->next; + if (head->keyword != NULL) + free(head->keyword); + free(head); + head = tmp; + } +} + +void FreeOutputList(OutputFuncNode *list) +{ + while (list != NULL) + { + OutputFuncNode *tmp = list; + + list = list->next; + free(tmp); + } +} + +/**************************************************************************** + * + * Function: DumpOutputPlugins() + * + * Purpose: Prints the keyword->preprocess list + * + * Arguments: None. + * + * Returns: void function + * + ***************************************************************************/ +void DumpOutputPlugins(void) +{ + OutputConfigFuncNode *idx = output_config_funcs; + + LogMessage("-------------------------------------------------\n"); + LogMessage(" Keyword | Output @ \n"); + LogMessage("-------------------------------------------------\n"); + while(idx != NULL) + { + LogMessage("%-13s: %p\n", idx->keyword, idx->func); + idx = idx->next; + } + LogMessage("-------------------------------------------------\n\n"); +} + +void AddFuncToOutputList(OutputFunc func, OutputType type, void *arg) +{ + switch (type) + { + case OUTPUT_TYPE__ALERT: + if (head_tmp != NULL) + AppendOutputFuncList(func, arg, &head_tmp->AlertList); + else + AppendOutputFuncList(func, arg, &AlertList); + + break; + + case OUTPUT_TYPE__LOG: + if (head_tmp != NULL) + AppendOutputFuncList(func, arg, &head_tmp->LogList); + else + AppendOutputFuncList(func, arg, &LogList); + + break; + + default: + /* just to be error-prone */ + FatalError("Unknown output type: %i. Possible bug, please " + "report.\n", type); + } +} + +void AppendOutputFuncList(OutputFunc func, void *arg, OutputFuncNode **list) +{ + OutputFuncNode *node; + + if (list == NULL) + return; + + node = (OutputFuncNode *)SnortAlloc(sizeof(OutputFuncNode)); + + if (*list == NULL) + { + *list = node; + } + else + { + OutputFuncNode *tmp = *list; + + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = node; + } + + node->func = func; + node->arg = arg; +} + + +/************************** Miscellaneous Functions **************************/ + +/* functions to aid in cleaning up after plugins + * Used for both rule options and output. Preprocessors have their own */ +void AddFuncToRestartList(PluginSignalFunc func, void *arg) +{ + AddFuncToSignalList(func, arg, &plugin_restart_funcs); +} + +void AddFuncToCleanExitList(PluginSignalFunc func, void *arg) +{ + AddFuncToSignalList(func, arg, &plugin_clean_exit_funcs); +} + +void AddFuncToShutdownList(PluginSignalFunc func, void *arg) +{ + AddFuncToSignalList(func, arg, &plugin_shutdown_funcs); +} + +void AddFuncToPostConfigList(PluginSignalFunc func, void *arg) +{ + SnortConfig *sc = snort_conf_for_parsing; + + if (sc == NULL) + { + FatalError("%s(%d) Snort config for parsing is NULL.\n", + __FILE__, __LINE__); + } + + AddFuncToSignalList(func, arg, &sc->plugin_post_config_funcs); +} + +void AddFuncToSignalList(PluginSignalFunc func, void *arg, PluginSignalFuncNode **list) +{ + PluginSignalFuncNode *node; + + if (list == NULL) + return; + + node = (PluginSignalFuncNode *)SnortAlloc(sizeof(PluginSignalFuncNode)); + + if (*list == NULL) + { + *list = node; + } + else + { + PluginSignalFuncNode *tmp = *list; + + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = node; + } + + node->func = func; + node->arg = arg; +} + +void AddFuncToRuleOptParseCleanupList(RuleOptParseCleanupFunc func) +{ + RuleOptParseCleanupNode *node = + (RuleOptParseCleanupNode *)SnortAlloc(sizeof(RuleOptParseCleanupNode)); + + if (rule_opt_parse_cleanup_list == NULL) + { + rule_opt_parse_cleanup_list = node; + } + else + { + RuleOptParseCleanupNode *tmp = rule_opt_parse_cleanup_list; + + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = node; + } + + node->func = func; +} + +void RuleOptParseCleanup(void) +{ + RuleOptParseCleanupNode *list = rule_opt_parse_cleanup_list; + + for (; list != NULL; list = list->next) + { + if (list->func != NULL) + list->func(); + } +} + +void FreeRuleOptParseCleanupList(RuleOptParseCleanupNode *head) +{ + while (head != NULL) + { + RuleOptParseCleanupNode *tmp = head; + + head = head->next; + free(tmp); + } +} + + diff --git a/config/snort-dev/patches/spoink_patch/2.8.6/util.c b/config/snort-dev/patches/spoink_patch/2.8.6/util.c new file mode 100644 index 00000000..b2d3b38b --- /dev/null +++ b/config/snort-dev/patches/spoink_patch/2.8.6/util.c @@ -0,0 +1,3233 @@ +/* $Id$ */ +/* +** Copyright (C) 2002-2010 Sourcefire, Inc. +** Copyright (C) 2002 Martin Roesch +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License Version 2 as +** published by the Free Software Foundation. You may not use, modify or +** distribute this program under any other version of the GNU General +** Public License. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#endif /* !WIN32 */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#endif /* !WIN32 */ + +#include + +#ifdef HAVE_STRINGS_H +#include +#endif + +#ifdef ZLIB +#include +#endif + +#include "snort.h" +#include "mstring.h" +#include "debug.h" +#include "util.h" +#include "parser.h" +#include "inline.h" +#include "build.h" +#include "plugbase.h" +#include "sf_types.h" +#include "sflsq.h" +#include "ipv6_port.h" + +#include "pcre.h" + +#include "mpse.h" + +#include "ppm.h" + +#ifdef TARGET_BASED +#include "sftarget_reader.h" +#endif + +#ifdef WIN32 +#include "win32/WIN32-Code/name.h" +#endif + +#include "stream5_common.h" + +#ifdef PATH_MAX +#define PATH_MAX_UTIL PATH_MAX +#else +#define PATH_MAX_UTIL 1024 +#endif /* PATH_MAX */ + +extern Stream5Stats s5stats; +extern int datalink; +extern pcap_t *pcap_handle; +extern PreprocStatsFuncNode *preproc_stats_funcs; + +static PcapPktStats pkt_stats; + +/* + * you may need to adjust this on the systems which don't have standard + * paths defined + */ +#ifndef _PATH_VARRUN +static char _PATH_VARRUN[STD_BUF]; +#endif + + +#ifdef NAME_MAX +#define NAME_MAX_UTIL NAME_MAX +#else +#define NAME_MAX_UTIL 256 +#endif /* NAME_MAX */ + +#define FILE_MAX_UTIL (PATH_MAX_UTIL + NAME_MAX_UTIL) + +/**************************************************************************** + * + * Function: CalcPct(uint64_t, uint64_t) + * + * Purpose: Calculate the percentage of a value compared to a total + * + * Arguments: cnt => the numerator in the equation + * total => the denominator in the calculation + * + * Returns: pct -> the percentage of cnt to value + * + ****************************************************************************/ +double CalcPct(uint64_t cnt, uint64_t total) +{ + double pct = 0.0; + + if (total == 0.0) + { + pct = (double)cnt; + } + else + { + pct = (double)cnt / (double)total; + } + + pct *= 100.0; + + return pct; +} + + +/**************************************************************************** + * + * Function: DisplayBanner() + * + * Purpose: Show valuable proggie info + * + * Arguments: None. + * + * Returns: 0 all the time + * + ****************************************************************************/ +int DisplayBanner(void) +{ + const char * info; + const char * pcre_ver; +#ifdef ZLIB + const char * zlib_ver; +#endif + + info = getenv("HOSTTYPE"); + if( !info ) + { + info=""; + } + + pcre_ver = pcre_version(); +#ifdef ZLIB + zlib_ver = zlib_version; +#endif + + LogMessage("\n"); + LogMessage(" ,,_ -*> Snort! <*-\n"); + LogMessage(" o\" )~ Version %s%s%s (Build %s) %s %s\n", + VERSION, +#ifdef SUP_IP6 + " IPv6", +#else + "", +#endif +#ifdef GRE + " GRE", +#else + "", +#endif + BUILD, +#ifdef GIDS + "inline", +#else + "", +#endif + info); + LogMessage(" '''' By Martin Roesch & The Snort Team: http://www.snort.org/snort/snort-team\n"); + LogMessage(" Copyright (C) 1998-2010 Sourcefire, Inc., et al.\n"); + LogMessage(" Using PCRE version: %s\n", pcre_ver); +#ifdef ZLIB + LogMessage(" Using ZLIB version: %s\n", zlib_ver); +#endif + LogMessage("\n"); + LogMessage(" ___ Built Date for Snort on Pfsense 2.0 is May 25 2010.\n"); + LogMessage(" ___/ f \\ Orion IPS Output Code Copyright (C) 2009-2010 Robert Zelaya.\n"); + LogMessage("/ p \\___/Sense\n"); + LogMessage("\\___/ \\\n"); + LogMessage(" \\___/ Using Snort.org dynamic plugins and Orion IPS source.\n"); + LogMessage("\n"); + + return 0; +} + + + +/**************************************************************************** + * + * Function: ts_print(register const struct, char *) + * + * Purpose: Generate a time stamp and stuff it in a buffer. This one has + * millisecond precision. Oh yeah, I ripped this code off from + * TCPdump, props to those guys. + * + * Arguments: timeval => clock struct coming out of libpcap + * timebuf => buffer to stuff timestamp into + * + * Returns: void function + * + ****************************************************************************/ +void ts_print(register const struct timeval *tvp, char *timebuf) +{ + register int s; + int localzone; + time_t Time; + struct timeval tv; + struct timezone tz; + struct tm *lt; /* place to stick the adjusted clock data */ + + /* if null was passed, we use current time */ + if(!tvp) + { + /* manual page (for linux) says tz is never used, so.. */ + bzero((char *) &tz, sizeof(tz)); + gettimeofday(&tv, &tz); + tvp = &tv; + } + + localzone = snort_conf->thiszone; + + /* + ** If we're doing UTC, then make sure that the timezone is correct. + */ + if (ScOutputUseUtc()) + localzone = 0; + + s = (tvp->tv_sec + localzone) % 86400; + Time = (tvp->tv_sec + localzone) - s; + + lt = gmtime(&Time); + + if (ScOutputIncludeYear()) + { + (void) SnortSnprintf(timebuf, TIMEBUF_SIZE, + "%02d/%02d/%02d-%02d:%02d:%02d.%06u ", + lt->tm_mon + 1, lt->tm_mday, lt->tm_year - 100, + s / 3600, (s % 3600) / 60, s % 60, + (u_int) tvp->tv_usec); + } + else + { + (void) SnortSnprintf(timebuf, TIMEBUF_SIZE, + "%02d/%02d-%02d:%02d:%02d.%06u ", lt->tm_mon + 1, + lt->tm_mday, s / 3600, (s % 3600) / 60, s % 60, + (u_int) tvp->tv_usec); + } +} + + + +/**************************************************************************** + * + * Function: gmt2local(time_t) + * + * Purpose: Figures out how to adjust the current clock reading based on the + * timezone you're in. Ripped off from TCPdump. + * + * Arguments: time_t => offset from GMT + * + * Returns: offset seconds from GMT + * + ****************************************************************************/ +int gmt2local(time_t t) +{ + register int dt, dir; + register struct tm *gmt, *loc; + struct tm sgmt; + + if(t == 0) + t = time(NULL); + + gmt = &sgmt; + *gmt = *gmtime(&t); + loc = localtime(&t); + + dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + + dir = loc->tm_year - gmt->tm_year; + + if(dir == 0) + dir = loc->tm_yday - gmt->tm_yday; + + dt += dir * 24 * 60 * 60; + + return(dt); +} + + + + +/**************************************************************************** + * + * Function: copy_argv(u_char **) + * + * Purpose: Copies a 2D array (like argv) into a flat string. Stolen from + * TCPDump. + * + * Arguments: argv => 2D array to flatten + * + * Returns: Pointer to the flat string + * + ****************************************************************************/ +char *copy_argv(char **argv) +{ + char **p; + u_int len = 0; + char *buf; + char *src, *dst; + //void ftlerr(char *,...); + + p = argv; + if(*p == 0) + return 0; + + while(*p) + len += strlen(*p++) + 1; + + buf = (char *) calloc(1,len); + + if(buf == NULL) + { + FatalError("calloc() failed: %s\n", strerror(errno)); + } + p = argv; + dst = buf; + + while((src = *p++) != NULL) + { + while((*dst++ = *src++) != '\0'); + dst[-1] = ' '; + } + + dst[-1] = '\0'; + + /* Check for an empty string */ + dst = buf; + while (isspace((int)*dst)) + dst++; + + if (strlen(dst) == 0) + { + free(buf); + buf = NULL; + } + + return buf; +} + + +/**************************************************************************** + * + * Function: strip(char *) + * + * Purpose: Strips a data buffer of CR/LF/TABs. Replaces CR/LF's with + * NULL and TABs with spaces. + * + * Arguments: data => ptr to the data buf to be stripped + * + * Returns: void + * + * 3/7/07 - changed to return void - use strlen to get size of string + * + * Note that this function will turn all '\n' and '\r' into null chars + * so, e.g. 'Hello\nWorld\n' => 'Hello\x00World\x00' + * note that the string is now just 'Hello' and the length is shortened + * by more than just an ending '\n' or '\r' + ****************************************************************************/ +void strip(char *data) +{ + int size; + char *end; + char *idx; + + idx = data; + end = data + strlen(data); + size = end - idx; + + while(idx != end) + { + if((*idx == '\n') || + (*idx == '\r')) + { + *idx = 0; + size--; + } + if(*idx == '\t') + { + *idx = ' '; + } + idx++; + } +} + +/* + * Function: ErrorMessage(const char *, ...) + * + * Purpose: Print a message to stderr. + * + * Arguments: format => the formatted error string to print out + * ... => format commands/fillers + * + * Returns: void function + */ +void ErrorMessage(const char *format,...) +{ + char buf[STD_BUF+1]; + va_list ap; + + if (snort_conf == NULL) + return; + + va_start(ap, format); + + if (ScDaemonMode() || ScLogSyslog()) + { + vsnprintf(buf, STD_BUF, format, ap); + buf[STD_BUF] = '\0'; + syslog(LOG_CONS | LOG_DAEMON | LOG_ERR, "%s", buf); + } + else + { + vfprintf(stderr, format, ap); + } + va_end(ap); +} + +/* + * Function: LogMessage(const char *, ...) + * + * Purpose: Print a message to stderr or with logfacility. + * + * Arguments: format => the formatted error string to print out + * ... => format commands/fillers + * + * Returns: void function + */ +void LogMessage(const char *format,...) +{ + char buf[STD_BUF+1]; + va_list ap; + + if (snort_conf == NULL) + return; + + if (ScLogQuiet() && !ScDaemonMode() && !ScLogSyslog()) + return; + + va_start(ap, format); + + if (ScDaemonMode() || ScLogSyslog()) + { + vsnprintf(buf, STD_BUF, format, ap); + buf[STD_BUF] = '\0'; + syslog(LOG_DAEMON | LOG_NOTICE, "%s", buf); + } + else + { + vfprintf(stderr, format, ap); + } + + va_end(ap); +} + +/* + * Function: CreateApplicationEventLogEntry(const char *) + * + * Purpose: Add an entry to the Win32 "Application" EventLog + * + * Arguments: szMessage => the formatted error string to print out + * + * Returns: void function + */ +#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE) +void CreateApplicationEventLogEntry(const char *msg) +{ + HANDLE hEventLog; + char* pEventSourceName = "SnortService"; + + /* prepare to write to Application log on local host + * with Event Source of SnortService + */ + AddEventSource(pEventSourceName); + hEventLog = RegisterEventSource(NULL, pEventSourceName); + if (hEventLog == NULL) + { + /* Could not register the event source. */ + return; + } + + if (!ReportEvent(hEventLog, /* event log handle */ + EVENTLOG_ERROR_TYPE, /* event type */ + 0, /* category zero */ + EVMSG_SIMPLE, /* event identifier */ + NULL, /* no user security identifier */ + 1, /* one substitution string */ + 0, /* no data */ + &msg, /* pointer to array of strings */ + NULL)) /* pointer to data */ + { + /* Could not report the event. */ + } + + DeregisterEventSource(hEventLog); +} +#endif /* WIN32 && ENABLE_WIN32_SERVICE */ + + +/* + * Function: FatalError(const char *, ...) + * + * Purpose: When a fatal error occurs, this function prints the error message + * and cleanly shuts down the program + * + * Arguments: format => the formatted error string to print out + * ... => format commands/fillers + * + * Returns: void function + */ +NORETURN void FatalError(const char *format,...) +{ + char buf[STD_BUF+1]; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, STD_BUF, format, ap); + va_end(ap); + + buf[STD_BUF] = '\0'; + + if ((snort_conf != NULL) && (ScDaemonMode() || ScLogSyslog())) + { + syslog(LOG_CONS | LOG_DAEMON | LOG_ERR, "FATAL ERROR: %s", buf); + } + else + { + fprintf(stderr, "ERROR: %s", buf); + fprintf(stderr,"Fatal Error, Quitting..\n"); +#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE) + CreateApplicationEventLogEntry(buf); +#endif + } + + exit(1); +} + + +/**************************************************************************** + * + * Function: CreatePidFile(char *) + * + * Purpose: Creates a PID file + * + * Arguments: Interface opened. + * + * Returns: void function + * + ****************************************************************************/ +static FILE *pid_lockfile = NULL; +static FILE *pid_file = NULL; +void CreatePidFile(char *intf) +{ + struct stat pt; + int pid = (int) getpid(); +#ifdef WIN32 + char dir[STD_BUF + 1]; +#endif + + if (!ScReadMode()) + { + LogMessage("Checking PID path...\n"); + + if (strlen(snort_conf->pid_path) != 0) + { + if((stat(snort_conf->pid_path, &pt) == -1) || + !S_ISDIR(pt.st_mode) || access(snort_conf->pid_path, W_OK) == -1) + { +#ifndef WIN32 + /* Save this just in case it's reset with LogMessage call */ + int err = errno; + + LogMessage("WARNING: %s is invalid, trying " + "/var/run...\n", snort_conf->pid_path); + if (err) + { + LogMessage("Previous Error, errno=%d, (%s)\n", + err, strerror(err) == NULL ? "Unknown error" : strerror(err)); + } +#endif + memset(snort_conf->pid_path, 0, sizeof(snort_conf->pid_path)); + } + else + { + LogMessage("PID path stat checked out ok, " + "PID path set to %s\n", snort_conf->pid_path); + } + } + + if (strlen(snort_conf->pid_path) == 0) + { +#ifndef _PATH_VARRUN +# ifndef WIN32 + SnortStrncpy(_PATH_VARRUN, "/var/run/", sizeof(_PATH_VARRUN)); +# else + if (GetCurrentDirectory(sizeof(dir) - 1, dir)) + SnortStrncpy(_PATH_VARRUN, dir, sizeof(_PATH_VARRUN)); +# endif /* WIN32 */ +#else + LogMessage("PATH_VARRUN is set to %s on this operating " + "system\n", _PATH_VARRUN); +#endif /* _PATH_VARRUN */ + + stat(_PATH_VARRUN, &pt); + + if(!S_ISDIR(pt.st_mode) || access(_PATH_VARRUN, W_OK) == -1) + { + LogMessage("WARNING: _PATH_VARRUN is invalid, trying " + "/var/log...\n"); + SnortStrncpy(snort_conf->pid_path, "/var/log/", sizeof(snort_conf->pid_path)); + stat(snort_conf->pid_path, &pt); + + if(!S_ISDIR(pt.st_mode) || access(snort_conf->pid_path, W_OK) == -1) + { + LogMessage("WARNING: %s is invalid, logging Snort " + "PID path to log directory (%s)\n", snort_conf->pid_path, + snort_conf->log_dir); + CheckLogDir(); + SnortSnprintf(snort_conf->pid_path, sizeof(snort_conf->pid_path), + "%s/", snort_conf->log_dir); + } + } + else + { + LogMessage("PID path stat checked out ok, " + "PID path set to %s\n", _PATH_VARRUN); + SnortStrncpy(snort_conf->pid_path, _PATH_VARRUN, sizeof(snort_conf->pid_path)); + } + } + } + + if(intf == NULL || strlen(snort_conf->pid_path) == 0) + { + /* snort_conf->pid_path should have some value by now + * so let us just be sane. */ + FatalError("CreatePidFile() failed to lookup interface or pid_path is unknown!\n"); + } + + SnortSnprintf(snort_conf->pid_filename, sizeof(snort_conf->pid_filename), + "%s/snort_%s%s.pid", snort_conf->pid_path, intf, snort_conf->pidfile_suffix); + +#ifndef WIN32 + if (!ScNoLockPidFile()) + { + char pid_lockfilename[STD_BUF+1]; + int lock_fd; + + /* First, lock the PID file */ + SnortSnprintf(pid_lockfilename, STD_BUF, "%s.lck", snort_conf->pid_filename); + pid_lockfile = fopen(pid_lockfilename, "w"); + + if (pid_lockfile) + { + struct flock lock; + lock_fd = fileno(pid_lockfile); + + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + if (fcntl(lock_fd, F_SETLK, &lock) == -1) + { + ClosePidFile(); + FatalError("Failed to Lock PID File \"%s\" for PID \"%d\"\n", snort_conf->pid_filename, pid); + } + } + } +#endif + + /* Okay, were able to lock PID file, now open and write PID */ + pid_file = fopen(snort_conf->pid_filename, "w"); + if(pid_file) + { + LogMessage("Writing PID \"%d\" to file \"%s\"\n", pid, snort_conf->pid_filename); + fprintf(pid_file, "%d\n", pid); + fflush(pid_file); + } + else + { + ErrorMessage("Failed to create pid file %s", snort_conf->pid_filename); + snort_conf->pid_filename[0] = 0; + } +} + +/**************************************************************************** + * + * Function: ClosePidFile(char *) + * + * Purpose: Releases lock on a PID file + * + * Arguments: None + * + * Returns: void function + * + ****************************************************************************/ +void ClosePidFile(void) +{ + if (pid_file) + { + fclose(pid_file); + pid_file = NULL; + } + if (pid_lockfile) + { + fclose(pid_lockfile); + pid_lockfile = NULL; + } +} + +/**************************************************************************** + * + * Function: SetUidGid() + * + * Purpose: Sets safe UserID and GroupID if needed + * + * Arguments: none + * + * Returns: void function + * + ****************************************************************************/ +void SetUidGid(int user_id, int group_id) +{ +#ifndef WIN32 + + if ((group_id != -1) && (getgid() != (gid_t)group_id)) + { + if (!InlineModeSetPrivsAllowed()) + { + ErrorMessage("Cannot set uid and gid when running Snort in " + "inline mode.\n"); + return; + } + + if (setgid(group_id) < 0) + FatalError("Cannot set gid: %d\n", group_id); + + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Set gid to %d\n", group_id);); + } + + if ((user_id != -1) && (getuid() != (uid_t)user_id)) + { + struct passwd *pw = getpwuid(user_id); + + if (!InlineModeSetPrivsAllowed()) + { + ErrorMessage("Cannot set uid and gid when running Snort in " + "inline mode.\n"); + return; + } + + if (pw != NULL) + { + /* getpwuid and initgroups may use the same static buffers */ + char *username = SnortStrdup(pw->pw_name); + + if ((getuid() == 0) && (initgroups(username, group_id) < 0)) + { + free(username); + FatalError("Can not initgroups(%s,%d)", + username, group_id); + } + + free(username); + } + + /** just to be on a safe side... **/ + endgrent(); + endpwent(); + + if (setuid(user_id) < 0) + FatalError("Can not set uid: %d\n", user_id); + + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Set uid to %d\n", user_id);); + } +#endif /* WIN32 */ +} + +#ifdef TIMESTATS + +static IntervalStats istats = {0}; +time_t start_time; + +void InitTimeStats(void) +{ + start_time = time(NULL); +} + +void ResetTimeStats(void) +{ + memset(&istats, 0, sizeof(istats)); +} + +/* This function prints out stats based on a configurable time + * interval. It is an indication on how well snort is */ +/* processing packets, including types, drops, etc */ +void DropStatsPerTimeInterval(void) +{ + double per_sec, per_minute, per_hour; + uint64_t recv, drop; + uint64_t total = 0; + uint32_t timestats_interval = ScTimestatsInterval(); + +#ifdef PCAP_CLOSE + if (UpdatePcapPktStats(0) != -1) +#else + if (UpdatePcapPktStats() != -1) +#endif + { + recv = GetPcapPktStatsRecv(); + drop = GetPcapPktStatsDrop(); + + istats.recv = recv - istats.recv_total; + istats.recv_total = recv; + + istats.drop = drop - istats.drop_total; + istats.drop_total = drop; + + /* calculate received packets by type */ + istats.tcp = pc.tcp - istats.tcp_total; + istats.tcp_total = pc.tcp; + + istats.udp = pc.udp - istats.udp_total; + istats.udp_total = pc.udp; + + istats.icmp = pc.icmp - istats.icmp_total; + istats.icmp_total = pc.icmp; + + istats.arp = pc.arp - istats.arp_total; + istats.arp_total = pc.arp; + +#ifdef GRE + istats.ip4ip4 = pc.ip4ip4 - istats.ip4ip4_total; + istats.ip4ip4_total = pc.ip4ip4; + + istats.ip4ip6 = pc.ip4ip6 - istats.ip4ip6_total; + istats.ip4ip6_total = pc.ip4ip6; + + istats.ip6ip4 = pc.ip6ip4 - istats.ip6ip4_total; + istats.ip6ip4_total = pc.ip6ip4; + + istats.ip6ip6 = pc.ip6ip6 - istats.ip6ip6_total; + istats.ip6ip6_total = pc.ip6ip6; + + istats.gre = pc.gre - istats.gre_total; + istats.gre_total = pc.gre; + + istats.gre_ip = pc.gre_ip - istats.gre_ip_total; + istats.gre_ip_total = pc.gre_ip; + + istats.gre_eth = pc.gre_eth - istats.gre_eth_total; + istats.gre_eth_total = pc.gre_eth; + + istats.gre_arp = pc.gre_arp - istats.gre_arp_total; + istats.gre_arp_total = pc.gre_arp; + + istats.gre_ipv6 = pc.gre_ipv6 - istats.gre_ipv6_total; + istats.gre_ipv6_total = pc.gre_ipv6; + + istats.gre_ipx = pc.gre_ipx - istats.gre_ipx_total; + istats.gre_ipx_total = pc.gre_ipx; + + istats.gre_loopback = pc.gre_loopback - istats.gre_loopback_total; + istats.gre_loopback_total = pc.gre_loopback; + + istats.gre_vlan = pc.gre_vlan - istats.gre_vlan_total; + istats.gre_vlan_total = pc.gre_vlan; + + istats.gre_ppp = pc.gre_ppp - istats.gre_ppp_total; + istats.gre_ppp_total = pc.gre_ppp; +#endif + +#ifdef DLT_IEEE802_11 /* if we are tracking wireless, add this to output */ + istats.wifi_mgmt = pc.wifi_mgmt - istats.wifi_mgmt_total; + istats.wifi_mgmt_total = pc.wifi_mgmt; + + istats.wifi_control = pc.wifi_control - istats.wifi_control_total; + istats.wifi_control_total = pc.wifi_control; + + istats.wifi_data = pc.wifi_data - istats.wifi_data_total; + istats.wifi_data_total = pc.wifi_data; +#endif + + istats.ipx = pc.ipx - istats.ipx_total; + istats.ipx_total = pc.ipx; + + istats.eapol = pc.eapol - istats.eapol_total; + istats.eapol_total = pc.eapol; + + istats.ipv6 = pc.ipv6 - istats.ipv6_total; + istats.ipv6_total = pc.ipv6; + + istats.ethloopback = pc.ethloopback - istats.ethloopback_total; + istats.ethloopback_total = pc.ethloopback; + + istats.other = pc.other - istats.other_total; + istats.other_total = pc.other; + + istats.discards = pc.discards - istats.discards_total; + istats.discards_total = pc.discards; + + if (pc.frags > 0) /* do we have any fragmented packets being seen? */ + { + istats.frags = pc.frags - istats.frags_total; + istats.frags_total = pc.frags; + + istats.frag_trackers = pc.frag_trackers - istats.frag_trackers_total; + istats.frag_trackers_total = pc.frag_trackers; + + istats.frag_rebuilt = pc.rebuilt_frags - istats.frag_rebuilt_total; + istats.frag_rebuilt_total = pc.rebuilt_frags; + + istats.frag_element = pc.rebuild_element - istats.frag_element_total; + istats.frag_element_total = pc.rebuild_element; + + istats.frag_incomp = pc.frag_incomp - istats.frag_incomp_total; + istats.frag_incomp_total = pc.frag_incomp; + + istats.frag_timeout = pc.frag_timeout - istats.frag_timeout_total; + istats.frag_timeout_total = pc.frag_timeout; + + istats.frag_mem_faults = pc.frag_mem_faults - istats.frag_mem_faults_total; + istats.frag_mem_faults_total = pc.frag_mem_faults; + } + + if (pc.tcp_stream_pkts > 0) /* do we have TCP stream re-assembly going on? */ + { + istats.tcp_str_packets = pc.tcp_stream_pkts - istats.tcp_str_packets_total; + istats.tcp_str_packets_total = pc.tcp_stream_pkts; + + istats.tcp_str_trackers = pc.tcp_streams - istats.tcp_str_trackers_total; + istats.tcp_str_trackers_total = pc.tcp_streams; + + istats.tcp_str_flushes = pc.rebuilt_tcp - istats.tcp_str_flushes_total; + istats.tcp_str_flushes_total = pc.rebuilt_tcp; + + istats.tcp_str_segs_used = pc.rebuilt_segs - istats.tcp_str_segs_used_total; + istats.tcp_str_segs_used_total = pc.rebuilt_segs; + + istats.tcp_str_segs_queued = pc.queued_segs - istats.tcp_str_segs_queued_total; + istats.tcp_str_segs_queued_total = pc.queued_segs; + + istats.tcp_str_mem_faults = pc.str_mem_faults - istats.tcp_str_mem_faults_total; + istats.tcp_str_mem_faults_total = pc.str_mem_faults; + } + + istats.processed = pc.total_processed - istats.processed_total; + istats.processed_total = pc.total_processed; + total = istats.processed; + + /* prepare packet type per time interval routine */ + LogMessage("================================================" + "===============================\n"); + + LogMessage("\n"); + LogMessage("Statistics Report (last %d seconds)\n", timestats_interval); + LogMessage("\n"); + + per_sec = (double)istats.recv / (double)timestats_interval; + + LogMessage("Packet Wire Totals:\n"); + LogMessage("Packets received: " FMTu64("13") "\n", istats.recv); + + if (timestats_interval >= SECONDS_PER_HOUR) + { + per_hour = (double)(istats.recv * SECONDS_PER_HOUR) / (double)timestats_interval; + LogMessage(" per hour: %13.2f\n", per_hour); + } + if (timestats_interval >= SECONDS_PER_MIN) + { + per_minute = (double)(istats.recv * SECONDS_PER_MIN) / (double)timestats_interval; + LogMessage(" per minute: %13.2f\n", per_minute); + } + LogMessage(" per second: %13.2f\n", per_sec); + LogMessage(" Packets dropped: " FMTu64("13") "\n", istats.drop); + LogMessage("\n"); + LogMessage("Packet Breakdown by Protocol (includes rebuilt packets):\n"); + + LogMessage(" TCP: " FMTu64("10") " (%.3f%%)\n", + istats.tcp, CalcPct(istats.tcp, total)); + LogMessage(" UDP: " FMTu64("10") " (%.3f%%)\n", + istats.udp, CalcPct(istats.udp, total)); + LogMessage(" ICMP: " FMTu64("10") " (%.3f%%)\n", + istats.icmp, CalcPct(istats.icmp, total)); + LogMessage(" ARP: " FMTu64("10") " (%.3f%%)\n", + istats.arp, CalcPct(istats.arp, total)); +#ifndef NO_NON_ETHER_DECODER + LogMessage(" EAPOL: " FMTu64("10") " (%.3f%%)\n", + istats.eapol, CalcPct(istats.eapol, total)); +#endif + LogMessage(" IPv6: " FMTu64("10") " (%.3f%%)\n", + istats.ipv6, CalcPct(istats.ipv6, total)); + LogMessage(" ETHLOOP: " FMTu64("10") " (%.3f%%)\n", + istats.ethloopback, CalcPct(istats.ethloopback, total)); + LogMessage(" IPX: " FMTu64("10") " (%.3f%%)\n", + istats.ipx, CalcPct(istats.ipx, total)); + +#ifdef GRE + LogMessage(" IP4/IP4: " FMTu64("-10") " (%.3f%%)\n", + istats.ip4ip4, CalcPct(istats.ip4ip4, total)); + LogMessage(" IP4/IP6: " FMTu64("-10") " (%.3f%%)\n", + istats.ip4ip6, CalcPct(istats.ip4ip6, total)); + LogMessage(" IP6/IP4: " FMTu64("-10") " (%.3f%%)\n", + istats.ip6ip4, CalcPct(istats.ip6ip4, total)); + LogMessage(" IP6/IP6: " FMTu64("-10") " (%.3f%%)\n", + istats.ip6ip6, CalcPct(istats.ip6ip6, total)); + LogMessage(" GRE: " FMTu64("10") " (%.3f%%)\n", + istats.gre, CalcPct(istats.gre, total)); + LogMessage(" GRE ETH: " FMTu64("-10") " (%.3f%%)\n", + istats.gre_eth, CalcPct(istats.gre_eth, total)); + LogMessage("GRE VLAN: " FMTu64("-10") " (%.3f%%)\n", + istats.gre_vlan, CalcPct(istats.gre_vlan, total)); + LogMessage(" GRE IP: " FMTu64("-10") " (%.3f%%)\n", + istats.gre_ip, CalcPct(istats.gre_ip, total)); + LogMessage("GRE IPv6: " FMTu64("-10") " (%.3f%%)\n", + istats.gre_ipv6, CalcPct(istats.gre_ipv6, total)); + LogMessage("GRE PPTP: " FMTu64("-10") " (%.3f%%)\n", + istats.gre_ppp, CalcPct(istats.gre_ppp, total)); + LogMessage(" GRE ARP: " FMTu64("-10") " (%.3f%%)\n", + istats.gre_arp, CalcPct(istats.gre_arp, total)); + LogMessage(" GRE IPX: " FMTu64("-10") " (%.3f%%)\n", + istats.gre_ipx, CalcPct(istats.gre_ipx, total)); + LogMessage("GRE LOOP: " FMTu64("-10") " (%.3f%%)\n", + istats.gre_loopback, CalcPct(istats.gre_loopback, total)); +#endif + + LogMessage(" FRAG: " FMTu64("10") " (%.3f%%)\n", + istats.frags, CalcPct(istats.frags, total)); + LogMessage(" OTHER: " FMTu64("10") " (%.3f%%)\n", + istats.other, CalcPct(istats.other, total)); + LogMessage(" DISCARD: " FMTu64("10") " (%.3f%%)\n", + istats.discards, CalcPct(istats.discards, total)); + LogMessage(" Total: " FMTu64("10") "\n", total); + + LogMessage("\n"); + + + /* handle case where wireless is enabled... */ + +#ifndef NO_NON_ETHER_DECODER +#ifdef DLT_IEEE802_11 + if (datalink == DLT_IEEE802_11) + { + LogMessage("\n"); + LogMessage("Wireless Stats:\n\n"); + LogMessage("Management Packets: " FMTu64("10") " (%.3f%%)\n", + istats.wifi_mgmt, CalcPct(istats.wifi_mgmt, total)); + LogMessage(" Control Packets: " FMTu64("10") " (%.3f%%)\n", + istats.wifi_control, CalcPct(istats.wifi_control, total)); + LogMessage(" Data Packets: " FMTu64("10") " (%.3f%%)\n", + istats.wifi_data, CalcPct(istats.wifi_data, total)); + LogMessage("\n"); + } + +#endif /* if wireless is enabled... */ +#endif // NO_NON_ETHER_DECODER + + /* handle case where we have snort seeing fragmented packets */ + + if (pc.frags > 0) /* begin if (pc.frags > 0) */ + { + LogMessage("\n"); + LogMessage("Fragmentation Stats:\n\n"); + LogMessage("Fragmented IP Packets: " FMTu64("10") "\n", istats.frags); + LogMessage(" Fragment Trackers: " FMTu64("10") "\n", istats.frag_trackers); + LogMessage(" Rebuilt IP Packets: " FMTu64("10") "\n", istats.frag_rebuilt); + LogMessage(" Frag Elements Used: " FMTu64("10") "\n", istats.frag_element); + LogMessage("Discarded(incomplete): " FMTu64("10") "\n", istats.frag_incomp); + LogMessage(" Discarded(timeout): " FMTu64("10") "\n", istats.frag_timeout); + LogMessage(" Frag2 memory faults: " FMTu64("10") "\n", istats.frag_mem_faults); + LogMessage("\n"); + } /* end if (pc.frags > 0) */ + + /* handle TCP stream re-assy stuff here */ + + if (pc.tcp_stream_pkts > 0) + { + LogMessage("\n"); + LogMessage("TCP Stream Reassembly Stats:\n\n"); + LogMessage(" TCP Packets Used: " FMTu64("10") "\n", istats.tcp_str_packets); + LogMessage(" Stream Trackers: " FMTu64("10") "\n", istats.tcp_str_trackers); + LogMessage(" Stream Flushes: " FMTu64("10") "\n", istats.tcp_str_flushes); + LogMessage(" Stream Segments Used: " FMTu64("10") "\n", istats.tcp_str_segs_used); + LogMessage("Stream Segments Queued: " FMTu64("10") "\n", istats.tcp_str_segs_queued); + LogMessage(" Stream4 Memory Faults: " FMTu64("10") "\n", istats.tcp_str_mem_faults); + LogMessage("\n"); + } + + //mpse_print_qinfo(); + + } /* end if pcap_stats(ps, &ps) */ + + alarm(timestats_interval); /* reset the alarm to go off again */ +} + +/* print out stats on how long snort ran */ +void TimeStats(void) +{ + +/* + * variable definitions for improved statistics handling + * + * end_time = time which snort finished running (unix epoch) + * total_secs = total amount of time snort ran + * int_total_secs = used to eliminate casts from this function (temp. var) + * days = number of days snort ran + * hrs = number of hrs snort ran + * mins = number of minutes snort ran + * secs = number of seconds snort ran + * + * ival = temp. variable for integer/modulus math + * ppd = packets per day processed + * pph = packets per hour processed + * ppm = packets per minute processed + * pps = packets per second processed + * + * hflag = used to flag when hrs = zero, but days > 0 + * mflag = used to flag when min = zero, but hrs > 0 + * + */ + + time_t end_time, total_secs; + uint32_t days = 0, hrs = 0, mins = 0, secs = 0, tmp = 0; + uint64_t pps = 0, ppm = 0, pph = 0, ppd = 0; + uint32_t int_total_secs = 0; + char hflag = 0, mflag = 0; + + + end_time = time(NULL); /* grab epoch for end time value (in seconds) */ + total_secs = end_time - start_time; /* total_secs is how many seconds snort ran for */ + + tmp = (uint32_t)total_secs; + int_total_secs = tmp; /* used for cast elimination */ + + days = tmp / SECONDS_PER_DAY; /* 86400 is number of seconds in a day */ + tmp = tmp % SECONDS_PER_DAY; /* grab remainder to process hours */ + hrs = tmp / SECONDS_PER_HOUR; /* 3600 is number of seconds in a(n) hour */ + tmp = tmp % SECONDS_PER_HOUR; /* grab remainder to process minutes */ + mins = tmp / SECONDS_PER_MIN; /* 60 is number of seconds in a minute */ + secs = tmp % SECONDS_PER_MIN; /* grab remainder to process seconds */ + + if (total_secs) + pps = (pc.total_from_pcap / int_total_secs); + else + pps = pc.total_from_pcap; /* guard against division by zero */ + + /* Use ErrorMessage because this is logged whether + * or not logging quietly */ + ErrorMessage("Snort ran for %u Days %u Hours %u Minutes %u Seconds\n", + days, hrs, mins, secs); + + if (days > 0) + { + ppd = (pc.total_from_pcap / (int_total_secs / SECONDS_PER_DAY)); + ErrorMessage("Snort Analyzed " STDu64 " Packets Per Day\n", ppd); + hflag = 1; + } + + if (hrs > 0 || hflag == 1) + { + pph = (pc.total_from_pcap / (int_total_secs / SECONDS_PER_HOUR)); + ErrorMessage("Snort Analyzed " STDu64 " Packets Per Hour\n", pph); + mflag = 1; + } + + if (mins > 0 || mflag == 1) + { + ppm = (pc.total_from_pcap / (int_total_secs / SECONDS_PER_MIN)); + ErrorMessage("Snort Analyzed " STDu64 " Packets Per Minute\n", ppm); + } + + ErrorMessage("Snort Analyzed " STDu64 " Packets Per Second\n", pps); + ErrorMessage("\n"); +} +#endif /* TIMESTATS */ + + +#ifdef PCAP_CLOSE +int UpdatePcapPktStats(int cacheReturn) +#else +int UpdatePcapPktStats(void) +#endif +{ + struct pcap_stat ps; + uint32_t recv, drop; + static char not_initialized = 1; + +#ifdef PCAP_CLOSE + static int priorReturn = 0; + static int returnWasCached = 0; + + if ( !cacheReturn && returnWasCached ) + { + returnWasCached = 0; + return priorReturn; + } + priorReturn = -1; + returnWasCached = cacheReturn; +#endif + + if (not_initialized) + { + memset(&pkt_stats, 0, sizeof(PcapPktStats)); + not_initialized = 0; + } + + if ((pcap_handle == NULL) || ScReadMode()) + return -1; + + if (pcap_stats(pcap_handle, &ps) == -1) + { + pcap_perror(pcap_handle, "pcap_stats"); + return -1; + } + + recv = (uint32_t)ps.ps_recv; + drop = (uint32_t)ps.ps_drop; + +#ifdef LINUX_LIBPCAP_DOUBLES_STATS + recv /= 2; + drop /= 2; +#endif + +#ifdef LIBPCAP_ACCUMULATES + /* pcap recv wrapped */ + if (recv < pkt_stats.wrap_recv) + pkt_stats.recv += (uint64_t)UINT32_MAX; + + /* pcap drop wrapped */ + if (drop < pkt_stats.wrap_drop) + pkt_stats.drop += (uint64_t)UINT32_MAX; + + pkt_stats.wrap_recv = recv; + pkt_stats.wrap_drop = drop; +#else + pkt_stats.recv += (uint64_t)recv; + pkt_stats.drop += (uint64_t)drop; +#endif /* LIBPCAP_ACCUMULATES */ + +#ifdef PCAP_CLOSE + priorReturn = 0; +#endif + return 0; +} + +uint64_t GetPcapPktStatsRecv(void) +{ + return pkt_stats.recv + (uint64_t)pkt_stats.wrap_recv; +} + +uint64_t GetPcapPktStatsDrop(void) +{ + return pkt_stats.drop + (uint64_t)pkt_stats.wrap_drop; +} + + +#ifdef PCAP_CLOSE +/* exiting should be 0 for if not exiting, 1 if restarting, and 2 if exiting */ +#else +/* exiting should be 0 for if not exiting and 1 if exiting */ +#endif +void DropStats(int exiting) +{ + PreprocStatsFuncNode *idx; + uint64_t total = 0; + uint64_t pkts_recv; + uint64_t pkts_drop; + + total = pc.total_processed; + +#ifdef PPM_MGR + PPM_PRINT_SUMMARY(&snort_conf->ppm_cfg); +#endif + + LogMessage("================================================" + "===============================\n"); + +#ifdef TIMESTATS + TimeStats(); /* how long did snort run? */ +#endif + + if (ScReadMode() +#ifdef GIDS + || ScAdapterInlineMode() +#endif + ) + { + LogMessage("Snort processed " STDu64 " packets.\n", total); + } + else + { +#ifdef PCAP_CLOSE + if (exiting < 2 && (pcap_handle == NULL)) +#else + if (pcap_handle == NULL) +#endif + { + LogMessage("Snort received 0 packets\n"); + } + else + { +#ifdef PCAP_CLOSE + if (UpdatePcapPktStats(0) != -1) +#else + if (UpdatePcapPktStats() != -1) +#endif + { + pkts_recv = GetPcapPktStatsRecv(); + pkts_drop = GetPcapPktStatsDrop(); + + LogMessage("Packet Wire Totals:\n"); + LogMessage(" Received: " FMTu64("12") "\n", pkts_recv); + LogMessage(" Analyzed: " FMTu64("12") " (%.3f%%)\n", pc.total_from_pcap, + CalcPct(pc.total_from_pcap, pkts_recv)); + LogMessage(" Dropped: " FMTu64("12") " (%.3f%%)\n", pkts_drop, + CalcPct(pkts_drop, pkts_recv)); + LogMessage("Outstanding: " FMTu64("12") " (%.3f%%)\n", + pkts_recv - pkts_drop - pc.total_from_pcap, + CalcPct((pkts_recv - pkts_drop - pc.total_from_pcap), pkts_recv)); + } + else + { + LogMessage("Unable to calculate percentages for stats\n"); + LogMessage("Total number of packets Analyzed: " FMTu64("12") "\n", pc.total_from_pcap); + } + } + } + + LogMessage("================================================" + "===============================\n"); + + LogMessage("Breakdown by protocol (includes rebuilt packets):\n"); + + LogMessage(" ETH: " FMTu64("-10") " (%.3f%%)\n", + pc.eth, CalcPct(pc.eth, total)); + LogMessage(" ETHdisc: " FMTu64("-10") " (%.3f%%)\n", + pc.ethdisc, CalcPct(pc.ethdisc, total)); +#ifdef GIDS +#ifndef IPFW + LogMessage(" IPTables: " FMTu64("-10") " (%.3f%%)\n", + pc.iptables, CalcPct(pc.iptables, total)); +#else + LogMessage(" IPFW: " FMTu64("-10") " (%.3f%%)\n", + pc.ipfw, CalcPct(pc.ipfw, total)); +#endif /* IPFW */ +#endif /* GIDS */ + LogMessage(" VLAN: " FMTu64("-10") " (%.3f%%)\n", + pc.vlan, CalcPct(pc.vlan, total)); + + if (pc.nested_vlan != 0) + LogMessage("Nested VLAN: " FMTu64("-10") " (%.3f%%)\n", + pc.nested_vlan, CalcPct(pc.nested_vlan, total)); + + LogMessage(" IPV6: " FMTu64("-10") " (%.3f%%)\n", + pc.ipv6, CalcPct(pc.ipv6, total)); + LogMessage(" IP6 EXT: " FMTu64("-10") " (%.3f%%)\n", + pc.ip6ext, CalcPct(pc.ip6ext, total)); + LogMessage(" IP6opts: " FMTu64("-10") " (%.3f%%)\n", + pc.ipv6opts, CalcPct(pc.ipv6opts, total)); + LogMessage(" IP6disc: " FMTu64("-10") " (%.3f%%)\n", + pc.ipv6disc, CalcPct(pc.ipv6disc, total)); + + LogMessage(" IP4: " FMTu64("-10") " (%.3f%%)\n", + pc.ip, CalcPct(pc.ip, total)); + LogMessage(" IP4disc: " FMTu64("-10") " (%.3f%%)\n", + pc.ipdisc, CalcPct(pc.ipdisc, total)); + + LogMessage(" TCP 6: " FMTu64("-10") " (%.3f%%)\n", + pc.tcp6, CalcPct(pc.tcp6, total)); + LogMessage(" UDP 6: " FMTu64("-10") " (%.3f%%)\n", + pc.udp6, CalcPct(pc.udp6, total)); + LogMessage(" ICMP6: " FMTu64("-10") " (%.3f%%)\n", + pc.icmp6, CalcPct(pc.icmp6, total)); + LogMessage(" ICMP-IP: " FMTu64("-10") " (%.3f%%)\n", + pc.embdip, CalcPct(pc.embdip, total)); + + LogMessage(" TCP: " FMTu64("-10") " (%.3f%%)\n", + pc.tcp, CalcPct(pc.tcp, total)); + LogMessage(" UDP: " FMTu64("-10") " (%.3f%%)\n", + pc.udp, CalcPct(pc.udp, total)); + LogMessage(" ICMP: " FMTu64("-10") " (%.3f%%)\n", + pc.icmp, CalcPct(pc.icmp, total)); + + LogMessage(" TCPdisc: " FMTu64("-10") " (%.3f%%)\n", + pc.tdisc, CalcPct(pc.tdisc, total)); + LogMessage(" UDPdisc: " FMTu64("-10") " (%.3f%%)\n", + pc.udisc, CalcPct(pc.udisc, total)); + LogMessage(" ICMPdis: " FMTu64("-10") " (%.3f%%)\n", + pc.icmpdisc, CalcPct(pc.icmpdisc, total)); + + LogMessage(" FRAG: " FMTu64("-10") " (%.3f%%)\n", + pc.frags, CalcPct(pc.frags, total)); + LogMessage(" FRAG 6: " FMTu64("-10") " (%.3f%%)\n", + pc.frag6, CalcPct(pc.frag6, total)); + + LogMessage(" ARP: " FMTu64("-10") " (%.3f%%)\n", + pc.arp, CalcPct(pc.arp, total)); +#ifndef NO_NON_ETHER_DECODER + LogMessage(" EAPOL: " FMTu64("-10") " (%.3f%%)\n", + pc.eapol, CalcPct(pc.eapol, total)); +#endif + LogMessage(" ETHLOOP: " FMTu64("-10") " (%.3f%%)\n", + pc.ethloopback, CalcPct(pc.ethloopback, total)); + LogMessage(" IPX: " FMTu64("-10") " (%.3f%%)\n", + pc.ipx, CalcPct(pc.ipx, total)); +#ifdef GRE + LogMessage("IPv4/IPv4: " FMTu64("-10") " (%.3f%%)\n", + pc.ip4ip4, CalcPct(pc.ip4ip4, total)); + LogMessage("IPv4/IPv6: " FMTu64("-10") " (%.3f%%)\n", + pc.ip4ip6, CalcPct(pc.ip4ip6, total)); + LogMessage("IPv6/IPv4: " FMTu64("-10") " (%.3f%%)\n", + pc.ip6ip4, CalcPct(pc.ip6ip4, total)); + LogMessage("IPv6/IPv6: " FMTu64("-10") " (%.3f%%)\n", + pc.ip6ip6, CalcPct(pc.ip6ip6, total)); + LogMessage(" GRE: " FMTu64("-10") " (%.3f%%)\n", + pc.gre, CalcPct(pc.gre, total)); + LogMessage(" GRE ETH: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_eth, CalcPct(pc.gre_eth, total)); + LogMessage(" GRE VLAN: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_vlan, CalcPct(pc.gre_vlan, total)); + LogMessage(" GRE IPv4: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_ip, CalcPct(pc.gre_ip, total)); + LogMessage(" GRE IPv6: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_ipv6, CalcPct(pc.gre_ipv6, total)); + LogMessage("GRE IP6 E: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_ipv6ext, CalcPct(pc.gre_ipv6ext, total)); + LogMessage(" GRE PPTP: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_ppp, CalcPct(pc.gre_ppp, total)); + LogMessage(" GRE ARP: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_arp, CalcPct(pc.gre_arp, total)); + LogMessage(" GRE IPX: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_ipx, CalcPct(pc.gre_ipx, total)); + LogMessage(" GRE LOOP: " FMTu64("-10") " (%.3f%%)\n", + pc.gre_loopback, CalcPct(pc.gre_loopback, total)); +#endif /* GRE */ +#ifdef MPLS + LogMessage(" MPLS: " FMTu64("-10") " (%.3f%%)\n", + pc.mpls, CalcPct(pc.mpls, total)); +#endif + LogMessage(" OTHER: " FMTu64("-10") " (%.3f%%)\n", + pc.other, CalcPct(pc.other, total)); + LogMessage(" DISCARD: " FMTu64("-10") " (%.3f%%)\n", + pc.discards, CalcPct(pc.discards, total)); + LogMessage("InvChkSum: " FMTu64("-10") " (%.3f%%)\n", + pc.invalid_checksums, CalcPct(pc.invalid_checksums, total)); + + LogMessage(" S5 G 1: " FMTu64("-10") " (%.3f%%)\n", + pc.s5tcp1, CalcPct(pc.s5tcp1, total)); + LogMessage(" S5 G 2: " FMTu64("-10") " (%.3f%%)\n", + pc.s5tcp2, CalcPct(pc.s5tcp2, total)); + + LogMessage(" Total: " FMTu64("-10") "\n", total); + + LogMessage("================================================" + "===============================\n"); + + LogMessage("Action Stats:\n"); + LogMessage("ALERTS: " STDu64 "\n", pc.alert_pkts); + LogMessage("LOGGED: " STDu64 "\n", pc.log_pkts); + LogMessage("PASSED: " STDu64 "\n", pc.pass_pkts); + +#ifdef TARGET_BASED + if (ScIdsMode() && IsAdaptiveConfigured(getDefaultPolicy(), 0)) + { + LogMessage("================================================" + "===============================\n"); + LogMessage("Attribute Table Stats:\n"); + LogMessage(" Number Entries: %u\n", SFAT_NumberOfHosts()); + LogMessage(" Table Reloaded: " STDu64 "\n", pc.attribute_table_reloads); + } +#endif /* TARGET_BASED */ + + //mpse_print_qinfo(); + +#ifndef NO_NON_ETHER_DECODER +#ifdef DLT_IEEE802_11 + if(datalink == DLT_IEEE802_11) + { + LogMessage("================================================" + "===============================\n"); + LogMessage("Wireless Stats:\n"); + LogMessage("Breakdown by type:\n"); + LogMessage(" Management Packets: " FMTu64("-10") " (%.3f%%)\n", + pc.wifi_mgmt, CalcPct(pc.wifi_mgmt, total)); + LogMessage(" Control Packets: " FMTu64("-10") " (%.3f%%)\n", + pc.wifi_control, CalcPct(pc.wifi_control, total)); + LogMessage(" Data Packets: " FMTu64("-10") " (%.3f%%)\n", + pc.wifi_data, CalcPct(pc.wifi_data, total)); + } +#endif /* DLT_IEEE802_11 */ +#endif // NO_NON_ETHER_DECODER + + for (idx = preproc_stats_funcs; idx != NULL; idx = idx->next) + { + LogMessage("==============================================" + "=================================\n"); + +#ifdef PCAP_CLOSE + idx->func(exiting ? 1 : 0); +#else + idx->func(exiting); +#endif + } + + LogMessage("==============================================" + "=================================\n"); + + return; +} + +/**************************************************************************** + * + * Function: CleanupProtoNames() + * + * Purpose: Frees the protocol names + * + * Arguments: None. + * + * Returns: void function + * + ****************************************************************************/ +void CleanupProtoNames(void) +{ + int i; + + for(i = 0; i < 256; i++) + { + if( protocol_names[i] != NULL ) + { + free( protocol_names[i] ); + protocol_names[i] = NULL; + } + } +} + +/**************************************************************************** + * + * Function: read_infile(char *) + * + * Purpose: Reads the BPF filters in from a file. Ripped from tcpdump. + * + * Arguments: fname => the name of the file containing the BPF filters + * + * Returns: the processed BPF string + * + ****************************************************************************/ +char *read_infile(char *fname) +{ + register int fd, cc; + register char *cp, *cmt; + struct stat buf; + + fd = open(fname, O_RDONLY); + + if(fd < 0) + FatalError("can't open %s: %s\n", fname, pcap_strerror(errno)); + + if(fstat(fd, &buf) < 0) + FatalError("can't stat %s: %s\n", fname, pcap_strerror(errno)); + + cp = (char *)SnortAlloc(((u_int)buf.st_size + 1) * sizeof(char)); + + cc = read(fd, cp, (int) buf.st_size); + + if(cc < 0) + FatalError("read %s: %s\n", fname, pcap_strerror(errno)); + + if(cc != buf.st_size) + FatalError("short read %s (%d != %d)\n", fname, cc, (int) buf.st_size); + + cp[(int) buf.st_size] = '\0'; + + close(fd); + + /* Treat everything upto the end of the line as a space + * so that we can put comments in our BPF filters + */ + + while((cmt = strchr(cp, '#')) != NULL) + { + while (*cmt != '\r' && *cmt != '\n' && *cmt != '\0') + { + *cmt++ = ' '; + } + } + + /** LogMessage("BPF filter file: %s\n", fname); **/ + + return(cp); +} + + + /**************************************************************************** + * + * Function: CheckLogDir() + * + * Purpose: CyberPsychotic sez: basically we only check if logdir exist and + * writable, since it might screw the whole thing in the middle. Any + * other checks could be performed here as well. + * + * Arguments: None. + * + * Returns: void function + * + ****************************************************************************/ +void CheckLogDir(void) +{ + struct stat st; + + if (snort_conf->log_dir == NULL) + return; + + if (stat(snort_conf->log_dir, &st) == -1) + FatalError("Stat check on log dir failed: %s.\n", strerror(errno)); + + if (!S_ISDIR(st.st_mode) || (access(snort_conf->log_dir, W_OK) == -1)) + { + FatalError("Can not get write access to logging directory \"%s\". " + "(directory doesn't exist or permissions are set incorrectly " + "or it is not a directory at all)\n", + snort_conf->log_dir); + } +} + +/* Signal handler for child process signaling the parent + * that is is ready */ +static int parent_wait = 1; +static void SigChildReadyHandler(int signal) +{ +#ifdef DEBUG + LogMessage("Received Signal from Child\n"); +#endif + parent_wait = 0; +} + +/**************************************************************************** + * + * Function: GoDaemon() + * + * Purpose: Puts the program into daemon mode, nice and quiet like.... + * + * Arguments: None. + * + * Returns: void function + * + ****************************************************************************/ +void GoDaemon(void) +{ +#ifndef WIN32 + int exit_val = 0; + pid_t fs; + + LogMessage("Initializing daemon mode\n"); + + if (ScDaemonRestart()) + return; + + /* Don't daemonize if we've already daemonized and + * received a SIGHUP. */ + if(getppid() != 1) + { + /* Register signal handler that parent can trap signal */ + signal(SIGNAL_SNORT_CHILD_READY, SigChildReadyHandler); + if (errno != 0) errno=0; + + /* now fork the child */ + fs = fork(); + + if(fs > 0) + { + /* Parent */ + + /* Don't exit quite yet. Wait for the child + * to signal that is there and created the PID + * file. + */ + while (parent_wait) + { + /* Continue waiting until receiving signal from child */ + int status; + if (waitpid(fs, &status, WNOHANG) == fs) + { + /* If the child is gone, parent should go away, too */ + if (WIFEXITED(status)) + { + LogMessage("Child exited unexpectedly\n"); + exit_val = -1; + break; + } + + if (WIFSIGNALED(status)) + { + LogMessage("Child terminated unexpectedly\n"); + exit_val = -2; + break; + } + } +#ifdef DEBUG + LogMessage("Parent waiting for child...\n"); +#endif + + sleep(1); + } + + LogMessage("Daemon parent exiting\n"); + + exit(exit_val); /* parent */ + } + + if(fs < 0) + { + /* Daemonizing failed... */ + perror("fork"); + exit(1); + } + + /* Child */ + setsid(); + } + + close(0); + close(1); + close(2); + +#ifdef DEBUG + /* redirect stdin/stdout/stderr to a file */ + open("/tmp/snort.debug", O_CREAT | O_RDWR); /* stdin, fd 0 */ + + /* Change ownership to that which we will drop privileges to */ + if ((snort_conf->user_id != -1) || (snort_conf->group_id != -1)) + { + uid_t user_id = getuid(); + gid_t group_id = getgid(); + + if (snort_conf->user_id != -1) + user_id = snort_conf->user_id; + if (snort_conf->group_id != -1) + group_id = snort_conf->group_id; + + chown("/tmp/snort.debug", user_id, group_id); + } +#else + /* redirect stdin/stdout/stderr to /dev/null */ + (void)open("/dev/null", O_RDWR); /* stdin, fd 0 */ +#endif + + dup(0); /* stdout, fd 0 => fd 1 */ + dup(0); /* stderr, fd 0 => fd 2 */ + + SignalWaitingParent(); + +#endif /* ! WIN32 */ +} + +/* Signal the parent that child is ready */ +void SignalWaitingParent(void) +{ +#ifndef WIN32 + pid_t parentpid = getppid(); +#ifdef DEBUG + LogMessage("Signaling parent %d from child %d\n", parentpid, getpid()); +#endif + + if (kill(parentpid, SIGNAL_SNORT_CHILD_READY)) + { + LogMessage("Daemon initialized, failed to signal parent pid: %d, failure: %d, %s\n", parentpid, errno, strerror(errno)); + } + else + { + LogMessage("Daemon initialized, signaled parent pid: %d\n", parentpid); + } +#endif +} + +/* This function has been moved into mstring.c, since that +* is where the allocation actually occurs. It has been +* renamed to mSplitFree(). +* +void FreeToks(char **toks, int num_toks) +{ + if (toks) + { + if (num_toks > 0) + { + do + { + num_toks--; + free(toks[num_toks]); + } while(num_toks); + } + free(toks); + } +} +*/ + + +/* Self preserving memory allocator */ +void *SPAlloc(unsigned long size, struct _SPMemControl *spmc) +{ + void *tmp; + + spmc->mem_usage += size; + + if(spmc->mem_usage > spmc->memcap) + { + spmc->sp_func(spmc); + } + + tmp = (void *) calloc(size, sizeof(char)); + + if(tmp == NULL) + { + FatalError("Unable to allocate memory! (%lu requested, %lu in use)\n", + size, spmc->mem_usage); + } + + return tmp; +} + +/* Guaranteed to be '\0' terminated even if truncation occurs. + * + * returns SNORT_SNPRINTF_SUCCESS if successful + * returns SNORT_SNPRINTF_TRUNCATION on truncation + * returns SNORT_SNPRINTF_ERROR on error + */ +int SnortSnprintf(char *buf, size_t buf_size, const char *format, ...) +{ + va_list ap; + int ret; + + if (buf == NULL || buf_size <= 0 || format == NULL) + return SNORT_SNPRINTF_ERROR; + + /* zero first byte in case an error occurs with + * vsnprintf, so buffer is null terminated with + * zero length */ + buf[0] = '\0'; + buf[buf_size - 1] = '\0'; + + va_start(ap, format); + + ret = vsnprintf(buf, buf_size, format, ap); + + va_end(ap); + + if (ret < 0) + return SNORT_SNPRINTF_ERROR; + + if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size) + { + /* result was truncated */ + buf[buf_size - 1] = '\0'; + return SNORT_SNPRINTF_TRUNCATION; + } + + return SNORT_SNPRINTF_SUCCESS; +} + +/* Appends to a given string + * Guaranteed to be '\0' terminated even if truncation occurs. + * + * returns SNORT_SNPRINTF_SUCCESS if successful + * returns SNORT_SNPRINTF_TRUNCATION on truncation + * returns SNORT_SNPRINTF_ERROR on error + */ +int SnortSnprintfAppend(char *buf, size_t buf_size, const char *format, ...) +{ + int str_len; + int ret; + va_list ap; + + if (buf == NULL || buf_size <= 0 || format == NULL) + return SNORT_SNPRINTF_ERROR; + + str_len = SnortStrnlen(buf, buf_size); + + /* since we've already checked buf and buf_size an error + * indicates no null termination, so just start at + * beginning of buffer */ + if (str_len == SNORT_STRNLEN_ERROR) + { + buf[0] = '\0'; + str_len = 0; + } + + buf[buf_size - 1] = '\0'; + + va_start(ap, format); + + ret = vsnprintf(buf + str_len, buf_size - (size_t)str_len, format, ap); + + va_end(ap); + + if (ret < 0) + return SNORT_SNPRINTF_ERROR; + + if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size) + { + /* truncation occured */ + buf[buf_size - 1] = '\0'; + return SNORT_SNPRINTF_TRUNCATION; + } + + return SNORT_SNPRINTF_SUCCESS; +} + +/* Guaranteed to be '\0' terminated even if truncation occurs. + * + * Arguments: dst - the string to contain the copy + * src - the string to copy from + * dst_size - the size of the destination buffer + * including the null byte. + * + * returns SNORT_STRNCPY_SUCCESS if successful + * returns SNORT_STRNCPY_TRUNCATION on truncation + * returns SNORT_STRNCPY_ERROR on error + * + * Note: Do not set dst[0] = '\0' on error since it's possible that + * dst and src are the same pointer - it will at least be null + * terminated in any case + */ +int SnortStrncpy(char *dst, const char *src, size_t dst_size) +{ + char *ret = NULL; + + if (dst == NULL || src == NULL || dst_size <= 0) + return SNORT_STRNCPY_ERROR; + + dst[dst_size - 1] = '\0'; + + ret = strncpy(dst, src, dst_size); + + /* Not sure if this ever happens but might as + * well be on the safe side */ + if (ret == NULL) + return SNORT_STRNCPY_ERROR; + + if (dst[dst_size - 1] != '\0') + { + /* result was truncated */ + dst[dst_size - 1] = '\0'; + return SNORT_STRNCPY_TRUNCATION; + } + + return SNORT_STRNCPY_SUCCESS; +} + +char *SnortStrndup(const char *src, size_t dst_size) +{ + char *ret = SnortAlloc(dst_size + 1); + int ret_val; + + ret_val = SnortStrncpy(ret, src, dst_size + 1); + + if(ret_val == SNORT_STRNCPY_ERROR) + { + free(ret); + return NULL; + } + + return ret; +} + +/* Determines whether a buffer is '\0' terminated and returns the + * string length if so + * + * returns the string length if '\0' terminated + * returns SNORT_STRNLEN_ERROR if not '\0' terminated + */ +int SnortStrnlen(const char *buf, int buf_size) +{ + int i = 0; + + if (buf == NULL || buf_size <= 0) + return SNORT_STRNLEN_ERROR; + + for (i = 0; i < buf_size; i++) + { + if (buf[i] == '\0') + break; + } + + if (i == buf_size) + return SNORT_STRNLEN_ERROR; + + return i; +} + +char * SnortStrdup(const char *str) +{ + char *copy = NULL; + + if (!str) + { + FatalError("Unable to duplicate string: NULL!\n"); + } + + copy = strdup(str); + + if (copy == NULL) + { + FatalError("Unable to duplicate string: %s!\n", str); + } + + return copy; +} + +/* + * Find first occurrence of char of accept in s, limited by slen. + * A 'safe' version of strpbrk that won't read past end of buffer s + * in cases that s is not NULL terminated. + * + * This code assumes 'accept' is a static string. + */ +const char *SnortStrnPbrk(const char *s, int slen, const char *accept) +{ + char ch; + const char *s_end; + if (!s || !*s || !accept || slen == 0) + return NULL; + + s_end = s + slen; + while (s < s_end) + { + ch = *s; + if (strchr(accept, ch)) + return s; + s++; + } + return NULL; +} + +/* + * Find first occurrence of searchstr in s, limited by slen. + * A 'safe' version of strstr that won't read past end of buffer s + * in cases that s is not NULL terminated. + */ +const char *SnortStrnStr(const char *s, int slen, const char *searchstr) +{ + char ch, nc; + int len; + if (!s || !*s || !searchstr || slen == 0) + return NULL; + + if ((ch = *searchstr++) != 0) + { + len = strlen(searchstr); + do + { + do + { + if ((nc = *s++) == 0) + { + return NULL; + } + slen--; + if (slen == 0) + return NULL; + } while (nc != ch); + if (slen - len < 0) + return NULL; + } while (memcmp(s, searchstr, len) != 0); + s--; + slen++; + } + return s; +} + +/* + * Find first occurrence of substring in s, ignore case. +*/ +const char *SnortStrcasestr(const char *s, const char *substr) +{ + char ch, nc; + int len; + + if (!s || !*s || !substr) + return NULL; + + if ((ch = *substr++) != 0) + { + ch = tolower((char)ch); + len = strlen(substr); + do + { + do + { + if ((nc = *s++) == 0) + { + return NULL; + } + } while ((char)tolower((uint8_t)nc) != ch); + } while (strncasecmp(s, substr, len) != 0); + s--; + } + return s; +} + +void *SnortAlloc(unsigned long size) +{ + void *tmp; + + tmp = (void *) calloc(size, sizeof(char)); + + if(tmp == NULL) + { + FatalError("Unable to allocate memory! (%lu requested)\n", size); + } + + return tmp; +} + +void * SnortAlloc2(size_t size, const char *format, ...) +{ + void *tmp; + + tmp = (void *)calloc(size, sizeof(char)); + + if(tmp == NULL) + { + va_list ap; + char buf[STD_BUF]; + + buf[STD_BUF - 1] = '\0'; + + va_start(ap, format); + + vsnprintf(buf, STD_BUF - 1, format, ap); + + va_end(ap); + + FatalError("%s", buf); + } + + return tmp; +} + +/** + * Chroot and adjust the snort_conf->log_dir reference + * + * @param directory directory to chroot to + * @param logstore ptr to snort_conf->log_dir which must be dynamically allocated + */ +void SetChroot(char *directory, char **logstore) +{ +#ifdef WIN32 + FatalError("SetChroot() should not be called under Win32!\n"); +#else + char *absdir; + size_t abslen; + char *logdir; + + if(!directory || !logstore) + { + FatalError("Null parameter passed\n"); + } + + logdir = *logstore; + + if(logdir == NULL || *logdir == '\0') + { + FatalError("Null log directory\n"); + } + + DEBUG_WRAP(DebugMessage(DEBUG_INIT,"SetChroot: %s\n", + CurrentWorkingDir());); + + logdir = GetAbsolutePath(logdir); + + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "SetChroot: %s\n", + CurrentWorkingDir())); + + logdir = SnortStrdup(logdir); + + /* We're going to reset logstore, so free it now */ + free(*logstore); + *logstore = NULL; + + /* change to the directory */ + if(chdir(directory) != 0) + { + FatalError("SetChroot: Can not chdir to \"%s\": %s\n", directory, + strerror(errno)); + } + + /* always returns an absolute pathname */ + absdir = CurrentWorkingDir(); + + if(absdir == NULL) + { + FatalError("NULL Chroot found\n"); + } + + abslen = strlen(absdir); + + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "ABS: %s %d\n", absdir, abslen);); + + /* make the chroot call */ + if(chroot(absdir) < 0) + { + FatalError("Can not chroot to \"%s\": absolute: %s: %s\n", + directory, absdir, strerror(errno)); + } + + DEBUG_WRAP(DebugMessage(DEBUG_INIT,"chroot success (%s ->", absdir);); + DEBUG_WRAP(DebugMessage(DEBUG_INIT,"%s)\n ", CurrentWorkingDir());); + + /* change to "/" in the new directory */ + if(chdir("/") < 0) + { + FatalError("Can not chdir to \"/\" after chroot: %s\n", + strerror(errno)); + } + + DEBUG_WRAP(DebugMessage(DEBUG_INIT,"chdir success (%s)\n", + CurrentWorkingDir());); + + + if(strncmp(absdir, logdir, strlen(absdir))) + { + FatalError("Absdir is not a subset of the logdir"); + } + + if(abslen >= strlen(logdir)) + { + *logstore = SnortStrdup("/"); + } + else + { + *logstore = SnortStrdup(logdir + abslen); + } + + DEBUG_WRAP(DebugMessage(DEBUG_INIT,"new logdir from %s to %s\n", + logdir, *logstore)); + + LogMessage("Chroot directory = %s\n", directory); + +#if 0 + /* XXX XXX */ + /* install the I can't do this signal handler */ + signal(SIGHUP, SigCantHupHandler); +#endif +#endif /* !WIN32 */ +} + + +/** + * Return a ptr to the absolute pathname of snort. This memory must + * be copied to another region if you wish to save it for later use. + */ +char *CurrentWorkingDir(void) +{ + static char buf[PATH_MAX_UTIL + 1]; + + if(getcwd((char *) buf, PATH_MAX_UTIL) == NULL) + { + return NULL; + } + + buf[PATH_MAX_UTIL] = '\0'; + + return (char *) buf; +} + +/** + * Given a directory name, return a ptr to a static + */ +char *GetAbsolutePath(char *dir) +{ + char *savedir, *dirp; + static char buf[PATH_MAX_UTIL + 1]; + + if(dir == NULL) + { + return NULL; + } + + savedir = strdup(CurrentWorkingDir()); + + if(savedir == NULL) + { + return NULL; + } + + if(chdir(dir) < 0) + { + LogMessage("Can't change to directory: %s\n", dir); + free(savedir); + return NULL; + } + + dirp = CurrentWorkingDir(); + + if(dirp == NULL) + { + LogMessage("Unable to access current directory\n"); + free(savedir); + return NULL; + } + else + { + strncpy(buf, dirp, PATH_MAX_UTIL); + buf[PATH_MAX_UTIL] = '\0'; + } + + if(chdir(savedir) < 0) + { + LogMessage("Can't change back to directory: %s\n", dir); + free(savedir); + return NULL; + } + + free(savedir); + return (char *) buf; +} + + +#ifndef WIN32 +/* very slow sort - do not use at runtime! */ +SF_LIST * SortDirectory(const char *path) +{ + SF_LIST *dir_entries; + DIR *dir; + struct dirent *direntry; + int ret = 0; + + if (path == NULL) + return NULL; + + dir_entries = sflist_new(); + if (dir_entries == NULL) + { + ErrorMessage("Could not allocate new list for directory entries\n"); + return NULL; + } + + dir = opendir(path); + if (dir == NULL) + { + ErrorMessage("Error opening directory: %s: %s\n", + path, strerror(errno)); + sflist_free_all(dir_entries, free); + return NULL; + } + + /* Reset errno since we'll be checking it unconditionally */ + errno = 0; + + while ((direntry = readdir(dir)) != NULL) + { + char *node_entry_name, *dir_entry_name; + SF_LNODE *node; + + dir_entry_name = SnortStrdup(direntry->d_name); + + for (node = sflist_first_node(dir_entries); + node != NULL; + node = sflist_next_node(dir_entries)) + { + node_entry_name = (char *)node->ndata; + if (strcmp(dir_entry_name, node_entry_name) < 0) + break; + } + + if (node == NULL) + ret = sflist_add_tail(dir_entries, (NODE_DATA)dir_entry_name); + else + ret = sflist_add_before(dir_entries, node, (NODE_DATA)dir_entry_name); + + if (ret == -1) + { + ErrorMessage("Error adding directory entry to list\n"); + sflist_free_all(dir_entries, free); + closedir(dir); + return NULL; + } + } + + if (errno != 0) + { + ErrorMessage("Error reading directory: %s: %s\n", + path, strerror(errno)); + errno = 0; + sflist_free_all(dir_entries, free); + closedir(dir); + return NULL; + } + + closedir(dir); + + return dir_entries; +} + +int GetFilesUnderDir(const char *path, SF_QUEUE *dir_queue, const char *filter) +{ + SF_LIST *dir_entries; + char *direntry; + int ret = 0; + int num_files = 0; + + if ((path == NULL) || (dir_queue == NULL)) + return -1; + + dir_entries = SortDirectory(path); + if (dir_entries == NULL) + { + ErrorMessage("Error sorting entries in directory: %s\n", path); + return -1; + } + + for (direntry = (char *)sflist_first(dir_entries); + direntry != NULL; + direntry = (char *)sflist_next(dir_entries)) + { + char path_buf[PATH_MAX]; + struct stat file_stat; + + /* Don't look at dot files */ + if (strncmp(".", direntry, 1) == 0) + continue; + + ret = SnortSnprintf(path_buf, PATH_MAX, "%s%s%s", + path, path[strlen(path) - 1] == '/' ? "" : "/", direntry); + if (ret == SNORT_SNPRINTF_TRUNCATION) + { + ErrorMessage("Error copying file to buffer: Path too long\n"); + sflist_free_all(dir_entries, free); + return -1; + } + else if (ret != SNORT_SNPRINTF_SUCCESS) + { + ErrorMessage("Error copying file to buffer\n"); + sflist_free_all(dir_entries, free); + return -1; + } + + ret = stat(path_buf, &file_stat); + if (ret == -1) + { + ErrorMessage("Could not stat file: %s: %s\n", + path_buf, strerror(errno)); + sflist_free_all(dir_entries, free); + return -1; + } + + if (file_stat.st_mode & S_IFDIR) + { + ret = GetFilesUnderDir(path_buf, dir_queue, filter); + if (ret == -1) + { + sflist_free_all(dir_entries, free); + return -1; + } + + num_files += ret; + } + else if (file_stat.st_mode & S_IFREG) + { + if ((filter == NULL) || (fnmatch(filter, direntry, 0) == 0)) + { + char *file = SnortStrdup(path_buf); + + ret = sfqueue_add(dir_queue, (NODE_DATA)file); + if (ret == -1) + { + ErrorMessage("Could not append item to list: %s\n", file); + free(file); + sflist_free_all(dir_entries, free); + return -1; + } + + num_files++; + } + } + } + + sflist_free_all(dir_entries, free); + + return num_files; +} +#endif + +/**************************************************************************** + * + * Function: GetUniqueName(char * iface) + * + * Purpose: To return a string that has a high probability of being unique + * for a given sensor. + * + * Arguments: char * iface - The network interface you are sniffing + * + * Returns: A char * -- its a static char * so you should not free it + * + ***************************************************************************/ +char *GetUniqueName(char * iface) +{ + char * rptr; + static char uniq_name[256]; + + if (iface == NULL) LogMessage("Interface is NULL. Name may not be unique for the host\n"); +#ifndef WIN32 + rptr = GetIP(iface); + if(rptr == NULL || !strcmp(rptr, "unknown")) +#endif + { + SnortSnprintf(uniq_name, 255, "%s:%s\n",GetHostname(),iface); + rptr = uniq_name; + } + if (ScLogVerbose()) LogMessage("Node unique name is: %s\n", rptr); + return rptr; +} + +/**************************************************************************** + * + * Function: GetIP(char * iface) + * + * Purpose: To return a string representing the IP address for an interface + * + * Arguments: char * iface - The network interface you want to find an IP + * address for. + * + * Returns: A char * -- make sure you call free on this when you are done + * with it. + * + ***************************************************************************/ +char *GetIP(char * iface) +{ + struct ifreq ifr; + struct sockaddr_in *addr; + int s; +#ifdef SUP_IP6 + sfip_t ret; +#endif + + if(iface) + { + /* Set up a dummy socket just so we can use ioctl to find the + ip address of the interface */ + s = socket(PF_INET, SOCK_DGRAM, 0); + if(s == -1) + { + FatalError("Problem establishing socket to find IP address for interface: %s\n", iface); + } + + SnortStrncpy(ifr.ifr_name, iface, strlen(iface) + 1); + +#ifndef WIN32 + if(ioctl(s, SIOCGIFADDR, &ifr) < 0) return NULL; + else +#endif + { + addr = (struct sockaddr_in *) &ifr.ifr_broadaddr; + } + close(s); + +#ifdef SUP_IP6 +// XXX-IPv6 uses ioctl to populate a sockaddr_in structure ... but what if the interface only has an IPv6 address? + sfip_set_raw(&ret, addr, AF_INET); + return SnortStrdup(sfip_ntoa(&ret)); +#else + return SnortStrdup(inet_ntoa(addr->sin_addr)); +#endif + } + else + { + return "unknown"; + } +} + +/**************************************************************************** + * + * Function: GetHostname() + * + * Purpose: To return a string representing the hostname + * + * Arguments: None + * + * Returns: A static char * representing the hostname. + * + ***************************************************************************/ +char *GetHostname(void) +{ +#ifdef WIN32 + DWORD bufflen = 256; + static char buff[256]; + GetComputerName(buff, &bufflen); + return buff; +#else + char * error = "unknown"; + if(getenv("HOSTNAME")) return getenv("HOSTNAME"); + else if(getenv("HOST")) return getenv("HOST"); + else return error; +#endif +} + +/**************************************************************************** + * + * Function: GetTimestamp(register const struct timeval *tvp, int tz) + * + * Purpose: Get an ISO-8601 formatted timestamp for tvp within the tz + * timezone. + * + * Arguments: tvp is a timeval pointer. tz is a timezone. + * + * Returns: char * -- You must free this char * when you are done with it. + * + ***************************************************************************/ +char *GetTimestamp(register const struct timeval *tvp, int tz) +{ + struct tm *lt; /* localtime */ + char * buf; + int msec; + + buf = (char *)SnortAlloc(SMALLBUFFER * sizeof(char)); + + msec = tvp->tv_usec / 1000; + + if (ScOutputUseUtc()) + { + lt = gmtime((time_t *)&tvp->tv_sec); + SnortSnprintf(buf, SMALLBUFFER, "%04i-%02i-%02i %02i:%02i:%02i.%03i", + 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, + lt->tm_hour, lt->tm_min, lt->tm_sec, msec); + } + else + { + lt = localtime((time_t *)&tvp->tv_sec); + SnortSnprintf(buf, SMALLBUFFER, + "%04i-%02i-%02i %02i:%02i:%02i.%03i+%03i", + 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, + lt->tm_hour, lt->tm_min, lt->tm_sec, msec, tz); + } + + return buf; +} + +/**************************************************************************** + * + * Function: GetLocalTimezone() + * + * Purpose: Find the offset from GMT for current host + * + * Arguments: none + * + * Returns: int representing the offset from GMT + * + ***************************************************************************/ +int GetLocalTimezone(void) +{ + time_t ut; + struct tm * ltm; + long seconds_away_from_utc; + + time(&ut); + ltm = localtime(&ut); + +#if defined(WIN32) || defined(SOLARIS) || defined(AIX) || defined(HPUX) + /* localtime() sets the global timezone variable, + which is defined in */ + seconds_away_from_utc = timezone; +#else + seconds_away_from_utc = ltm->tm_gmtoff; +#endif + + return seconds_away_from_utc/3600; +} + +/**************************************************************************** + * + * Function: GetCurrentTimestamp() + * + * Purpose: Generate an ISO-8601 formatted timestamp for the current time. + * + * Arguments: none + * + * Returns: char * -- You must free this char * when you are done with it. + * + ***************************************************************************/ +char *GetCurrentTimestamp(void) +{ + struct tm *lt; + struct timezone tz; + struct timeval tv; + struct timeval *tvp; + char * buf; + int tzone; + int msec; + + buf = (char *)SnortAlloc(SMALLBUFFER * sizeof(char)); + + bzero((char *)&tz,sizeof(tz)); + gettimeofday(&tv,&tz); + tvp = &tv; + + msec = tvp->tv_usec/1000; + + if (ScOutputUseUtc()) + { + lt = gmtime((time_t *)&tvp->tv_sec); + SnortSnprintf(buf, SMALLBUFFER, "%04i-%02i-%02i %02i:%02i:%02i.%03i", + 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, + lt->tm_hour, lt->tm_min, lt->tm_sec, msec); + } + else + { + lt = localtime((time_t *)&tvp->tv_sec); + + tzone = GetLocalTimezone(); + + SnortSnprintf(buf, SMALLBUFFER, + "%04i-%02i-%02i %02i:%02i:%02i.%03i+%03i", + 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, + lt->tm_hour, lt->tm_min, lt->tm_sec, msec, tzone); + } + + return buf; +} + +/**************************************************************************** + * Function: base64(char * xdata, int length) + * + * Purpose: Insert data into the database + * + * Arguments: xdata => pointer to data to base64 encode + * length => how much data to encode + * + * Make sure you allocate memory for the output before you pass + * the output pointer into this function. You should allocate + * (1.5 * length) bytes to be safe. + * + * Returns: data base64 encoded as a char * + * + ***************************************************************************/ +char * base64(const u_char * xdata, int length) +{ + int count, cols, bits, c, char_count; + unsigned char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* 64 bytes */ + char * payloadptr; + char * output; + char_count = 0; + bits = 0; + cols = 0; + + output = (char *)SnortAlloc( ((unsigned int) (length * 1.5 + 4)) * sizeof(char) ); + + payloadptr = output; + + for(count = 0; count < length; count++) + { + c = xdata[count]; + + if(c > 255) + { + ErrorMessage("plugbase.c->base64(): encountered char > 255 (decimal %d)\n If you see this error message a char is more than one byte on your machine\n This means your base64 results can not be trusted", c); + } + + bits += c; + char_count++; + + if(char_count == 3) + { + *output = alpha[bits >> 18]; output++; + *output = alpha[(bits >> 12) & 0x3f]; output++; + *output = alpha[(bits >> 6) & 0x3f]; output++; + *output = alpha[bits & 0x3f]; output++; + cols += 4; + if(cols == 72) + { + *output = '\n'; output++; + cols = 0; + } + bits = 0; + char_count = 0; + } + else + { + bits <<= 8; + } + } + + if(char_count != 0) + { + bits <<= 16 - (8 * char_count); + *output = alpha[bits >> 18]; output++; + *output = alpha[(bits >> 12) & 0x3f]; output++; + if(char_count == 1) + { + *output = '='; output++; + *output = '='; output++; + } + else + { + *output = alpha[(bits >> 6) & 0x3f]; + output++; *output = '='; + output++; + } + } + *output = '\0'; + return payloadptr; +} + +/**************************************************************************** + * + * Function: ascii(u_char *xdata, int length) + * + * Purpose: This function takes takes a buffer "xdata" and its length then + * returns a string of only the printable ASCII characters. + * + * Arguments: xdata is the buffer, length is the length of the buffer in + * bytes + * + * Returns: char * -- You must free this char * when you are done with it. + * + ***************************************************************************/ +char *ascii(const u_char *xdata, int length) +{ + char *d_ptr, *ret_val; + int i,count = 0; + int size; + + if(xdata == NULL) + { + return NULL; + } + + for(i=0;i') /* > */ + count += 4; + } + + size = length + count + 1; + ret_val = (char *) calloc(1,size); + + if(ret_val == NULL) + { + LogMessage("plugbase.c: ascii(): Out of memory, can't log anything!\n"); + return NULL; + } + + d_ptr = ret_val; + + for(i=0;i 0x1F) && (xdata[i] < 0x7F)) + { + if(xdata[i] == '<') + { + SnortStrncpy(d_ptr, "<", size - (d_ptr - ret_val)); + d_ptr+=4; + } + else if(xdata[i] == '&') + { + SnortStrncpy(d_ptr, "&", size - (d_ptr - ret_val)); + d_ptr += 5; + } + else if(xdata[i] == '>') + { + SnortStrncpy(d_ptr, ">", size - (d_ptr - ret_val)); + d_ptr += 4; + } + else + { + *d_ptr++ = xdata[i]; + } + } + else + { + *d_ptr++ = '.'; + } + } + + *d_ptr++ = '\0'; + + return ret_val; +} + +/**************************************************************************** + * + * Function: hex(u_char *xdata, int length) + * + * Purpose: This function takes takes a buffer "xdata" and its length then + * returns a string of hex with no spaces + * + * Arguments: xdata is the buffer, length is the length of the buffer in + * bytes + * + * Returns: char * -- You must free this char * when you are done with it. + * + ***************************************************************************/ +char *hex(const u_char *xdata, int length) +{ + int x; + char *rval = NULL; + char *buf = NULL; + + if (xdata == NULL) + return NULL; + + buf = (char *)calloc((length * 2) + 1, sizeof(char)); + + if (buf != NULL) + { + rval = buf; + + for (x = 0; x < length; x++) + { + SnortSnprintf(buf, 3, "%02X", xdata[x]); + buf += 2; + } + + rval[length * 2] = '\0'; + } + + return rval; +} + + + +char *fasthex(const u_char *xdata, int length) +{ + char conv[] = "0123456789ABCDEF"; + char *retbuf = NULL; + const u_char *index; + const u_char *end; + char *ridx; + + index = xdata; + end = xdata + length; + retbuf = (char *)SnortAlloc(((length * 2) + 1) * sizeof(char)); + ridx = retbuf; + + while(index < end) + { + *ridx++ = conv[((*index & 0xFF)>>4)]; + *ridx++ = conv[((*index & 0xFF)&0x0F)]; + index++; + } + + return retbuf; +} + +/* + * Fatal Integer Parser + * Ascii to Integer conversion with fatal error support + */ +long int xatol(const char *s , const char *etext) +{ + long int val; + char *endptr; + char *default_error = "xatol() error\n"; + + if (etext == NULL) + etext = default_error; + + if (s == NULL) + FatalError("%s: String is NULL\n", etext); + + while (isspace((int)*s)) + s++; + + if (strlen(s) == 0) + FatalError("%s: String is empty\n", etext); + + + /* + * strtoul - errors on win32 : ERANGE (VS 6.0) + * errors on linux : ERANGE, EINVAL + * (for EINVAL, unsupported base which won't happen here) + */ + val = SnortStrtol(s, &endptr, 0); + + if ((errno == ERANGE) || (*endptr != '\0')) + FatalError("%s: Invalid integer input: %s\n", etext, s); + + return val; +} + +/* + * Fatal Integer Parser + * Ascii to Integer conversion with fatal error support + */ +unsigned long int xatou(const char *s , const char *etext) +{ + unsigned long int val; + char *endptr; + char *default_error = "xatou() error\n"; + + if (etext == NULL) + etext = default_error; + + if (s == NULL) + FatalError("%s: String is NULL\n", etext); + + while (isspace((int)*s)) + s++; + + if (strlen(s) == 0) + FatalError("%s: String is empty\n", etext); + + if (*s == '-') + { + FatalError("%s: Invalid unsigned integer - negative sign found, " + "input: %s\n", etext, s); + } + + + /* + * strtoul - errors on win32 : ERANGE (VS 6.0) + * errors on linux : ERANGE, EINVAL + */ + val = SnortStrtoul(s, &endptr, 0); + + if ((errno == ERANGE) || (*endptr != '\0')) + FatalError("%s: Invalid integer input: %s\n", etext, s); + + return val; +} + +unsigned long int xatoup(const char *s , const char *etext) +{ + unsigned long int val = xatou(s, etext); + if ( !val ) + FatalError("%s: must be > 0\n", etext); + return val; +} + +#ifndef SUP_IP6 +char * ObfuscateIpToText(const struct in_addr ip_addr) +#else +char * ObfuscateIpToText(sfip_t *ip) +#endif +{ + static char ip_buf1[INET6_ADDRSTRLEN]; + static char ip_buf2[INET6_ADDRSTRLEN]; + static int buf_num = 0; + int buf_size = INET6_ADDRSTRLEN; + char *ip_buf; +#ifndef SUP_IP6 + uint32_t ip = ip_addr.s_addr; +#endif + + if (buf_num) + ip_buf = ip_buf2; + else + ip_buf = ip_buf1; + + buf_num ^= 1; + ip_buf[0] = 0; + +#ifndef SUP_IP6 + if (ip == 0) + return ip_buf; + + if (snort_conf->obfuscation_net == 0) + { + /* Fully obfuscate - just use 'x' */ + SnortSnprintf(ip_buf, buf_size, "xxx.xxx.xxx.xxx"); + } + else + { + if (snort_conf->homenet != 0) + { + if ((ip & snort_conf->netmask) == snort_conf->homenet) + ip = snort_conf->obfuscation_net | (ip & snort_conf->obfuscation_mask); + } + else + { + ip = snort_conf->obfuscation_net | (ip & snort_conf->obfuscation_mask); + } + + SnortSnprintf(ip_buf, buf_size, "%s", inet_ntoa(*((struct in_addr *)&ip))); + } + +#else + if (ip == NULL) + return ip_buf; + + if (!IS_SET(snort_conf->obfuscation_net)) + { + if (IS_IP6(ip)) + SnortSnprintf(ip_buf, buf_size, "x:x:x:x::x:x:x:x"); + else + SnortSnprintf(ip_buf, buf_size, "xxx.xxx.xxx.xxx"); + } + else + { + sfip_t tmp; + char *tmp_buf; + + IP_COPY_VALUE(tmp, ip); + + if (IS_SET(snort_conf->homenet)) + { + if (sfip_contains(&snort_conf->homenet, &tmp) == SFIP_CONTAINS) + sfip_obfuscate(&snort_conf->obfuscation_net, &tmp); + } + else + { + sfip_obfuscate(&snort_conf->obfuscation_net, &tmp); + } + + tmp_buf = sfip_to_str(&tmp); + SnortSnprintf(ip_buf, buf_size, "%s", tmp_buf); + } +#endif + + return ip_buf; +} + +void PrintPacketData(const uint8_t *data, const uint32_t len) +{ + uint32_t i, j; + uint32_t total_len = 0; + uint8_t hex_buf[16]; + uint8_t char_buf[16]; + char *length_chars = " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n" + "------------------------------------------------------\n"; + + LogMessage("%s", length_chars); + + for (i = 0; i <= len; i++) + { + if ((i%16 == 0) && (i != 0)) + { + LogMessage("%04x ", total_len); + total_len += 16; + + for (j = 0; j < 16; j++) + { + LogMessage("%02x ", hex_buf[j]); + if (j == 7) + LogMessage(" "); + } + + LogMessage(" "); + + for (j = 0; j < 16; j++) + { + LogMessage("%c", char_buf[j]); + if (j == 7) + LogMessage(" "); + } + + LogMessage("\n"); + } + + if (i == len) + break; + + hex_buf[i%16] = data[i]; + + if (isprint((int)data[i])) + char_buf[i%16] = data[i]; + else + char_buf[i%16] = '.'; + } + + if ((i-total_len) > 0) + { + LogMessage("%04x ", total_len); + + for (j = 0; j < i-total_len; j++) + { + LogMessage("%02x ", hex_buf[j]); + if (j == 7) + LogMessage(" "); + } + + if (j < 8) + LogMessage(" "); + LogMessage("%*s", (16-j)*3, ""); + LogMessage(" "); + + for (j = 0; j < i-total_len; j++) + { + LogMessage("%c", char_buf[j]); + if (j == 7) + LogMessage(" "); + } + } + + LogMessage("\n"); +} + diff --git a/config/snort-dev/patches/spoink_patch/spo_pf.c b/config/snort-dev/patches/spoink_patch/spo_pf.c new file mode 100644 index 00000000..121920fc --- /dev/null +++ b/config/snort-dev/patches/spoink_patch/spo_pf.c @@ -0,0 +1,462 @@ +/* +* +* Copyright (c) 2006 Antonio Benojar +* Copyright (c) 2005 Antonio Benojar +* +* Copyright (c) 2003, 2004 Armin Wolfermann: +* +* s2c_pf_block and s2c_pf_unblock functions are based +* in Armin's Wolfermann pftabled-1.03 functions. +* +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/* + TODO + + - num. max ips. + - ipwhitelisting structure + - best ip regex expr +*/ + + +#ifndef LIST_END +#define LIST_END(head) NULL +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "event.h" +#include "decode.h" +#include "plugbase.h" +#include "spo_plugbase.h" +#include "debug.h" +#include "parser.h" +#include "util.h" +#include "log.h" +#include "mstring.h" + +#include "snort.h" + +#include "spo_pf.h" + +#ifdef HAVE_STRINGS_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PFDEVICE "/dev/pf" + +typedef struct _SpoAlertPfData { + FILE *wlfile; + char *pftable; + int fd; + struct wlist_head head; +} SpoAlertPfData; + +void AlertPfInit(u_char *); +SpoAlertPfData *ParseAlertPfArgs(char *); +void AlertPf(Packet *, char *, void *, Event *); +void AlertPfCleanExit(int, void *); +void AlertPfRestart(int, void *); + +int s2c_pf_init(void); +int s2c_pf_block(int, char *, char *, int); +int s2c_pf_intbl(int, char *, int); + +int s2c_parse_line(char *, FILE*); +int s2c_parse_load_wl(FILE*, struct wlist_head*, int); +int s2c_parse_search_wl(char *, struct wlist_head); +int s2c_parse_free_wl(struct wlist_head*); +int s2c_parse_ip(char *, char *, int); + + +void AlertPfSetup(void) +{ + RegisterOutputPlugin("alert_pf", OUTPUT_TYPE_FLAG__ALERT, AlertPfInit); + + DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Output plugin: AlertPf is setup...\n");); +} + +void AlertPfInit(u_char *args) +{ + SpoAlertPfData *data; + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Output: AlertPf Initialized\n");); + + data = ParseAlertPfArgs(args); + + DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Linking AlertPf functions to call lists...\n");); + + AddFuncToOutputList(AlertPf, OUTPUT_TYPE_FLAG__ALERT, data); + AddFuncToCleanExitList(AlertPfCleanExit, data); + AddFuncToRestartList(AlertPfRestart, data); +} + + +void AlertPf(Packet *p, char *msg, void *arg, Event *event) +{ + SpoAlertPfData *data = (SpoAlertPfData *)arg; + char *ip; + int ret; + + DEBUG_WRAP(DebugMessage(DEBUG_LOG, "spoink block'n!!\n");); + + ip = inet_ntoa(p->iph->ip_src); + + if (ip == NULL) + FatalError("AlertPf() => inet_ntoa() = NULL\n", strerror(errno)); + + ret = s2c_parse_search_wl(ip, data->head); + + if (ret == 0) + s2c_pf_block(data->fd, data->pftable, inet_ntoa(p->iph->ip_src), 0); + + return; +} + +SpoAlertPfData *ParseAlertPfArgs(char *args) +{ + char **toks; + int num_toks; + SpoAlertPfData *data; + + int res = 0; + + data = (SpoAlertPfData *)SnortAlloc(sizeof(SpoAlertPfData)); + + if(args == NULL) + FatalError("Unable to load pf args\n", strerror(errno)); + + data->fd = s2c_pf_init(); + + if (data->fd == -1) + FatalError("s2c_pf_init() => no pf device\n"); + + DEBUG_WRAP(DebugMessage(DEBUG_LOG,"ParseAlertPfArgs: %s\n", args);); + + toks = mSplit(args, ",", 2, &num_toks, 0); + + if(num_toks <= 1) + FatalError("snort.conf => You must supply TWO arguments for the pf plugin...\n", strerror(errno)); + + if(strstr(toks[0], "..") != NULL) + FatalError("snort.conf => File definition contains \"..\". Do not do that!\n"); + + data->wlfile = fopen(toks[0], "r"); + + if (data->wlfile == NULL) + FatalError("snort.conf => Unable to open whitelist file\n", strerror(errno)); + + if (toks[1] == NULL) + FatalError("snort.conf => No pf table defined\n", strerror(errno)); + else + data->pftable = toks[1]; + + if (s2c_pf_intbl(data->fd, data->pftable, 0) == 0) + FatalError("pf.conf => Table %s don't exists in packet filter\n", data->pftable, strerror(errno)); + + res = s2c_parse_load_wl(data->wlfile, &data->head, 0); + if (res == -1) + FatalError("snort.conf => Unable to load whitelist\n", strerror(errno)); + + return data; +} + +void AlertPfCleanExit(int signal, void *arg) +{ + SpoAlertPfData *data = (SpoAlertPfData *)arg; + DEBUG_WRAP(DebugMessage(DEBUG_LOG,"AlertPfCleanExit\n");); + + s2c_parse_free_wl(&data->head); + fclose(data->wlfile); + close(data->fd); + + free(data); +} + +void AlertPfRestart(int signal, void *arg) +{ + SpoAlertPfData *data = (SpoAlertPfData *)arg; + DEBUG_WRAP(DebugMessage(DEBUG_LOG,"AlertPfRestart\n");); + + s2c_parse_free_wl(&data->head); + fclose(data->wlfile); + close(data->fd); + + free(data); +} + + +int s2c_pf_init(void) +{ + return(open(PFDEVICE, O_RDWR)); +} + +int s2c_pf_block(int dev, char *tablename, char *ip, int debug) +{ + + struct pfioc_table io; + struct pfr_table table; + struct pfr_addr addr; + struct in_addr *net_addr=NULL; + + memset(&io, 0x00, sizeof(struct pfioc_table)); + memset(&table, 0x00, sizeof(struct pfr_table)); + memset(&addr, 0x00, sizeof(struct pfr_addr)); + + strlcpy(table.pfrt_name, tablename, PF_TABLE_NAME_SIZE); + net_addr=(struct in_addr*)malloc(sizeof(struct in_addr)); + + if (net_addr == NULL ) + FatalError("s2c_pf_block() => malloc()\n", strerror(errno)); + + inet_aton(ip, (struct in_addr *)&net_addr); + memcpy(&addr.pfra_ip4addr.s_addr, &net_addr, sizeof(struct in_addr)); + + addr.pfra_af = AF_INET; + addr.pfra_net = 32; + + io.pfrio_table = table; + io.pfrio_buffer = &addr; + io.pfrio_esize = sizeof(struct pfr_addr); + io.pfrio_size = 1; + + if (ioctl(dev, DIOCRADDADDRS, &io)) + FatalError("s2c_pf_block() => ioctl() DIOCRADDADDRS\n", strerror(errno)); + + return(0); +} + +int s2c_pf_intbl(int dev, char * tablename, int debug) +{ + int i; + struct pfioc_table io; + struct pfr_table *table_aux = NULL; + + memset(&io, 0x00, sizeof(struct pfioc_table)); + + io.pfrio_buffer = table_aux; + io.pfrio_esize = sizeof(struct pfr_table); + io.pfrio_size = 0; + + if(ioctl(dev, DIOCRGETTABLES, &io)) + FatalError("s2c_pf_intbl() => ioctl() DIOCRGETTABLES\n", strerror(errno)); + + table_aux = (struct pfr_table*)malloc(sizeof(struct pfr_table)*io.pfrio_size); + + if (table_aux == NULL) + FatalError("s2c_pf_intbl() => malloc()\n", strerror(errno)); + + io.pfrio_buffer = table_aux; + io.pfrio_esize = sizeof(struct pfr_table); + + if(ioctl(dev, DIOCRGETTABLES, &io)) + FatalError("s2c_pf_intbl() => ioctl() DIOCRGETTABLES\n", strerror(errno)); + + for(i=0; i< io.pfrio_size; i++) { + if (!strcmp(table_aux[i].pfrt_name, tablename)) + return 1; + } + + return 0; + +} + + +int s2c_parse_line(char buf[WLMAX] , FILE* wfile) +{ + static char next_ch = ' '; + int i = 0; + + if (feof(wfile)) { + return (0); + } + do { + next_ch = fgetc(wfile); + if (i < WLMAX) + buf[i++] = next_ch; + } while (!feof(wfile) && !isspace(next_ch)); + if (i >= WLMAX) { + return (-1); + } + + buf[i] = '\0'; + return (1); +} + + +int s2c_parse_load_wl(FILE *wfile, struct wlist_head *head, int debug) +{ + + char cad[WLMAX]; + char ret[WLMAX]; + struct ipwlist *ipw2, *ipw1 = NULL; + struct flock lock; + + if (wfile == NULL) + FatalError("s2c_parse_load_wl() => Unable to open whitelist file\n", strerror(errno)); + + memset(&lock, 0x00, sizeof(struct flock)); + lock.l_type = F_RDLCK; + fcntl(fileno(wfile), F_SETLKW, &lock); + + LIST_INIT(head); + + if (s2c_parse_line(cad, wfile) == 1) { + if (s2c_parse_ip(cad, ret, debug) == 1) { + ipw1 = (struct ipwlist*)malloc(sizeof(struct ipwlist)); + if (ipw1 == NULL) + FatalError("s2c_parse_load_wl() => malloc()\n", strerror(errno)); + inet_aton(ret, &ipw1->waddr); + LIST_INSERT_HEAD(head, ipw1, elem); + + } else { + FatalError("s2c_parse_load_wl() => Invalid data in whitelist file\n", strerror(errno)); + } + } + + while(s2c_parse_line(cad, wfile) == 1) { + if (s2c_parse_ip(cad, ret, debug) == 1) { + ipw2 = (struct ipwlist*)malloc(sizeof(struct ipwlist)); + if (ipw2 == NULL) + FatalError("s2c_parse_load_wl() => malloc()\n", strerror(errno)); + inet_aton(ret, &ipw2->waddr); + LIST_INSERT_AFTER(ipw1, ipw2, elem); + ipw1 = ipw2; + } else { + break; + } + + } + + lock.l_type = F_UNLCK; + fcntl(fileno(wfile), F_SETLKW, &lock); + + return (0); +} + +/* XXX: optimize */ + +int +s2c_parse_search_wl(char *ip, struct wlist_head wl) +{ + struct ipwlist *aux2; + char *ip_aux, ip1[IPMAX], ip2[IPMAX]; + int ret; + + strlcpy(ip1, ip, sizeof(ip1)); + + for(aux2=wl.lh_first; aux2 !=NULL; aux2=aux2->elem.le_next) { + ip_aux = inet_ntoa(aux2->waddr); + strlcpy(ip2, ip_aux, sizeof(ip2)); + ret = strcmp(ip1, ip2); + + if (ret == 0) + return 1; + } + return (0); +} + + +int s2c_parse_free_wl(struct wlist_head *wl) +{ + struct ipwlist *aux, *aux2; + for(aux = LIST_FIRST(wl); aux != LIST_END(wl); aux = aux2) { + aux2 = LIST_NEXT(aux, elem); + LIST_REMOVE(aux, elem); + free(aux); + } + if (LIST_EMPTY(wl)) { + return (1); + } else { + FatalError("s2c_parse_free_wl() => Unable to free whitelist\n", strerror(errno)); + return (0); + } +} + +/* XXX: too much complex ? */ + +int s2c_parse_ip(char *cad, char ret[WLMAX], int debug) +{ + int len; + unsigned int enc=1; + regex_t *expr; + regmatch_t *resultado; + expr = (regex_t*)malloc(sizeof(regex_t)); + + bzero(ret, WLMAX); + + if (expr == NULL) + FatalError("s2c_parse_ip() => malloc()\n", strerror(errno)); + + resultado = (regmatch_t*)malloc(sizeof(regmatch_t)); + + if (resultado == NULL) + FatalError("s2c_parse_ip() => malloc()\n", strerror(errno)); + + if (regcomp(expr, REG_ADDR, REG_EXTENDED) !=0) + FatalError("s2c_parse_ip() => regcomp()\n", strerror(errno)); + + if (regexec(expr, cad, 1, resultado, 0) !=0) + enc=0; + + if (enc !=0) { + len = resultado->rm_eo - resultado->rm_so; + memcpy(ret, cad + resultado->rm_so, len); + ret[len]='\0'; + } + + free(resultado); + regfree(expr); + + if(enc) + return (1); + else { + errno = EINVAL; + return (0); + } +} diff --git a/config/snort-dev/patches/spoink_patch/spo_pf.h b/config/snort-dev/patches/spoink_patch/spo_pf.h new file mode 100644 index 00000000..af07dacd --- /dev/null +++ b/config/snort-dev/patches/spoink_patch/spo_pf.h @@ -0,0 +1,60 @@ +/* +* +* Copyright (c) 2006 Antonio Benojar +* Copyright (c) 2005 Antonio Benojar +* +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __SPO_PF_H__ +#define __SPO_PF_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WLMAX 1024 +#define IPMAX 20 +#define REG_ADDR "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}" + + +struct ipwlist { + struct in_addr waddr; + LIST_ENTRY(ipwlist) elem; +}; + +LIST_HEAD(wlist_head, ipwlist); + +void AlertPfSetup(void); + +#endif + + -- cgit v1.2.3