Winpcap网络编程六之Winpcap学习教程,获取已安装设备的高级信息

上一节我们展示了如何获取适配器的基本信息 (如设备的名称和描述)。

实际上,获取适配器基本信息远远不止这些,让我们先看下pcap_if结构体的内容

pcap_if *  next 
  if not NULL, a pointer to the next element in the list; NULL for the last element of the list 
 
char *  name 
  a pointer to a string giving a name for the device to pass to pcap_open_live() 
 
char *  description 
  if not NULL, a pointer to a string giving a human-readable description of the device 
 
pcap_addr *  addresses 
  a pointer to the first element of a list of addresses for the interface 
 
u_int  flags 
  PCAP_IF_ interface flags. Currently the only possible flag is PCAP_IF_LOOPBACK, that is set if the interface is a loopback interface. 
 
大家可以发现它有一个pcap_addr 的结构体,而这个结构体的组成如下:

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 
 

  • 一个地址列表
  • 一个掩码列表 (each of which corresponds to an entry in the addresses list).
  • 一个广播地址列表 (each of which corresponds to an entry in the addresses list).
  • 一个目的地址列表 (each of which corresponds to an entry in the addresses list).
  • 一个链接到下一个pcap_addr 的指针

下面的范例使用了ifprint()函数来打印出 pcap_if 结构体中所有的内容。程序对每一个由pcap_findalldevs_ex() 函数返回的pcap_if,都调用ifprint()函数来实现打印。代码如下:

#include "pcap.h"

#ifndef WIN32
    #include 
    #include 
#else
    #include 
#endif


// 函数原型
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;
}

改编版:

#include 
#include 
#include 

void ifprint(pcap_if_t *d);
char *iptos(u_long in);       //u_long即为 unsigned long

