Libpcap學習筆記

參考

[1]http://www.tcpdump.org/pcap.html

[2]http://blog.csdn.net/lsg_down/article/details/78486614

[3]http://e-ghost.deusto.es/docs/2005/conferencias/pcap.pdf

[4]wiki

[5]API

簡單介紹

libpcap(Packet Capture Library),即數據包捕獲函數庫,是Unix/Linux平臺下的網絡數據包捕獲函數庫。它是一個獨立於系統的用戶層包捕獲的API接口,爲底層網絡監測提供了一個可移植的框架。

libpcap工作原理

​ libpcap主要由兩部份組成:網絡分接頭(Network Tap)和數據過濾器(Packet Filter)。網絡分接頭從網絡設備驅動程序中收集數據拷貝,過濾器決定是否接收該數據包。Libpcap利用BSD Packet Filter(BPF)算法對網卡接收到的鏈路層數據包進行過濾。BPF算法的基本思想是在有BPF監聽的網絡中,網卡驅動將接收到的數據包複製一份交給BPF過濾器,過濾器根據用戶定義的規則決定是否接收此數據包以及需要拷貝該數據包的那些內容,然後將過濾後的數據給與過濾器相關聯的上層應用程序。

​ libpcap的包捕獲機制就是在數據鏈路層加一個旁路處理。當一個數據包到達網絡接口時,libpcap首先利用已經創建的Socket從鏈路層驅動程序中獲得該數據包的拷貝,再通過Tap函數將數據包發給BPF過濾器。BPF過濾器根據用戶已經定義好的過濾規則對數據包進行逐一匹配,匹配成功則放入內核緩衝區,並傳遞給用戶緩衝區,匹配失敗則直接丟棄。如果沒有設置過濾規則,所有數據包都將放入內核緩衝區,並傳遞給用戶層緩衝區。

常用函數

  • pcap_lookupdev()

    函數用於查找網絡設備,返回可被pcap_open_live()函數調用的網絡設備名指針。

  • pcap_open_live()

    函數用於打開網絡設備,並且返回用於捕獲網絡數據包的數據包捕獲描述字。對於此網絡設備的操作都要基於此網絡設備描述字。

  • pcap_lookupnet()

    函數獲得指定網絡設備的網絡號和掩碼。

  • pcap_compile()

    函數用於將用戶制定的過濾策略編譯到過濾程序中。

  • pcap_setfilter()

    函數用於設置過濾器。

  • pcap_loop()

    函數pcap_dispatch()函數用於捕獲數據包,捕獲後還可以進行處理,此外pcap_next()和pcap_next_ex()兩個函數也可以用來捕獲數據包。

  • pcap_close()

    函數用於關閉網絡設備,釋放資源。

抓包步驟

  1. 設置設備。In Linux this may be something like eth0, in BSD it may be xl1, etc. We can either define this device in a string, or we can ask pcap to provide us with the name of an interface that will do the job.
  2. 初始化pcap。正式決定在那個設備上用於抓包,通過handles區別不同的設備。
  3. 編譯過濾器
  4. 進入執行循環隊列。
  5. 關閉會話。

1. 設置設備

  1. 參數輸入
#include <stdio.h>
#include <pcap.h>

int main(int argc, char *argv[])
{
  char *dev = argv[1];

  printf("Device: %s\n", dev);
  return(0);
}
  1. 使用pcap_lookupdev查找

    注:pcap_lookupdev只返回第一個可用於嗅探的接口

#include <stdio.h>
#include <pcap.h>

int main(int argc, char *argv[])
{
  char *dev, errbuf[PCAP_ERRBUF_SIZE];

  dev = pcap_lookupdev(errbuf);
  if (dev == NULL) {
    fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
    return(2);
  }
  printf("Device: %s\n", dev);
  return(0);
}

2. 打開設備用於嗅探

使用pcap_open_live打開一個設備

pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms,
        char *ebuf)

