天天看點

linux下libpcap抓包分析

一、首先下載下傳libpcap包 http://www.tcpdump.org/#latest-release

  然後安裝,安裝完成後進入安裝根目錄的tests檔案夾,編譯運作findalldevstest.c(編譯時加上-lpcap),檢視是否發現所有網絡裝置。

二、下載下傳wireshark觀察抓包軟體的各種功能

三、熟悉libpcap工作原理:

linux下libpcap抓包分析
四、了解libpcap抓包基本流程:
linux下libpcap抓包分析
五、程式設計實作
linux下libpcap抓包分析

未完待續。。。 

PS:整理了一下libpcap常用的資料類型定義

  • 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(一個打開的捕獲執行個體的描述符?)這個結構對使用者是不透明的。

3)、typedef pcap_dumper pcap_dumper_t

libpcap儲存檔案的描述符。

4)、typedef pcap_if pcap_if_t

網卡連結清單的一個元素;

5)、typedef pcap_addr pcap_addr_t

網卡位址的表示;

6)、typedef void (*pcap_handler)(u_char *args, const struct pcap_pkthdr *header,    const u_char *packet);

    其中agrs是從pcap_dispatch()函數傳遞過來的第四個形參 ,一般我們自己的包捕捉程式不需要提供它,總是為NULL ;header指向

pcap_pkthdr結構,該結構位于真正的實體幀前面,用于消除不同鍊路層支援的差異 ;packet指向所捕獲封包的實體幀。

  • libpcap結構體

Libpcap庫函數所必須的資料結構定義主要包含在pcap.h和pcap-int.h兩個頭檔案中

1)、pcap結構在pcap-int.h頭檔案中被定義:

 程式設計時需要涉及到的成員有:int fd; 打開裝置的描述符;u_char *buffer; 是指向所捕獲到資料的緩沖區指針

struct pcap

{

   int fd; /* 檔案描述字,實際就是 socket */

    int selectable_fd; /* 在 socket 上,可以使用 select() 和 poll() 等 I/O 複用類型函數 */

    int snapshot; /* 使用者期望的捕獲資料包最大長度 */

    int linktype; /* 裝置類型 */

    int tzoff;         /* 時區位置,實際上沒有被使用 */

    int offset;       /* 邊界對齊偏移量 */

    int break_loop; /* 強制從讀資料包循環中跳出的标志 */

    struct pcap_sf sf; /* 資料包儲存到檔案的相關配置資料結構 */

    struct pcap_md md; /* 具體描述如下 */

    int bufsize; /* 讀緩沖區的長度 */

    u_char buffer; /* 讀緩沖區指針 */

    u_char *bp;

    int cc;

    u_char *pkt;

    /* 相關抽象操作的函數指針,最終指向特定作業系統的處理函數 */

    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 過濾代碼不能在核心中執行,則将其儲存并在使用者空間執行 */

    struct bpf_program fcode;

    /* 函數調用出錯資訊緩沖區 */

    char errbuf[PCAP_ERRBUF_SIZE + 1];

    /* 目前裝置支援的、可更改的資料鍊路類型的個數 */

    int dlt_count;

    /* 可更改的資料鍊路類型号連結清單,在 linux 下沒有使用 */

    int *dlt_list;

    /* 資料包自定義頭部,對資料包捕獲時間、捕獲長度、真實長度進行描述 [pcap.h] */

    struct pcap_pkthdr pcap_header;  

};

/* 包含了捕獲句柄的接口、狀态、過濾資訊  [pcap-int.h] */

struct pcap_md {

/* 捕獲狀态結構  [pcap.h] */

struct pcap_stat stat; 

    int use_bpf; /* 如果為1,則代表使用核心過濾*/

    u_long    TotPkts;

    u_long    TotAccepted; /* 被接收資料包數目 */

    u_long    TotDrops;       /* 被丢棄資料包數目 */

    long TotMissed;      /* 在過濾進行時被接口丢棄的資料包數目 */

    long OrigMissed; /*在過濾進行前被接口丢棄的資料包數目*/

#ifdef linux

    int   sock_packet; /* 如果為 1,則代表使用 2.0 核心的 SOCK_PACKET 模式 */

    int   timeout;  /* pcap_open_live() 函數逾時傳回時間*/

    int   clear_promisc; /* 關閉時設定接口為非混雜模式 */

    int   cooked;          /* 使用 SOCK_DGRAM 類型 */

    int   lo_ifindex;      /* 回路裝置索引号 */

    char *device;  /* 接口裝置名稱 */

/* 以混雜模式打開 SOCK_PACKET 類型 socket 的 pcap_t 連結清單*/

struct pcap *next;      

#endif

(2)bpf_program結構

該結構在pcap_compile()函數中被使用,在bpf.h頭檔案中定義。

/* [pcap-bpf.h] */

struct bpf_program {

u_int bf_len; /* BPF 代碼中謂詞判斷指令的數目 */

struct bpf_insn *bf_insns; /* 第一個謂詞判斷指令 */

/* 謂詞判斷指令結構 */

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.

*/

核心過濾器每輸出一個包,将在輸出的資料前加了20位元組的資料,這就是 struct bpf_hdr

struct bpf_hdr

    struct timeval bh_tstamp;   /* time stamp                 */

    bpf_u_int32    bh_caplen;   /* length of captured portion資料長度*/

    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結構

 調用函數 pcap_stats() 可以傳回一個該結構

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:網卡位址描述

pcap_addr *next;如果非空,指向連結清單中一個元素的指針;空表示連結清單中的最後一個元素

sockaddr  *addr;  指向包含一個位址的sockaddr的結構的指針

sockaddr *netmask;如果非空,指向包含相對于addr指向的位址的一個網絡掩碼的結構

sockaddr *broadaddr;如果非空,指向包含相對于addr指向的位址的一個網絡掩碼的結構

sockaddr *dstaddr; 如果非空,指向一個相對于addr指向的源位址的目的位址,如果網絡不支援點對點通訊,則為空

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_*) */

然後是每一個包的標頭和資料

pcap_pkthdr結構

/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.

/* 自定義頭部在把資料包儲存到檔案中也被使用 */

struct pcap_pkthdr

           struct timeval ts; /* 捕獲時間戳 */

           bpf_u_int32 caplen; /* 捕獲到資料包的長度 */

           bpf_u_int32 len; /* 資料包的真正長度 */

}

/* 單個資料包結構,包含資料包元資訊和資料資訊 */

struct singleton [pcap.c]

struct pcap_pkthdr hdr; /* libpcap 自定義資料標頭部 */

const u_char * pkt; /* 指向捕獲到的網絡資料 */

7)、pcap_if (libpcap 自定義的接口資訊連結清單 [pcap.h])

struct pcap_if

struct pcap_if *next;

char *name; /* 接口裝置名 */

char *description; /* 接口描述 */

/*接口的 IP 位址, 位址掩碼, 廣播位址,目的位址 */

struct pcap_addr addresses;

bpf_u_int32 flags;      /* 接口的參數 */

繼續閱讀