pcap簡單使用和簡單解釋


數據類型bpf_u_int32實際上就是u_int的一個別名,還有吧bpf_int32實際上就是int的別名。當然這個int是32位的,如果操作系統對int的定義不是4字節,bpf_int32就對應另外一種類型,總之,bpf_u_int32就是一個32位的無符號整型。

關鍵函數:
int pcap_lookupnet(const char *device, bpf_u_int32 *netp,bpf_u_int32 *maskp, char *errbuf)


用於獲取網卡的網絡號和子網掩碼。其中device參數是網卡名,netp 和maskp表示將要獲得的網絡號和子網掩碼,都是以網絡字節序存放的,比如一個IP為10.108.20.0,那么netp中存放的這個地址就是:1338378。轉換成二進制就是:
00000000 00010100 01101100 00001010
這個數在內存中的存在形式就是:
低地址----------------------------------------》高地址
00001010 01101100 00010100 00000000
對應每個字節的十進制就是:
10 108 20 0
網絡字節序和主機字節序比較容易混亂(大端表示和小端表示)。
網絡字節序采用大端表示,就是數據的高位要存放到低地址。
而大多數主機字節序采用小端表示(也有采用大端表示的主機字節序),就是數據的低位放到低地址。
比如無符號整型1338378,的二進制表示為:
數據的高位----------------------------》數據的低位
00000000 00010100 01101100 00001010
所以采用小端表示的主機字節序時,內存中存放的形式為:
低地址----------------------------------------》高地址
00001010 01101100 00010100 00000000
errbuf存放錯誤信息。失敗返回-1
errbuf的大小可以定義為:PCAP_ERRBUF_SIZE


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

用於打開網絡設備,返回一個pcap_t結構體的指針。
幫助文檔中的說法是:用於獲取一個數據包捕獲的描述符,以便用來查看網絡上的數據包。device是網卡名稱。snaplen表示捕獲的最大字節數,如果這個值小於被捕獲的數據包的大小,則只顯示前snaplen位(實驗表明,后面為全是0),通常來講數據包的大小不會超過65535。promisc表示是否開啟混雜模式。 to_ms 表示讀取的超時時間,毫秒為單位,就是說沒有必要看到一個數據包這個函數就返回,而是設定一個返回時間,這個時間內可能會讀取很多個數據包,然后一起返回。如果這個值為0,這個函數一直等待足夠多的數據包到來。errbuf用於存儲錯誤信息。

int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask)
用於編譯字符串str成為一個過路程序,program參數是一個指向bpf_program結構體的指針,這個參數由函數pcap_compile()填充。optimize參數用於控制是否采用最優化的結果。netmask用於指定IPv4的網絡子網掩碼,這個參數僅僅在檢查過濾程序中的IPv4廣播地址時才會使用。

int pcap_setfilter(pcap_t *p, struct bpf_program *fp)
用於指定一個過濾器程序,fp是一個指向bpf_program結構體的指針,通常是pcap_compile返回的結果。p通常是pcap_open_live()函數返回的結果。

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

這個函數用於收集和加工數據包。cnt指定用於加工的數據包的最大數量,超過了這個數量函數就會返回。當讀取一個實時捕獲的時候,一次僅有一個數據包的緩沖區被讀取,所以處理的數據包的個數有可能少於cnt個。當cnt的值為-1時,會處理到達一個緩沖區的所有數據包,或者(如果不是實時捕獲而是處理一個pcap文件)會處理文件中所有的數據包。 callback指定了一個回調函數。這個回調函數有三個參數:一個u_char類型的指針,這個參數是通過pcap_dispatch()函數傳遞的(應該是提供用戶使用的), 一個指向pcap_pkthdr結構體常量的指針。這個結構體含有三個域,
struct pcap_pkthdr
{
struct timeval ts; ts是一個結構struct timeval,它有兩個部分,第一部分是1900開始以來的秒數,第二部分是當前秒之后的毫秒數。表示數據包捕獲的時間。
bpf_u_int32 caplen; 表示抓到的數據長度
bpf_u_int32 len; 表示數據包的實際長度
}
第二個域是一個u_char常量的指針,指向的一個數據包的前caplen個字節。

成功返回0,失敗返回-1可以用pcap_perror來打印錯誤信息。
注意:當讀取一個實時捕獲時,當讀取超時時pcap_dispatch()函數沒有必要返回。

pcap_loop()函數和pcap_dispatch()用法相似。
int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user)
這個函數當讀取超時時也不會返回。

void pcap_close ( pcap_t * p );
用於關閉pcap_open_live()獲取的包捕捉句柄,釋放相關資源。
一個典型的過程:

#include <stdio.h>  
#include <string.h>
#include <stdlib.h>

#include <pcap.h>  

#include <arpa/inet.h>
#include <unistd.h>//getopt
#include <sys/types.h>//u_char


void get_packet(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet)
{
    //    prase_packet(packet, pkthdr->len);
}


int main(int argc,char* argv[])  
{
    char* device=NULL;
    char ch;
    //getopt()
    //
    if((ch = getopt(argc,argv,"d:"))==-1)
    {
        printf("no options!!!\n");
        exit(1);
    }
    optind=1;
    while ((ch = getopt(argc, argv, "d:")) != -1)
    {
        switch (ch) 
           {    
               case 'd':
            if(optarg!=NULL)
            {
                if(  (  device  =  (char*)malloc(strlen(optarg) ) ) !=NULL)//remeber to free
                {
                    strcpy(device,optarg);
                    //printf("%s\n",device);
                }
                else
                {
                    printf("malloc error\n");
                    exit(1);
                }
                        
            }
            else
            {
                exit(1);
            }
                   
            break;
     
            case '?':
            default:
                printf("Unknown option: %c\n",(char)optopt);
                exit(1);
                    
        }
    }
           
    //capture
    if(!device)
    {
          printf("no device\n");
          exit(1);
    }
            


    char errBuf[PCAP_ERRBUF_SIZE]; //error Buff
  
   // struct pcap_pkthdr packet;  The header that pcap gives us
       pcap_t *phandle; //network interface
       
       bpf_u_int32 netp, maskp; //網絡號和子網掩碼
       char *net, *mask;
       struct bpf_program fcode;
       struct in_addr addr;
    //look up device network addr and mask
    //獲取網絡參數

       if(pcap_lookupnet(device, &netp, &maskp, errBuf)==-1) 
       {
        printf("get net failure\n");
           exit(1);
       }

       addr.s_addr = netp;
    printf("%u\n",netp);
       net = inet_ntoa(addr);
       printf("network: %s\n", net);
    
       addr.s_addr = maskp;
       mask = inet_ntoa(addr);
       printf("mask: %s\n", mask);
    

    //open network device for packet capture
       phandle = pcap_open_live(device, 65535, 1, 500, errBuf);
       if(NULL == phandle) 
       {
           printf("open %s failure\n", device);
           perror(errBuf);
           exit(1);
       }
    char* filterString="ether src D8:5D:4C:36:76:83 or ether dst D8:5D:4C:36:76:83";
    
    if(pcap_compile(phandle,&fcode,filterString,0,maskp)==-1)
    {
           fprintf(stderr,"pcap_compile: %s\n",pcap_geterr(phandle));
           exit(1);
    }

    

     if(pcap_setfilter(phandle,&fcode)==-1)
     {
           fprintf(stderr,"pcap_setfilter: %s\n",pcap_geterr(phandle));
           exit(1);
       }
        
    pcap_loop(phandle, -1, get_packet, NULL);
    
        //close device
    pcap_close(phandle);

       return 0; 
}

如果您覺得對您有幫助,請點贊哦^^。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM