]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #599 in SNORT/snort3 from ips_fragbits to master
authorTom Peters (thopeter) <thopeter@cisco.com>
Mon, 22 Aug 2016 20:58:27 +0000 (16:58 -0400)
committerTom Peters (thopeter) <thopeter@cisco.com>
Mon, 22 Aug 2016 20:58:27 +0000 (16:58 -0400)
Squashed commit of the following:

commit 60190f6f0526808c8179610ce66e8e81e29cd796
Author: alewis <albert.l.lewis@gmail.com>
Date:   Sat Aug 20 16:38:21 2016 -0400

    removed empty line

commit debb157e5077fb43acd1e7b17b5c4aa7c0bee825
Author: alewis <albert.l.lewis@gmail.com>
Date:   Sat Aug 20 16:30:43 2016 -0400

    updated file added enums and replace if/else ladder

commit 9dd73493258e9687bcd10ce09bd492cc3483e966
Author: alewis <albert.l.lewis@gmail.com>
Date:   Sat Aug 20 12:33:37 2016 -0400

    changed const values to enum

commit e1f477039b0d934e629654f2dc7b8bd99511e91e
Author: alewis <albert.l.lewis@gmail.com>
Date:   Fri Aug 19 11:19:22 2016 -0400

    updated ips_fragbits

src/ips_options/ips_fragbits.cc

index 4dcca9e2e74a2e2b890e9653243885107a524380..4abcb0020065a539ea99183c99595b6f0fc71f83 100644 (file)
 // with this program; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
+// ips_fragbits.cc author Al Lewis <allewi>@cisco.com
+// based on work by Martin Roesch <roesch@sourcefire.com>
 
