2012-08-13 2 views
1

내 서버에 대한 모든 요청 인 클라이언트 MAC 주소를 캡처하고 싶습니다. 다음 프로그램을 사용하여 클라이언트의 MAC 주소를 얻지 만 "ioctl : Protocol Family Not Supported"를 표시합니다. 얻으려면 어떻게 MAC 주소? .. 당신은 로컬 서브넷의 MAC 주소를 얻을 수 ioctl(SIOCGARP)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 주소 만 가져올 수 있습니까? –

+0

다른 네트워크에있는 클라이언트 MAC을 얻고 싶습니다. 아니면 어디서나 ... 어떻게 얻을 수 있습니까? ... – user1216216

+2

정말, 할 수 없습니다. 유일한 확실한 방법은 사용 된 프로토콜이 서버의 쿼리를 포함하여 클라이언트에게 자체 MAC 주소를 제공하도록 요청하는 것입니다. –

답변

1

을 SIOCGARP 로컬 ARP 테이블에서 MAC 주소를 반환하기 때문이다.

SIOCGARP 약간 잘못된 방법입니다. SIOCGARP의 인수는 입출력 유형입니다. 따라서 을 호출하기 전에 arpreq_ 필드를 채워야합니다. man page을 참조하십시오.

피어가 이더넷 서브넷을 벗어나면 트래픽은 라우터를 통해 전달되고 피어는 이더넷 네트워크에있을 수 있습니다 (예 : 휴대 전화). 따라서 모든 피어로부터 이더넷 MAC 주소를 얻는 것은 불가능할 수 있습니다.

피어와 통신하는 호스트는 첫 번째 라우터의 MAC 주소가 사용됩니다.

0

나는 원하는대로 할 수있는 코드가 있습니다.

저는 네트워크의 원격 컴퓨터에서 MAC 주소를 얻을 수있는 C++ 코드를 얻으려고했습니다. 이것을 이해하는 데 꽤 많은 시간이 걸렸습니다. 몇 가지 예제를 병합하여 작업 데모로 수정했습니다. Socket 연결로 작동하도록 수정하는 것은 매우 쉽습니다.

이 코드는 네트워크 장치와 IP 주소를 인수로 사용합니다. (예 : eth0 192.168.1.1)

프로그램이 IP의 정확성을 검사 한 다음 IP 주소를 ping하여 ARP 테이블에 추가 한 다음 ARP 테이블에서 MAC 주소를 추출한 다음 MAC 주소가 표시됩니다.

저는 C++ 코더가 아닙니다 (또는 적어도 newb입니다) 코드가 닦여 졌을 수 있습니다.

이 코드는 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; 
} 
관련 문제