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的匹配結構構建方式是多選一的,超酷.