首页 > 代码库 > 打开适配器并捕获数据包

打开适配器并捕获数据包

得到适配器的具体信息就可以抓取信息了。

抓取信息之前应该介绍一个核心的函数:pcap_open_live() (在之前的版本用的是pcap_open()这个函数)

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

原文是这样描述的

pcap_t* pcap_open_live(char* device, int snaplen, int promisc, int to_ms, char* ebuf)     Opens a physical interface for live capture.//打开一个物理接口并实时捕获

pcap_open_live() is used to obtain a packet capture descriptor to look at packets on the network.//pcap_open_live() 在网络上捕获数据包并查看1. device is a string that specifies the network device to open; on Linux systems with 2.2 or later kernels, a device argument of "any" or NULL can be used to capture packets from all interfaces. //device是一个打开的网络适配器的字符串,在linux 2.2内核系统或者更高的系统,适配器参数的“任何”或NULL可以应用在所有捕获数据包的接口
//在获取适配器链表后,通过返回pcap_if的name即可知道设备的名称。

2. snaplen specifies the maximum number of bytes to capture. //snaplen指定要捕获的最大字节数。
//在一些操作系统中,驱动可以被配置成只捕获数据包的初始化部分,它的好处就是可以减少应用程序间复制数量的量,从而提高捕获效率。下面将要给出的实例程序中设为65535。我们知道对于使用以太网的局域网来说,最大传输单元为1500字节,那么设为65535则能保证收到完整的数据包。

3. promisc specifies if the interface is to be put into promiscuous mode. (Note that even if this parameter is false, the interface could well be in promiscuous mode for some other reason.)For now, this doesn‘t work on the "any" device; if an argument of "any" or NULL is supplied, the promisc flag is ignored.
//promisc指定如果界面混杂模式。注意,即使这个参数是false,因为其他原因接口也有可能是混则模式。现在,如果适配器没有工作,如果参数是“any”或者NULL,那么promisc这个参数将被忽略
//一般情况下,适配器只接收发给它自己的数据包, 而那些在其他机器之间通讯的数据包,将会被丢弃。 相反,如果适配器是混杂模式,那么不管这个数据包是不是发给我的,我都会去捕获。也就是说,我会去捕获所有的数据包。 这意味着在一个共享媒介(比如总线型以太网),WinPcap能捕获其他主机的所有的数据包。 大多数用于数据捕获的应用程序都会将适配器设置成混杂模式,所以,我们也会在下面的范例中,使用混杂模式。
00178     /* Set promisquous mode */00179     if (promisc) PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS);00180      else PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL);
//说明promisc的值有 整数 或者 0 两个值。