-/* Snort Detection Plugin Source File for IP Fragment Bits plugin */
-
-/* sp_ip_fragbits
+/* ips_fragbits.cc
  *
  * Purpose:
  *
  * Arguments:
  *
  * The keyword to reference this plugin is "fragbits".  Possible arguments are
- * D, M and R for DF, MF and RB, respectively.
+ * D, M and R for DF, MF and RB, respectively. 
+ * 
+ * Possible modes are '+', '!', and '*' for plus, not and any modes.
  *
  * Effect:
  *
- * Inidicates whether any of the specified bits have been set.
+ * Indicates whether any of the specified bits have been set.
  *
  * Comments:
  *
 #include "framework/parameter.h"
 #include "framework/module.h"
 
-#define GREATER_THAN            1
-#define LESS_THAN               2
 
-#define FB_NORMAL   0
-#define FB_ALL      1
-#define FB_ANY      2
-#define FB_NOT      3
+static THREAD_LOCAL ProfileStats fragBitsPerfStats;
 
-#define FB_RB  0x8000
-#define FB_DF  0x4000
-#define FB_MF  0x2000
+// this class holds the logic for setting up the fragment test 
+// data and testing for the data match (is_match function). 
+class FragBitsData
+{
+public:    
+    FragBitsData()
+    {
+        mode = 0;
+        frag_bits = 0;
+    }
+    
+    uint8_t get_mode() const;
+    uint16_t get_frag_bits() const;
+    void set_frag_bits(uint16_t);
+    void set_more_fragment_bit();
+    void set_dont_fragment_bit();
+    void set_reserved_bit();
+    
+    //no mode for normal since it is set as the default
+    void set_not_mode();
+    void set_any_mode();
+    void set_plus_mode();
+    
+    void parse_fragbits(const char* data);
+    
+    bool is_match(Packet *);
+    
+private:
+    //numeric mode values
+    enum MODE { NORMAL, PLUS, ANY, NOT};
+    
+    const static uint16_t BITMASK = 0xE000; 
+    const static uint16_t RESERVED_BIT = 0x8000;
+    const static uint16_t DONT_FRAG_BIT = 0x4000;
+    const static uint16_t MORE_FRAG_BIT = 0x2000;
+   
+    //flags used to indicate mode
+    const static char PLUS_FLAG = '+';
+    const static char ANY_FLAG = '*'; 
+    const static char NOT_FLAG = '!';
+    
+    bool has_normal_mode();
+    bool has_any_mode();
+    bool has_not_mode();
+    bool has_plus_mode();
+    
+    bool check_normal(const uint16_t);
+    bool check_any(const uint16_t);
+    bool check_not(const uint16_t);
+    bool check_plus(const uint16_t);
+    
+    uint8_t mode;
+    uint16_t frag_bits;
+};
 
-#define s_name "fragbits"
+//setter and getters
+uint8_t FragBitsData::get_mode() const
+{ return mode; }
 
-static THREAD_LOCAL ProfileStats fragBitsPerfStats;
+uint16_t FragBitsData::get_frag_bits() const
+{ return (frag_bits); }
+
+void FragBitsData::set_dont_fragment_bit()
+{ frag_bits |= DONT_FRAG_BIT; }
+
+void FragBitsData::set_more_fragment_bit()
+{ frag_bits |= MORE_FRAG_BIT; }
+
+void FragBitsData::set_reserved_bit()
+{ frag_bits |= RESERVED_BIT; }
+
+void FragBitsData::set_any_mode()
+{ mode = ANY; }
+
+void FragBitsData::set_plus_mode()
+{ mode = PLUS; }
+
+void FragBitsData::set_not_mode()
+{ mode = NOT; }
+
+bool FragBitsData::has_normal_mode()
+{ return (mode == NORMAL); }
+
+bool FragBitsData::has_any_mode()
+{ return (mode == ANY); }
+
+bool FragBitsData::has_not_mode()
+{ return (mode == NOT); }
+
+bool FragBitsData::has_plus_mode() 
+{ return (mode == PLUS); }
 
-typedef struct _FragBitsData
+// this is the function that checks for a match
+bool FragBitsData::is_match(Packet* p) 
 {
-    char mode;
-    uint16_t frag_bits;
-} FragBitsData;
+    uint16_t packet_fragbits = p->ptrs.ip_api.off_w_flags();   
+    
+    // strip the offset value and leave only the fragment bits
+    packet_fragbits &= BITMASK;
+    
+    bool match = false;
+    
+    // get the mode we have .. then check for match
+    switch( get_mode() )
+    {
+        case NORMAL:
+            match = check_normal(packet_fragbits); 
+            break;
+        case ANY:
+            match = check_any(packet_fragbits);
+            break;
+        case PLUS:
+            match = check_plus(packet_fragbits);
+            break;
+        case NOT:
+            match = check_not(packet_fragbits);
+            break;
+    }
+    
+    return match;
+}
+
+// check if all of flags are present
+bool FragBitsData::check_normal(const uint16_t packet_fragbits)
+{
+    if (get_frag_bits() == packet_fragbits)
+    {
+        return true;
+    }
+    return false;
+}
+
+// check for these flags being set PLUS additional '+'
+bool FragBitsData::check_plus(const uint16_t packet_fragbits)
+{
+    if ( (get_frag_bits() &  packet_fragbits ) != 0)
+    {
+        return true;
+    }
+     return false;
+}
+
+// check for any flags that match the ones set '*'
+// logic is same as the check_plus
+bool FragBitsData::check_any(const uint16_t packet_fragbits)
+{
+    if ( (get_frag_bits() & packet_fragbits ) != 0)
+    {
+        return true;
+    }
+    return false;
+}
+
+//check for packets that do NOT have matching flags set '!'
+bool FragBitsData::check_not(const uint16_t packet_fragbits) 
+{
+    if ( (get_frag_bits() & packet_fragbits ) == 0)
+    {
+        return true;
+    }
+    return false;
+}
+
+// parse fragbits and populate the information into this class
+void FragBitsData::parse_fragbits(const char* data)
+{
+    std::string bit_string;
+    
+    // if its null the bit_string will stay empty
+    if(data)
+    {
+        bit_string = data;
+    }
+    else if ( bit_string.empty() )
+    {
+        ParseError("no arguments to the fragbits keyword");
+        return;
+    }
+    
+    unsigned long len = bit_string.length();
+    
+    for(unsigned long a = 0; a <  len; a++)
+    {
+        //if we hit a space skip/continue
+        if( isspace( bit_string.at(a) ) )
+            continue;
+        
+        switch ( bit_string.at( a ) )
+        {
+        case 'd': // dont fragment
+        case 'D': 
+            set_dont_fragment_bit();
+            break;
+            
+        case 'm': // more fragment
+        case 'M': 
+            set_more_fragment_bit();
+            break;
+            
+        case 'r': // reserved bit
+        case 'R':   
+            set_reserved_bit();
+            break;
+            
+        case NOT_FLAG:// NOT flag, fire if flags are NOT set
+            set_not_mode();
+            break;
+
+        case ANY_FLAG: // '*' ANY flag, fire on ANY of these bits
+            set_any_mode();
+            break;
+
+        case PLUS_FLAG: // PLUS flag, fire on these bits PLUS any others
+            set_plus_mode();
+            break;
+                
+        default:
+            ParseError("Bad fragbit = '%c'. Valid options are: RDM+!*",
+                    bit_string.at(a) );
+            return;
+        }
+    }
+}
+
+#define s_name "fragbits"
 
+// IpsOptions class
 class FragBitsOption : public IpsOption
 {
 public:
-    FragBitsOption(const FragBitsData& c) :
+    FragBitsOption(const FragBitsData& fragBitsData) :
         IpsOption(s_name)
-    { config = c; }
+    { this->fragBitsData = fragBitsData; }
 
     uint32_t hash() const override;
     bool operator==(const IpsOption&) const override;
@@ -99,11 +309,9 @@ public:
     int eval(Cursor&, Packet*) override;
 
 private:
-    FragBitsData config;
+    FragBitsData fragBitsData;
 };
 
-static uint16_t bitmask = 0x0;
-
 //-------------------------------------------------------------------------
 // api methods
 //-------------------------------------------------------------------------
@@ -111,10 +319,10 @@ static uint16_t bitmask = 0x0;
 uint32_t FragBitsOption::hash() const
 {
     uint32_t a,b,c;
-    const FragBitsData* data = &config;
+    const FragBitsData* data = &fragBitsData;
 
-    a = data->mode;
-    b = data->frag_bits;
+    a = data->get_mode(); 
+    b = data->get_frag_bits(); 
     c = 0;
 
     mix_str(a,b,c,get_name());
@@ -129,11 +337,11 @@ bool FragBitsOption::operator==(const IpsOption& ips) const
         return false;
 
     FragBitsOption& rhs = (FragBitsOption&)ips;
-    FragBitsData* left = (FragBitsData*)&config;
-    FragBitsData* right = (FragBitsData*)&rhs.config;
+    FragBitsData* left = (FragBitsData*)&fragBitsData;
+    FragBitsData* right = (FragBitsData*)&rhs.fragBitsData;
 
-    if ((left->mode == right->mode) &&
-        (left->frag_bits == right->frag_bits))
+    if ((left->get_mode() == right->get_mode()) &&
+        (left->get_frag_bits() == right->get_frag_bits()))
     {
         return true;
     }
@@ -145,153 +353,18 @@ int FragBitsOption::eval(Cursor&, Packet* p)
 {
     Profile profile(fragBitsPerfStats);
 
-    FragBitsData* fb = &config;
-
     if ( !p->has_ip() )
         return DETECTION_OPTION_NO_MATCH;
 
-
-    const uint16_t frag_offset = p->ptrs.ip_api.off_w_flags();
-
-
-    DebugMessage(DEBUG_IPS_OPTION, "           <!!> CheckFragBits: ");
-        DebugFormat(DEBUG_IPS_OPTION, "[rule: 0x%X:%d   pkt: 0x%X] ",
-        fb->frag_bits, fb->mode, frag_offset & bitmask);
-
-    switch (fb->mode)
-    {
-    case FB_NORMAL:
-        /* check if the rule bits match the bits in the packet */
-        if (fb->frag_bits == (frag_offset & bitmask))
-        {
-            DebugMessage(DEBUG_IPS_OPTION,"Got Normal bits match\n");
-            return DETECTION_OPTION_MATCH;
-        }
-        else
-        {
-            DebugMessage(DEBUG_IPS_OPTION,"Normal test failed\n");
-        }
-
-        break;
-
-    case FB_NOT:
-        /* check if the rule bits don't match the bits in the packet */
-        if ((fb->frag_bits & (frag_offset & bitmask)) == 0)
-        {
-            DebugMessage(DEBUG_IPS_OPTION,"Got NOT bits match\n");
-            return DETECTION_OPTION_MATCH;
-        }
-        else
-        {
-            DebugMessage(DEBUG_IPS_OPTION,"NOT test failed\n");
-        }
-        break;
-
-    case FB_ALL:
-        /* check if the rule bits are present in the packet */
-        if ((fb->frag_bits & (frag_offset & bitmask)) == fb->frag_bits)
-        {
-            DebugMessage(DEBUG_IPS_OPTION,"Got ALL bits match\n");
-            return DETECTION_OPTION_MATCH;
-        }
-        else
-        {
-            DebugMessage(DEBUG_IPS_OPTION,"ALL test failed\n");
-        }
-        break;
-
-    case FB_ANY:
-        /* check if any of the rule bits match the bits in the packet */
-        if ((fb->frag_bits & (frag_offset & bitmask)) != 0)
-        {
-            DebugMessage(DEBUG_IPS_OPTION,"Got ANY bits match\n");
-            return DETECTION_OPTION_MATCH;
-        }
-        else
-        {
-            DebugMessage(DEBUG_IPS_OPTION,"ANY test failed\n");
-        }
-        break;
-
-    default:
-        break;
-    }
-
-    /* if the test isn't successful, this function *must* return 0 */
+    bool is_match = fragBitsData.is_match(p);
+    
+    if(is_match)
+        return DETECTION_OPTION_MATCH;
+    // if the test isn't successful, this function *must* return 0
     return DETECTION_OPTION_NO_MATCH;
 }
 
