libpcap使用總結!
libpcap 是一個開發sniffer的工具包。pcap:packet capture!
libpcap的數據類型定義:
struct pcap_addr:網卡地址描述
{
pcap_addr * next;
sockaddr * addr;
sockaddr *.netmask;
sockaddr *broadaddr;
sockaddr *dstaddr;
};
pcap_addr * next;
如果非空,指向鏈表中一個元素的指針;空表示鏈表中的最后一個元素。
sockaddr * addr;
指向包含一個地址的sockaddr的結構的指針。
sockaddr * netmask;
如果非空,指向包含相對于addr指向的地址的一個網絡掩碼的結構。
sockaddr * broadaddr;
如果非空,指向包含相對于addr指向的地址的一個廣播地址,如果網絡不支持廣播可能為空。
sockaddr * dstaddr;
如果非空,指向一個相對于addr指向的源地址的目的地址,如果網絡不支持點對點通訊,則為空。
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; /* aclearcase/" target="_blank" >ccuracy of timestamps */
bpf_u_int32 snaplen; /* max length saved portion of each pkt */
bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */
};
bpf_u_int32 magic;
????????????????????????????????
u_short version_major;
Libpcap的主版本號。
u_shart version_minor;
Libpcap的從版本號。
bpf_u_int32 sigfigs;
時間戳描述。
bpf_u_int32 snaplen;
保存的每個pkt的分片號的最大值。
bpf_u_int32 linktype;
數據鏈的類型。
細節說明:
libpcap dump文件頭;
libpcap dump文件中的第一個記錄包含了一些標志的保存值,這些標志在打印階段用到。這兒的很多域都是32位的int,所以compilers不用進行轉化;這些文件需要具有跨層次的可交換性。
無論如何不要改變結構的層次(包括僅僅改變這個結構中域的長度);
struct pcap_if { /*網卡數據鏈的一個元素*/
struct pcap_if *next;
char *name; /* name to hand to "pcap_open_live()" */
char *description; /* textual description of interface, or NULL */
struct pcap_addr *addresses;
u_int flags; /* PCAP_IF_ interface flags */
};
pcap_if *next;
如果非空,指向鏈的下一個元素。如果為空是鏈的最后一個元素。
char * name;
指向一個字符串,該字符串是傳給pcap_open_live()函數的設備名;
char * description;
如果非空,指向一個對設備的人性化的描述字符串。
pcap_addr *addresses;
指向網卡地址鏈中的第一個元素。
u_int flags;
PCAP_IF_ 網卡的標志?,F在唯一可用的標識是PCAP_IF_LOOKBACK,它被用來標識網卡是不是lookback網卡。
struct pcap_pkthdr { /*dump 文件中的數據包頭*/
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* length this packet (off wire) */
};
timeval ts;
數據報時間戳;
bpf_u_int32 caplen;
當前分片的長度;
dpf_u_int32 len;
這個數據報的長度;
細節描述:
在dump文件中的每個數據報都有這樣一個報頭。它用來處理不同數據報網卡的不同報頭問題。
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 */
};
u_int ps_recv;
接受數據報的數目;
u_int ps_drop;
被驅動程序丟棄的數據報的數目;
u_int ps_ifdrop;
被網卡丟棄的數據報的數目;
struct pcap_sf { //pacap的savefile結構 定義
FILE *rfile; //該指針指向savefile文件
int swapped; //?
int hdrsize; //頭大小嗎?
int version_major;//主版本號
int version_minor;//從版本號
u_char *base;//?
};
struct pcap_md { //?
struct pcap_stat stat;
/*XXX*/
int use_bpf; /* using kernel filter */
u_long TotPkts; /* can't oflow for 79 hrs on ether */
u_long TotAccepted; /* count accepted by filter */
u_long TotDrops; /* count of dropped packets */
long TotMissed; /* missed by i/f during this run */
long OrigMissed; /* missed by i/f before this run */
#ifdef linux
int sock_packet; /* using Linux 2.0 compatible interface */
int timeout; /* timeout specified to pcap_open_live */
int clear_promisc; /* must clear promiscuous mode when we close */
int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */
int lo_ifindex; /* interface index of the loopback device */
char *device; /* device name */
struct pcap *next; /* list of open promiscuous sock_packet pcaps */
#endif
};
struct pcap { //這個結構很重要
int fd;
int snapshot;
int linktype;
int tzoff; /* timezone offset */
int offset; /* offset for proper alignment */
struct pcap_sf sf;
struct pcap_md md;
/*
* Read buffer.
*/
int bufsize;
u_char *buffer;
u_char *bp;
int cc;
/*
* Place holder for pcap_next().
*/
u_char *pkt;
/*
* Placeholder for filter code if bpf not in kernel.
*/
struct bpf_program fcode;
char errbuf[PCAP_ERRBUF_SIZE];
};
lipcap的聲明:
#define PCAP_VERSION_MAJOR 2
libpcap dump文件的主版本號;
#define PCAP_VERSION_MINOR 4
libpcap dump文件的從版本號;
#define PCAP_ERRBUF_SIZE 256
用來存放libpcap出錯信息的緩沖區的大??;
#define PCAP_IF_LOOPBACK 0x00000001
網卡是回環網卡;
#define MODE_CAPT 0
抓報模式,在調用pcap_setmode()時使用;
#define MODE_STAT 1
靜態模式,在調用pcap_setmode()時使用;
libpcap的類型定義:
typedef int bpf_int32
32bit 的整形;
typedef u_int bpf_u_int32
32bit 的無類型整形;
typedef pcap pcap_t
Descriptor of an open capture instance(一個打開的捕獲實例的描述符?)這個結構對用戶是不透明的。
typedef pcap_dumper pcap_dumper_t
libpcap保存文件的描述符。
typedef pcap_if pcap_if_t
網卡鏈表的一個元素;
typedef pcap_addr pcap_addr_t
網卡地址的表示;
libpcap函數描述:
char *pcap_lookupdev(char * errbuf);
描述: 這個函數用于獲取一個合適的網卡描述,以供pcap_open_liver函數和pcap_lookupnet函數使用。如果找不到網卡或者所有網卡為off,則返回null。如果一個系統中有多個網卡,那么該函數返回找到的第一個on的網卡。最后才是回環接口?;丨h網卡一直被忽略;
參數:
char * errbuf 存放pcap_lookupdev函數的出錯信息,只有在pcap_lookup失敗是才有值。
返回值: 如果函數執行成功,則返回一個用于描述系統上的一個網卡的描述符的指針。如果失敗,返回null,errbuf中存放出錯信息。
int pcap_lookupnet(char * device, bpf_u_int32 * netp, bpf_u_int32 * maskp,char * errbuf);
描述:該函數用于監測網卡所在網絡的網絡地址和子網掩碼。
參數:
char *devic:網卡的描述符指針,由pcap_looupdev函數獲??;
bpf_u_int32 *netp:存放網絡地址;
bpf_u_int32 *maskp:存放子網掩碼;
char * errbuf: 存放出錯信息;
返回值:如果函數執行成功,則返回值為0,否則返回值為-1,并在errbuf中存放出錯信息。
pcap_t *pcap_open_live(char * device, int snaplen,int promisc, int to_ms, char * ebuf);
描述:該函數用于打開網卡用于捕獲數據報。單詞live的意思就是表示一個運行的網卡(相對于offline而言)被打開了,如同一個保存有被抓數據報的文件被打開一樣。在捕獲數據報之前這個函數必須被執行。所有的其他的用于處理數據報捕獲的函數用到的捕獲數據報的描述符由該函數產生。查看pcap_open_offlin()函數的定義,了解如何打開一個預先保存的包含數據報的文件的細節。
參數:
char *device:網卡的描述符指針,由pcap_looupdev函數獲??;
int snaplen:規定捕獲的每個數據報的最大字節數;
int promisc:1為混雜模式;0為非混雜模式;
int to_ms:規定讀超時的微秒(milliseconds)數;
char *ebuf:存放錯誤信息,只有在pcap_open_live失敗時才被設置;
返回值:如果函數成功執行,則返回一個指向數據報捕獲的指針;如果錯誤,返回null,ebuf存放出錯信息;
int pcap_compile(pcap_t * p, struct bpf_ program *fp, char * str,int optimize, bpf_u_int32 netmask);
描述:該函數用于將str指定的規則整合到fp過濾程序中去,并生成過濾程序入口地址,用于過濾選擇期望的數據報;
參數:
pcap_t *p:pcap_open_live返回的數據報捕獲的指針;
struct bpf_program *fp:指向一個子函數用于過濾,在pcap_compile()函數中被賦值;
char *str:該字符串規定過濾規則;
int optimize:規定了在結果代碼上的選擇是否被執行;
bpf_u_int32 netmask:該網卡的子網掩碼,可以通過pcap_lookupnet()獲??;
返回值:
如果成功執行,返回0,否則返回-1;
int pcap_loop(pcap_t * p, int cnt, pcap_handler callback,u_char * user);
描述:
該函數用于讀取和處理數據報。既可以用來處理事先捕獲的保存在文件中的數據報,也可以用來處理實時捕獲的數據報;
這個函數類似于pcap_dispatch函數,除了它繼續讀取數據報直至完成cnt個報的處理,或者文件處理完(在offline情況下),或者有錯誤發生為止。它不會在實時讀超時時返回(而如果為pcap_open_live()函數指定了一個非零值的超時設置,然后調用
pcap_dispatch()函數,則當超時發生時pcap_dispatch()函數會返回。)
注意第三個參數,callback是pcap_handler類型的變量。這是一個用戶提供的有著三個參數的子函數。定義為:
void user_routine(u_char *user, struct pcap_pkthdr *phrd, u_char *pdata)
這三個參數中,user,是傳遞給pcap_dispatch()的那個參數;phdr,是個pcap_pkthdr類型的指針,是savefile中的數據報的頭指針,pdata,指向數據報數據;這個函數允許用戶定義子集的數據報過濾程序;
參數:
pcap_t * p:pcap_open_live返回的數據報捕獲的指針;
int cnt:規定了函數返回前應處理的數據報數目;
pcap_handler callback:指向一個用戶自定義的函數,在處理每個報后自動調用該函數進行再處理;
u_char *user:該指針用于傳遞給callback.(不知道有什么用?)
返回值:
如果函數成功執行(包括讀文件時讀到EOF),則返回0.否則返回-1,那么錯誤信息將由函數pcap_geterr或pcap_perror給出;
補充:callback函數:
The concept behind a callback function is fairly simple. Suppose I have a program that is waiting for an event of some sort. For the purpose of this example, lets pretend that my program wants a user to press a key on the keyboard. Every time they press a key, I want to call a function which then will determine that to do. The function I am utilizing is a callback function.
pcap_open_dead()
is used for creating a pcap_t structure to use when calling the other functions in libpcap. It is typically used when just using libpcap for compiling BPF code.
pcap_dump_open()
is called to open a ``savefile'' for writing. The name "-" in a synonym for stdout. NULL is returned on failure. p is a pcap struct as returned by pcap_open_offline() or pcap_open_live(). fname specifies the name of the file to open. If NULL is returned, pcap_geterr() can be used to get the error text.
pcap_setnonblock()
puts a capture descriptor, opened with pcap_open_live(), into ``non-blocking'' mode, or takes it out of ``non-blocking'' mode, depending on whether the nonblock argument is non-zero or zero. It has no effect on ``savefiles''. If there is an error, -1 is returned and errbuf is filled in with an appropriate error message; otherwise, 0 is returned. In ``non-blocking'' mode, an attempt to read from the capture descriptor with pcap_dispatch() will, if no packets are currently available to be read, return 0 immediately rather than blocking waiting for packets to arrive. pcap_loop() and pcap_next() will not work in ``non-blocking'' mode.
libpcap文件選讀:
ethernet.c:定義了三個內聯函數:
static inline int xdtoi(int):該函數將十六進值數轉化為整數;
static inline int skip_space(FILE *):該函數定義了在一個文件中含有空格時,返回第一個不是'\n'的字符。
static inline int skip_line(FILE *):
struct pcap_etherent {
u_char addr[6];
char name[122];
};
ethertype.h定義了各個協議的值。如#define ETHERTYPE_IP 0x0800 /* IP protocol */