现在是2020年2月5号,因为疫情在家,决定写写博客见证自己的学习过程。处女作,希望大家有好的建议请在评论区给我留言。
这是我第一次如此认真的阅读一个优秀开源软件. 在工作中已经有别人提供的匹配模块,但是我更希望自己也能够掌握这个算法。
- ac算法的原理
Aho-Corasick自动机算法,简称就叫做AC算法。
那什么是自动机呢?
ac自动机本质是一颗带状态的字典树,自动机中每一个节点都有自己的状态,通过输入字符到自动机,会在自动机中发生状态转移,当到达一个节点,他的状态是命中时,可以输出结果。(纯属个人的理解,希望大家斧正)
黑色是起始状态,蓝色是命中状态
如果输入字符集为 ab , 输入a走到节点1,输入b走到节点4,此时4是终止节点,退出自动机。
ac的特点
ac在用于匹配之前需要构建两张表,fail表 和 output表。就是失败表和输出表。
字典树的作用是合并了拥有相同前缀模式串的公共前缀。
fail是用于当模式串A的前缀是模式串B的子串时,会有fail指针,例如 abcd 和 bbabce。作用是当匹配失败时会利用已经匹配到的子串继续匹配,(已经匹配串的子串是否是其他模式串的前缀),而不用回溯到开始的位置重新匹配。
output用于当包含模式串如 abcdef 和 def时,待匹配字符串“123abcdef”同时命中了两个字符串。需要把两个字符串都加入到“f”节点的输出表中。
- snort是如何实现的?
代码参照snort 4版本以上。算法实现在acsmx2.h中。
现在我们结合代码,使用一个例子来分析这个过程。
首先介绍几个数据结构:
struct ACSM_PATTERN2
{
ACSM_PATTERN2* next;//下一条模式串uint8_t* patrn;//忽略大小写模式串
uint8_t* casepatrn;//区分大小写模式串int n;//模式串长度
int nocase;//是否区分大小写
int negative;
};
//这里定义了acstate_t 类型,默认是 unsigned short,会节约内存的使用。
#define AC32
#ifdef AC32
typedef unsigned int acstate_t;
#define ACSM_FAIL_STATE2 0xffffffff#else
typedef unsigned short acstate_t;
#define ACSM_FAIL_STATE2 0xffff#endif
/*
* transition nodes - either 8 or 12 bytes* 这是用来预编译临时使用的链表节点
*/
struct trans_node_t
{
/* The character that got us here - sized to keep structure aligned on 4 bytes