pcapReader 原始碼分析

2021-07-31 23:11:35 字數 4235 閱讀 4134

pcapreader是ndpi開源中的乙個example。大家可以從/example/pcapreader.c中找到它的源**。通過pcaplib和ndpi相結合,進行深度包檢測。雖然只有短短的幾行**,但是他將展現的不僅是pcaplib和ndpi的使用方法,還有包分析的一些技巧。看完之後其實外國人寫的程式也就是那樣,並沒有什麼特別之處。我們先來一起看看基本的函式結構。

注:我們只對原始碼中的linux平台部分進行解釋

在main函式中,通過呼叫test_lib()對程式進行整合。   

123

4567

891011

1213

1415

1617

void

test_lib

()

來自code的**片

pcapreader_test_lib.c

runpcaploop()函式中通過pcap_loop(_pcap_handle, -1, &pcap_packet_callback, null)進行迴圈抓包。pcap_loop是pcaplib中提供的api。_pcap_handle指向的是網絡卡裝置,pcap_packet_callback是迴圈抓包之後的包處理函式,-1代表的是不停地抓直到抓包出錯的時候停止。接下來我們針對pcap_packet_callback函式中的包處理進行分析

pcap_packet_callback函式中,按順序分成4個主要部分:

1、ndpi_ethhdr進行資料鏈路層的拆包分析。針對linux cooked capture 和vlan的特殊包結構。對包頭和資訊進行了對應的偏移,並且記錄在ip_offset變數中。

2、ndpi_iphdr進行網路層的拆包。這裡進行了ipv4和ipv6的檢測,我們接下來只對ipv4進行介紹。

3、gtp隧道協議的處理

4、packet_processing()函式進一步的包處理

注:2中的網路層拆包儲存在iph變數中,並在packet_processing()中作為ndpi協議檢測的資料來源

packet_processing函式作為ndpi分析的主體,這裡通過get_ndpi_flow函式分類會話。然後利用ndpi_detection_process_packet函式進行資料分析得到應用層協議。我們繼續往下看看get_ndpi_flow是怎樣建立起資料結構的。

注:get_ndpi_flow6針對ipv6進行了轉換,最後還是通過get_ndpi_flow建立

get_ndpi_flow函式:

1、通過傳輸層拆包獲得協議包的源和目的埠(tcp通過ndpi_tcphdr 、udp通過ndpi_udphdr分別進行拆包)

2、結合網路層和傳輸層的資料,通過源目的ip和埠分類會話

3、以ndpi_flows_root為hash陣列,(lower_ip + upper_ip + iph->protocol + lower_port + upper_port) % num_roots計算出會話對應的陣列位置。然後對於陣列的每個單元維護乙個二叉查詢鍊錶。

4、通過ndpi_tfind函式對二叉樹進行查詢,如果存在相對應的會話,則返回對應結果。如果不存在,則通過ndpi_tsearch把新的會話插入二叉樹中。

node_cmp函式中定義了比較的規則。ndpi_tfind和ndpi_tsearch在/src/lib/ndpi_main.c檔案中進行的二叉查詢的封裝。

123

4567

891011

1213

1415

1617

1819

2021

2223

2425

2627

2829

3031

3233

3435

3637

3839

4041

4243

4445

typedef

struct

node_t

ndpi_node

; /* find a node, or return 0 */

void

*ndpi_tfind

(const

void

*vkey

,void

*vrootp

,int(*

compar

)(const

void*,

const

void*))

return

(ndpi_node*)0;}

void

*ndpi_tsearch

(const

void

*vkey

,void

**vrootp

,int(*

compar

)(const

void*,

const

void*))

q=(ndpi_node*)

ndpi_malloc

(sizeof

(ndpi_node

));/* t5: key not found */

if(q

!=(ndpi_node*)

0)return

((void*)

q);}

來自code的**片

1、setupdetection();//ndpi檢測協議的註冊,以及引數設定

通過ndpi提供的一系列函式,註冊需要深度檢測的協議。大略如下

ndpi_init_detection_module啟用cache支援,主要針對一些占用快取的協議如skype

ndpi_set_protocol_detection_bitmask2註冊需要進行檢測的協議

ndpi_detection_get_sizeof_ndpi_id_struct

ndpi_detection_get_sizeof_ndpi_flow_struct:獲取ndpi_flow_struct和ndpi_id_struct的大小在為二叉樹插入新節點時,申請空間和變數的初始化

2、openpcapfileordevice();//pcaplib的初始化準備

errbuf[pcap_errbuf_size]:pcaplib存放錯誤資訊的緩衝區

pcap_open_live開啟對應的網絡卡裝置

注:如果開啟失敗,或者命令中指定利用pcap_open_offline從檔案中讀入資料

pcap_datalink獲取當前資料鏈路的型別,一般為乙太網v2

pcap_compile和pcap_setfilter分別用於編譯和設定抓包的過濾規則

3、signal(sigint, sigproc);//包含在signal.h標頭檔案中,這裡主要互動式訊號,如中斷做出反應。觸發sigproc函式關閉程式   

123

4567

89

void

sigproc

(int

sig)

來自code的**片

pcapreader_signal.c

如果產生中斷,則呼叫如上函式關閉pcap和ndpi並且輸出結果。

4、closepcapfile();

通過pcap_close函式清除_pcap_handle指標並關閉抓包。

5、printresults(tot_usec);//輸出結果

6、terminatedetection();

通過ndpi_tdestroy釋放hash陣列及其陣列上的二叉查詢樹節點,最後通過ndpi_exit_detection_module結束ndpi程式。

7、static void parseoptions(int argc, char **argv)   /*命令列的實現,這裡argc和argv從main中argc和argv引數傳遞進來。*/

getopt函式是命令列分析 第三個引數解釋:

1).單個字元,表示選項

2).單個字元後接乙個冒號:表示該選項後必須跟乙個引數。引數緊跟在選項後或者以空格隔開。該引數的指標賦給optarg。

3).單個字元後跟兩個冒號,表示該選項後可以跟乙個引數,也可以不跟。如果跟乙個引數,引數必須緊跟在選項後不能以空格隔開。該引數的指標賦給optarg。

getopt中選項得到的引數傳遞給全域性變數optarg

spring原始碼分析 spring原始碼分析

1.spring 執行原理 spring 啟動時讀取應用程式提供的 bean 配置資訊,並在 spring 容器中生成乙份相應的 bean 配置登錄檔,然後根據這張登錄檔例項化 bean,裝配好 bean 之間的依賴關係,為上 層應用提供準備就緒的執行環境。二 spring 原始碼分析 1.1spr...

思科VPP原始碼分析(dpo機制原始碼分析)

vpp的dpo機制跟路由緊密結合在一起。路由表查詢 ip4 lookup 的最後結果是乙個load balance t結構。該結構可以看做是乙個hash表,裡面包含了很多dpo,指向為下一步處理動作。每個dpo都是新增路由時的乙個path的結果。dpo標準型別有 dpo drop,dpo ip nu...

redux原始碼分析(三) 原始碼部分

下面是每個部分的一些解讀 createstore apicreatestore reducer,initialstate enhancer 曾經非常好奇這個函式的第二個引數到底是initialstate還是enhancer,因為見過兩種寫法都有的,以為是版本問題。看了原始碼才發現,都可以的。如果你不...