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
# initialization
#--------------------------------------------------------------------------
-AC_INIT([snort], [2.10.087])
+AC_INIT([snort], [2.10.088])
AC_PREREQ([2.68])
AC_CONFIG_SRCDIR([src/main.h])
--- /dev/null
+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_*
+
return 1;
}
-int OptListEnd(void*, Packet*)
+int OptListEnd(void*, Cursor&, Packet*)
{
return DETECTION_OPTION_MATCH;
}
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*);
#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"
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;
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. */
{
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 */
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) &&
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:
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:
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
{
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;
}
/* 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;i<node->num_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);
}
}
- 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
* 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
// 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);
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
{
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;
#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
{
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
} 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;
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);
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
* 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;
sc,
pattern,
pattern_length,
- pmd->nocase,
+ pmd->no_case,
pmd->offset,
pmd->depth,
(unsigned)pmd->exception_flag,
return 0;
}
+#if 0
+// FIXIT fast_pattern
static PmType GetPmType (HTTP_BUFFER hb_type)
{
switch ( 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;
}
}
+#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);
return 0;
}
}
+#endif
/* If we get this far then no URI contents were added */
#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"
}
#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
RULE_OPTION_TYPE_OTHER
} option_type_t;
-#endif /* RULE_OPTION_TYPES_H */
+#endif
+
/* context data for this test */
void *context;
- int (*OptTestFunc)(void *option_data, Packet *p);
+ int (*OptTestFunc)(void* option_data, struct Cursor&, Packet*);
OptFpList *next;
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);
base_api.h
bits.h
codec.h
- content_buffer.h
+ cursor.h
logger.h
inspector.h
ips_option.h
add_library ( framework STATIC
${FRAMEWORK_INCLUDES}
+ cursor.cc
inspector.cc
ips_option.cc
parameter.cc
base_api.h \
bits.h \
codec.h \
-content_buffer.h \
+cursor.h \
logger.h \
inspector.h \
ips_option.h \
value.h
libframework_a_SOURCES = \
+cursor.cc \
inspector.cc \
ips_option.cc \
parameter.cc \
--- /dev/null
+/*
+** 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 <rucombs@cisco.com>
+
+#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);
+ }
+}
+
--- /dev/null
+/*
+** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
+** Copyright (C) 2002-2013 Sourcefire, Inc.
+** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+**
+** 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 <rucombs@cisco.com>
+
+#ifndef CURSOR_H
+#define CURSOR_H
+
+#include <ctype.h>
+#include <stdint.h>
+#include <string.h>
+
+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
+
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
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
InspectFunc sum; // accumulate stats
InspectFunc stats; // output stats
InspectFunc reset; // clear stats
- InspectBufFunc getbuf; // 0-based, eg getbuf(1) means foo_b above
};
#endif
// 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; };
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
ips_isdataat.cc
ips_itype.cc
ips_pkt_data.cc
+ ips_raw_data.cc
ips_react.cc
ips_resp.cc
ips_rpc.cc
ips_options.h
ips_pcre.cc
ips_pcre.h
+ ips_replace.cc
+ ips_replace.h
ips_so.cc
- replace.cc
- replace.h
)
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)
ips_isdataat.cc \
ips_itype.cc \
ips_pkt_data.cc \
+ips_raw_data.cc \
ips_react.cc \
ips_resp.cc \
ips_rpc.cc \
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)
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
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
TcpAckCheckData config;
return false;
}
-int TcpAckOption::eval(Packet *p)
+int TcpAckOption::eval(Cursor&, Packet *p)
{
TcpAckCheckData *ackCheckData = &config;
int rval = DETECTION_OPTION_NO_MATCH;
bool is_relative()
{ return ( config.offset_type == REL_OFFSET ); };
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
ASN1_CTXT config;
return false;
}
-int Asn1Option::eval(Packet *p)
+int Asn1Option::eval(Cursor&, Packet *p)
{
PROFILE_VARS;
#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
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;
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);
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
Base64DecodeData config;
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;
#include "extract.h"
#include "fpdetect.h"
#include "framework/ips_option.h"
+#include "framework/cursor.h"
#ifdef PERF_PROFILING
static THREAD_LOCAL PreprocStats byteExtractPerfStats;
bool is_relative()
{ return (config.relative_flag == 1); };
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
ByteExtractData config;
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)
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 */
}
/* 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);
#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
bool is_relative()
{ return (config.relative_flag == 1); };
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
ByteJumpData config;
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;
}
}
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;
}
bool is_relative()
{ return ( config.relative_flag == 1 ); };
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
ByteTestData config;
return false;
}
-int ByteTestOption::eval(Packet *p)
+int ByteTestOption::eval(Cursor&, Packet *p)
{
ByteTestData *btd = (ByteTestData *)&config;
int rval = DETECTION_OPTION_NO_MATCH;
#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"
#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
{
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
//-------------------------------------------------------------------------
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);
}
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;
mix(a,b,c);
a += pmd->depth_var;
- b += pmd->distance_var;
- c += pmd->within_var;
final(a,b,c);
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;i<left->pattern_size;i++)
{
if (toupper(left->pattern_buf[i]) != toupper(right->pattern_buf[i]))
}
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;
}
}
- /* 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;
}
/* 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;
}
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)
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)
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;
{
ContentOption* opt = (ContentOption*)pv;
PatternMatchData* pmd = opt->get_data();
- return ( pmd->within == 0 );
+ return ( pmd->depth == 0 );
}
//-------------------------------------------------------------------------
/*
* 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 )
{
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"););
}
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;
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;
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)
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)
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)
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)
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;
}
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)
{
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;
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(
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 */
{
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);
{
PayloadSearchWithin(pmd, opt1, otn);
}
- else if (!strcasecmp(opts[0], "replace"))
- {
- PayloadReplaceInit(pmd, opt1, otn);
- }
else
{
ParseError("Invalid content parameter specified: %s", opts[0]);
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");
}
#include "detection/rules.h"
#include "detection/treenodes.h"
#include "detection/detection_util.h"
+#include "framework/content_buffer.h"
extern THREAD_LOCAL int lastType;
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;
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)
} 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,
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 )
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
CvsRuleOption config;
return false;
}
-int CvsOption::eval(Packet *p)
+int CvsOption::eval(Cursor&, Packet *p)
{
int ret;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
DsizeCheckData config;
}
// 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;
#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";
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
FileData* get_data()
{ return &config; };
return false;
}
-int FileDataOption::eval(Packet *p)
+int FileDataOption::eval(Cursor& c, Packet *p)
{
int rval = DETECTION_OPTION_NO_MATCH;
uint8_t *data;
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);
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
TcpFlagCheckData config;
return false;
}
-int TcpFlagOption::eval(Packet *p)
+int TcpFlagOption::eval(Cursor&, Packet *p)
{
TcpFlagCheckData *flagptr = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
FlowCheckData config;
return false;
}
-int FlowCheckOption::eval(Packet *p)
+int FlowCheckOption::eval(Cursor&, Packet *p)
{
FlowCheckData *fcd = &config;
PROFILE_VARS;
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; };
return true;
}
-int FlowBitsOption::eval(Packet *p)
+int FlowBitsOption::eval(Cursor&, Packet *p)
{
FLOWBITS_OP *flowbits = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
FragBitsData config;
return false;
}
-int FragBitsOption::eval(Packet *p)
+int FragBitsOption::eval(Cursor&, Packet *p)
{
FragBitsData *fb = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
FragOffsetData config;
return false;
}
-int FragOffsetOption::eval(Packet *p)
+int FragOffsetOption::eval(Cursor&, Packet *p)
{
FragOffsetData *ipd = &config;
int p_offset = p->frag_offset * 8;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
IcmpIdCheckData config;
return false;
}
-int IcmpIdOption::eval(Packet *p)
+int IcmpIdOption::eval(Cursor&, Packet *p)
{
IcmpIdCheckData *icmpId = &config;
PROFILE_VARS;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
IcmpSeqCheckData config;
return false;
}
-int IcmpSeqOption::eval(Packet *p)
+int IcmpSeqOption::eval(Cursor&, Packet *p)
{
IcmpSeqCheckData *icmpSeq = &config;
PROFILE_VARS;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
IcmpCodeCheckData config;
return false;
}
-int IcmpCodeOption::eval(Packet *p)
+int IcmpCodeOption::eval(Cursor&, Packet *p)
{
IcmpCodeCheckData *ds_ptr = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
IpIdCheckData config;
return false;
}
-int IpIdOption::eval(Packet *p)
+int IpIdOption::eval(Cursor&, Packet *p)
{
IpIdCheckData *ipIdCheckData = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
IpProtoData* get_data()
{ return &config; };
return false;
}
-int IpProtoOption::eval(Packet *p)
+int IpProtoOption::eval(Cursor&, Packet *p)
{
IpProtoData *ipd = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
IpOptionData* get_data()
{ return &config; };
return false;
}
-int IpOptOption::eval(Packet *p)
+int IpOptOption::eval(Cursor&, Packet *p)
{
IpOptionData *ipOptionData = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
IsDataAtData* get_data()
{ return &config; };
return false;
}
-int IsDataAtOption::eval(Packet *p)
+int IsDataAtOption::eval(Cursor&, Packet *p)
{
IsDataAtData *isdata = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
IcmpTypeCheckData config;
return false;
}
-int IcmpTypeOption::eval(Packet *p)
+int IcmpTypeOption::eval(Cursor&, Packet *p)
{
IcmpTypeCheckData *ds_ptr = &config;
int rval = DETECTION_OPTION_NO_MATCH;
return true;
}
-int LuaJITOption::eval(Packet* p)
+int LuaJITOption::eval(Cursor&, Packet* p)
{
packet = p;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
void init(const char*, const char*);
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;
ips_isdataat,
ips_itype,
ips_pkt_data,
+ ips_raw_data,
ips_react,
ips_resp,
ips_rpc,
#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
* 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<expression_len;i+=4)
- {
- tmp = 0;
- k = expression_len - i;
- if (k > 4)
- k=4;
-
- for (l=0;l<k;l++)
- {
- tmp |= *(data->expression + 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)
{
char delimit = '/';
int erroffset;
int compile_flags = 0;
- unsigned http = 0;
if(data == NULL)
{
* 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");
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);
"%d : %s", re, erroffset, error);
}
-
/* now study it... */
pcre_data->pe = pcre_study(pcre_data->re, 0, &error);
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<expression_len;i+=4)
+ {
+ tmp = 0;
+ k = expression_len - i;
+ if (k > 4)
+ k=4;
+
+ for (l=0;l<k;l++)
+ {
+ tmp |= *(data->expression + 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)
{
#include <stdint.h>
-// 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)
#define SNORT_OVERRIDE_MATCH_LIMIT 0x00100 // Override default limits on match & match recursion
#include <pcre.h>
-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
#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";
{
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(
--- /dev/null
+/*
+** 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 <sys/types.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#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
+
** 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 <assert.h>
+#include <string>
+using namespace std;
#include "snort_types.h"
#include "snort_bounds.h"
#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];
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)
{
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() )
{
" 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)
num_rpl = 0;
}
-void Replace_QueueChange(PatternMatchData* pmd)
+void Replace_QueueChange(string& s, int off)
{
Replacement* r;
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()
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
+
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
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
RpcCheckData config;
return false;
}
-int RpcOption::eval(Packet *p)
+int RpcOption::eval(Cursor&, Packet *p)
{
RpcCheckData *ds_ptr = &config;
unsigned char* c=(unsigned char*)p->data;
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;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
TcpSeqCheckData config;
return false;
}
-int TcpSeqOption::eval(Packet *p)
+int TcpSeqOption::eval(Cursor&, Packet *p)
{
TcpSeqCheckData *tcpSeqCheckData = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
SessionData config;
return false;
}
-int SessionOption::eval(Packet *p)
+int SessionOption::eval(Cursor&, Packet *p)
{
SessionData *session_data = &config;
FILE *session; /* session file ptr */
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet* p)
+ int eval(Cursor&, Packet* p)
{ return func(data, p); };
private:
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
IpTosData* get_data()
{ return &config; };
* 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;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
TtlCheckData config;
return false;
}
-int TtlOption::eval(Packet *p)
+int TtlOption::eval(Cursor&, Packet *p)
{
TtlCheckData *ttlCheckData = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
UriLenCheckData config;
return false;
}
-int UriLenOption::eval(Packet*)
+int UriLenOption::eval(Cursor&, Packet*)
{
UriLenCheckData *udata = &config;
int rval = DETECTION_OPTION_NO_MATCH;
uint32_t hash() const;
bool operator==(const IpsOption&) const;
- int eval(Packet*);
+ int eval(Cursor&, Packet*);
private:
TcpWinCheckData config;
return false;
}
-int TcpWinOption::eval(Packet *p)
+int TcpWinOption::eval(Cursor&, Packet *p)
{
TcpWinCheckData *tcpWinCheckData = &config;
int rval = DETECTION_OPTION_NO_MATCH;
command = AC_NONE;
}
- if ( DAQ_Acquire(1, main_func, NULL) )
+ if ( DAQ_Acquire(0, main_func, NULL) )
break;
++count;
#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"
* 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;
cout << ": " << p->help;
if ( p->range )
- cout << " { " << p->range << " }";
+ cout << " { " << (char*)p->range << " }";
#else
cout << item();
cout << p->get_type();
IT_PROTOCOL,
PROTO_BIT__ARP,
nullptr, // service
- nullptr, // contents
as_init,
nullptr, // term
as_ctor,
nullptr, // ssn
as_sum,
as_stats,
- as_reset,
- nullptr // getbuf
+ as_reset
};
#ifdef BUILDING_SO
IT_PACKET,
PROTO_BITS,
nullptr, // service
- nullptr, // contents
no_init,
nullptr, // term
no_ctor,
nullptr, // ssn
no_sum,
no_stats,
- no_reset,
- nullptr // getbuf
+ no_reset
};
const BaseApi* nin_normalize = &no_api.base;
IT_PACKET,
PROTO_BIT__ALL,
nullptr, // service
- nullptr, // contents
pm_init,
nullptr, // term
pm_ctor,
nullptr, // ssn
pm_sum,
pm_stats,
- pm_reset,
- nullptr // getbuf
+ pm_reset
};
const BaseApi* nin_perf_monitor = &pm_api.base;
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,
nullptr, // ssn
sp_sum,
sp_stats,
- sp_reset,
- nullptr // getbuf
+ sp_reset
};
#ifdef BUILDING_SO
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;
-}
-
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 */
unsigned int sid;
int dir;
char content;
- char uricontent;
} port_entry_t;
plist->pl_array[i].dst_port );
LogMessage(" content %d",
plist->pl_array[i].content);
- LogMessage(" uricontent %d",
- plist->pl_array[i].uricontent);
LogMessage(" }\n");
}
}
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
/* 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;
}
IT_PROTOCOL,
PROTO_BIT__UDP,
nullptr, // service
- nullptr, // contents
bo_init,
nullptr, // term
bo_ctor,
nullptr, // ssn
bo_sum,
bo_stats,
- bo_reset,
- nullptr // getbuf
+ bo_reset
};
#ifdef BUILDING_SO
IT_SERVICE,
PROTO_BIT__TCP,
"ftp", // FIXIT add ftp-data inspector
- nullptr, // contents
fs_init,
nullptr, // term
fs_ctor,
nullptr, // ssn
fs_sum,
fs_stats,
- fs_reset,
- nullptr // getbuf
+ fs_reset
};
#ifdef BUILDING_SO
IT_SERVICE,
PROTO_BIT__TCP,
"telnet",
- nullptr, // contents
tn_init,
nullptr, // term
tn_ctor,
tn_sum,
tn_stats,
tn_reset,
- nullptr // getbuf
};
set (FILE_LIST
http_inspect.cc
+ http_inspect.h
hi_main.cc
hi_main.h
hi_ad.cc
hi_cmd_lookup.cc
hi_cmd_lookup.h
hi_include.h
+ hi_ips_options.cc
hi_mi.cc
hi_mi.h
hi_norm.cc
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 \
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 \
--- /dev/null
+/*
+** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
+** Copyright (C) 2002-2013 Sourcefire, Inc.
+** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+**
+** 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 <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#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
+
#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;
IT_SERVICE,
PROTO_BIT__TCP,
"http",
- contents,
hs_init,
hs_term,
hs_ctor,
nullptr, // ssn
hs_sum,
hs_stats,
- hs_reset,
- nullptr // getbuf
+ hs_reset
};
#ifdef BUILDING_SO
--- /dev/null
+/****************************************************************************
+ *
+ * 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
+
IT_SERVICE,
PROTO_BIT__TCP,
"http",
- nullptr, // contents
NHttpApi::nhttp_init,
NHttpApi::nhttp_term,
NHttpApi::nhttp_ctor,
nullptr,
NHttpApi::nhttp_sum,
NHttpApi::nhttp_stats,
- NHttpApi::nhttp_reset,
- nullptr // getbuf
+ NHttpApi::nhttp_reset
};
#ifdef BUILDING_SO
IT_SERVICE,
PROTO_BIT__TCP,
"sunrpc",
- nullptr, // contents
rd_init,
nullptr, // term
rd_ctor,
nullptr, // ssn
rd_sum,
rd_stats,
- rd_reset,
- nullptr // getbuf
+ rd_reset
};
#ifdef BUILDING_SO
#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;
{
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,
IT_STREAM,
PROTO_BIT__IP,
nullptr, // service
- nullptr, // contents
base_init,
nullptr, // term
base_ctor,
nullptr, // ssn
base_sum,
base_stats,
- base_reset,
- nullptr // getbuf
+ base_reset
};
const BaseApi* nin_stream_base = &base_api.base;
IT_STREAM,
PROTO_BIT__ICMP,
nullptr, // service
- nullptr, // contents
icmp_init,
nullptr, // term
icmp_ctor,
icmp_ssn,
icmp_sum,
icmp_stats,
- icmp_reset,
- nullptr // getbuf
+ icmp_reset
};
const BaseApi* nin_stream_icmp = &icmp_api.base;
IT_STREAM,
PROTO_BIT__IP,
nullptr, // service
- nullptr, // contents
ip_init,
nullptr, // term
ip_ctor,
ip_ssn,
ip_sum,
ip_stats,
- ip_reset,
- nullptr // getbuf
+ ip_reset
};
const BaseApi* nin_stream_ip = &ip_api.base;
IT_STREAM,
PROTO_BIT__TCP,
nullptr, // service
- nullptr, // contents
tcp_init,
nullptr, // term
tcp_ctor,
tcp_ssn,
tcp_sum,
tcp_stats,
- tcp_reset,
- nullptr // getbuf
+ tcp_reset
};
const BaseApi* nin_stream_tcp = &tcp_api.base;
IT_STREAM,
PROTO_BIT__UDP,
nullptr, // service
- nullptr, // contents
udp_init,
nullptr, // term
udp_ctor,
udp_ssn,
udp_sum,
udp_stats,
- udp_reset,
- nullptr // getbuf
+ udp_reset
};
const BaseApi* nin_stream_udp = &udp_api.base;
${SNPRINTF_SOURCES}
asn1.cc
asn1.h
+ boyer_moore.cc
+ boyer_moore.h
dyn_array.cc
dyn_array.h
ring.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 \
--- /dev/null
+/*
+** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
+** Copyright (C) 2002-2013 Sourcefire, Inc.
+** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#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;
+}
+
--- /dev/null
+/*
+** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
+** Copyright (C) 2002-2013 Sourcefire, Inc.
+** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+**
+** 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
+