From 0efae728d5dcb80a825889ddbff1908c1cae4158 Mon Sep 17 00:00:00 2001 From: Emil Mikulic Date: Mon, 20 Jun 2011 22:46:15 +1000 Subject: [PATCH] Restore pre-IPv6 localip_update() code for systems without ifaddrs.h Requested by: Prof Abimbola Olowofoyeku for Routertech (uses uclibc) --- Makefile.in | 2 +- configure.ac | 4 ++ localip.c | 120 ++++++++++++++++++++++++++++++++------------------- 3 files changed, 81 insertions(+), 45 deletions(-) diff --git a/Makefile.in b/Makefile.in index b6b65ff..4c1af22 100644 --- a/Makefile.in +++ b/Makefile.in @@ -132,7 +132,7 @@ hosts_sort.o: hosts_sort.c cdefs.h err.h hosts_db.h addr.h html.o: html.c config.h str.h html.h opt.h http.o: http.c cdefs.h config.h conv.h err.h graph_db.h hosts_db.h addr.h \ http.h now.h queue.h str.h stylecss.h graphjs.h -localip.o: localip.c addr.h conv.h config.h err.h cdefs.h localip.h +localip.o: localip.c addr.h config.h conv.h err.h cdefs.h localip.h ncache.o: ncache.c conv.h config.h err.h cdefs.h ncache.h tree.h pidfile.o: pidfile.c err.h cdefs.h str.h pidfile.h str.o: str.c conv.h config.h err.h cdefs.h str.h diff --git a/configure.ac b/configure.ac index 55dbfcb..c9b68ab 100644 --- a/configure.ac +++ b/configure.ac @@ -238,7 +238,11 @@ AC_CHECK_HEADERS(sys/filio.h) # GNU/kfreebsd needs net/if_ether.h for ETH_P_IPV6 AC_CHECK_HEADERS(net/if_ether.h) +# This is the modern way. Older systems use the ioctl method. +AC_CHECK_HEADERS(ifaddrs.h) +# Some OSes (Solaris) need sys/sockio.h for SIOCGIFADDR +AC_CHECK_HEADERS(sys/sockio.h) # Check for libpcap AC_ARG_WITH(pcap, AS_HELP_STRING([--with-pcap=DIR], diff --git a/localip.c b/localip.c index 51a1bc3..15daa46 100644 --- a/localip.c +++ b/localip.c @@ -8,17 +8,26 @@ */ #include "addr.h" +#include "config.h" /* for HAVE_IFADDRS_H */ #include "conv.h" /* for strlcpy */ #include "err.h" #include "localip.h" #include #include -#include #include #include #include +#ifdef HAVE_IFADDRS_H +# include +#else +# ifdef HAVE_SYS_SOCKIO_H +# include /* for SIOCGIFADDR, especially on Solaris */ +# endif +# include +#endif + static const char *iface = NULL; struct addr localip4, localip6; static struct addr last_localip4, last_localip6; @@ -33,58 +42,81 @@ localip_init(const char *interface) void localip_update(void) { - struct ifaddrs *ifas, *ifa; - int got_v4 = 0, got_v6 = 0; - + /* defaults */ localip4.family = IPv4; - localip6.family = IPv6; + localip4.ip.v4 = 0; - if (iface == NULL) { - /* reading from capfile */ - localip4.ip.v4 = 0; - memset(&(localip6.ip.v6), 0, sizeof(localip6.ip.v6)); - return; - } - - if (getifaddrs(&ifas) < 0) - err(1, "can't get own IP address on interface \"%s\"", iface); + localip6.family = IPv6; + memset(&(localip6.ip.v6), 0, sizeof(localip6.ip.v6)); + + if (iface != NULL) { + /* not reading from capfile */ +#ifdef HAVE_IFADDRS_H + int got_v4 = 0, got_v6 = 0; + struct ifaddrs *ifas, *ifa; + + if (getifaddrs(&ifas) < 0) + err(1, "can't get own IP address on interface \"%s\"", iface); + + for (ifa = ifas; ifa; ifa = ifa->ifa_next) { + if (got_v4 && got_v6) + break; /* Task is already complete. */ + + if (strncmp(ifa->ifa_name, iface, IFNAMSIZ)) + continue; /* Wrong interface. */ + + /* The first IPv4 name is always functional. */ + if ((ifa->ifa_addr->sa_family == AF_INET) && !got_v4) + { + /* Good IPv4 address. */ + localip4.ip.v4 = + ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; + got_v4 = 1; + continue; + } - for (ifa = ifas; ifa; ifa = ifa->ifa_next) { - if (got_v4 && got_v6) - break; /* Task is already complete. */ + /* IPv6 needs some obvious exceptions. */ + if ( ifa->ifa_addr->sa_family == AF_INET6 ) { + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) ifa->ifa_addr; - if (strncmp(ifa->ifa_name, iface, IFNAMSIZ)) - continue; /* Wrong interface. */ + if ( IN6_IS_ADDR_LINKLOCAL(&(sa6->sin6_addr)) + || IN6_IS_ADDR_SITELOCAL(&(sa6->sin6_addr)) ) + continue; - /* The first IPv4 name is always functional. */ - if ((ifa->ifa_addr->sa_family == AF_INET) && !got_v4) - { - /* Good IPv4 address. */ - localip4.ip.v4 = - ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; - got_v4 = 1; - continue; + /* Only standard IPv6 can reach this point. */ + memcpy(&(localip6.ip.v6), &sa6->sin6_addr, sizeof(localip6.ip.v6)); + got_v6 = 1; + } } - /* IPv6 needs some obvious exceptions. */ - if ( ifa->ifa_addr->sa_family == AF_INET6 ) { - struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) ifa->ifa_addr; - - if ( IN6_IS_ADDR_LINKLOCAL(&(sa6->sin6_addr)) - || IN6_IS_ADDR_SITELOCAL(&(sa6->sin6_addr)) ) - continue; - - /* Only standard IPv6 can reach this point. */ - memcpy(&(localip6.ip.v6), &sa6->sin6_addr, sizeof(localip6.ip.v6)); - got_v6 = 1; + freeifaddrs(ifas); + + /* Report an error if IPv4 address could not be found. */ + if (!got_v4) + err(1, "can't get own IPv4 address on interface \"%s\"", iface); + +#else /* don't HAVE_IFADDRS_H */ + + int tmp = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + struct ifreq ifr; + struct sockaddr sa; + + strlcpy(ifr.ifr_name, iface, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(tmp, SIOCGIFADDR, &ifr) == -1) { + if (errno == EADDRNOTAVAIL) { + verbosef("lost local IP"); + } else + err(1, "can't get own IP address on interface \"%s\"", iface); + } else { + /* success! */ + sa = ifr.ifr_addr; + localip4.ip.v4 = ((struct sockaddr_in*)&sa)->sin_addr.s_addr; } - } - - freeifaddrs(ifas); + close(tmp); - /* Report an error if IPv4 address could not be found. */ - if (!got_v4) - err(1, "can't get own IPv4 address on interface \"%s\"", iface); +#endif + } if (!addr_equal(&last_localip4, &localip4)) { verbosef("localip4 update(%s) = %s", iface, addr_to_str(&localip4)); -- 2.17.1