suricata源碼之tag

tag是suricata提供的一個規則關鍵字,但是在suricata的說明文檔,這裏並沒有給出關鍵字的解釋,因爲他是爲了兼容snort規則而支持的一個關鍵字。

tag的字面含義就是標籤的意思。通常來說當一個規則命中的時候,往往會去記錄命中該規則報文的信息,如果想要按照個人需求記錄更多的信息,比如記錄該規則命中之後10秒內該條流上所有的報文信息或者命中之後10個上行報文信息,該怎麼辦呢?這其實就是tag關鍵字所能夠提供的能力,即標記規則命中之後的指定流量信息,用於指導日誌對這些流量進行輸出,方便分析。

例如:

 alert tcp any any -> any 53 (sid:100; tag:session,10,seconds;)

上述規則表示的就sid爲100的這條規則在命中之後,該條TCP流上10秒內的流量都需要記錄。

tag關鍵字的基本格式如下:

tag:type, count, metric, direction;

type有如下兩種:

  • 1,session,表示的是tag標記的是一個具體的流。
  • 2,host,表示tag標記的是IP地址,也就是跟當前匹配報文具有相同IP地址的報文上。

count表示基數。metric表示單位,可以是packets ,seconds ,bytes 。兩者配合使用,即規則觸發之後記錄多長時間或者多少個報文,再或者是多少流量的數據。

direction可以是src ,dst ,exclusive 。其中當type爲host類型的時候使用src,dst表示的是標記源,目的IP地址的報文。當type爲session的時候使用exclusive,表示僅標記第一個匹配該規則的流,其他的流不標記。

下面從源碼的角度看看tag的功能是如何實現的,包括tag關鍵字的解析,打標籤,去標籤以及在實現tag功能過程中用到的數據結構和方法思路。

tag規則解析

對應的函數爲DetectTagSetup,最終會將解析之後的結果放入DetectTagData結構中,對應的就是前面tag格式中的幾個字段內容。真正的解析函數爲DetectTagParse,使用的是pcre,在suricata中多數關鍵字的解析都是這樣實現的。有一點需要注意的是,SigMatchAppendSMToList在解析之後的規則加入的是DETECT_SM_LIST_TMATCH這個sm list。一般的非字符串匹配的規則加入的是DETECT_SM_LIST_MATCH中,通常是傳輸層以下的匹配,字符串匹配的規則加入的是DETECT_SM_LIST_PMATCH,通常是傳輸層以上的匹配,後置規則的匹配加入的是DETECT_SM_LIST_POSTMATCHDETECT_SM_LIST_TMATCH這個sm list專門用於tag的匹配。

tag打標籤

tag作用的type要麼是流要麼是一類的IP地址。標籤中的數據包括要匹配的流量條件以及當前已經匹配的內容,即DetectTagDataEntry結構的內容。標籤數據要和流或者報文進行關聯,由於tag的內容並不是flow或則和packet的必選內容,而且完全依賴於規則。規則中有了tag規則,命中該規則之後纔會有tag的數據與流或者packet進行關聯,沒有則則不需要關聯。其出現的概率不大,直接放在flow或者packet結構中會浪費內存。因此suricata對於這類可可選的資源信息進行統一的抽象,將其命名爲storage。這一塊存儲可以是tag信息,也可以是其他的信息。將這個storage與流或者報文進行關聯即可。來看看tag是如何實現的:

在流表管理這篇文章中,提到在每條流申請的時候,每條流結構內存之後額外申請了一些指針的空間用於指向與這條流有關的數據內容。如果這條流命中的規則中包含tag,那麼就會有一個指針指向tag數據的內存。流程如下:
1,數據包的後置匹配調用爲DetectRunPostRules->PacketAlertFinalize->DetectTagMatch

由於DETECT_SM_LIST_TMATCH這個sm list只用於tag關鍵字,因此簡單的搜索一下,可以發現tag規則的匹配是在DetectRunPostRules->PacketAlertFinalize即後置匹配函數中進行調用,如下代碼:

if (s->sm_arrays[DETECT_SM_LIST_TMATCH] != NULL) {
                KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_TMATCH);
                SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_TMATCH];
                while (1) {
                    /* tags are set only for alerts */
                    KEYWORD_PROFILING_START;
                    sigmatch_table[smd->type].Match(NULL, det_ctx, p, (Signature *)s, smd->ctx);
                    KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
                    if (smd->is_last)
                        break;
                    smd++;
                }
            }

其中match的匹配函數是DetectTagMatch

2,要明白的是tag關鍵字的目的並不是去匹配,而是給流或者packet包打上標誌,以流爲例說明打標籤的過程。

DetectTagMatch->TagFlowAdd中:

  • 1,FlowGetStorageById查看該流後面有沒有tag數據。
  • 2,如果有就更新與這條流有關的tag存儲的數據,如果該條流有關的tag有多個,需要遍歷。
  • 3,如果是剛剛匹配上,這個時候還沒有tag數據,則需要DetectTagDataCopy新建這樣的tag數據,並通過FlowSetStorageById函數讓流結構體後面的指針指向此處。這樣同一條流上的下個報文來的時候就能通過流中的指針指向找到tag數據並更新。

3,type爲session的類型的tag打在流上,那麼type爲host的標籤打在哪個上面呢?

因爲流是全局的hash表,當packet過來的時候很容易根據五元組找到該流的內存位置,然後找到tag。同樣的當packet過來的時候,要想找到host地址對應的tag數據,則也需要一個全局的host表,根據packet的源或者目的IP找到host的內存位置,然後找到tag。那麼host表完全可以參照flow表的設計,用hash表來組織,用IP地址來進行索引。如果你看過我前面文章對於流表的解釋,相信host表也很容易理解。host表的目的也很簡單,爲了支持對於像tag這類作用在IP地址上的規則,而額外建立的用於索引IP地址相關數據之用。採用同樣設計的這種全局表還包括Defrag表,IPPair表等,這幾個全局表都存在着時效性的問題,都需要老化,老化的操作是在FlowManager之中,這幾個表將在後續單獨的分析。

tag去標籤

由於tag標籤也是具有時效性的,要麼是時間多少秒,要麼是多少個packets包,要麼是多少個字節的數據。因此在這些條件達到之後,tag數據也就失去了意義,需要進行回收處理,該回收處理的過程就是PacketAlertFinalize->TagHandlePacket。可以看到無論在TagHandlePacketFlow流tag的回收還是TagHandlePacketHost IP tag的回收。都是在達到限定條件之後,將tag的內存數據進行釋放。

本文爲CSDN村中少年原創文章,轉載記得加上原創出處,博主鏈接這裏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章