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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1779715/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:55:31  来源:igfitidea点击:

How to get MAC address of your machine using a C program?

clinuxmac-address

提问by Bruce

I am working on Ubuntu. How can I get MAC address of my machine or an interface say eth0 using C program.

我在 Ubuntu 上工作。如何使用 C 程序获取我的机器的 MAC 地址或接口说 eth0。

采纳答案by Charles Salvia

You need to iterate over all the available interfaces on your machine, and use ioctlwith SIOCGIFHWADDRflag to get the mac address. The mac address will be obtained as a 6-octet binary array. You also want to skip the loopback interface.

您需要遍历机器上所有可用的接口,并使用ioctlwithSIOCGIFHWADDR标志来获取 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);
}

回答by jldupont

  1. On Linux, use the service of "Network Manager" over the DBus.

  2. There is also good'olshell program which can be invoke and the result grabbed (use an execfunction under C):

  1. 在 Linux 上,通过 DBus 使用“网络管理器”服务。

  2. 还有good'olshell程序可以调用并获取结果(在C下使用exec函数):

$ /sbin/ifconfig | grep HWaddr

$ /sbin/ifconfig | grep HWaddr

回答by Juliano

You want to take a look at the getifaddrs(3)manual page. There is an example in C in the manpage itself that you can use. You want to get the address with the type AF_LINK.

您想查看getifaddrs(3)手册页。您可以使用联机帮助页中的 C 语言示例。您想获取类型为 的地址AF_LINK

回答by Matt

A very portable way is to parse the output of this command.

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

ifconfig | awk '
#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;
}
~ /HWaddr/ { print }'

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.

提供 ifconfig 可以作为当前用户运行(通常可以)并安装 awk(通常是)。这会给你机器的mac地址。

回答by Employed Russian

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

回答by user175104

Much nicer than all this socket or shell madness is simply using sysfs for this:

比所有这些 socket 或 shell 疯狂更好的是简单地使用 sysfs 来做到这一点:

the file /sys/class/net/eth0/addresscarries your mac adress as simple string you can read with fopen()/fscanf()/fclose(). Nothing easier than that.

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

And if you want to support other network interfaces than eth0 (and you probably want), then simply use opendir()/readdir()/closedir()on /sys/class/net/.

如果你想支持其他网络接口eth0的比(和你可能想),然后只需使用opendir()/ readdir()/closedir()/sys/class/net/

回答by Akagi201

I have just write one and test it on gentoo in virtualbox.

我刚刚写了一个并在virtualbox中的gentoo上测试它。

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

回答by mpromonet

Using getifaddrsyou can get MAC address from the family AF_PACKET.

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

In order to display the MAC address to each interface, you can proceed like this:

为了显示每个接口的 MAC 地址,您可以按以下步骤操作:

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

Ideone

艾德尼

回答by Jesse Chisholm

Expanding on the answer given by @user175104 ...

扩展@user175104 给出的答案......

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

回答by Lincoln

Assuming that c++ code (c++11) is ok as well and the interface is known.

假设 c++ 代码(c++11)也可以,并且接口是已知的。

##代码##