zoukankan      html  css  js  c++  java
  • 通过IP获取MAC地址例子(应用层)

      博客地址:http://home.cnblogs.com/u/zengjianrong/

      由于某种需求,需要获取某个ip的mac地址,在应用层实现例子如下代码。

      流程:1. 先遍历arp表,若存在对应mac地址,则取出并结束。否则继续。

         2. 构造arp包,发arp request,若收不到arp reply,则返回失败并结束。否则继续。

         3. 解析arp reply包,获取MAC,并将ip、mac信息存到内核的arp表。

    #include <errno.h>
    #include <net/if_arp.h>
    #include <netinet/if_ether.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/ioctl.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <time.h>
    #include <unistd.h>
    
    #define MAC_BCAST_ADDR        (unsigned char *)"xffxffxffxffxffxff"
    #define LOCAL_MAC_ADDR        (unsigned char *)"x00x50x56xCCx99x0E"
    #define LOCAL_DEV           (unsigned char *)"eth0"
    
    #ifndef  ATF_FORCE_ADD
    #define ATF_FORCE_ADD    0x80        /* force to add an entry    --add by zengjianrong */
    #endif
    
    
    typedef unsigned int        u_int32_t;
    typedef unsigned int        u_int;
    
    #ifdef ZJR_READ  /* just for reading */
    typedef unsigned short    sa_family_t; 
    struct sockaddr {
        sa_family_t    sa_family;    /* address family, AF_xxx    */
        char        sa_data[14];    /* 14 bytes of protocol address    */
    };
    struct sockaddr_in 
    {
        sa_family_t        sin_family;    /* Address family        */
        __be16            sin_port;    /* Port number            */
        struct in_addr    sin_addr;    /* Internet address        */
    
        /* Pad to size of `struct sockaddr'. */
        unsigned char    __pad[__SOCK_SIZE__ - sizeof(short int) -
                sizeof(unsigned short int) - sizeof(struct in_addr)];
    };
    struct arpreq 
    {
        struct sockaddr    arp_pa;        /* protocol address        */
        struct sockaddr    arp_ha;        /* hardware address        */
        int            arp_flags;    /* flags            */
        struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
        char            arp_dev[16];
    };
    #endif
    
    #define SYSTEM_ERROR    1
    #define PROCESS_PRINT   0
    #define DEBUGGING_LVL   0
    #define DEBUGGING
    
    #ifdef DEBUGGING
    #define DEBUG(lvl, ...)
        do
        {
            if (lvl >= DEBUGGING_LVL)
            {
                printf("[DEBUG] in %s:%d %s(), ",
                    __FILE__, __LINE__, __FUNCTION__);
                printf(__VA_ARGS__);
                printf("
    ");
            }
        } while(0)
    #else
    #define DEBUG(lvl, ...) do {} while(0)
    #endif 
    
    typedef enum
    {
        ARP_TBL_BEGIN = 1,
        ARP_TBL_GET,
        ARP_TBL_SET,
        ARP_TBL_DEL,
        ARP_TBL_END,
    }ARP_TBL_TRL_ENUM;
    
    struct arpMsg 
    {
        struct ethhdr ethhdr;           /* Ethernet header */
        u_short htype;              /* hardware type (must be ARPHRD_ETHER) */
        u_short ptype;              /* protocol type (must be ETH_P_IP) */
        u_char  hlen;               /* hardware address length (must be 6) */
        u_char  plen;               /* protocol address length (must be 4) */
        u_short operation;          /* ARP opcode */
        u_char  sHaddr[6];          /* sender's hardware address */
        u_char  sInaddr[4];         /* sender's IP address */
        u_char  tHaddr[6];          /* target's hardware address */
        u_char  tInaddr[4];         /* target's IP address */
        u_char  pad[18];            /* pad for min. Ethernet payload (60 bytes) */
    };
    
    static int fd_arp_tbl = -1;
    
    /******************************************************************************
     * nSendArp - send arp, get mac from arp reply if have
     * DESCRIPTION: -  
     * Input:       unRemoteIp  - remote ip
     *              unLocalIp   - our ip
     *              pucLocalMac - our mac address
     *              pchEth      - interface to use
     * Output:      pstArp      - arp info
     * Returns:     1           - addr free
     *              0           - addr used, get mac ok
     *              -1          - error 
     * 
     * modification history
     * --------------------
     * 2.00, 2014-12-25 , zengjianrong written
     * --------------------
     ******************************************************************************/
    int nSendArp(u_int32_t unRemoteIp, u_int32_t unLocalIp, unsigned char *pucLocalMac, char *pchEth, struct arpMsg *pstArp)
    {
        int     nTimeOut = 2;
        int     nOptVal = 1;
        int     nSk = -1;         /* socket */
        int     nRtVal = 1;         /* return value */
        fd_set  fdset;
        time_t  prevTime;
        struct sockaddr addr;   /* for interface name */
        struct timeval  tm;
    
        if (-1 == (nSk=socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)))) 
        {
            DEBUG(SYSTEM_ERROR, "func->socket error(%d:%s).", errno, strerror(errno));
            return -1;
        }
    
        if (-1 == setsockopt(nSk, SOL_SOCKET, SO_BROADCAST, &nOptVal, sizeof(nOptVal))) 
        {        
            DEBUG(SYSTEM_ERROR, "func->setsocketopt error(%d:%s).", errno, strerror(errno));
            close(nSk);
            return -1;
        }
    
        /* make a arp request */
        memset(pstArp, 0, sizeof(struct arpMsg));
        memcpy(pstArp->ethhdr.h_dest, MAC_BCAST_ADDR, 6);  /* MAC DA */
        memcpy(pstArp->ethhdr.h_source, pucLocalMac, 6);               /* MAC SA */
        pstArp->ethhdr.h_proto = htons(ETH_P_ARP);             /* protocol type (Ethernet) */
        pstArp->htype = htons(ARPHRD_ETHER);                   /* hardware type */
        pstArp->ptype = htons(ETH_P_IP);                       /* protocol type (ARP message) */
        pstArp->hlen = 6;                                      /* hardware address length */
        pstArp->plen = 4;                                      /* protocol address length */
        pstArp->operation = htons(ARPOP_REQUEST);              /* ARP op code */
        *((u_int *) pstArp->sInaddr) = unLocalIp;                     /* source IP address */
        memcpy(pstArp->sHaddr, pucLocalMac, 6);                        /* source hardware address */
        //*((u_int *) pstArp->tInaddr) = unRemoteIp;         
        memcpy(pstArp->tInaddr, (unsigned char *)&unRemoteIp, sizeof(pstArp->tInaddr));/* target IP address */    
        memset(&addr, 0, sizeof(addr));
        strcpy(addr.sa_data, pchEth);
        
        /* send arp request */
        if (0 > sendto(nSk, pstArp, sizeof(struct arpMsg), 0, &addr, sizeof(addr)))
        {
            DEBUG(SYSTEM_ERROR, "func->sendto error(%d:%s).", errno, strerror(errno));
            close(nSk);
            return -1;
        }
    
        /* wait arp reply, and check it */
        tm.tv_usec = 0;
        time(&prevTime);
        while (nTimeOut > 0)
        {
            FD_ZERO(&fdset);
            FD_SET(nSk, &fdset);
            tm.tv_sec = nTimeOut;
            if (select(nSk + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0)
            {
                DEBUG(SYSTEM_ERROR, "func->select error(%d:%s).", errno, strerror(errno));
                if (errno != EINTR)
                {
                    nRtVal = 0;
                }
            }
            else if (FD_ISSET(nSk, &fdset))
            {
                if (recv(nSk, pstArp, sizeof(struct arpMsg), 0) < 0 )
                {
                    nRtVal = 0;
                }
                if (pstArp->operation == htons(ARPOP_REPLY) && 
                    bcmp(pstArp->tHaddr, pucLocalMac, 6) == 0 && 
                    *((u_int *) pstArp->sInaddr) == unRemoteIp)
                {
                    //DEBUG(PROCESS_PRINT, "valid arp reply receved for this address.");
                    nRtVal = 0;
                    break;
                }
            }
            nTimeOut -= time(NULL) - prevTime;
            time(&prevTime);
        }
        close(nSk);
        DEBUG(PROCESS_PRINT, "%salid arp replies for this address", nRtVal ? "no v" : "v");  
        return nRtVal;
    }           
    
    /******************************************************************************
     * nArpTblCtl - get/set/del ip<->mac info 
     * DESCRIPTION: -  
     * Input: 
     * Output: 
     * Returns: 
     * 
     * modification history
     * --------------------
     * 2.00, 2014-12-25 , zengjianrong written
     * --------------------
     ******************************************************************************/
    int nArpTblCtl(ARP_TBL_TRL_ENUM cmd, struct in_addr stRemoteIp, char *pcDevName, unsigned char *pucMac)
    {
        unsigned int        unCmd = 0;
        unsigned char       *pucHwAddr = NULL;
        struct sockaddr_in  *pSin = NULL;
        struct arpreq       stArpreq;
        
        if ((0 == stRemoteIp.s_addr)
            || (cmd <= ARP_TBL_BEGIN)
            || (cmd >= ARP_TBL_END)
            || (ARP_TBL_DEL != cmd && NULL == pucMac))
        {
            DEBUG(SYSTEM_ERROR, "param error.");
            return -1;
        }
        
        memset(&stArpreq, 0, sizeof(struct arpreq));
        switch (cmd)
        {
            case ARP_TBL_GET:
                unCmd = SIOCGARP;
                break;
            case ARP_TBL_DEL:
                stArpreq.arp_ha.sa_family = AF_UNSPEC;
                unCmd = SIOCDARP;
                break;
            case ARP_TBL_SET:
                stArpreq.arp_ha.sa_family = AF_UNSPEC;
                //stArpreq.arp_flags = ATF_PERM | ATF_PUBL | ATF_FORCE_ADD;
                stArpreq.arp_flags = ATF_COM;
                memcpy((char *)stArpreq.arp_ha.sa_data, pucMac, 6);
                unCmd = SIOCSARP;
                break;
            default:
                return -1;
        }
    
        if (-1 == fd_arp_tbl)
        {
            fd_arp_tbl = socket(AF_INET, SOCK_DGRAM, 0);
            if (fd_arp_tbl < 0)
            {
                DEBUG(SYSTEM_ERROR, "func->socket error(%d:%s).", errno, strerror(errno));
                return -1;
            }
        }
        
        pSin = (struct sockaddr_in *) &stArpreq.arp_pa;
        pSin->sin_family = AF_INET;
        memcpy(&(pSin->sin_addr), &stRemoteIp, sizeof(struct in_addr));
        strcpy(stArpreq.arp_dev, pcDevName);
    
        if (0 > ioctl(fd_arp_tbl, unCmd, &stArpreq))
        {
            DEBUG(SYSTEM_ERROR, "func->ioctl error(%d:%s).", errno, strerror(errno));
            close(fd_arp_tbl);
            fd_arp_tbl = -1;
            return -1;
        }
        else if (ARP_TBL_GET == cmd)
        {        
            pucHwAddr = (unsigned char *) stArpreq.arp_ha.sa_data;
            memcpy(pucMac, pucHwAddr, 6);
            if (0 == pucMac[0] && 0 == pucMac[1] && 0 == pucMac[2] 
                && 0== pucMac[3] && 0 == pucMac[4] && 0 == pucMac[5])
            {
                return -1;
            }
        }
        
        return 0;
    }
    
    
    int main(int argc, char *argv[])
    {
        unsigned char       aucMac[6];
        struct in_addr      sin_remote_addr;
        struct in_addr      sin_local_addr;
        struct arpMsg       stArpMsg;
    
        memset(&sin_local_addr, 0, sizeof(struct in_addr));
        memset(&stArpMsg, 0, sizeof(struct arpMsg));
        memset(aucMac, 0, 6);
    
        if (argc!=2) 
        {
            DEBUG(SYSTEM_ERROR, "usage: %s <IP address>
    ",argv[0]);
            return -1;
        }
    
        /* initial global values */
        fd_arp_tbl = -1;
    
        if (0 == (inet_aton("138.0.225.226", &sin_local_addr))) 
        {
            DEBUG(SYSTEM_ERROR, "func->inet_aton error(%d:%s).", errno, strerror(errno));
            return -1;
        }
        
        if (0 == (inet_aton(argv[1], &sin_remote_addr))) 
        {
            DEBUG(SYSTEM_ERROR, "func->inet_aton error(%d:%s), '%s' not valid.", 
                errno, strerror(errno), argv[1]);
            return -1;
        }
    
        if (0 > (nArpTblCtl(ARP_TBL_GET, sin_remote_addr, LOCAL_DEV, aucMac)))
        {
            DEBUG(PROCESS_PRINT, "no entry in arp_cache for '%s', send arp request.", argv[1]);
            if (0 != (nSendArp(sin_remote_addr.s_addr, sin_local_addr.s_addr, 
                              LOCAL_MAC_ADDR, LOCAL_DEV, &stArpMsg)))
            {   
                DEBUG(SYSTEM_ERROR, "there is no device using '%s', or nSendArp error.", argv[1]);
                return -1;
            }
            else
            {
                if (0 > (nArpTblCtl(ARP_TBL_SET, sin_remote_addr, LOCAL_DEV, stArpMsg.sHaddr)))
                {
                    DEBUG(SYSTEM_ERROR, "func->nArpTblCtl set error.");
                    return -1;
                }
                if (0 > (nArpTblCtl(ARP_TBL_GET, sin_remote_addr, LOCAL_DEV, aucMac)))
                {
                    DEBUG(PROCESS_PRINT, "there is no device using '%s'.", argv[1]);
                    return 0;
                }
            }
        }
        DEBUG(PROCESS_PRINT, "%s-->%02x:%02x:%02x:%02x:%02x:%02x.", argv[1], 
            aucMac[0], aucMac[1], aucMac[2], aucMac[3], aucMac[4], aucMac[5]);  
        
        return 0;
    }

      测试结果如下:

    [root@zeng test]# ifconfig 
    eth0      Link encap:Ethernet  HWaddr 00:50:56:CC:99:0E  
              inet addr:138.0.225.226  Bcast:138.0.255.255  Mask:255.255.0.0
              inet6 addr: fe80::250:56ff:fecc:990e/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:2314211 errors:0 dropped:0 overruns:0 frame:0
              TX packets:13648 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:161772378 (154.2 MiB)  TX bytes:18844506 (17.9 MiB)
              Interrupt:67 Base address:0x2024 
    
    eth1      Link encap:Ethernet  HWaddr 00:50:56:DE:99:0E  
              inet addr:192.168.123.225  Bcast:192.168.123.255  Mask:255.255.255.0
              inet6 addr: fe80::250:56ff:fede:990e/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:32187 errors:0 dropped:0 overruns:0 frame:0
              TX packets:21581 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:2529373 (2.4 MiB)  TX bytes:1040688 (1016.2 KiB)
              Interrupt:75 Base address:0x20a4 
    
    eth2      Link encap:Ethernet  HWaddr 00:50:56:DC:99:0E  
              inet addr:192.168.213.225  Bcast:192.168.213.255  Mask:255.255.255.0
              inet6 addr: fe80::250:56ff:fedc:990e/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:1658819 errors:0 dropped:0 overruns:0 frame:0
              TX packets:1976333 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:340738638 (324.9 MiB)  TX bytes:1445346752 (1.3 GiB)
              Interrupt:75 Base address:0x2424 
    
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              inet6 addr: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:16436  Metric:1
              RX packets:840 errors:0 dropped:0 overruns:0 frame:0
              TX packets:840 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:56072 (54.7 KiB)  TX bytes:56072 (54.7 KiB)
    
    [root@zeng test]# ./getMacFromIp.o 138.0.0.90
    [DEBUG] in /mnt/hgfs/source_code_20140312/test/2getMacFromIp.c:278 nArpTblCtl(), func->ioctl error(6:No such device or address).
    [DEBUG] in /mnt/hgfs/source_code_20140312/test/2getMacFromIp.c:333 main(), no entry in arp_cache for '138.0.0.90', send arp request.
    [DEBUG] in /mnt/hgfs/source_code_20140312/test/2getMacFromIp.c:220 nSendArp(), valid arp replies for this address
    [DEBUG] in /mnt/hgfs/source_code_20140312/test/2getMacFromIp.c:355 main(), 138.0.0.90-->74:d4:35:49:5b:7c.
    [root@zeng test]# ./getMacFromIp.o 138.0.156.125
    [DEBUG] in /mnt/hgfs/source_code_20140312/test/2getMacFromIp.c:278 nArpTblCtl(), func->ioctl error(6:No such device or address).
    [DEBUG] in /mnt/hgfs/source_code_20140312/test/2getMacFromIp.c:333 main(), no entry in arp_cache for '138.0.156.125', send arp request.
    [DEBUG] in /mnt/hgfs/source_code_20140312/test/2getMacFromIp.c:220 nSendArp(), no valid arp replies for this address
    [DEBUG] in /mnt/hgfs/source_code_20140312/test/2getMacFromIp.c:337 main(), there is no device using '138.0.156.125', or nSendArp error.
    [root@zeng test]# 
  • 相关阅读:
    爬取阳光问政平台
    CrawlSpider爬取腾讯招聘信息
    LinkExtractor
    镜像源列表
    screen命令总结
    PHP解决中文乱码问题
    Linux查找大文件或目录
    CentOS6/7系列防火墙管理
    删除win10冗余的服务
    解决win10安装wireshark新版本,欢迎界面卡顿情况
  • 原文地址:https://www.cnblogs.com/zengjianrong/p/4185424.html
Copyright © 2011-2022 走看看