added new /proc/net/route method to find interfaces on android

(would you believe that using ifconfig to READ about interfaces
requires ROOT on android).
should also help for interfaces with multiple addresses.
This commit is contained in:
gardners 2012-05-03 22:46:00 +09:30
parent 6e933be9ec
commit 98ea86bde0
3 changed files with 82 additions and 30 deletions

44
lsif.c
View File

@ -59,6 +59,47 @@
#define SIOCGIFBRDADDR OSIOCGIFBRDADDR
#endif
int overlay_interface_register(unsigned char *name,
struct sockaddr_in local,
struct sockaddr_in broadcast);
/* for when all other options fail, as can happen on Android,
if the permissions for the socket-based method are broken.
Down side is that it while it gets the interface name and
broadcast, it doesn't get the local address for that
interface.
*/
int scrapeProcNetRoute()
{
FILE *f=fopen("/proc/net/route","r");
if (!f) return fprintf(stderr,"Can't read from /proc/net/route\n");
char line[1024],name[1024],dest[1024],mask[1024];
/* skip header line */
line[0]=0; fgets(line,1024,f);
line[0]=0; fgets(line,1024,f);
while(line[0]) {
int r;
if ((r=sscanf(line,"%s %s %*s %*s %*s %*s %*s %s",name,dest,mask))==3)
{
unsigned int d = strtol(dest,NULL,16);
unsigned int m = strtol(mask,NULL,16);
struct sockaddr_in local,broadcast;
if (!(d&(~m))) {
local.sin_addr.s_addr=d;
broadcast.sin_addr.s_addr=d|~m;
overlay_interface_register((unsigned char *)name,local,broadcast);
}
}
line[0]=0; fgets(line,1024,f);
}
fclose(f);
return 0;
}
#ifdef ANDROID
int lsif(void)
{
@ -74,7 +115,8 @@ int lsif(void)
/* Get a socket handle. */
sck = socket(PF_INET, SOCK_DGRAM, 0);
if(sck < 0) {
fprintf(stderr,"Failed to gt socket handle to list addresses\n");
fprintf(stderr,"Failed to gt socket handle to list addresses, errno=%d\n",
errno);
return 1;
}

View File

@ -178,7 +178,7 @@ int overlay_interface_args(char *arg)
int overlay_interface_init_socket(int interface,struct sockaddr_in src_addr,struct sockaddr_in broadcast)
{
#define I(X) overlay_interfaces[interface].X
I(local_address)=src_addr;
// I(local_address)=src_addr;
I(broadcast_address)=broadcast;
I(fileP)=0;
@ -502,29 +502,36 @@ int overlay_interface_register(unsigned char *name,
int i;
for(i=0;i<overlay_interface_count;i++) if (!strcasecmp(overlay_interfaces[i].name,(char *)name)) break;
if (i<overlay_interface_count) {
/* We already know about this interface, so just update it */
if (((overlay_interfaces[i].local_address.sin_addr.s_addr&0xffffffff)
==(local.sin_addr.s_addr&0xffffffff))
&&((overlay_interfaces[i].broadcast_address.sin_addr.s_addr&0xffffffff)
==(broadcast.sin_addr.s_addr&0xffffffff)))
/* We already know about this interface, so just update it.
We actually only care about the broadcast address for the overlay mesh.
this is a good thing, because it turns out to be pretty hard to discover
your own IP address on Android. */
if ( /* ((overlay_interfaces[i].local_address.sin_addr.s_addr&0xffffffff)
==(local.sin_addr.s_addr&0xffffffff))&& */
((overlay_interfaces[i].broadcast_address.sin_addr.s_addr&0xffffffff)
==(broadcast.sin_addr.s_addr&0xffffffff)))
{
/* Mark it as being seen */
overlay_interfaces[i].observed=1;
return 0;
}
else
{
/* Interface has changed */
WHYF("Interface changed %08llx.%08llx vs %08llx.%08llx",
overlay_interfaces[i].local_address.sin_addr.s_addr,
overlay_interfaces[i].broadcast_address.sin_addr.s_addr,
local.sin_addr.s_addr,
broadcast.sin_addr.s_addr);
close(overlay_interfaces[i].fd);
overlay_interfaces[i].fd=-1;
if (overlay_interface_init_socket(i,local,broadcast))
WHY("Could not reinitialise changed interface");
}
if (0)
{
/* Interface has changed.
This old approach has problems for machines with multiple IP
addresses on a given interface, so now we allow multiple
interfaces on the same underlying network adaptor. */
WHYF("Interface changed %08llx.%08llx vs %08llx.%08llx",
/* overlay_interfaces[i].local_address.sin_addr.s_addr */0,
overlay_interfaces[i].broadcast_address.sin_addr.s_addr,
local.sin_addr.s_addr,
broadcast.sin_addr.s_addr);
close(overlay_interfaces[i].fd);
overlay_interfaces[i].fd=-1;
if (overlay_interface_init_socket(i,local,broadcast))
WHY("Could not reinitialise changed interface");
}
}
else {
/* New interface, so register it */
@ -543,8 +550,12 @@ int overlay_interface_discover()
{
/* Don't waste too much time and effort on interface discovery,
especially if we can't attach to a given interface for some reason. */
WHY("called");
if ((time(0)-overlay_last_interface_discover_time)<0)
overlay_last_interface_discover_time=time(0);
if ((time(0)-overlay_last_interface_discover_time)<2) return 0;
overlay_last_interface_discover_time=time(0);
WHY("checking");
/* The Android ndk doesn't have ifaddrs.h, so we have to use the netlink interface.
However, netlink is only available on Linux, so for BSD systems, e.g., Mac, we
@ -578,6 +589,13 @@ int overlay_interface_discover()
r=r->next;
}
#ifdef ANDROID
/* Use alternative linux-only method to find and register interfaces. */
lsif();
#endif
/* /proc based approach */
scrapeProcNetRoute();
#ifdef HAVE_IFADDRS_H
struct ifaddrs *ifaddr,*ifa;
int family;
@ -607,16 +625,6 @@ int overlay_interface_discover()
}
freeifaddrs(ifaddr);
#endif
#ifdef ANDROID
/* Use alternative linux-only method to find and register interfaces. */
lsif();
#else
#ifdef HAVE_IFADDRS_H
#else
#error Don't know how to get interface list on this platform
#endif
#endif
return 0;
}

View File

@ -601,7 +601,9 @@ typedef struct overlay_interface {
int sequence_number;
/* Broadcast address and netmask, if known */
struct sockaddr_in local_address;
/* We really only case about distinct broadcast addresses on interfaces.
Also simplifies aliases on interfaces.
struct sockaddr_in local_address; */
struct sockaddr_in broadcast_address;
/* Not necessarily the real MTU, but the largest frame size we are willing to TX on this interface.