-//-------------------------------------------------------------------------
-// api methods
-//-------------------------------------------------------------------------
-
-static void fragbits_parse(const char* data, FragBitsData* ds_ptr)
-{
-    const char* fptr;
-    const char* fend;
-
-    /* manipulate the option arguments here */
-    fptr = data;
-
-    while (isspace((u_char) *fptr))
-    {
-        fptr++;
-    }
-
-    if (strlen(fptr) == 0)
-    {
-        ParseError("no arguments to the fragbits keyword");
-        return;
-    }
-
-    fend = fptr + strlen(fptr);
-
-    ds_ptr->mode = FB_NORMAL;  /* default value */
-
-    while (fptr < fend)
-    {
-        switch ((*fptr&0xFF))
-        {
-        case 'd':
-        case 'D':     /* don't frag bit */
-            ds_ptr->frag_bits |= FB_DF;
-            break;
-
-        case 'm':
-        case 'M':     /* more frags bit */
-            ds_ptr->frag_bits |= FB_MF;
-            break;
-
-        case 'r':
-        case 'R':     /* reserved bit */
-            ds_ptr->frag_bits |= FB_RB;
-            break;
-
-        case '!':     /* NOT flag, fire if flags are not set */
-            ds_ptr->mode = FB_NOT;
-            break;
-
-        case '*':     /* ANY flag, fire on any of these bits */
-            ds_ptr->mode = FB_ANY;
-            break;
-
-        case '+':     /* ALL flag, fire on these bits plus any others */
-            ds_ptr->mode = FB_ALL;
-            break;
-
-        default:
-            ParseError(
-                "Bad Frag Bits = '%c'. Valid options are: RDM+!*", *fptr);
-            return;
-        }
-
-        fptr++;
-    }
-
-    /* put the bits in network order for fast comparisons */
-    ds_ptr->frag_bits = htons(ds_ptr->frag_bits);
-}
-
 //-------------------------------------------------------------------------
 // module
 //-------------------------------------------------------------------------
