程式扎記: [C 範例代碼] libpcap : 捕捉我的第一個封包

標籤

2011年9月8日 星期四

[C 範例代碼] libpcap : 捕捉我的第一個封包

轉載自 這裡
前言 :
我們知道每台電腦都會有所謂的 network interface, 而封包的交換便是透過那些 network interface. 底下將介紹如何使用 libpcap 來捕捉 network interface 上面的封包並將之投映於螢幕上, 在開始編碼前請先到以下位置下載 pcap 的 library : 

* Download libpcap source from www.tcpdump.org here
* Download libpcap for win32 from www.winpcap.org
* Check out a better pcap tutorial here

捕捉我的第一個封包 :
接著請參考下面代碼 :
- pcap_example02.c : Simple single packet capture program
  1. #include   
  2. #include   
  3. #include  /* if this gives you an error try pcap/pcap.h */  
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include  /* includes net/ethernet.h */  
  9.   
  10. int main(int argc, char **argv)  
  11. {  
  12.     int i;  
  13.     char *dev;   
  14.     char errbuf[PCAP_ERRBUF_SIZE];  
  15.     pcap_t* descr;  
  16.     const u_char *packet;  
  17.     struct pcap_pkthdr hdr;     /* pcap.h */  
  18.     struct ether_header *eptr;  /* net/ethernet.h */  
  19.   
  20.     u_char *ptr; /* printing out hardware header info */  
  21.   
  22.     /* grab a device to peak into... */  
  23.     dev = pcap_lookupdev(errbuf);  
  24.   
  25.     if(dev == NULL)  
  26.     {  
  27.         printf("%s\n",errbuf);  
  28.         exit(1);  
  29.     }  
  30.   
  31.     printf("DEV: %s\n",dev);  
  32.   
  33.     /* open the device for sniffing. 
  34.  
  35.        pcap_t *pcap_open_live(char *device,int snaplen, int prmisc,int to_ms, 
  36.        char *ebuf) 
  37.  
  38.        snaplen - maximum size of packets to capture in bytes 
  39.        promisc - set card in promiscuous mode? 
  40.        to_ms   - time to wait for packets in miliseconds before read 
  41.        times out 
  42.        errbuf  - if something happens, place error string here 
  43.  
  44.        Note if you change "prmisc" param to anything other than zero, you will 
  45.        get all packets your device sees, whether they are intendeed for you or 
  46.        not!! Be sure you know the rules of the network you are running on 
  47.        before you set your card in promiscuous mode!!     */  
  48.   
  49.     descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf);  
  50.   
  51.     if(descr == NULL)  
  52.     {  
  53.         printf("pcap_open_live(): %s\n",errbuf);  
  54.         exit(1);  
  55.     }  
  56.   
  57.   
  58.     /* 
  59.        grab a packet from descr (yay!)                     
  60.        u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h)  
  61.        so just pass in the descriptor we got from          
  62.        our call to pcap_open_live and an allocated         
  63.        struct pcap_pkthdr                                 */  
  64.   
  65.     packet = pcap_next(descr,&hdr);  
  66.   
  67.     if(packet == NULL)  
  68.     {/* dinna work *sob* */  
  69.         printf("Didn't grab packet\n");  
  70.         exit(1);  
  71.     }  
  72.   
  73.     /*  struct pcap_pkthdr { 
  74.         struct timeval ts;   time stamp  
  75.         bpf_u_int32 caplen;  length of portion present  
  76.         bpf_u_int32;         lebgth this packet (off wire)  
  77.         } 
  78.      */  
  79.   
  80.     printf("Grabbed packet of length %d\n",hdr.len);  
  81.     printf("Recieved at ..... %s\n",ctime((const time_t*)&hdr.ts.tv_sec));   
  82.     printf("Ethernet address length is %d\n",ETHER_HDR_LEN);  
  83.   
  84.     /* lets start with the ether header... */  
  85.     eptr = (struct ether_header *) packet;  
  86.   
  87.     /* Do a couple of checks to see what packet type we have..*/  
  88.     if (ntohs (eptr->ether_type) == ETHERTYPE_IP)  
  89.     {  
  90.         printf("Ethernet type hex:%x dec:%d is an IP packet\n",  
  91.                 ntohs(eptr->ether_type),  
  92.                 ntohs(eptr->ether_type));  
  93.     }else  if (ntohs (eptr->ether_type) == ETHERTYPE_ARP)  
  94.     {  
  95.         printf("Ethernet type hex:%x dec:%d is an ARP packet\n",  
  96.                 ntohs(eptr->ether_type),  
  97.                 ntohs(eptr->ether_type));  
  98.     }else {  
  99.         printf("Ethernet type %x not IP", ntohs(eptr->ether_type));  
  100.         exit(1);  
  101.     }  
  102.   
  103.     /* copied from Steven's UNP */  
  104.     ptr = eptr->ether_dhost;  
  105.     i = ETHER_ADDR_LEN;  
  106.     printf(" Destination Address:  ");  
  107.     do{  
  108.         printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);  
  109.     }while(--i>0);  
  110.     printf("\n");  
  111.   
  112.     ptr = eptr->ether_shost;  
  113.     i = ETHER_ADDR_LEN;  
  114.     printf(" Source Address:  ");  
  115.     do{  
  116.         printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);  
  117.     }while(--i>0);  
  118.     printf("\n");  
  119.   
  120.     return 0;  
  121. }  

