From: Russ Combs Date: Thu, 19 Jun 2014 02:36:35 +0000 (-0400) Subject: see change log for 88; mostly detection using Cursor X-Git-Tag: 3.0.0-233~1483 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=056ecc3ea2aac73e9d7a829073b2e548c8700fc8;p=thirdparty%2Fsnort3.git see change log for 88; mostly detection using Cursor --- diff --git a/ChangeLog b/ChangeLog index 64d129330..d347576a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 88 --- tweaked allocation of pmd.last_check +-- overhauled content and pcre detection to use Cursor +-- http_* are now first class rule options +-- removed experimental contents and get_buf() from InspectApi +-- changed call to acquire daq with count 0 (all) +-- changed replace to be 1st class rule option +-- split boyer-moore functions out of mstring module 87 -- renamed api function typedefs to camel case for consistency and to match diff --git a/configure.ac b/configure.ac index 44d970cbd..0573a3125 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,7 @@ # initialization #-------------------------------------------------------------------------- -AC_INIT([snort], [2.10.087]) +AC_INIT([snort], [2.10.088]) AC_PREREQ([2.68]) AC_CONFIG_SRCDIR([src/main.h]) diff --git a/extra/README b/extra/README new file mode 100644 index 000000000..b5c743feb --- /dev/null +++ b/extra/README @@ -0,0 +1,30 @@ +0. Given this variable: + +install_dir=/home/snorty/install + +1. Build and install the Snort package first: + +./configure --prefix=$install_dir ... + +2. Make sure that pkg-config is installed. Then + +export PKG_CONFIG_PATH=$install_dir/lib/pkgconfig + +3. Build and install the example plugins: + +./configure --prefix=$install_dir --with-snort-includes=$install_dir/include/snort +make +make install + +4. Run Snort with the example plugins: + +snort --plugin-path $install_dir/lib/snort_examples ... + +5. Now build your own plugins following the examples. + For inspiration, also look at: + +src/service_handlers/ +src/network_handlers/ +src/event_handlers/ +src/detection_plugins/ips_* + diff --git a/src/detection/detect.cc b/src/detection/detect.cc index 607e6fdb4..4ea5821e5 100644 --- a/src/detection/detect.cc +++ b/src/detection/detect.cc @@ -819,7 +819,7 @@ int RuleListEnd(Packet*, RuleTreeNode*, RuleFpList*, int) return 1; } -int OptListEnd(void*, Packet*) +int OptListEnd(void*, Cursor&, Packet*) { return DETECTION_OPTION_MATCH; } diff --git a/src/detection/detect.h b/src/detection/detect.h index 07ba0f8f7..69026f672 100644 --- a/src/detection/detect.h +++ b/src/detection/detect.h @@ -70,7 +70,7 @@ int CheckSrcPortNotEq(Packet *, RuleTreeNode *, RuleFpList *, int); int CheckDstPortNotEq(Packet *, RuleTreeNode *, RuleFpList *, int); int RuleListEnd(Packet *, RuleTreeNode *, RuleFpList *, int); -int OptListEnd(void *option_data, Packet *p); +int OptListEnd(void* option_data, struct Cursor&, Packet*); void snort_log(Packet*); void CallLogFuncs(Packet*, Event*, const char*); diff --git a/src/detection/detection_options.cc b/src/detection/detection_options.cc index 2ef329908..e4e0ba02c 100644 --- a/src/detection/detection_options.cc +++ b/src/detection/detection_options.cc @@ -49,13 +49,14 @@ #include "ips_options/ips_flowbits.h" #include "ips_options/ips_content.h" #include "ips_options/ips_pcre.h" -#include "ips_options/replace.h" +#include "ips_options/ips_replace.h" #include "fpdetect.h" #include "ppm.h" #include "profiler.h" #include "filters/detection_filter.h" #include "main/thread.h" #include "framework/ips_option.h" +#include "framework/cursor.h" #include "managers/ips_manager.h" #include "managers/packet_manager.h" @@ -388,15 +389,15 @@ int add_detection_option_tree( THREAD_LOCAL uint64_t rule_eval_pkt_count = 0; int detection_option_node_evaluate( - detection_option_tree_node_t *node, detection_option_eval_data_t *eval_data) + detection_option_tree_node_t *node, detection_option_eval_data_t *eval_data, + Cursor& orig_cursor) { - int i, result = 0, prior_result = 0; + int i, result = 0; //, prior_result = 0; int rval = DETECTION_OPTION_NO_MATCH; - const uint8_t *orig_doe_ptr; char tmp_noalert_flag = 0; - PatternMatchData dup_content_option_data; - PcreData dup_pcre_option_data; - const uint8_t *dp = NULL; + Cursor cursor = orig_cursor; + PatternMatchData* content_data; + PcreData* pcre_data; char continue_loop = 1; char flowbits_setoperation = 0; int loop_count = 0; @@ -441,64 +442,14 @@ int detection_option_node_evaluate( state->last_check.flowbit_failed = 0; /* Save some stuff off for repeated pattern tests */ - orig_doe_ptr = doe_ptr; - if ((node->option_type == RULE_OPTION_TYPE_CONTENT) || (node->option_type == RULE_OPTION_TYPE_CONTENT_URI)) { - PatternMatchDuplicatePmd(node->option_data, &dup_content_option_data); - - if (dup_content_option_data.buffer_func == CHECK_URI_PATTERN_MATCH) - { - const HttpBuffer* hb = GetHttpBuffer(dup_content_option_data.http_buffer); - dp = hb ? hb->buf : NULL; // FIXTHIS set length too - } - else if (dup_content_option_data.rawbytes == 0) - { - /* If AltDetect is set by calling the rule options which set it, - * we should use the Alt Detect before checking for any other buffers. - * Alt Detect will take precedence over the Alt Decode and/or packet data. - */ - if(Is_DetectFlag(FLAG_ALT_DETECT)) - dp = (uint8_t *)DetectBuffer.data; - else if(Is_DetectFlag(FLAG_ALT_DECODE)) - dp = (uint8_t *)DecodeBuffer.data; - else - dp = eval_data->p->data; - } - else - { - dp = eval_data->p->data; - } + content_data = content_get_data(node->option_data); } else if (node->option_type == RULE_OPTION_TYPE_PCRE) { - HTTP_BUFFER hb_type; - PcreDuplicatePcreData(node->option_data, &dup_pcre_option_data); - hb_type = (HTTP_BUFFER)(dup_pcre_option_data.options & SNORT_PCRE_HTTP_BUFS); - - if ( hb_type ) - { - const HttpBuffer* hb = GetHttpBuffer(hb_type); - dp = hb ? hb->buf : NULL; // FIXTHIS set length too - } - else if (!(dup_pcre_option_data.options & SNORT_PCRE_RAWBYTES)) - { - /* If AltDetect is set by calling the rule options which set it, - * we should use the Alt Detect before checking for any other buffers. - * Alt Detect will take precedence over the Alt Decode and/or packet data. - */ - if(Is_DetectFlag(FLAG_ALT_DETECT)) - dp = (uint8_t *)DetectBuffer.data; - else if(Is_DetectFlag(FLAG_ALT_DECODE)) - dp = (uint8_t *)DecodeBuffer.data; - else - dp = eval_data->p->data; - } - else - { - dp = eval_data->p->data; - } + pcre_data = pcre_get_data(node->option_data); } /* No, haven't evaluated this one before... Check it. */ @@ -528,7 +479,8 @@ int detection_option_node_evaluate( { if (otn->sigInfo.services[svc_idx].service_ordinal != 0) { - if (eval_data->p->application_protocol_ordinal == otn->sigInfo.services[svc_idx].service_ordinal) + if (eval_data->p->application_protocol_ordinal == + otn->sigInfo.services[svc_idx].service_ordinal) { check_ports = 0; break; /* out of for */ @@ -574,16 +526,17 @@ int detection_option_node_evaluate( case RULE_OPTION_TYPE_CONTENT: if (node->evaluate) { +#if 0 /* This will be set in the fast pattern matcher if we found * a content and the rule option specifies not that * content. Essentially we've already evaluated this rule * option via the content option processing since only not * contents that are not relative in any way will have this * flag set */ - if (dup_content_option_data.last_check) + if (content_data->last_check) { PmdLastCheck* last_check = - dup_content_option_data.last_check + get_instance_id(); + content_data->last_check + get_instance_id(); if ((last_check->ts.tv_sec == eval_data->p->pkth->ts.tv_sec) && (last_check->ts.tv_usec == eval_data->p->pkth->ts.tv_usec) && @@ -594,23 +547,20 @@ int detection_option_node_evaluate( break; } } - - rval = eval_dup_content( - node->option_data, eval_data->p, &dup_content_option_data); +#endif + rval = node->evaluate(node->option_data, cursor, eval_data->p); } break; case RULE_OPTION_TYPE_CONTENT_URI: if (node->evaluate) { - rval = eval_dup_content( - node->option_data, eval_data->p, &dup_content_option_data); + rval = node->evaluate(node->option_data, cursor, eval_data->p); } break; case RULE_OPTION_TYPE_PCRE: if (node->evaluate) { - rval = eval_dup_pcre( - node->option_data, eval_data->p, &dup_pcre_option_data); + rval = node->evaluate(node->option_data, cursor, eval_data->p); } break; case RULE_OPTION_TYPE_PKT_DATA: @@ -619,7 +569,7 @@ int detection_option_node_evaluate( if (node->evaluate) { save_dflags = Get_DetectFlags(); - rval = node->evaluate(node->option_data, eval_data->p); + rval = node->evaluate(node->option_data, cursor, eval_data->p); } break; case RULE_OPTION_TYPE_FLOWBIT: @@ -628,7 +578,7 @@ int detection_option_node_evaluate( flowbits_setoperation = FlowBits_SetOperation(node->option_data); if (!flowbits_setoperation) { - rval = node->evaluate(node->option_data, eval_data->p); + rval = node->evaluate(node->option_data, cursor, eval_data->p); } else { @@ -639,7 +589,7 @@ int detection_option_node_evaluate( break; default: if (node->evaluate) - rval = node->evaluate(node->option_data, eval_data->p); + rval = node->evaluate(node->option_data, cursor, eval_data->p); break; } @@ -700,18 +650,12 @@ int detection_option_node_evaluate( /* Passed, check the children. */ if (node->num_children) { - const uint8_t *tmp_doe_ptr = doe_ptr; - const uint8_t tmp_doe_flags = doe_buf_flags; - for (i=0;inum_children; i++) { int j = 0; detection_option_tree_node_t *child_node = node->children[i]; dot_node_state_t* child_state = child_node->state + get_instance_id(); - /* reset the DOE ptr for each child from here */ - SetDoePtr(tmp_doe_ptr, tmp_doe_flags); - for (j = 0; j < NUM_BYTE_EXTRACT_VARS; j++) { SetByteExtractValue(tmp_byte_extract_vars[j], (int8_t)j); @@ -762,7 +706,9 @@ int detection_option_node_evaluate( } } - child_state->result = detection_option_node_evaluate(node->children[i], eval_data); + child_state->result = detection_option_node_evaluate( + node->children[i], eval_data, cursor); + if (child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE) { /* Leaf node won't have any children but will return success @@ -798,8 +744,6 @@ int detection_option_node_evaluate( * rule option */ if (result == node->num_children) continue_loop = 0; - else - SetDoePtr(tmp_doe_ptr, tmp_doe_flags); /* Don't need to reset since it's only checked after we've gone * through the loop at least once and the result will have @@ -808,16 +752,19 @@ int detection_option_node_evaluate( // node->children[i]->result; } +#if 0 + // FIXIT replace is broken now :( if (result - prior_result > 0 && node->option_type == RULE_OPTION_TYPE_CONTENT - && Replace_OffsetStored(&dup_content_option_data) && ScInlineMode()) + && Replace_OffsetStored(content_data) && ScInlineMode()) { // FIXIT queuing replacements here is premature // should be done if / when rule actually fires // and at that point, the change can be applied - Replace_QueueChange(&dup_content_option_data); + Replace_QueueChange(content_data); prior_result = result; } +#endif NODE_PROFILE_TMPSTART(node); @@ -832,41 +779,11 @@ int detection_option_node_evaluate( if ((node->option_type == RULE_OPTION_TYPE_CONTENT) || (node->option_type == RULE_OPTION_TYPE_CONTENT_URI)) { - if (dup_content_option_data.exception_flag) - { - continue_loop = 0; - } - else - { - const uint8_t *orig_ptr; - - if (dup_content_option_data.use_doe) - orig_ptr = (orig_doe_ptr == NULL) ? dp : orig_doe_ptr; - else - orig_ptr = dp; - - continue_loop = PatternMatchAdjustRelativeOffsets( - node->option_data, &dup_content_option_data, - doe_ptr, orig_ptr); - } + continue_loop = content_next(content_data); } else if (node->option_type == RULE_OPTION_TYPE_PCRE) { - if (dup_pcre_option_data.options & SNORT_PCRE_INVERT) - { - continue_loop = 0; - } - else - { - const uint8_t *orig_ptr; - - if (dup_pcre_option_data.options & SNORT_PCRE_RELATIVE) - orig_ptr = (orig_doe_ptr == NULL) ? dp : orig_doe_ptr; - else - orig_ptr = dp; - - continue_loop = PcreAdjustRelativeOffsets(&dup_pcre_option_data, doe_ptr - orig_ptr); - } + continue_loop = pcre_next(pcre_data); } else { @@ -887,16 +804,13 @@ int detection_option_node_evaluate( loop_count++; - if (continue_loop) - UpdateDoePtr(orig_doe_ptr, 0); - } while (continue_loop); if (flowbits_setoperation && (result == DETECTION_OPTION_MATCH)) { /* Do any setting/clearing/resetting/toggling of flowbits here * given that other rule options matched. */ - rval = node->evaluate(node->option_data, eval_data->p); + rval = node->evaluate(node->option_data, cursor, eval_data->p); if (rval != DETECTION_OPTION_MATCH) { result = rval; diff --git a/src/detection/detection_options.h b/src/detection/detection_options.h index 59f3100ed..cf92e3717 100644 --- a/src/detection/detection_options.h +++ b/src/detection/detection_options.h @@ -45,7 +45,7 @@ #include "detection/detection_defines.h" #include "hash/sfhashfcn.h" -typedef int (*eval_func_t)(void *option_data, Packet *p); +typedef int (*eval_func_t)(void* option_data, struct Cursor&, Packet*); struct dot_node_state_t { @@ -117,7 +117,9 @@ int add_detection_option( int add_detection_option_tree( struct SnortConfig*, detection_option_tree_node_t *option_tree, void **existing_data); -int detection_option_node_evaluate(detection_option_tree_node_t *node, detection_option_eval_data_t *eval_data); +int detection_option_node_evaluate( + detection_option_tree_node_t *node, detection_option_eval_data_t *eval_data, struct Cursor&); + void DetectionHashTableFree(SFXHASH *); void DetectionTreeHashTableFree(SFXHASH *); #ifdef DEBUG_OPTION_TREE diff --git a/src/detection/detection_util.h b/src/detection/detection_util.h index 6713c45de..b68ffc53a 100644 --- a/src/detection/detection_util.h +++ b/src/detection/detection_util.h @@ -63,43 +63,31 @@ typedef enum } HTTP_BUFFER; #endif -typedef enum { +enum DetectFlagType +{ FLAG_ALT_DECODE = 0x0001, FLAG_ALT_DETECT = 0x0002, FLAG_DETECT_ALL = 0xffff -} DetectFlagType; - -#define DOE_BUF_URI 0x01 -#define DOE_BUF_STD 0x02 - -#define HTTPURI_PIPELINE_REQ 0x01 +}; -#define HTTP_ENCODE_TYPE__UTF8_UNICODE 0x00000001 -#define HTTP_ENCODE_TYPE__DOUBLE_ENCODE 0x00000002 -#define HTTP_ENCODE_TYPE__NONASCII 0x00000004 -#define HTTP_ENCODE_TYPE__BASE36 0x00000008 -#define HTTP_ENCODE_TYPE__UENCODE 0x00000010 -#define HTTP_ENCODE_TYPE__BARE_BYTE 0x00000020 -#define HTTP_ENCODE_TYPE__IIS_UNICODE 0x00000040 -#define HTTP_ENCODE_TYPE__ASCII 0x00000080 - -typedef struct +struct HttpBuffer { const uint8_t* buf; uint16_t length; uint32_t encode_type; -} HttpBuffer; +}; -typedef struct { +struct DataPointer +{ uint8_t *data; uint16_t len; -} DataPointer; +}; - -typedef struct { +struct DataBuffer +{ uint8_t data[DECODE_BLEN]; uint16_t len; -} DataBuffer; +}; extern THREAD_LOCAL uint8_t base64_decode_buf[DECODE_BLEN]; extern THREAD_LOCAL uint32_t base64_decode_size; @@ -179,74 +167,6 @@ static inline void setFileDataPtr(uint8_t *ptr, uint16_t decode_size) file_data_ptr.len = decode_size; } -/* - * Function: IsBase64DecodeBuf - * - * Purpose: Checks if there is base64 decoded buffer. - * - * Arguments: p => doe_ptr - * - * Returns: Returns 1 if there is base64 decoded data - * and if the doe_ptr is within the buffer. - * Returns 0 otherwise. - * - */ - -static inline int IsBase64DecodeBuf(const uint8_t *p) -{ - if( base64_decode_size && p ) - { - if ((p >= base64_decode_buf) && - (p < (base64_decode_buf + base64_decode_size))) - { - return 1; - } - else - return 0; - } - else - return 0; -} - -/* - * Function: SetDoePtr(const uint8_t *ptr, uint8_t type) - * - * Purpose: This function set the doe_ptr and sets the type of - * buffer to which doe_ptr points. - * - * Arguments: ptr => pointer - * type => type of buffer - * - * Returns: void - * -*/ - -static inline void SetDoePtr(const uint8_t *ptr, uint8_t type) -{ - doe_ptr = ptr; - doe_buf_flags = type; -} - -/* - * Function: UpdateDoePtr(const uint8_t *ptr, uint8_t update) - * - * Purpose: This function updates the doe_ptr and resets the type of - * buffer to which doe_ptr points based on the update value. - * - * Arguments: ptr => pointer - * update => reset the buf flag if update is not zero. - * - * Returns: void - * -*/ - -static inline void UpdateDoePtr(const uint8_t *ptr, uint8_t update) -{ - doe_ptr = ptr; - if(update) - doe_buf_flags = DOE_BUF_STD; -} - void EventTrace_Init(void); void EventTrace_Term(void); diff --git a/src/detection/fpcreate.cc b/src/detection/fpcreate.cc index fe19a5d1c..1b47605f7 100644 --- a/src/detection/fpcreate.cc +++ b/src/detection/fpcreate.cc @@ -875,10 +875,6 @@ static inline int IsPmdFpEligible(PatternMatchData *content) if ((content->pattern_buf != NULL) && (content->pattern_size != 0)) { - /* We don't add cookie and some other contents to fast pattern matcher */ - if(content->http_buffer && !IsHttpBufFpEligible(content->http_buffer)) - return 0; - if (content->exception_flag) { /* Negative contents can only be considered if they are not relative @@ -889,7 +885,7 @@ static inline int IsPmdFpEligible(PatternMatchData *content) * Also case sensitive patterns cannot be considered since patterns * are inserted into the pattern matcher without case which may * lead to false negatives */ - if (content->use_doe || !content->nocase + if (content->use_doe || !content->no_case || (content->offset != 0) || (content->depth != 0)) { return 0; @@ -1061,7 +1057,7 @@ static int fpFinishPortGroupRule( sc, pattern, pattern_length, - pmd->nocase, + pmd->no_case, pmd->offset, pmd->depth, (unsigned)pmd->exception_flag, @@ -1169,6 +1165,8 @@ static int fpAllocPms( return 0; } +#if 0 +// FIXIT fast_pattern static PmType GetPmType (HTTP_BUFFER hb_type) { switch ( hb_type ) @@ -1187,12 +1185,12 @@ static PmType GetPmType (HTTP_BUFFER hb_type) } return PM_TYPE__CONTENT; } +#endif static int fpAddPortGroupRule( SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, FastPatternConfig *fp) { PatternMatchData *pmd = NULL; - PatternMatchData *pmd_uri = NULL; if ((pg == NULL) || (otn == NULL)) return -1; @@ -1218,6 +1216,8 @@ static int fpAddPortGroupRule( } } +#if 0 + FIXIT need to select http_uri for fast_pattern /* http buffer contents take precedence over normal contents if * no normal contents have the fast_pattern option */ pmd_uri = GetLongestPmdContent(otn, CONTENT_HTTP); @@ -1233,6 +1233,7 @@ static int fpAddPortGroupRule( return 0; } } +#endif /* If we get this far then no URI contents were added */ diff --git a/src/detection/fpdetect.cc b/src/detection/fpdetect.cc index e42699b6d..685718bd2 100644 --- a/src/detection/fpdetect.cc +++ b/src/detection/fpdetect.cc @@ -51,6 +51,7 @@ #include "treenodes.h" #include "pcrm.h" #include "fpcreate.h" +#include "framework/cursor.h" #include "framework/mpse.h" #include "bitop.h" #include "perf_monitor/perf.h" @@ -446,13 +447,12 @@ static int detection_option_tree_evaluate( } #endif + Cursor c(eval_data->p); + for ( i = 0; i< root->num_children; i++) { - /* New tree, reset doe_ptr for safety */ - UpdateDoePtr(NULL, 0); - /* Increment number of events generated from that child */ - rval += detection_option_node_evaluate(root->children[i], eval_data); + rval += detection_option_node_evaluate(root->children[i], eval_data, c); } #ifdef PPM_MGR diff --git a/src/detection/rule_option_types.h b/src/detection/rule_option_types.h index 167bb1406..10fd41c51 100644 --- a/src/detection/rule_option_types.h +++ b/src/detection/rule_option_types.h @@ -40,4 +40,5 @@ typedef enum _option_type_t RULE_OPTION_TYPE_OTHER } option_type_t; -#endif /* RULE_OPTION_TYPES_H */ +#endif + diff --git a/src/detection/treenodes.h b/src/detection/treenodes.h index 21de6849d..d40855550 100644 --- a/src/detection/treenodes.h +++ b/src/detection/treenodes.h @@ -43,7 +43,7 @@ struct OptFpList /* context data for this test */ void *context; - int (*OptTestFunc)(void *option_data, Packet *p); + int (*OptTestFunc)(void* option_data, struct Cursor&, Packet*); OptFpList *next; @@ -155,7 +155,7 @@ struct RuleTreeNode unsigned int otnRefCount; }; -typedef int (*RuleOptEvalFunc)(void *, Packet *); +typedef int (*RuleOptEvalFunc)(void*, Cursor&, Packet*); OptFpList * AddOptFuncToList(RuleOptEvalFunc, OptTreeNode *); void* get_rule_type_data(OptTreeNode*, option_type_t); diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index e289027a7..5ea8a8149 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -4,7 +4,7 @@ set (FRAMEWORK_INCLUDES base_api.h bits.h codec.h - content_buffer.h + cursor.h logger.h inspector.h ips_option.h @@ -19,6 +19,7 @@ set (FRAMEWORK_INCLUDES add_library ( framework STATIC ${FRAMEWORK_INCLUDES} + cursor.cc inspector.cc ips_option.cc parameter.cc diff --git a/src/framework/Makefile.am b/src/framework/Makefile.am index 23a697bb9..ee5871a60 100644 --- a/src/framework/Makefile.am +++ b/src/framework/Makefile.am @@ -8,7 +8,7 @@ x_include_HEADERS = \ base_api.h \ bits.h \ codec.h \ -content_buffer.h \ +cursor.h \ logger.h \ inspector.h \ ips_option.h \ @@ -21,6 +21,7 @@ so_rule.h \ value.h libframework_a_SOURCES = \ +cursor.cc \ inspector.cc \ ips_option.cc \ parameter.cc \ diff --git a/src/framework/cursor.cc b/src/framework/cursor.cc new file mode 100644 index 000000000..74f6dbdc9 --- /dev/null +++ b/src/framework/cursor.cc @@ -0,0 +1,59 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** +** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +// cursor.cc author Russ Combs + +#include "cursor.h" +#include "detection/detection_util.h" +#include "protocols/packet.h" + +Cursor::Cursor(Packet* p) +{ + reset(p); +} + +Cursor::Cursor(const Cursor& rhs) +{ + *this = rhs; + delta = 0; +} + +void Cursor::reset(Packet* p) +{ + /* If AltDetect is set by calling the rule options which set it, + * we should use the Alt Detect before checking for any other buffers. + * Alt Detect will take precedence over the Alt Decode and/or packet data. + */ + if ( Is_DetectFlag(FLAG_ALT_DETECT) ) + { + set("pkt_data", (uint8_t *)DetectBuffer.data, DetectBuffer.len); + } + else if ( Is_DetectFlag(FLAG_ALT_DECODE) ) + { + set("pkt_data", (uint8_t *)DecodeBuffer.data, DecodeBuffer.len); + } + else if( IsLimitedDetect(p) ) + { + set("pkt_data", p->data, p->alt_dsize); + } + else + { + set("pkt_data", p->data, p->dsize); + } +} + diff --git a/src/framework/cursor.h b/src/framework/cursor.h new file mode 100644 index 000000000..1bb43de91 --- /dev/null +++ b/src/framework/cursor.h @@ -0,0 +1,99 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2002-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +// cursor.h author Russ Combs + +#ifndef CURSOR_H +#define CURSOR_H + +#include +#include +#include + +struct Packet; + +class Cursor +{ +public: + Cursor(Packet*); + Cursor(const Cursor&); + + bool is(const char* s) + { return !strcmp(name, s); }; + + void reset(Packet*); + + void set(const char* s, const uint8_t* b, unsigned n) + { name = s; data = b; sz = n; pos = delta = 0; }; + + const uint8_t* buffer() + { return data; }; + + unsigned size() + { return sz; }; + + const uint8_t* start() + { return data + pos; }; + + unsigned length() + { return sz - pos; }; + + unsigned get_pos() + { return pos; }; + + unsigned get_delta() + { return delta; }; + + bool add_pos(unsigned n) + { + if (pos + n > sz) + return false; + pos += n; + return true; + }; + + // pos and delta may go 1 byte after end + bool set_pos(unsigned n) + { + if (n > sz) + return false; + pos = n; + return true; + }; + + bool set_delta(unsigned n) + { + if (n > sz) + return false; + delta = n; + return true; + }; + +private: + const char* name; // rule option name ("pkt_data", "http_uri", etc.) + const uint8_t* data; // start of buffer + unsigned sz; // size of buffer + unsigned pos; // current pos + unsigned delta; // loop offset + +}; + +#endif + diff --git a/src/framework/inspector.h b/src/framework/inspector.h index 478df8c30..e397322bc 100644 --- a/src/framework/inspector.h +++ b/src/framework/inspector.h @@ -109,7 +109,6 @@ typedef Inspector* (*InspectNew)(Module*); typedef void (*InspectDelFunc)(Inspector*); typedef void (*InspectFunc)(); typedef class Session* (*InspectSsnFunc)(class Flow*); -typedef struct ContentBuffer* (*InspectBufFunc)(unsigned); // FIXIT ensure all provide stats struct InspectApi @@ -121,9 +120,6 @@ struct InspectApi const char* service; // nullptr when type != IT_SERVICE //ServiceTag tags; // null terminated list of tags - // list of thread local detection buffers captured by inspector - const char* contents; // space separated, eg "foo_a foo_b foo_c" - // main thread funcs - parse time data only InspectFunc init; // allocate process static data InspectFunc term; // release init() data @@ -137,7 +133,6 @@ struct InspectApi InspectFunc sum; // accumulate stats InspectFunc stats; // output stats InspectFunc reset; // clear stats - InspectBufFunc getbuf; // 0-based, eg getbuf(1) means foo_b above }; #endif diff --git a/src/framework/ips_option.h b/src/framework/ips_option.h index d02ec2be3..567642230 100644 --- a/src/framework/ips_option.h +++ b/src/framework/ips_option.h @@ -56,7 +56,7 @@ public: // packet threads virtual void config(SnortConfig*) { }; virtual bool is_relative() { return false; }; - virtual int eval(Packet*) { return true; }; + virtual int eval(struct Cursor&, Packet*) { return true; }; virtual void action(Packet*) { }; option_type_t get_type() const { return type; }; @@ -103,10 +103,10 @@ struct IpsApi IpsChkFunc verify; }; -static inline int ips_option_eval(void* v, Packet* p) +static inline int ips_option_eval(void* v, Cursor& c, Packet* p) { IpsOption* opt = (IpsOption*)v; - return opt->eval(p); + return opt->eval(c, p); } #endif diff --git a/src/ips_options/CMakeLists.txt b/src/ips_options/CMakeLists.txt index 26b0e68cd..24fe71113 100644 --- a/src/ips_options/CMakeLists.txt +++ b/src/ips_options/CMakeLists.txt @@ -23,6 +23,7 @@ SET( PLUGIN_LIST ips_isdataat.cc ips_itype.cc ips_pkt_data.cc + ips_raw_data.cc ips_react.cc ips_resp.cc ips_rpc.cc @@ -57,9 +58,9 @@ set (IPS_SOURCES ips_options.h ips_pcre.cc ips_pcre.h + ips_replace.cc + ips_replace.h ips_so.cc - replace.cc - replace.h ) @@ -94,6 +95,7 @@ else (STATIC_IPS_OPTIONS) add_shared_library(ips_isdataat ips_options ips_isdataat.cc) add_shared_library(ips_itype ips_options ips_itype.cc) add_shared_library(ips_pkt_data ips_options ips_pkt_data.cc) + add_shared_library(ips_raw_data ips_options ips_raw_data.cc) add_shared_library(ips_react ips_options ips_react.cc) add_shared_library(ips_resp ips_options ips_resp.cc) add_shared_library(ips_rpc ips_options ips_rpc.cc) diff --git a/src/ips_options/Makefile.am b/src/ips_options/Makefile.am index be835d84e..2f50097ed 100644 --- a/src/ips_options/Makefile.am +++ b/src/ips_options/Makefile.am @@ -24,6 +24,7 @@ ips_ipopts.cc \ ips_isdataat.cc \ ips_itype.cc \ ips_pkt_data.cc \ +ips_raw_data.cc \ ips_react.cc \ ips_resp.cc \ ips_rpc.cc \ @@ -46,8 +47,8 @@ ips_ip_proto.cc ips_ip_proto.h \ ips_luajit.cc ips_luajit.h \ ips_options.cc ips_options.h \ ips_pcre.cc ips_pcre.h \ -ips_so.cc \ -replace.cc replace.h +ips_replace.cc ips_replace.h \ +ips_so.cc if STATIC_IPS_OPTIONS libips_options_a_SOURCES += $(plugin_list) @@ -149,6 +150,11 @@ libips_pkt_data_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO libips_pkt_data_la_LDFLAGS = -export-dynamic -shared libips_pkt_data_la_SOURCES = ips_pkt_data.cc +optlib_LTLIBRARIES += libips_raw_data.la +libips_raw_data_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO +libips_raw_data_la_LDFLAGS = -export-dynamic -shared +libips_raw_data_la_SOURCES = ips_raw_data.cc + optlib_LTLIBRARIES += libips_react.la libips_react_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO libips_react_la_LDFLAGS = -export-dynamic -shared diff --git a/src/ips_options/ips_ack.cc b/src/ips_options/ips_ack.cc index d88f7e638..d9ef2a367 100644 --- a/src/ips_options/ips_ack.cc +++ b/src/ips_options/ips_ack.cc @@ -69,7 +69,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: TcpAckCheckData config; @@ -111,7 +111,7 @@ bool TcpAckOption::operator==(const IpsOption& ips) const return false; } -int TcpAckOption::eval(Packet *p) +int TcpAckOption::eval(Cursor&, Packet *p) { TcpAckCheckData *ackCheckData = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_asn1.cc b/src/ips_options/ips_asn1.cc index 191d13c62..758f75967 100644 --- a/src/ips_options/ips_asn1.cc +++ b/src/ips_options/ips_asn1.cc @@ -115,7 +115,7 @@ public: bool is_relative() { return ( config.offset_type == REL_OFFSET ); }; - int eval(Packet*); + int eval(Cursor&, Packet*); private: ASN1_CTXT config; @@ -174,7 +174,7 @@ bool Asn1Option::operator==(const IpsOption& rhs) const return false; } -int Asn1Option::eval(Packet *p) +int Asn1Option::eval(Cursor&, Packet *p) { PROFILE_VARS; diff --git a/src/ips_options/ips_base64_data.cc b/src/ips_options/ips_base64_data.cc index a890ef244..0e4381c5a 100644 --- a/src/ips_options/ips_base64_data.cc +++ b/src/ips_options/ips_base64_data.cc @@ -43,6 +43,7 @@ #include "fpdetect.h" #include "detection/detection_defines.h" #include "detection/detection_util.h" +#include "framework/cursor.h" #include "framework/ips_option.h" #ifdef PERF_PROFILING @@ -64,10 +65,10 @@ class Base64DataOption : public IpsOption public: Base64DataOption() : IpsOption(s_name, RULE_OPTION_TYPE_BASE64_DATA) { }; - int eval(Packet*); + int eval(Cursor&, Packet*); }; -int Base64DataOption::eval(Packet *p) +int Base64DataOption::eval(Cursor& c, Packet *p) { int rval = DETECTION_OPTION_NO_MATCH; PROFILE_VARS; @@ -80,8 +81,7 @@ int Base64DataOption::eval(Packet *p) return rval; } - SetDoePtr(base64_decode_buf, DOE_BUF_STD); - SetAltDetect(base64_decode_buf, (uint16_t)base64_decode_size); + c.set(s_name, base64_decode_buf, base64_decode_size); rval = DETECTION_OPTION_MATCH; PREPROC_PROFILE_END(base64DataPerfStats); diff --git a/src/ips_options/ips_base64_decode.cc b/src/ips_options/ips_base64_decode.cc index f6b3183a4..82b9fc60b 100644 --- a/src/ips_options/ips_base64_decode.cc +++ b/src/ips_options/ips_base64_decode.cc @@ -81,7 +81,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: Base64DecodeData config; @@ -126,7 +126,7 @@ bool Base64DecodeOption::operator==(const IpsOption& ips) const return false; } -int Base64DecodeOption::eval(Packet *p) +int Base64DecodeOption::eval(Cursor&, Packet *p) { int rval = DETECTION_OPTION_NO_MATCH; const uint8_t *start_ptr = NULL; diff --git a/src/ips_options/ips_byte_extract.cc b/src/ips_options/ips_byte_extract.cc index a385a79ef..f2b78ecae 100644 --- a/src/ips_options/ips_byte_extract.cc +++ b/src/ips_options/ips_byte_extract.cc @@ -35,6 +35,7 @@ #include "extract.h" #include "fpdetect.h" #include "framework/ips_option.h" +#include "framework/cursor.h" #ifdef PERF_PROFILING static THREAD_LOCAL PreprocStats byteExtractPerfStats; @@ -91,7 +92,7 @@ public: bool is_relative() { return (config.relative_flag == 1); }; - int eval(Packet*); + int eval(Cursor&, Packet*); private: ByteExtractData config; @@ -152,15 +153,13 @@ bool ByteExtractOption::operator==(const IpsOption& ips) const return false; } -int ByteExtractOption::eval(Packet *p) +int ByteExtractOption::eval(Cursor& c, Packet *p) { ByteExtractData *data = &config; - int ret, bytes_read, dsize; - const uint8_t *ptr, *start, *end; + int ret, bytes_read; uint32_t *value; - uint8_t rst_doe_flags = 1; - PROFILE_VARS; + PROFILE_VARS; PREPROC_PROFILE_START(byteExtractPerfStats); if (data == NULL || p == NULL) @@ -169,36 +168,13 @@ int ByteExtractOption::eval(Packet *p) return DETECTION_OPTION_NO_MATCH; } - /* setup our fun pointers */ - if (Is_DetectFlag(FLAG_ALT_DETECT)) - { - dsize = DetectBuffer.len; - start = DetectBuffer.data; - } - else if (Is_DetectFlag(FLAG_ALT_DECODE)) - { - dsize = DecodeBuffer.len; - start = DecodeBuffer.data; - } - else - { - if(IsLimitedDetect(p)) - dsize = p->alt_dsize; - else - dsize = p->dsize; - start = p->data; - } - - if (data->relative_flag) - { - ptr = doe_ptr; - rst_doe_flags = 0; - } - else - ptr = start; + const uint8_t* start = c.buffer(); + int dsize = c.size(); + const uint8_t* ptr = data->relative_flag ? c.start() : c.buffer(); ptr += data->offset; - end = start + dsize; + + const uint8_t* end = start + dsize; value = &(extracted_values[data->var_number]); /* check bounds */ @@ -244,7 +220,7 @@ int ByteExtractOption::eval(Packet *p) } /* push doe_ptr */ - UpdateDoePtr((ptr + bytes_read), rst_doe_flags); + c.add_pos(bytes_read); /* this rule option always "matches" if the read is performed correctly */ PREPROC_PROFILE_END(byteExtractPerfStats); diff --git a/src/ips_options/ips_byte_jump.cc b/src/ips_options/ips_byte_jump.cc index 93000ed53..5a63c750e 100644 --- a/src/ips_options/ips_byte_jump.cc +++ b/src/ips_options/ips_byte_jump.cc @@ -89,6 +89,7 @@ #include "sfhashfcn.h" #include "detection/detection_defines.h" #include "detection/detection_util.h" +#include "framework/cursor.h" #include "framework/ips_option.h" #ifdef PERF_PROFILING @@ -135,7 +136,7 @@ public: bool is_relative() { return (config.relative_flag == 1); }; - int eval(Packet*); + int eval(Cursor&, Packet*); private: ByteJumpData config; @@ -203,102 +204,52 @@ bool ByteJumpOption::operator==(const IpsOption& ips) const return false; } -int ByteJumpOption::eval(Packet *p) +int ByteJumpOption::eval(Cursor& c, Packet*) { ByteJumpData *bjd = (ByteJumpData *)&config; int rval = DETECTION_OPTION_NO_MATCH; - uint32_t value = 0; - uint32_t jump_value = 0; + uint32_t jump = 0; uint32_t payload_bytes_grabbed = 0; uint32_t extract_offset; - int32_t tmp = 0; - int dsize; - const uint8_t *base_ptr, *end_ptr, *start_ptr; - uint8_t rst_doe_flags = 1; - PROFILE_VARS; + int32_t offset; + PROFILE_VARS; PREPROC_PROFILE_START(byteJumpPerfStats); - if (Is_DetectFlag(FLAG_ALT_DETECT)) - { - dsize = DetectBuffer.len; - start_ptr = DetectBuffer.data; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Using Alternative Detect buffer!\n");); - } - else if(Is_DetectFlag(FLAG_ALT_DECODE)) - { - dsize = DecodeBuffer.len; - start_ptr = DecodeBuffer.data; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Using Alternative Decode buffer!\n");); - } - else - { - start_ptr = p->data; - if(IsLimitedDetect(p)) - dsize = p->alt_dsize; - else - dsize = p->dsize; - } - - DEBUG_WRAP( - DebugMessage(DEBUG_PATTERN_MATCH,"[*] byte jump firing...\n"); - DebugMessage(DEBUG_PATTERN_MATCH,"payload starts at %p\n", start_ptr); - ); /* END DEBUG_WRAP */ - - /* save off whatever our ending pointer is */ - end_ptr = start_ptr + dsize; - //base_ptr = start_ptr; + const uint8_t *base_ptr, *end_ptr, *start_ptr; + int dsize; /* Get values from byte_extract variables, if present. */ if (bjd->offset_var >= 0 && bjd->offset_var < NUM_BYTE_EXTRACT_VARS) { GetByteExtractValue(&extract_offset, bjd->offset_var); - bjd->offset = (int32_t) extract_offset; + offset = (int32_t) extract_offset; } + else + offset = bjd->offset; - if(bjd->relative_flag && doe_ptr) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Checking relative offset!\n");); - - /* @todo: possibly degrade to use the other buffer, seems non-intuitive - * Because doe_ptr can be "end" in the last match, - * use end + 1 for upper bound - * Bound checked also after offset is applied - * (see byte_extract() and string_extract()) - */ - if(!inBounds(start_ptr, end_ptr + 1, doe_ptr)) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "[*] byte jump bounds check failed..\n");); - - PREPROC_PROFILE_END(byteJumpPerfStats); - return rval; - } + start_ptr = c.buffer(); + dsize = c.size(); + end_ptr = start_ptr + dsize; - base_ptr = doe_ptr + bjd->offset; - rst_doe_flags = 0; + if( bjd->relative_flag ) + { + base_ptr = c.start() + offset; } else { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "checking absolute offset %d\n", bjd->offset);); - base_ptr = start_ptr + bjd->offset; + base_ptr = c.buffer() + offset; } - /* Both of the extraction functions contain checks to insure the data + /* Both of the extraction functions contain checks to ensure the data * is always inbounds */ - if(!bjd->data_string_convert_flag) + if ( !bjd->data_string_convert_flag ) { - if(byte_extract(bjd->endianess, bjd->bytes_to_grab, - base_ptr, start_ptr, end_ptr, &value)) + if ( byte_extract( + bjd->endianess, bjd->bytes_to_grab, + base_ptr, start_ptr, end_ptr, &jump) ) { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Byte Extraction Failed\n");); - PREPROC_PROFILE_END(byteJumpPerfStats); return rval; } @@ -307,76 +258,39 @@ int ByteJumpOption::eval(Packet *p) } else { - payload_bytes_grabbed = tmp = string_extract(bjd->bytes_to_grab, bjd->base, - base_ptr, start_ptr, end_ptr, &value); + int32_t tmp = string_extract( + bjd->bytes_to_grab, bjd->base, + base_ptr, start_ptr, end_ptr, &jump); + if (tmp < 0) { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Byte Extraction Failed\n");); - PREPROC_PROFILE_END(byteJumpPerfStats); return rval; } - + payload_bytes_grabbed = tmp; } - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "grabbed %d of %d bytes, value = %08X\n", - payload_bytes_grabbed, bjd->bytes_to_grab, value);); - - /* Adjust the jump_value (# bytes to jump forward) with the multiplier. */ if (bjd->multiplier) - jump_value = value * bjd->multiplier; - else - jump_value = value; - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "grabbed %d of %d bytes, after multiplier value = %08X\n", - payload_bytes_grabbed, bjd->bytes_to_grab, jump_value);); - + jump *= bjd->multiplier; /* if we need to align on 32-bit boundries, round up to the next * 32-bit value */ if(bjd->align_flag) { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "offset currently at %d\n", jump_value);); - if ((jump_value % 4) != 0) + if ((jump % 4) != 0) { - jump_value += (4 - (jump_value % 4)); + jump += (4 - (jump % 4)); } - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "offset aligned to %d\n", jump_value);); } - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Grabbed %d bytes at offset %d, value = 0x%08X\n", - payload_bytes_grabbed, bjd->offset, jump_value);); - - if(bjd->from_beginning_flag) - { - /* Reset base_ptr if from_beginning */ - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "jumping from beginning %d bytes\n", jump_value);); - base_ptr = start_ptr; - - /* from base, push doe_ptr ahead "value" number of bytes */ - SetDoePtr((base_ptr + jump_value), DOE_BUF_STD); - - } - else - { - UpdateDoePtr((base_ptr + payload_bytes_grabbed + jump_value), rst_doe_flags); - } + if ( !bjd->from_beginning_flag ) + jump += payload_bytes_grabbed; - /* now adjust using post_offset -- before bounds checking */ - doe_ptr += bjd->post_offset; + jump += bjd->post_offset; - if(!inBounds(start_ptr, end_ptr, doe_ptr)) + if ( !c.set_pos(jump) ) { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "tmp ptr is not in bounds %p\n", doe_ptr);); PREPROC_PROFILE_END(byteJumpPerfStats); return rval; } diff --git a/src/ips_options/ips_byte_test.cc b/src/ips_options/ips_byte_test.cc index c196bb9c6..21d74c25e 100644 --- a/src/ips_options/ips_byte_test.cc +++ b/src/ips_options/ips_byte_test.cc @@ -185,7 +185,7 @@ public: bool is_relative() { return ( config.relative_flag == 1 ); }; - int eval(Packet*); + int eval(Cursor&, Packet*); private: ByteTestData config; @@ -252,7 +252,7 @@ bool ByteTestOption::operator==(const IpsOption& ips) const return false; } -int ByteTestOption::eval(Packet *p) +int ByteTestOption::eval(Cursor&, Packet *p) { ByteTestData *btd = (ByteTestData *)&config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_content.cc b/src/ips_options/ips_content.cc index 4ac446cc5..9b4ee7762 100644 --- a/src/ips_options/ips_content.cc +++ b/src/ips_options/ips_content.cc @@ -31,14 +31,15 @@ #endif #include "snort_types.h" -#include "replace.h" #include "snort_bounds.h" #include "detection/treenodes.h" #include "snort_debug.h" -#include "mstring.h" +#include "parser/mstring.h" +#include "utils/boyer_moore.h" #include "util.h" -#include "parser.h" +#include "parser/parser.h" #include "sfhashfcn.h" +#include "framework/cursor.h" #include "framework/ips_option.h" #include "snort.h" #include "profiler.h" @@ -53,22 +54,17 @@ #ifdef PERF_PROFILING static THREAD_LOCAL PreprocStats contentPerfStats; -static THREAD_LOCAL PreprocStats uricontentPerfStats; static PreprocStats* con_get_profile(const char* key) { if ( !strcmp(key, "content") ) return &contentPerfStats; - if ( !strcmp(key, "uricontent") ) - return &uricontentPerfStats; - return nullptr; } #endif -static int CheckANDPatternMatch(PatternMatchData*, Packet*); -static int CheckUriPatternMatch(PatternMatchData*, Packet*); +static int CheckANDPatternMatch(PatternMatchData*, Cursor&); class ContentOption : public IpsOption { @@ -92,23 +88,13 @@ public: void set_data(PatternMatchData* pmd) { config = pmd; }; - int eval(Packet* p) - { return CheckANDPatternMatch(config, p); }; + int eval(Cursor& c, Packet*) + { return CheckANDPatternMatch(config, c); }; protected: PatternMatchData* config; }; -class UriContentOption : public ContentOption -{ -public: - UriContentOption(PatternMatchData* c) : - ContentOption(c, "uricontent", RULE_OPTION_TYPE_CONTENT_URI) { }; - - int eval(Packet* p) - { return CheckUriPatternMatch(config, p); }; -}; - //------------------------------------------------------------------------- // class methods //------------------------------------------------------------------------- @@ -127,11 +113,6 @@ ContentOption::~ContentOption() if(pmd->shift_stride) free(pmd->shift_stride); - if (pmd->replace_buf) - free(pmd->replace_buf); - if ( pmd->replace_depth ) - free(pmd->replace_depth); - free(pmd->last_check); free(pmd); } @@ -147,30 +128,16 @@ uint32_t ContentOption::hash() const mix(a,b,c); - a += pmd->distance; - b += pmd->within; - c += pmd->rawbytes; - - mix(a,b,c); - - a += pmd->nocase; - b += pmd->use_doe; - c += pmd->http_buffer; - - mix(a,b,c); - a += pmd->pattern_size; - b += pmd->replace_size; - c += pmd->pattern_max_jump_size; + b += pmd->use_doe; + c += pmd->match_delta; mix(a,b,c); if ( pmd->pattern_size ) mix_str(a,b,c,pmd->pattern_buf, pmd->pattern_size); - if ( pmd->replace_size ) - mix_str(a,b,c,pmd->replace_buf, pmd->replace_size); - + a += pmd->no_case; b += pmd->fp; c += pmd->fp_only; @@ -184,8 +151,6 @@ uint32_t ContentOption::hash() const mix(a,b,c); a += pmd->depth_var; - b += pmd->distance_var; - c += pmd->within_var; final(a,b,c); @@ -202,21 +167,17 @@ bool ContentOption::operator==(const IpsOption& ips) const PatternMatchData *right = rhs.config; unsigned int i; - if (left->buffer_func != right->buffer_func) - return false; - /* Sizes will be most different, check that first */ if ((left->pattern_size != right->pattern_size) || - (left->replace_size != right->replace_size) || - (left->nocase != right->nocase)) + (left->no_case != right->no_case)) return false; /* Next compare the patterns for uniqueness */ if (left->pattern_size) { - if (left->nocase) + if (left->no_case) { - /* If nocase is set, do case insensitive compare on pattern */ + /* If no_case is set, do case insensitive compare on pattern */ for (i=0;ipattern_size;i++) { if (toupper(left->pattern_buf[i]) != toupper(right->pattern_buf[i])) @@ -227,7 +188,7 @@ bool ContentOption::operator==(const IpsOption& ips) const } else { - /* If nocase is not set, do case sensitive compare on pattern */ + /* If no_case is not set, do case sensitive compare on pattern */ if (memcmp(left->pattern_buf, right->pattern_buf, left->pattern_size) != 0) { return false; @@ -235,34 +196,18 @@ bool ContentOption::operator==(const IpsOption& ips) const } } - /* Check the replace pattern if exists */ - if (left->replace_size) - { - if (memcmp(left->replace_buf, right->replace_buf, left->replace_size) != 0) - { - return false; - } - } - /* Now check the rest of the options */ if ((left->exception_flag == right->exception_flag) && (left->offset == right->offset) && (left->depth == right->depth) && - (left->distance == right->distance) && - (left->within == right->within) && - (left->rawbytes == right->rawbytes) && (left->use_doe == right->use_doe) && - (left->http_buffer == right->http_buffer) && - (left->search == right->search) && - (left->pattern_max_jump_size == right->pattern_max_jump_size) && + (left->match_delta == right->match_delta) && (left->fp == right->fp) && (left->fp_only == right->fp_only) && (left->fp_offset == right->fp_offset) && (left->fp_length == right->fp_length) && (left->offset_var == right->offset_var) && - (left->depth_var == right->depth_var) && - (left->distance_var == right->distance_var) && - (left->within_var == right->within_var) ) + (left->depth_var == right->depth_var) ) { return true; } @@ -281,8 +226,6 @@ static PatternMatchData* new_pmd() /* Set any non-zero default values here. */ pmd->offset_var = BYTE_EXTRACT_NO_VAR; pmd->depth_var = BYTE_EXTRACT_NO_VAR; - pmd->distance_var = BYTE_EXTRACT_NO_VAR; - pmd->within_var = BYTE_EXTRACT_NO_VAR; return pmd; } @@ -331,82 +274,17 @@ static int32_t ParseInt(const char* data, const char* tag) return value; } -/* Options that can't be used with http content modifiers. Additionally - * http_inspect preprocessor needs to be enabled */ -static void ValidateHttpContentModifiers( - SnortConfig*, PatternMatchData *pmd) -{ - if (pmd == NULL) - ParseError("Please place 'content' rules before http content modifiers"); - -#if 0 - // FIXIT HI should make the content modifiers available and - // if not available parsing of the modifier should fail - if (!IsPreprocEnabled(sc, PP_HTTPINSPECT)) - { - ParseError("Please enable the HTTP Inspect preprocessor " - "before using the http content modifiers"); - } -#endif - - if (pmd->replace_buf != NULL) - { - ParseError("'replace' option is not supported in conjunction with " - "http content modifiers"); - } - - if (pmd->rawbytes == 1) - { - ParseError("Cannot use 'rawbytes' and http content as modifiers for " - "the same 'content'"); - } -} - -static void set_last_type(OptTreeNode *otn, option_type_t type) -{ - OptFpList* fpl = otn ? otn->opt_func : nullptr; - OptFpList* last = nullptr; - - while ( fpl ) - { - if ( (fpl->type == RULE_OPTION_TYPE_CONTENT) || - (fpl->type == RULE_OPTION_TYPE_CONTENT_URI) ) - { - last = fpl; - } - fpl = fpl->next; - } - if ( last ) - last->type = type; -} - -/* This is used if we get an http content modifier, since specifying "content" - * defaults to the RULE_OPTION_TYPE_CONTENT list. We need to move the pmd to the - * RULE_OPTION_TYPE_CONTENT_URI list */ -static void MovePmdToUriDsList(OptTreeNode *otn, PatternMatchData *pmd) -{ - set_last_type(otn, RULE_OPTION_TYPE_CONTENT_URI); // FIXIT make this unnecessary - pmd->buffer_func = CHECK_URI_PATTERN_MATCH; -} - +// FIXIT the following comment is no longer true; /* Since each content modifier can be parsed as a rule option, do this check * after parsing the entire rule in FinalizeContentUniqueness() */ static void ValidateContent( - SnortConfig* sc, PatternMatchData *pmd, int type){ + SnortConfig*, PatternMatchData *pmd, int) +{ if (pmd == NULL) return; if (pmd->fp) { - if ((type == RULE_OPTION_TYPE_CONTENT_URI) && !IsHttpBufFpEligible(pmd->http_buffer)) - - { - ParseError( - "Cannot use the fast_pattern content modifier for a lone " - "http cookie/http raw uri /http raw header /http raw cookie " - "/status code / status msg /http method buffer content."); - } - if (pmd->use_doe || (pmd->offset != 0) || (pmd->depth != 0)) { if (pmd->exception_flag) @@ -426,19 +304,10 @@ static void ValidateContent( if (pmd->fp_only) { - if (pmd->replace_buf != NULL) - { - ParseError( - "Fast pattern only contents cannot use replace modifier."); - } - if (pmd->exception_flag) ParseError("Fast pattern only contents cannot be negated."); } } - - if (type == RULE_OPTION_TYPE_CONTENT_URI) - ValidateHttpContentModifiers(sc, pmd); } static void make_precomp(PatternMatchData * idx) @@ -528,8 +397,7 @@ static unsigned int GetMaxJumpSize(char *data, int data_len) PatternMatchData* get_pmd(OptFpList* ofl) { - if ( (ofl->type != RULE_OPTION_TYPE_CONTENT) && - (ofl->type != RULE_OPTION_TYPE_CONTENT_URI) ) + if ( ofl->type != RULE_OPTION_TYPE_CONTENT ) return nullptr; ContentOption* opt = (ContentOption*)ofl->context; @@ -550,7 +418,7 @@ bool is_unbounded(void* pv) { ContentOption* opt = (ContentOption*)pv; PatternMatchData* pmd = opt->get_data(); - return ( pmd->within == 0 ); + return ( pmd->depth == 0 ); } //------------------------------------------------------------------------- @@ -560,266 +428,99 @@ bool is_unbounded(void* pv) /* * single search function. * - * data = ptr to buffer to search - * dlen = distance to the back of the buffer being tested, validated - * against offset + depth before function entry (not distance/within) - * pmd = pointer to pattern match data struct - * nocase = 0 means case sensitve, 1 means case insensitive - * * return 1 for found * return 0 for not found * return -1 for error (search out of bounds) */ -// FIXIT PMD -static int uniSearchReal(const char *data, int dlen, PatternMatchData *pmd, int nocase) +static int uniSearchReal(PatternMatchData* pmd, Cursor& c) { - /* - * in theory computeDepth doesn't need to be called because the - * depth + offset adjustments have been made by the calling function - */ - int depth = dlen; - int success = 0; - const char *start_ptr = data; - const char *end_ptr = data + dlen; - const char *base_ptr;// = start_ptr; - uint32_t extract_offset, extract_depth, extract_distance, extract_within; - - if(pmd->use_doe != 1) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "NOT Using Doe Ptr\n");); - UpdateDoePtr(NULL, 0); /* get rid of all our pattern match state */ - } + int offset, depth; /* Get byte_extract variables */ - // FIXIT these need to be thread local if (pmd->offset_var >= 0 && pmd->offset_var < NUM_BYTE_EXTRACT_VARS) { - GetByteExtractValue(&extract_offset, pmd->offset_var); - pmd->offset = (int) extract_offset; + uint32_t extract; + GetByteExtractValue(&extract, pmd->offset_var); + offset = (int) extract; } + else + offset = pmd->offset; + if (pmd->depth_var >= 0 && pmd->depth_var < NUM_BYTE_EXTRACT_VARS) { - GetByteExtractValue(&extract_depth, pmd->depth_var); - pmd->depth = (int) extract_depth; - } - if (pmd->distance_var >= 0 && pmd->distance_var < NUM_BYTE_EXTRACT_VARS) - { - GetByteExtractValue(&extract_distance, pmd->distance_var); - pmd->distance = (int) extract_distance; - } - if (pmd->within_var >= 0 && pmd->within_var < NUM_BYTE_EXTRACT_VARS) - { - GetByteExtractValue(&extract_within, pmd->within_var); - pmd->within = (u_int) extract_within; + uint32_t extract; + GetByteExtractValue(&extract, pmd->depth_var); + depth = (int) extract; } + else + depth = pmd->depth; - // Set our initial starting point - if (doe_ptr) - { - // Sanity check to make sure the doe_ptr is within the buffer we're - // searching. It could be at the very end of the buffer due to a - // previous match, but may have a negative distance here. - if (((char *)doe_ptr < start_ptr) || ((char *)doe_ptr > end_ptr)) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Returning because " - "doe_ptr isn't within the buffer we're searching: " - "start_ptr: %p, end_ptr: %p, doe_ptr: %p\n", - start_ptr, end_ptr, doe_ptr);); - return -1; - } + int pos = c.get_delta(); - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Setting base_ptr to doe_ptr (%p)\n", doe_ptr);); + if ( !pos && pmd->use_doe ) + pos = c.get_pos(); - base_ptr = (const char *)doe_ptr; - depth = dlen - ((char *)doe_ptr - data); - } - else - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Setting base_ptr to start_ptr (%p)\n", start_ptr);); + pos += offset; - base_ptr = start_ptr; - depth = dlen; - } + if ( pos < 0 ) + pos = 0; - // Adjust base_ptr and depth based on distance/within - // or offset/depth parameters. - if ((pmd->distance != 0) || (pmd->within != 0)) - { - if (pmd->distance != 0) - { - base_ptr += pmd->distance; - depth -= pmd->distance; - } + int len = c.size() - pos; - // If the distance is negative and puts us before start_ptr - // set base_ptr to start_ptr and adjust depth based on within. - if (base_ptr < start_ptr) - { - int delta = (int)pmd->within - (start_ptr - base_ptr); - base_ptr = start_ptr; - depth = ((pmd->within == 0) || (delta > dlen)) ? dlen : delta; - } - else if ((pmd->within != 0) && ((int)pmd->within < depth)) - { - depth = (int)pmd->within; - } - } - else if ((pmd->offset != 0) || (pmd->depth != 0)) - { - if (pmd->offset != 0) - { - base_ptr += pmd->offset; - depth -= pmd->offset; - } + if ( !depth || len < depth ) + depth = len; - if ((pmd->depth != 0) && (pmd->depth < depth)) - depth = pmd->depth; - } + unsigned end = pos + pmd->pattern_size; // If the pattern size is greater than the amount of data we have to // search, there's no way we can match, but return 0 here for the // case where the match is inverted and there is at least some data. - if ((int)pmd->pattern_size > depth) + if ( end > c.size() || (int)end > pos + depth ) { - if (pmd->exception_flag && (depth > 0)) + if ( pmd->exception_flag && (depth > 0) ) return 0; return -1; } -#ifdef DEBUG_MSGS - { - char *hexbuf; - - assert(depth <= dlen); - - DebugMessage(DEBUG_PATTERN_MATCH, "uniSearchReal:\n "); - - hexbuf = hex((u_char *)pmd->pattern_buf, pmd->pattern_size); - DebugMessage(DEBUG_PATTERN_MATCH, " p->data: %p\n doe_ptr: %p\n " - "base_ptr: %p\n depth: %d\n searching for: %s\n", - data, doe_ptr, base_ptr, depth, hexbuf); - free(hexbuf); - } -#endif /* DEBUG_MSGS */ + const uint8_t* base = c.buffer() + pos; + int found; - if(nocase) + if ( pmd->no_case ) { - success = mSearchCI(base_ptr, depth, - pmd->pattern_buf, - pmd->pattern_size, - pmd->skip_stride, - pmd->shift_stride); + found = mSearchCI( + (const char*)base, depth, pmd->pattern_buf, pmd->pattern_size, + pmd->skip_stride, pmd->shift_stride); } else { - success = mSearch(base_ptr, depth, - pmd->pattern_buf, - pmd->pattern_size, - pmd->skip_stride, - pmd->shift_stride); + found = mSearch( + (const char*)base, depth, pmd->pattern_buf, pmd->pattern_size, + pmd->skip_stride, pmd->shift_stride); } + c.set_delta(pos + pmd->match_delta); -#ifdef DEBUG_MSGS - if(success) + if ( found >= 0 ) { - DebugMessage(DEBUG_PATTERN_MATCH, "matched, doe_ptr: %p (%d)\n", - doe_ptr, ((char *)doe_ptr - data)); + c.set_pos(pos + found + pmd->pattern_size); + return 1; } -#endif - - return success; -} -/* - * case sensitive search - * - * data = ptr to buffer to search - * dlen = distance to the back of the buffer being tested, validated - * against offset + depth before function entry (not distance/within) - * pmd = pointer to pattern match data struct - */ - -static int uniSearch(const char *data, int dlen, PatternMatchData *pmd) -{ - return uniSearchReal(data, dlen, pmd, 0); -} - -/* - * case insensitive search - * - * data = ptr to buffer to search - * dlen = distance to the back of the buffer being tested, validated - * against offset + depth before function entry (not distance/within) - * pmd = pointer to pattern match data struct - */ -static int uniSearchCI(const char *data, int dlen, PatternMatchData *pmd) -{ - return uniSearchReal(data, dlen, pmd, 1); + return 0; } -static int CheckANDPatternMatch(PatternMatchData* idx, Packet *p) +static int CheckANDPatternMatch(PatternMatchData* idx, Cursor& c) { int rval = DETECTION_OPTION_NO_MATCH; int found = 0; - int dsize; - char *dp; - PROFILE_VARS; + PROFILE_VARS; PREPROC_PROFILE_START(contentPerfStats); DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "CheckPatternANDMatch: ");); - if(idx->rawbytes == 0) - { - if(Is_DetectFlag(FLAG_ALT_DETECT)) - { - dsize = DetectBuffer.len; - dp = (char *) DetectBuffer.data; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Using Alternative Detect buffer!\n");); - } - else if(Is_DetectFlag(FLAG_ALT_DECODE)) - { - dsize = DecodeBuffer.len; - dp = (char *) DecodeBuffer.data; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Using Alternative Decode buffer!\n");); - } - else - { - if(IsLimitedDetect(p)) - { - dsize = p->alt_dsize; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Using Limited Packet Data!\n");); - } - else - { - dsize = p->dsize; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Using Full Packet Data!\n");); - } - dp = (char *) p->data; - } - } - else - { - dsize = p->dsize; - dp = (char *) p->data; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Using Full Packet Data!\n");); - } - - if(doe_buf_flags & DOE_BUF_URI) - UpdateDoePtr(NULL, 0); - - doe_buf_flags = DOE_BUF_STD; - - found = idx->search(dp, dsize, idx); + found = uniSearchReal(idx, c); if ( found == -1 ) { @@ -836,20 +537,6 @@ static int CheckANDPatternMatch(PatternMatchData* idx, Packet *p) if ( found ) { - if ( idx->replace_buf && !PacketWasCooked(p) ) - { - //fix the packet buffer to have the new string - int detect_depth = (char *)doe_ptr - idx->pattern_size - dp; - - // this check should be redundant (never be true) - if (detect_depth < 0) - { - Replace_ResetOffset(idx); - PREPROC_PROFILE_END(contentPerfStats); - return rval; - } - Replace_StoreOffset(idx, detect_depth); - } rval = DETECTION_OPTION_MATCH; DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Pattern match found\n");); } @@ -862,271 +549,26 @@ static int CheckANDPatternMatch(PatternMatchData* idx, Packet *p) return rval; } -static int CheckUriPatternMatch(PatternMatchData* idx, Packet*) +PatternMatchData* content_get_data(void* pv) { - int rval = DETECTION_OPTION_NO_MATCH; - int found = 0; - const HttpBuffer* hb = GetHttpBuffer(idx->http_buffer); - PROFILE_VARS; - - if ( !hb ) - { - DEBUG_WRAP(DebugMessage(DEBUG_HTTP_DECODE,"CheckUriPatternMatch: no " - "HTTP buffers set, retuning");); - return rval; - } - - PREPROC_PROFILE_START(uricontentPerfStats); - - /* - * have to reset the doe_ptr for each new UriBuf - */ - if(idx->use_doe != 1) - UpdateDoePtr(NULL, 0); - - else if(!(doe_buf_flags & DOE_BUF_URI)) - SetDoePtr(hb->buf, DOE_BUF_URI); - - /* this now takes care of all the special cases where we'd run - * over the buffer */ - found = idx->search((const char *)hb->buf, hb->length, idx); - - if (found == -1) - found = 0; - else - found ^= idx->exception_flag; - - if(found > 0 ) - { - doe_buf_flags = DOE_BUF_URI; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern Match successful!\n");); - - /* call the next function in the OTN */ - PREPROC_PROFILE_END(uricontentPerfStats); - return DETECTION_OPTION_MATCH; - } - - DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Pattern match failed\n");); - PREPROC_PROFILE_END(uricontentPerfStats); - return rval; -} - -void PatternMatchDuplicatePmd(void *src, PatternMatchData *pmd_dup) -{ - ContentOption* opt = (ContentOption*)src; - PatternMatchData *pmd_src = opt->get_data(); - *pmd_dup = *pmd_src; - Replace_ResetOffset(pmd_dup); + ContentOption* opt = (ContentOption*)pv; + return opt->get_data(); } -// FIXIT this kinda hurts ... -int eval_dup_content(void* v, Packet* p, PatternMatchData* dup) +/* current should be the doe_ptr after this content rule option matched + * orig is the place from where we first did evaluation of this content */ +bool content_next(PatternMatchData* pmd) { - ContentOption* opt = (ContentOption*)v; - - if ( opt->get_type() == RULE_OPTION_TYPE_CONTENT ) - { - ContentOption tmp(dup, "content"); - int rval = tmp.eval(p); - tmp.set_data(nullptr); - return rval; - } - UriContentOption tmp(dup); - int rval = tmp.eval(p); - tmp.set_data(nullptr); - return rval; -} - -/* current_cursor should be the doe_ptr after this content rule option matched - * orig_cursor is the place from where we first did evaluation of this content */ -int PatternMatchAdjustRelativeOffsets( - void* pv, PatternMatchData *dup_pmd, - const uint8_t *current_cursor, const uint8_t *orig_cursor) -{ - ContentOption* opt = (ContentOption*)pv; - PatternMatchData* orig_pmd = opt->get_data(); - - /* Adjust for repeating patterns, e.g. ABAB - * This is where the new search for this content should start */ - const uint8_t *start_cursor = - (current_cursor - dup_pmd->pattern_size) + dup_pmd->pattern_max_jump_size; - - if (orig_pmd->depth != 0) - { - /* This was relative to a previously found pattern. No space left to - * search, we're done */ - if ((start_cursor + dup_pmd->pattern_size) - > (orig_cursor + dup_pmd->offset + dup_pmd->depth)) - { - return 0; - } - - /* Adjust offset and depth to reflect new position */ - /* Lop off what we used */ - dup_pmd->depth -= start_cursor - (orig_cursor + dup_pmd->offset); - /* Make offset where we will start the next search */ - dup_pmd->offset = start_cursor - orig_cursor; - } - else if (orig_pmd->within != 0) - { - /* This was relative to a previously found pattern. No space left to - * search, we're done */ - if ((start_cursor + dup_pmd->pattern_size) - > (orig_cursor + dup_pmd->distance + dup_pmd->within)) - { - return 0; - } - - /* Adjust distance and within to reflect new position */ - /* Lop off what we used */ - dup_pmd->within -= start_cursor - (orig_cursor + dup_pmd->distance); - /* Make distance where we will start the next search */ - dup_pmd->distance = start_cursor - orig_cursor; - } - else if (orig_pmd->use_doe) - { - dup_pmd->distance = start_cursor - orig_cursor; - } - else - { - dup_pmd->offset = start_cursor - orig_cursor; - } + if ( pmd->exception_flag ) + return false; - return 1; + return true; } -// FIXIT PMD //------------------------------------------------------------------------- // suboption handlers //------------------------------------------------------------------------- -static void PayloadSearchHttpMethod( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_method' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_METHOD; - MovePmdToUriDsList(otn, pmd); -} - -static void PayloadSearchHttpUri( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_uri' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_URI; - MovePmdToUriDsList(otn, pmd); -} - -static void PayloadSearchHttpHeader( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_header' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_HEADER; - MovePmdToUriDsList(otn, pmd); -} - -static void PayloadSearchHttpCookie( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_cookie' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_COOKIE; - MovePmdToUriDsList(otn, pmd); -} - -static void PayloadSearchHttpBody( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_client_body' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_CLIENT_BODY; - MovePmdToUriDsList(otn, pmd); -} - -static void PayloadSearchHttpRawUri( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_raw_uri' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_RAW_URI; - MovePmdToUriDsList(otn, pmd); -} - -static void PayloadSearchHttpRawHeader( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_raw_header' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_RAW_HEADER; - MovePmdToUriDsList(otn, pmd); -} -static void PayloadSearchHttpRawCookie( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_raw_cookie' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_RAW_COOKIE; - MovePmdToUriDsList(otn, pmd); -} -static void PayloadSearchHttpStatCode( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_stat_code' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_STAT_CODE; - MovePmdToUriDsList(otn, pmd); -} -static void PayloadSearchHttpStatMsg( - PatternMatchData* pmd, char *data, OptTreeNode * otn) -{ - if (data != NULL) - ParseError("'http_stat_msg' does not take an argument"); - - if ( pmd->http_buffer ) - ParseWarning("at most one http buffer can be specified per content option"); - - pmd->http_buffer = HTTP_BUFFER_STAT_MSG; - MovePmdToUriDsList(otn, pmd); -} - typedef enum { CMF_DISTANCE = 0x1, CMF_WITHIN = 0x2, CMF_OFFSET = 0x4, CMF_DEPTH = 0x8 } ContentModifierFlags; @@ -1134,8 +576,6 @@ typedef enum { static unsigned GetCMF (PatternMatchData* pmd) { unsigned cmf = 0; - if ( (pmd->distance != 0) || (pmd->distance_var != -1) ) cmf |= CMF_DISTANCE; - if ( (pmd->within != 0) || (pmd->within_var != -1) ) cmf |= CMF_WITHIN; if ( (pmd->offset != 0) || (pmd->offset_var != -1) ) cmf |= CMF_OFFSET; if ( (pmd->depth != 0) || (pmd->depth_var != -1) ) cmf |= CMF_DEPTH; return cmf; @@ -1149,7 +589,7 @@ static unsigned GetCMF (PatternMatchData* pmd) static void PayloadSearchOffset( PatternMatchData* pmd, char *data, OptTreeNode*) { - if ( GetCMF(pmd) & BAD_OFFSET ) + if ( GetCMF(pmd) & BAD_OFFSET && pmd->use_doe ) ParseError("offset can't be used with itself, distance, or within"); if (data == NULL) @@ -1175,7 +615,7 @@ static void PayloadSearchOffset( static void PayloadSearchDepth( PatternMatchData* pmd, char *data, OptTreeNode*) { - if ( GetCMF(pmd) & BAD_DEPTH ) + if ( GetCMF(pmd) & BAD_DEPTH && pmd->use_doe ) ParseError("depth can't be used with itself, distance, or within"); if (data == NULL) @@ -1208,7 +648,7 @@ static void PayloadSearchDepth( static void PayloadSearchDistance( PatternMatchData* pmd, char *data, OptTreeNode*) { - if ( GetCMF(pmd) & BAD_DISTANCE ) + if ( GetCMF(pmd) & BAD_DISTANCE && !pmd->use_doe ) ParseError("distance can't be used with itself, offset, or depth"); if (data == NULL) @@ -1216,27 +656,24 @@ static void PayloadSearchDistance( if (isdigit(data[0]) || data[0] == '-') { - pmd->distance = ParseInt(data, "distance"); + pmd->offset = ParseInt(data, "distance"); } else { - pmd->distance_var = GetVarByName(data); - if (pmd->distance_var == BYTE_EXTRACT_NO_VAR) + pmd->offset_var = GetVarByName(data); + if (pmd->offset_var == BYTE_EXTRACT_NO_VAR) { ParseError(BYTE_EXTRACT_INVALID_ERR_STR); } } - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern distance = %d\n", - pmd->distance);); - pmd->use_doe = 1; } static void PayloadSearchWithin( PatternMatchData* pmd, char *data, OptTreeNode*) { - if ( GetCMF(pmd) & BAD_WITHIN ) + if ( GetCMF(pmd) & BAD_WITHIN && !pmd->use_doe ) ParseError("within can't be used with itself, offset, or depth"); if (data == NULL) @@ -1244,22 +681,22 @@ static void PayloadSearchWithin( if (isdigit(data[0]) || data[0] == '-') { - pmd->within = ParseInt(data, "within"); + pmd->depth = ParseInt(data, "within"); - if (pmd->within < pmd->pattern_size) - ParseError("within (%d) is smaller than size of pattern", pmd->within); + if (pmd->depth < (int)pmd->pattern_size) + ParseError("within (%d) is smaller than size of pattern", pmd->depth); } else { - pmd->within_var = GetVarByName(data); - if (pmd->within_var == BYTE_EXTRACT_NO_VAR) + pmd->depth_var = GetVarByName(data); + if (pmd->depth_var == BYTE_EXTRACT_NO_VAR) { ParseError(BYTE_EXTRACT_INVALID_ERR_STR); } } DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern within = %d\n", - pmd->within);); + pmd->depth);); pmd->use_doe = 1; } @@ -1270,28 +707,15 @@ static void PayloadSearchNocase( unsigned int i; if (data != NULL) - ParseError("'nocase' does not take an argument"); + ParseError("'no_case' does not take an argument"); for (i = 0; i < pmd->pattern_size; i++) pmd->pattern_buf[i] = toupper((int)pmd->pattern_buf[i]); - pmd->nocase = 1; - - pmd->search = uniSearchCI; + pmd->no_case = 1; make_precomp(pmd); } -static void PayloadSearchRawbytes( - PatternMatchData* pmd, char *data, OptTreeNode*) -{ - if (data != NULL) - ParseError("'rawbytes' does not take an argument"); - - /* mark this as inspecting a raw pattern match rather than a - * decoded application buffer */ - pmd->rawbytes = 1; -} - static void PayloadSearchFastPattern( PatternMatchData* pmd, char *data, OptTreeNode *otn) { @@ -1305,8 +729,6 @@ static void PayloadSearchFastPattern( if (HasFastPattern(otn, RULE_OPTION_TYPE_CONTENT)) ParseError("Can only use the fast_pattern modifier once in a rule."); - if (HasFastPattern(otn, RULE_OPTION_TYPE_CONTENT_URI)) - ParseError("Can only use the fast_pattern modifier once in a rule."); pmd->fp = 1; @@ -1649,12 +1071,11 @@ static void content_parse(char *rule, PatternMatchData* ds_idx) memcpy(ds_idx->pattern_buf, tmp_buf, dummy_size); ds_idx->pattern_size = dummy_size; - ds_idx->search = uniSearch; make_precomp(ds_idx); ds_idx->exception_flag = exception_flag; - ds_idx->pattern_max_jump_size = GetMaxJumpSize(ds_idx->pattern_buf, ds_idx->pattern_size); + ds_idx->match_delta = GetMaxJumpSize(ds_idx->pattern_buf, ds_idx->pattern_size); } static IpsOption* content_ctor( @@ -1679,9 +1100,6 @@ static IpsOption* content_ctor( update_pmd(pmd); next_opt = opt_data + opt_len; - pmd->http_buffer = HTTP_BUFFER_NONE; - pmd->buffer_func = CHECK_AND_PATTERN_MATCH; - while (next_opt < data_end) { char **opts; /* dbl ptr for mSplit call, holds rule tokens */ @@ -1717,50 +1135,6 @@ static IpsOption* content_ctor( { PayloadSearchNocase(pmd, opt1, otn); } - else if (!strcasecmp(opts[0], "rawbytes")) - { - PayloadSearchRawbytes(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_uri")) - { - PayloadSearchHttpUri(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_client_body")) - { - PayloadSearchHttpBody(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_header")) - { - PayloadSearchHttpHeader(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_method")) - { - PayloadSearchHttpMethod(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_cookie")) - { - PayloadSearchHttpCookie(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_raw_uri")) - { - PayloadSearchHttpRawUri(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_raw_header")) - { - PayloadSearchHttpRawHeader(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_raw_cookie")) - { - PayloadSearchHttpRawCookie(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_stat_code")) - { - PayloadSearchHttpStatCode(pmd, opt1, otn); - } - else if (!strcasecmp(opts[0], "http_stat_msg")) - { - PayloadSearchHttpStatMsg(pmd, opt1, otn); - } else if (!strcasecmp(opts[0], "fast_pattern")) { PayloadSearchFastPattern(pmd, opt1, otn); @@ -1773,10 +1147,6 @@ static IpsOption* content_ctor( { PayloadSearchWithin(pmd, opt1, otn); } - else if (!strcasecmp(opts[0], "replace")) - { - PayloadReplaceInit(pmd, opt1, otn); - } else { ParseError("Invalid content parameter specified: %s", opts[0]); @@ -1787,9 +1157,6 @@ static IpsOption* content_ctor( free(data_dup); ValidateContent(sc, pmd, RULE_OPTION_TYPE_CONTENT); - if ( pmd->buffer_func == CHECK_URI_PATTERN_MATCH ) - return new UriContentOption(pmd); - return new ContentOption(pmd, "content"); } diff --git a/src/ips_options/ips_content.h b/src/ips_options/ips_content.h index 5d537fec8..93a18ab80 100644 --- a/src/ips_options/ips_content.h +++ b/src/ips_options/ips_content.h @@ -29,6 +29,7 @@ #include "detection/rules.h" #include "detection/treenodes.h" #include "detection/detection_util.h" +#include "framework/content_buffer.h" extern THREAD_LOCAL int lastType; @@ -44,38 +45,27 @@ struct PmdLastCheck typedef struct _PatternMatchData { - // FIXIT below must be thread local or the cloned instance must be - // thread local because they are updated :( int offset; /* pattern search start offset */ int depth; /* pattern search depth */ - int distance; /* offset to start from based on last match */ - unsigned within; /* this pattern must be found - within X bytes of last match*/ - // FIXIT above must be thread local or the cloned instance must be - // thread local because they are updated :( - int8_t offset_var; /* byte_extract variable indices for offset, */ int8_t depth_var; /* depth, distance, within */ int8_t distance_var; int8_t within_var; - int rawbytes; /* Search the raw bytes rather than any decoded app - buffer */ - - int nocase; /* Toggle case insensitity */ + int no_case; /* Toggle case sensitivity */ int use_doe; /* Use the doe_ptr for relative pattern searching */ - HTTP_BUFFER http_buffer;/* Index of the URI buffer */ - int buffer_func; /* buffer function CheckAND or CheckUri */ - unsigned pattern_size; /* size of app layer pattern */ - unsigned replace_size; /* size of app layer replace pattern */ + + unsigned pattern_size; /* size of app layer pattern */ + unsigned replace_size; /* size of app layer replace pattern */ + char *replace_buf; /* app layer pattern to replace with */ char *pattern_buf; /* app layer pattern to match on */ - int (*search)(const char *, int, struct _PatternMatchData *); /* search function */ - int *skip_stride; /* B-M skip array */ - int *shift_stride; /* B-M shift array */ - unsigned pattern_max_jump_size; /* Maximum distance we can jump to search for - * this pattern again. */ + + int *skip_stride; /* B-M skip array */ + int *shift_stride; /* B-M shift array */ + unsigned match_delta; /* Maximum distance we can jump to search for + * this pattern again. */ /* For fast_pattern arguments */ uint8_t fp; @@ -85,8 +75,6 @@ typedef struct _PatternMatchData uint8_t exception_flag; /* search for "not this pattern" */ - int* replace_depth; /* >=0 is offset to start of replace */ - // FIXIT wasting some memory here: // - this is not used by content option logic directly // - and only used on current eval (not across packets) @@ -99,8 +87,8 @@ typedef struct _PatternMatchData } PatternMatchData; -void PatternMatchDuplicatePmd(void *, PatternMatchData *); -int eval_dup_content(void* v, struct Packet* p, PatternMatchData* alt); +PatternMatchData* content_get_data(void* pv); +bool content_next(PatternMatchData*); int PatternMatchAdjustRelativeOffsets( void*, PatternMatchData *dup_pmd, @@ -112,6 +100,8 @@ PatternMatchData* get_pmd(OptFpList*); bool is_fast_pattern_only(OptFpList*); bool is_unbounded(void*); +// FIXIT must add same fast_pattern options from content to these +// rule options: static inline bool IsHttpBufFpEligible (HTTP_BUFFER http_buffer) { switch ( http_buffer ) diff --git a/src/ips_options/ips_cvs.cc b/src/ips_options/ips_cvs.cc index 8de2e2a3b..e9569bf94 100644 --- a/src/ips_options/ips_cvs.cc +++ b/src/ips_options/ips_cvs.cc @@ -130,7 +130,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: CvsRuleOption config; @@ -172,7 +172,7 @@ bool CvsOption::operator==(const IpsOption& ips) const return false; } -int CvsOption::eval(Packet *p) +int CvsOption::eval(Cursor&, Packet *p) { int ret; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_dsize.cc b/src/ips_options/ips_dsize.cc index 28c123b84..b55b541ff 100644 --- a/src/ips_options/ips_dsize.cc +++ b/src/ips_options/ips_dsize.cc @@ -79,7 +79,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: DsizeCheckData config; @@ -125,7 +125,7 @@ bool DsizeOption::operator==(const IpsOption& ips) const } // Test the packet's payload size against the rule payload size value -int DsizeOption::eval(Packet *p) +int DsizeOption::eval(Cursor&, Packet *p) { DsizeCheckData *ds_ptr = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_file_data.cc b/src/ips_options/ips_file_data.cc index 44fc1cf81..11c785de9 100644 --- a/src/ips_options/ips_file_data.cc +++ b/src/ips_options/ips_file_data.cc @@ -41,6 +41,7 @@ #include "fpdetect.h" #include "detection/detection_defines.h" #include "detection/detection_util.h" +#include "framework/cursor.h" #include "framework/ips_option.h" static const char* s_name = "file_data"; @@ -74,7 +75,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); FileData* get_data() { return &config; }; @@ -117,7 +118,7 @@ bool FileDataOption::operator==(const IpsOption& ips) const return false; } -int FileDataOption::eval(Packet *p) +int FileDataOption::eval(Cursor& c, Packet *p) { int rval = DETECTION_OPTION_NO_MATCH; uint8_t *data; @@ -142,8 +143,7 @@ int FileDataOption::eval(Packet *p) else mime_present = 0; - SetDoePtr(data, DOE_BUF_STD); - SetAltDetect(data, len); + c.set(s_name, data, len); rval = DETECTION_OPTION_MATCH; PREPROC_PROFILE_END(fileDataPerfStats); diff --git a/src/ips_options/ips_flags.cc b/src/ips_options/ips_flags.cc index d90c5341d..d85076a81 100644 --- a/src/ips_options/ips_flags.cc +++ b/src/ips_options/ips_flags.cc @@ -86,7 +86,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: TcpFlagCheckData config; @@ -130,7 +130,7 @@ bool TcpFlagOption::operator==(const IpsOption& ips) const return false; } -int TcpFlagOption::eval(Packet *p) +int TcpFlagOption::eval(Cursor&, Packet *p) { TcpFlagCheckData *flagptr = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_flow.cc b/src/ips_options/ips_flow.cc index 050277b8c..47e5a9293 100644 --- a/src/ips_options/ips_flow.cc +++ b/src/ips_options/ips_flow.cc @@ -84,7 +84,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: FlowCheckData config; @@ -135,7 +135,7 @@ bool FlowCheckOption::operator==(const IpsOption& ips) const return false; } -int FlowCheckOption::eval(Packet *p) +int FlowCheckOption::eval(Cursor&, Packet *p) { FlowCheckData *fcd = &config; PROFILE_VARS; diff --git a/src/ips_options/ips_flowbits.cc b/src/ips_options/ips_flowbits.cc index 53307f879..0228589d9 100644 --- a/src/ips_options/ips_flowbits.cc +++ b/src/ips_options/ips_flowbits.cc @@ -174,7 +174,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); bool is_set(uint8_t bits) { return (config.type & bits) != 0; }; @@ -269,7 +269,7 @@ bool FlowBitsOption::operator==(const IpsOption& ips) const return true; } -int FlowBitsOption::eval(Packet *p) +int FlowBitsOption::eval(Cursor&, Packet *p) { FLOWBITS_OP *flowbits = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_fragbits.cc b/src/ips_options/ips_fragbits.cc index 9fd828e29..703cbb0ef 100644 --- a/src/ips_options/ips_fragbits.cc +++ b/src/ips_options/ips_fragbits.cc @@ -108,7 +108,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: FragBitsData config; @@ -153,7 +153,7 @@ bool FragBitsOption::operator==(const IpsOption& ips) const return false; } -int FragBitsOption::eval(Packet *p) +int FragBitsOption::eval(Cursor&, Packet *p) { FragBitsData *fb = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_fragoffset.cc b/src/ips_options/ips_fragoffset.cc index 576b31b23..072048f99 100644 --- a/src/ips_options/ips_fragoffset.cc +++ b/src/ips_options/ips_fragoffset.cc @@ -85,7 +85,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: FragOffsetData config; @@ -129,7 +129,7 @@ bool FragOffsetOption::operator==(const IpsOption& ips) const return false; } -int FragOffsetOption::eval(Packet *p) +int FragOffsetOption::eval(Cursor&, Packet *p) { FragOffsetData *ipd = &config; int p_offset = p->frag_offset * 8; diff --git a/src/ips_options/ips_icmp_id.cc b/src/ips_options/ips_icmp_id.cc index 108f88d7b..b71a6c42a 100644 --- a/src/ips_options/ips_icmp_id.cc +++ b/src/ips_options/ips_icmp_id.cc @@ -92,7 +92,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: IcmpIdCheckData config; @@ -134,7 +134,7 @@ bool IcmpIdOption::operator==(const IpsOption& ips) const return false; } -int IcmpIdOption::eval(Packet *p) +int IcmpIdOption::eval(Cursor&, Packet *p) { IcmpIdCheckData *icmpId = &config; PROFILE_VARS; diff --git a/src/ips_options/ips_icmp_seq.cc b/src/ips_options/ips_icmp_seq.cc index d8552922b..a98ef56c1 100644 --- a/src/ips_options/ips_icmp_seq.cc +++ b/src/ips_options/ips_icmp_seq.cc @@ -91,7 +91,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: IcmpSeqCheckData config; @@ -133,7 +133,7 @@ bool IcmpSeqOption::operator==(const IpsOption& ips) const return false; } -int IcmpSeqOption::eval(Packet *p) +int IcmpSeqOption::eval(Cursor&, Packet *p) { IcmpSeqCheckData *icmpSeq = &config; PROFILE_VARS; diff --git a/src/ips_options/ips_icode.cc b/src/ips_options/ips_icode.cc index 366eeae1a..5b7fc8228 100644 --- a/src/ips_options/ips_icode.cc +++ b/src/ips_options/ips_icode.cc @@ -78,7 +78,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: IcmpCodeCheckData config; @@ -123,7 +123,7 @@ bool IcmpCodeOption::operator==(const IpsOption& ips) const return false; } -int IcmpCodeOption::eval(Packet *p) +int IcmpCodeOption::eval(Cursor&, Packet *p) { IcmpCodeCheckData *ds_ptr = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_id.cc b/src/ips_options/ips_id.cc index 95587e574..ebb66ec6e 100644 --- a/src/ips_options/ips_id.cc +++ b/src/ips_options/ips_id.cc @@ -70,7 +70,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: IpIdCheckData config; @@ -112,7 +112,7 @@ bool IpIdOption::operator==(const IpsOption& ips) const return false; } -int IpIdOption::eval(Packet *p) +int IpIdOption::eval(Cursor&, Packet *p) { IpIdCheckData *ipIdCheckData = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_ip_proto.cc b/src/ips_options/ips_ip_proto.cc index 880a84c51..d8018317c 100644 --- a/src/ips_options/ips_ip_proto.cc +++ b/src/ips_options/ips_ip_proto.cc @@ -80,7 +80,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); IpProtoData* get_data() { return &config; }; @@ -126,7 +126,7 @@ bool IpProtoOption::operator==(const IpsOption& ips) const return false; } -int IpProtoOption::eval(Packet *p) +int IpProtoOption::eval(Cursor&, Packet *p) { IpProtoData *ipd = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_ipopts.cc b/src/ips_options/ips_ipopts.cc index fc47f5e06..3a847d928 100644 --- a/src/ips_options/ips_ipopts.cc +++ b/src/ips_options/ips_ipopts.cc @@ -72,7 +72,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); IpOptionData* get_data() { return &config; }; @@ -118,7 +118,7 @@ bool IpOptOption::operator==(const IpsOption& ips) const return false; } -int IpOptOption::eval(Packet *p) +int IpOptOption::eval(Cursor&, Packet *p) { IpOptionData *ipOptionData = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_isdataat.cc b/src/ips_options/ips_isdataat.cc index 5e6a0e67f..47ddc7b4f 100644 --- a/src/ips_options/ips_isdataat.cc +++ b/src/ips_options/ips_isdataat.cc @@ -97,7 +97,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); IsDataAtData* get_data() { return &config; }; @@ -148,7 +148,7 @@ bool IsDataAtOption::operator==(const IpsOption& ips) const return false; } -int IsDataAtOption::eval(Packet *p) +int IsDataAtOption::eval(Cursor&, Packet *p) { IsDataAtData *isdata = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_itype.cc b/src/ips_options/ips_itype.cc index b4a80dc42..1fd9c0804 100644 --- a/src/ips_options/ips_itype.cc +++ b/src/ips_options/ips_itype.cc @@ -78,7 +78,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: IcmpTypeCheckData config; @@ -123,7 +123,7 @@ bool IcmpTypeOption::operator==(const IpsOption& ips) const return false; } -int IcmpTypeOption::eval(Packet *p) +int IcmpTypeOption::eval(Cursor&, Packet *p) { IcmpTypeCheckData *ds_ptr = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_luajit.cc b/src/ips_options/ips_luajit.cc index 9ffc6c65f..b004d053a 100644 --- a/src/ips_options/ips_luajit.cc +++ b/src/ips_options/ips_luajit.cc @@ -232,7 +232,7 @@ bool LuaJITOption::operator==(const IpsOption& ips) const return true; } -int LuaJITOption::eval(Packet* p) +int LuaJITOption::eval(Cursor&, Packet* p) { packet = p; diff --git a/src/ips_options/ips_luajit.h b/src/ips_options/ips_luajit.h index dc34a65eb..a9bd30c75 100644 --- a/src/ips_options/ips_luajit.h +++ b/src/ips_options/ips_luajit.h @@ -33,7 +33,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: void init(const char*, const char*); diff --git a/src/ips_options/ips_options.cc b/src/ips_options/ips_options.cc index 0ef496384..08d750048 100644 --- a/src/ips_options/ips_options.cc +++ b/src/ips_options/ips_options.cc @@ -54,6 +54,7 @@ extern const BaseApi* ips_ipopts; extern const BaseApi* ips_isdataat; extern const BaseApi* ips_itype; extern const BaseApi* ips_pkt_data; +extern const BaseApi* ips_raw_data; extern const BaseApi* ips_react; extern const BaseApi* ips_resp; extern const BaseApi* ips_rpc; @@ -96,6 +97,7 @@ const BaseApi* ips_options[] = ips_isdataat, ips_itype, ips_pkt_data, + ips_raw_data, ips_react, ips_resp, ips_rpc, diff --git a/src/ips_options/ips_pcre.cc b/src/ips_options/ips_pcre.cc index 63cff4396..277b53110 100644 --- a/src/ips_options/ips_pcre.cc +++ b/src/ips_options/ips_pcre.cc @@ -44,22 +44,11 @@ #include "sfhashfcn.h" #include "detection/detection_defines.h" #include "detection_util.h" +#include "framework/cursor.h" #include "framework/ips_option.h" static const char* s_name = "pcre"; -#ifdef PERF_PROFILING -static THREAD_LOCAL PreprocStats pcrePerfStats; - -static PreprocStats* pcre_get_profile(const char* key) -{ - if ( !strcmp(key, s_name) ) - return &pcrePerfStats; - - return nullptr; -} -#endif - /* * we need to specify the vector length for our pcre_exec call. we only care * about the first vector, which if the match is successful will include the @@ -74,410 +63,22 @@ static PreprocStats* pcre_get_profile(const char* key) * configuraton, we won't pcre_capture count again, so save the max. */ static int s_ovector_max = 0; -class PcreOption : public IpsOption -{ -public: - PcreOption(PcreData* c) : - IpsOption(s_name, RULE_OPTION_TYPE_PCRE) - { config = c; }; - - ~PcreOption(); - - uint32_t hash() const; - bool operator==(const IpsOption&) const; - - bool is_relative() - { return (config->options & SNORT_PCRE_RELATIVE) != 0; }; - - int eval(Packet*); - - PcreData* get_data() - { return config; }; - - void set_data(PcreData* pcre) - { config = pcre; }; - -private: - PcreData* config; -}; - -static int pcre_search( - const PcreData*, const char*, int len, int start_offset, int* found_offset); - -//------------------------------------------------------------------------- -// class methods -//------------------------------------------------------------------------- - -PcreOption::~PcreOption() -{ - if ( !config ) - return; - - if (config->expression) - free(config->expression); - if (config->pe) - free(config->pe); - if (config->re) - free(config->re); - - free(config); -} - -uint32_t PcreOption::hash() const -{ - int i,j,k,l,expression_len; - uint32_t a,b,c,tmp; - const PcreData *data = config; - - expression_len = strlen(data->expression); - a = b = c = 0; - - for (i=0,j=0;i 4) - k=4; - - for (l=0;lexpression + i + l) << l*8; - } - - switch (j) - { - case 0: - a += tmp; - break; - case 1: - b += tmp; - break; - case 2: - c += tmp; - break; - } - j++; - - if (j == 3) - { - mix(a,b,c); - j=0; - } - } - - if (j != 0) - { - mix(a,b,c); - } - - a += data->options; - - mix_str(a,b,c,get_name()); - final(a,b,c); - - return c; -} - -bool PcreOption::operator==(const IpsOption& ips) const -{ - if ( strcmp(get_name(), ips.get_name()) ) - return false; - - PcreOption& rhs = (PcreOption&)ips; - PcreData *left = config; - PcreData *right = rhs.config; - - if (( strcmp(left->expression, right->expression) == 0) && - ( left->options == right->options)) - { - return true; - } - - return false; -} - -int PcreOption::eval(Packet *p) -{ - PcreData *pcre_data = config; - int found_offset = -1; /* where is the ending location of the pattern */ - const uint8_t *base_ptr, *end_ptr, *start_ptr; - int dsize; - int length; /* length of the buffer pointed to by base_ptr */ - int matched = 0; - uint8_t rst_doe_flags = 1; - HTTP_BUFFER hb_type; - DEBUG_WRAP(char *hexbuf;) - - PROFILE_VARS; - PREPROC_PROFILE_START(pcrePerfStats); - - //short circuit this for testing pcre performance impact - if (ScNoPcre()) - { - PREPROC_PROFILE_END(pcrePerfStats); - return DETECTION_OPTION_NO_MATCH; - } - - /* This is the HTTP case */ - if ( (hb_type = (HTTP_BUFFER)(pcre_data->options & SNORT_PCRE_HTTP_BUFS)) ) - { - const HttpBuffer* hb = GetHttpBuffer(hb_type); - - if ( hb ) - { - matched = pcre_search( - pcre_data, (const char*)hb->buf, hb->length, 0, &found_offset); - - if ( matched ) - { - /* don't touch doe_ptr on URI contents */ - PREPROC_PROFILE_END(pcrePerfStats); - return DETECTION_OPTION_MATCH; - } - } - PREPROC_PROFILE_END(pcrePerfStats); - return DETECTION_OPTION_NO_MATCH; - } - /* end of the HTTP case */ - - if( !(pcre_data->options & SNORT_PCRE_RAWBYTES)) - { - if(Is_DetectFlag(FLAG_ALT_DETECT)) - { - dsize = DetectBuffer.len; - start_ptr = DetectBuffer.data; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "using alternative detect buffer in pcre!\n");); - } - else if(Is_DetectFlag(FLAG_ALT_DECODE)) - { - dsize = DecodeBuffer.len; - start_ptr = DecodeBuffer.data; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "using alternative decode buffer in pcre!\n");); - } - else - { - if(IsLimitedDetect(p)) - dsize = p->alt_dsize; - else - dsize = p->dsize; - start_ptr = p->data; - } - } - else - { - dsize = p->dsize; - start_ptr = p->data; - } - - //base_ptr = start_ptr; - end_ptr = start_ptr + dsize; - - /* doe_ptr's would be set by the previous content option */ - if(pcre_data->options & SNORT_PCRE_RELATIVE && doe_ptr) - { - if(!inBounds(start_ptr, end_ptr, doe_ptr)) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "pcre bounds check failed on a relative content match\n");); - PREPROC_PROFILE_END(pcrePerfStats); - return DETECTION_OPTION_NO_MATCH; - } - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "pcre ... checking relative offset\n");); - base_ptr = doe_ptr; - rst_doe_flags = 0; - } - else - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "pcre ... checking absolute offset\n");); - base_ptr = start_ptr; - } - - length = end_ptr - base_ptr; - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "pcre ... base: %p start: %p end: %p doe: %p length: %d\n", - base_ptr, start_ptr, end_ptr, doe_ptr, length);); - - DEBUG_WRAP(hexbuf = hex(base_ptr, length); - DebugMessage(DEBUG_PATTERN_MATCH, "pcre payload: %s\n", hexbuf); - free(hexbuf); - ); - - matched = pcre_search(pcre_data, (const char *)base_ptr, length, pcre_data->search_offset, &found_offset); - - /* set the doe_ptr if we have a valid offset */ - if(found_offset > 0) - { - UpdateDoePtr(((uint8_t *) base_ptr + found_offset), rst_doe_flags); - } - - if (matched) - { - PREPROC_PROFILE_END(pcrePerfStats); - return DETECTION_OPTION_MATCH; - } - - /* finally return 0 */ - PREPROC_PROFILE_END(pcrePerfStats); - return DETECTION_OPTION_NO_MATCH; -} - -//------------------------------------------------------------------------- -// public methods -//------------------------------------------------------------------------- - -void PcreDuplicatePcreData(void *src, PcreData *pcre_dup) -{ - PcreOption* opt = (PcreOption*)src; - PcreData* pcre_src = opt->get_data(); - *pcre_dup = *pcre_src; - pcre_dup->search_offset = 0; -} - -// FIXIT this kinda hurts ... -int eval_dup_pcre(void*, Packet* p, PcreData* dup) -{ - PcreOption tmp(dup); - int rval = tmp.eval(p); - tmp.set_data(nullptr); - return rval; -} +#ifdef PERF_PROFILING +static THREAD_LOCAL PreprocStats pcrePerfStats; -int PcreAdjustRelativeOffsets(PcreData *pcre, uint32_t search_offset) +static PreprocStats* pcre_get_profile(const char* key) { - if ((pcre->options & (SNORT_PCRE_INVERT | SNORT_PCRE_ANCHORED))) - { - return 0; /* Don't search again */ - } - - if (pcre->options & ( SNORT_PCRE_HTTP_BUFS )) - { - return 0; - } - - /* What's coming in has the absolute offset */ - pcre->search_offset += search_offset; + if ( !strcmp(key, s_name) ) + return &pcrePerfStats; - return 1; /* Continue searcing */ + return nullptr; } +#endif //------------------------------------------------------------------------- // implementation foo //------------------------------------------------------------------------- -/** - * Perform a search of the PCRE data. - * - * @param pcre_data structure that options and patterns are passed in - * @param buf buffer to search - * @param len size of buffer - * @param start_offset initial offset into the buffer - * @param found_offset pointer to an integer so that we know where the search ended - * - * *found_offset will be set to -1 when the find is unsucessful OR the routine is inverted - * - * @return 1 when we find the string, 0 when we don't (unless we've been passed a flag to invert) - */ -static int pcre_search( - const PcreData *pcre_data, - const char *buf, - int len, - int start_offset, - int *found_offset) -{ - int matched; - int result; - - if(pcre_data == NULL - || buf == NULL - || len <= 0 - || start_offset < 0 - || start_offset >= len - || found_offset == NULL) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Returning 0 because we didn't have the required parameters!\n");); - return 0; - } - - *found_offset = -1; - - SnortState* ss = snort_conf->state + get_instance_id(); - - result = pcre_exec( - pcre_data->re, /* result of pcre_compile() */ - pcre_data->pe, /* result of pcre_study() */ - buf, /* the subject string */ - len, /* the length of the subject string */ - start_offset, /* start at offset 0 in the subject */ - 0, /* options(handled at compile time */ - ss->pcre_ovector, /* vector for substring information */ - snort_conf->pcre_ovector_size);/* number of elements in the vector */ - - if(result >= 0) - { - matched = 1; - - /* From the PCRE man page: When a match is successful, information - * about captured substrings is returned in pairs of integers, - * starting at the beginning of ovector, and continuing up to - * two-thirds of its length at the most. The first element of a - * pair is set to the offset of the first character in a substring, - * and the second is set to the offset of the first character after - * the end of a substring. The first pair, ovector[0] and - * ovector[1], identify the portion of the subject string matched - * by the entire pattern. The next pair is used for the first - * capturing subpattern, and so on. The value returned by - * pcre_exec() is the number of pairs that have been set. If there - * are no capturing subpatterns, the return value from a successful - * match is 1, indicating that just the first pair of offsets has - * been set. - * - * In Snort's case, the ovector size only allows for the first pair - * and a single int for scratch space. - */ - - *found_offset = ss->pcre_ovector[1]; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "Setting Doe_ptr and found_offset: %p %d\n", doe_ptr, found_offset);); - } - else if(result == PCRE_ERROR_NOMATCH) - { - matched = 0; - } - else - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_exec error : %d \n", result);); - return 0; - } - - /* invert sense of match */ - if(pcre_data->options & SNORT_PCRE_INVERT) - { - matched = !matched; - } - - return matched; -} - -//------------------------------------------------------------------------- -// api methods -//------------------------------------------------------------------------- - -static void ValidatePcreHttpContentModifiers(PcreData *pcre_data) -{ - if( pcre_data->options & SNORT_PCRE_RELATIVE ) - ParseError("PCRE unsupported configuration : both relative & uri options specified"); - - if( pcre_data->options & SNORT_PCRE_RAWBYTES ) - ParseError("PCRE unsupported configuration : both rawbytes & uri options specified"); -} - static void pcre_capture( SnortConfig* sc, const void *code, const void *extra) { @@ -546,7 +147,6 @@ static void pcre_parse( char delimit = '/'; int erroffset; int compile_flags = 0; - unsigned http = 0; if(data == NULL) { @@ -631,18 +231,7 @@ static void pcre_parse( * these are snort specific don't work with pcre or perl */ case 'R': pcre_data->options |= SNORT_PCRE_RELATIVE; break; - case 'B': pcre_data->options |= SNORT_PCRE_RAWBYTES; break; case 'O': pcre_data->options |= SNORT_OVERRIDE_MATCH_LIMIT; break; - case 'U': pcre_data->options |= SNORT_PCRE_HTTP_URI; http++; break; - case 'P': pcre_data->options |= SNORT_PCRE_HTTP_BODY; http++; break; - case 'H': pcre_data->options |= SNORT_PCRE_HTTP_HEADER; http++; break; - case 'M': pcre_data->options |= SNORT_PCRE_HTTP_METHOD; http++; break; - case 'C': pcre_data->options |= SNORT_PCRE_HTTP_COOKIE; http++; break; - case 'I': pcre_data->options |= SNORT_PCRE_HTTP_RAW_URI; http++; break; - case 'D': pcre_data->options |= SNORT_PCRE_HTTP_RAW_HEADER; http++; break; - case 'K': pcre_data->options |= SNORT_PCRE_HTTP_RAW_COOKIE; http++; break; - case 'S': pcre_data->options |= SNORT_PCRE_HTTP_STAT_CODE; http++; break; - case 'Y': pcre_data->options |= SNORT_PCRE_HTTP_STAT_MSG; http++; break; default: ParseError("unknown/extra pcre option encountered"); @@ -650,12 +239,6 @@ static void pcre_parse( opts++; } - if ( http > 1 ) - ParseWarning("at most one HTTP buffer may be indicated with pcre"); - - if(pcre_data->options & (SNORT_PCRE_HTTP_BUFS)) - ValidatePcreHttpContentModifiers(pcre_data); - /* now compile the re */ DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre: compiling %s\n", re);); pcre_data->re = pcre_compile(re, compile_flags, &error, &erroffset, NULL); @@ -666,7 +249,6 @@ static void pcre_parse( "%d : %s", re, erroffset, error); } - /* now study it... */ pcre_data->pe = pcre_study(pcre_data->re, 0, &error); @@ -739,6 +321,293 @@ static void pcre_parse( ParseError("unable to parse pcre regex %s", data); } +/** + * Perform a search of the PCRE data. + * + * @param pcre_data structure that options and patterns are passed in + * @param buf buffer to search + * @param len size of buffer + * @param found_offset pointer to an integer so that we know where the search ended + * + * *found_offset will be set to -1 when the find is unsucessful OR the routine is inverted + * + * @return 1 when we find the string, 0 when we don't (unless we've been passed a flag to invert) + */ +static bool pcre_search( + const PcreData *pcre_data, + const uint8_t *buf, + int len, + int start_offset, + int *found_offset) +{ + bool matched; + int result; + + if(pcre_data == NULL + || buf == NULL + || len <= 0 + || found_offset == NULL) + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "Returning 0 because we didn't have the required parameters!\n");); + return false; + } + + *found_offset = -1; + + SnortState* ss = snort_conf->state + get_instance_id(); + + result = pcre_exec( + pcre_data->re, /* result of pcre_compile() */ + pcre_data->pe, /* result of pcre_study() */ + (const char*)buf, /* the subject string */ + len, /* the length of the subject string */ + start_offset, /* start at offset 0 in the subject */ + 0, /* options(handled at compile time */ + ss->pcre_ovector, /* vector for substring information */ + snort_conf->pcre_ovector_size);/* number of elements in the vector */ + + if(result >= 0) + { + matched = true; + + /* From the PCRE man page: When a match is successful, information + * about captured substrings is returned in pairs of integers, + * starting at the beginning of ovector, and continuing up to + * two-thirds of its length at the most. The first element of a + * pair is set to the offset of the first character in a substring, + * and the second is set to the offset of the first character after + * the end of a substring. The first pair, ovector[0] and + * ovector[1], identify the portion of the subject string matched + * by the entire pattern. The next pair is used for the first + * capturing subpattern, and so on. The value returned by + * pcre_exec() is the number of pairs that have been set. If there + * are no capturing subpatterns, the return value from a successful + * match is 1, indicating that just the first pair of offsets has + * been set. + * + * In Snort's case, the ovector size only allows for the first pair + * and a single int for scratch space. + */ + + *found_offset = ss->pcre_ovector[1]; + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "Setting Doe_ptr and found_offset: %p %d\n", doe_ptr, found_offset);); + } + else if(result == PCRE_ERROR_NOMATCH) + { + matched = false; + } + else + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "pcre_exec error : %d \n", result);); + return false; + } + + /* invert sense of match */ + if(pcre_data->options & SNORT_PCRE_INVERT) + { + matched = !matched; + } + + return matched; +} + +//------------------------------------------------------------------------- +// class methods +//------------------------------------------------------------------------- + +class PcreOption : public IpsOption +{ +public: + PcreOption(PcreData* c) : + IpsOption(s_name, RULE_OPTION_TYPE_PCRE) + { config = c; }; + + ~PcreOption(); + + uint32_t hash() const; + bool operator==(const IpsOption&) const; + + bool is_relative() + { return (config->options & SNORT_PCRE_RELATIVE) != 0; }; + + int eval(Cursor&, Packet*); + + PcreData* get_data() + { return config; }; + + void set_data(PcreData* pcre) + { config = pcre; }; + +private: + PcreData* config; +}; + +PcreOption::~PcreOption() +{ + if ( !config ) + return; + + if (config->expression) + free(config->expression); + if (config->pe) + free(config->pe); + if (config->re) + free(config->re); + + free(config); +} + +uint32_t PcreOption::hash() const +{ + int i,j,k,l,expression_len; + uint32_t a,b,c,tmp; + const PcreData *data = config; + + expression_len = strlen(data->expression); + a = b = c = 0; + + for (i=0,j=0;i 4) + k=4; + + for (l=0;lexpression + i + l) << l*8; + } + + switch (j) + { + case 0: + a += tmp; + break; + case 1: + b += tmp; + break; + case 2: + c += tmp; + break; + } + j++; + + if (j == 3) + { + mix(a,b,c); + j=0; + } + } + + if (j != 0) + { + mix(a,b,c); + } + + a += data->options; + + mix_str(a,b,c,get_name()); + final(a,b,c); + + return c; +} + +bool PcreOption::operator==(const IpsOption& ips) const +{ + if ( strcmp(get_name(), ips.get_name()) ) + return false; + + PcreOption& rhs = (PcreOption&)ips; + PcreData *left = config; + PcreData *right = rhs.config; + + if (( strcmp(left->expression, right->expression) == 0) && + ( left->options == right->options)) + { + return true; + } + + return false; +} + +int PcreOption::eval(Cursor& c, Packet*) +{ + PcreData *pcre_data = config; + int found_offset = -1; /* where is the ending location of the pattern */ + bool matched = false; + + PROFILE_VARS; + PREPROC_PROFILE_START(pcrePerfStats); + + //short circuit this for testing pcre performance impact + if (ScNoPcre()) + { + PREPROC_PROFILE_END(pcrePerfStats); + return DETECTION_OPTION_NO_MATCH; + } + + unsigned pos = c.get_delta(); + + if ( !pos && (pcre_data->options & SNORT_PCRE_RELATIVE) ) + pos = c.get_pos(); + + if ( pos > c.size() ) + return 0; + + matched = pcre_search(pcre_data, c.buffer(), c.size(), pos, &found_offset); + + if (matched) + { + if ( found_offset > 0 ) + { + c.set_pos(found_offset); + c.set_delta(found_offset); + } + PREPROC_PROFILE_END(pcrePerfStats); + return DETECTION_OPTION_MATCH; + } + + PREPROC_PROFILE_END(pcrePerfStats); + return DETECTION_OPTION_NO_MATCH; +} + +//------------------------------------------------------------------------- +// public methods +//------------------------------------------------------------------------- + +PcreData* pcre_get_data(void* pv) +{ + PcreOption* opt = (PcreOption*)pv; + return opt->get_data(); +} + +// we always advance by found_offset so no adjustments to cursor are done +// here; note also that this means relative pcre matches on overlapping +// patterns won't work. given the test pattern "ABABACD": +// +// ( sid:1; content:"ABA"; content:"C"; within:1; ) +// ( sid:2; pcre:"/ABA/"; content:"C"; within:1; ) +// +// sid 1 will fire but sid 2 will NOT. this example is easily fixed by +// using content, but more advanced pcre won't work for the relative / +// overlap case. + +bool pcre_next(PcreData* pcre) +{ + if ((pcre->options & (SNORT_PCRE_INVERT | SNORT_PCRE_ANCHORED))) + { + return false; // no go + } + + return true; // continue +} + +//------------------------------------------------------------------------- +// api methods +//------------------------------------------------------------------------- + static IpsOption* pcre_ctor( SnortConfig* sc, char *data, OptTreeNode *otn) { diff --git a/src/ips_options/ips_pcre.h b/src/ips_options/ips_pcre.h index 4ee16d1af..af0f76c3e 100644 --- a/src/ips_options/ips_pcre.h +++ b/src/ips_options/ips_pcre.h @@ -23,19 +23,7 @@ #include -// low nibble must be same as HTTP_BUFFER_* -// see detection_util.h for enum -#define SNORT_PCRE_HTTP_URI 0x00001 // check URI buffers -#define SNORT_PCRE_HTTP_HEADER 0x00002 // Check HTTP header buffer -#define SNORT_PCRE_HTTP_BODY 0x00003 // Check HTTP body buffer -#define SNORT_PCRE_HTTP_METHOD 0x00004 // Check HTTP method buffer -#define SNORT_PCRE_HTTP_COOKIE 0x00005 // Check HTTP cookie buffer -#define SNORT_PCRE_HTTP_STAT_CODE 0x00006 -#define SNORT_PCRE_HTTP_STAT_MSG 0x00007 -#define SNORT_PCRE_HTTP_RAW_URI 0x00008 -#define SNORT_PCRE_HTTP_RAW_HEADER 0x00009 -#define SNORT_PCRE_HTTP_RAW_COOKIE 0x0000A -#define SNORT_PCRE_HTTP_BUFS 0x0000F +// FIXTHIS poor encapsulation #define SNORT_PCRE_RELATIVE 0x00010 // relative to the end of the last match #define SNORT_PCRE_INVERT 0x00020 // invert detect #define SNORT_PCRE_RAWBYTES 0x00040 // Don't use decoded buffer (if available) @@ -43,21 +31,17 @@ #define SNORT_OVERRIDE_MATCH_LIMIT 0x00100 // Override default limits on match & match recursion #include -typedef struct _PcreData + +struct PcreData { pcre *re; /* compiled regex */ pcre_extra *pe; /* studied regex foo */ int options; /* sp_pcre specfic options (relative & inverse) */ char *expression; +}; - // FIXIT this doesn't need to be thread local but should be split off of this - // struct - used only at runtime for dup pcre data??? - uint32_t search_offset; -} PcreData; - -void PcreDuplicatePcreData(void *src, PcreData *pcre_dup); -int eval_dup_pcre(void* v, struct Packet* p, PcreData* alt); -int PcreAdjustRelativeOffsets(PcreData *pcre, uint32_t search_offset); +PcreData* pcre_get_data(void*); +bool pcre_next(PcreData*); #endif diff --git a/src/ips_options/ips_pkt_data.cc b/src/ips_options/ips_pkt_data.cc index 44d51484c..19ca6200e 100644 --- a/src/ips_options/ips_pkt_data.cc +++ b/src/ips_options/ips_pkt_data.cc @@ -37,8 +37,7 @@ #include "snort.h" #include "profiler.h" #include "fpdetect.h" -#include "detection/detection_defines.h" -#include "detection_util.h" +#include "framework/cursor.h" #include "framework/ips_option.h" static const char* s_name = "pkt_data"; @@ -59,22 +58,18 @@ class PktDataOption : public IpsOption { public: PktDataOption() : IpsOption(s_name, RULE_OPTION_TYPE_PKT_DATA) { }; - - int eval(Packet*); + int eval(Cursor&, Packet*); }; -int PktDataOption::eval(Packet*) +int PktDataOption::eval(Cursor& c, Packet* p) { - int rval = DETECTION_OPTION_MATCH; PROFILE_VARS; - PREPROC_PROFILE_START(pktDataPerfStats); - SetDoePtr(NULL, DOE_BUF_STD); - DetectFlag_Disable(FLAG_ALT_DETECT); + c.reset(p); PREPROC_PROFILE_END(pktDataPerfStats); - return rval; + return DETECTION_OPTION_MATCH; } static IpsOption* pkt_data_ctor( diff --git a/src/ips_options/ips_raw_data.cc b/src/ips_options/ips_raw_data.cc new file mode 100644 index 000000000..58392ac91 --- /dev/null +++ b/src/ips_options/ips_raw_data.cc @@ -0,0 +1,128 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. + ** Copyright (C) 1998-2013 Sourcefire, Inc. + ** + ** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "snort_types.h" +#include "snort_bounds.h" +#include "protocols/packet.h" +#include "parser.h" +#include "snort_debug.h" +#include "util.h" +#include "mstring.h" +#include "snort.h" +#include "profiler.h" +#include "fpdetect.h" +#include "detection/detection_defines.h" +#include "detection_util.h" +#include "framework/cursor.h" +#include "framework/ips_option.h" + +static const char* s_name = "raw_data"; + +#ifdef PERF_PROFILING +static THREAD_LOCAL PreprocStats rawDataPerfStats; + +static PreprocStats* pd_get_profile(const char* key) +{ + if ( !strcmp(key, s_name) ) + return &rawDataPerfStats; + + return nullptr; +} +#endif + +class RawDataOption : public IpsOption +{ +public: + RawDataOption() : IpsOption(s_name, RULE_OPTION_TYPE_OTHER) { }; + int eval(Cursor&, Packet*); +}; + +int RawDataOption::eval(Cursor& c, Packet* p) +{ + PROFILE_VARS; + PREPROC_PROFILE_START(rawDataPerfStats); + + c.set(s_name, p->data, p->dsize); + + PREPROC_PROFILE_END(rawDataPerfStats); + return DETECTION_OPTION_MATCH; +} + +static IpsOption* raw_data_ctor( + SnortConfig*, char *data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("raw_data takes no arguments"); + + return new RawDataOption; +} + +static void raw_data_dtor(IpsOption* p) +{ + delete p; +} + +static void raw_data_ginit(SnortConfig*) +{ +#ifdef PERF_PROFILING + RegisterOtnProfile(s_name, &rawDataPerfStats, pd_get_profile); +#endif +} + +static const IpsApi raw_data_api = +{ + { + PT_IPS_OPTION, + s_name, + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 0, 0, + raw_data_ginit, + nullptr, + nullptr, + nullptr, + raw_data_ctor, + raw_data_dtor, + nullptr +}; + +#ifdef BUILDING_SO +SO_PUBLIC const BaseApi* snort_plugins[] = +{ + &raw_data_api.base, + nullptr +}; +#else +const BaseApi* ips_raw_data = &raw_data_api.base; +#endif + diff --git a/src/ips_options/replace.cc b/src/ips_options/ips_replace.cc similarity index 66% rename from src/ips_options/replace.cc rename to src/ips_options/ips_replace.cc index 55fba27d4..b45489eb7 100644 --- a/src/ips_options/replace.cc +++ b/src/ips_options/ips_replace.cc @@ -19,13 +19,15 @@ ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "replace.h" +#include "ips_replace.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include +#include +using namespace std; #include "snort_types.h" #include "snort_bounds.h" @@ -35,11 +37,12 @@ #include "ips_content.h" #include "snort.h" #include "packet_io/sfdaq.h" +#include "framework/cursor.h" +#include "framework/ips_option.h" #define MAX_PATTERN_SIZE 2048 -static void Replace_Parse( - char *rule, OptTreeNode*, PatternMatchData* pmd) +static void replace_parse(char* args, string& s) { char tmp_buf[MAX_PATTERN_SIZE]; @@ -57,20 +60,19 @@ static void Replace_Parse( int pending = 0; int cnt = 0; int literal = 0; - int ret; - if ( !rule ) + if ( !args ) { ParseError("missing argument to 'replace' option"); } /* clear out the temp buffer */ memset(tmp_buf, 0, MAX_PATTERN_SIZE); - while(isspace((int)*rule)) - rule++; + while(isspace((int)*args)) + args++; /* find the start of the data */ - start_ptr = strchr(rule, '"'); + start_ptr = strchr(args, '"'); if(start_ptr == NULL) { @@ -297,36 +299,15 @@ static void Replace_Parse( ParseError("Replace hexmode is not completed"); } - if((pmd->replace_buf = (char *) calloc(dummy_size+1, - sizeof(char))) == NULL) - { - ParseError("Replace pattern_buf malloc failed"); - - } - - ret = SafeMemcpy(pmd->replace_buf, tmp_buf, dummy_size, - pmd->replace_buf, (pmd->replace_buf+dummy_size)); - - if (ret == SAFEMEM_ERROR) - { - ParseError("Replace SafeMemcpy failed"); - } - - pmd->replace_size = dummy_size; - pmd->replace_depth = (int*)SnortAlloc(get_instance_max() * sizeof(int)); - - DEBUG_WRAP(DebugMessage(DEBUG_PARSER, - "pmd (%p) replace_size(%d) replace_buf(%s)\n", pmd, - pmd->replace_size, pmd->replace_buf);); + s.assign(tmp_buf, dummy_size); } -void PayloadReplaceInit( - PatternMatchData* pmd, char *data, OptTreeNode * otn) +static bool replace_ok() { static int warned = 0; - if( !ScInlineMode() ) - return; + if ( !ScInlineMode() ) + return false; if ( !DAQ_CanReplace() ) { @@ -336,20 +317,23 @@ void PayloadReplaceInit( " can't replace packets.\n"); warned = 1; } - return; + return false; } - - Replace_Parse(data, otn, pmd); + return true; } -typedef struct { - const char* data; - int size; - int depth; -} Replacement; +//-------------------------------------------------------------------------- +// queue foo +//-------------------------------------------------------------------------- + +struct Replacement +{ + string data; + int offset; +}; #define MAX_REPLACEMENTS 32 -static THREAD_LOCAL Replacement rpl[MAX_REPLACEMENTS]; +static THREAD_LOCAL Replacement* rpl; static THREAD_LOCAL int num_rpl = 0; void Replace_ResetQueue(void) @@ -357,7 +341,7 @@ void Replace_ResetQueue(void) num_rpl = 0; } -void Replace_QueueChange(PatternMatchData* pmd) +void Replace_QueueChange(string& s, int off) { Replacement* r; @@ -366,23 +350,22 @@ void Replace_QueueChange(PatternMatchData* pmd) r = rpl + num_rpl++; - r->data = pmd->replace_buf; - r->size = pmd->replace_size; - r->depth = pmd->replace_depth[get_instance_id()]; + r->data = s; + r->offset = off; } static inline void Replace_ApplyChange(Packet *p, Replacement* r) { - uint8_t* start = (uint8_t*)p->data + r->depth; + uint8_t* start = (uint8_t*)p->data + r->offset; const uint8_t* end = p->data + p->dsize; unsigned len; - if ( (start + r->size) >= end ) - len = p->dsize - r->depth; + if ( (start + r->data.size()) >= end ) + len = p->dsize - r->offset; else - len = r->size; + len = r->data.size(); - memcpy(start, r->data, len); + memcpy(start, r->data.c_str(), len); } // FIXIT this could be ContentOption::action() @@ -400,3 +383,200 @@ void Replace_ModifyPacket(Packet *p) num_rpl = 0; } +//------------------------------------------------------------------------- +// replace rule option +//------------------------------------------------------------------------- + +static const char* s_name = "replace"; + +#ifdef PERF_PROFILING +static THREAD_LOCAL PreprocStats replacePerfStats; + +static PreprocStats* pd_get_profile(const char* key) +{ + if ( !strcmp(key, s_name) ) + return &replacePerfStats; + + return nullptr; +} +#endif + +class ReplaceOption : public IpsOption +{ +public: + ReplaceOption(string&); + ~ReplaceOption(); + + int eval(Cursor&, Packet*); + void action(Packet*); + + uint32_t hash() const; + bool operator==(const IpsOption&) const; + + void store(int off) + { offset[get_instance_id()] = off; }; + + bool pending() + { return offset[get_instance_id()] >= 0; }; + + int pos() + { return offset[get_instance_id()]; }; +private: + string repl; + int* offset; /* >=0 is offset to start of replace */ +}; + +ReplaceOption::ReplaceOption(string& s) : IpsOption(s_name, RULE_OPTION_TYPE_OTHER) +{ + unsigned n = get_instance_max(); + offset = new int[n]; + + for ( unsigned i = 0; i < n; i++ ) + offset[i] = -1; + + repl = s; +} + +ReplaceOption::~ReplaceOption() +{ + delete[] offset; +} + +uint32_t ReplaceOption::hash() const +{ + uint32_t a,b,c; + + const char* s = repl.c_str(); + unsigned n = repl.size(); + + a = 0; + b = n; + c = 0; + + mix(a,b,c); + mix_str(a,b,c,s,n); + mix_str(a,b,c,get_name()); + final(a,b,c); + + return c; +} + +bool ReplaceOption::operator==(const IpsOption& ips) const +{ + if ( strcmp(get_name(), ips.get_name()) ) + return false; + + ReplaceOption& rhs = (ReplaceOption&)ips; + + if ( repl != rhs.repl ) + return false; + + return true; +} + +int ReplaceOption::eval(Cursor& c, Packet* p) +{ + PROFILE_VARS; + PREPROC_PROFILE_START(replacePerfStats); + + if ( PacketWasCooked(p) ) + return false; + + if ( !c.is("pkt_data") ) + return DETECTION_OPTION_NO_MATCH; + + if ( c.length() < repl.size() ) + return DETECTION_OPTION_NO_MATCH; + + store(c.get_pos()); + + PREPROC_PROFILE_END(replacePerfStats); + return DETECTION_OPTION_MATCH; +} + +// FIXIT this may need to be apply change here +// and queue change from some other point +// (almost certainly broke) +void ReplaceOption::action(Packet*) +{ + PROFILE_VARS; + PREPROC_PROFILE_START(replacePerfStats); + + if ( pending() ) + Replace_QueueChange(repl, pos()); + + PREPROC_PROFILE_END(replacePerfStats); +} + +static IpsOption* replace_ctor( + SnortConfig*, char *data, OptTreeNode* otn) +{ + if ( !replace_ok() ) + return nullptr; + + string s; + replace_parse(data, s); + + ReplaceOption* opt = new ReplaceOption(s); + + if ( otn_set_agent(otn, opt) ) + return opt; + + delete opt; + ParseError("At most one action per rule is allowed"); + return nullptr; +} + +static void replace_dtor(IpsOption* p) +{ + delete p; +} + +static void replace_ginit(SnortConfig*) +{ +#ifdef PERF_PROFILING + RegisterOtnProfile(s_name, &replacePerfStats, pd_get_profile); +#endif +} + +static void replace_tinit(SnortConfig*) +{ + rpl = new Replacement[MAX_REPLACEMENTS]; +} + +static void replace_tterm(SnortConfig*) +{ + delete[] rpl; +} + +static const IpsApi replace_api = +{ + { + PT_IPS_OPTION, + s_name, + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 0, 0, + replace_ginit, + nullptr, + replace_tinit, + replace_tterm, + replace_ctor, + replace_dtor, + nullptr +}; + +#ifdef BUILDING_SO +SO_PUBLIC const BaseApi* snort_plugins[] = +{ + &replace_api.base, + nullptr +}; +#else +const BaseApi* ips_replace = &replace_api.base; +#endif + diff --git a/src/ips_options/replace.h b/src/ips_options/ips_replace.h similarity index 71% rename from src/ips_options/replace.h rename to src/ips_options/ips_replace.h index 9961304ac..045918dc3 100644 --- a/src/ips_options/replace.h +++ b/src/ips_options/ips_replace.h @@ -32,25 +32,5 @@ void Replace_ResetQueue(void); void Replace_QueueChange(PatternMatchData*); void Replace_ModifyPacket(Packet*); -static inline void Replace_ResetOffset(PatternMatchData* pmd) -{ - if ( pmd->replace_depth ) - pmd->replace_depth[get_instance_id()] = -1; -} - -static inline void Replace_StoreOffset(PatternMatchData* pmd, int detect_depth) -{ - if ( pmd->replace_depth ) - pmd->replace_depth[get_instance_id()] = detect_depth; -} - -static inline int Replace_OffsetStored(PatternMatchData* pmd) -{ - if ( pmd->replace_depth ) - return pmd->replace_depth[get_instance_id()] >= 0; - - return 0; -} - #endif diff --git a/src/ips_options/ips_rpc.cc b/src/ips_options/ips_rpc.cc index 44df9474f..407e2c358 100644 --- a/src/ips_options/ips_rpc.cc +++ b/src/ips_options/ips_rpc.cc @@ -83,7 +83,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: RpcCheckData config; @@ -132,7 +132,7 @@ bool RpcOption::operator==(const IpsOption& ips) const return false; } -int RpcOption::eval(Packet *p) +int RpcOption::eval(Cursor&, Packet *p) { RpcCheckData *ds_ptr = &config; unsigned char* c=(unsigned char*)p->data; diff --git a/src/ips_options/ips_sameip.cc b/src/ips_options/ips_sameip.cc index ba78eb1ad..eae1dc329 100644 --- a/src/ips_options/ips_sameip.cc +++ b/src/ips_options/ips_sameip.cc @@ -59,14 +59,14 @@ class SameIpOption : public IpsOption public: SameIpOption() : IpsOption(s_name) { }; - int eval(Packet*); + int eval(Cursor&, Packet*); }; //------------------------------------------------------------------------- // class methods //------------------------------------------------------------------------- -int SameIpOption::eval(Packet *p) +int SameIpOption::eval(Cursor&, Packet *p) { int rval = DETECTION_OPTION_NO_MATCH; PROFILE_VARS; diff --git a/src/ips_options/ips_seq.cc b/src/ips_options/ips_seq.cc index 409a4a3a8..b64b3d8c6 100644 --- a/src/ips_options/ips_seq.cc +++ b/src/ips_options/ips_seq.cc @@ -70,7 +70,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: TcpSeqCheckData config; @@ -112,7 +112,7 @@ bool TcpSeqOption::operator==(const IpsOption& ips) const return false; } -int TcpSeqOption::eval(Packet *p) +int TcpSeqOption::eval(Cursor&, Packet *p) { TcpSeqCheckData *tcpSeqCheckData = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_session.cc b/src/ips_options/ips_session.cc index 041c95fd3..1b7e7a8e3 100644 --- a/src/ips_options/ips_session.cc +++ b/src/ips_options/ips_session.cc @@ -105,7 +105,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: SessionData config; @@ -150,7 +150,7 @@ bool SessionOption::operator==(const IpsOption& ips) const return false; } -int SessionOption::eval(Packet *p) +int SessionOption::eval(Cursor&, Packet *p) { SessionData *session_data = &config; FILE *session; /* session file ptr */ diff --git a/src/ips_options/ips_so.cc b/src/ips_options/ips_so.cc index 4533f7b07..1075c70d0 100644 --- a/src/ips_options/ips_so.cc +++ b/src/ips_options/ips_so.cc @@ -35,7 +35,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet* p) + int eval(Cursor&, Packet* p) { return func(data, p); }; private: diff --git a/src/ips_options/ips_tos.cc b/src/ips_options/ips_tos.cc index 86927cc68..7641d48fc 100644 --- a/src/ips_options/ips_tos.cc +++ b/src/ips_options/ips_tos.cc @@ -70,7 +70,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); IpTosData* get_data() { return &config; }; @@ -120,7 +120,7 @@ bool IpTosOption::operator==(const IpsOption& ips) const * value in the rule. This is useful to detect things like the "bubonic" DoS tool. */ -int IpTosOption::eval(Packet *p) +int IpTosOption::eval(Cursor&, Packet *p) { IpTosData *ipTosData = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_ttl.cc b/src/ips_options/ips_ttl.cc index 76e20cd04..c78cf5473 100644 --- a/src/ips_options/ips_ttl.cc +++ b/src/ips_options/ips_ttl.cc @@ -78,7 +78,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: TtlCheckData config; @@ -123,7 +123,7 @@ bool TtlOption::operator==(const IpsOption& ips) const return false; } -int TtlOption::eval(Packet *p) +int TtlOption::eval(Cursor&, Packet *p) { TtlCheckData *ttlCheckData = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_urilen.cc b/src/ips_options/ips_urilen.cc index 9ec6e809b..fdd35b41a 100644 --- a/src/ips_options/ips_urilen.cc +++ b/src/ips_options/ips_urilen.cc @@ -77,7 +77,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: UriLenCheckData config; @@ -127,7 +127,7 @@ bool UriLenOption::operator==(const IpsOption& ips) const return false; } -int UriLenOption::eval(Packet*) +int UriLenOption::eval(Cursor&, Packet*) { UriLenCheckData *udata = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/ips_options/ips_window.cc b/src/ips_options/ips_window.cc index 739183900..749d788a0 100644 --- a/src/ips_options/ips_window.cc +++ b/src/ips_options/ips_window.cc @@ -72,7 +72,7 @@ public: uint32_t hash() const; bool operator==(const IpsOption&) const; - int eval(Packet*); + int eval(Cursor&, Packet*); private: TcpWinCheckData config; @@ -115,7 +115,7 @@ bool TcpWinOption::operator==(const IpsOption& ips) const return false; } -int TcpWinOption::eval(Packet *p) +int TcpWinOption::eval(Cursor&, Packet *p) { TcpWinCheckData *tcpWinCheckData = &config; int rval = DETECTION_OPTION_NO_MATCH; diff --git a/src/main/analyzer.cc b/src/main/analyzer.cc index abc2d4e97..656eed3f2 100644 --- a/src/main/analyzer.cc +++ b/src/main/analyzer.cc @@ -114,7 +114,7 @@ void Analyzer::analyze() command = AC_NONE; } - if ( DAQ_Acquire(1, main_func, NULL) ) + if ( DAQ_Acquire(0, main_func, NULL) ) break; ++count; diff --git a/src/main/snort.cc b/src/main/snort.cc index 1aecb21f1..99480ffc3 100644 --- a/src/main/snort.cc +++ b/src/main/snort.cc @@ -108,7 +108,7 @@ using namespace std; #include "target_based/sftarget_reader.h" #include "stream/stream_api.h" #include "stream/stream.h" -#include "ips_options/replace.h" +#include "ips_options/ips_replace.h" #ifdef INTEL_SOFT_CPM #include "search/intel_soft_cpm.h" diff --git a/src/main/snort_config.h b/src/main/snort_config.h index d64667e35..a849a122c 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -227,10 +227,9 @@ struct SnortConfig * and for Icmp we map the dst port to the Icmp type. This * allows us to use the decode packet information to in O(1) * select a group of rules to apply to the packet. These - * rules may have uricontent, content, or they may be no content - * rules, or any combination. We process the uricontent 1st, - * then the content, and then the no content rules for udp/tcp - * and icmp, than we process the ip rules. */ + * rules may or may not have content. We process the content + * 1st and then the no content rules for udp/tcp and icmp, and + * then we process the ip rules. */ PORT_RULE_MAP *prmIpRTNX; PORT_RULE_MAP *prmTcpRTNX; PORT_RULE_MAP *prmUdpRTNX; diff --git a/src/managers/module_manager.cc b/src/managers/module_manager.cc index 73aef49f9..62341e6fe 100644 --- a/src/managers/module_manager.cc +++ b/src/managers/module_manager.cc @@ -209,7 +209,7 @@ static void dump_field(string& key, const char* pfx, const Parameter* p, bool li cout << ": " << p->help; if ( p->range ) - cout << " { " << p->range << " }"; + cout << " { " << (char*)p->range << " }"; #else cout << item(); cout << p->get_type(); diff --git a/src/network_inspectors/arp_spoof/arp_spoof.cc b/src/network_inspectors/arp_spoof/arp_spoof.cc index 1ae919262..ea2a83e41 100644 --- a/src/network_inspectors/arp_spoof/arp_spoof.cc +++ b/src/network_inspectors/arp_spoof/arp_spoof.cc @@ -339,7 +339,6 @@ static const InspectApi as_api = IT_PROTOCOL, PROTO_BIT__ARP, nullptr, // service - nullptr, // contents as_init, nullptr, // term as_ctor, @@ -349,8 +348,7 @@ static const InspectApi as_api = nullptr, // ssn as_sum, as_stats, - as_reset, - nullptr // getbuf + as_reset }; #ifdef BUILDING_SO diff --git a/src/network_inspectors/normalize/normalize.cc b/src/network_inspectors/normalize/normalize.cc index 4fe211b9c..18ec90226 100644 --- a/src/network_inspectors/normalize/normalize.cc +++ b/src/network_inspectors/normalize/normalize.cc @@ -296,7 +296,6 @@ static const InspectApi no_api = IT_PACKET, PROTO_BITS, nullptr, // service - nullptr, // contents no_init, nullptr, // term no_ctor, @@ -306,8 +305,7 @@ static const InspectApi no_api = nullptr, // ssn no_sum, no_stats, - no_reset, - nullptr // getbuf + no_reset }; const BaseApi* nin_normalize = &no_api.base; diff --git a/src/network_inspectors/perf_monitor/perf_monitor.cc b/src/network_inspectors/perf_monitor/perf_monitor.cc index 921154ad2..154fdbd49 100644 --- a/src/network_inspectors/perf_monitor/perf_monitor.cc +++ b/src/network_inspectors/perf_monitor/perf_monitor.cc @@ -407,7 +407,6 @@ static const InspectApi pm_api = IT_PACKET, PROTO_BIT__ALL, nullptr, // service - nullptr, // contents pm_init, nullptr, // term pm_ctor, @@ -417,8 +416,7 @@ static const InspectApi pm_api = nullptr, // ssn pm_sum, pm_stats, - pm_reset, - nullptr // getbuf + pm_reset }; const BaseApi* nin_perf_monitor = &pm_api.base; diff --git a/src/network_inspectors/port_scan/port_scan.cc b/src/network_inspectors/port_scan/port_scan.cc index e89a5c6c4..8e365537f 100644 --- a/src/network_inspectors/port_scan/port_scan.cc +++ b/src/network_inspectors/port_scan/port_scan.cc @@ -1032,7 +1032,6 @@ static const InspectApi sp_api = IT_PROTOCOL, PROTO_BIT__IP|PROTO_BIT__ICMP|PROTO_BIT__TCP|PROTO_BIT__UDP, // FIXIT dynamic assign nullptr, // service - nullptr, // contents sp_init, nullptr, // term sp_ctor, @@ -1042,8 +1041,7 @@ static const InspectApi sp_api = nullptr, // ssn sp_sum, sp_stats, - sp_reset, - nullptr // getbuf + sp_reset }; #ifdef BUILDING_SO diff --git a/src/parser/mstring.cc b/src/parser/mstring.cc index 2d13d65de..a3c750a71 100644 --- a/src/parser/mstring.cc +++ b/src/parser/mstring.cc @@ -564,344 +564,3 @@ SO_PUBLIC int mContainsSubstr(const char *buf, int b_len, const char *pat, int p return 0; } - - - -/**************************************************************** - * - * Function: make_skip(char *, int) - * - * Purpose: Create a Boyer-Moore skip table for a given pattern - * - * Parameters: - * ptrn => pattern - * plen => length of the data in the pattern buffer - * - * Returns: - * int * - the skip table - * - ****************************************************************/ -int *make_skip(char *ptrn, int plen) -{ - int i; - int *skip = (int *) SnortAlloc(256* sizeof(int)); - - for ( i = 0; i < 256; i++ ) - skip[i] = plen + 1; - - while(plen != 0) - skip[(unsigned char) *ptrn++] = plen--; - - return skip; -} - - - -/**************************************************************** - * - * Function: make_shift(char *, int) - * - * Purpose: Create a Boyer-Moore shift table for a given pattern - * - * Parameters: - * ptrn => pattern - * plen => length of the data in the pattern buffer - * - * Returns: - * int * - the shift table - * - ****************************************************************/ -int *make_shift(char *ptrn, int plen) -{ - int *shift = (int *) SnortAlloc(plen * sizeof(int)); - int *sptr = shift + plen - 1; - char *pptr = ptrn + plen - 1; - char c; - - c = ptrn[plen - 1]; - - *sptr = 1; - - while(sptr-- != shift) - { - char *p1 = ptrn + plen - 2, *p2, *p3; - - do - { - while(p1 >= ptrn && *p1-- != c); - - p2 = ptrn + plen - 2; - p3 = p1; - - while(p3 >= ptrn && *p3-- == *p2-- && p2 >= pptr); - } - while(p3 >= ptrn && p2 >= pptr); - - *sptr = shift + plen - sptr + p2 - p3; - - pptr--; - } - - return shift; -} - - - -/**************************************************************** - * - * Function: mSearch(char *, int, char *, int) - * - * Purpose: Determines if a string contains a (non-regex) - * substring. - * - * Parameters: - * buf => data buffer we want to find the data in - * blen => data buffer length - * ptrn => pattern to find - * plen => length of the data in the pattern buffer - * skip => the B-M skip array - * shift => the B-M shift array - * - * Returns: - * Integer value, 1 on success (str constains substr), 0 on - * failure (substr not in str) - * - ****************************************************************/ -SO_PUBLIC int mSearch(const char *buf, int blen, const char *ptrn, int plen, int *skip, int *shift) -{ - int b_idx = plen; - -#ifdef DEBUG_MSGS - char *hexbuf; - int cmpcnt = 0; -#endif - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,"buf: %p blen: %d ptrn: %p " - "plen: %d\n", buf, blen, ptrn, plen);); - -#ifdef DEBUG_MSGS - hexbuf = fasthex((const u_char *)buf, blen); - DebugMessage(DEBUG_PATTERN_MATCH,"buf: %s\n", hexbuf); - free(hexbuf); - hexbuf = fasthex((const u_char *)ptrn, plen); - DebugMessage(DEBUG_PATTERN_MATCH,"ptrn: %s\n", hexbuf); - free(hexbuf); - DebugMessage(DEBUG_PATTERN_MATCH,"buf: %p blen: %d ptrn: %p " - "plen: %d\n", buf, blen, ptrn, plen); -#endif /* DEBUG_MSGS */ - if(plen == 0) - return 1; - - while(b_idx <= blen) - { - int p_idx = plen, skip_stride, shift_stride; - - while(buf[--b_idx] == ptrn[--p_idx]) - { -#ifdef DEBUG_MSGS - cmpcnt++; -#endif - if(b_idx < 0) - return 0; - - if(p_idx == 0) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "match: compares = %d.\n", cmpcnt);); - UpdateDoePtr(((const uint8_t *)&(buf[b_idx]) + plen), 0); - return 1; - } - } - - skip_stride = skip[(unsigned char) buf[b_idx]]; - shift_stride = shift[p_idx]; - - b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride; - } - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "no match: compares = %d.\n", cmpcnt);); - - return 0; -} - - - -/**************************************************************** - * - * Function: mSearchCI(char *, int, char *, int) - * - * Purpose: Determines if a string contains a (non-regex) - * substring matching is case insensitive - * - * Parameters: - * buf => data buffer we want to find the data in - * blen => data buffer length - * ptrn => pattern to find - * plen => length of the data in the pattern buffer - * skip => the B-M skip array - * shift => the B-M shift array - * - * Returns: - * Integer value, 1 on success (str constains substr), 0 on - * failure (substr not in str) - * - ****************************************************************/ -SO_PUBLIC int mSearchCI(const char *buf, int blen, const char *ptrn, int plen, int *skip, int *shift) -{ - int b_idx = plen; -#ifdef DEBUG_MSGS - int cmpcnt = 0; -#endif - - if(plen == 0) - return 1; - - while(b_idx <= blen) - { - int p_idx = plen, skip_stride, shift_stride; - - while((unsigned char) ptrn[--p_idx] == - toupper((unsigned char) buf[--b_idx])) - { -#ifdef DEBUG_MSGS - cmpcnt++; -#endif - if(p_idx == 0) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "match: compares = %d.\n", - cmpcnt);); - UpdateDoePtr(((const uint8_t *)&(buf[b_idx]) + plen), 0); - return 1; - } - } - - skip_stride = skip[toupper((unsigned char) buf[b_idx])]; - shift_stride = shift[p_idx]; - - b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride; - } - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "no match: compares = %d.\n", cmpcnt);); - - return 0; -} - - -/**************************************************************** - * - * Function: mSearchREG(char *, int, char *, int) - * - * Purpose: Determines if a string contains a (regex) - * substring. - * - * Parameters: - * buf => data buffer we want to find the data in - * blen => data buffer length - * ptrn => pattern to find - * plen => length of the data in the pattern buffer - * skip => the B-M skip array - * shift => the B-M shift array - * - * Returns: - * Integer value, 1 on success (str constains substr), 0 on - * failure (substr not in str) - * - ****************************************************************/ -SO_PUBLIC int mSearchREG( - const char *buf, int blen, const char *ptrn, int plen, int *skip, int *shift) -{ - int b_idx = plen; - int literal = 0; - int regexcomp = 0; -#ifdef DEBUG_MSGS - int cmpcnt = 0; -#endif /* DEBUG_MSGS */ - - DEBUG_WRAP( - DebugMessage(DEBUG_PATTERN_MATCH, "buf: %p blen: %d ptrn: %p " - " plen: %d b_idx: %d\n", buf, blen, ptrn, plen, b_idx); - DebugMessage(DEBUG_PATTERN_MATCH, "packet data: \"%s\"\n", buf); - DebugMessage(DEBUG_PATTERN_MATCH, "matching for \"%s\"\n", ptrn); - ); - - if(plen == 0) - return 1; - - while(b_idx <= blen) - { - int p_idx = plen, skip_stride, shift_stride; - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Looping... " - "([%d]0x%X (%c) -> [%d]0x%X(%c))\n", - b_idx, buf[b_idx-1], - buf[b_idx-1], - p_idx, ptrn[p_idx-1], ptrn[p_idx-1]);); - - while(buf[--b_idx] == ptrn[--p_idx] - || (ptrn[p_idx] == '?' && !literal) - || (ptrn[p_idx] == '*' && !literal) - || (ptrn[p_idx] == '\\' && !literal)) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "comparing: b:%c -> p:%c\n", - buf[b_idx], ptrn[p_idx]);); -#ifdef DEBUG_MSGS - cmpcnt++; -#endif - - if(literal) - literal = 0; - if(!literal && ptrn[p_idx] == '\\') - literal = 1; - if(ptrn[p_idx] == '*') - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,"Checking wildcard matching...\n");); - while(p_idx != 0 && ptrn[--p_idx] == '*'); /* fool-proof */ - - while(buf[--b_idx] != ptrn[p_idx]) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "comparing: b[%d]:%c -> p[%d]:%c\n", - b_idx, buf[b_idx], p_idx, ptrn[p_idx]);); - - regexcomp++; - if(b_idx == 0) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "b_idx went to 0, returning 0\n");) - return 0; - } - } - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "got wildcard final char match! (b[%d]: %c -> p[%d]: %c\n", b_idx, buf[b_idx], p_idx, ptrn[p_idx]);); - } - - if(p_idx == 0) - { - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "match: compares = %d.\n", - cmpcnt);); - return 1; - } - - if(b_idx == 0) - break; - } - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "skip-shifting...\n");); - skip_stride = skip[(unsigned char) buf[b_idx]]; - shift_stride = shift[p_idx]; - - b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "b_idx skip-shifted to %d\n", b_idx);); - b_idx += regexcomp; - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, - "b_idx regex compensated %d steps, to %d\n", regexcomp, b_idx);); - regexcomp = 0; - } - - DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "no match: compares = %d, b_idx = %d, " - "blen = %d\n", cmpcnt, b_idx, blen);); - - return 0; -} - diff --git a/src/parser/mstring.h b/src/parser/mstring.h index 3ea5389ac..c3de46db8 100644 --- a/src/parser/mstring.h +++ b/src/parser/mstring.h @@ -31,10 +31,5 @@ char ** mSplit(const char *, const char *, const int, int *, const char); void mSplitFree(char ***toks, int numtoks); int mContainsSubstr(const char *, int, const char *, int); -int mSearch(const char *, int, const char *, int, int *, int *); -int mSearchCI(const char *, int, const char *, int, int *, int *); -int mSearchREG(const char *, int, const char *, int, int *, int *); -int *make_skip(char *, int); -int *make_shift(char *, int); #endif /* MSTRING_H */ diff --git a/src/parser/parse_rule.cc b/src/parser/parse_rule.cc index 9719f80db..8063575f1 100644 --- a/src/parser/parse_rule.cc +++ b/src/parser/parse_rule.cc @@ -96,7 +96,6 @@ typedef struct unsigned int sid; int dir; char content; - char uricontent; } port_entry_t; @@ -199,8 +198,6 @@ static void port_list_print( port_list_t * plist) plist->pl_array[i].dst_port ); LogMessage(" content %d", plist->pl_array[i].content); - LogMessage(" uricontent %d", - plist->pl_array[i].uricontent); LogMessage(" }\n"); } } @@ -294,7 +291,7 @@ static int FinishPortListRule(rule_port_tables_t *port_tables, RuleTreeNode *rtn rim_index = otn->ruleIndex; /* Add up the nocontent rules */ - if (!pe->content && !pe->uricontent) + if ( !pe->content ) prc->nc++; /* If not an any-any rule test for port bleedover, if we are using a @@ -1640,29 +1637,7 @@ void parse_rule( /* See what kind of content is going in the fast pattern matcher */ { - /* Since http_cookie content is not used in fast pattern matcher, - * need to iterate the entire list */ - if ( otn_has_plugin(otn, RULE_OPTION_TYPE_CONTENT_URI) ) - { - OptFpList* fpl = otn->opt_func; - - while ( fpl ) - { - if ( fpl->type == RULE_OPTION_TYPE_CONTENT_URI ) - { - PatternMatchData* pmd = get_pmd(fpl); - - if ( IsHttpBufFpEligible(pmd->http_buffer) ) - { - pe.uricontent = 1; - break; - } - } - fpl = fpl->next; - } - } - - if (!pe.uricontent && otn_has_plugin(otn, RULE_OPTION_TYPE_CONTENT) ) + if ( otn_has_plugin(otn, RULE_OPTION_TYPE_CONTENT) ) { pe.content = 1; } diff --git a/src/service_inspectors/back_orifice/back_orifice.cc b/src/service_inspectors/back_orifice/back_orifice.cc index 09f1c3b2e..0907100c4 100644 --- a/src/service_inspectors/back_orifice/back_orifice.cc +++ b/src/service_inspectors/back_orifice/back_orifice.cc @@ -628,7 +628,6 @@ static const InspectApi bo_api = IT_PROTOCOL, PROTO_BIT__UDP, nullptr, // service - nullptr, // contents bo_init, nullptr, // term bo_ctor, @@ -638,8 +637,7 @@ static const InspectApi bo_api = nullptr, // ssn bo_sum, bo_stats, - bo_reset, - nullptr // getbuf + bo_reset }; #ifdef BUILDING_SO diff --git a/src/service_inspectors/ftp_telnet/ftp.cc b/src/service_inspectors/ftp_telnet/ftp.cc index 1e3d2eba1..16beec8ae 100644 --- a/src/service_inspectors/ftp_telnet/ftp.cc +++ b/src/service_inspectors/ftp_telnet/ftp.cc @@ -718,7 +718,6 @@ static const InspectApi fs_api = IT_SERVICE, PROTO_BIT__TCP, "ftp", // FIXIT add ftp-data inspector - nullptr, // contents fs_init, nullptr, // term fs_ctor, @@ -728,8 +727,7 @@ static const InspectApi fs_api = nullptr, // ssn fs_sum, fs_stats, - fs_reset, - nullptr // getbuf + fs_reset }; #ifdef BUILDING_SO diff --git a/src/service_inspectors/ftp_telnet/telnet.cc b/src/service_inspectors/ftp_telnet/telnet.cc index 096340f37..1d0ec2f8f 100644 --- a/src/service_inspectors/ftp_telnet/telnet.cc +++ b/src/service_inspectors/ftp_telnet/telnet.cc @@ -346,7 +346,6 @@ const InspectApi tn_api = IT_SERVICE, PROTO_BIT__TCP, "telnet", - nullptr, // contents tn_init, nullptr, // term tn_ctor, @@ -357,6 +356,5 @@ const InspectApi tn_api = tn_sum, tn_stats, tn_reset, - nullptr // getbuf }; diff --git a/src/service_inspectors/http_inspect/CMakeLists.txt b/src/service_inspectors/http_inspect/CMakeLists.txt index c427ea22c..fe2368e29 100644 --- a/src/service_inspectors/http_inspect/CMakeLists.txt +++ b/src/service_inspectors/http_inspect/CMakeLists.txt @@ -2,6 +2,7 @@ set (FILE_LIST http_inspect.cc + http_inspect.h hi_main.cc hi_main.h hi_ad.cc @@ -14,6 +15,7 @@ set (FILE_LIST hi_cmd_lookup.cc hi_cmd_lookup.h hi_include.h + hi_ips_options.cc hi_mi.cc hi_mi.h hi_norm.cc diff --git a/src/service_inspectors/http_inspect/Makefile.am b/src/service_inspectors/http_inspect/Makefile.am index 0b78f41d3..a43f8e0cd 100644 --- a/src/service_inspectors/http_inspect/Makefile.am +++ b/src/service_inspectors/http_inspect/Makefile.am @@ -1,7 +1,7 @@ AUTOMAKE_OPTIONS=foreign no-dependencies file_list = \ -http_inspect.cc \ +http_inspect.cc http_inspect.h \ hi_main.cc hi_main.h \ hi_ad.cc hi_ad.h \ hi_client.cc hi_client.h \ @@ -10,6 +10,7 @@ hi_client_stateful.h \ hi_cmd_lookup.cc hi_cmd_lookup.h \ hi_events.h \ hi_include.h \ +hi_ips_options.cc \ hi_mi.cc hi_mi.h \ hi_module.cc hi_module.h \ hi_norm.cc hi_norm.h \ diff --git a/src/service_inspectors/http_inspect/hi_ips_options.cc b/src/service_inspectors/http_inspect/hi_ips_options.cc new file mode 100644 index 000000000..619e446d2 --- /dev/null +++ b/src/service_inspectors/http_inspect/hi_ips_options.cc @@ -0,0 +1,482 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2002-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "snort_types.h" +#include "treenodes.h" +#include "protocols/packet.h" +#include "parser.h" +#include "util.h" +#include "snort_debug.h" +#include "snort.h" +#include "profiler.h" +#include "fpdetect.h" +#include "detection/detection_defines.h" +#include "detection/detection_util.h" +#include "framework/ips_option.h" +#include "framework/cursor.h" + +//------------------------------------------------------------------------- +// api methods +//------------------------------------------------------------------------- + +static const char* s_name = "http_ips"; + +#ifdef PERF_PROFILING +static THREAD_LOCAL PreprocStats httpIpsPerfStats; + +static PreprocStats* hi_ips_get_profile(const char* key) +{ + if ( !strcmp(key, s_name) ) + return &httpIpsPerfStats; + + return nullptr; +} +#endif + +static void hi_ips_dtor(IpsOption* p) +{ + delete p; +} + +static void hi_ips_ginit(SnortConfig*) +{ +#ifdef PERF_PROFILING + RegisterOtnProfile(s_name, &httpIpsPerfStats, hi_ips_get_profile); +#endif +} + +//------------------------------------------------------------------------- +// generic buffer stuffer +//------------------------------------------------------------------------- + +class HttpIpsOption : public IpsOption +{ +public: + HttpIpsOption(const char* s, HTTP_BUFFER b) : IpsOption(s) + { key = s; type = b; }; + + int eval(Cursor&, Packet*); +private: + const char* key; + HTTP_BUFFER type; +}; + +int HttpIpsOption::eval(Cursor& c, Packet*) +{ + PROFILE_VARS; + PREPROC_PROFILE_START(httpIpsPerfStats); + + int rval; + const HttpBuffer* hb = GetHttpBuffer(type); + + if ( !hb ) + rval = DETECTION_OPTION_MATCH; + else + { + c.set(key, hb->buf, hb->length); + rval = DETECTION_OPTION_MATCH; + } + + PREPROC_PROFILE_END(httpIpsPerfStats); + return rval; +} + +//------------------------------------------------------------------------- +// http_uri +//------------------------------------------------------------------------- + +static IpsOption* http_uri_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_uri"); + + return new HttpIpsOption("http_uri", HTTP_BUFFER_URI); +} + +static const IpsApi http_uri_api = +{ + { + PT_IPS_OPTION, + "http_uri", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_uri_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_header +//------------------------------------------------------------------------- + +static IpsOption* http_header_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_header"); + + return new HttpIpsOption("http_header", HTTP_BUFFER_HEADER); +} + +static const IpsApi http_header_api = +{ + { + PT_IPS_OPTION, + "http_header", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_header_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_client_body +//------------------------------------------------------------------------- + +static IpsOption* http_client_body_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_client_body"); + + return new HttpIpsOption("http_client_body", HTTP_BUFFER_CLIENT_BODY); +} + +static const IpsApi http_client_body_api = +{ + { + PT_IPS_OPTION, + "http_client_body", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_client_body_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_method +//------------------------------------------------------------------------- + +static IpsOption* http_method_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_method"); + + return new HttpIpsOption("http_method", HTTP_BUFFER_METHOD); +} + +static const IpsApi http_method_api = +{ + { + PT_IPS_OPTION, + "http_method", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_method_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_cookie +//------------------------------------------------------------------------- + +static IpsOption* http_cookie_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_cookie"); + + return new HttpIpsOption("http_cookie", HTTP_BUFFER_COOKIE); +} + +static const IpsApi http_cookie_api = +{ + { + PT_IPS_OPTION, + "http_cookie", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_cookie_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_stat_code +//------------------------------------------------------------------------- + +static IpsOption* http_stat_code_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_stat_code"); + + return new HttpIpsOption("http_stat_code", HTTP_BUFFER_STAT_CODE); +} + +static const IpsApi http_stat_code_api = +{ + { + PT_IPS_OPTION, + "http_stat_code", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_stat_code_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_stat_msg +//------------------------------------------------------------------------- + +static IpsOption* http_stat_msg_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_stat_msg"); + + return new HttpIpsOption("http_stat_msg", HTTP_BUFFER_STAT_MSG); +} + +static const IpsApi http_stat_msg_api = +{ + { + PT_IPS_OPTION, + "http_stat_msg", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_stat_msg_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_raw_uri +//------------------------------------------------------------------------- + +static IpsOption* http_raw_uri_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_raw_uri"); + + return new HttpIpsOption("http_raw_uri", HTTP_BUFFER_RAW_URI); +} + +static const IpsApi http_raw_uri_api = +{ + { + PT_IPS_OPTION, + "http_raw_uri", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_raw_uri_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_raw_header +//------------------------------------------------------------------------- + +static IpsOption* http_raw_header_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_raw_header"); + + return new HttpIpsOption("http_raw_header", HTTP_BUFFER_RAW_HEADER); +} + +static const IpsApi http_raw_header_api = +{ + { + PT_IPS_OPTION, + "http_raw_header", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_raw_header_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_raw_cookie +//------------------------------------------------------------------------- + +static IpsOption* http_raw_cookie_ctor( + SnortConfig*, char* data, OptTreeNode*) +{ + if (!IsEmptyStr(data)) + ParseError("%s takes no arguments", "http_raw_cookie"); + + return new HttpIpsOption("http_raw_cookie", HTTP_BUFFER_RAW_COOKIE); +} + +static const IpsApi http_raw_cookie_api = +{ + { + PT_IPS_OPTION, + "http_raw_cookie", + IPSAPI_PLUGIN_V0, + 0, + nullptr, + nullptr + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + hi_ips_ginit, + nullptr, + nullptr, + nullptr, + http_raw_cookie_ctor, + hi_ips_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// plugins +//------------------------------------------------------------------------- + +#ifdef BUILDING_SO +SO_PUBLIC const BaseApi* snort_plugins[] = +{ + &http_uri_api.base, + &http_header_api.base, + &http_client_body_api.base, + &http_method_api.base, + &http_cookie_api.base, + &http_stat_code_api.base, + &http_stat_msg_api.base, + &http_raw_uri_api.base, + &http_raw_header_api.base, + &http_raw_cookie_api.base, + nullptr +}; +#else +const BaseApi* ips_http_uri = &http_uri_api.base; +const BaseApi* ips_http_header = &http_header_api.base; +const BaseApi* ips_http_client_body = &http_client_body_api.base; +const BaseApi* ips_http_method = &http_method_api.base; +const BaseApi* ips_http_cookie = &http_cookie_api.base; +const BaseApi* ips_http_stat_code = &http_stat_code_api.base; +const BaseApi* ips_http_stat_msg = &http_stat_msg_api.base; +const BaseApi* ips_http_raw_uri = &http_raw_uri_api.base; +const BaseApi* ips_http_raw_header = &http_raw_header_api.base; +const BaseApi* ips_http_raw_cookie = &http_raw_cookie_api.base; +#endif + diff --git a/src/service_inspectors/http_inspect/hi_norm.cc b/src/service_inspectors/http_inspect/hi_norm.cc index 7fa65806e..967ee7b0b 100644 --- a/src/service_inspectors/http_inspect/hi_norm.cc +++ b/src/service_inspectors/http_inspect/hi_norm.cc @@ -65,6 +65,15 @@ #define NON_ASCII_CHAR 0xff +#define HTTP_ENCODE_TYPE__UTF8_UNICODE 0x00000001 +#define HTTP_ENCODE_TYPE__DOUBLE_ENCODE 0x00000002 +#define HTTP_ENCODE_TYPE__NONASCII 0x00000004 +#define HTTP_ENCODE_TYPE__BASE36 0x00000008 +#define HTTP_ENCODE_TYPE__UENCODE 0x00000010 +#define HTTP_ENCODE_TYPE__BARE_BYTE 0x00000020 +#define HTTP_ENCODE_TYPE__IIS_UNICODE 0x00000040 +#define HTTP_ENCODE_TYPE__ASCII 0x00000080 + typedef struct s_URI_NORM_STATE { u_char *abs_uri; diff --git a/src/service_inspectors/http_inspect/http_inspect.cc b/src/service_inspectors/http_inspect/http_inspect.cc index 1d9eaf4d6..70d1628f4 100644 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -507,7 +507,6 @@ static const InspectApi hs_api = IT_SERVICE, PROTO_BIT__TCP, "http", - contents, hs_init, hs_term, hs_ctor, @@ -517,8 +516,7 @@ static const InspectApi hs_api = nullptr, // ssn hs_sum, hs_stats, - hs_reset, - nullptr // getbuf + hs_reset }; #ifdef BUILDING_SO diff --git a/src/service_inspectors/http_inspect/http_inspect.h b/src/service_inspectors/http_inspect/http_inspect.h new file mode 100644 index 000000000..16b093a3b --- /dev/null +++ b/src/service_inspectors/http_inspect/http_inspect.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * + * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ****************************************************************************/ + +#ifndef HTTP_INSPECT_H +#define HTTP_INSPECT_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +struct BaseApi; + +extern const BaseApi* ips_http_uri; +extern const BaseApi* ips_http_header; +extern const BaseApi* ips_http_client_body; +extern const BaseApi* ips_http_method; +extern const BaseApi* ips_http_cookie; +extern const BaseApi* ips_http_stat_code; +extern const BaseApi* ips_http_stat_msg; +extern const BaseApi* ips_http_raw_uri; +extern const BaseApi* ips_http_raw_header; +extern const BaseApi* ips_http_raw_cookie; + +#endif + diff --git a/src/service_inspectors/nhttp_inspect/nhttp_api.cc b/src/service_inspectors/nhttp_inspect/nhttp_api.cc index 99e77933a..9c6944b42 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_api.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_api.cc @@ -108,7 +108,6 @@ const InspectApi NHttpApi::nhttp_api = IT_SERVICE, PROTO_BIT__TCP, "http", - nullptr, // contents NHttpApi::nhttp_init, NHttpApi::nhttp_term, NHttpApi::nhttp_ctor, @@ -118,8 +117,7 @@ const InspectApi NHttpApi::nhttp_api = nullptr, NHttpApi::nhttp_sum, NHttpApi::nhttp_stats, - NHttpApi::nhttp_reset, - nullptr // getbuf + NHttpApi::nhttp_reset }; #ifdef BUILDING_SO diff --git a/src/service_inspectors/rpc_decode/rpc_decode.cc b/src/service_inspectors/rpc_decode/rpc_decode.cc index 67711fbfa..b131b6c8e 100644 --- a/src/service_inspectors/rpc_decode/rpc_decode.cc +++ b/src/service_inspectors/rpc_decode/rpc_decode.cc @@ -1166,7 +1166,6 @@ static const InspectApi rd_api = IT_SERVICE, PROTO_BIT__TCP, "sunrpc", - nullptr, // contents rd_init, nullptr, // term rd_ctor, @@ -1176,8 +1175,7 @@ static const InspectApi rd_api = nullptr, // ssn rd_sum, rd_stats, - rd_reset, - nullptr // getbuf + rd_reset }; #ifdef BUILDING_SO diff --git a/src/service_inspectors/service_inspectors.cc b/src/service_inspectors/service_inspectors.cc index 4ef91c57b..22be9a070 100644 --- a/src/service_inspectors/service_inspectors.cc +++ b/src/service_inspectors/service_inspectors.cc @@ -24,6 +24,7 @@ #include "config.h" #endif #include "framework/inspector.h" +#include "http_inspect/http_inspect.h" extern const BaseApi* sin_http_global; extern const BaseApi* sin_http_server; @@ -41,6 +42,18 @@ const BaseApi* service_inspectors[] = { sin_http_global, sin_http_server, + + ips_http_uri, + ips_http_header, + ips_http_client_body, + ips_http_method, + ips_http_cookie, + ips_http_stat_code, + ips_http_stat_msg, + ips_http_raw_uri, + ips_http_raw_header, + ips_http_raw_cookie, + #ifdef STATIC_INSPECTORS sin_bo, sin_ftp_client, diff --git a/src/stream/base/stream_base.cc b/src/stream/base/stream_base.cc index a5bc47fe8..8f10a6ed7 100644 --- a/src/stream/base/stream_base.cc +++ b/src/stream/base/stream_base.cc @@ -299,7 +299,6 @@ static const InspectApi base_api = IT_STREAM, PROTO_BIT__IP, nullptr, // service - nullptr, // contents base_init, nullptr, // term base_ctor, @@ -309,8 +308,7 @@ static const InspectApi base_api = nullptr, // ssn base_sum, base_stats, - base_reset, - nullptr // getbuf + base_reset }; const BaseApi* nin_stream_base = &base_api.base; diff --git a/src/stream/icmp/stream_icmp.cc b/src/stream/icmp/stream_icmp.cc index 26bb1eac4..a26f05de5 100644 --- a/src/stream/icmp/stream_icmp.cc +++ b/src/stream/icmp/stream_icmp.cc @@ -123,7 +123,6 @@ static const InspectApi icmp_api = IT_STREAM, PROTO_BIT__ICMP, nullptr, // service - nullptr, // contents icmp_init, nullptr, // term icmp_ctor, @@ -133,8 +132,7 @@ static const InspectApi icmp_api = icmp_ssn, icmp_sum, icmp_stats, - icmp_reset, - nullptr // getbuf + icmp_reset }; const BaseApi* nin_stream_icmp = &icmp_api.base; diff --git a/src/stream/ip/stream_ip.cc b/src/stream/ip/stream_ip.cc index 3e0cc376a..bc7071407 100644 --- a/src/stream/ip/stream_ip.cc +++ b/src/stream/ip/stream_ip.cc @@ -170,7 +170,6 @@ static const InspectApi ip_api = IT_STREAM, PROTO_BIT__IP, nullptr, // service - nullptr, // contents ip_init, nullptr, // term ip_ctor, @@ -180,8 +179,7 @@ static const InspectApi ip_api = ip_ssn, ip_sum, ip_stats, - ip_reset, - nullptr // getbuf + ip_reset }; const BaseApi* nin_stream_ip = &ip_api.base; diff --git a/src/stream/tcp/stream_tcp.cc b/src/stream/tcp/stream_tcp.cc index b731523b6..d96a9710e 100644 --- a/src/stream/tcp/stream_tcp.cc +++ b/src/stream/tcp/stream_tcp.cc @@ -138,7 +138,6 @@ static const InspectApi tcp_api = IT_STREAM, PROTO_BIT__TCP, nullptr, // service - nullptr, // contents tcp_init, nullptr, // term tcp_ctor, @@ -148,8 +147,7 @@ static const InspectApi tcp_api = tcp_ssn, tcp_sum, tcp_stats, - tcp_reset, - nullptr // getbuf + tcp_reset }; const BaseApi* nin_stream_tcp = &tcp_api.base; diff --git a/src/stream/udp/stream_udp.cc b/src/stream/udp/stream_udp.cc index 28bb4acac..86e59057a 100644 --- a/src/stream/udp/stream_udp.cc +++ b/src/stream/udp/stream_udp.cc @@ -138,7 +138,6 @@ static const InspectApi udp_api = IT_STREAM, PROTO_BIT__UDP, nullptr, // service - nullptr, // contents udp_init, nullptr, // term udp_ctor, @@ -148,8 +147,7 @@ static const InspectApi udp_api = udp_ssn, udp_sum, udp_stats, - udp_reset, - nullptr // getbuf + udp_reset }; const BaseApi* nin_stream_udp = &udp_api.base; diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index b4db53485..7c31d1580 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -28,6 +28,8 @@ ADD_LIBRARY( utils STATIC ${SNPRINTF_SOURCES} asn1.cc asn1.h + boyer_moore.cc + boyer_moore.h dyn_array.cc dyn_array.h ring.h diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index ef24e8f9b..35d114fbb 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -16,6 +16,7 @@ stats.h libutils_a_SOURCES = \ asn1.cc asn1.h \ +boyer_moore.cc boyer_moore.h \ dyn_array.cc dyn_array.h \ ring.h ring_logic.h \ segment_mem.cc \ diff --git a/src/utils/boyer_moore.cc b/src/utils/boyer_moore.cc new file mode 100644 index 000000000..bdece9e9d --- /dev/null +++ b/src/utils/boyer_moore.cc @@ -0,0 +1,412 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2002-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +// boyer_moore.cc was split out of mstring.cc which had these comments: + +/*************************************************************************** + * + * File: MSTRING.C + * + * Purpose: Provide a variety of string functions not included in libc. Makes + * up for the fact that the libstdc++ is hard to get reference + * material on and I don't want to write any more non-portable c++ + * code until I have solid references and libraries to use. + * + * History: + * + * Date: Author: Notes: + * ---------- ------- ---------------------------------------------- + * 08/19/98 MFR Initial coding begun + * 03/06/99 MFR Added Boyer-Moore pattern match routine, don't use + * mContainsSubstr() any more if you don't have to + * 12/31/99 JGW Added a full Boyer-Moore implementation to increase + * performance. Added a case insensitive version of mSearch + * 07/24/01 MFR Fixed Regex pattern matcher introduced by Fyodor + * + **************************************************************************/ +#include "boyer_moore.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "snort_types.h" +#include "snort_debug.h" +#include "util.h" + +#ifdef TEST_MSTRING +int main() +{ + char test[] = "\0\0\0\0\0\0\0\0\0CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\0\0"; + char find[] = "CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\0\0"; + +/* char test[] = "\x90\x90\x90\x90\x90\x90\xe8\xc0\xff\xff\xff/bin/sh\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; + char find[] = "\xe8\xc0\xff\xff\xff/bin/sh"; */ + int i; + int toks; + int *shift; + int *skip; + +/* shift=make_shift(find,sizeof(find)-1); + skip=make_skip(find,sizeof(find)-1); */ + + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,"%d\n", + mSearch(test, sizeof(test) - 1, find, + sizeof(find) - 1, shift, skip));); + + return 0; +} + +#endif + +/**************************************************************** + * + * Function: make_skip(char *, int) + * + * Purpose: Create a Boyer-Moore skip table for a given pattern + * + * Parameters: + * ptrn => pattern + * plen => length of the data in the pattern buffer + * + * Returns: + * int * - the skip table + * + ****************************************************************/ +int *make_skip(char *ptrn, int plen) +{ + int i; + int *skip = (int *) SnortAlloc(256* sizeof(int)); + + for ( i = 0; i < 256; i++ ) + skip[i] = plen + 1; + + while(plen != 0) + skip[(unsigned char) *ptrn++] = plen--; + + return skip; +} + +/**************************************************************** + * + * Function: make_shift(char *, int) + * + * Purpose: Create a Boyer-Moore shift table for a given pattern + * + * Parameters: + * ptrn => pattern + * plen => length of the data in the pattern buffer + * + * Returns: + * int * - the shift table + * + ****************************************************************/ +int *make_shift(char *ptrn, int plen) +{ + int *shift = (int *) SnortAlloc(plen * sizeof(int)); + int *sptr = shift + plen - 1; + char *pptr = ptrn + plen - 1; + char c; + + c = ptrn[plen - 1]; + + *sptr = 1; + + while(sptr-- != shift) + { + char *p1 = ptrn + plen - 2, *p2, *p3; + + do + { + while(p1 >= ptrn && *p1-- != c); + + p2 = ptrn + plen - 2; + p3 = p1; + + while(p3 >= ptrn && *p3-- == *p2-- && p2 >= pptr); + } + while(p3 >= ptrn && p2 >= pptr); + + *sptr = shift + plen - sptr + p2 - p3; + + pptr--; + } + + return shift; +} + +/**************************************************************** + * + * Function: mSearch(char *, int, char *, int) + * + * Purpose: Determines if a string contains a (non-regex) + * substring. + * + * Parameters: + * buf => data buffer we want to find the data in + * blen => data buffer length + * ptrn => pattern to find + * plen => length of the data in the pattern buffer + * skip => the B-M skip array + * shift => the B-M shift array + * + * Returns: + * -1 if not found or offset >= 0 if found + * + ****************************************************************/ +SO_PUBLIC int mSearch( + const char *buf, int blen, const char *ptrn, int plen, int *skip, int *shift) +{ + int b_idx = plen; + +#ifdef DEBUG_MSGS + char *hexbuf; + int cmpcnt = 0; +#endif + + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,"buf: %p blen: %d ptrn: %p " + "plen: %d\n", buf, blen, ptrn, plen);); + +#ifdef DEBUG_MSGS + hexbuf = fasthex((const u_char *)buf, blen); + DebugMessage(DEBUG_PATTERN_MATCH,"buf: %s\n", hexbuf); + free(hexbuf); + hexbuf = fasthex((const u_char *)ptrn, plen); + DebugMessage(DEBUG_PATTERN_MATCH,"ptrn: %s\n", hexbuf); + free(hexbuf); + DebugMessage(DEBUG_PATTERN_MATCH,"buf: %p blen: %d ptrn: %p " + "plen: %d\n", buf, blen, ptrn, plen); +#endif /* DEBUG_MSGS */ + if(plen == 0) + return -1; + + while(b_idx <= blen) + { + int p_idx = plen, skip_stride, shift_stride; + + while(buf[--b_idx] == ptrn[--p_idx]) + { +#ifdef DEBUG_MSGS + cmpcnt++; +#endif + if(b_idx < 0) + return -1; + + if(p_idx == 0) + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "match: compares = %d.\n", cmpcnt);); + return b_idx; + } + } + + skip_stride = skip[(unsigned char) buf[b_idx]]; + shift_stride = shift[p_idx]; + + b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride; + } + + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "no match: compares = %d.\n", cmpcnt);); + + return -1; +} + +/**************************************************************** + * + * Function: mSearchCI(char *, int, char *, int) + * + * Purpose: Determines if a string contains a (non-regex) + * substring matching is case insensitive + * + * Parameters: + * buf => data buffer we want to find the data in + * blen => data buffer length + * ptrn => pattern to find + * plen => length of the data in the pattern buffer + * skip => the B-M skip array + * shift => the B-M shift array + * + * Returns: + * -1 if not found or offset >= 0 if found + * + ****************************************************************/ +SO_PUBLIC int mSearchCI(const char *buf, int blen, const char *ptrn, int plen, int *skip, int *shift) +{ + int b_idx = plen; +#ifdef DEBUG_MSGS + int cmpcnt = 0; +#endif + + if(plen == 0) + return -1; + + while(b_idx <= blen) + { + int p_idx = plen, skip_stride, shift_stride; + + while((unsigned char) ptrn[--p_idx] == + toupper((unsigned char) buf[--b_idx])) + { +#ifdef DEBUG_MSGS + cmpcnt++; +#endif + if(p_idx == 0) + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "match: compares = %d.\n", + cmpcnt);); + return b_idx; + } + } + + skip_stride = skip[toupper((unsigned char) buf[b_idx])]; + shift_stride = shift[p_idx]; + + b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride; + } + + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "no match: compares = %d.\n", cmpcnt);); + + return -1; +} + +/**************************************************************** + * + * Function: mSearchREG(char *, int, char *, int) + * + * Purpose: Determines if a string contains a (regex) + * substring. + * + * Parameters: + * buf => data buffer we want to find the data in + * blen => data buffer length + * ptrn => pattern to find + * plen => length of the data in the pattern buffer + * skip => the B-M skip array + * shift => the B-M shift array + * + * Returns: + * 1 = found, 0 = not found + * + ****************************************************************/ +SO_PUBLIC int mSearchREG( + const char *buf, int blen, const char *ptrn, int plen, int *skip, int *shift) +{ + int b_idx = plen; + int literal = 0; + int regexcomp = 0; +#ifdef DEBUG_MSGS + int cmpcnt = 0; +#endif /* DEBUG_MSGS */ + + DEBUG_WRAP( + DebugMessage(DEBUG_PATTERN_MATCH, "buf: %p blen: %d ptrn: %p " + " plen: %d b_idx: %d\n", buf, blen, ptrn, plen, b_idx); + DebugMessage(DEBUG_PATTERN_MATCH, "packet data: \"%s\"\n", buf); + DebugMessage(DEBUG_PATTERN_MATCH, "matching for \"%s\"\n", ptrn); + ); + + if(plen == 0) + return 1; + + while(b_idx <= blen) + { + int p_idx = plen, skip_stride, shift_stride; + + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Looping... " + "([%d]0x%X (%c) -> [%d]0x%X(%c))\n", + b_idx, buf[b_idx-1], + buf[b_idx-1], + p_idx, ptrn[p_idx-1], ptrn[p_idx-1]);); + + while(buf[--b_idx] == ptrn[--p_idx] + || (ptrn[p_idx] == '?' && !literal) + || (ptrn[p_idx] == '*' && !literal) + || (ptrn[p_idx] == '\\' && !literal)) + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "comparing: b:%c -> p:%c\n", + buf[b_idx], ptrn[p_idx]);); +#ifdef DEBUG_MSGS + cmpcnt++; +#endif + + if(literal) + literal = 0; + if(!literal && ptrn[p_idx] == '\\') + literal = 1; + if(ptrn[p_idx] == '*') + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,"Checking wildcard matching...\n");); + while(p_idx != 0 && ptrn[--p_idx] == '*'); /* fool-proof */ + + while(buf[--b_idx] != ptrn[p_idx]) + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "comparing: b[%d]:%c -> p[%d]:%c\n", + b_idx, buf[b_idx], p_idx, ptrn[p_idx]);); + + regexcomp++; + if(b_idx == 0) + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "b_idx went to 0, returning 0\n");) + return 0; + } + } + + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "got wildcard final char match! (b[%d]: %c -> p[%d]: %c\n", b_idx, buf[b_idx], p_idx, ptrn[p_idx]);); + } + + if(p_idx == 0) + { + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "match: compares = %d.\n", + cmpcnt);); + return 1; + } + + if(b_idx == 0) + break; + } + + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "skip-shifting...\n");); + skip_stride = skip[(unsigned char) buf[b_idx]]; + shift_stride = shift[p_idx]; + + b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride; + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "b_idx skip-shifted to %d\n", b_idx);); + b_idx += regexcomp; + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, + "b_idx regex compensated %d steps, to %d\n", regexcomp, b_idx);); + regexcomp = 0; + } + + DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "no match: compares = %d, b_idx = %d, " + "blen = %d\n", cmpcnt, b_idx, blen);); + + return 0; +} + diff --git a/src/utils/boyer_moore.h b/src/utils/boyer_moore.h new file mode 100644 index 000000000..518bff49f --- /dev/null +++ b/src/utils/boyer_moore.h @@ -0,0 +1,34 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2002-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef BOYER_MOORE_H +#define BOYER_MOORE_H + +// boyer_moore.h was split out of mstring.h + +int *make_skip(char *, int); +int *make_shift(char *, int); +int mSearch(const char *, int, const char *, int, int *, int *); +int mSearchCI(const char *, int, const char *, int, int *, int *); +int mSearchREG(const char *, int, const char *, int, int *, int *); + +#endif +