1. 程式人生 > >libpcap使用簡解

libpcap使用簡解

一,libpcap簡介
libpcap是unix/linux平臺下的網路資料包捕獲函式包,大多數網路監控軟體都以它為基礎。Libpcap可以在絕大多數類unix平臺下工作,本文分析了libpcap在linux 下的原始碼實現,其中重點是linux的底層包捕獲機制和過濾器設定方式,同時也簡要的討論了 libpcap使用的包過濾機制 BPF。其官方網站是http://winpcap.polito.it/
二,工作原理
Libpcap 主要由兩部份組成:網路分接頭(Network Tap)和資料過濾器(Packet Filter)。網路分接頭從網路裝置驅動程式中收集資料拷貝,過濾器決定是否接收該資料包。Libpcap 利用 BSD Packet Filter(BPF)演算法對網絡卡接收到的鏈路層資料包進行過濾。BPF 演算法的基本思想是在有 BPF 監聽的網路中,網絡卡驅動將接收到的資料包複製一份交給 BPF 過濾器,過濾器根據使用者定義的規則決定是否接收此資料包以及需要拷貝該資料包的那些內容,然後將過濾後的資料給與過濾器相關聯的上層應用程式。BPF 的架構如圖所示:這裡寫圖片描述


libpcap的包捕獲機制就是在資料鏈路層加一個旁路處理。當一個數據包到達網路介面時,libpcap首先利用已經建立的Socket從鏈路層驅動程式中獲得該資料包的拷貝,再通過Tap函式將資料包發給BPF過濾器。BPF過濾器根據使用者已經定義好的過濾規則對資料包進行逐一匹配,匹配成功則放入核心緩衝區,並傳遞給使用者緩衝區,匹配失敗則直接丟棄。如果沒有設定過濾規則,所有資料包都將放入核心緩衝區,並傳遞給使用者層緩衝區。捕捉步驟
這裡寫圖片描述
三,libpcap的抓包框架(很簡單的一個執行步驟)
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()函式用於關閉網路裝置,釋放資源。
其實pcap的應用程式格式很簡單,總的來說可以可以分為以下5部分
1.我們從決定用哪一個介面進行嗅探開始。在Linux中,這可能是eth0,而在BSD系統中則可能是xl1等等。我們自己也可以自行定義,或者採用pcap提供的介面名來工作(pcap_lookupdev())。
2.初始化pcap。在這裡我們要告訴pcap對什麼裝置進行嗅探。假如願意的話,我們還可以嗅探多個裝置。怎樣區分它們呢?使用 檔案控制代碼。就像開啟一個檔案進行讀寫一樣,必須命名我們的嗅探“會話”,以此使它們各自區別開來(pcap_open_live(),pcap_lookupnet())。
3.假如我們只想嗅探特定的傳輸(如TCP/IP包,發往埠23的包等等),我們必須建立一個規則集合,編譯並且使用它。這個過程分為三個相互緊密關聯的階段。規則集合被置於一個字串內,並且被轉換成能被pcap讀的格式(因此編譯它)。編譯實際上就是在我們的程式裡呼叫一個不被外部程式使用的函式。接下來我們要告訴 pcap使用它來過濾出我們想要的那一個會話(pcap_compile()和pcap_setfilter())。
4.最後,我們告訴pcap進入它的主體執行迴圈。在這個階段內pcap一直工作到它接收了所有我們想要的包為止。每當它收到一個包就呼叫另一個已經定義好的函式,這個函式可以做我們想要的任何工作,它可以剖析所部獲的包並給使用者打印出結果,它可以將結果儲存為一個檔案,或者什麼也不作(pcap_loop()或pcap_dispatch())。
5.在嗅探到所需的資料後,我們要關閉會話並結束(pcap_close())。
四,部分函式解析以及例項
1,獲取網路介面
函式原型char * pcap_lookupdev(char * errbuf)
上面這個函式返回第一個合適的網路介面的字串指標,如果出錯,則errBuf存放出錯資訊字串,errbBuf至少應該是PCAP_ERRBUF_SIZE個位元組長度的。注意,很多libpcap函式都有這個引數。
pcap_lookupdev()一般可以在跨平臺的,且各個平臺上的網路介面名稱都不相同的情況下使用。
如果我們手動指定要監聽的網路介面,則這一步跳過,我們在第二步中將要監聽的網路介面字串硬編碼在pcap_open_live裡。PCAP_ERRBUF_SIZE是在標頭檔案中已有定義
案例