​ 其第一個參數是我們在上一節中指定的設備,snaplen是整形的,它定義了將被pcap捕捉的最大字節數。當promisc設爲true時將置指定接口爲混雜模式(然而,當它置爲false時接口仍處於混雜模式的非凡情況也是有可能的)。to_ms是讀取時的超時值,單位是毫秒(假如爲0則一直嗅探直到錯誤發生,爲-1則不確定)。最後,ebuf是一個我們可以存入任何錯誤信息的字符串(就像上面的errbuf)。此函數返回其會話句柄。

​ 混雜模式與非混雜模式的區別:這兩種方式區別很大。一般來說,非混雜模式的嗅探器中,主機僅嗅探那些跟它直接有關的通信,如發向它的,從它發出的,或經它路由的等都會被嗅探器捕捉。而在混雜模式中則嗅探傳輸線路上的所有通信。在非交換式網絡中,這將是整個網絡的通信。這樣做最明顯的優點就是使更多的包被嗅探到,它們因你嗅探網絡的原因或者對你有幫助,或者沒有。但是,混雜模式是可被探測到的。一個主機可以通過高強度的測試判定另一臺主機是否正在進行混雜模式的嗅探。其次,它僅在非交換式的網絡環境中有效工作(如集線器,或者交換中的ARP層面)。再次,在高負荷的網絡中,主機的系統資源將消耗的非常嚴重。

示例程序:

 #include <pcap.h>
//...
 pcap_t *handle;
/*This code fragment opens the device stored in the strong "dev", tells it to read however many bytes are specified in BUFSIZ (which is defined in pcap.h). We are telling it to put the device into promiscuous mode, to sniff until an error occurs, and if there is an error, store it in the string errbuf; it uses that string to print an error message.*/
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
  fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
  return(2);
}

不是所有包的鏈路層頭都一樣。

# If your program doesn't support the link-layer header type provided by the device, it has to give up; this would be done with code such as

if (pcap_datalink(handle) != DLT_EN10MB) {
  fprintf(stderr, "Device %s doesn't provide Ethernet headers - not supported\n", dev);
  return(2);
}

常用的鏈路層類別有,具體區別見【http://www.tcpdump.org/linktypes.html】:

DLT_NULL:BSD loopback encapsulation
DLT_EN10MB:Ethernet (10Mb, 100Mb, 1000Mb, and up)
DLT_IEEE802:IEEE 802.5 Token Ring
DLT_ARCNET:ARCNET
DLT_SLIP:SLIP
DLT_PPP:PPP
DLT_FDDI:FDDI
DLT_ATM_RFC1483:RFC 1483 LLCSNAP-encapsulated ATM
DLT_RAW:raw IP, el paquete comienza con una cabecera IP
DLT_PPP_SERIAL:PPP en modo HDLC-like framing (RFC 1662)
DLT_PPP_ETHER:PPPoE
DLT_C_HDLC:Cisco PPP con HDLC framing, definido en 4.3.1 RFC 1547
DLT_IEEE802_11:IEEE 802.11 wireless LAN
DLT_LOOP:OpenBSD loopback encapsulation
DLT_LINUX_SLL:Linux cooked capture encapsulation
LT_LTALK:Apple LocalTal

3. 過濾通信

3.1. 編譯過濾器

int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize, 
        bpf_u_int32 netmask)

​ 第一個參數是會話句柄。接下來的是我們存儲被編譯的過濾器版本的地址的引用。再接下來的則是表達式本身,存儲在規定的字符串格式裏。再下邊是一個定義表達式是否被優化的整形量(0爲false,1爲true,標準規定)。最後,我們必須指定應用此過濾器的網絡掩碼。函數返回-1爲失敗,其他的任何值都表明是成功的。

3.2. 設置過濾器

​ 表達式被編譯之後就可以使用了。現在進入pcap_setfilter()。

int pcap_setfilter(pcap_t *p, struct bpf_program *fp)

​ 這非常直觀,第一個參數是會話句柄,第二個參數是被編譯表達式版本的引用(可推測出它與pcap_compile()的第二個參數相同)。

3.3. 示例代碼

#include <pcap.h>
...
  pcap_t *handle;       /* Session handle */
