網絡分流器-戎騰網絡-DPI檢測是當前比較流行的網絡監控前端的一種模式,而網絡分流器對於網絡安全的重要性能夠說是到頭重要的!今天咱們來聊聊DPI檢測
前端
深度數據包檢測(DPI)git
深度數據包檢測(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文件夾就好了。github
如何用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就能夠完成任務了。ide
配置協議分析模塊
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的8一、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等用來實現經常使用的數據結構操做。