上一节我们展示了如何获取适配器的基本信息 (如设备的名称和描述)。
实际上,获取适配器基本信息远远不止这些,让我们先看下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
下面的范例使用了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