Objective-C : How to fetch the router address?

Daniel picture Daniel · Jan 21, 2010 · Viewed 17.5k times · Source

I tried to fetch the router address this way.

- (NSString *) routerIp {

  NSString *address = @"error";
  struct ifaddrs *interfaces = NULL;
  struct ifaddrs *temp_addr = NULL;
  int success = 0;

  // retrieve the current interfaces - returns 0 on success
  success = getifaddrs(&interfaces);
  if (success == 0)
  {
    // Loop through linked list of interfaces
    temp_addr = interfaces;
    while(temp_addr != NULL)
    {
      if(temp_addr->ifa_addr->sa_family == AF_INET)
      {
        // Check if interface is en0 which is the wifi connection on the iPhone
        if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"])
        {
          // Get NSString from C String //ifa_addr
          address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)];
        }
      }

      temp_addr = temp_addr->ifa_next;
    }
  }

  // Free memory
  freeifaddrs(interfaces);

  return address;
}

The router address always looks like xxx.xxx.255.255 but it is supposed to look like xxx.xxx.0.1 or something this way...

Is there anything to do to get the valid address?

Thanks for your help!

Answer

mike picture mike · Dec 3, 2012

I've been looking for a way to get the IP address of the default gateway myself. I'm going to focus just on this - I didn't need to get the MAC address of the default router, so this only partially answers the OP's question.

I didn't like the idea of parsing the netstat output. Also, you can't get a default route based on the IP address an interface on your machine has. Any IP address within the same range as yours can be a default gateway - the only rule is that both your IP and the default gateway need to be part of the same subnet.

One more thing I wanted to ensure is to get an IP address of the default gateway even if more than one of my local interfaces has an IP address assigned to it (e.g. I'm connected to the Wifi and to the wired Ethernet at the same time, and both interfaces are up, with an IP address on them). For my application, it doesn't matter which interface the default route is set via (it can be en0, en1, ppp0 or anything else at all).

I think the best (and most Apple-like) way to get that info is to use System Configuration Framework - the links in the post above in this thread pointed me in that direction, but didn't really give much detail as to how to use it, and I didn't find the Apple documentation on it very useful (at least taking into consideration my skill level).

Please mind I'm not very experienced in Objective-C - I'm in the middle of writing an app that I need myself (and which I couldn't find), and for that app I just need the IP address of the default gateway.

So - here's what I'm doing in my app, and it seems to be working fine (plus is much shorter and simpler than most other solutions I found so far:

- (NSString *)defaultRouter {

    SCDynamicStoreRef ds = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("myapp"), NULL, NULL);
    CFDictionaryRef dr = SCDynamicStoreCopyValue(ds, CFSTR("State:/Network/Global/IPv4"));
    CFStringRef router = CFDictionaryGetValue(dr, CFSTR("Router"));
    NSString *routerString = [NSString stringWithString:(__bridge NSString *)router];
    CFRelease(dr);
    CFRelease(ds);

    return routerString;
}

Please note that in my app, the above is part of a larger method (I don't actually have a defaultRouter: method in there). Also, I've omitted some of the checks (like [routerString length] and so on) for brevity.

Hopefully someone finds this useful. Please also feel free to fix any errors I might have in the code above - I'm still a newbie!

PS. I got an idea of what to look for when I checked the output of 'scutil', which uses the System Configuration Framework itself:

MacBook:~$ scutil 
> show State:/Network/Global/IPv4
<dictionary> {
  PrimaryInterface : en1
  PrimaryService : <service_id>
  Router : <ipv4_address>
}
> show State:/Network/Global/IPv6
<dictionary> {
  PrimaryInterface : en1
  PrimaryService : <service_id>
  Router : <ipv6_address>
}