int main(){

	pcap_if_t  * alldevs;       //所有网络适配器
	pcap_if_t  *d;					//选中的网络适配器
	char errbuf[PCAP_ERRBUF_SIZE];   //错误缓冲区,大小为256
	char source[PCAP_ERRBUF_SIZE];

	int i = 0;                            //适配器计数变量
	/**
		int pcap_findalldevs_ex  ( char *  source,  
													  struct pcap_rmtauth *  auth,  
													  pcap_if_t **  alldevs,  
													  char *  errbuf  );
		PCAP_SRC_IF_STRING代表用户想从一个本地文件开始捕获内容;
	*/
	//获取本地适配器列表
	if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf) == -1){
		//结果为-1代表出现获取适配器列表失败
		fprintf(stderr,"Error in pcap_findalldevs_ex:\n",errbuf);
		//exit(0)代表正常退出,exit(other)为非正常退出,这个值会传给操作系统
		exit(1);
	}
	//打印设备列表信息
	/**
		d = alldevs 代表赋值第一个设备,d = d->next代表切换到下一个设备
		结构体 pcap_if_t:
		pcap_if *  next					指向下一个pcap_if,pcap_if_t和pcap_if 结构是一样的
		char *  name						代表适配器的名字
		char *  description			对适配器的描述
		pcap_addr *  addresses  适配器存储的地址
		u_int  flags							适配器接口标识符,值为PCAP_IF_LOOPBACK
	*/
	for(d = alldevs;d !=NULL;d = d->next){
		printf("-----------------------------------------------------------------\nnumber:%d\nname:%s\n",++i,d->name);
		if(d->description){
			//打印适配器的描述信息
			printf("description:%s\n",d->description);
		}else{
			//适配器不存在描述信息
			printf("description:%s","no description\n");
		}
		//打印本地环回地址
		 printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");
		 /**
		 pcap_addr *  next     指向下一个地址的指针
		 sockaddr *  addr       IP地址
		 sockaddr *  netmask  子网掩码
		 sockaddr *  broadaddr   广播地址
		 sockaddr *  dstaddr        目的地址
		 */
		 pcap_addr_t *a;       //网络适配器的地址用来存储变量
		 for(a = d->addresses;a;a = a->next){
			 //sa_family代表了地址的类型,是IPV4地址类型还是IPV6地址类型
			 switch (a->addr->sa_family)
			 {
				 case AF_INET:  //代表IPV4类型地址
					 printf("Address Family Name:AF_INET\n");
					 if(a->addr){
						 //->的优先级等同于括号,高于强制类型转换,因为addr为sockaddr类型,对其进行操作须转换为sockaddr_in类型
						 printf("Address:%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: //代表IPV6类型地址
					 printf("Address Family Name:AF_INET6\n");
					 printf("this is an IPV6 address\n");
					 break;
				 default:
					 break;
			 }
		 }
	}
	//i为0代表上述循环未进入,即没有找到适配器,可能的原因为Winpcap没有安装导致未扫描到
	if(i == 0){
		printf("interface not found,please check winpcap installation");
	}
	//释放网络适配器列表
	pcap_freealldevs(alldevs);
	int inum;
	scanf_s("%d", &inum);

	return 0;

}

/* 将数字类型的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_s(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
    return output[which];
}

需要特别指出的是,如果你用的是VC,那么下面的ipv6信息是无法编译通过的,需要在VS2005以上的环境下才能编译通过。

我用的Eclipse,编译器是mingw,很遗憾,这个也不支持ipv6信息的获取,调试了一段时间后发现无法编译通过。

既然这样的话我们就将 包含ipv6信息的代码去掉来运行。

#include "pcap.h"

#ifndef WIN32
    #include 
    #include 
#else
    #include 
#endif


// 函数原型
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;
}
*/

运行结果:

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

Enter your choice: rpcap://  

 
  
rpcap://\Device\NPF_{5AC72F8D-019C-4003-B51B-7ABB67AF392A}
	Description: Network adapter 'Microsoft' on local host
	Loopback: no
	Address Family: #23
	Address Family Name: Unknown
	Address Family: #23
	Address Family Name: Unknown

rpcap://\Device\NPF_{C17EB3F6-1E86-40E5-8790-AC2518B74D05}
	Description: Network adapter 'Microsoft' on local host
	Loopback: no
	Address Family: #23
	Address Family Name: Unknown
	Address Family: #2
	Address Family Name: AF_INET
	Address: 192.168.95.1
	Netmask: 255.255.255.0
	Broadcast Address: 255.255.255.255

rpcap://\Device\NPF_{33E23A2F-F791-409B-8452-A3FB5A78B73E}
	Description: Network adapter 'Qualcomm Atheros Ar81xx series PCI-E Ethernet Controller' on local host
	Loopback: no
	Address Family: #23
	Address Family Name: Unknown
	Address Family: #23
	Address Family Name: Unknown
	Address Family: #23
	Address Family Name: Unknown
	Address Family: #2
	Address Family Name: AF_INET
	Address: 121.250.216.237
	Netmask: 255.255.255.0
	Broadcast Address: 255.255.255.255

rpcap://\Device\NPF_{DCCF036F-A9A8-4225-B980-D3A3F0575F5B}
	Description: Network adapter 'Microsoft' on local host
	Loopback: no
	Address Family: #23
	Address Family Name: Unknown
	Address Family: #23
	Address Family Name: Unknown

rpcap://\Device\NPF_{D62A0060-F424-46FC-83A5-3394081685FD}
	Description: Network adapter 'Microsoft' on local host
	Loopback: no
	Address Family: #23
	Address Family Name: Unknown
	Address Family: #2
	Address Family Name: AF_INET
	Address: 192.168.191.1
	Netmask: 255.255.255.0
	Broadcast Address: 255.255.255.255

rpcap://\Device\NPF_{B5224A53-8450-4537-AB3B-9869158121CD}
	Description: Network adapter 'Microsoft' on local host
	Loopback: no
	Address Family: #23
	Address Family Name: Unknown
	Address Family: #2
	Address Family Name: AF_INET
	Address: 0.0.0.0
	Netmask: 255.0.0.0
	Broadcast Address: 255.255.255.255


你可能感兴趣的:(Eclipse,C++,计算机网络,C)