#include<stdio.h>
#include<pcap.h>
//#define PACP_ERRBUF_SIZE 256
int main(void)
{
    char *device;//用來儲存開啟的裝置
    char errBuf[PCAP_ERRBUF_SIZE];//儲存錯誤資訊
    device = pcap_lookupdev(errBuf);
    if(device)
        {
        printf("lookup is ok %s\n",device);
        }
    else
        {
            printf
("lookup is error\n"); } return 0; }

結果如圖
這裡寫圖片描述
如上面所說,在linux中一般是eth0

2,開啟網路介面
函式原型pcap_t * pcap_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf)
第一個引數是第一步獲取的網路介面字串,可以直接使用硬編碼。
第二個引數是對於每個資料包,從開頭要抓多少個位元組,我們可以設定這個值來只抓每個資料包的頭部,而不關心具體的內容。典型的乙太網幀長度是1518位元組,但其他的某些協議的資料包會更長一點,但任何一個協議的一個數據包長度都必然小於65535個位元組。
第三個引數指定是否開啟混雜模式(Promiscuous Mode),0表示非混雜模式,任何其他值表示混合模式。如果要開啟混雜模式,那麼網絡卡必須也要開啟混雜模式,可以使用如下的命令開啟eth0混雜模式:
ifconfig eth0 promisc
第四個引數指定需要等待的毫秒數,超過這個數值後,第3步獲取資料包的這幾個函式就會立即返回。0表示一直等待直到有資料包到來。
第五個引數是存放出錯資訊的陣列

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

案例

#include<stdio.h>
#include<pcap.h>
//pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
int main(void)
{
    char *device;
    char errBuf[PCAP_ERRBUF_SIZE];
    pcap_t *head;
    device = pcap_lookupdev(errBuf);
    if(device)
        {
        printf("lookup is ok %s\n",device);
        }
        else
        {
       printf("lookup is error %s\n",errBuf);
            return 0;
        }
        head = pcap_open_live(device,65535,0,0,errBuf);
        if(head)
         {
            printf("open is ok\n");
         }
        else
        {
            printf("open is error %s\n",errBuf);
            return 0;
        }
        //void pcap_close(pcap_t * p)
        pcap_close(head);
        return 0;
}

結果如圖
這裡寫圖片描述
注意如果是開啟eth0 必須以root許可權進行執行
3,獲得指定網路裝置的網路號和掩碼
函式原型int pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, char *errbuf);
第一個引數是指定的裝置
第二個引數和第三個引數分別是儲存裝置的ip和掩碼
第四個引數是儲存錯誤資訊
returns 0 on success and -1 on failure
案例

int main(void)
{
    char *device=NULL;
    char *errBuf[PCAP_ERRBUF_SIZE]={0};
    pcap_t *head;
    bpf_u_int32 netp;     
    bpf_u_int32 maskp;    
   int ret;  
    char * net;     
   char * mask;    
   struct in_addr addr;

    device = pcap_lookupdev(errBuf);
    if(device)
    {
        printf("lookup is ok %s\n",device);
    }
    else
    {
        printf("lookup is error %s\n",errBuf);
        return 0;
    }
    head = pcap_open_live(device,65535,1,0,errBuf);
    if(head)
    {
        printf("open is ok\n");
    }
    else
    {
        printf("open is error %s\n",errBuf);
        return 0;
    }

  ret = pcap_lookupnet(device, &netp, &maskp, errBuf);  
  if(ret == -1)  
  {  
    printf("pcap_lookupnet() error: %s\n", errBuf);  
    exit(1);  
  }  
  addr.s_addr = netp;  
  net = inet_ntoa(addr);  
  if(!net)  
  {  
    perror("inet_ntoa() ip error: ");  
    exit(1);  
  }  
  printf("ip: %s\n", net);  
  addr.s_addr = maskp;  
  mask = inet_ntoa(addr);   
  if(!mask)  
  {  
    perror("inet_ntoa() sub mask error: ");  
    exit(1);  
  }    
  printf("sub mask: %s\n", mask);  
 pcap_close(head);
 return 0;      
}

