从IP地址查找MAC地址

时间:2009-07-09 15:32:47

标签: c++ c

我正在研究一个具有客户端 - 服务器架构的模块。我必须在MAC address的基础上验证连接的对等机器。

在安装时,我存储了有效MAC地址的加密列表。

请注意,我无法控制此对等计算机,并且某些第三方应用程序将在此运行,我无法在此对等计算机上安装任何应用程序。

在发生套接字连接的运行时,我需要知道连接中使用的IP地址的MAC地址,以便我可以根据以前存储的MAC地址对其进行验证。

是否有可用的C / C ++ API可以帮助我从IP地址获取MAC地址。这台机器通常连接在局域网中,但它可以位于不同的子网上。

我的模块是多平台的,可在Windows,Solaris和Linux上运行,类似地,对等机可以在任何操作系统上运行。

4 个答案:

答案 0 :(得分:8)

不幸的是,简单的答案实际上是“不要那样做”。

如果您的对等计算机位于不同的子网上(因此您和对等方之间的流量通过路由器),则无法执行您想要的操作 - 您收到的数据包的MAC地址将是转发给您的路由器的MAC地址,因为它是您正在与之通信的链路层设备。只有离对等机最近的路由器才能知道对等体的MAC地址是什么 - 并且该信息不会被传递。

如果对等计算机位于同一子网上,则传入的数据包将包含以太网报头中对等方的MAC地址...但在将数据包传送到您的应用程序之前,这将被剥离。您的选项几乎限于您正在侦听以获取整个数据包的网络接口上的数据包捕获,或者使用系统提供的任何工具来检查本地ARP表。这两个选项都非常依赖于平台!

此外,如果您正在处理的接口不是以太网接口(也许它们是PPP链接,或WiFi,或某种类型的时髦虚拟化接口,......),如果没有修改,这两个选项都不可能继续工作。 ),他们也不会使用IPv6。

如果毕竟还未确定,请查看libpcap / WinPCap进行数据包捕获,这是最容易想到的便携式选项。要检查本地ARP表,Linux,OS X,Solaris和Windows都提供arp命令行实用程序,但语法可能会有所不同。如果API可用,我不希望平台之间有任何共性 - 这种事情没有标准,因为你真的不应该这样做!

答案 1 :(得分:2)

这是不可能的。无法保证您的连接对等体甚至具有MAC地址。对等体完全有可能通过拨号(PPP)或其他非以太网接口连接到网络。

答案 2 :(得分:1)

不要通过MAC地址进行身份验证。很容易欺骗他们。使用HTTP身份验证库,如Chilkat

答案 3 :(得分:1)

正如mcandre所说,欺骗MAC地址非常容易,但仍然回答你的问题,如果你在同一个局域网上,我认为你可以通过BSD风格的套接字在所有操作系统上做到这一点:

以下是this forum post

的一些示例代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
    struct ifreq ifr;
    int sock, j, k;
    char *p, addr[32], mask[32], mac[32];

    if (argc<2) {
        fprintf(stderr,"missing argument, example: eth0\n");
        return 1;
    }

    sock=socket(PF_INET, SOCK_STREAM, 0);
    if (-1==sock) {
        perror("socket() ");
        return 1;
    }

    strncpy(ifr.ifr_name,argv[1],sizeof(ifr.ifr_name)-1);
    ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0';

    if (-1==ioctl(sock, SIOCGIFADDR, &ifr)) {
        perror("ioctl(SIOCGIFADDR) ");
        return 1;
    }
    p=inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr);
    strncpy(addr,p,sizeof(addr)-1);
    addr[sizeof(addr)-1]='\0';

    if (-1==ioctl(sock, SIOCGIFNETMASK, &ifr)) {
        perror("ioctl(SIOCGIFNETMASK) ");
            return 1;
        }
        p=inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_netmask))->sin_addr);
        strncpy(mask,p,sizeof(mask)-1);
        mask[sizeof(mask)-1]='\0';

        if (-1==ioctl(sock, SIOCGIFHWADDR, &ifr)) {
        perror("ioctl(SIOCGIFHWADDR) ");
        return 1;
    }
    for (j=0, k=0; j<6; j++) {
        k+=snprintf(mac+k, sizeof(mac)-k-1, j ? ":%02X" : "%02X",
            (int)(unsigned int)(unsigned char)ifr.ifr_hwaddr.sa_data[j]);
    }
    mac[sizeof(mac)-1]='\0';

    printf("\n");
    printf("name:    %s\n",ifr.ifr_name);
    printf("address: %s\n",addr);
    printf("netmask: %s\n",mask);
    printf("macaddr: %s\n",mac);
    printf("\n");

    close(sock);
    return 0;
}