c++ winpcap开发(7)
来源:互联网 发布:有约束的最短路径算法 编辑:程序博客网 时间:2024/05/29 03:42
处理离线转储文件
在这个课程中,我们将学习如何处理数据包捕获到一个文件(转储到文件)。WinPcap提供广泛的功能来将文件的网络流量保存到文件并读取转储的内容 - 本课将介绍如何使用所有这些功能。我们还将了解如何使用WinPcap的内核转储功能来获取高性能转储(注意:由于新内核缓冲区存在一些问题,此功能已禁用)。
转储文件的格式是libpcap格式。该格式包含二进制形式的捕获数据包的数据,是许多网络工具(包括WinDump,Ethereal和Snort)使用的标准。
将数据包保存到转储文件
首先,我们来看看如何用libpcap格式写数据包。
以下示例捕获所选接口的数据包,并将其保存在名称由用户提供的文件中。
#include "pcap.h"/* prototype of the packet handler */void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);int main(int argc, char **argv){pcap_if_t *alldevs;pcap_if_t *d;int inum;int i=0;pcap_t *adhandle;char errbuf[PCAP_ERRBUF_SIZE];pcap_dumper_t *dumpfile; /* Check command line */ if(argc != 2) { printf("usage: %s filename", argv[0]); return -1; } /* Retrieve the device list on the local machine */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /* Print the list */ for(d=alldevs; d; d=d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return -1; } printf("Enter the interface number (1-%d):",i); scanf_s("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } /* Jump to the selected adapter */ for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); /* Open the device */ if ( (adhandle= pcap_open(d->name, // name of the device 65536, // portion of the packet to capture // 65536 guarantees that the whole packet will be captured on all the link layers PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 1000, // read timeout NULL, // authentication on the remote machine errbuf // error buffer ) ) == NULL) { fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } /* Open the dump file */ dumpfile = pcap_dump_open(adhandle, argv[1]); if(dumpfile==NULL) { fprintf(stderr,"\nError opening output file\n"); return -1; } printf("\nlistening on %s... Press Ctrl+C to stop...\n", d->description); /* At this point, we no longer need the device list. Free it */ pcap_freealldevs(alldevs); /* start the capture */ pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile); return 0;}/* Callback function invoked by libpcap for every incoming packet */void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data){ /* save the packet on the dump file */ pcap_dump(dumpfile, header, pkt_data);}
正如你所看到的,程序的结构与以前的课程中看到的结构非常相似。差异在于:
- 一旦打开接口,就会发出一个对pcap_dump_open()的调用。此调用打开一个转储文件并将其与该接口相关联。
- 数据包将从packet_handler()回调中使用pcap_dump()写入此文件。的参数pcap_dump()是在1-1对应于参数pcap_handler() 。
从转储文件读取数据包
现在我们有一个转储文件可用,我们可以尝试阅读它的内容。以下代码打开一个WinPcap / libpcap转储文件,并显示文件中包含的每个数据包。该文件使用pcap_open_offline()打开,那么通常使用pcap_loop()来对数据包进行排序。如您所见,从离线捕获读取数据包与从物理接口接收数据包几乎相同。
此示例介绍另一个功能:pcap_createsrcsrc()。创建一个源字符串需要创建一个源字符串,它以一个标记开头,用于告诉WinPcap的源类型,例如“rpcap://”,如果我们要打开一个适配器,或者“file://”,如果我们打开文件。当使用pcap_findalldevs_ex()(返回的值已经包含这些字符串)时,不需要此步骤。但是,在此示例中是必需的,因为从用户输入读取文件的名称。
#include <stdio.h>#include <pcap.h>#define LINE_LEN 16void dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *);int main(int argc, char **argv){pcap_t *fp;char errbuf[PCAP_ERRBUF_SIZE];char source[PCAP_BUF_SIZE]; if(argc != 2){ printf("usage: %s filename", argv[0]); return -1; } /* Create the source string according to the new WinPcap syntax */ if ( pcap_createsrcstr( source, // variable that will keep the source string PCAP_SRC_FILE, // we want to open a file NULL, // remote host NULL, // port on the remote host argv[1], // name of the file we want to open errbuf // error buffer ) != 0) { fprintf(stderr,"\nError creating a source string\n"); return -1; } /* Open the capture file */ if ( (fp= pcap_open(source, // name of the device 65536, // portion of the packet to capture // 65536 guarantees that the whole packet will be captured on all the link layers PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 1000, // read timeout NULL, // authentication on the remote machine errbuf // error buffer ) ) == NULL) { fprintf(stderr,"\nUnable to open the file %s.\n", source); return -1; } // read and dispatch packets until EOF is reached pcap_loop(fp, 0, dispatcher_handler, NULL); return 0;}void dispatcher_handler(u_char *temp1, const struct pcap_pkthdr *header, const u_char *pkt_data){ u_int i=0; /* * Unused variable */ (VOID)temp1; /* print pkt timestamp and pkt len */ printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len); /* Print the packet */ for (i=1; (i < header->caplen + 1 ) ; i++) { printf("%.2x ", pkt_data[i-1]); if ( (i % LINE_LEN) == 0) printf("\n"); } printf("\n\n"); }
#include <stdio.h>#include <pcap.h>#define LINE_LEN 16int main(int argc, char **argv){pcap_t *fp;char errbuf[PCAP_ERRBUF_SIZE];char source[PCAP_BUF_SIZE];struct pcap_pkthdr *header;const u_char *pkt_data;u_int i=0;int res; if(argc != 2) { printf("usage: %s filename", argv[0]); return -1; } /* Create the source string according to the new WinPcap syntax */ if ( pcap_createsrcstr( source, // variable that will keep the source string PCAP_SRC_FILE, // we want to open a file NULL, // remote host NULL, // port on the remote host argv[1], // name of the file we want to open errbuf // error buffer ) != 0) { fprintf(stderr,"\nError creating a source string\n"); return -1; } /* Open the capture file */ if ( (fp= pcap_open(source, // name of the device 65536, // portion of the packet to capture // 65536 guarantees that the whole packet will be captured on all the link layers PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 1000, // read timeout NULL, // authentication on the remote machine errbuf // error buffer ) ) == NULL) { fprintf(stderr,"\nUnable to open the file %s.\n", source); return -1; } /* Retrieve the packets from the file */ while((res = pcap_next_ex( fp, &header, &pkt_data)) >= 0) { /* print pkt timestamp and pkt len */ printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len); /* Print the packet */ for (i=1; (i < header->caplen + 1 ) ; i++) { printf("%.2x ", pkt_data[i-1]); if ( (i % LINE_LEN) == 0) printf("\n"); } printf("\n\n"); } if (res == -1) { printf("Error reading the packets: %s\n", pcap_geterr(fp)); } return 0;}
Writing packets to a dump file with pcap_live_dump
注意:由于新内核缓冲区存在一些问题,此功能已被禁用。
WinPcap的最新版本提供了一种将网络流量节省到pcap_live_dump()函数的另一种方法。pcap_live_dump()具有三个参数:一个文件名,允许该文件达到的最大大小(以字节为单位),以及该文件允许包含的最大数据包数。零表示对这两个值没有限制。请注意,在调用pcap_live_dump()之前,该程序可以设置一个过滤器(使用pcap_setfilter(),请参阅过滤流量),以定义要保存的流量的子集。
pcap_live_dump()是非阻塞的,因此它将启动转储并立即返回:转储进程异步进行,直到达到最大文件大小或最大数据包数。
应用程序可以使用pcap_live_dump_ended()等待或检查转储结束。请注意,如果同步参数非零,如果极限均为0,此功能将永久阻止应用程序。
#include <stdlib.h>#include <stdio.h>#include <pcap.h>#error At the moment the kernel dump feature is not supported in the drivermain(int argc, char **argv) { pcap_if_t *alldevs, *d; pcap_t *fp; u_int inum, i=0; char errbuf[PCAP_ERRBUF_SIZE]; printf("kdump: saves the network traffic to file using WinPcap kernel-level dump faeature.\n"); printf("\t Usage: %s [adapter] | dump_file_name max_size max_packs\n", argv[0]); printf("\t Where: max_size is the maximum size that the dump file will reach (0 means no limit)\n"); printf("\t Where: max_packs is the maximum number of packets that will be saved (0 means no limit)\n\n"); if(argc < 5){ /* The user didn't provide a packet source: Retrieve the device list */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /* Print the list */ for(d=alldevs; d; d=d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return -1; } printf("Enter the interface number (1-%d):",i); scanf("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); /* Free the device list */ return -1; } /* Jump to the selected adapter */ for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); /* Open the device */ if ( (fp = pcap_open_live(d->name, 100, 1, 20, errbuf) ) == NULL) { fprintf(stderr,"\nError opening adapter\n"); return -1; } /* Free the device list */ pcap_freealldevs(alldevs); /* Start the dump */ if(pcap_live_dump(fp, argv[1], atoi(argv[2]), atoi(argv[3]))==-1){ printf("Unable to start the dump, %s\n", pcap_geterr(fp)); return -1; } } else{ /* Open the device */ if ( (fp= pcap_open_live(argv[1], 100, 1, 20, errbuf) ) == NULL) { fprintf(stderr,"\nError opening adapter\n"); return -1; } /* Start the dump */ if(pcap_live_dump(fp, argv[0], atoi(argv[1]), atoi(argv[2]))==-1){ printf("Unable to start the dump, %s\n", pcap_geterr(fp)); return -1; } } /* Wait until the dump finishes, i.e. when max_size or max_packs is reached*/ pcap_live_dump_ended(fp, TRUE); /* Close the adapter, so that the file is correctly flushed */ pcap_close(fp); return 0;}
除了设置限制的可能性之外,pcap_live_dump()和pcap_dump()之间的区别是性能。pcap_live_dump()利用了WinPcap NPF驱动程序的功能(参见NPF驱动程序内部手册)从内核级写入转储,最小化上下文切换和内存副本的数量。
显然,由于此功能目前在其他操作系统上不可用,因此pcap_live_dump()是WinPcap特有的,仅在Win32下存在。
- c++ winpcap开发(7)
- Winpcap网络开发库入门,分类: C/C++/VC++
- winpcap 编程C|C++
- winpcap 应用于C++builder
- winpcap一些开发实践
- WinPcap开发心得
- 搭建WinPcap开发环境
- c++ winpcap开发(1)
- c++ winpcap开发(2)
- c++ winpcap开发(3)
- c++ winpcap开发(4)
- c++ winpcap开发(5)
- c++ winpcap开发(6)
- c++ winpcap开发(8)
- c++ winpcap开发(9)
- c++ winpcap开发(10)
- Winpcap 开发教程
- Winpcap网络开发库入门
- go语言1小时——从不会到入门
- js,根据包名,在指定空间中创建对象
- 面试提问垃圾回收机制
- 找合法帧 QAQ
- epoll_server实现web服务器
- c++ winpcap开发(7)
- OGNL—Action类与JSP页面之间的数据传递
- 算法_插入排序
- java对象构造过程
- linux下vim的管理输入输出
- js,dom节点查找
- windows64 装PIL时遇到的问题以及解决办法
- 安装 CICS TXS
- Nginx系列—虚拟主机配置的三种方式(一)