WINPCAP编程环境设置

发布时间:2010-08-24 21:16:23   来源:文档文库   
字号:

因为项目需要,而且以前从没用过Winpcap,所以不得不从头学起。以前虽然看过winsocket,但是,Winpcap的第一个程序,我花了很长时间才编译通过。对于初学者来说,不太好做的可能是编译程序之前应该做什么事。我就大体说一下我的过程。

首先先大体介绍下Winpcap

winpcap(windows packet capture)windows平台下一个免费,公共的网络访问系统。开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。它提供了以下的各项功能:

1> 捕获原始数据包,包括在共享网络上各主机发送/接收的以及相互之间交换的数据包;

2> 在数据包发往应用程序之前,按照自定义的规则将某些特殊的数据包过滤掉;

3> 在网络上发送原始的数据包;

4> 收集网络通信过程中的统计信息。

具体介绍参见http://baike.baidu.com/view/696423.htm 这里有Winpcap的详细介绍。

下面说一下你在编译Winpcap之前要做的事情。

1 下载Winpcap安装包,地址http://www.winpcap.org/install/default.htm

2 然后到  http://www.winpcap.org/devel.htm下载WinPcap developer's pack包,解压,里面有配置好的例子和include library

3 VC6.0菜单中,点Tolls->Options->Directories中的include files library files中添加包里面的includelibrary

 

然后我们就来编写一个最简单的Winpcap程序——获取已连接的网络适配器列表。

首先新建一个工程,选择Win32 Console Application,工程名我们设为winpcap.然后这这个工程中新建一个C++源文件,名字winpcap。在里面填写如下代码:

#include

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 前面加上一个预处理程序定义#define HAVE_REMOTE。二,直接加上#include ,因为在这个文件里有pcap_findalldevs_ex()的函数定义。其实第一种方法也就变相的调用remote_ext.h这个文件,其过程大家可以在pcap.h中找到。

   PS2:为什么前面已经设置了路径了,函数编译的时候为什么还的手动添加动态链接库?因为这个路径只是告诉它在哪里找,也就是说,只是个路径提示。就像include 一样,它也是在Directories设置的include文件中的,但是我们在程序的开头还的包括这个头文件,这个道理是一样的。

  ps3: 发现上面的运行结果的图给贴错了,这个图是我禁用无线网络后运行的,所以没有打印出无线网卡的信息,只是有两个,第一个根据老师的介绍是计算机的拨号和VPN(虚拟专用网)的网络接口(俗称的“猫”),第二个是以太网卡。

1.VC 6.0[工具]->[选择]->[目录]分别把解压包里的inludelibrary加进去。

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

#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_header.ts.tv_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

它是pcap_findalldevs()的一个超集, 他不仅可以获取本地的设备列表,还可以获取远程计算机的设备列表

捕获多个网络数据包

#include

#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已包含了

char timestr[16];//接收转换后的时间

time_t local_tv_sec;

/**//* 获得时间*/

local_tv_sec = header->ts.tv_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->ts.tv_usec, header->len);

}

运行结果:

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xklxlmw/archive/2007/05/09/1602319.aspx

本文来源:https://www.2haoxitong.net/k/doc/70dfb13383c4bb4cf7ecd177.html

《WINPCAP编程环境设置.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式