您的位置:首页 > 理论基础 > 计算机网络

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

2014-10-08 20:28 393 查看
上一节我们展示了如何获取适配器的基本信息 (如设备的名称和描述)。

实际上,获取适配器基本信息远远不止这些,让我们先看下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 <sys/socket.h>
#include <netinet/in.h>
#else
#include <winsock.h>
#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 <stdio.h>
#include <stdlib.h>
#include <pcap.h>

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 <sys/socket.h>
#include <netinet/in.h>
#else
#include <winsock.h>
#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息