// 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;
int eval(Cursor&, Packet*) override;
private:
- FragBitsData config;
+ FragBitsData fragBitsData;
};
-static uint16_t bitmask = 0x0;
-
//-------------------------------------------------------------------------
// api methods
//-------------------------------------------------------------------------
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());
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;
}
{
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
//-------------------------------------------------------------------------
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;
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)
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
#else
const BaseApi* ips_fragbits = &fragbits_api.base;
#endif
-