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

本文转载自: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    12
char *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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值