Determine MAC Address – UDID Alternative

Mon, Nov 7

The MAC (Media Access Control) address is an identifier that is associated with a network adapter and uniquely identifies a device on a network. A MAC address consists of 12 hexadecimal numbers, typically formatted as follows

XX:XX:XX:YY:YY:YY

The XX values in a MAC address identify the manufacturer, the YY values are the serial number assigned to the network adapter.

The MAC address can be useful if you need a way to uniquely identify a device – this can be used as a substitute for the UDID value that is now deprecated in iOS 5 and greater.

The code below shows how to get the MAC address on an iOS device:

#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
 
...
 
- (NSString *)getMacAddress
{
  int                 mgmtInfoBase[6];
  char                *msgBuffer = NULL;
  size_t              length;
  unsigned char       macAddress[6];
  struct if_msghdr    *interfaceMsgStruct;
  struct sockaddr_dl  *socketStruct;
  NSString            *errorFlag = NULL;
 
  // Setup the management Information Base (mib)
  mgmtInfoBase[0] = CTL_NET;        // Request network subsystem
  mgmtInfoBase[1] = AF_ROUTE;       // Routing table info
  mgmtInfoBase[2] = 0;              
  mgmtInfoBase[3] = AF_LINK;        // Request link layer information
  mgmtInfoBase[4] = NET_RT_IFLIST;  // Request all configured interfaces
 
  // With all configured interfaces requested, get handle index
  if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0) 
    errorFlag = @"if_nametoindex failure";
  else
  {
    // Get the size of the data available (store in len)
    if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0) 
      errorFlag = @"sysctl mgmtInfoBase failure";
    else
    {
      // Alloc memory based on above call
      if ((msgBuffer = malloc(length)) == NULL)
        errorFlag = @"buffer allocation failure";
      else
      {
        // Get system information, store in buffer
        if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
          errorFlag = @"sysctl msgBuffer failure";
      }
    }
  }
 
  // Befor going any further...
  if (errorFlag != NULL)
  {
    NSLog(@"Error: %@", errorFlag);
    return errorFlag;
  }
 
  // Map msgbuffer to interface message structure
  interfaceMsgStruct = (struct if_msghdr *) msgBuffer;
 
  // Map to link-level socket structure
  socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);
 
  // Copy link layer address data in socket structure to an array
  memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);
 
  // Read from char array into a string object, into traditional Mac address format
  NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                                macAddress[0], macAddress[1], macAddress[2], 
                                macAddress[3], macAddress[4], macAddress[5]];
  NSLog(@"Mac Address: %@", macAddressString);
 
  // Release the buffer memory
  free(msgBuffer);
 
  return macAddressString;
}

The output will look as follows: Mac Address: E0:F8:47:C0:E3:C9

18 comments

Great tip, but, will Apple aprove an application that uses this code?

by Marcos on Nov 7, 2011. Reply #

All the code is based on available (public) API’s, so there should be no issues with app approval.

by John Muchow on Nov 7, 2011. Reply #

What headers does one need to import to compile this for iOS?

by Jeff Kelley on Nov 7, 2011. Reply #

Good call Jeff, I forgot to include the header files, I’ve updated the example above.

by John Muchow on Nov 7, 2011. Reply #

Can this be isolated under a cocoa touch static library?

which frameworks are needed in order to use the static lib under another project?

by david on Nov 8, 2011. Reply #

I have not tried the code in a library, I would imagine this would work fine…

by John Muchow on Nov 9, 2011. Reply #

Beautiful … almost cried after seeing pure C code after such a long time … oh the good old memcpy malloc/free … the classics. Thanks :)

by Devang Kamdar on Nov 9, 2011. Reply #

Hi John,

What libraries do you need to link against for this? From a quick grep, it seems like libresolve.dylib and/or perhaps system/libsystem_info.dylib or system/libsystem_network.dylib?

by Jeffrey Stedfast on Nov 9, 2011. Reply #

Hi Jeffrey, I didn’t link any additional libraries/frameworks in my test project, only UIKit and Foundation.

by John Muchow on Nov 9, 2011. Reply #

It needs more than UIKit and Foundation. That might be enough if you are building a project inside Xcode, (i.e. it probably links against other libs that you aren’t aware of) but it definitely needs more when building/linking manually outside of Xcode :-(

by Jeffrey Stedfast on Nov 9, 2011. Reply #

Not sure how to determine which libs are included in the build. I’ve looked at the binary, however, nothing obvious stands out. Interesting question, how to determine which libs are included in a build?

by John Muchow on Nov 9, 2011. Reply #

There is i a potential memory leak in case errorFlag = @”sysctl msgBuffer failure”, as msgBuffer will not be released…

You should add it for example before the ‘return errorFlag’, like in the code below:

if (errorFlag != NULL)
{
NSLog(@”Error: %@”, errorFlag);
if ( msgBuffer ) free(msgBuffer);
return errorFlag;
}

by Daniel Morais on Nov 14, 2011. Reply #

Made a slight change to prevent the warning with Xcode:
https://gist.github.com/1409855/

by Cœur on Dec 7, 2011. Reply #

Does it work to get Bluetooth MAC address also?

by Andrew on Jan 6, 2012. Reply #

thank’s!!!! 100% good.

by samuel on Jun 18, 2012. Reply #

This is much better than the official UUID approach, just wondering if Apple will deprecate this one sooner or later…Anyway, thanks for sharing!

by K-Res on Jun 26, 2012. Reply #

Great great! Works perfectly. Great thanks to you!!!!!…by the way, i love pure C :D

by Cordess on Sep 5, 2012. Reply #

Thanks! Just what I needed

by Sam on Oct 4, 2012. Reply #

Leave a Comment