[c] How to get MAC address of your machine using a C program?

I am working on Ubuntu. How can I get MAC address of my machine or an interface say eth0 using C program.

This question is related to c linux mac-address

The answer is


A very portable way is to parse the output of this command.

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

Provided ifconfig can be run as the current user (usually can) and awk is installed (it often is). This will give you the mac address of the machine.


Much nicer than all this socket or shell madness is simply using sysfs for this:

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/.


This is a Bash line that prints all available mac addresses, except the loopback:

for x in `ls /sys/class/net |grep -v lo`; do cat /sys/class/net/$x/address; done

Can be executed from a C program.


Assuming that c++ code (c++11) is okay as well and the interface is known.

#include <cstdint>
#include <fstream>
#include <streambuf>
#include <regex>

using namespace std;

uint64_t getIFMAC(const string &ifname) {
  ifstream iface("/sys/class/net/" + ifname + "/address");
  string str((istreambuf_iterator<char>(iface)), istreambuf_iterator<char>());
  if (str.length() > 0) {
    string hex = regex_replace(str, std::regex(":"), "");
    return stoull(hex, 0, 16);
  } else {
    return 0;
  }
} 
int main()
{
  string iface = "eth0";
  printf("%s: mac=%016llX\n", iface.c_str(), getIFMAC(iface));
}

You want to take a look at the getifaddrs(3) manual page. There is an example in C in the manpage itself that you can use. You want to get the address with the type AF_LINK.


Expanding on the answer given by @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/c-c-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;
}

netlink socket is possible

man netlink(7) netlink(3) rtnetlink(7) rtnetlink(3)

#include <assert.h>
#include <stdio.h>
#include <linux/if.h>
#include <linux/rtnetlink.h>
#include <unistd.h>

#define SZ 8192

int main(){

  // Send
  typedef struct {
    struct nlmsghdr nh;
    struct ifinfomsg ifi;
  } Req_getlink;
  assert(NLMSG_LENGTH(sizeof(struct ifinfomsg))==sizeof(Req_getlink));
  int fd=-1;
  fd=socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
  assert(0==bind(fd,(struct sockaddr*)(&(struct sockaddr_nl){
    .nl_family=AF_NETLINK,
    .nl_pad=0,
    .nl_pid=getpid(),
    .nl_groups=0
  }),sizeof(struct sockaddr_nl)));
  assert(sizeof(Req_getlink)==send(fd,&(Req_getlink){
    .nh={
      .nlmsg_len=NLMSG_LENGTH(sizeof(struct ifinfomsg)),
      .nlmsg_type=RTM_GETLINK,
      .nlmsg_flags=NLM_F_REQUEST|NLM_F_ROOT,
      .nlmsg_seq=0,
      .nlmsg_pid=0
    },
    .ifi={
      .ifi_family=AF_UNSPEC,
      // .ifi_family=AF_INET,
      .ifi_type=0,
      .ifi_index=0,
      .ifi_flags=0,
      .ifi_change=0,
    }
  },sizeof(Req_getlink),0));

  // Receive
  char recvbuf[SZ]={};
  int len=0;
  for(char *p=recvbuf;;){
    const int seglen=recv(fd,p,sizeof(recvbuf)-len,0);
    assert(seglen>=1);
    len += seglen;
    if(((struct nlmsghdr*)p)->nlmsg_type==NLMSG_DONE||((struct nlmsghdr*)p)->nlmsg_type==NLMSG_ERROR)
      break;
    p += seglen;
  }

  struct nlmsghdr *nh=(struct nlmsghdr*)recvbuf;
  for(;NLMSG_OK(nh,len);nh=NLMSG_NEXT(nh,len)){
    if(nh->nlmsg_type==NLMSG_DONE)
      break;

    struct ifinfomsg *ifm=(struct ifinfomsg*)NLMSG_DATA(nh);

    printf("#%d ",ifm->ifi_index);
    #ifdef _NET_IF_H
    #pragma GCC error "include <linux/if.h> instead of <net/if.h>"
    #endif

    // Part 3 rtattr
    struct rtattr *rta=IFLA_RTA(ifm); // /usr/include/linux/if_link.h
    int rtl=RTM_PAYLOAD(nh);

    for(;RTA_OK(rta,rtl);rta=RTA_NEXT(rta,rtl))switch(rta->rta_type){
    case IFLA_IFNAME:printf("%s ",(const char*)RTA_DATA(rta));break;
    case IFLA_ADDRESS:
      printf("hwaddr ");
      for(int i=0;i<5;++i)
        printf("%02X:",*((unsigned char*)RTA_DATA(rta)+i));
      printf("%02X ",*((unsigned char*)RTA_DATA(rta)+5));
      break;
    case IFLA_BROADCAST:
      printf("bcast ");
      for(int i=0;i<5;++i)
        printf("%02X:",*((unsigned char*)RTA_DATA(rta)+i));
      printf("%02X ",*((unsigned char*)RTA_DATA(rta)+5));
      break;
    case IFLA_PERM_ADDRESS:
      printf("perm ");
      for(int i=0;i<5;++i)
        printf("%02X:",*((unsigned char*)RTA_DATA(rta)+i));
      printf("%02X ",*((unsigned char*)RTA_DATA(rta)+5));
      break;
    }

    printf("\n");

  }

  close(fd);
  fd=-1;
  return 0;

}

Example

#1 lo hwaddr 00:00:00:00:00:00 bcast 00:00:00:00:00:00
#2 eth0 hwaddr 57:da:52:45:5b:1a bcast ff:ff:ff:ff:ff:ff perm 57:da:52:45:5b:1a
#3 wlan0 hwaddr 3c:7f:46:47:58:c2 bcast ff:ff:ff:ff:ff:ff perm 3c:7f:46:47:58:c2

I have just write one and test it on gentoo in virtualbox.

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

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

  1. On Linux, use the service of "Network Manager" over the DBus.

  2. There is also good'ol shell program which can be invoke and the result grabbed (use an exec function under C):

$ /sbin/ifconfig | grep HWaddr


Using getifaddrs you can get MAC address from the family AF_PACKET.

In order to display the MAC address to each interface, you can proceed like this:

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

Ideone


Examples related to c

conflicting types for 'outchar' Can't compile C program on a Mac after upgrade to Mojave Program to find largest and second largest number in array Prime numbers between 1 to 100 in C Programming Language In c, in bool, true == 1 and false == 0? How I can print to stderr in C? Visual Studio Code includePath "error: assignment to expression with array type error" when I assign a struct field (C) Compiling an application for use in highly radioactive environments How can you print multiple variables inside a string using printf?

Examples related to linux

grep's at sign caught as whitespace How to prevent Google Colab from disconnecting? "E: Unable to locate package python-pip" on Ubuntu 18.04 How to upgrade Python version to 3.7? Install Qt on Ubuntu Get first line of a shell command's output Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running? Run bash command on jenkins pipeline How to uninstall an older PHP version from centOS7 How to update-alternatives to Python 3 without breaking apt?

Examples related to mac-address

Get MAC address using shell script Programmatically getting the MAC of an Android device How to get MAC address of your machine using a C program? How can I get the MAC and the IP address of a connected client in PHP? Reliable method to get machine's MAC address in C# How can I programmatically get the MAC address of an iphone MAC addresses in JavaScript