WinPcap编程入门(2)——获取安装设备的高级信息

来源:互联网 发布:淘宝网如何刷销量 编辑:程序博客网 时间:2024/06/06 07:08

本文转载自:http://www.cnblogs.com/blacksword/    

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

<span style="font-family:KaiTi_GB2312;font-size:18px;">//#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    12char *iptos(u_long in){    static char output[IPTOSBUFFERS][3*4+3+1];    static short which;    u_char *p;    p = (u_char *)∈    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;}</span>

  在编译本程序的时候碰到了很多问题,这里想总结一下解决的办法。之前在网上查找过很多博客,但是发现程序都是在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添加的情况:


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


 再看一看源程序,跟上一个程序很类似。只是本程序提供了更高级的信息。我们知道由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结构体指针类型。

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

<span style="font-family:KaiTi_GB2312;font-size:18px;">#define WINVER 0x0501</span>
 这行是搞什么东东呢?源码中也没用到这个WINVER是吧。我刚开始因为没有添加这一行折腾了很久,一直报getnameinfo这个函数未定义,但是查看getnameinfo函数的声明处又偏偏看到了:

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


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


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


0 0
原创粉丝点击