Winpcap笔记4之不用回调函数捕获数据包
函数1:
pcap_next_ex(pcap_t* p,
struct pcap_pkthdr** pkt_header,
const u_char* pkt_data
)
从一个网络接口或离线捕获方式(例如读文件)读取一个数据包。该函数被用来重新获得下一个可用的数据包,没有使用libpcap提供的传统的回调方法。pcap_next_ex用指向头和下一个被捕获的数据包的指针为pkt_header和pkt_data参数赋值。
返回值有下列几种情况:
1,数据包被正确读取
0,pcap_open_live()设置的超时时间到。在这种情况下pkt_header和pkt_data不指向有效数据包
-1,发生错误
-2,离线捕获的时候读取到EOF
我们通常使用pcap_next_ex()而不是pcap_next(),因为pcap_next()有些缺点。首先,pcap_next()效率低,因为它隐藏了回调方法但是还是依赖于pcap_dispatch;第二,它不能检测EOF,所以当从一个文件获取数据包时它不是很有用。
函数2:
u_char* pcap_next(pcap_t* p,
struct pcap_pkthdr* h
)
返回下一个可用的数据包并且返回一个u_char指向该数据包数据部分的指针。如果发生错误或者活动的抓包没有读取到数据包(例如:数据包不能通过包过滤器而被丢弃,或者在支持读超时(read timeout)的平台上在任何数据包到来之前就超时终止,又或者是抓包设备的文件描述符在非阻塞(non-blocking)模式下并且没有数据包可以被读取),或者文件已被读完时返回NULL。不幸的是,没有办法检测是否发生错误。
Winpcap提供(libpcap也提供)的一个强大特性是过滤引擎(filtering engine)。它提供了一个非常有效的接收网络流量的方法,并且它通常与Winpcap提供的抓包机制集成在一起。用于过滤数据包的函数是pcap_complie()和pcap_setfilter()。
pcap_complie()使用一个包含高级布尔表达式的字符串并且产生一个能被过滤引擎集成到数据包驱动中的低级字节码。
pcap_setfilter()把一个过滤器与核心驱动抓包会话关联起来。一旦pcap_setfilter()被调用,相关的过滤器将被应用到所有的来自网络的数据包上,并且所有的一致的数据包将被复制给应用程序。
1 //不用回掉函数捕获数据包 2 #include "pcap.h" 3 4 5 int main() 6 { 7 pcap_if_t *alldevs; 8 pcap_if_t *d; 9 int inum; 10 int i = 0; 11 pcap_t *adhandle; 12 int res; 13 char errbuf[PCAP_ERRBUF_SIZE]; 14 struct tm *ltime; 15 char timestr[16]; 16 struct pcap_pkthdr *header; 17 const u_char *pkt_data; 18 time_t local_tv_sec; 19 20 21 /* 获取本机设备列表 */ 22 if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) 23 { 24 fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf); 25 exit(1); 26 } 27 28 /* 打印列表 */ 29 for (d = alldevs; d; d = d->next) 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 } 37 38 if (i == 0) 39 { 40 printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 41 return -1; 42 } 43 44 printf("Enter the interface number (1-%d):", i); 45 scanf("%d", &inum); 46 47 if (inum < 1 || inum > i) 48 { 49 printf("\nInterface number out of range.\n"); 50 /* 释放设备列表 */ 51 pcap_freealldevs(alldevs); 52 return -1; 53 } 54 55 /* 跳转到已选中的适配器 */ 56 for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++); 57 58 /* 打开设备 */ 59 if ((adhandle = pcap_open(d->name, // 设备名 60 65536, // 要捕捉的数据包的部分 61 // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容 62 PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式 63 1000, // 读取超时时间 64 NULL, // 远程机器验证 65 errbuf // 错误缓冲池 66 )) == NULL) 67 { 68 fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); 69 /* 释放设列表 */ 70 pcap_freealldevs(alldevs); 71 return -1; 72 } 73 74 printf("\nlistening on %s...\n", d->description); 75 76 /* 释放设备列表 */ 77 pcap_freealldevs(alldevs); 78 79 /* 获取数据包 */ 80 while ((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0){ 81 82 if (res == 0) 83 /* 超时时间到 */ 84 continue; 85 86 /* 将时间戳转换成可识别的格式 */ 87 local_tv_sec = header->ts.tv_sec; 88 ltime = localtime(&local_tv_sec); 89 strftime(timestr, sizeof timestr, "%H:%M:%S", ltime); 90 91 printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len); 92 } 93 94 if (res == -1){ 95 printf("Error reading the packets: %s\n", pcap_geterr(adhandle)); 96 return -1; 97 } 98 99 return 0; 100 }