WINPCAP编程环境设置
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
因为项目需要,而且以前从没用过Winpcap,所以不得不从头学起。
以前虽然看过winsocket,但是,Winpcap的第一个程序,我花了很长时间才编译通过。
对于初学者来说,不太好做的可能是编译程序之前应该做什么事。
我就大体说一下我的过程。
首先先大体介绍下Winpcap。
winpcap(windows packet capture)windows平台下一个免费,公共的网络访问系统。
开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。
它提供了以下的各项功能:
1> 捕获原始数据包,包括在共享网络上各主机发送/接收的以及相互之间交换的数据包;
2> 在数据包发往应用程序之前,按照自定义的规则将某些特殊的数据包过滤掉;
3> 在网络上发送原始的数据包;
4> 收集网络通信过程中的统计信息。
具体介绍参见/view/696423.htm这里有Winpcap的详细介绍。
下面说一下你在编译Winpcap之前要做的事情。
1 下载Winpcap安装包,地址/install/default.htm。
2 然后到/devel.htm下载WinPcap developer's pack包,解压,里面有配置好的例子和include library。
3 在VC6.0菜单中,点Tolls->Options->Directories中的include files 和library files中添加包里面的include和library。
然后我们就来编写一个最简单的Winpcap程序——获取已连接的网络适配器列表。
首先新建一个工程,选择Win32 Console Application,工程名我们设为winpcap.然后这这个工程中新建一个C++源文件,名字winpcap。
在里面填写如下代码:
#include <pcap.h>
main( )
pcap_if_t *alldevs;
pcap_if_t *d;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); exit(1);
}
for(d= alldevs; d != NULL; 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;
}
pcap_freealldevs(alldevs);
return 0;
}
运行之前我们要手动给它添加一个动态链接库wpcap.lib,方法是在菜单Project中点Settings,然后在选项中选Link,在library modules 后面填上wpcap.lib,注意和前面的要有空格隔开。
然后编译,链接。
运行结果如下
正是我电脑的网卡信息,其中第一个现在我还没弄明白是什么,第二是我的无线网卡,第三是我现在正在用它上网的Realtek以太网卡。
关于这个程序的一些函数和变量的解释,大家可以看看Winpcap documentation,里面介绍的很详细,这里就不分析了。
PS:细心的人会发现,这里用来获取网络适配器信息的函数为pcap_findalldevs(),
和Winpcap documentation里面的例子不同,它那里用的函数是pcap_findalldevs_ex(),这个函数的参数有四个,这两个函数的定义及参数问题,在帮助文档上都很详细,这里也不说了。
要是用这个函数的话,编译时会有错误,说pcap_findalldevs_ex()未定义,为什么呢?因为我们这里头文件只包含了winpcap.h,在这个头文件里,你会发现并没有
pcap_findalldevs_ex()这个函数的定义,而只有pcap_findalldevs()的定义。
那么怎么办呢?两个方法,一,在#include <pcap.h>前面加上一个预处理程序定义#define
HAVE_REMOTE。
二,直接加上#include <remote_ext.h>,因为在这个文件里有
pcap_findalldevs_ex()的函数定义。
其实第一种方法也就变相的调用remote_ext.h这个文件,其过程大家可以在pcap.h中找到。
PS2:为什么前面已经设置了路径了,函数编译的时候为什么还的手动添加动态链接库?因为这个路径只是告诉它在哪里找,也就是说,只是个路径提示。
就像include <pcap.h>一样,它也是在Directories设置的include文件中的,但是我们在程序的开头还的包括这个头文件,这个道理是一样的。
ps3: 发现上面的运行结果的图给贴错了,这个图是我禁用无线网络后运行的,所以没有打印出无线网卡的信息,只是有两个,第一个根据老师的介绍是计算机的拨号和VPN(虚拟专用网)的网络接口(俗称的“猫”),第二个是以太网卡。
1.在VC 6.0中[工具]->[选择]->[目录]分别把解压包里的inlude和library加进去。
2.在VC 6.0中[工程]->[Link]中加wpcap.lib Packet.lib或在源文件中加入
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "Packet.lib")。
3.若要在程序中使用套接字,还须加#pragma comment(lib, "wsock32.lib")。
二列举网卡及对应的网络地址和子网掩码
#include "pcap.h"
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "Packet.lib")
#pragma comment(lib, "wsock32.lib")
void main()
...{
pcap_if_t *alldevs; //网络接口结点指针
pcap_if_t *d;
struct in_addr net_ip_address;//网络地址
u_int32_t net_ip;//某种格式的网络地址
char *net_ip_string;//可输出格式的网络地址
struct in_addr net_mask_address;//子网掩码
u_int32_t net_mask;//某种格式的子网掩码
char *net_mask_string;//可输出格式的子网掩码
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
/**//* 取得列表*/
if (pcap_findalldevs(&alldevs, errbuf) == -1)
...{
fprintf(stderr,"Error in pcap_findalldevs: %s ", errbuf);
exit(1);
}
/**//* 输出列表*/
for(d=alldevs;d;d=d->next)
...{
printf("%s ",d->name);//网卡名字
pcap_lookupnet(d->name,&net_ip,&net_mask,errbuf);
//获取网络地址和子网掩码
net_ip_address.s_addr = net_ip;
net_ip_string = inet_ntoa(net_ip_address); //格式转化printf("网络地址:%s ", net_ip_string);
net_mask_address.s_addr = net_mask;
net_mask_string = inet_ntoa(net_mask_address); //格式转化printf("网络掩码:%s ", net_mask_string);
}
pcap_freealldevs(alldevs); //释放接口结点链表
}
运行结果如图:
注:网络地址不是IP地址,故是10.10.138.0
三捕获一个网络数据包
#include <pcap.h>
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "Packet.lib")
#pragma comment(lib, "wsock32.lib")
/**//*
-----------------------------------------------------------------------------------------------------------------------
WinPcap头文件;
以下是以太网协议格式
-----------------------------------------------------------------------------------------------------------------------
*/
struct ether_header
...{
u_int8_t ether_dhost[6];
/**//* 以太网目的地址*/
u_int8_t ether_shost[6];
/**//* 源以太网地址*/
u_int16_t ether_type;
/**//* 以太网类型*/
};
void main()
...{
pcap_if_t *alldevs;
char error_content[PCAP_ERRBUF_SIZE];
/**//* 存储错误信息*/
pcap_t *pcap_handle;
/**//* winpcap句柄*/
const u_char *packet_content;
/**//* 数据包内容*/
u_char *mac_string;
/**//* 以太网地址*/
u_short ethernet_type;
/**//* 以太网类型*/
bpf_u_int32 net_mask;
/**//* 掩码地址*/
bpf_u_int32 net_ip;
/**//* 网络地址*/
char *net_interface;
/**//* 网络接口*/
struct pcap_pkthdr protocol_header;
/**//* 数据包头部信息*/
struct ether_header *ethernet_protocol;
/**//* 以太网协议变量*/
struct bpf_program bpf_filter;
/**//* BPF过滤规则*/
char bpf_filter_string[] = "ip";
/**//* 过滤规则字符串*/
// net_interface = pcap_lookupdev(error_content); //因为第一个是moden的网卡,所以不用这个
if (pcap_findalldevs(&alldevs,error_content) == -1)
...{
fprintf(stderr,"Error in pcap_findalldevs: %s ",error_content);
exit(1);
}
net_interface=alldevs->next->name;//得到第二个网卡(以太网卡)的名字
/**//* 获得网络接口*/
pcap_lookupnet(net_interface, &net_ip, &net_mask, error_content);
/**//* 获得网络地址和网络掩码*/
pcap_handle = pcap_open_live(net_interface, BUFSIZ, 1, 0, error_content);
/**//* 打开网路接口*/
pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_ip);
/**//* 编译过滤规则*/
pcap_setfilter(pcap_handle, &bpf_filter);
/**//* 设置过滤规则*/
if (pcap_datalink(pcap_handle) != DLT_EN10MB)
return ;
packet_content = pcap_next(pcap_handle, &protocol_header);
/**//* 捕获一个数据包,数据包内容返回给packet_content */
printf("--------------------*****----------------------- ");
printf("捕获到一个网络数据包");
printf("捕获时间: ");
printf("%s", ctime((const time_t*) &protocol__sec));
printf("数据包长度: ");
printf("%d ", protocol_header.len);
ethernet_protocol = (struct ether_header*)packet_content;
/**//* 获得数据包内容*/
printf("以太网类型: ");
ethernet_type = ntohs(ethernet_protocol->ether_type);
/**//* 获得以太网类型*/
printf("%04x ", ethernet_type);
switch (ethernet_type)
...{
case 0x0800:
printf("上层协议是IP协议");
break;
case 0x0806:
printf("上层协议是ARP协议");
break;
case 0x8035:
printf("上层协议是RARP协议");
break;
default:
break;
}
printf("源以太网地址: ");
mac_string = ethernet_protocol->ether_shost;
printf("%02x:%02x:%02x:%02x:%02x:%02x ", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
/**//* 获得源以太网地址*/
printf("目的以太网地址: ");
mac_string = ethernet_protocol->ether_dhost;
printf("%02x:%02x:%02x:%02x:%02x:%02x ", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
/**//* 获得目的以太网地址*/
printf("--------------------*****----------------------- ");
pcap_close(pcap_handle);
/**//* 关闭winpcap操作*/
}
运行结果(随便打开一个网页)如图:
注:因为第一个网卡是moden的网卡,所以要用
pcap_findalldevs(&alldevs,error_content);
net_interface=alldevs->next->name;
若使用pcap_findalldevs_ex(),应#include <remote-ext.h>
它是pcap_findalldevs()的一个超集, 他不仅可以获取本地的设备列表,还可以获取远程计算机的设备列表
四捕获多个网络数据包
#include <pcap.h>
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "Packet.lib")
/**//* 回调处理函数的原型*/
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
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(stderr,"Error in pcap_findalldevs: %s ", errbuf);
exit(1);
}
/**//* 输入列表*/
for(d=alldevs; d; d=d->next)
...{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s) ", d->description);
else
printf(" (No description available) ");
}
if(i==0)//如果网卡数等于0,则输出"找不到网卡"
...{
printf(" No interfaces found! Make sure WinPcap is installed. ");
return -1;
}
/**//* 选择欲抓包网卡号*/
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i)
...{
printf(" Interface number out of range. ");
/**//* Free the device list */
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, // 要捕获的数据包字节数
1, // 混杂模式为非0,非混杂为0
1000, // read timeout
errbuf // error buffer
)) == NULL)
...{
fprintf(stderr," Unable to open the adapter. %s is not supported by WinPcap ", d->name); pcap_freealldevs(alldevs);
return -1;
}
printf(" listening on %s... ", d->description);
/**//* 释放网络接口列表结点链表空间*/
pcap_freealldevs(alldevs);
/**//* 开始循环抓包,每抓一个包就用第三个参数所指的处理函数来处理*/
pcap_loop(adhandle, 0, packet_handler, NULL);
pcap_close(adhandle);
return 0;
}
/**//* 回调处理函数*/
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) ...{
struct tm *ltime;//在pcap.h已包含了<time.h>
char timestr[16];//接收转换后的时间
time_t local_tv_sec;
/**//* 获得时间*/
local_tv_sec = header->_sec;//日历日间,相当于local_tv_sec = time(NULL);
ltime=localtime(&local_tv_sec);//日历时间转化为本地时间
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);//时间显示格式
printf("%s,%.6d len:%d ", timestr, header->_usec, header->len);
}
运行结果:
本文来自CSDN博客,转载请标明出处:/xklxlmw/archive/2007/05/09/1602319.aspx。