FIELD NOTES: 書を持って街へ出よう

合同会社フィールドワークス プログラマ兼代表のブログ

LinuxとMac OS XでMACアドレスと取得する方法

実行マシンのMACアドレスを取得する必要があってやり方を探したのですが,意外と探すのに時間がかかりました。結果をここにまとめておきます。

やりたいこと

  • 実行マシンが持つネットワークカードの名称とMACアドレスを列挙したい。
  • LinuxMac OS Xの両方で動かしたい。
  • ifconfigなど外部コマンドを呼び出さずにAPIで実現したい。

Linux

ioctl(_, SIOCGIFCONF, _)でネットワーク・インターフェース情報の一覧を取得してから,個々のインターフェースに対して,ioctl (_, SIOCGIFHWADDR, _)でMACアドレスを取得します。

#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>

#define  MAX_IFS 20

int main()
{ 
    struct ifreq *ifr, *ifend;
    struct ifreq ifreq;
    struct ifconf ifc;
    struct ifreq ifs[MAX_IFS];
    int SockFD;
    unsigned char *addr;

    SockFD = socket(AF_INET, SOCK_DGRAM, 0);
    ifc.ifc_len = sizeof(ifs);
    ifc.ifc_req = ifs;
    if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) {
	return 1;
    }

    ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
    for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
	if (ifr->ifr_addr.sa_family == AF_INET) {
	    strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
	    if (ioctl (SockFD, SIOCGIFHWADDR, &ifreq) < 0) {
		return 1;
	    }
            addr = ifreq.ifr_hwaddr.sa_data;
            printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n",
                    ifreq.ifr_name,
                    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 
	}
    }
    return 0;
}

Mac版

getifaddrs()で,MACアドレスも含めたネットワーク・インターフェース情報の一覧を取得できます。BSD系のUnixであれば,同じ方法で取得できるはずです。

#include <stdio.h>
#include <string.h>
#include <ifaddrs.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>

int main()
{ 
    struct ifaddrs *ifa_list, *ifa; 
    struct sockaddr_dl *dl; 
    char name[12];
    unsigned char *addr;
    if (getifaddrs(&ifa_list) < 0) {
        return 1;
    }
    for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) { 
        dl = (struct sockaddr_dl*)ifa->ifa_addr; 
        if (dl->sdl_family == AF_LINK && dl->sdl_type == IFT_ETHER) {
            memcpy(name, dl->sdl_data, dl->sdl_nlen);
            name[dl->sdl_nlen] = '\0';
            addr = LLADDR(dl);
            printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n",
                    name,
                    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 
        }
    } 
    freeifaddrs(ifa_list); 
    return 0;
}