接著請編譯該代碼並執行 :
$ cc -g -Wall -c pcap_example02.c
pcap_example02.c: In function ‘main’:
pcap_example02.c:89:5: warning: implicit declaration of function ‘ctime’
pcap_example02.c:89:5: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
$ cc pcap_example02.o -lpcap -o test
$ sudo ./test
DEV: eth0
Grabbed packet of length 106
Recieved at ..... Fri Sep 9 09:43:36 2011

Ethernet address length is 14
Ethernet type hex:800 dec:2048 is an IP packet
Destination Address: 0:50:56:c0:0:8
Source Address: 0:c:29:e1:b3:32

這邊可以發現列印出來的 Address 並不是我們熟悉的 IP 格式而是所謂的 Hardware address (Mac address). 而在網路通訊協定中是透過 ARP 協定 將 IP 與 實體位置做 Mapping. 而你可以透過命令 arp -n 來檢視這個 Mapping table :


在這個代碼裡, 我們將捕捉到的 packet 轉成 struct ether_header *. 而該結構定義在 net/ethernet.h :
  1. /* 10Mb/s ethernet header */  
  2. struct ether_header  
  3. {  
  4.   u_int8_t  ether_dhost[ETH_ALEN];  /* destination eth addr */  
  5.   u_int8_t  ether_shost[ETH_ALEN];  /* source ether addr    */  
  6.   u_int16_t ether_type;             /* packet type ID field */  
  7. } __attribute__ ((__packed__));  
而在該結構的 ether_type 也可以在 net/ethernet.h 找到 :
  1. /* Ethernet protocol ID's */  
  2. #define ETHERTYPE_PUP       0x0200      /* Xerox PUP */  
  3. #define ETHERTYPE_IP        0x0800      /* IP */  
  4. #define ETHERTYPE_ARP       0x0806      /* Address resolution */  
  5. #define ETHERTYPE_REVARP    0x8035      /* Reverse ARP */  
事實上我們目前只使用了少部分 libpcap 的 APIs, 在實際應用上我們可能需要 filter 掉沒有興趣的 packet 與捕抓不只一個的 packet 來進行網路封包的分析與延伸應用. 而這邊所用的每一支 libpcap 的 API, 你都可以使用 man 來檢視該 API 的用法. 更多的範例與使用介紹將在後面陸續進行介紹.

沒有留言:

張貼留言

網誌存檔