結果如圖
這裡寫圖片描述
4,獲取資料包
開啟網路介面後就已經開始監聽了,那如何知道收到了資料包呢?有下面3種方法:
4.1
u_char * pcap_next(pcap_t * p, struct pcap_pkthdr * h)
如果返回值為NULL,表示沒有抓到包
第一個引數是第2步返回的pcap_t型別的指標
第二個引數是儲存收到的第一個資料包的pcap_pkthdr型別的指標
pcap_pkthdr型別的定義如下:
[cpp] view plaincopy
struct pcap_pkthdr
{
struct timeval ts;
bpf_u_int32 caplen;
bpf_u_int32 len;
};
注意這個函式只要收到一個數據包後就會立即返回
案例:

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

int main(void)
{
    char *device;
    char errBuf[PCAP_ERRBUF_SIZE];
    pcap_t * head;
    device = pcap_lookupdev(errBuf);
    if(device)
    {
        printf("lookup is ok %s\n",device);
    }
    else
    {
        printf("lookup is error %s\n",errBuf);
        return 0;
    }

    head = pcap_open_live(device,65535,1,0,errBuf);
    if(head)
    {
        printf("open is ok\n");
    }
    else
    {
        printf("open is error %s\n",errBuf);
        return 0;
    }

//u_char * pcap_next(pcap_t * p, struct pcap_pkthdr * h)
    /*  struct pcap_pkthdr  
        {  
          struct timeval ts;      
          bpf_u_int32 caplen;     
          bpf_u_int32 len;        
        };*/  
    struct pcap_pkthdr pdata;//儲存資料的結構體

    const u_char * pktStr = pcap_next(head,&pdata);
    //一旦抓到資料就會立刻返回
    if(pktStr)
        {
        printf(" Packet length: %d\n", pdata.len);  
        printf("Number of bytes: %d\n", pdata.caplen);  
        printf("Recived time: %s\n", ctime((const time_t *)&pdata.ts.tv_sec));   
      }
  else
     {
            printf("is NULL\n");
            return 0;
    }
    pcap_close(head);
    return 0;
}

結果如圖
這裡寫圖片描述
4.2
int pcap_loop(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
第一個引數是第2步返回的pcap_t型別的指標
第二個引數是需要抓的資料包的個數,一旦抓到了cnt個數據包,pcap_loop立即返回。負數的cnt表示pcap_loop永遠迴圈抓包,直到出現錯誤。
第三個引數是一個回撥函式指標,它必須是如下的形式:
void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
第一個引數是pcap_loop的最後一個引數,當收到足夠數量的包後pcap_loop會呼叫callback回撥函式,同時將pcap_loop()的user引數傳遞給它
第二個引數是收到的資料包的pcap_pkthdr型別的指標
第三個引數是收到的資料包資料
案例

#include<stdio.h>
#include<pcap.h>
#include<time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
//int pcap_loop(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
//void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
void callback(u_char *userarg,const struct pcap_pkthdr * pkthdr, const u_char * packet)
{
     int * id = (int *)userarg;  

     printf("id: %d\n", ++(*id));  
     printf("length: %d\n", pkthdr->len);  
     printf("Number of bytes: %d\n", pkthdr->caplen);  
     printf("time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));   

    int i;  
    for(i=0; i<pkthdr->len; ++i)  
        {  
            printf(" %0x", packet[i]);  
            if( (i + 1) % 16 == 0 )  
            {  
                    printf("\n");  
            }  
                    //sleep(1);
        }  

        printf("\n\n");  
}
int main(void)
{
    char *device=NULL;
    char *errBuf[PCAP_ERRBUF_SIZE]={0};
    pcap_t *head;

    device = pcap_lookupdev(errBuf);
    if(device)
        {
            printf("lookup is ok %s\n",device);
        }
        else
        {
            printf("lookup is error %s\n",errBuf);
            return 0;
        }
        head = pcap_open_live(device,65535,1,0,errBuf);
        if(head)
        {
            printf("open is ok\n");
        }
        else
        {
            printf("open is error %s\n",errBuf);
            return 0;
        }

    int id = 0;
    pcap_loop(head, -1,  callback, (u_char *)&id);
    pcap_close(head);
        return 0;       
}

結果如圖
這裡寫圖片描述

4.3
int pcap_dispatch(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
這個函式和pcap_loop()非常類似,只是在超過to_ms毫秒後就會返回(to_ms是pcap_open_live()的第4個引數)

5,過濾資料
我們抓到的資料包往往很多,如何過濾掉我們不感興趣的資料包呢?
幾乎所有的作業系統(BSD, AIX, Mac OS, Linux等)都會在核心中提供過濾資料包的方法,主要都是基於BSD Packet Filter(BPF)結構的。libpcap利用BPF來過濾資料包。
過濾資料包三步驟
1, 構造一個過濾表示式
2, 編譯這個表示式
3, 應用這個過濾器

1
BPF使用一種類似於組合語言的語法書寫過濾表示式,不過libpcap和tcpdump都把它封裝成更高階且更容易的語法了,具體可以man tcpdump,以下是一些例子:
src host 192.168.1.177
只接收源ip地址是192.168.1.177的資料包
dst port 80
只接收tcp/udp的目的埠是80的資料包

not tcp
只接收不使用tcp協議的資料包

tcp[13] == 0x02 and (dst port 22 or dst port 23)
只接收SYN標誌位置位且目標埠是22或23的資料包(tcp首部開始的第13個位元組)

icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo
只接收icmp的ping請求和ping響應的資料包

ehter dst 00:e0:09:c1:0e:82
只接收乙太網mac地址是00:e0:09:c1:0e:82的資料包

ip[8] == 5
只接收ip的ttl=5的資料包(ip首部開始的第8個位元組)

2
構造完過濾表示式後,我們需要編譯它,使用如下函式:
int pcap_compile(pcap_t * p, struct bpf_program * fp, char * str, int optimize, bpf_u_int32 netmask)
fp:這是一個傳出引數,存放編譯後的bpf
str:過濾表示式
optimize:是否需要優化過濾表示式
metmask:簡單設定為0即可

3
最後我們需要應用這個過濾表示式:
int pcap_setfilter(pcap_t * p, struct bpf_program * fp)
第二個引數fp就是前一步pcap_compile()的第二個引數

應用完過濾表示式之後我們便可以使用pcap_loop()或pcap_next()等抓包函式來抓包了。
案例

#include<pcap.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <sys/types.h>

int main(void)
{
        char *device;
        pcap_t *handle;
        char errBuf[PCAP_ERRBUF_SIZE];
        struct bpf_program filter; /*已經編譯好的過濾表示式*/
       char filter_app[] = "port 8000";/* 過濾表示式*/
        bpf_u_int32 net;/* 執行嗅探的裝置的IP地址 */
        bpf_u_int32 mask;/* 執行嗅探的裝置的網路掩碼 */

      struct pcap_pkthdr header; /* 由pcap.h定義 用於儲存獲取到的包*/
      const u_char *packet; /* 實際的包 */
        device = pcap_lookupdev(errBuf);
        if(device)
        {
            printf("lookup is ok %s\n",device);
        }
        else
        {
            printf("lookup is error %s\n",errBuf);
            return 0;
        }
         /* 探查裝置屬性 */
            pcap_lookupnet(device,&net,&mask,errBuf);
     /* 以混雜模式開啟會話 */
     handle = pcap_open_live(device, BUFSIZ, 1, 0, errBuf);
        /* 編譯並應用過濾器 */
     pcap_compile(handle, &filter, filter_app, 0, net);
     pcap_setfilter(handle, &filter);
             /* 截獲一個包 */
        packet = pcap_next(handle,&header);
      /*列印長度*/
        printf("packet length is %d\n",header.len);
        /*關閉*/
    pcap_close(handle);
return 0;
}

6,資料解析
部分資料包的格式
   /* 乙太網幀頭部 */
   struct sniff_ethernet {
   u_char ether_dhost[ETHER_ADDR_LEN]; /* 目的主機的地址 */
   u_char ether_shost[ETHER_ADDR_LEN]; /* 源主機的地址 */
   u_short ether_type; /* IP? ARP? RARP? etc */
   };
   /* IP資料包的頭部 */
   struct sniff_ip {
   #if BYTE_ORDER == LITTLE_ENDIAN
   u_int ip_hl:4, /* 頭部長度 */
   ip_v:4; /* 版本號 */
   #if BYTE_ORDER == BIG_ENDIAN
   u_int ip_v:4, /* 版本號 */
   ip_hl:4; /* 頭部長度 */
   #endif
   #endif /* not _IP_VHL */
   u_char ip_tos; /* 服務的型別 */
   u_short ip_len; /* 總長度 */
   u_short ip_id; /包標誌號 /
   u_short ip_off; /* 碎片偏移 */
   #define IP_RF 0x8000 /* 保留的碎片標誌 */
   #define IP_DF 0x4000 /* dont fragment flag */
   #define IP_MF 0x2000 /* 多碎片標誌*/
   #define IP_OFFMASK 0x1fff /分段位 /
   u_char ip_ttl; /* 資料包的生存時間 */
   u_char ip_p; /* 所使用的協議 */
   u_short ip_sum; /* 校驗和 */
   struct in_addr ip_src,ip_dst; /* 源地址、目的地址*/
   };
   /* TCP 資料包的頭部 */
   struct sniff_tcp {
   u_short th_sport; /* 源埠 */
   u_short th_dport; /* 目的埠 */
   tcp_seq th_seq; /* 包序號 */
   tcp_seq th_ack; /* 確認序號 */
   #if BYTE_ORDER == LITTLE_ENDIAN
   u_int th_x2:4, /* 還沒有用到 */
   th_off:4; /* 資料偏移 */
   #endif
   #if BYTE_ORDER == BIG_ENDIAN
   u_int th_off:4, /* 資料偏移*/
   th_x2:4; /還沒有用到 /
   #endif
   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_FINTH_SYNTH_RSTTH_ACKTH_URGTH_ECETH_CWR)
   u_short th_win; /* TCP滑動視窗 */
   u_short th_sum; /* 頭部校驗和 */
   u_short th_urp; /* 緊急服務位 */
   };
案例

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

#include<unistd.h>


#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>

 void  callback(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet)
 {

                     int * id = (int *)user;

                    struct in_addr addr;
                struct iphdr *ipptr;
                struct tcphdr *tcpptr;//太次片,,ip,tcp資料結構
                struct ether_header *eptr;//乙太網字頭
                u_char *ptr;
                char *data;
                int i;
              printf("id: %d\n", ++(*id));  
                  printf("Packet length: %d\n", pkthdr->len);  
                  printf("Number of bytes: %d\n", pkthdr->caplen);  
                  printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));   



          eptr = (struct ether_header*)packet;//得到乙太網字頭
                if (ntohs(eptr->ether_type) == ETHERTYPE_IP)
                {
                    printf ("Ethernet type hex:%x dec:%d is an IP packet/n",
                                ntohs(eptr->ether_type), ntohs(eptr->ether_type));
                }
                else 
                {
                    if (ntohs(eptr->ether_type) == ETHERTYPE_ARP)
                    {
                        printf ("Ethernet type hex:%x dec:%d is an ARP packet/n",
                                    ntohs(eptr->ether_type), ntohs(eptr->ether_type));
                    }
                    else
                    {
                        printf ("Ethernet type %x not IP/n", ntohs(eptr->ether_type));
                        exit (1);
                    }
                }

    ptr = eptr->ether_dhost;
    i = ETHER_ADDR_LEN;
    printf ("i=%d/n", i);
    printf ("Destination Address: ");
    do
    {
        printf ("%s%x", (i == ETHER_ADDR_LEN)?"":":", *ptr++);
    }while(--i>0);
    printf ("/n");
    //printf ("%x/n",ptr);

    ptr = eptr->ether_shost;
    i = ETHER_ADDR_LEN;
    printf ("Source Address: ");
    do
    {
        printf ("%s%x", (i == ETHER_ADDR_LEN)?"":":", *ptr++);
    }while(--i>0);
    printf ("/n");
    printf ("Now decoding the IP packet.\n");
    ipptr = (struct iphdr*)(packet+sizeof(struct ether_header));//得到ip包頭

    printf ("the IP packets total_length is :%d\n", ipptr->tot_len);
    printf ("the IP protocol is %d\n", ipptr->protocol);
     printf("\n\n");  
    addr.s_addr = ipptr->daddr;
    printf ("Destination IP: %s\n", inet_ntoa(addr));    
    addr.s_addr = ipptr->saddr;
    printf ("Source IP: %s\n", inet_ntoa(addr));

    printf ("Now decoding the TCP packet.\n");
    tcpptr = (struct iphdr*)(packet+sizeof(struct ether_header)
                                    +sizeof(struct iphdr));//得到tcp包頭
    printf ("Destination port : %d\n", tcpptr->dest);
    printf ("Source port : %d\n", tcpptr->source);
    printf ("the seq of packet is %d\n", tcpptr->seq);
//以上關於ip、tcp的結構資訊請查詢/usr/include/linux/ip.h | tcp.h

    data = (char*)(packet+sizeof(struct ether_header)+sizeof(struct iphdr)
                                    +sizeof(struct tcphdr));//得到資料包裡內容,不過一般為亂碼。
     printf("\n\n");  
    printf ("the content of packets is /n%s/n",data);



 }
