2012-08-13 199 views
1

我想捕获所有请求我的服务器的客户端MAC地址。我使用以下程序获取客户端的MAC地址,但显示“ioctl:协议族不支持”。如何获取MAC地址?..如何使用ioctl函数获取客户端的MAC地址?

#include<stdio.h> 
#include<sys/socket.h> 
#include<sys/types.h> 
#include<netinet/in.h> 
#include<netdb.h> 
#include<errno.h> 
#include<string.h> 
#include<netinet/if_ether.h> 
#include<net/if.h> 
#include<linux/sockios.h> 
int main() 
{ 
    int socket1, socket2; 
    socket1 = 0; 
    socket2 = 0; 
    struct sockaddr_in server, client; 
    int returnstatus = 0; 
socket1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
if(socket1 == -1) 
{ 
    perror("socket()"); 
} 

server.sin_family = AF_INET; 
server.sin_addr.s_addr = INADDR_ANY; 
server.sin_port = htons(8888); 
returnstatus = bind(socket1, (struct sockaddr*)&server, sizeof(server)); 
if(returnstatus == -1) 
{ 
    perror("bind()"); 
} 
returnstatus = listen(socket1, 5); 
if(returnstatus == -1) 
{ 
perror("listen()"); 
} 
for(;;) 
{ 
    int buffr[4]; 
    int addrlen, n; 
    addrlen = sizeof(client); 
    socket2 = accept(socket1, (struct sockaddr *)&client, &addrlen); 
    printf("%s\n",inet_ntoa(client.sin_addr)); 
    printf("%d\n",(int) ntohs(client.sin_port)); 
struct arpreq arpreq_; 
bzero(&arpreq_, sizeof(struct arpreq)); 

if((n = ioctl(socket2, SIOCGARP, &arpreq_)) < 0){ 
perror("ioctl"); 
} 

unsigned char *ptr = &arpreq_.arp_ha.sa_data[0]; 
printf("MAC: %x:%x:%x:%x:%x:%x\n", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), 
*(ptr+4), *(ptr+5)); 

if (socket2 == -1) 
{ 
    perror("accept()"); 
} 
returnstatus = read(socket2, buffr, sizeof(buffr)); 

if(returnstatus == -1) 
{ 
    perror("read()"); 
} 
int c[2]; 
int *w; 
c[0] = buffr[0] + buffr[1]; 
w = c; 
returnstatus = write(socket2, w, sizeof(c)); 
if(returnstatus == -1) 
{ 
perror("write()"); 
} 
close(socket2); 

} 
close(socket1); 
return 0; 
} 

int addition(int x, int y) 
{ 
int z; 
z = x + y; 
return(z); 
} 
+1

如果客户端位于另一个网络或甚至另一个子网上,该怎么办?那么你不是只能得到关闭路由器的MAC地址吗? – 2012-08-13 07:09:04

+0

我想要得到另一个网络中的客户端MAC,甚至在世界任何地方......我怎样才能得到它?.. – user1216216 2012-08-13 07:11:52

+2

你不能,真的。唯一可行的方法是使所使用的协议包括来自服务器的查询以请求客户端提供其自己的MAC地址。 – 2012-08-13 07:31:09

回答

1

随着ioctl(SIOCGARP)你可能会得到本地子网的唯一MAC地址,因为SIOCGARP将从本地的ARP表中返回的MAC地址。

您正在使用SIOCGARP一点点错误的方式。 SIOCGARP的论点是一种投入产出类型。因此,在致电ioctl之前,您必须填写arpreq_的一些字段。 见man page

当对等设备不在以太网子网中时,流量将通过路由器传输,对等设备可能位于以太网或不在(例如:手机)。所以从每个对等体获得以太网MAC地址是不可能的。

当你主机与对等体通信时,使用第一个路由器的MAC地址。

0

我有一些代码似乎做你想做的。

我一直在试图获得一些C++代码,它将从我的网络上的远程计算机获取MAC地址。花了相当长的时间才弄明白这一点。我设法将几个示例合并并修改为一个工作演示。修改这个以使用Socket连接应该很容易。

这段代码将网络设备和IP地址作为参数。 (例如192.168.1.1的eth0)

程序将检查IP的正确性,则它将ping IP地址将其添加到ARP表中,那么它会提取从ARP表中的MAC地址,那么它将显示MAC地址。

我不是一个C++编码器(或者至少我是一个新手),所以代码可能会被刷新。

此代码仅在Raspbian上进行过测试!

