pcapreader是ndpi開源中的乙個example。大家可以從/example/pcapreader.c中找到它的源**。通過pcaplib和ndpi相結合,進行深度包檢測。雖然只有短短的幾行**,但是他將展現的不僅是pcaplib和ndpi的使用方法,還有包分析的一些技巧。看完之後其實外國人寫的程式也就是那樣,並沒有什麼特別之處。我們先來一起看看基本的函式結構。
注:我們只對原始碼中的linux平台部分進行解釋
在main函式中,通過呼叫test_lib()對程式進行整合。
1234567
891011
1213
1415
1617
void來自code的**片test_lib
()
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檔案中進行的二叉查詢的封裝。
1234567
891011
1213
1415
1617
1819
2021
2223
2425
2627
2829
3031
3233
3435
3637
3839
4041
4243
4445
typedef來自code的**片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);}
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函式關閉程式
1234567
89
void來自code的**片sigproc
(int
sig)
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,因為見過兩種寫法都有的,以為是版本問題。看了原始碼才發現,都可以的。如果你不...