linux下libpcap抓包分析
一、首先下載libpcap包http://www.tcpdump.org/
然后安裝,安裝完成后進(jìn)入安裝根目錄的tests文件夾,編譯運行findalldevstest.c(編譯時加上-lpcap),查看是否發(fā)現(xiàn)所有網(wǎng)絡(luò)設(shè)備。
二、下載wireshark觀察抓包軟件的各種功能
三、熟悉libpcap工作原理:
四、了解libpcap抓包基本流程:
五、編程實現(xiàn)
未完待續(xù)。。。
PS:整理了一下libpcap常用的數(shù)據(jù)類型定義
libpcap的類型定義:
0)、typedef int bpf_int32
1)、typedef u_int bpf_u_int32
32bit 的無類型整形;
2)、typedef pcap pcap_t
Descriptor of an open capture instance(一個打開的捕獲實例的描述符?)這個結(jié)構(gòu)對用戶是不透明的。
3)、typedef pcap_dumper pcap_dumper_t
libpcap保存文件的描述符。
4)、typedef pcap_if pcap_if_t
網(wǎng)卡鏈表的一個元素;
5)、typedef pcap_addr pcap_addr_t
網(wǎng)卡地址的表示;
6)、typedef void (*pcap_handler)(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
其中agrs是從pcap_dispatch()函數(shù)傳遞過來的第四個形參 ,一般我們自己的包捕捉程序不需要提供它,總是為NULL ;header指向
pcap_pkthdr結(jié)構(gòu),該結(jié)構(gòu)位于真正的物理幀前面,用于消除不同鏈路層支持的差異 ;packet指向所捕獲報文的物理幀。
libpcap結(jié)構(gòu)體
Libpcap庫函數(shù)所必須的數(shù)據(jù)結(jié)構(gòu)定義主要包含在pcap.h和pcap-int.h兩個頭文件中
1)、pcap結(jié)構(gòu)在pcap-int.h頭文件中被定義:
編程時需要涉及到的成員有:int fd; 打開設(shè)備的描述符;u_char *buffer; 是指向所捕獲到數(shù)據(jù)的緩沖區(qū)指針
struct pcap
{
int fd; /* 文件描述字,實際就是 socket */
int selectable_fd; /* 在 socket 上,可以使用 select() 和 poll() 等 I/O 復(fù)用類型函數(shù) */
int snapshot; /* 用戶期望的捕獲數(shù)據(jù)包最大長度 */
int linktype; /* 設(shè)備類型 */
int tzoff; /* 時區(qū)位置,實際上沒有被使用 */
int offset; /* 邊界對齊偏移量 */
int break_loop; /* 強制從讀數(shù)據(jù)包循環(huán)中跳出的標(biāo)志 */
struct pcap_sf sf; /* 數(shù)據(jù)包保存到文件的相關(guān)配置數(shù)據(jù)結(jié)構(gòu) */
struct pcap_md md; /* 具體描述如下 */
int bufsize; /* 讀緩沖區(qū)的長度 */
u_char buffer; /* 讀緩沖區(qū)指針 */
u_char *bp;
int cc;
u_char *pkt;
/* 相關(guān)抽象操作的函數(shù)指針,最終指向特定操作系統(tǒng)的處理函數(shù) */
int (*read_op)(pcap_t *, int cnt, pcap_handler, u_char *);
int (*setfilter_op)(pcap_t *, struct bpf_program *);
int (*set_datalink_op)(pcap_t *, int);
int (*getnonblock_op)(pcap_t *, char *);
int (*setnonblock_op)(pcap_t *, int, char *);
int (*stats_op)(pcap_t *, struct pcap_stat *);
void (*close_op)(pcap_t *);
/*如果 BPF 過濾代碼不能在內(nèi)核中執(zhí)行,則將其保存并在用戶空間執(zhí)行 */
struct bpf_program fcode;
/* 函數(shù)調(diào)用出錯信息緩沖區(qū) */
char errbuf[PCAP_ERRBUF_SIZE + 1];
/* 當(dāng)前設(shè)備支持的、可更改的數(shù)據(jù)鏈路類型的個數(shù) */
int dlt_count;
/* 可更改的數(shù)據(jù)鏈路類型號鏈表,在 linux 下沒有使用 */
int *dlt_list;
/* 數(shù)據(jù)包自定義頭部,對數(shù)據(jù)包捕獲時間、捕獲長度、真實長度進(jìn)行描述 [pcap.h] */
struct pcap_pkthdr pcap_header;
};
/* 包含了捕獲句柄的接口、狀態(tài)、過濾信息 [pcap-int.h] */
struct pcap_md {
/* 捕獲狀態(tài)結(jié)構(gòu) [pcap.h] */
struct pcap_stat stat;
int use_bpf; /* 如果為1,則代表使用內(nèi)核過濾*/
u_long TotPkts;
u_long TotAccepted; /* 被接收數(shù)據(jù)包數(shù)目 */
u_long TotDrops; /* 被丟棄數(shù)據(jù)包數(shù)目 */
long TotMissed; /* 在過濾進(jìn)行時被接口丟棄的數(shù)據(jù)包數(shù)目 */
long OrigMissed; /*在過濾進(jìn)行前被接口丟棄的數(shù)據(jù)包數(shù)目*/
#ifdef linux
int sock_packet; /* 如果為 1,則代表使用 2.0 內(nèi)核的 SOCK_PACKET 模式 */
int timeout; /* pcap_open_live() 函數(shù)超時返回時間*/
int clear_promisc; /* 關(guān)閉時設(shè)置接口為非混雜模式 */
int cooked; /* 使用 SOCK_DGRAM 類型 */
int lo_ifindex; /* 回路設(shè)備索引號 */
char *device; /* 接口設(shè)備名稱 */
/* 以混雜模式打開 SOCK_PACKET 類型 socket 的 pcap_t 鏈表*/
struct pcap *next;
#endif
};
(2)bpf_program結(jié)構(gòu)
該結(jié)構(gòu)在pcap_compile()函數(shù)中被使用,在bpf.h頭文件中定義。
/* [pcap-bpf.h] */
struct bpf_program {
u_int bf_len; /* BPF 代碼中謂詞判斷指令的數(shù)目 */
struct bpf_insn *bf_insns; /* 第一個謂詞判斷指令 */
};
/* 謂詞判斷指令結(jié)構(gòu) */
struct bpf_insn {
u_short code;
u_char jt;
u_char jf;
bpf_int32 k;
};
(3)
/usr/include/net/bpf.h
/*
* Structure prepended to each packet.
*/
內(nèi)核過濾器每輸出一個包,將在輸出的數(shù)據(jù)前加了20字節(jié)的數(shù)據(jù),這就是 struct bpf_hdr
struct bpf_hdr
{
struct timeval bh_tstamp; /* time stamp */
bpf_u_int32 bh_caplen; /* length of captured portion數(shù)據(jù)長度*/
bpf_u_int32 bh_datalen; /* original length of packet實際包長度 */
u_short bh_hdrlen; /* length of bpf header (this struct
plus alignment padding) */
};
(4)pcap_stat結(jié)構(gòu)
調(diào)用函數(shù) pcap_stats() 可以返回一個該結(jié)構(gòu)
struct pcap_stat {
u_int ps_recv; /* number of packets received */
u_int ps_drop; /* number of packets dropped */
u_int ps_ifdrop; /* drops by interface XXX not yet supported */
};
5)、
struct pcap_addr:網(wǎng)卡地址描述
{
pcap_addr *next;如果非空,指向鏈表中一個元素的指針;空表示鏈表中的最后一個元素
sockaddr *addr; 指向包含一個地址的sockaddr的結(jié)構(gòu)的指針
sockaddr *netmask;如果非空,指向包含相對于addr指向的地址的一個網(wǎng)絡(luò)掩碼的結(jié)構(gòu)
sockaddr *broadaddr;如果非空,指向包含相對于addr指向的地址的一個網(wǎng)絡(luò)掩碼的結(jié)構(gòu)
sockaddr *dstaddr; 如果非空,指向一個相對于addr指向的源地址的目的地址,如果網(wǎng)絡(luò)不支持點對點通訊,則為空
};
6)、dump文件格式
首先是Dump文件頭
struct pcap_file_header {
bpf_u_int32 magic;
u_short version_major;
u_short version_minor;
bpf_int32 thiszone; /* gmt to local correction */
bpf_u_int32 sigfigs; /* accuracy of timestamps */
bpf_u_int32 snaplen; /* max length saved portion of each pkt */
bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */
};
然后是每一個包的包頭和數(shù)據(jù)
pcap_pkthdr結(jié)構(gòu)
/usr/include/pcap.h
/*
* Each packet in the dump file is prepended with this generic header.
* This gets around the problem of different headers for different
* packet interfaces.
*/
/* 自定義頭部在把數(shù)據(jù)包保存到文件中也被使用 */
struct pcap_pkthdr
{
struct timeval ts; /* 捕獲時間戳 */
bpf_u_int32 caplen; /* 捕獲到數(shù)據(jù)包的長度 */
bpf_u_int32 len; /* 數(shù)據(jù)包的真正長度 */
}
/* 單個數(shù)據(jù)包結(jié)構(gòu),包含數(shù)據(jù)包元信息和數(shù)據(jù)信息 */
struct singleton [pcap.c]
{
struct pcap_pkthdr hdr; /* libpcap 自定義數(shù)據(jù)包頭部 */
const u_char * pkt; /* 指向捕獲到的網(wǎng)絡(luò)數(shù)據(jù) */
};
7)、pcap_if (libpcap 自定義的接口信息鏈表 [pcap.h])
struct pcap_if
{
struct pcap_if *next;
char *name; /* 接口設(shè)備名 */
char *description; /* 接口描述 */
/*接口的 IP 地址, 地址掩碼, 廣播地址,目的地址 */
struct pcap_addr addresses;
bpf_u_int32 flags; /* 接口的參數(shù) */
};
總結(jié)
以上是生活随笔為你收集整理的linux下libpcap抓包分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 视频流媒体服务器如何通过ONVIF探测和
- 下一篇: VI使用的小白教程