iOS - Get ARP table

BlackM picture BlackM · Jul 5, 2015 · Viewed 11.1k times · Source

I am trying to build a network scanner. I know the procedure so I want to ping all available hosts in the network and then get the ARP table so I can map the MAC address for each IP. I Googled for ARP table but I didn't find any guide how to implement this feature. I also found these similar questions on Stack overflow:

Link1

Link2

The answer are unclear on how to implement the ARP feature. Is there any official guide for this one? Is Apple approving the ARP table feature?

Answer

BlackM picture BlackM · Jul 6, 2015

UPDATE AFTER 10.2

Check the library here

I finally got it working so I will post the procedure in detail to save some time for other guys:

  1. Go to Applications and right click on Xcode -> Show package contents and browse to: Developer ▸ Platforms ▸ MacOSX.platform ▸ Developer ▸ SDKs ▸ MacOSX10.10.sdk ▸ usr ▸ include. From "net" folder copy the route.h and if_types.h and from the "netinet" folder copy the if_ether.h into your Xcode project.
  2. Then import the following .m and .h files:

MacFinder.h

#import <Foundation/Foundation.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sysctl.h>

#include <net/if.h>
#include <net/if_dl.h>
#include "if_types.h"

#if TARGET_IPHONE_SIMULATOR
#include <net/route.h>
#else
#include "route.h"
#endif

#include "if_ether.h"
#include <netinet/in.h>


#include <arpa/inet.h>

#include <err.h>
#include <errno.h>
#include <netdb.h>

#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

@interface MacFinder : NSObject{

    int nflag;
}

-(NSString*) ip2mac: (char*)ip;

@end

MacFinder.m

#import "MacFinder.h"

@implementation MacFinder
-(NSString*) ip2mac: (char*)ip
{
    int  found_entry = 0;



    NSString *mAddr = nil;
    u_long addr = inet_addr(ip);
    int mib[6];
    size_t needed;
    char *host, *lim, *buf, *next;
    struct rt_msghdr *rtm;
    struct sockaddr_inarp *sin;
    struct sockaddr_dl *sdl;
    extern int h_errno;
    struct hostent *hp;

    mib[0] = CTL_NET;
    mib[1] = PF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_INET;
    mib[4] = NET_RT_FLAGS;
    mib[5] = RTF_LLINFO;
    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
        err(1, "route-sysctl-estimate");
    if ((buf = malloc(needed)) == NULL)
        err(1, "malloc");
    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
        err(1, "actual retrieval of routing table");


    lim = buf + needed;
    for (next = buf; next < lim; next += rtm->rtm_msglen) {
        rtm = (struct rt_msghdr *)next;
        sin = (struct sockaddr_inarp *)(rtm + 1);
        sdl = (struct sockaddr_dl *)(sin + 1);
        if (addr) {
            if (addr != sin->sin_addr.s_addr)
                continue;
            found_entry = 1;
        }
        if (nflag == 0)
            hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
                               sizeof sin->sin_addr, AF_INET);
        else
            hp = 0;
        if (hp)
            host = hp->h_name;
        else {
            host = "?";
            if (h_errno == TRY_AGAIN)
                nflag = 1;
        }



        if (sdl->sdl_alen) {

            u_char *cp = LLADDR(sdl);

            mAddr = [NSString stringWithFormat:@"%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]];


            //  ether_print((u_char *)LLADDR(sdl));
        }
        else

            mAddr = nil;



    }


    if (found_entry == 0) {
        return nil;
    } else {
        return mAddr;
    }




}
@end
  1. Then import the MacFinder.h file in your ViewController
  2. Example how to use it for each host you want to find the MAC Address:

MacFinder *mc = [[MacFinder alloc]init]; NSString *mac = [mc ip2mac:"192.168.10.24"]; NSLog(@"Mac:%@",mac);

If you still having trouble here is tutorial and here the full working project (Including the necessary files)