深度資料報檢測(dpi)
深度資料報檢測(deep packet inspection,縮寫為 dpi)是一種特殊的網路技術,一般網路裝置只會檢視乙太網頭部、ip頭部而不會分析tcp/udp裡面的內容這種被稱為淺資料報檢測;與之對應的dpi會檢查tcp/udp裡面的內容,所以稱為深度資料報檢測。
dpi一般是乙個硬體或者軟體,一般用「旁掛」的方式接入到網路。它會對網路中的每個資料報進行檢查,識別出應用層協議,根據識別的協議採取一定的措施(比如記錄http訪問行為)。對於tcp協議它可以識別完整的tcp互動過程(比如http請求從請求到響應中間會有多次tcp資料報傳送)。
編譯安裝之後它生成/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函式。就是這個坑爹的函式,**程度幾乎可以說用令人髮指來形容。
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等用來實現常用的資料結構操作。
完成分析
呼叫完ndpi_detection_process_packet函式後我們需要檢查返回值,如果它不等於ndpi_protocol_unknown證明就找到了協議型別。
dpi分析一般分為三種情況:
前兩種情況可以合二為一,都是判斷出協議型別後釋放資源;第三種請比較特殊,我們需要遍歷整個二叉樹尋找「過期」的flow然後刪除。這就是例子中最後一部分的含義(遍歷的時候我們每次尋找乙個flow,用變數idle_scan_idx表示)。
Kinect 深度資料
kinect兩側的感測器負責獲取深度資料 深度資料是指kinect視野範圍內的物體到kinect的三維空間距離。深度資料流提供了一種結構 該結構中每個畫素的高13位表示在深度感測器的視野範圍內離特定座標物體最近的距離。在kinect sdk中,通過處理深度資料來識別感測器組前的兩個人體影象。從程式中...
Kinect深度資料文字分析
深度值計算公式 depth pixeldata i depthimageframe.playerindexbitmaskwidth 解析 pixeldata存放的是short型資料,原始資料為二進位制,2個位元組,16位。在vs中以十進位制方式顯示 depthimageframe.playerind...
Kinect獲取深度資料利用色彩展示
根據微軟資料顯示,kinect v2的深度幀資料為0.5m 8m,每一幀的大小為512 424 pixel 每一畫素點的深度值存放在乙個16位bit的ushort中。這裡的深度是指畫素點到kinect sensor平面的距離,網上有資料說資料的前13位表示距離,後3位表示使用者id,也有說12 4的...