如何获取局域网内某个IP所对应的网卡的 MAC (物理地址)?
我现在只会获取本机网卡的MAC地址。调用ioctl()函数。
在windows 98/NT,可以调用SendARP()来获取LAN的计算机的MAC。
那linux里,如何做呢?请帮助,谢谢!
|
PF_PACKET是用来处理原始报文协议的
这里有一个很久以前的代码,你看看能不能用
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* 得到本机的mac地址和ip地址 */
int GetLocalMac(const char *device,char *mac,char *ip)
{
int sockfd;
struct ifreq req;
struct sockaddr_in * sin;
if((sockfd = socket(PF_INET,SOCK_DGRAM,0))==-1)
{
fprintf(stderr,"Sock Error:%sna",strerror(errno));
return(-1);
}
memset(&req,0,sizeof(req));
strcpy(req.ifr_name,device);
if(ioctl(sockfd,SIOCGIFHWADDR,(char *)&req)==-1)
{
fprintf(stderr,"ioctl SIOCGIFHWADDR:%sna",strerror(errno));
close(sockfd);
return(-1);
}
memcpy(mac,req.ifr_hwaddr.sa_data,6);
req.ifr_addr.sa_family = PF_INET;
if(ioctl(sockfd,SIOCGIFADDR,(char *)&req)==-1)
{
fprintf(stderr,"ioctl SIOCGIFADDR:%sna",strerror(errno));
close(sockfd);
return(-1);
}
sin = (struct sockaddr_in *)&req.ifr_addr;
memcpy(ip,(char *)&sin->sin_addr,4);
return(0);
}
char *mac_ntoa(const unsigned char *mac)
{
/* Linux 下有 ether_ntoa(),不过我们重新写一个也很简单 */
static char buffer[18];
memset(buffer,0,sizeof(buffer));
sprintf(buffer,"%02X:%02X:%02X:%02X:%02X:%02X",
mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
return(buffer);
}
/*根据 RFC 0826 修改*/
typedefstruct _Ether_pkgEther_pkg;
struct _Ether_pkg {
/* 前面是ethernet头 */
unsigned char ether_dhost[6];/* 目地硬件地址*/
unsigned char ether_shost[6];/* 源硬件地址*/
unsigned short int ether_type; /* 网络类型*/
/* 下面是arp协议 */
unsigned short int ar_hrd;/* 硬件地址格式 */
unsigned short int ar_pro;/* 协议地址格式 */
unsigned char ar_hln;/* 硬件地址长度(字节) */
unsigned char ar_pln;/* 协议地址长度(字节) */
unsigned short int ar_op;/* 操作代码*/
unsigned char arp_sha[6];/* 源硬件地址 */
unsigned char arp_spa[4];/* 源协议地址*/
unsigned char arp_tha[6];/* 目地硬件地址 */
unsigned char arp_tpa[4];/* 目地协议地址 */
};
void parse_ether_package(const Ether_pkg *pkg)
{
printf("目地mac地址:[%s]n",mac_ntoa(pkg->ether_dhost));
printf("源 mac地址:[%s]n",mac_ntoa(pkg->ether_shost));
switch (ntohs(pkg->ether_type))
{
case ETHERTYPE_ARP:
printf("IP->MAC解析n");
break;
case ETHERTYPE_REVARP:
printf("MAC->IP解析n");
break;
default:
printf("解析未处理 =[%d]n",ntohs(pkg->ether_type));
break;
}
switch (ntohs(pkg->ar_hrd))
{
case ARPHRD_ETHER:
printf("以太网地址n");
break;
default:
printf("网络地址类型未解析 =[%d]n",ntohs(pkg->ar_hrd));
break;
}
switch (ntohs(pkg->ar_pro))
{
case ETHERTYPE_IP:
printf("IP地址n");
break;
default:
printf("其它地址未解析 =[%d]n",ntohs(pkg->ar_pro));
break;
}
printf("硬件地址长度=[%d]n",pkg->ar_hln);
printf("协议地址长度=[%d]n",pkg->ar_pln);
switch (ntohs(pkg->ar_op))
{
case ARPOP_REQUEST:
printf("IP->MAC地址解析请求n");
break;
case ARPOP_REPLY:
printf("IP->MAC地址解析应答n");
break;
default:
printf("其它类型的包文 =[%d]n",ntohs(pkg->ar_op));
}
printf("源 MAC地址 =[%s]n",mac_ntoa(pkg->arp_sha));
printf("源 IP地址 =[%s]n",inet_ntoa(*(struct in_addr *)pkg->arp_spa));
printf("目地MAC地址 =[%s]n",mac_ntoa(pkg->arp_tha));
printf("目地 IP地址 =[%s]n",inet_ntoa(*(struct in_addr *)pkg->arp_tpa));
}
int main(int argc,char **argv)
{
Ether_pkgpkg,*parse;
charbuffer[255];
unsigned charmac[7];
unsigned charip[5];
struct hostent *host =NULL;
intsockfd,len;
struct sockaddr sa;
unsigned charbroad_mac[7]={0xff,0xff,0xff,0xff,0xff,0xff,0x00};
memset(mac,0,sizeof(mac));
memset(ip,0,sizeof(ip));
if(GetLocalMac("eth0",mac,ip)==-1)
return(-1);
printf("本地 Mac=[%s] Ip=[%s]n",
mac_ntoa(mac),inet_ntoa(*(struct in_addr *)ip));
if(argc==1)return(-1);
memset((char *)&pkg,'',sizeof(pkg));
/* 填充ethernet包文 */
memcpy((char *)pkg.ether_shost,(char *)mac,6);
memcpy((char *)pkg.ether_dhost,(char *)broad_mac,6);
pkg.ether_type = htons(ETHERTYPE_ARP);
/* 下面填充arp包文 */
pkg.ar_hrd = htons(ARPHRD_ETHER);
pkg.ar_pro = htons(ETHERTYPE_IP);
pkg.ar_hln = 6;
pkg.ar_pln = 4;
pkg.ar_op = htons(ARPOP_REQUEST);
memcpy((char *)pkg.arp_sha,(char *)mac,6);
memcpy((char *)pkg.arp_spa,(char *)ip,4);
memcpy((char *)pkg.arp_tha,(char *)broad_mac,6);
printf("Resolve [%s],Please Waiting...",argv[1]);
fflush(stdout);
memset(ip,0,sizeof(ip));
if(inet_aton(argv[1],(struct in_addr *)ip)==0)
{
if((host = gethostbyname(argv[1]))==NULL)
{
fprintf(stderr,"Fail! %sna",hstrerror(h_errno));
return(-1);
}
memcpy((char *)ip,host->h_addr,4);
}
printf(" Done!n");
memcpy((char *)pkg.arp_tpa,(char *)ip,4);
/* 实际应该使用PF_PACKET */
if((sockfd = socket(PF_INET,SOCK_PACKET,htons(ETH_P_ALL)))==-1)
{
fprintf(stderr,"Socket Error:%sna",strerror(errno));
return(0);
}
memset(&sa,'',sizeof(sa));
strcpy(sa.sa_data,"eth0");
len = sendto(sockfd,&pkg,sizeof(pkg),0,&sa,sizeof(sa));
if(len != sizeof(pkg))
{
fprintf(stderr,"Sendto Error:%sna",strerror(errno));
return(0);
}
parse = (Ether_pkg *)buffer;
while(1)
{
memset(buffer,0,sizeof(buffer));
recvfrom(sockfd,buffer,sizeof(buffer),0,NULL,&len);
if( (ntohs(parse->ether_type) ==ETHERTYPE_ARP) &&
(ntohs(parse->ar_op) == ARPOP_REPLY))
{
parse_ether_package(parse);
break;
}
}
return(0);
}
|
1.你可以首先ping这个机器,然后执行arp就可以看到这台机器的mac地址
2。自己按照arp协议发送和接收一个包(可以参考TCP-IP详解卷1:协议一书的第四章)
欢迎访问我的个人网址 www.linuxc.net
|
上面代码太繁琐了.其实在LINUX下得到局域网内IP对应的MAC地址很简单.
只要把socket 设置为原始 socket,把网卡设为混杂模式. 然后再向局域网发送广播包(IP为255.255.255.255) 就行了.(详细实现请看ARP协议)
(注: 这种方法不适合WINDOW下,因为WINDOW下的SOCKET不支持MAC层通讯!)