首页 文章

如何使用C程序获取机器的MAC地址?

提问于
浏览
62

我正在研究Ubuntu . 如何使用C程序获取我的机器的MAC地址或接口说eth0 .

11 回答

  • 2

    您需要迭代计算机上的所有可用接口,并使用 ioctlSIOCGIFHWADDR 标志来获取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);
    }
    
  • 8

    比所有这个套接字或shell疯狂更好的只是使用sysfs:

    文件 /sys/class/net/eth0/address 将您的mac地址作为简单字符串,您可以使用 fopen() / fscanf() / fclose() 读取 . 没有比这更容易的了 .

    如果你想支持除eth0之外的其他网络接口(你可能想要),那么只需在 /sys/class/net/ 上使用 opendir() / readdir() / closedir() .

  • -1

    您想看一下getifaddrs(3)手册页 . 在您可以使用的联机帮助页中的C中有一个示例 . 您想获取类型 AF_LINK 的地址 .

  • 1
    #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;
    }
    
  • 125

    我刚刚写了一个并在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;
    }
    
  • 7

    使用getifaddrs,您可以从家庭 AF_PACKET 获取MAC地址 .

    为了显示每个接口的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

    假设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));
    }
    
  • 24
    • 在Linux上,使用DBus上的“网络管理器”服务 .

    • 还有一个好的shell程序可以调用并抓取结果(在C下使用exec函数):

    $ /sbin/ifconfig | grep HWaddr

  • 0

    一种非常便携的方法是解析此命令的输出 .

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

    提供ifconfig可以作为当前用户(通常可以)和awk安装(通常是)运行 . 这将为您提供机器的mac地址 .

  • 51

    这是一个Bash行,它打印除loopback之外的所有可用mac地址:

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

    可以从C程序执行 .

  • 17

    扩展@ 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;
    }
    

相关问题