通过ip获取mac地址

发表于: 2013年01月02 00:00

这里是通过ARP协议获取局域网中指定ip地址的对应的硬件地址

大概流程如下

1.这里通过socket创建原始套节字,需要root权限

2.自己构建一个arp请求的数据包

3.发送这个数据包,接受arp回应包,处理数据

构建arp数据包时需要本地的ip及硬件地址。这个在上篇文章有介绍这里为了简单,直接指定了本地的ip和mac

发送的包,arp部分长度只有28.所以还要有18字节填充,否则发送不了这个数据包

程序运行时需要指定两个参数分别是:目标ip和网卡

例如

:::bash
./a.out 192.168.1.103 eth0

:::cpp
/************************************************
 * arp发包,接受包的简单实现
 * 实现功能:通过ip地址获取以太网中对应机器的mac地址
 * http://fluyy.net
 ************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
#include<netdb.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<net/if_arp.h>
#include<net/ethernet.h>
#include<netpacket/packet.h>
#include<netinet/in.h>
#include<net/if.h>
#include<getopt.h>
#include<sys/ioctl.h>
//SRCIP 发送端的ip地址
#define SRCIP "192.168.1.101"
//SRCMAC 发送端的MAC地址
#define SRCMAC "\x34\xc9\xa9\x5b\x47\x9d"
//广播
#define MAC "\xff\xff\xff\xff\xff\xff"
#define INLEN 4
#define BUFLEN 100
int creakpkg(ARPADDR *src,ARPADDR *dst,ARPPKG *parp,int type);
typedef struct arp_addr
{
    u_char mac[ETH_ALEN];
    struct in_addr addr;
}ARPADDR;
typedef struct arppkg
{
     u_char edst_mac[ETH_ALEN];
     u_char esrc_mac[ETH_ALEN];
     u_short eth_type;
     u_short ar_hrd;//硬件类型
     u_short ar_pro;//协议类型
     u_char  ar_hln;//硬件地址长度
     u_char  ar_pln;//协议地址长度
     u_short ar_op;//ARP操作类型
     u_char ar_srcmac[ETH_ALEN];
     u_char ar_srcip[INLEN];
     u_char ar_dstmac[ETH_ALEN];
     u_char ar_dstip[INLEN];
     u_char padding[18];
}ARPPKG;
int main(int argc,char **args)
{
    ARPADDR src,dst;
    if(inet_aton(args[1],&(dst.addr))==0)
    {
        perror("inet_aton:");
        exit(0);
    }
    if(inet_aton(SRCIP,&(src.addr))==0)
    {
        perror("inet_aton:");
        exit(0);
    }
    memcpy(dst.mac,MAC,ETH_ALEN);
    memcpy(src.mac,SRCMAC,ETH_ALEN);
    arpwork(&src,&dst,args[2]);
}

void showmac(u_char *buf)
{
    //输出硬件地址
    printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
}
int arpwork(struct arp_addr *src,struct arp_addr *dst,char *dev)
{
    int pkgsize;
    int recsize;
    int sendsize;
    u_char recv_buf[BUFLEN];
    int sockfd=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ARP));//创建原始套节字
    if(sockfd==-1)
    {
        perror("socket");
        exit(0);
    }
    else
    {
        struct arphdr parp;                                                 
        struct sockaddr_ll dstaddr,srcaddr;
        ARPPKG buf;
        int alen;
        memset(&srcaddr,0,sizeof(srcaddr));
        srcaddr.sll_family=PF_PACKET;                                           
        srcaddr.sll_ifindex=if_nametoindex(dev);
        if(srcaddr.sll_ifindex==0)
        {
            perror("if_nametoindex");
            exit(0);
        }
        pkgsize=sizeof(ARPPKG);
        creakpkg(src,dst,&buf,ARPOP_REQUEST);
        sendsize=sendto(sockfd,&buf,pkgsize,0,(struct sockaddr *)&srcaddr,sizeof(srcaddr));//发送这个包
        if(sendsize<=0)
        {
            perror("send");
            exit(0);
        }
        memset(recv_buf,0,sizeof(recv_buf));
        memset(&dstaddr,0,sizeof(dstaddr));
        alen=sizeof(dstaddr);
        while(1)
        {
            recsize=recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&dstaddr,&alen);
            if(recsize<=0)
            {
                perror("send");
                exit(0);
            }
            if(memcmp(&(dst->addr),&recv_buf[28],INLEN)==0)
            {
                showmac(recv_buf+22);
                break;  
            }
        }
        close(sockfd);
    }
    return 0;
}
//填充一个包
int creakpkg(ARPADDR *src,ARPADDR *dst,ARPPKG *parp,int type)
{
    memcpy(parp->edst_mac,dst->mac,ETH_ALEN);//目标硬件地址
    memcpy(parp->esrc_mac,src->mac,ETH_ALEN);//源硬件地址
    parp->eth_type=htons(ETHERTYPE_ARP);
    parp->ar_hrd=htons(ARPHRD_ETHER);//硬件类型
    parp->ar_pro=htons(ETHERTYPE_IP);//协议类型
    parp->ar_hln=ETH_ALEN;//硬件地址长度
    parp->ar_pln=INLEN;//协议地址长度
    parp->ar_op=htons(ARPOP_REQUEST);//ARP操作类型
    memcpy(parp->ar_srcmac,src->mac,ETH_ALEN); //发送者的硬件地址                                   
    memcpy(parp->ar_srcip,&src->addr,INLEN);//发送者的协议地址
    memcpy(parp->ar_dstmac,dst->mac,ETH_ALEN); //目标的硬件地址
    memcpy(parp->ar_dstip,&(dst->addr),INLEN); //目标协议地址
}
© 2018 - fluyy - 粤ICP备17114935号