libpcap體現的不是捕捉技術上的難點,而是對細節的控制上,對跨平臺代碼的編寫上,對過濾機制的優化上。
大象的命門是在腳筋,也就是支撐的地方。 很顯然,得先對接口的流動和他的數據結構有個了解。而且在這套庫里面看到了好多人的代碼和自己的功能說明,感覺著一種合作開放的精神。
剪枝刪節,將其中linux部分提了出來,涉及到的文件大概有:
inet.c fad-getad.c pcap-linux.c pcap-int.h pcap.c
整個的大概結構是,查找設備,確定設備,過濾條件的嵌入,套接字的創建,網卡的設置,包的捕獲。
查找設備:用到的函數有pcap_lookupdev()-pcap_findalldevs()-getifaddrs()-add_addr_to_iflist()//inet.c fad_getad.c
該函數是將所找到的設備信息用連表連接起來,設備號小的在前,因此通常是eth0.
數據結構為struct pcap_if{},//pcap.h
打開網絡設備:2。0以后的linux內核版本用新的協議簇PF_PACKET來實現。早期是(SOCK_PACKET)他的形式可以是SOCK_RAW和SOCK_DGRAM。RAW是原始數據,DGRAM是對數據包進行加工,把數據包的鏈路層頭部去掉,使用sockaddr_ll來保存。在兩種情況下RAW不可用:某些類型設備數據鏈路層頭部不可用,當捕捉為any時,為了是包過濾機制在所有類型數據包上正常工作,要求所有數據使用相同數據鏈路頭部。
pcap-linux.c
pcap_open_live();用到的數據結構是pcap_t,//pcap-int.h,這是一個比較重要的參數,主要包括對socket的描述,和一些底層上的設置。比如緩沖區大小,設備類型,邊界對齊等,對應的函數指針,可更改的鏈路數,BPF過濾代碼是否能使用等。
pcap_stat stat;//pcap.h,捕捉狀態結構,包括是否過濾,接受包的數目,丟棄的數目等。
在函數內部有new和old兩種版本,分別對2.0前后的版本創建socket.而在其內部的選擇上,又涉及到對是否支持鏈路層頭部結構的判斷,最后將網卡設為混雜模式,創建socket
在這一層中,libpcap提供的用戶程序接口是pcap_next()//pcap.c,通過跟蹤可發現,它最后是調用pcap_read_packet//pcap-linux.c接收。接收完后做的工作如下:偏移量設置,為了給偽數據鏈路層留出空間,接著要修正長度,判斷是否有用內核級的包過濾,最后填充捕獲時間/長度/時間,對包數據累加。
完成以上兩個步驟,發現最關鍵兩個步驟就是找設備的函數,和socket的創建。但是通過查看源代碼可知,作者在跨平臺,細節處理,包通用的完善性上做了很多很多的工作,這無一不給我們提供了一個很好的學習尺度。
接下來是對過濾機制的描述:
這個我想是最有難點的地方了,一些算法不做描述,查看pcap-bpf.h,gencode.c,optimize.c,grammar,c,scanner.c
用到的特性有這么幾個:因為在捕捉時,是先經過捕捉,然后把控制權再給數據鏈路,這樣就直接在內核緩沖內進行過濾。而在算法是上使用BPF包過濾機制,算法上很復雜,使用偽機器碼的方式,類似于匯編語言。如果是以后做到類似多重判斷跳轉之類的可以參考里面的無環控制流圖CFG的實現.
個人認為該庫很大一部分研究價值除了跨平臺編寫,還有就是對linux底層過濾器的調用使用。