char dev[] = "rl0";     /* Device to sniff on */
char errbuf[PCAP_ERRBUF_SIZE];  /* Error string */
struct bpf_program fp;      /* The compiled filter expression */
char filter_exp[] = "port 23";  /* The filter expression */
bpf_u_int32 mask;       /* The netmask of our sniffing device */
bpf_u_int32 net;        /* The IP of our sniffing device */

if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
  fprintf(stderr, "Can't get netmask for device %s\n", dev);
  net = 0;
  mask = 0;
}
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
  fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
  return(2);
}
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
  fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
  return(2);
}
if (pcap_setfilter(handle, &fp) == -1) {
  fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
  return(2);
}

這個程序使嗅探器嗅探經由端口23的所有通信,使用混雜模式,設備是rl0.

# 官網註釋:不起作用?
You may notice that the previous example contains a function that we have not yet discussed. pcap_lookupnet() is a function that, given the name of a device, returns one of its IPv4 network numbers and corresponding network mask (the network number is the IPv4 address ANDed with the network mask, so it contains only the network part of the address). This was essential because we needed to know the network mask in order to apply the filter. This function is described in the Miscellaneous section at the end of the document.

It has been my experience that this filter does not work across all operating systems. In my test environment, I found that OpenBSD 2.9 with a default kernel does support this type of filter, but FreeBSD 4.3 with a default kernel does not. Your mileage may vary.

4. 真實的嗅探

​ 有兩種手段捕捉包。我們可以一次只捕捉一個包,也可以進入一個循環,等捕捉到多個包再進行處理。我們將先看看怎樣去捕捉單個包,然後再看看使用循環的方法。爲此,我們使用函數pcap_next()。

u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

​ 第一個參數是會話句柄,第二個參數是指向一個包括了當前數據包總體信息(被捕捉時的時間,包的長度,其被指定的部分長度)的結構體的指針(在這裏只有一個片斷,只作爲一個示例)。pcap_next()返回一個u_char指針給被這個結構體描述的包。我們將稍後討論這種實際讀取包本身的手段。

   這裏有一個演示怎樣使用pcap_next()來嗅探一個包的例子:

#include <pcap.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
  pcap_t *handle;           /* Session handle */
  char *dev;            /* The device to sniff on */
  char errbuf[PCAP_ERRBUF_SIZE];    /* Error string */
  struct bpf_program fp;        /* The compiled filter */
  char filter_exp[] = "port 23";    /* The filter expression */
  bpf_u_int32 mask;     /* Our netmask */
  bpf_u_int32 net;      /* Our IP */
  struct pcap_pkthdr header;    /* The header that pcap gives us */
  const u_char *packet;     /* The actual packet */

  /* Define the device */
  dev = pcap_lookupdev(errbuf);
  if (dev == NULL) {
    fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
    return(2);
  }
  /* Find the properties for the device */
  if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
    fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
    net = 0;
    mask = 0;
  }
  /* Open the session in promiscuous mode */
  handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
  if (handle == NULL) {
    fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
    return(2);
  }
  /* Compile and apply the filter */
  if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
    fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
    return(2);
  }
  if (pcap_setfilter(handle, &fp) == -1) {
    fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
    return(2);
  }
  /* Grab a packet */
  packet = pcap_next(handle, &header);
  /* Print its length */
  printf("Jacked a packet with length of [%d]\n", header.len);
  /* And close the session */
  pcap_close(handle);
  return(0);
}

這個程序嗅探被pcap_lookupdev()返回的設備並將它置爲混雜模式。它發現第一個包經過端口23(telnet)並且告訴用戶此包的大小(以字 節爲單位)。這個程序又包含了一個新的調用pcap_close(),我們將在後面討論(儘管它的名字就足夠證實它自己的作用)。

實際上很少有嗅探程序會真正的使用pcap_next()。通常,它們使用pcap_loop()或者 pcap_dispatch()(它就是用了pcap_loop())。

pcap_loop()的原型如下:

int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)