4. to_ms specifies the read timeout in milliseconds. //to_ms指定读取超时,以毫秒为单位。The read timeout is used to arrange that the read not necessarily return immediately when a packet is seen, but that it wait for some amount of time to allow more packets to arrive and to read multiple packets from the OS kernel in one operation. //读超时一般因为排列,读不一定立即看到返回的数据包,而是从操作系统内核。等待一段时间让更多的数据包到达并读取多个数据包
//表示的是读取数据的超时时间,单位是毫秒。意思就是说会在read_timeout时间内对适配器的读取操作进行响应,不管有没有读到数据。这里有两个特殊的值需要说明一下,如果将时间设置为0意味着没有超时,那么如果没有数据到达的话,读操作就永远不会返回;如果设置为-1则恰恰相反,不论有没有读到数据都会立即返回
Not all platforms support a read timeout; on platforms that don‘t, the read timeout is ignored. //不是所有平台都支持读超时;在不支持的平台上,读超时被忽略,5. errbuf is used to return error or warning text.//errbuf用于返回错误或警告文本It will be set to error text when pcap_open_live() fails and returns NULL. //当pcap_open_live()失败,返回NULL,它将被设置为错误文本。errbuf may also be set to warning text when pcap_open_live() succeds; to detect this case the caller should store a zero length string in errbuf before calling pcap_open_live() and display the warning to the user if errbuf is no longer a zero-length string.//errbuf也可能将警告文本当pcap_open_live()函数执行成功;在这种情况下,调用者应该在调用pcap_open_live()之前用一个零长度字符串存储在errbuf中,如果errbuf不再是一个长度为零的字符串,向用户显示警告。

 函数的返回值是一个pcap_t的指针类型,查看声明处我们可以发现pcap_t实际上是pcap结构体,而文档上说明它是一个已打开的捕捉实例的描述符。这个结构体对用户来说是不透明的(我们查看pcap的声明处是找不到的),它通过wpcap.dll提供的函数,维护了它的内容。

  1 #include <stdio.h>  2 #include <stdlib.h>  3 #include <string.h>  4 #include "pcap.h"  5 #include <winsock2.h>  6   7 typedef struct sockaddr_in sockad;  8 /* 数据包处理程序原型 */  9 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); 10  11  12 /* 从tcptraceroute数字IP地址转换为字符串 */ 13 #define IPTOSBUFFERS    12 14 char *iptos(u_long in) 15 { 16     static char output[IPTOSBUFFERS][3*4+3+1]; 17     static short which; 18     u_char *p; 19  20     p = (u_char *)&in; 21     which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); 22     sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); 23     return output[which]; 24 } 25  26  27 void ifprint(pcap_if_t *d,int* i) 28 { 29     pcap_addr_t *a; 30  31     printf("%d. %s", ++(*i), d->name); 32     if (d->description) 33         printf(" (%s)\n", d->description); 34     else 35         printf(" (No description available)\n"); 36     for(a=d->addresses;a;a=a->next) 37     { 38         switch(a->addr->sa_family) 39         { 40         case AF_INET: 41             if(a->addr) 42                 printf("\tIPv4地址:%s\n",iptos(((sockad *)a->addr)->sin_addr.s_addr)); 43             break; 44         } 45     } 46 } 47  48 int main() 49 { 50     pcap_if_t *alldevs; 51     pcap_if_t *d; 52     int inum; 53     int i=0; 54     pcap_t *adhandle; 55     char errbuf[PCAP_ERRBUF_SIZE]; 56  57     /* 获取设备列表 */ 58     if (pcap_findalldevs(&alldevs, errbuf) == -1) 59     { 60         fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); 61         exit(1); 62     } 63  64     /* 打印列表 */ 65     for(d=alldevs; d; d=d->next) 66     { 67         ifprint(d,&i); 68     } 69  70     if(i==0) 71     { 72         printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 73         return -1; 74     } 75  76     printf("Enter the interface number (1-%d):",i); 77     scanf("%d", &inum); 78  79     if(inum < 1 || inum > i) 80     { 81         printf("\nInterface number out of range.\n"); 82         /* Free the device list */ 83         pcap_freealldevs(alldevs); 84         return -1; 85     } 86  87     /* Jump to the selected adapter */ 88     for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); 89  90     /* Open the adapter */ 91     if ( (adhandle= pcap_open_live(d->name, // name of the device 92                              65536,     // portion of the packet to capture. 93                              // 65536 grants that the whole packet will be captured on all the MACs. 94                              1,         // promiscuous mode 95                              1000,      // read timeout 96                              errbuf     // error buffer 97                              ) ) == NULL) 98     { 99         fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");100         /* Free the device list */101         pcap_freealldevs(alldevs);102         return -1;103     }104 105     printf("\nlistening on %s...\n", d->description);106 107     /* At this point, we don‘t need any more the device list. Free it */108     pcap_freealldevs(alldevs);109 110     /* start the capture */111     pcap_loop(adhandle, 0, packet_handler, NULL);112 113     return 0;114 }115 116 117 /* 回调函数调用libpcap为每个传入的数据包 */118 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)119 {120     struct tm *ltime;121     char timestr[16];122 123     /* 时间戳转换为可读的格式*/124     ltime=localtime(&header->ts.tv_sec);125     strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);126 127     printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);128 129 }

 

packet_handler 函数为在监听时对每个数据包的读取函数,本章仅仅展示一下。

技术分享

技术分享

 

打开适配器并捕获数据包