Не можете понять, как получить информацию об интерфейсе Ethernet в Mac OS X, используя ioctl / SIOCGIFADDR / SIOCGIFCONF? - PullRequest
5 голосов
/ 19 октября 2010

У вас есть проблема с выяснением того, как получить информацию об интерфейсе в Mac OS X с помощью ioctl / SIOCGIFADDR / SIOCGIFCONF?

У меня было много проблем с получением кода, который отлично работал в Linux для работы в Mac OSХ сегодня.

Ответы [ 3 ]

11 голосов
/ 24 ноября 2010

Копирование-вставка в main.c и gcc main.c && ./a.out должно работать (перечислены все сетевые интерфейсы, их IPv4 / 6-адрес, маска сети и MAC-адрес , если они связаны):

Работает нормальнона Mac OSX и iOS 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;
  }
}
8 голосов
/ 20 октября 2010

Механизм получения 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, но у вас может быть другой способ справиться с различиями платформ.

Обратите внимание, что параметр имени интерфейса по умолчанию для этих функций является значением по умолчанию для первого интерфейса Ethernet в Linux и OS X,Возможно, вам придется переопределить это для других ОС или передать другое значение, если вас интересует MAC-адрес для другого интерфейса.

2 голосов
/ 19 октября 2010

Эта тема несколько совпала с моей проблемой:

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

Эта тема очень помогла:

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

потому что этот поток в конечном итоге упоминает, что вместо него следует использовать getifaddrs (). На man-странице Ubuntu 10.04 был отличный пример того, как использовать getifaddrs, и использование его в качестве справки помогло мне разобраться в коде, который работал как на Mac, так и на Linux. Я не хочу, чтобы кто-то еще тратил время на что-то настолько простое, поэтому я пишу и отвечаю себе здесь. Надеюсь, что мой пост поможет вам ...

...