​ 第一個參數是會話句柄,接下來是一個整型,它告訴pcap_loop()在返回前應捕捉多少個數據包(若爲負值則表示應該一直工作直至錯誤發生)。第三個參數是回調函數的名稱(正像其標識符所指,無括號)。最後一個參數在有些應用裏有用,但更多時候則置爲NULL。假設我們有我們自己的想送往回調函數的參數,另外還有pcap_loop()發送的參數,這就需要用到它。很明顯,必須是一個u_char類型的指針以確保結果正確;正像我們稍後見到的,pcap使用了很有意思的方法以u_char指針的形勢傳遞信息。pcap_dispatch()的用法幾乎相同。唯一不同的是它們如何處理超時(還記得在調用pcap_open_live()時怎樣設置超時嗎?這就是它起作用的地方)。Pcap_loop()忽略超時而pcap_dispatch()則不。關於它們之間區別的更深入的討論請參見pcap的手冊頁。

callback的原型如下:

void got_packet(u_char *args, const struct pcap_pkthdr *header,
        const u_char *packet);

​ 讓我們更細緻的考察它。首先,你會注重到該函數返回void類型,這是符合邏輯的,因爲pcap_loop()不知道如何去處理一個回調返回值。第一個參數相應於pcap_loop()的最後一個參數。每當回調函數被老婆 調用時,無論最後一個參數傳給pcap_loop()什麼值,這個值都會傳給我們回調函數的第一個參數。第二個參數是pcap頭文件定義的,它包括數據包被嗅探的時間、大小等信息。

​ 結構體pcap_pkhdr在pcap.h中定義如下:

struct pcap_pkthdr {
        struct timeval ts; /* time stamp */
        bpf_u_int32 caplen; /* length of portion present */
        bpf_u_int32 len; /* length this packet (off wire) */
    };

​ 最後一個參數在它們中是最有意思的,也最讓pcap程序新手感到迷惑。這又是一個u_char指針,它包含了被pcap_loop()嗅探到的所有包。

​ 但是你怎樣使用這個我們在原型裏稱爲packet的變量呢?一個數據包包含許多屬性,因此你可以想象它不只是一個字符串,而實質上是一個結構體的集合(比如,一個TCP/IP包會有一個以太網的頭部,一個IP頭部,一個TCP頭部,還有此包的有效載荷)。這個u_char就是這些結構體的串聯版本。爲了使用它,我們必須作一些有趣的匹配工作。

​ 下面這些是一些數據包的結構體(libpcap中已經包含有一些預定好的eternet頭,ip header,tcp header,分別在net/ethernet.h、netinet/ip.h,netinet/tcp.h

/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN  6

    /* Ethernet header */
    struct sniff_ethernet {
        u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
        u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
        u_short ether_type; /* IP? ARP? RARP? etc */
    };

    /* IP header */
    struct sniff_ip {
        u_char ip_vhl;      /* version << 4 | header length >> 2 */
        u_char ip_tos;      /* type of service */
        u_short ip_len;     /* total length */
        u_short ip_id;      /* identification */
        u_short ip_off;     /* fragment offset field */
    #define IP_RF 0x8000        /* reserved fragment flag */
    #define IP_DF 0x4000        /* dont fragment flag */
    #define IP_MF 0x2000        /* more fragments flag */
    #define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */
        u_char ip_ttl;      /* time to live */
        u_char ip_p;        /* protocol */
        u_short ip_sum;     /* checksum */
        struct in_addr ip_src,ip_dst; /* source and dest address */
    };
    #define IP_HL(ip)       (((ip)->ip_vhl) & 0x0f)
    #define IP_V(ip)        (((ip)->ip_vhl) >> 4)

    /* TCP header */
    typedef u_int tcp_seq;

    struct sniff_tcp {
        u_short th_sport;   /* source port */
        u_short th_dport;   /* destination port */
        tcp_seq th_seq;     /* sequence number */
        tcp_seq th_ack;     /* acknowledgement number */
        u_char th_offx2;    /* data offset, rsvd */
    #define TH_OFF(th)  (((th)->th_offx2 & 0xf0) >> 4)
        u_char th_flags;
    #define TH_FIN 0x01
    #define TH_SYN 0x02
    #define TH_RST 0x04
    #define TH_PUSH 0x08
    #define TH_ACK 0x10
    #define TH_URG 0x20
    #define TH_ECE 0x40
    #define TH_CWR 0x80
    #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
        u_short th_win;     /* window */
        u_short th_sum;     /* checksum */
        u_short th_urp;     /* urgent pointer */
};

​ pcap嗅探數據包時正是使用的這些結構。接下來,它簡單的創建一個u_char字符串並且將這些結構體填入。那麼我們怎樣才能區分它們呢?預備好見證指針最實用的好處之一吧。

​ 我們再一次假定要對以太網上的TCP/IP包進行處理。同樣的手段可以應用於任何數據包,唯一的區別是你實際所使用的結構體的類型。讓我們從聲明分解u_char包的變量開始:

#define SIZE_ETHERNET 14

const struct sniff_ethernet *ethernet; /* The ethernet header */
const struct sniff_ip *ip; /* The IP header */
const struct sniff_tcp *tcp; /* The TCP header */
const char *payload; /* Packet payload */

u_int size_ip;
u_int size_tcp;

開始賦值

ethernet = (struct sniff_ethernet*)(packet);
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip)*4;
if (size_ip < 20) {
  printf("   * Invalid IP header length: %u bytes\n", size_ip);
  return;
}
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
if (size_tcp < 20) {
  printf("   * Invalid TCP header length: %u bytes\n", size_tcp);
  return;
}
payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);

