winpcap编程学习笔记(2) 获取已安装设备的高级信息

这两天要准备公务员考试,一程序拖拖拉拉的四天才弄完,效率真是低下,下次要抓紧时间了。好了,进入正题,上次学习的是用winpcap来获网络适配器的一些 简单的信息,这次依然是获取信息,只是我们要获得更详细的关于网络的信息。
 
大家应该还记得,上次我在说pcap_if(也就是pcap_if_t,上次讲过,两个变量其实是一个结构)的时候,有一个成员变量address没有用到就没有说,让我们再来看看pcap_if的结构
 
pcap_f_t   
        pcap_f  *next    
        char *name   
        char *description 
        pcap_addr *address 
        u_int flags
 
而本次我们则主要是利用pcap_addr *address来获取网络适配器的ip地址,子网掩码,广播地址已经ip协议版本等重要的信息。
 
接下来让我们来看看pcap_addr *address的结构
 
pcap_addr *next   //指向链表的下一个节点
 
sockaddr *addr    //一个sockaddr结构的指针,包含ip地址和协议版本
 
sockaddr *netmask  //同上,子网掩码的地址
 
sockaddr *broadaddr  //同上,广播的地址
 
sockaddr *dstaddr     //看文档应该是目的地址,具体我还不是很明白
 
好了我们来看程序代码
 
#include "pcap.h"
#include "winsock.h"
void printpcapif(pcap_if_t *d);
char *ip4tostring(u_long u_longIp);
char *ip6tostring(SOCKADDR *sockaddr,char *address,int addrlen);

int main(int argc,int *argv[])
{
     pcap_if_t *alldevs;
     pcap_if_t *d;
     char errbuf[PCAP_ERRBUF_SIZE+1]; 
     if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf)==-1)
     {
          fprintf(stderr,"Error in pcap_findalldevs_ex",errbuf);
          exit(1);
      }
     for(d=alldevs;d;d=d->next)
     {
          printpcapif(d);
          printf("\n\n");
     }
     pcap_freealldevs(alldevs);
     return 0;
}
void printpcapif(pcap_if_t *d)
{
     pcap_addr_t *a;
     char ip6str[128];
     /*device name*/
     printf("device name:%s\n",d->name);
     /*device description*/
     if(d->description)
     {
          printf("device description:%s\n",d->description);
     }
     /*IP Address*/ 
      for(a=d->addresses;a;a=a->next)
     {
          /*IP version*/
          printf("Address Familiy:%d\n",a->addr->sa_family);
    
          /*Detail info of the IP*/
         switch(a->addr->sa_family)
      {
           case AF_INET:
           printf("Family Name:AF_INET\n");
           if(a->addr)
          {
              printf("IP Address: %s\n",ip4tostring((((SOCKADDR_IN *)a->addr)->sin_addr).S_un.S_addr));
     }
           if(a->netmask)
          {
              printf("Subnet Mask: %s\n",ip4tostring((((SOCKADDR_IN *)a->netmask)->sin_addr).S_un.S_addr));
           }
           if(a->broadaddr)
          {
               printf("Broad Address: %s\n",ip4tostring((((SOCKADDR_IN *)a->broadaddr)->sin_addr).S_un.S_addr));
           }
           if(a->dstaddr)
          {
               printf("Destination Address: %s\n",ip4tostring((((SOCKADDR_IN *)a->dstaddr)->sin_addr).S_un.S_addr));
           }
     break;
     
   case AF_INET6:
     
     printf("Family Name:AF_INET6\n");
     if(a->addr)
     {
          printf("%s\n",ip6tostring(a->addr,ip6str,sizeof(ip6str)));
     }
     break;
   default:
         printf("Adress Family Name:Unknow");
     break;
     
  }
 }
}
    /*Convert ip type from u_long to string*/
    #define IPTOSBUFFERS 12
    char *ip4tostring(u_long u_longIp)
    {
         static char output[3*4+3+1];
         ZeroMemory(output,3*4+3+1);
         u_char *p=(u_char *)&u_longIp;
         sprintf(output,"%d.%d.%d.%d",p[0],p[1],p[2],p[3]);
         return output;
    }
    char *ip6tostring(SOCKADDR *sockaddr,char *address,int addrlen)
    {
         socklen_t sockaddrlen=sizeof(struct sockaddr_in6);
         if(getnameinfo(sockaddr,sockaddrlen,address,addrlen,NULL,0,NI_NUMERICHOST)!=0)
 {
          address=NULL;
 }
     return address;
}
这个代码有这么几处需要注意的,
 
        和源代码相比,我为了简单,把ip4tostring函数中的output数组由二维改成了一维,因为我没有保存地址信息,只是做简单的类型转换然后返回而已。
 
        再就是注意ip4tostring中把ip地址由u_long转换成字符串的方法,本来我百思不得其解,凭什么把u_long型的变量的地址强制转换成u_char型,就能进行数组操作了p[0] p[1] p[2] p[3],后来看了看msdn 关于IN_ADDR类型的定义才发现,原来它是一个共用体,有u_char 和u_long两种类型,我想可能是由于这个原因,所以地址转换之后才可以通用。
 
        最后就是要注意sprintf函数的用法,可以转化类型,链接字符串等,相当方便,具体可以看我转帖中的一篇关于sprintf使用的文章。
 
以上代码在windows平台上vc++ 6.0编译运行正确

你可能感兴趣的:(职场,笔记,休闲,设备,winpcap)