网站建议:179001057@qq.com

WinPcap基础知识(第一课:获得设备列表)

技术2022-05-12  4

一个基本的WinPcap应用程序所需的第一件事情是获得合适的网络适配器。Libpcap/ Winpcap提供 pcap_findalldevs() 函数完成这个功能:这个函数返回一个相连的pcap_if结构的列表。列表的每一项包含关于适配器的复杂的信息。特别的,namedescription域数据包含设备的名称和可读的描述。如下的代码提取设备列表,然后打印到屏幕上。如果没有发现适配器,则显示一个错误。

 #include <pcap.h> void main() { pcap_if_t *alldevs; pcap_if_t *d; int i=0; char errbuf[PCAP_ERRBUF_SIZE]; /* 取得本机的网络设备列表 */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* 这个参数在这里不需要 */, &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; } /* We don't need any more the device list. Free it */ pcap_freealldevs(alldevs); }  

 

在第一行 #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支持的所有的操作系统提供网络适配器的描述,因此如果我们想要编写一个可移植的应用程序,我们必须考虑descriptionnull的情况。在这种情况下我们打印"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_ifincs/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>中定义

 

 

数据域:

 

 

pcap_addr

 

next

 

 

 

if not NULL, a pointer to the next element in the list; NULL for the last element of the list

 

sockaddr * 

 

addr

 

 

 

a pointer to a struct sockaddr containing an address

 

sockaddr * 

 

netmask

 

 

 

if not NULL, a pointer to a struct sockaddr that contains the netmask corresponding to the address pointed to by addr.

 

sockaddr * 

 

broadaddr

 

 

 

if not NULL, a pointer to a struct sockaddr that contains the broadcast address corre­ sponding to the address pointed to by addr; may be null if the interface doesn't support broadcasts

 

sockaddr * 

 

dstaddr

 

 

 

if not NULL, a pointer to a struct sockaddr that contains the destination address corre­ sponding to the address pointed to by addr; may be null if the interface isn't a point- to-point interface

 

 

⑶函数说明

 

 

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用来存放出错信息。

 

 

返回值

 

 

成功返回0alldevs返回设备列表,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/ [列出远程机器上的可以列出的设备]

 

关于hostport参数,可以为数字或者字母。由于支持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

 

 

 

 

 


最新回复(0)