I need to obtain the IP address of the default gateway in an iPhone application. I cannot find the proper API. Anyone know if iPhone exposes this information?
I was successful obtaining the address from SSDP protocol by sending a UDP packet out looking for service type "urn:schemas-upnp-org:device:InternetGatewayDevice:1" and noting the first device (if any) that replies (ignoring the payload, since I only want the IP address of the gateway).
This works for my application, but requires that the router implement SSDP, which is not perfect, although works in my case.
Since this is a special-purpose iPhone App (in-house, only), I am going to go with this. I won't mark this as "the answer" because it is not a general purpose solution. If I come back to this and look for a general purpose solution (such as using ICMP), or figuring out how to use the iPhone SDK configuration APIs to query for this information, I will post here.
I have solved this, though i dunno if this solution is valid (wont be rejected by apple)
first i'll give you the sources i used to build my solution upon:
http://code.google.com/p/doubango/source/browse/trunk/thirdparties/iphone/include/net/route.h?r=348
http://code.google.com/p/touchcode/source/browse/Experimental/TouchHTTPD/Externals/libnatpmp-20071213/getgateway.c?r=bc90b03205cbebb0633a7b5b203c2c6d5cb860dc
It would be great to get some feedback if you think apple will allow this kind of code.
getgateway.h
#ifndef __GETGATEWAY_H__
#define __GETGATEWAY_H__
/* getdefaultgateway() :
* return value :
* 0 : success
* -1 : failure */
int getdefaultgateway(in_addr_t * addr);
#endif
getgateway.c
#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include "getgateway.h"
#include "route.h"
#include <net/if.h>
#include <string.h>
#define CTL_NET 4 /* network, see socket.h */
#if defined(BSD) || defined(__APPLE__)
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int getdefaultgateway(in_addr_t * addr)
{
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_FLAGS, RTF_GATEWAY};
size_t l;
char * buf, * p;
struct rt_msghdr * rt;
struct sockaddr * sa;
struct sockaddr * sa_tab[RTAX_MAX];
int i;
int r = -1;
if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
return -1;
}
if(l>0) {
buf = malloc(l);
if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
return -1;
}
for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
rt = (struct rt_msghdr *)p;
sa = (struct sockaddr *)(rt + 1);
for(i=0; i<RTAX_MAX; i++) {
if(rt->rtm_addrs & (1 << i)) {
sa_tab[i] = sa;
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
} else {
sa_tab[i] = NULL;
}
}
if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
&& sa_tab[RTAX_DST]->sa_family == AF_INET
&& sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
char ifName[128];
if_indextoname(rt->rtm_index,ifName);
if(strcmp("en0",ifName)==0){
*addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
r = 0;
}
}
}
}
free(buf);
}
return r;
}
#endif
On iOS ≥ 12, you can use the Network framework.
The NWPath you get from the NWPathMonitor.pathUpdateHandler will have the NWPath.gateways variable set to the gateways IPs.
let monitor = NWPathMonitor(requiredInterfaceType: .wifi)
monitor.pathUpdateHandler = { path in
print(path.gateways)
}
monitor.start(queue: DispatchQueue(label: "nwpathmonitor.queue"))
If I'm not mistaken, the gateway IP is always whatever your device IP address is, with the last octet set to "1", isn't it? If that's what you're looking for, you should be able to find the hints you need from the localhostAddresses.m file which is part of the samples in CocoaHTTPServer sources. I use the project to add an internal webserver within my app and I get the devices IP from that source file's methods.
Dr. Touch talks about it at this link.
for those who need human readable IP, i modified my getgateway.c as follow:
add to includes:
#include <arpa/inet.h>
inside the last if statement, between *addr and r=0;
if(strcmp("en0",ifName)==0){
*addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr), str, INET_ADDRSTRLEN); // supports IPv6
printf("IP: %s\n", str); // prints "192.0.2.33"
r = 0;
}