想知道如何使用ioctl / SIOCGIFADDR / SIOCGIFCONF获取Mac OS X上的以太网接口信息?

您是否遇到了一个问题,弄清楚如何使用ioctl / SIOCGIFADDR / SIOCGIFCONF获取Mac OS X上的界面信息?

我遇到了很多麻烦,使得在Linux上运行良好的代码能够在Mac OS X上运行。

复制粘贴到main.cgcc main.c && ./a.out应该工作(列出所有网络接口,它们的ipv4 / 6地址,网络掩码和MAC地址,如果关联的话):

Mac OSXiOS iPad / iPhone上运行良好

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <net/if.h> #include <net/if_dl.h> #include <ifaddrs.h> #include <errno.h> int main() { struct ifaddrs *if_addrs = NULL; struct ifaddrs *if_addr = NULL; void *tmp = NULL; char buf[INET6_ADDRSTRLEN]; if (0 == getifaddrs(&if_addrs)) { for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next) { printf("name : %s\n", if_addr->ifa_name); // Address if (if_addr->ifa_addr->sa_family == AF_INET) { tmp = &((struct sockaddr_in *)if_addr->ifa_addr)->sin_addr; } else { tmp = &((struct sockaddr_in6 *)if_addr->ifa_addr)->sin6_addr; } printf("addr : %s\n", inet_ntop(if_addr->ifa_addr->sa_family, tmp, buf, sizeof(buf))); // Mask if (if_addr->ifa_netmask != NULL) { if (if_addr->ifa_netmask->sa_family == AF_INET) { tmp = &((struct sockaddr_in *)if_addr->ifa_netmask)->sin_addr; } else { tmp = &((struct sockaddr_in6 *)if_addr->ifa_netmask)->sin6_addr; } printf("mask : %s\n", inet_ntop(if_addr->ifa_netmask->sa_family, tmp, buf, sizeof(buf))); } // MAC address if (if_addr->ifa_addr != NULL && if_addr->ifa_addr->sa_family == AF_LINK) { struct sockaddr_dl* sdl = (struct sockaddr_dl *)if_addr->ifa_addr; unsigned char mac[6]; if (6 == sdl->sdl_alen) { memcpy(mac, LLADDR(sdl), sdl->sdl_alen); printf("mac : %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } } printf("\n"); } freeifaddrs(if_addrs); if_addrs = NULL; } else { printf("getifaddrs() failed with errno = %i %s\n", errno, strerror(errno)); return -1; } } 

获取MAC地址的机制在基于BSD的操作系统上完全不同于Linux。 这包括OS X.

这里是我使用的代码,在Linux和OS X上,也可能在BSD上:

 #if defined(HAVE_SIOCGIFHWADDR) bool get_mac_address(char* mac_addr, const char* if_name = "eth0") { struct ifreq ifinfo; strcpy(ifinfo.ifr_name, if_name); int sd = socket(AF_INET, SOCK_DGRAM, 0); int result = ioctl(sd, SIOCGIFHWADDR, &ifinfo); close(sd); if ((result == 0) && (ifinfo.ifr_hwaddr.sa_family == 1)) { memcpy(mac_addr, ifinfo.ifr_hwaddr.sa_data, IFHWADDRLEN); return true; } else { return false; } } #elif defined(HAVE_GETIFADDRS) bool get_mac_address(char* mac_addr, const char* if_name = "en0") { ifaddrs* iflist; bool found = false; if (getifaddrs(&iflist) == 0) { for (ifaddrs* cur = iflist; cur; cur = cur->ifa_next) { if ((cur->ifa_addr->sa_family == AF_LINK) && (strcmp(cur->ifa_name, if_name) == 0) && cur->ifa_addr) { sockaddr_dl* sdl = (sockaddr_dl*)cur->ifa_addr; memcpy(mac_addr, LLADDR(sdl), sdl->sdl_alen); found = true; break; } } freeifaddrs(iflist); } return found; } #else # error no definition for get_mac_address() on this platform! #endif 

由您决定如何获得为平台定义的正确的HAVE_*宏。 我碰巧使用了autoconf,但是你可能有另一种处理平台差异的方法。

请注意,这些功能的默认接口名称参数是Linux和OS X机箱上第一个以太网接口的默认接口名称。 您可能需要为其他操作系统覆盖此值,或者如果您对不同接口的MAC地址感兴趣,则可以传递另一个值。

这个线程有点匹配我的问题:

http://discussions.apple.com/thread.jspa?messageID=10935410&tstart=0

这个线程帮了很多:

https://lists.isc.org/pipermail/dhcp-hackers/2007-September/000767.html

因为该线程最终提到应该使用getifaddrs()。 在Ubuntu 10.04上的手册页有一个很好的例子,说明如何使用getifaddrs并将其用作参考,帮助我找出在Mac和Linux上都可用的代码。 我不希望别人把时间浪费在这么简单的事情上,所以我在这里发帖回答。 希望我的文章可以帮助你…