@@ -317,21 +390,30 @@ public:
 
     ProfileStats* get_profile() const override
     { return &fragBitsPerfStats; }
+    
+    FragBitsData get_fragBits_data();
 
-    FragBitsData data;
+private:
+    FragBitsData fragBitsData;
 };
 
+//provide access to the data object within the module
+FragBitsData FragBitsModule::get_fragBits_data()
+{
+    return fragBitsData;
+}
+
 bool FragBitsModule::begin(const char*, int, SnortConfig*)
 {
-    memset(&data, 0, sizeof(data));
     return true;
 }
 
+// the fragbitsData object is set here from the value string
+// which is the string of command line arguments
 bool FragBitsModule::set(const char*, Value& v, SnortConfig*)
 {
     if ( v.is("~flags") )
-        fragbits_parse(v.get_string(), &data);
-
+        fragBitsData.parse_fragbits(v.get_string());
     else
         return false;
 
@@ -352,15 +434,10 @@ static void mod_dtor(Module* m)
     delete m;
 }
 
-static void fragbits_init(SnortConfig*)
-{
-    bitmask = htons(0xE000);
-}
-
 static IpsOption* fragbits_ctor(Module* p, OptTreeNode*)
 {
-    FragBitsModule* m = (FragBitsModule*)p;
-    return new FragBitsOption(m->data);
+    FragBitsModule* fragBitsModule = (FragBitsModule*)p;
+    return new FragBitsOption( fragBitsModule->get_fragBits_data() );
 }
 
 static void fragbits_dtor(IpsOption* p)