int main()
{
    char *device;
    char errBuf[PCAP_ERRBUF_SIZE];
    pcap_t *head;

    device = pcap_lookupdev(errBuf);
    if(device)
        {
            printf("lookup is ok %s\n",device);
        }
        else
        {
            printf("lookup is error %s\n",errBuf);
            return 0;
        }
        head = pcap_open_live(device,65535,1,0,errBuf);
        if(head)
            {
                printf("open is ok\n");
            }
            else
            {
                    printf("open is error %s\n",errBuf);
                    return 0;
            }

            // typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);

      // int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
      int i = 0;
       pcap_dispatch(head, 0,callback, (u_char *)&i);

       pcap_close(head);
       return 0;
}

結果這裡寫圖片描述如圖

7,一些其他的主要介面

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()函式獲取錯誤消
息。

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()函式獲取錯誤訊息。

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。

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引數相應的檔案,並釋放資源。

相關推薦

libpcap使用

一,libpcap簡介 libpcap是unix/linux平臺下的網路資料包捕獲函式包,大多數網路監控軟體都以它為基礎。Libpcap可以在絕大多數類unix平臺下工作,本文分析了libpcap在linux 下的原始碼實現,其中重點是linux的

json處理[JSONObject、JSONArray]

member pan mem art 組裝 spa 位置 key .so json處理目前有已經成熟使用的jar能夠支持相關處理,json-lib 常用方法為put、putAll、addput方法傳參為:key、value/jsonObject 支持json對象賦值和

