4.1.5 动态规则
一个动态规则可能用到以下任何数据结构。这些数据结构都定义在sf_snort_plugin_api.h中。
Rule
Rule结构体定义了一条规则的基本概况,包含文本规则中可见的一些信息。它包括协议、IP地址和端口信息和一些规则信息(类别、厂家和ID号、版本、级别和一些摘要等)。当然还包括一些规则选项和一些规则匹配函数。
#define REGISTER_RULE 1
#define DONT_REGISTER_RULE 0
typedef struct _Rule
{
IPInfo ip;
RuleInformation info;
RuleOption **options; /* NULL terminated array of RuleOption union */
ruleEvalFunc evalFunc;
char initialized; /* Rule Initialized, used internally */
uint32_t numOptions; /* Rule option count, used internally */
char noAlert; /* Flag with no alert, used internally */
void *ruleData; /* Hash table for dynamic data pointers */
} Rule;
ruleEvalFunc定义如下:
typedef int (*ruleEvalFunc)(void *);
参数是一个指向SFSnortPacket 结构体的指针。
RuleInformation
Ruleinformation结构体定义了规则的元数据,包括规矩厂商ID,签名ID,版本,类别,级别,消息体和一些引用。
typedef struct _RuleInformation
{
uint32_t genID;
uint32_t sigID;
uint32_t revision;
char *classification; /* String format of classification name */
uint32_t priority;
char *message;
RuleReference **references; /* NULL terminated array of references */
RuleMetaData **meta; /* NULL terminated array of references */
} RuleInformation;
RuleReference
RuleReference结构体定义了一个规则的引用数据,包括系统名称和引用标示。
typedef struct _RuleReference
{
char *systemName;
char *refIdentifier;
} RuleReference;
IPInfo
IPInfo结构体定义了一个规则匹配时的首要比较的项,它包括协议、源地址和端口、目的地址和端口,还有流方向。有一些是预定义好的标量,比如:any、HOME_NET,HTTP_SERVERS/HTTP_PORTS等。
typedef struct _IPInfo
{
u_int8_t protocol;
char * src_addr;
char * src_port; /* 0 for non TCP/UDP */
char direction; /* non-zero is bi-directional */
char * dst_addr;
char * dst_port; /* 0 for non TCP/UDP */
} IPInfo;
#define ANY_NET "any"
#define HOME_NET "$HOME_NET"
#define EXTERNAL_NET "$EXTERNAL_NET"
#define ANY_PORT "any"
#define HTTP_SERVERS "$HTTP_SERVERS"
#define HTTP_PORTS "$HTTP_PORTS"
#define SMTP_SERVERS "$SMTP_SERVERS"
RuleOption
RuleOption结构体定义了某一规则中的选项,像选项类型和该选项的数据引用。每一个选项包含一个天特定的标记,就像一个Not标记一下。Not标记用来指示逻辑非。
typedef enum {
OPTION_TYPE_PREPROCESSOR,
OPTION_TYPE_CONTENT,
OPTION_TYPE_PROTECTED_CONTENT,
OPTION_TYPE_PCRE,
OPTION_TYPE_FLOWBIT,
OPTION_TYPE_FLOWFLAGS,
OPTION_TYPE_ASN1,
OPTION_TYPE_CURSOR,
OPTION_TYPE_HDR_CHECK,
OPTION_TYPE_BYTE_TEST,
OPTION_TYPE_BYTE_JUMP,
OPTION_TYPE_BYTE_EXTRACT,
OPTION_TYPE_SET_CURSOR,
OPTION_TYPE_LOOP,
OPTION_TYPE_FILE_DATA,
OPTION_TYPE_PKT_DATA,
OPTION_TYPE_BASE64_DATA,
OPTION_TYPE_BASE64_DECODE,
OPTION_TYPE_MAX
} DynamicOptionType;
typedef struct _RuleOption
{
DynamicOptionType optionType;
union
{
void *ptr;
ContentInfo *content;
ProtectedContentInfo *protectedContent;
CursorInfo *cursor;
PCREInfo *pcre;
FlowBitsInfo *flowBit;
ByteData *byte;
ByteExtract *byteExtract;
FlowFlags *flowFlags;
Asn1Context *asn1;
HdrOptCheck *hdrData;
LoopInfo *loop;
base64DecodeData *bData;
PreprocessorOption *preprocOpt;
} option_u;
} RuleOption;
#define NOT_FLAG 0x10000000
一些选项也包括运行时的初始信息,比如PCRE信息,BM算法匹配的内容,字节流的ID信息等。 相关选项类型和涉及到的结构体如下:
- 选项:Content及结构:ContentInfo ContentInfo结构体定义了内容匹配的选项。它包括了匹配模式、长度和偏移,还有一些标记(其中一种用来标记匹配的数据-原始数据(raw)、URI或者正常数据(normalized))。其它标记还包括nocase、relative、unicode和一个用来指示该内容用与Snort快速匹配的标记。一个规则中的大部分情况,需要指定一个快速匹配的标识,在Snort中提供的动态检测引擎中,如果一个规则中没有给定ContenInfo结构体,则使用大内容长度来匹配。
typedef struct _ContentInfo
{
const uint8_t *pattern;
uint32_t depth;
int32_t offset;
uint32_t flags; /* must include a CONTENT_BUF_X */
void *boyer_ptr;
uint8_t *patternByteForm;
uint32_t patternByteFormLength;
uint32_t incrementLength;
uint16_t fp_offset;
uint16_t fp_length;
uint8_t fp_only;
char *offset_refId; /* To match up with a DynamicElement refId */
char *depth_refId; /* To match up with a DynamicElement refId */
int32_t *offset_location;
uint32_t *depth_location;
} ContentInfo;
#define CONTENT_BUF_NONE 0x00000000
#define CONTENT_BUF_URI 0x00000001
#define CONTENT_BUF_HEADER 0x00000002
#define CONTENT_BUF_POST 0x00000003
#define CONTENT_BUF_METHOD 0x00000004
#define CONTENT_BUF_COOKIE 0x00000005
#define CONTENT_BUF_STAT_CODE 0x00000006
#define CONTENT_BUF_STAT_MSG 0x00000007
#define CONTENT_BUF_RAW_URI 0x00000008
#define CONTENT_BUF_RAW_HEADER 0x00000009
#define CONTENT_BUF_RAW_COOKIE 0x0000000A
#define CONTENT_BUF_HTTP 0x0000000F
#define CONTENT_BUF_NORMALIZED 0x00000100
#define CONTENT_BUF_RAW 0x00000200
#define CONTENT_END_BUFFER 0x00000400
#define CONTENT_NOCASE 0x00001000
#define CONTENT_RELATIVE 0x00002000
#define CONTENT_FAST_PATTERN 0x00010000
#define CONTENT_FAST_PATTERN_ONLY 0x00020000 // implies fast pattern
#define CONTENT_UNICODE2BYTE 0x00100000
#define CONTENT_UNICODE4BYTE 0x00200000
- 选项:PCRE及结构体:PCREInfo PCREInfo结构体定义了一正则匹配的选项。它包括正则表达式、正则标记比如:匹配大小写、和一些缓存标记,这些标记和PCRE.h中定义了。
/*
pcre.h provides flags:
PCRE_CASELESS
PCRE_MULTILINE
PCRE_DOTALL
PCRE_EXTENDED
PCRE_ANCHORED
PCRE_DOLLAR_ENDONLY
PCRE_UNGREEDY
*/
typedef struct _PCREInfo
{
char *expr;
void *compiled_expr;
void *compiled_extra;
uint32_t compile_flags;
uint32_t flags; /* must include a CONTENT_BUF_X */
int32_t offset;
} PCREInfo;
- 选项:Flowbit及结构体:FlowBitsInfo FlowBitsInfo结构体定义了一个字节流选项。它定义了一个字节流名称和操作(set。setx、unset、toggle、isset、isnotset)
#define FLOWBIT_SET 0x01
#define FLOWBIT_UNSET 0x02
#define FLOWBIT_TOGGLE 0x04
#define FLOWBIT_ISSET 0x08
#define FLOWBIT_ISNOTSET 0x10
#define FLOWBIT_RESET 0x20
#define FLOWBIT_NOALERT 0x40
#define FLOWBIT_SETX 0x80
typedef struct _FlowBitsInfo
{
char *flowBitsName;
uint8_t operation;
uint16_t id;
uint32_t flags;
char *groupName;
uint8_t eval;
uint16_t *ids;
uint8_t num_ids;
} FlowBitsInfo;
- 选项:流标记及结构体FlowFlags FlowFlags结构体定义了一个流选项。它包括建立会话时的方向(从服务器发起,连向服务器)。
#define FLOW_ESTABLISHED 0x0008
#define FLOW_FR_SERVER 0x0040
#define FLOW_TO_CLIENT 0x0040 /* Just for convenience */
#define FLOW_TO_SERVER 0x0080
#define FLOW_FR_CLIENT 0x0080 /* Just for convenience */
#define FLOW_IGNORE_REASSEMBLED 0x1000
#define FLOW_ONLY_REASSEMBLED 0x2000
#define FLOW_ONLY_REASSMBLED FLOW_ONLY_REASSEMBLED
typedef struct _FlowFlags
{
uint32_t flags; /* FLOW_* values */
} FlowFlags;
- 选项:ASN.1及结构体:Asn1Context Asn1Context结构体定义了关于ASN.1的选项。它包括了ASN.1规则选项并且也包括了一个flags选项。
#define ASN1_ABS_OFFSET 1
#define ASN1_REL_OFFSET 2
typedef struct _Asn1Context
{
int bs_overflow;
int double_overflow;
int print;
int length;
unsigned int max_length;
int offset;
int offset_type;
uint32_t flags;
} Asn1Context;
- 选项:Cursor Check及结构体:CursorInfo CursorInfo结构体定义了规则匹配时的游标选项。游标是在当前匹配过程中缓存的位置,就像正则匹配过程中的内容、字节测试和跳转等。它包括一个偏移量和一个针对缓存的特定标记flage。这样就可以用来判断是否有足够的数据来继续匹配,这一点和isdataat很像。
typedef struct _CursorInfo
{
int32_t offset;
uint32_t flags; /* specify one of CONTENT_BUF_X */
char *offset_refId; /* To match up with a DynamicElement refId */
int32_t *offset_location;
} CursorInfo;
- 选项:协议头及结构体:HdrOptCheck HdrOptCheck结构体定义了一个用来检测特定值的协议头的选项。它包括头部字段、操作(《,》,=等),一个值和一个用来忽略匹配的掩码和标记。
#define IP_HDR_ID 0x0001 /* IP Header ID */
#define IP_HDR_PROTO 0x0002 /* IP Protocol */
#define IP_HDR_FRAGBITS 0x0003 /* Frag Flags set in IP Header */
#define IP_HDR_FRAGOFFSET 0x0004 /* Frag Offset set in IP Header */
#define IP_HDR_OPTIONS 0x0005 /* IP Options -- is option xx included */
#define IP_HDR_TTL 0x0006 /* IP Time to live */
#define IP_HDR_TOS 0x0007 /* IP Type of Service */
#define IP_HDR_OPTCHECK_MASK 0x000f
#define TCP_HDR_ACK 0x0010 /* TCP Ack Value */
#define TCP_HDR_SEQ 0x0020 /* TCP Seq Value */
#define TCP_HDR_FLAGS 0x0030 /* Flags set in TCP Header */
#define TCP_HDR_OPTIONS 0x0040 /* TCP Options -- is option xx included */
#define TCP_HDR_WIN 0x0050 /* TCP Window */
#define TCP_HDR_OPTCHECK_MASK 0x00f0
#define ICMP_HDR_CODE 0x1000 /* ICMP Header Code */
#define ICMP_HDR_TYPE 0x2000 /* ICMP Header Type */
#define ICMP_HDR_ID 0x3000 /* ICMP ID for ICMP_ECHO/ICMP_ECHO_REPLY */
#define ICMP_HDR_SEQ 0x4000 /* ICMP ID for ICMP_ECHO/ICMP_ECHO_REPLY */
#define ICMP_HDR_OPTCHECK_MASK 0xf000
typedef struct _HdrOptCheck
{
uint16_t hdrField; /* Field to check */
uint32_t op; /* Type of comparison */
uint32_t value; /* Value to compare value against */
uint32_t mask_value; /* bits of value to ignore */
uint32_t flags;
} HdrOptCheck;
- 选项:Byte Test及结构体:ByteData ByteData结构体定义了ByteTest和ByteJump操作信息。它包括字节数、一个操作(<,>,=等),一个值,一个偏移量,乘及和一个标识。这个标识必须是和内容相关的。
#define CHECK_EQ 0
#define CHECK_NEQ 1
#define CHECK_LT 2
#define CHECK_GT 3
#define CHECK_LTE 4
#define CHECK_GTE 5
#define CHECK_AND 6
#define CHECK_XOR 7
#define CHECK_ALL 8
#define CHECK_ATLEASTONE 9
#define CHECK_NONE 10
typedef struct _ByteData
{
uint32_t bytes; /* Number of bytes to extract */
uint32_t op; /* Type of byte comparison, for checkValue */
uint32_t value; /* Value to compare value against, for checkValue, or extracted value */
int32_t offset; /* Offset from cursor */
uint32_t multiplier; /* Used for byte jump -- 32bits is MORE than enough */
uint32_t flags; /* must include a CONTENT_BUF_X */
int32_t post_offset;/* Use for byte jump -- adjust cusor by this much after the jump */
char *offset_refId; /* To match up with a DynamicElement refId */
char *value_refId; /* To match up with a DynamicElement refId */
int32_t *offset_location;
uint32_t *value_location;
} ByteData;
- 选项:Byte Jump及结构体:ByteData
- 选项:Set Cursor及结构体:CursorInfo
- 选项:loop及结构体:LoopInfo,ByteExtract,DynamicElement LoopInfo结构体定义了一系列用来循环匹配的选项。这些选项就像FOR循环一下,包括起始值,结束值和一个递增值。它包括一个每次迭代动态调整的游标,一个对RuleInfo的引用,该引用中定义了每次迭代过程中的操作。
typedef struct _LoopInfo
{
DynamicElement *start; /* Starting value of FOR loop (i=start) */
DynamicElement *end; /* Ending value of FOR loop (i OP end) */
DynamicElement *increment; /* Increment value of FOR loop (i+= increment) */
uint32_t op; /* Type of comparison for loop termination */
CursorInfo *cursorAdjust; /* How to move cursor each iteration of loop */
struct _Rule *subRule; /* Pointer to SubRule & options to evaluate within
* the loop */
uint8_t initialized; /* Loop initialized properly (safeguard) */
uint32_t flags; /* can be used to negate loop results, specifies
* relative. */
} LoopInfo;
ByteExtract结构体定义了一个在循环中匹配时,DynamicElement数据的选项。它包括字节数,偏移量,步长值,关于buffer的标记和一个对DynamicElement的引用。
typedef struct _ByteData
{
uint32_t bytes; /* Number of bytes to extract */
uint32_t op; /* Type of byte comparison, for checkValue */
uint32_t value; /* Value to compare value against, for checkValue, or extracted value */
int32_t offset; /* Offset from cursor */
uint32_t multiplier; /* Used for byte jump -- 32bits is MORE than enough */
uint32_t flags; /* must include a CONTENT_BUF_X */
int32_t post_offset;/* Use for byte jump -- adjust cusor by this much after the jump */
char *offset_refId; /* To match up with a DynamicElement refId */
char *value_refId; /* To match up with a DynamicElement refId */
int32_t *offset_location;
uint32_t *value_location;
} ByteData;
DynamicElement结构体用来定义每次循环过程中配置值。它包括这些元素是静态的还是动态的(从数据包中获取)和一个value。如果元素是动态类型,则这个value在每次循环时,由ByteExtract相关操作负责填充。
#define DYNAMIC_TYPE_INT_STATIC 1
#define DYNAMIC_TYPE_INT_REF 2
typedef struct _DynamicElement
{
char dynamicType; /* type of this field - static or reference */
char *refId; /* reference ID (NULL if static) */
union
{
void *voidPtr; /* Holder */
int32_t staticInt; /* Value of static */
int32_t *dynamicInt; /* Pointer to value of dynamic */
} data;
} DynamicElement;