UFO ET IT

C 프로그램을 사용하여 컴퓨터의 MAC 주소를 얻는 방법은 무엇입니까?

ufoet 2020. 11. 15. 12:09
반응형

C 프로그램을 사용하여 컴퓨터의 MAC 주소를 얻는 방법은 무엇입니까?


저는 우분투에서 일하고 있습니다. 내 컴퓨터의 MAC 주소 또는 C 프로그램을 사용하여 eth0이라는 인터페이스를 어떻게 얻을 수 있습니까?


컴퓨터에서 사용 가능한 모든 인터페이스를 반복 ioctl하고 SIOCGIFHWADDR플래그 와 함께 사용 하여 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);
}

이 모든 소켓 또는 셸 광기보다 훨씬 좋은 것은 단순히 sysfs를 사용하는 것입니다.

파일 /sys/class/net/eth0/addressfopen()/ fscanf()/로 읽을 수있는 간단한 문자열로 Mac 주소를 전달합니다 fclose(). 그보다 쉬운 것은 없습니다.

그리고 eth0 이외의 다른 네트워크 인터페이스를 지원하고 싶다면 (그리고 아마도 원할 것입니다) opendir()/ readdir()/ closedir()on을 사용하십시오 /sys/class/net/.


getifaddrs (3) 매뉴얼 페이지를 보고 싶습니다 . 맨 페이지 자체에 사용할 수있는 C의 예가 있습니다. 유형으로 주소를 얻고 싶습니다 AF_LINK.


#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;
}

getifaddrs사용 하면 제품군에서 MAC 주소를 얻을 수 있습니다 AF_PACKET.

각 인터페이스에 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;
}

Ideone


하나를 작성하고 virtualbox의 gentoo에서 테스트했습니다.

// 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;
}

C ++ 코드 (c ++ 11)도 괜찮고 인터페이스가 알려져 있다고 가정합니다.

#include <cstdint>
#include <fstream>
#include <streambuf>
#include <regex>

using namespace std;

uint64_t getIFMAC(const string &ifname) {
  ifstream iface("/sys/class/net/"+ifname+"/address");
  string str((istreambuf_iterator<char>(iface)), istreambuf_iterator<char>());
  if (str.length() > 0) {
    string hex = regex_replace(str, std::regex(":"), "");
    return stoull(hex, 0, 16);
  } else {
    return 0;
  }
} 
int main()
{
  string iface="eth0";
  printf("%s: mac=%016lX\n", iface.c_str(), getIFMAC(iface));
}

  1. Linux에서는 DBus를 통해 "Network Manager"서비스를 사용하십시오.

  2. 도있다 good'ol (AN 사용하여 호출 될 수있는 쉘 프로그램 결과는 잡고 간부 C 하에서 기능) :

$ /sbin/ifconfig | grep HWaddr


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

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

Provided ifconfig can be run as the current user (usually can) and awk is installed (it often is). This will give you the mac address of the machine.


This is a Bash line that prints all available mac addresses, except the loopback:

for x in `ls /sys/class/net |grep -v lo`; do cat /sys/class/net/$x/address; done

Can be executed from a C program.


Expanding on the answer given by @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;
}

참고URL : https://stackoverflow.com/questions/1779715/how-to-get-mac-address-of-your-machine-using-a-c-program

반응형