获取已安装设备的高级信息

      继续WinPcap编程的学习,上一节说到《获取本地适配器信息》,本节的实例程序功能跟上一节的程序功能类似,只是打印了适配器更详细的信息,来看一下源码(在windows下codeblocks下编译运行,即使用MingW编译器通过)

//#define WPCAP

//#include <winsock2.h>
#define WINVER 0x0501

#define HAVE_REMOTE
#include <pcap.h>
//#include <winsock2.h>
#include <ws2tcpip.h>

//#define _WIN32_WINNT 0x0501

//typedef int socklen_t;

// 函数原型
void ifprint(pcap_if_t *d);
char *iptos(u_long in);
char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen);


int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
char errbuf[PCAP_ERRBUF_SIZE+1];
char source[PCAP_ERRBUF_SIZE+1];

printf("Enter the device you want to list:\n"
"rpcap:// ==> lists interfaces in the local machine\n"
"rpcap://hostname:port ==> lists interfaces in a remote machine\n"
" (rpcapd daemon must be up and running\n"
" and it must accept 'null' authentication)\n"
"file://foldername ==> lists all pcap files in the give folder\n\n"
"Enter your choice: ");

fgets(source, PCAP_ERRBUF_SIZE, stdin);
source[PCAP_ERRBUF_SIZE] = '\0';

/* 获得接口列表 */
if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
exit(1);
}

/* 扫描列表并打印每一项 */
for(d=alldevs;d;d=d->next)
{
ifprint(d);
}

pcap_freealldevs(alldevs);

return 1;
}



/* 打印所有可用信息 */
void ifprint(pcap_if_t *d)
{
pcap_addr_t *a;
char ip6str[128];

/* 设备名(Name) */
printf("%s\n",d->name);

/* 设备描述(Description) */
if (d->description)
printf("\tDescription: %s\n",d->description);

/* Loopback Address*/
printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");

/* IP addresses */
for(a=d->addresses;a;a=a->next) {
printf("\tAddress Family: #%d\n",a->addr->sa_family);

switch(a->addr->sa_family)
{
case AF_INET:
printf("\tAddress Family Name: AF_INET\n");
if (a->addr)
printf("\tAddress: %s\n",iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
if (a->netmask)
printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
if (a->broadaddr)
printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
if (a->dstaddr)
printf("\tDestination Address: %s\n",iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));
break;

case AF_INET6:
printf("\tAddress Family Name: AF_INET6\n");
if (a->addr)
printf("\tAddress: %s\n", ip6tos(a->addr, ip6str, sizeof(ip6str)));
break;

default:
printf("\tAddress Family Name: Unknown\n");
break;
}
}
printf("\n");
}



/* 将数字类型的IP地址转换成字符串类型的 */
#define IPTOSBUFFERS 12
char *iptos(u_long in)
{
static char output[IPTOSBUFFERS][3*4+3+1];
static short which;
u_char *p;

p = (u_char *)&in;
which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return output[which];
}

char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen)
{
socklen_t sockaddrlen;

#ifdef WIN32
sockaddrlen = sizeof(struct sockaddr_in6);
#else
sockaddrlen = sizeof(struct sockaddr_storage);
#endif


if(getnameinfo(sockaddr,
sockaddrlen,
address,
addrlen,
NULL,
0,
NI_NUMERICHOST) != 0) address = NULL;

return address;
}

      在编译本程序的时候碰到了很多问题,这里想总结一下解决的办法。之前在网上查找过很多博客,但是发现程序都是在VC下进行编译的,而我的codeblocks用的是MingW编译器进行编译的,之间会有很多区别,VC编译器如何解决我这里就不做介绍了,因为编写C程序还是比较习惯在codeblocks下,个人偏好。配置其实跟VC下的配置差不多,仍然是在Link Libraries下加入Packet.lib和wpcap.lib,这两个库文件是WinPcap提供的;另外,还要添加libws2_32.a这个库,这个库可以在MingW安装目录下的lib文件夹里面找到,VC下面是要添加ws2_32.lib这个库,大家千万不要搞混了,因为有看到很多博客上写的是配置codeblocks添加ws2_32.lib,当然如果是用VC的编译器就没问题,但如果用MingW编译器一般不会报错,但是会出现很多Warning,大家注意一下便是。截图给大家看一下,以下是本机codeblocks Link Libraries添加的情况:

获取已安装设备的高级信息_第1张图片

      另外,在Search directories的Compiler目录下加入WinPcap的include目录,也可以把MingW安装目录下的include目录添加进去,添不添加关系不大,但是WinPcap的include目录一定是要包含进去的。同样,截图给大家看一下本机配置情况:

获取已安装设备的高级信息_第2张图片

      再看一看源程序,跟上一个程序很类似。只是本程序提供了更高级的信息。我们知道由pcap_findalldevs_ex()返回的每一个pcap_if结构体,都包含一个pcap_addr结构体,这个结构体如下元素组成:

      一个地址列表、一个掩码列表、一个广播地址列表、一个目的地址列表

      另外,函数pcap_findalldevs_ex()还能返回远程适配器信息和一个位于所给的本地文件夹的pcap文件列表,跟函数第一个参数有关。

      我们看到源码中声明了3个函数,ifprint、iptos和ip6tos。ifprint函数其实就是一个打印函数,打印设备名、设备描述、回环地址、IP地址信息;iptos函数和ip6tos函数功能类似,就是把IP地址转换成为char*类型,只是协议族不同,一个是ipv4,另一个是ipv6,而且iptos函数参数中IP地址是unsigned long类型,ip6tos函数参数中IP地址是sockaddr结构体指针类型。

      程序功能很简单,但是有一点想说一下。我们看到源码中多了一行:

#define WINVER 0x0501

     这行是搞什么东东呢?源码中也没用到这个WINVER是吧。我刚开始因为没有添加这一行折腾了很久,一直报getnameinfo这个函数未定义,但是查看getnameinfo函数的声明处又偏偏看到了:

获取已安装设备的高级信息_第3张图片

      找了很久没有找到答案,于是自己仔细分析了一下,因为这是一个条件编译,如果说没有找到声明,肯定是if判断不成功。于是乎我看了一下_WIN32_WINNT是在哪里声明的:

获取已安装设备的高级信息_第4张图片

      原来_WIN32_WINNT的前身是WINVER!!根据它的注释的意思,是要自己define WINVER或者包含windef.h这个头文件,但是查看windef.h这个头文件看到WINVER的值为0x0400,包含了这个头文件条件编译仍然是不能通过的,要大于或等于0x0501。那得了,我们之间#define WINVER 0x0501不就好了,事实上也是的,添加进去后编译就可以通过了,Congratulations!下面是程序运行后的截图:

获取已安装设备的高级信息_第5张图片

      输入rpcap://后回车,返回结果如下图所示:

获取已安装设备的高级信息_第6张图片

你可能感兴趣的:(安装)