2009-11-22 2 views

답변

49

컴퓨터에서 사용 가능한 모든 인터페이스를 반복해야하고 플래그를 사용하여 ioctl 플래그를 사용하여 MAC 주소를 가져와야합니다. mac 주소는 6 옥텟 이진 배열로 얻어집니다. 또한 루프백 인터페이스를 건너 뛰기를 원할 수도 있습니다.

#include <sys/ioctl.h> 
#include <net/if.h> 
#include <unistd.h> 
#include <netinet/in.h> 
#include <string.h> 

int main() 
{ 
    struct ifreq ifr; 
    struct ifconf ifc; 
    char buf[1024]; 
    int success = 0; 

    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 
    if (sock == -1) { /* handle error*/ }; 

    ifc.ifc_len = sizeof(buf); 
    ifc.ifc_buf = buf; 
    if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) { /* handle error */ } 

    struct ifreq* it = ifc.ifc_req; 
    const struct ifreq* const end = it + (ifc.ifc_len/sizeof(struct ifreq)); 

    for (; it != end; ++it) { 
     strcpy(ifr.ifr_name, it->ifr_name); 
     if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) { 
      if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback 
       if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) { 
        success = 1; 
        break; 
       } 
      } 
     } 
     else { /* handle error */ } 
    } 

    unsigned char mac_address[6]; 

    if (success) memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6); 
} 
+1

ifreq 및 ifconf가 앞에 struct가 필요하지 않은 이유는 무엇입니까? 이 구조체에 대한 typedef가 더 최근의 커널에서 제거 되었는가? 이것이 작성되었을 때인 2009 년에 존재 했는가? –

+0

@Karl, 고치세요. –

+0

OpenVZ 컨테이너에는 MAC 주소가 없으므로 이러한 솔루션 중 어느 것도 작동하지 않는다는 점에 유의해야한다고 생각합니다. MAC 주소는 "00 : 00 : 00 : 00 : 00 : 00"으로 가정합니다. – ub3rst4r

1
  1. Linux의 경우 DBus를 통해 "네트워크 관리자"서비스를 사용하십시오.

  2. 호출 할 수 good'ol 쉘 프로그램도있다 결과는 (C 아래 간부 기능 사용) 잡고 :

$ /sbin/ifconfig | grep HWaddr

21

당신이 먹고 싶어를 getifaddrs(3) 매뉴얼 페이지를보십시오. C에서 맨 페이지 자체에 사용할 수있는 예제가 있습니다. 주소가 AF_LINK 인 주소를 받으려고합니다.

+1

에 의해 주어진 대답에 확장 'AF_LINK'유형이 연결되어 있지 않습니다. 아마 이것은 AF_PACKET으로 대체 될 것인가? – mpromonet

-1

매우 유용한 방법은이 명령의 출력을 구문 분석하는 것입니다.

ifconfig | awk '$0 ~ /HWaddr/ { print $5 }' 

제공 ifconfig는 현재 사용자 (대개 can)로 실행할 수 있으며 awk가 설치되어 있습니다 (종종 있습니다). 이렇게하면 기계의 MAC 주소를 알 수 있습니다.

+2

전혀 휴대 할 수 없습니다. Mac OS X에서는 아무것도 제공하지 않습니다.'ifconfig'의 출력에는'HWaddr'라는 텍스트가 없습니다. – dreamlax

+7

매우 휴대가 편리합니다. 우분투 및 쿠분투에서 실행됩니다. ;-) – EricSchaefer

+0

solaris, linux 및 hpux에서 올해 초에이 작업을 수행해야했습니다. – Matt

17
#include <sys/socket.h> 
#include <sys/ioctl.h> 
#include <linux/if.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <string.h> 

int main() 
{ 
    struct ifreq s; 
    int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 

    strcpy(s.ifr_name, "eth0"); 
    if (0 == ioctl(fd, SIOCGIFHWADDR, &s)) { 
    int i; 
    for (i = 0; i < 6; ++i) 
     printf(" %02x", (unsigned char) s.ifr_addr.sa_data[i]); 
    puts("\n"); 
    return 0; 
    } 
    return 1; 
} 
+1

코드 끝에 닫기 (fd)를 추가하십시오 – SLdraogn

116

이 모든 소켓 또는 쉘 광기보다 훨씬 더 좋은 단순히 이것에 대한 sysfs를 사용하고 : 당신의 MAC 주소를 전달 /sys/class/net/eth0/address

