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

我正在Ubuntu上工作。 我怎么能得到我的机器的MAC地址或接口说eth0使用C程序。

您需要迭代计算机上所有可用的接口,并使用带有SIOCGIFHWADDR标志的ioctl来获取mac地址。 MAC地址将以6个八位字节的二进制数组forms获得。 您还想跳过回送界面。

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

比所有这个套接字或shell疯狂好多是简单地使用sysfs为此:

fopen() / fscanf() / fclose()可以读取文件/sys/class/net/eth0/address作为简单的string。 没有比这更容易的了。

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

你想看看getifaddrs(3)手册页。 您可以使用manpage中的C语言中的一个示例。 您想要获得types为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; } 

我只写了一个,在virtualbox的gentoo上testing。

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

使用getifadd你可以从家庭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; } 
  1. 在Linux上,通过DBus使用“networkingpipe理器”服务。

  2. 还有好的 shell程序可以调用,并且抓取结果(在C下使用exec函数):

$ /sbin/ifconfig | grep HWaddr

一个非常便携的方法是parsing这个命令的输出。

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

提供的ifconfig可以像当前用户(通常可以)那样运行,并且安装了awk(通常是)。 这会给你机器的MAC地址。

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