@@ -370,27 +447,31 @@ static void fragbits_dtor(IpsOption* p)
 
 static const IpsApi fragbits_api =
 {
+    //BaseApi struct
     {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        0,
-        API_RESERVED,
-        API_OPTIONS,
-        s_name,
-        s_help,
-        mod_ctor,
-        mod_dtor
+        PT_IPS_OPTION,  //PlugType type
+        sizeof(IpsApi), //uint32_t size
+        IPSAPI_VERSION, //uint32_t api_version
+        0,              //uint32_t version
+        API_RESERVED,   //uint32_t reserved
+        API_OPTIONS,    //const char* options
+        s_name,         //const char* name
+        s_help,         //const char* help
+        mod_ctor,       //ModNewFunc constructor
+        mod_dtor        //ModDelFunc destructor
     },
-    OPT_TYPE_DETECTION,
-    1, 0,
-    fragbits_init,
-    nullptr,
-    nullptr,
-    nullptr,
-    fragbits_ctor,
-    fragbits_dtor,
-    nullptr
+    
+    //IpsApi struct
+    OPT_TYPE_DETECTION, //RuleOptType
+    1,                  //max per rule 
+    0,                  //IpsOptFunc protos
+    nullptr,            //IpsOptFunc pinit
+    nullptr,            //IpsOptFunc pterm
+    nullptr,            //IpsOptFunc tinit
+    nullptr,            //IpsOptFunc tterm
+    fragbits_ctor,      //IpsNewFunc ctor
+    fragbits_dtor,      //IpsNewFunc dtor
+    nullptr             //IpsOptFunc verify
 };
 
 #ifdef BUILDING_SO
@@ -402,4 +483,3 @@ SO_PUBLIC const BaseApi* snort_plugins[] =
 #else
 const BaseApi* ips_fragbits = &fragbits_api.base;
 #endif
-