Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Having a problem figuring out how to get Ethernet interface info on Mac OS X using ioctl/SIOCGIFADDR/SIOCGIFCONF?

Are you having a problem figuring out how to get interface info on Mac OS X using ioctl/SIOCGIFADDR/SIOCGIFCONF?

I had a lot of trouble getting code that worked fine on Linux to work on Mac OS X today.

like image 665
Mark Avatar asked Oct 19 '10 00:10

Mark


People also ask

How do I find Network interface on MAC?

Mac OS X 10.9 or laterClick on the Apple icon in the top left, and click on System Preferences, or open System Preferences from your Dock. In the System Preferences window, click on Network. In the resulting network window, there will be network interfaces listed on the left.

How do I read Ifconfig files on MAC?

Locate and open Terminal from Applications->Utilities->Terminal. At the Terminal Prompt, type ifconfig and press Enter. This will list all of your network settings, including the physical addresses of your wired and wireless hardware. Write down or copy/paste the addresses into a document for future reference.

What is Siocgifaddr?

SIOCGIFADDR. Get the interface address for the given interface. argp shall point to a ifreq structure. Before calling, the caller should fill in the ifr_name field with the interface name, and upon return, the ifr_ifru. ifru_addr field is set with the interface address.

How do I find my MAC address Linux C?

the file /sys/class/net/eth0/address carries your mac adress as simple string you can read with fopen() / fscanf() / fclose() . Nothing easier than that. 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/ .


2 Answers

Copy-paste to main.c and gcc main.c && ./a.out should work (lists all network interfaces, their ipv4/6 address, netmask and MAC address if associated):

Works fine on Mac OSX and 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;
  }
}
like image 171
Mirek Rusin Avatar answered Sep 21 '22 16:09

Mirek Rusin


The mechanism to get MAC addresses is entirely different on BSD-derived OSes than on Linux. This includes OS X.

Here's code I use that works on Linux and OS X, and probably on the BSDs, too:

#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

It's up to you to work out how to get the right HAVE_* macro defined for the platform. I happen to use autoconf for this, but you may have another way of dealing with platform differences.

Notice that the default interface name parameter for these functions is the default for the first Ethernet interface on Linux and OS X boxes. You may need to override this for other OSes, or pass another value if you're interested in the MAC address for a different interface.

like image 38
Warren Young Avatar answered Sep 24 '22 16:09

Warren Young