파일을 간단 문자열이 fopen()/fscanf()/fclose()로 읽을 수 있습니다. 그보다 더 쉬운 것은 없습니다.

그리고 당신은 eth0를보다 다른 네트워크 인터페이스를 지원하려는 (그리고 당신은 아마 할) 경우, 단순히 /sys/class/net/opendir()/readdir()/closedir()를 사용합니다.

+3

+1 유용한 답변 –

+3

좋은 답변이지만 모든 상황에 적용 할 수는 없습니다. 예 : 임베디드 시스템 (이전 버전의 busybox와 같이 특히 시스템 자체가 너무 오래되어서 sysfs가 없거나 지원할 수 있음) –

+3

질문에 C 솔루션을 특별히 요구했습니다. –

8

나는 단지 하나를 작성하고 가상 박스의 젠투에서 테스트했다.

// get_mac.c 
#include <stdio.h> //printf 
#include <string.h> //strncpy 
#include <sys/socket.h> 
#include <sys/ioctl.h> 
#include <net/if.h> //ifreq 
#include <unistd.h> //close 

int main() 
{ 
    int fd; 
    struct ifreq ifr; 
    char *iface = "enp0s3"; 
    unsigned char *mac = NULL; 

    memset(&ifr, 0, sizeof(ifr)); 

    fd = socket(AF_INET, SOCK_DGRAM, 0); 

    ifr.ifr_addr.sa_family = AF_INET; 
    strncpy(ifr.ifr_name , iface , IFNAMSIZ-1); 

    if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr)) { 
     mac = (unsigned char *)ifr.ifr_hwaddr.sa_data; 

     //display mac address 
     printf("Mac : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n" , mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 
    } 

    close(fd); 

    return 0; 
} 
3

당신이 가족 AF_PACKET에서 MAC 주소를 얻을 수 getifaddrs 사용.

각 인터페이스의 MAC 주소를 표시하기 위해, 당신은 다음과 같이 진행할 수 :

#include <stdio.h> 
#include <ifaddrs.h> 
#include <netpacket/packet.h> 

int main (int argc, const char * argv[]) 
{ 
    struct ifaddrs *ifaddr=NULL; 
    struct ifaddrs *ifa = NULL; 
    int i = 0; 

    if (getifaddrs(&ifaddr) == -1) 
    { 
     perror("getifaddrs"); 
    } 
    else 
    { 
     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 
     { 
      if ((ifa->ifa_addr) && (ifa->ifa_addr->sa_family == AF_PACKET)) 
      { 
        struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr; 
        printf("%-8s ", ifa->ifa_name); 
        for (i=0; i <s->sll_halen; i++) 
        { 
         printf("%02x%c", (s->sll_addr[i]), (i+1!=s->sll_halen)?':':'\n'); 
        } 
      } 
     } 
     freeifaddrs(ifaddr); 
    } 
    return 0; 
} 
+0

실행 가능한 솔루션. –

0

을의 getifaddrs의 맨 페이지에서 @ user175104 ...

std::vector<std::string> GetAllFiles(const std::string& folder, bool recursive = false) 
{ 
    // uses opendir, readdir, and struct dirent. 
    // left as an exercise to the reader, as it isn't the point of this OP and answer. 
} 

bool ReadFileContents(const std::string& folder, const std::string& fname, std::string& contents) 
{ 
    // uses ifstream to read entire contents 
    // left as an exercise to the reader, as it isn't the point of this OP and answer. 
} 

std::vector<std::string> GetAllMacAddresses() 
{ 
    std::vector<std::string> macs; 
    std::string address; 

    // from: https://stackoverflow.com/questions/9034575/c-c-linux-mac-address-of-all-interfaces 
    // ... just read /sys/class/net/eth0/address 

    // NOTE: there may be more than one: /sys/class/net/*/address 
    // (1) so walk /sys/class/net/* to find the names to read the address of. 

    std::vector<std::string> nets = GetAllFiles("/sys/class/net/", false); 
    for (auto it = nets.begin(); it != nets.end(); ++it) 
    { 
    // we don't care about the local loopback interface 
    if (0 == strcmp((*it).substr(-3).c_str(), "/lo")) 
     continue; 
    address.clear(); 
    if (ReadFileContents(*it, "address", address)) 
    { 
     if (!address.empty()) 
     { 
     macs.push_back(address); 
     } 
    } 
    } 
    return macs; 
} 
관련 문제