基于Linux C的socketEthereal程序和Package分析 (一个)
執(zhí)行測試平臺:CentOS 6.5發(fā)行版,內核版本號3.11
1. Linux抓包源程序
在OSI七層模型中。網(wǎng)卡工作在物理層和數(shù)據(jù)鏈路層的MAC子層。
進行網(wǎng)絡通信時。源主機通過socket(或其他)應用程序產生IP報文,經(jīng)過各個OSI層層封裝,數(shù)據(jù)包以Ethernet幀的形式進入物理層。Ethernet幀包括源主機地址、IP報文、目標地址(IP地址、port號或映射的6字節(jié)MAC地址)和須要傳送到目標主機的其他信息。
目標的MAC地址是哪里來的呢?這牽扯到一個ARP協(xié)議(介乎于網(wǎng)絡層和數(shù)據(jù)鏈路層的一個協(xié)議)。第一次傳送某個目的IP地址的數(shù)據(jù)的時候,先會發(fā)出一個ARP包。其MAC的目標地址是廣播地址,里面說到:"誰是xxx.xxx.xxx.xxx這個IP地址的主人?"由于是廣播包,全部這個局域網(wǎng)的主機都收到了這個ARP請求。
收到請求的主機將這個IP地址和自己的相比較,假設不同樣就不予理會,假設同樣就發(fā)出ARP響應包。
這個IP地址的主機收到這個ARP請求包后回復的ARP響應里說到:"我是這個IP地址的主人"。這個包里面就包含了他的MAC地址。
以后的給這個IP地址的幀的目標MAC地址就被確定了。
就這樣,以太網(wǎng)幀開始在數(shù)據(jù)鏈路層傳播。Ethernet幀在鏈路層基于廣播方式傳播,即網(wǎng)段內的全部網(wǎng)卡都能觀察該幀,但僅僅有一個網(wǎng)卡通過對照6字節(jié)MAC地址發(fā)現(xiàn)與自己相符。然后它就接收該幀。而其他網(wǎng)卡則放棄該幀。(其他網(wǎng)卡也能夠接受該幀,即實際的網(wǎng)絡Sniffer,可進行信息竊取等操作)
網(wǎng)卡得到Ethernet幀后。通過網(wǎng)絡驅動程序和上層協(xié)議對其進行還原操作,即層層剝離報文頭后將數(shù)據(jù)交由目標主機的socket(或其他)應用程序使用。
假設我們須要原始的以太網(wǎng)幀,以便觀察與目標主機進行通信的源主機信息,則能夠通過建立基于PF_PACKET的socket應用程序實現(xiàn)。PF_PACKET協(xié)議簇同意應用程序直接獲得網(wǎng)絡驅動程序得到的數(shù)據(jù)幀信息。PF_PACKET支持SOCK_DGRAM和SOCK_RAW兩種socket類型,前者利用操作系統(tǒng)處理報文頭,而后者則將以太網(wǎng)幀直接交由應用程序處理。
須要注意到是,僅僅有root權限用戶才干使用PF_PACKET程序。
以下的代碼就可以實現(xiàn)由應用程序直接獲得以太網(wǎng)幀的需求。
#include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <linux/if_ether.h> #include <linux/in.h>#define BUFFER_MAX 2048int main(int argc, char *argv[]){int SOCKET_SRC;char buf[BUFFER_MAX];int n_rd;if( (SOCKET_SRC = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0 ){fprintf(stderr, "create socket error.\n");exit(0);}while(1){n_rd = recvfrom(SOCKET_SRC, buf, BUFFER_MAX, 0, NULL, NULL);if (n_rd<46) {perror("recvfrom():");printf("Incomplete packet (errno is %d)\n", errno);close(SOCKET_SRC);exit(0);}/* An Ethernet frame was written to buf, frame analysis can be processed here *//* Termination control */}close(SOCKET_SRC);return 0; }
2. 數(shù)據(jù)包(以太網(wǎng)幀)分析
一個以太網(wǎng)幀(RFC894)的數(shù)據(jù)格式例如以下圖所看到的。
以太網(wǎng)幀(RFC894)格式
程序通過運行一次
n_rd = recvfrom(SOCKET_SRC, buf, BUFFER_MAX, 0, NULL, NULL);
就將上面一條以太網(wǎng)幀寫入buf中。
(1) 為了從buf中提取以太網(wǎng)報文頭,我們能夠定義例如以下結構體。
typedef struct mac_frm_hdr {char dest_addr[6]; //destination MAC address shall be defined first.char src_addr[6];short type;}__attribute__((packed)) MAC_FRM_HDR;
定義該結構體時,須要注意下面幾點。
a.各屬性需按幀格式的出現(xiàn)順序定義。
b.數(shù)據(jù)類型長度必須和幀中對應區(qū)域的長度同樣。
c. 使用__attribute__((packed))取消編譯器自己主動優(yōu)化對齊結構體,也是為了保證屬性長度和幀中對應區(qū)域的長度同樣。
(2)為了提取IP報文頭。依據(jù)IP報文頭的格式。我們可定義例如以下結構體。
typedef struct ip_hdr{ //header of IPV4#ifdef __LITTLE_ENDIAN_BIFIELDu_char ip_len:4, ip_ver:4;#elseu_char ip_ver:4, ip_len:4;#endifu_char ip_tos;u_short ip_total_len;u_short ip_id;u_short ip_flags;u_char ip_ttl;u_char ip_protocol;u_short ip_chksum;u_int32 ip_src;u_int32 ip_dest; }__attribute__((packed)) IP_HDR;
為保證各屬性長度與IP報文頭中一致,我們應該在定義該結構體前作例如以下聲明。
typedef int int32; typedef unsigned int u_int32; typedef unsigned char u_char; typedef unsigned short u_short;
注意事項參考定義以太網(wǎng)幀結構體。
(3)為了提取UDP/TCP報文頭,可依據(jù)UDP/TCP報文頭格式。定義對應結構體,這里不作贅述。
以下是對以太網(wǎng)幀進行解析的詳細代碼。
/*************************************************************************
????> Author: kleguan
??? >? 如用不當之處,歡迎指正
??? >? 轉載請注明出處
?? ************************************************************************/
版權聲明:本文博客原創(chuàng)文章。博客,未經(jīng)同意,不得轉載。
總結
以上是生活随笔為你收集整理的基于Linux C的socketEthereal程序和Package分析 (一个)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OAF_开发系列21_实现OAF事物控制
- 下一篇: Android Studio添加jar包