1. 程式人生 > >網絡分流器-DPI深度數據包檢測

網絡分流器-DPI深度數據包檢測

color 編寫 模式 sha github 串行 all 簡單的 asi

網絡分流器-戎騰網絡-DPI檢測是當前比較流行的網絡監控前端的一種模式,而網絡分流器對於網絡安全的重要性可以說是到頭重要的!今天我們來聊聊DPI檢測
技術分享圖片
技術分享圖片

深度數據包檢測(DPI)

深度數據包檢測(Deep packet inspection,縮寫為 DPI)是一種特殊的網絡技術,一般網絡設備只會查看以太網頭部、IP頭部而不會分析TCP/UDP裏面的內容這種被稱為淺數據包檢測;與之對應的DPI會檢查TCP/UDP裏面的內容,所以稱為深度數據包檢測。
DPI一般是一個硬件或者軟件,一般用“旁掛”的方式接入到網絡。它會對網絡中的每個數據包進行檢查,識別出應用層協議,根據識別的協議采取一定的措施(比如記錄HTTP訪問行為)。對於TCP協議它可以識別完整的TCP交互過程(比如HTTP請求從請求到響應中間會有多次TCP數據包發送)。

技術分享圖片
戎騰網絡移動互聯網采集器支持160個10G和20個100G

nDPI
nDPI是一個C語言編寫的DPI庫,用來實現軟件DPI系統。它是從OpenDPI擴展而來,二者的架構和實現基本上差不多。
編譯安裝之後它生成/usr/local/lib/libndpi.(a,so)庫文件(a靜態庫文件,so動態鏈接庫);/usr/local/include/會安裝相關的頭文件。
我個人喜歡用 靜態庫文件,這樣會把所有的二進制代碼合並到一個可執行文件中運行的時候不需要安裝一大堆庫。另外我也不喜歡把東西放到/usr/local/lib下,所以我提供的代碼是通過cmake做了一個“all in one”的編譯。github上放到是1.6版本的,如果你想更新代碼只要替換src文件夾就行了。

如何用nDPI

nDPI的代碼寫 的很爛,也沒有什麽架構就是一團亂麻(其實稍微寫寫都要比這個好)。但是它至少還能正常工作而且是唯一一個“開放”的DPI庫,所以無論什麽原因你選擇了它都必須忍受它的“醜陋”。
nDPI幾乎沒有文檔說明,只帶了一個“ndpiReader”的例子,寫的“洋洋灑灑”如行雲流水一般(就不吐槽了)。這就是我這篇文章的寫作原因,希望能給使用nDPI的同學一點幫助。

nDPI最重要的一個數據結構是ndpi_detection_module_struct_t它通過ndpi_init_detection_module構造出來
技術分享圖片
網絡分流器
第一個參數用來計算nDPI分析協議的各種超時時間,一般精確到毫秒就可以了1000(nDPI協議分析部分和“全局部分”耦合非常緊,這個數據其實只有“協議分析模塊”需要)

第二個、三個參數是封裝過的“內存分配”函數;nDPI的內存管理非常亂,有些地方是我們自己申請內存而由nDPI內部幫我們釋放。所以必須nDPI並不直接使用malloc、free之類的申請、釋放內存而是交由程序員自己提供函數;

第三個參數是調試函數,如果定義了NDPI_ENABLE_DEBUG_MESSAGES那麽nDPI會調用這個函數輸出一些調試信息;

所有的nDPI API都是這種“鬼畜”風格,幾乎是各種糾結。。。萬幸我們只需要使用很少的API就可以完成任務了。

配置協議分析模塊

nDPI支持多種協議,都在protocols文件夾中。編譯的時候所有協議都會被放到nDPI庫中。使用的時候我們可以自己設置需要開啟那些分析模塊
技術分享圖片

NDPI_PROTOCOL_BITMASK定義開啟協議的“位圖”,通過NDPI_BITMASK_ADD函數可以添加支持的協議,最後調用ndpi_set_protocol_detection_bitmask2配置位圖。

ndpi_set_protocol_detection_bitmask2函數的第一個參數就是ndpi_detection_module_struct_t(上面我們初始化的那個數據結構);第二個參數是位圖標誌。

特別註意:開啟的協議越多識別速度越慢;nDPI識別協議的時候是一個串行結構,無論是否被成功是被都會認認真真遍歷完我們配置好的協議

子協議

子協議是某個協議的細分,比如我們想要分析所有“Google”的HTTP請求那麽第一步是分析出“HTTP”請求,第二步是判斷HOST包含google.com。這裏的第二步就是“子協議”。

nDPI唯一的一份“QuickStartGuide”對這個有進一步解釋,子協議識別是以配置文件的方式提供給nDPI的。比如
技術分享圖片

它還支持端口的方式(TCP的81、8181直接被標記為HTTP不再做內容檢測)

技術分享圖片
網絡分流器

nDPI此處的實現使用了一個非常有名的算法—— Aho-Corasick。以第一幅圖為例子,裏面配置了兩條規則“Google”和“Veneer”,我們有一個字符串(HOST),怎麽判斷這個字符串符合那個規則呢?最簡單的辦法是循環所有的規則,如果規則條目很多那麽速度會非常慢。Aho-Corasick就是這樣一種算法,它可以在O(n)中完成所有的匹配任務。

通過ndpi_load_protocols_file函數加載“子協議”。

開始識別

識別協議的API非常簡單——ndpi_detection_process_packet函數。就是這個坑爹的函數,變態程度幾乎可以說用令人發指來形容。

ndpi_struct全局的結構體
flow比較特殊,我們後面講
packet指向IP頭部的指針
packetlen數據包大小
current_tick_l當前時間(精確到毫秒)用於判斷“過期的TCP請求”
src,dst其實沒有什麽用途,文檔上說是跟狀態機有關其實沒有半毛錢關系。唯一的用途是更新“分析協議”的配置。一般設置為NULL就行了
TCP協議是一個流(flow)式的協議,經過從三次握手開始通訊雙方都是“請求->響應”的結構。DPI可以跟蹤其中的一個或者幾個數據包,也可以實現全部跟蹤(後續我會交叉使用TCP會話、會話、flow,三個名詞其實是一樣的)。

nDPI內部不會記錄完整的TCP數據包,而是用一個定義非常模糊的ndpi_flow_struct類型來表示一個TCP會話(這個數據結構還包含了“協議分析”部分數據,所以定義非常模糊)。為了便於分析完整的TCP請求我們定義了一個自己的數據結構dpi_flow_t,ndpi_flow_struct作為它的一個成員。用偽代碼表示分析過程:

落到代碼上就是get_ndpi_flow函數;實現上我們會對目標、源端口排序再做hash;這是由於數據包是“相互通訊”的所以發送方、接收方是相對而言,否則識別到的可能是“一方”的數據。

一般我們用一個二叉樹存放所有正在分析的TCP會話,nDPI移植了FreeBSD中的一組函數ndpi_tfind、ndpi_tsearch、ndpi_twalk、ndpi_tdelete等用來實現常用的數據結構操作。
技術分享圖片

網絡分流器-DPI深度數據包檢測