#include <errno.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <sys/ioctl.h> 
#include <net/if_arp.h> 
#include <arpa/inet.h> 
#include <sstream> 


bool isValidIpAddress(char *ipAddress) { 
    int result = 0; 
    struct sockaddr_in sa; 
    result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr)); 
    return result; 
} 

/** 
* @brief Convert String to Number 
*/ 
template <typename TP> 
TP str2num(std::string const& value){ 
    std::stringstream sin; 
    sin << value; 
    TP output; 
    sin >> output; 
    return output; 
} 

/** 
* @brief Convert number to string 
*/ 
template <typename TP> 
std::string num2str(TP const& value){ 
    std::stringstream sin; 
    sin << value; 
    return sin.str(); 
} 

/** 
* @brief Execute Generic Shell Command 
* 
* @param[in] command Command to execute. 
* @param[out] output Shell output. 
* @param[in] mode read/write access 
* 
* @return 0 for success, 1 otherwise. 
* 
*/ 
int Execute_Command(const std::string& command, 
    std::string& output, 
    const std::string& mode = "r") { 

    // Create the stringstream 
    std::stringstream sout; 

    // Run Popen 
    FILE *in; 
    char buff[512]; 

    // Test output 
    if(!(in = popen(command.c_str(), mode.c_str()))){ 
     return 1; 
    } 

    // Parse output 
    while(fgets(buff, sizeof(buff), in)!=NULL){ 
     sout << buff; 
    } 

    // Close 
    int exit_code = pclose(in); 

    // set output 
    output = sout.str(); 

    // Return exit code 
    return exit_code; 
} 

/** 
* @brief Ping 
* 
* @param[in] address Address to ping. 
* @param[in] max_attempts Number of attempts to try and ping. 
* @param[out] details Details of failure if one occurs. 
* 
* @return True if responsive, false otherwise. 
* 
* @note { I am redirecting stderr to stdout. I would recommend 
*   capturing this information separately.} 
*/ 
bool Ping(const std::string& address) { 
    // Format a command string 
    std::string command = "ping -c " + num2str(2) + " " + address + " 2>&1"; 
    std::string output; 
    std::string details; 

    // Execute the ping command 
    int code = Execute_Command(command, details); 
    return (code == 0); 
} 


static char *ethernet_mactoa(struct sockaddr *addr) { 
    static char buff[256]; 
    unsigned char *ptr = (unsigned char *) addr->sa_data; 

    sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", 
     (ptr[0] & 0xff), (ptr[1] & 0xff), (ptr[2] & 0xff), 
     (ptr[3] & 0xff), (ptr[4] & 0xff), (ptr[5] & 0xff)); 

    return (buff); 
} 


int main(int argc, char *argv[]) { 
    int s; 
    struct arpreq areq; 
    struct sockaddr_in *sin; 
    struct in_addr ipaddr; 

    if (argc != 3) { 
     fprintf(stderr, "-- Usage: %s device ipaddress\n", argv[0]); 
     exit(1); 
    } 

    /* Get an internet domain socket. */ 
    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 
     perror("socket"); 
     exit(1); 
    } 


    if (!isValidIpAddress(argv[2])) { 
     fprintf(stderr, "-- Error: invalid IP Address '%s'.\n", 
      argv[2]); 
     exit(1); 
    } 

    if (inet_aton(argv[2], &ipaddr) == 0) { 
     fprintf(stderr, "-- Error: bad dotted-decimal IP '%s'.\n", 
      argv[2]); 
     exit(1); 
    } 

    /* Ping the Address for ARP table listing */ 

    if (!Ping(argv[2])) { 
     fprintf(stderr, "-- Error: unable to ping IP '%s'.\n", 
      argv[2]); 
     exit(1); 
    } 

    /* Make the ARP request. */ 
    memset(&areq, 0, sizeof(areq)); 
    sin = (struct sockaddr_in *) &areq.arp_pa; 
    sin->sin_family = AF_INET; 

    sin->sin_addr = ipaddr; 
    sin = (struct sockaddr_in *) &areq.arp_ha; 
    sin->sin_family = ARPHRD_ETHER; 

    strncpy(areq.arp_dev, argv[1], 15); 

    if (ioctl(s, SIOCGARP, (caddr_t) &areq) == -1) { 
     perror("-- Error: unable to make ARP request, error"); 
     exit(1); 
    } 

    printf("%s -> %s\n", 
    inet_ntoa(((struct sockaddr_in *) &areq.arp_pa)->sin_addr), 
    ethernet_mactoa(&areq.arp_ha)); 

    return 0; 
} 
相关问题