http keep-alive

結束 編碼 完全 靜態頁面 1.0 是否 客戶端 問題 connect http協議中,客戶端發送請求,服務端再接收到請求後返回所需要的數據後即關閉連接,這樣客戶端讀取數據局時會返回EOF(-1),表明數據已接受完全 備註:EOF end of file 什麽是keep-a

Linux 變量

linux shell 變量 變量 1.自定義變量 ①變量=變量值 x=5 name="jie chao"(雙引號中的符號有含義,單引號中的符號無含義) ②調用 $name ③變量疊加 x=123,x="$x"456 ④刪除變量 unset 變量名(不加$符號) ⑤查看所有變量 set

Linux文本處理命令“sed”

linux sed 文本處理編輯命令sed命令格式: sed [選項] ‘(截取的行)[動作]‘ 文件名 選項:-n:只把經過sed處理的行輸出 -e:允許輸入多條動作 -i:sed修改的結果寫入文件 截取行:(1)直接輸入行號 (2)/正則表達式/ (3)x

Linux文本處理命令“awk”

linux awk awk 格式: awk [option] ‘條件1{動作1}條件2{動作2}...‘ 文件名 條件:正則表達式;邏輯判斷式 動作:格式化輸出;流程控制語句 選項: -F 指定分割符 變量: $1 $2 ... 第某列 NR 行號

