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;