现在已经知道了如何去获得网卡的信息现在就打开网卡并捕获数据流。打开网卡的功能是通过pcap_open_live()来实现的它有三个参数snaplen、promisc、to_ms。
snaplen用于指定所捕获包的特定部分,在一些系统上(象xBSD and Win32等)驱动只给出所捕获数据包的一部分而不是全部,这样就减少了拷贝数据的数量从而提高了包捕获的效率。
promisc指明网卡处于混杂模式,在正常情况下网卡只接受去往它的包而去往其他主机的数据包则被忽略。相反当网卡处于混杂 模式时他将接收所有的流经它的数据包:这就意味着在共享介质的情况下我门可以捕获到其它主机的数据包。大部分的包捕获程序都将混杂模式设为默认,下面的例子里也将网卡设为混杂模式。to_ms 参数指定读数据的超时控制,超时以毫秒计算。当在超时时间内网卡上没有数据到来时对网卡的读操作将返回(如pcap_dispatch() or pcap_next_ex()等函数)。还有,如果网卡处于统计模式下to_ms还定义了统计的时间间隔。如果该参数为0那么意味着没有超时控制,对网卡的读操作在没有数据到来是将永远堵塞。如果为-1那么对网卡的读操作将立即返回不管有没有数据可读。
/************************************************************************ struct pcap_pkthdr { struct timeval ts;// 时间戳 bpf_u_int32 caplen;// 当前部分的长度 bpf_u_int32 len;// 长度 }; }; ************************************************************************/ 程序代码: ///////////////////////////////////////////////////////////////////////////// // Name: PackageCapture.cpp // Purpose: wincap网络数据包的捕获。 // Compiler: VS2005 // Author: 陈相礼 // Modified by: // Created: 09/18/09 // Copyright: // Licence: ///////////////////////////////////////////////////////////////////////////// #include "pcap.h" #pragma comment(lib,"Packet.lib") #pragma comment(lib,"wpcap.lib") /* 包处理器原型 */ void packet_handler( u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); int main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *adhandle; char errbuf[PCAP_ERRBUF_SIZE]; /* 获得网卡的列表 */ if ( pcap_findalldevs( &alldevs, errbuf ) == -1 ) { fprintf_s( stderr, "pcap_findalldevs调用错误: %s/n", errbuf ); exit(1); } /* 打印网卡信息 */ for( d = alldevs; d; d = d->next ) { printf_s( "%d. %s", ++i, d->name ); if ( d->description ) printf_s( " (%s)/n", d->description ); else printf_s( " (无可用描述)/n" ); } if(i==0) { printf_s( "/n没有发现适配器! 确保安装了WinPcap./n" ); return -1; } printf_s( "选择适配器 (1-%d):", i ); scanf_s( "%d", &inum ); // 输入要选择打开的网卡号 if( inum < 1 || inum > i ) // 判断号的合法性 { printf_s( "/n输入有误,没有此网卡./n" ); /* 释放资源 */ pcap_freealldevs( alldevs ); return -1; } /* 找到要选择的网卡结构 */ for( d = alldevs, i = 0; i < inum-1; d = d->next, i++ ); /* 打开选择的网卡 */ if ( (adhandle= pcap_open_live( d->name, // 设备名称 65536, // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容 1, // 混杂模式 1000, // 读超时为1秒 errbuf // 错误缓冲 ) ) == NULL) { fprintf_s( stderr, "/n无法打开适配器. %s 不被WinPcap支持./n", errbuf ); /* 释放资源 */ pcap_freealldevs( alldevs ); return -1; } printf_s( "/n开始监听网卡 %s.../n", d->description ); /* 资源释放 */ pcap_freealldevs( alldevs ); /* 开始捕获包 */ pcap_loop( adhandle, 0, packet_handler, NULL ); return 0; } /* 对每一个到来的数据包调用该函数 */ void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) { struct tm ltime; char timestr[16]; /* 将时间戳转变为易读的标准格式*/ time_t t = (time_t )&header->ts.tv_sec; localtime_s( <ime, &t ); strftime( timestr, sizeof timestr, "%H:%M:%S", <ime); printf_s("%s,/t%.6d毫秒/t长度:%d/n", timestr, header->ts.tv_usec, header->len ); }