InnoDB

des 恢復 check 如果 redo log 使用 編寫 概念 客戶端 熟悉 MySQL 的人,都知道 InnoDB 存儲引擎,如大家所知,Redo Log 是 innodb 的核心事務日誌之一,innodb 寫入 Redo Log

go-time

go語言的time包 組成 time.Duration(時長,耗時) time.Time(時間點) time.C(放時間點的管道)[ Time.C:=make(chan time.Time) ] time包裡有2個東西,一個是時間點,另一個是時長  時間點

KMP演算法:兩張圖徹底看懂

網上有很多關於講解KMP演算法的文章,很多都用了具體的例子,但本文只需要兩張抽象圖,即可快速理解KMP演算法。 在理解了BF演算法之後,我們發現因為模式串指標的每次復位,都可能造成不必要的某段匹配,這就需要某種策略,來使模式串指標跳過這段匹配,KMP演算法應運而生。以下以一

《Linux網路程式設計》: libpcap

1.概述 libpcap (Packet Capture Library)是一個網路資料包捕獲函式庫,是Unix/Linux平臺下的網路資料包捕獲函式庫。它是一個獨立於系統的使用者層包捕獲的API介面,為底層網路監測提供了一個可移植的框架。功能非常強大,Linux 下著名的 tcpd

快速排序---

快速排序是真的塊。 簡單的說一下快排的思想: 第一步,找出一個鍵值,通常取第一個元素,用temp中間變數暫存,left和right為排序範圍的左邊界和右邊界。 第二步、從右邊找出比temp小的放入i下標的位置。i++。 第三步、從i+1的位置往後找到比temp大的值放

關於GUID和UUID

      GUID(Globals Unique Identifiers 全域性統一識別符號)是指在一臺機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的。通常平臺會提供生成GUID的API。生成演算法很有意思,用到了乙太網卡地址、納秒級時間、晶片ID碼和許多可能的

華為RIP

本章簡解華為路由器RIP配置方法 1.基本宣告 2.基於介面調整RIP收發報文版本 3.RIP基於介面認證 4.手動彙總RIP路由條目 拓撲圖如下 宣告介面加入RIP程序: [Huawei]rip [Huawei-rip-1]network 1.0.0.0

Python的函式傳值與傳引用

Python到底值傳值還是傳引用? 先看兩段程式碼 程式碼1: 1 2 3 4 5 6 7 >>> a=3 >>> def f(b): ...     b=1 ...     >>> f

Ubuntu 16.04安裝Oracle 11g

1、環境 系統:Ubuntu 16.04 64位Java 8安裝成功2、 安裝Oracle所需要的依賴包 sudo apt-get install automake sudo apt-get install autotools-dev sudo apt-get insta

排序演算法

目錄 演算法穩定性 堆排序 快速排序 歸併排序 演算法穩定性   排序演算法穩定性的簡單形式化定義為:如果Ai = Aj,排序前Ai在Aj之前,排序後Ai還在Aj之前,則稱這種排序演算法是穩定的。通俗地講就是保證排序前後兩個相等的數的相對順序不變。   對於

【Hadoop】HBase、HDFS和MapReduce架構異同

HBase、HDFS和MapReduce架構異同 .. HBase(公司架構模型) HDFS2.0(公司架構模型) MR2.0(公司架構模型) MR1.0(公司架構模型)

蘋果推送服務端java 程式碼

思路: 從客戶端獲取的deviceToken,定義訊息模式Payload,註冊deviceToken,連線APNS,傳送推送,停止連線APNS,刪除deviceToken; 1,從客戶端獲取的deviceToken,在此為了測試簡單,寫固定的一個測試裝置標識 String

單模匹配之KMP演算法

void BF(char *x, int m, char *y, int n)  { int i, j; for (j = 0; j <= n - m; ++j)  { for (i = 0; i < m && x[i] == y[i +

SqlSessionFactory和SqlSession

【1】SqlSessionFactoryBuilder 這個類可以被初始化、使用和丟棄,如果你已經建立好了一個SqlSessionFactory 後就不用再保留它。 因此,SqlSessionFactoryBuilder 的最好作用域是方法體內 比如說定義一個