snort做为一个网络入侵检测工具,与同类工具拥有类似的处理流程,以下所示:node
基本数据初始化数组
回调函数注册网络
读取规则创建临时结构app
使用临时结构创建最终便于匹配的结构,该过程也可称为编译过程。tcp
进入循环获取报文进行处理函数
而报文的处理又经历以下流程工具
拆包this
预处理url
匹配spa
动做
前面文章已经分析了规则的读取:
http://my.oschina.net/u/572632/blog/290351
这里就将继续分析如何创建匹配结构,创建匹配结构的过程又可称为编译过程,目地是将读取规则后创建的便于收集数据的结构转换为专门用于匹配的结构。
以下图所示,当端口初次解析的过程当中snort使用以下的方式存放解析出的端口对象。
按照端口所属规则的协议类型将其分为tcp, udp等几类
每一类协议包含anyany_object, src_table, dst_table
若是这条规则的源和目地端口都为any则直接将该规则的规则索引加入anyany_object持有的规则链表中。
若是该规则的源端口非any,则将该规则的源端口对象入src_table中,并将该规则对应的索引加入源端口对象持有的规则链中。若是该规则的数据流是双向的则还须要将源端口对象加入dst_table中。
若是该规则的目地端口非any,则将该规则的目地端口对象入dst_table中,并将该规则对应的索引加入目地端口对象持有的规则链中。若是该规则的数据流是双向的则还须要将源端口对象加入dst_table中。
存在必有其理由,代码也同样,做者的处理必然有其缘由,所以这里先分析下目前的情况。
如今咱们的anyany_object表现的很良好,但在src_table或者dst_table中会有多个port_object,当读取规则完成后在src_table或dst_table中的portObject目前以下图。这会带来下面几个问题。
port item在前面的文章作过度析,他多是一个端口,也多是端口范围,甚至多是其包含的端口取反,更糟糕的是port Object是他持有的端口条目综合得出的。
即便咱们为port object处理了port item集合后,在port object之间也可能出现重复的问题,极端状况可能6000个端口指向同一个port object而咱们却保留了6000个副本,这是至关糟糕的。
所以在这里的匹配结构咱们但愿是下面这样的,每一个端口下面是匹配上该端口的规则集合。
因此这里的代码所需的工做就是从上面的结构转换为下面的结构。
实际构建的快速匹配结构和上面的相似,快速匹配主要是构建了两点
端口,即上面所述的端口覆盖范围交错等问题
模式匹配,主要是针对uri, url等较长字串的模式匹配,须要注意的是这里匹配的具体方式是从多个方案中选择的,选择哪一个要看具体配置
下面结合图示对其构建的结构具体的分析下。
总体结构是呈现一个树状,即在每一层针对某一特性将全部的被匹配结构进行分类,不断的重复这种方案所构成的树状结构再匹配时就能经过路径选择较少没必要要的数据扫描。
最顶层是使用协议区分,以下:
每个PORT_RULE_MAP表明一种协议
/* The port-rule-maps map the src-dst ports to rules for * udp and tcp, for Ip we map the dst port as the protocol, * 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. */ PORT_RULE_MAP *prmIpRTNX; PORT_RULE_MAP *prmTcpRTNX; PORT_RULE_MAP *prmUdpRTNX; PORT_RULE_MAP *prmIcmpRTNX;
接下来是每一个协议集合,即PORT_RULE_MAP中主要包含什么?
以下所示,PORT_RULE_MAP中主要是存放PORT_GROUP结构,每一个端口都存放一个该结构,即
prmSrcPort 和prmDstPort数组中下标表明端口号,而其中存放的是规则集合。
须要注意的是any group 图示和代码不一致,这是由于any 的规则集合被放入了每个端口,由于any表明所有端口匹配。
typedef struct { int prmNumDstRules; int prmNumSrcRules; int prmNumGenericRules; int prmNumDstGroups; int prmNumSrcGroups; PORT_GROUP *prmSrcPort[MAX_PORTS]; PORT_GROUP *prmDstPort[MAX_PORTS]; /* char prmConflicts[MAX_PORTS]; */ PORT_GROUP *prmGeneric; } PORT_RULE_MAP ;
最后是PORT_GROUP结构分析了,PORT_GROUP结构中主要是负责模式匹配,所以对于非HTTP的协议PORT_GROUP中的内容就不过重要了,仍是结合代码说明.
以下,将规则集合再次分为三种, content, no-content 和 uri-content. 即content匹配,不含content, uri匹配。
规则集合有了,图示中对应的模式匹配结构呢?
模式匹配结构再pgPms, 还需注意上面说明, MPSE若是对模式匹配感兴趣呀能够重点阅读该部分代码。
typedef struct { /* Content List */ RULE_NODE *pgHead, *pgTail, *pgCur; int pgContentCount; /* No-Content List */ RULE_NODE *pgHeadNC, *pgTailNC, *pgCurNC; int pgNoContentCount; /* Uri-Content List */ RULE_NODE *pgUriHead, *pgUriTail, *pgUriCur; int pgUriContentCount; /* Pattern Matching data structures (MPSE) */ void *pgPms[PM_TYPE__MAX]; /* detection option tree */ void *pgNonContentTree; int avgLen; int minLen; int maxLen; int c1,c2,c3,c4,c5; /* * Not rule list for this group */ NOT_RULE_NODE *pgNotRuleList; /* ** Count of rule_node's in this group/list */ int pgCount; int pgNQEvents; int pgQEvents; }PORT_GROUP;
snort快速匹配的核心思想是使用规则集合中的某个特征不断将规则拆分为更小的子类,从而构建出树状结构,减小匹配路径。
对于像URI这样的字串匹配作专门的模式串构建,snort的匹配结构构建方式是多选一的,超酷.