一个基本的WinPcap应用程序所需的第一件事情是获得合适的网络适配器。Libpcap/ Winpcap提供 pcap_findalldevs() 函数完成这个功能:这个函数返回一个相连的pcap_if结构的列表。列表的每一项包含关于适配器的复杂的信息。特别的,name和description域数据包含设备的名称和可读的描述。如下的代码提取设备列表,然后打印到屏幕上。如果没有发现适配器,则显示一个错误。
在第一行 #include <pcap.h>的前面加上#define HAVE_REMOTE,或者你在项目属性里面添加“C语言预处理程序定义”一栏里面
加上HAVE_REMOTE(注意用‘,’隔开)。加上HAVE_REMOTE,因为在pcap.h头文件里面对此进行判断,
如果定义了符号HAVE_REMOTE,pcap.h头文件会自动包含<remote-ext.h>文件,而该文件中申明了函数pcap_findalldevs_ex()
以及宏定义PCAP_SRC_IF_STRING。
另外注意一下,在vs2003下面编译的时候,要把项目属性里面的预处理器定义(宏定义)要加上_MBCS的定义,默认的创建VC++控制台应用程序里面是没有该符号的定义的,如果没有该符号定义,编译上面的程序会提示出错。
代码的解释如下(部分):
首先,象其他libpcap函数一样, pcap_findalldevs()具有一个errbuf参数。该参数指向一个由libpcap填充的字符串。当有错误发生时,错误的描述被写入到这个字符串。
其次,记住不是libpcap支持的所有的操作系统提供网络适配器的描述,因此如果我们想要编写一个可移植的应用程序,我们必须考虑description为null的情况。在这种情况下我们打印"No description available" 这个字符串。
最后注意当我们使用列表完成后我们用pcap_freealldevs() 函数释放了它。
试着编译和运行第一个例子。为了在Unix或者Cygwin下编译它,输入:
gcc -o testaprog testprog.c -lpcap
在Windows下,你需要建立一个project。按照"Using WinPcap in your programs " 的介绍。不过,我建议你使用WinPcap 开发包(在http://winpcap.polito.it 提供下载)。开发包提供很多正确设置的示例程序,并且包含本指南所有代码和编译示例所需的项目、包含文件和库。
编译完成,在我的WinXP工作站上运行程序,结果是
1. {4E273621-5161-46C8-895A-48D0E52A0B83} (Realtek RTL8029(AS) Ethernet Adapter)
2. {5D24AE04-C486-4A96-83FB-8B5EC6C7F430} (3Com EtherLink PCI)
现在你可以看到,Windows下网络适配器的名称(当打开设备时会传递给libpcap)基本上不知所云,也就是说可读性不好,所以旁边的描述对读者将十分有用。
本课用到的数据结构简介:
①pcap_if 结构:
⑴typedef struct pcap_if pcap_if_t
pcap_if在incs/pcap.h文件的72行有定义,在程序里面用此结构,要#include <pcap.h>
⑵pcap_if结构里面的数据域:
pcap_if * next :如果非空,是指向下一个元素的指针;如果是NULL,表示是最后一个元素了。
char * name :一个指向字符串的指针,该字符串表示一个设备的名字,作为一个参数传递给pcap_open_live()
char *description; textual description of interface, or NULL
pcap_addr * addresses :指向接口的地址列表的第一个元素
u_int flags : PCAP_IF_INTERFACE 标志。目前唯一可以的标志是PCAP_IF_LOOPBACK,当接口是回送接口(loopback)
②pcap_addr结构:代表一个接口地址,在<pcap.h>中定义
数据域:
⑶函数说明
int pcap_findalldevs_ex ( char * source, struct pcap_rmtauth * auth,
pcap_if_t ** alldevs, char * errbuf )
pcap_findalldevs_ex函数获得网络设备的一个列表,并且这个列表可以被pcap_open()打开。
Pcap_findalldevs_ex()是pcap_findalldevs()的超集,后者是以前的老函数,它只能列出在本地机器的设备。相反,pcap_findalldevs_ex可以列出远程及其上面的设备。除此之外,它还可以列出某个给定的具体目录下面的所有的pcap文件的列表。而且,pcap_findalldevs_ex()还是平台独立的,因为它依靠标准的pcap_findalldevs()来在本地机器上获得地址 。和pcap_findalldevs()不同的是,该函数获得接口名称(alldevs->name )已经可以直接作为参数传递给pcap_open()进行调用。但是pcap_findalldevs_ex()不能,它得到的结果必须要先用
Pcap_createsrcstr()进行格式化,然后把source 标识符传递给pcap_open()。
如果该函数必须列出远程机器上的接口,它打开一个新的控制连接来连接远程机器,然后获得接口,完成后就释放连接。但是,如果该函数检测到远程机器是处于非活动状态,这个连接不会被释放。
参数说明:
Source : 该变量告诉函数在哪儿去查找,它和pcap_open()使用通用的语法。它是一个字符串,用来存放源位置(source location),例如:source 可以是”rpcap://”,表示本地适配器;也可以是”rpcap://host:port”,表示远程主机上面的适配器;还可以是pcap文件,例如:source可以是”rpcap://c:/myfolder/”。
auth:指向pcap_rmtauth结构的指针,用来保存连接到远程主机上授权信息。在查询本地机器时,此参数没什么意义,可以为NULL。
alldevs: 指向pcap_if_t结构的指针,该指针不需要初始化,它会在函数的调用过程中进行初始化。此函数返回时,该指针被设置为所获得的设备接口列表的第一个元素,列表的每一个元素都是
Pcap_if_t结构。
errbuf :指向用户分配的缓冲区(大小为PCAP_ERRBUF_SIZE),该buf用来存放出错信息。
返回值:
成功返回0,alldevs返回设备列表,alldevs不会为NULL。否则返回-1,那就是说系统没有任何接口可以列举的。
出错的消息在errbuf里面返回,错误可能由下面的原因造成的:
① libpcap/winpcap在本地/远程主机上没有安装。
② 用户没有足够的权限来列举设备/文件
③ 网络问题
④ 其它的错误(比如没有足够的内存或者其它原因)
注意的问题:
接口列表一定要手动释放,通过调用pcap_freealldevs()函数。
Source参数的语法:
⑴两个宏定义:
#define PCAP_SRC_FILE_STRING “ file://”
#define PCAP_SRC_IF_STRING “rpcap://”
此两个宏在remote-ext.h里面定义。
(2)详细描述
下面列举出了能够被pcap_open()函数打开的格式:
file://path_and_filename [打开一个本地文件]
rpcap://devicename [打开本地机器上面的可以打开的设备,不使用rpcap协议]
rpcap://host/devicename [打开远程机子上可以打开的设备]
rpcap://host:port/devicename [打开远程机器上面选择的设备,用一个非标准端口作为rpcap]
adaptername [打开一个本地适配器,kept for compability,不推荐]
(NULL) [打开第一个本地适配器,kept for compability,不推荐]
Pcap_findalldevs_ex()允许的格式如下:
file://folder/ [列出指定目录的所有文件]
rpcap:// [列出本地的适配器]
rpcap://host:port/ [列出远程机器上的可以列出的设备]
关于host和port参数,可以为数字或者字母。由于支持IPV6,它们可以是下面的格式:
· host (literal): e.g. host.foo.bar
- host (numeric IPv4): e.g. 10.11.12.13
- host (numeric IPv4, IPv6 style): e.g. [10.11.12.13]
- host (numeric IPv6): e.g. [1:2:3::4]
- port: can be either numeric (e.g. '80') or literal (e.g. 'http')
这里是一些例子:
rpcap://host.foo.bar/devicename [everything literal, no port number]
- rpcap://host.foo.bar:1234/devicename [everything literal, with port number]
- rpcap://10.11.12.13/devicename [IPv4 numeric, no port number]
- rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number]
- rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number]
- rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number]
- rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number]
- rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number]
转自:http://wotseb.bokee.com/1418997.html