libpcap庫函數介紹(附源代碼)

libpcap的英文意思是 Packet Capture library,即數據包捕獲函數庫。該庫提供的C函數接口可用於需要捕獲經過網絡接口(只要經過該接口,目標地址不一定爲本機)數據包的系統開發上。由 Berkeley大學Lawrence Berkeley National Laboratory研究院的Van Jacobson、Craig Leres和Steven McCanne編寫。該函數庫支持Linux、Solaris和*BSD系統平臺。

  主要接口函數說明如 下:

    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參數相應的文件,並釋放資源。

    void pcap_dump_close(pcap_dumper_t *p)

      關閉相應的被打開文件。

ling:
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;    /* accuracy 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_ 網卡的標誌。現在唯一可用的標識是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的網卡。最後纔是迴環接口。迴環網卡一直被忽略;
    參數:
    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 *):該函數定義了在一個文件中含有空格時,返回第一個不是'
'的字符。
    static inline int skip_line(FILE *):
    struct pcap_etherent {
            u_char addr[6];
            char name[122];
        };
    ethertype.h定義了各個協議的值。如#define ETHERTYPE_IP            0x0800  /* IP protocol */

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