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

Bru*_*uce 65 c linux mac-address

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

use*_*104 127

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

该文件/sys/class/net/eth0/address携带的MAC地址作为简单的字符串,你可以读fopen()/ fscanf()/ fclose().没有比这更容易的了.

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

  • @CharlesSalvia打开并读取系统文件似乎仍然是一个C解决方案......只要你知道你的目标系统提供了什么!当然,您的程序将与该类型的系统绑定.但只是编译程序将其与系统架构联系起来.我认为这个答案对许多(但不是全部)情况都有帮助. (8认同)
  • 答案很好,但不适用于所有情况.例如嵌入式系统(特别是旧版本,例如busybox的旧版本,没有sysfs也无法支持它,因为系统本身可能太旧了) (3认同)
  • 这个问题特别要求C解决方案 (3认同)

Cha*_*via 54

您需要迭代计算机上的所有可用接口,并使用ioctlwith SIOCGIFHWADDRflag来获取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);
}
Run Code Online (Sandbox Code Playgroud)

  • 也许接近(袜子)? (5认同)
  • 只有在eth0上有链接时才有效.如果拔下网络电缆(在Ubuntu上),它将无法工作. (2认同)

Jul*_*ano 24

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

  • 在链接的 getifaddrs 联机帮助页中,未描述类型“AF_LINK”。也许这被`AF_PACKET`取代? (2认同)
  • 根据/sf/answers/1822695101/,似乎AF_LINK是macOS / BSD特定的,而AF_PACKET是Linux的等效物。 (2认同)

Emp*_*ian 19

#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;
}
Run Code Online (Sandbox Code Playgroud)

  • 在代码末尾添加close(fd) (2认同)
  • 不要忘记错误检查 socket() 并在套接字打开成功时关闭它。 (2认同)

mpr*_*net 10

使用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;
}
Run Code Online (Sandbox Code Playgroud)


小智 9

我刚刚写了一个并在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;
}
Run Code Online (Sandbox Code Playgroud)


Lin*_*oln 5

假设 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=%016llX\n", iface.c_str(), getIFMAC(iface));
}
Run Code Online (Sandbox Code Playgroud)