From 95002535b32ca05b4fa03a49afa211c4271bea1d Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Wed, 16 Feb 2022 17:58:42 +0100 Subject: [PATCH] getifaddr.c: prefer non-reserved over reserved addresses in `getifaddr()` When iterating interface addresses obtained via `getifaddrs()`, don't stop at the first found IPv4 address but continue checking all IPv4 addresses and prefer to use a non-reserved one in case an interface has both reserved (private) and non-reserved (public) addresses assigned. After this fix, miniupnpd on OpenWrt is able to properly detect the external IP address of an external interface with both a private RFC1918 and a public IP assigned regardless of whether `getifaddrs()` happens to return the private or the public IPv4 address first. Signed-off-by: Jo-Philipp Wich --- miniupnpd/getifaddr.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/miniupnpd/getifaddr.c b/miniupnpd/getifaddr.c index 7c09064..67ec235 100644 --- a/miniupnpd/getifaddr.c +++ b/miniupnpd/getifaddr.c @@ -101,6 +101,7 @@ getifaddr(const char * ifname, char * buf, int len, /* Works for all address families (both ip v4 and ip v6) */ struct ifaddrs * ifap; struct ifaddrs * ife; + struct ifaddrs * candidate = NULL; if(!ifname || ifname[0]=='\0') return -1; @@ -119,14 +120,10 @@ getifaddr(const char * ifname, char * buf, int len, switch(ife->ifa_addr->sa_family) { case AF_INET: - if(buf) - { - inet_ntop(ife->ifa_addr->sa_family, - &((struct sockaddr_in *)ife->ifa_addr)->sin_addr, - buf, len); - } - if(addr) *addr = ((struct sockaddr_in *)ife->ifa_addr)->sin_addr; - if(mask) *mask = ((struct sockaddr_in *)ife->ifa_netmask)->sin_addr; + if(!candidate || + (addr_is_reserved(&((struct sockaddr_in *)candidate->ifa_addr)->sin_addr) && + !addr_is_reserved(&((struct sockaddr_in *)ife->ifa_addr)->sin_addr))) + candidate = ife; break; /* case AF_INET6: @@ -136,6 +133,17 @@ getifaddr(const char * ifname, char * buf, int len, */ } } + if(candidate) + { + if(buf) + { + inet_ntop(candidate->ifa_addr->sa_family, + &((struct sockaddr_in *)candidate->ifa_addr)->sin_addr, + buf, len); + } + if(addr) *addr = ((struct sockaddr_in *)candidate->ifa_addr)->sin_addr; + if(mask) *mask = ((struct sockaddr_in *)candidate->ifa_netmask)->sin_addr; + } freeifaddrs(ifap); #endif return 0;