Restore pre-IPv6 localip_update() code for systems without ifaddrs.h
authorEmil Mikulic <emikulic@gmail.com>
Mon, 20 Jun 2011 12:46:15 +0000 (22:46 +1000)
committerEmil Mikulic <emikulic@gmail.com>
Tue, 21 Jun 2011 12:22:28 +0000 (22:22 +1000)
Requested by: Prof Abimbola Olowofoyeku for Routertech (uses uclibc)

Makefile.in
configure.ac
localip.c

index b6b65ff..4c1af22 100644 (file)
@@ -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
index 55dbfcb..c9b68ab 100644 (file)
@@ -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],
index 51a1bc3..15daa46 100644 (file)
--- 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 <sys/socket.h>
 #include <net/if.h>
-#include <ifaddrs.h>
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
 
+#ifdef HAVE_IFADDRS_H
+# include <ifaddrs.h>
+#else
+# ifdef HAVE_SYS_SOCKIO_H
+#  include <sys/sockio.h> /* for SIOCGIFADDR, especially on Solaris */
+# endif
+# include <sys/ioctl.h>
+#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));