这两天要准备公务员考试,一程序拖拖拉拉的四天才弄完,效率真是低下,下次要抓紧时间了。好了,进入正题,上次学习的是用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编译运行正确