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]# 
  • 相关阅读:
    FEniCS 1.1.0 发布,计算算术模型
    Piwik 1.10 发布,增加社交网站统计
    淘宝褚霸谈做技术的心态
    CyanogenMod 10.1 M1 发布
    Druid 发布 0.2.11 版本,数据库连接池
    GNU Gatekeeper 3.2 发布
    Phalcon 0.9.0 BETA版本发布,新增大量功能
    EUGene 2.6.1 发布,UML 模型操作工具
    CVSps 3.10 发布,CVS 资料库更改收集
    Opera 移动版将采用 WebKit 引擎
  • 原文地址:https://www.cnblogs.com/zengjianrong/p/4185424.html
Copyright © 2011-2022 走看看