​ 此處如何工作?考慮u_char在內存中的層次。基本的,當pcap將這些結構體填入u_char的時候是將這些數據存入一個字符串中,那個字符串將被送入我們的回調函數中。反向轉換是這樣的,不考慮這些結構體制中的值,它們的大小將是一致的。例如在我的平臺上,一個sniff_ethernet結構體的大小是14字節。一個sniff_ip結構體是20字節,一個sniff_tcp結構體也是20字節。 u_char指針正是包含了內存地址的一個變量,這也是指針的實質,它指向內存的一個區域。簡單而言,我們說指針指向的地址爲x,假如三個結構體恰好線性排列,第一個(sniff_ethernet)被裝載到內存地址的x處則我們很輕易的發現其他結構體的地址,讓我們以表格顯示之:

Variable Location (in bytes)
sniff_ethernet X
sniff_ip X + SIZE_ETHERNET
sniff_tcp X + SIZE_ETHERNET + {IP header length}
payload X + SIZE_ETHERNET + {IP header length} + {TCP header length}

​ 結構體sniff_ethernet正好在x處,緊接着它的sniff_ip則位於x加上它本身佔用的空間(此例爲14字節),依此類推可得全部地址。

完整的示例程序【http://www.tcpdump.org/sniffex.c

主要的函數接口

  • pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)

    獲得用於捕獲網絡數據包的數據包捕獲描述字。device參數爲指定打開的網絡設備名。snaplen參數定義捕獲數據的最大字節數。promisc指定是否將網絡接口置於混雜模式。to_ms參數指定超時時間(毫秒)。ebuf參數則僅在pcap_open_live()函數出錯返回NULL時用於傳遞錯誤消息。

  • pcap_t *pcap_open_offline(char *fname, char *ebuf)

    打開以前保存捕獲數據包的文件,用於讀取。fname參數指定打開的文件名。該文件中的數據格式與tcpdump和tcpslice兼容。”-“爲標準輸入。ebuf參數則僅在pcap_open_offline()函數出錯返回NULL時用於傳遞錯誤消息。

  • pcap_dumper_t *pcap_dump_open(pcap_t *p, char *fname)

    打開用於保存捕獲數據包的文件,用於寫入。fname參數爲”-“時表示標準輸出。出錯時返回NULL。p參數爲調用pcap_open_offline()或pcap_open_live()函數後返回的pcap結構指針。fname參數指定打開的文件名。如果返回NULL,則可調用pcap_geterr()函數獲取錯誤消息。

  • char *pcap_lookupdev(char *errbuf)

    用於返回可被pcap_open_live()或pcap_lookupnet()函數調用的網絡設備名指針。如果函數出錯,則返回NULL,同時errbuf中存放相關的錯誤消息。

  • int pcap_lookupnet(char *device, bpf_u_int32 *netp,bpf_u_int32 *maskp, char *errbuf)

    獲得指定網絡設備的網絡號和掩碼。netp參數和maskp參數都是bpf_u_int32指針。如果函數出錯,則返回-1,同時errbuf中存放相關的錯誤消息。

  • int pcap_dispatch(pcap_t *p, int cnt,pcap_handler callback, u_char *user)

    捕獲並處理數據包。cnt參數指定函數返回前所處理數據包的最大值。cnt=-1表示在一個緩衝區中處理所有的數據包。cnt=0表示處理所有數據包,直到產生以下錯誤之一:讀取到EOF;超時讀取。callback參數指定一個帶有三個參數的回調函數,這三個參數爲:一個從pcap_dispatch()函數傳遞過來的u_char指針,一個pcap_pkthdr結構的指針,和一個數據包大小的u_char指針。如果成功則返回讀取到的字節數。讀取到EOF時則返回零值。出錯時則返回-1,此時可調用pcap_perror()或pcap_geterr()函數獲取錯誤消息。

  • int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user)

    功能基本與pcap_dispatch()函數相同,只不過此函數在cnt個數據包被處理或出現錯誤時才返回,但讀取超時不會返回。而如果爲pcap_open_live()函數指定了一個非零值的超時設置,然後調用pcap_dispatch()函數,則當超時發生時pcap_dispatch()函數會返回。cnt參數爲負值時pcap_loop()函數將始終循環運行,除非出現錯誤。

  • void pcap_dump(u_char *user, struct pcap_pkthdr *h,u_char *sp)

    向調用pcap_dump_open()函數打開的文件輸出一個數據包。該函數可作爲pcap_dispatch()函數的回調函數。

  • int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask)

    將str參數指定的字符串編譯到過濾程序中。fp是一個bpf_program結構的指針,在pcap_compile()函數中被賦值。optimize參數控制結果代碼的優化。netmask參數指定本地網絡的網絡掩碼。

  • int pcap_setfilter(pcap_t *p, struct bpf_program *fp)

    指定一個過濾程序。fp參數是bpf_program結構指針,通常取自pcap_compile()函數調用。出錯時返回-1;成功時返回0。

  • u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

    返回指向下一個數據包的u_char指針。

  • int pcap_datalink(pcap_t *p)

    返回數據鏈路層類型,例如DLT_EN10MB。

  • int pcap_snapshot(pcap_t *p)

    返回pcap_open_live被調用後的snapshot參數值。

  • int pcap_is_swapped(pcap_t *p)

    返回當前系統主機字節與被打開文件的字節順序是否不同。

  • int pcap_major_version(pcap_t *p)

    返回寫入被打開文件所使用的pcap函數的主版本號。

  • int pcap_minor_version(pcap_t *p)

    返回寫入被打開文件所使用的pcap函數的輔版本號。

  • int pcap_stats(pcap_t *p, struct pcap_stat *ps)

    向pcap_stat結構賦值。成功時返回0。這些數值包括了從開始捕獲數據以來至今共捕獲到的數據包統計。如果出錯或不支持數據包統計,則返回-1,且可調用pcap_perror()或pcap_geterr()函數來獲取錯誤消息。

  • FILE *pcap_file(pcap_t *p)

    返回被打開文件的文件名。

  • int pcap_fileno(pcap_t *p)

    返回被打開文件的文件描述字號碼。

  • void pcap_perror(pcap_t *p, char *prefix)

    在標準輸出設備上顯示最後一個pcap庫錯誤消息。以prefix參數指定的字符串爲消息頭。

  • char *pcap_geterr(pcap_t *p)

    返回最後一個pcap庫錯誤消息。

  • char *pcap_strerror(int error)

    如果strerror()函數不可用,則可調用pcap_strerror函數替代。

  • void pcap_close(pcap_t *p)

    關閉p參數相應的文件,並釋放資源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章