/* darkstat 3
- * copyright (c) 2001-2008 Emil Mikulic.
+ * copyright (c) 2001-2011 Emil Mikulic.
*
* localip.c: determine local IP of our capture interface
*
* GNU General Public License version 2. (see COPYING.GPL)
*/
-#include "darkstat.h"
#include "addr.h"
-#include "conv.h" /* for strlcpy */
+#include "config.h" /* for HAVE_IFADDRS_H */
#include "err.h"
#include "localip.h"
+#include "bsd.h" /* for strlcpy */
-#include <sys/types.h> /* OpenBSD needs this */
#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;
localip_init(const char *interface)
{
iface = interface;
+
+ /* defaults */
+ localip4.family = IPv4;
+ localip4.ip.v4 = 0;
+
+ localip6.family = IPv6;
+ memset(&(localip6.ip.v6), 0, sizeof(localip6.ip.v6));
+
+ last_localip4 = localip4;
+ last_localip6 = localip6;
+
+ /* initial update */
localip_update();
}
-void
-localip_update(void)
+static void
+localip_update_helper(void)
{
- struct ifaddrs *ifas, *ifa;
- int got_v4 = 0, got_v6 = 0;
-
+ /* defaults */
localip4.family = IPv4;
+ localip4.ip.v4 = 0;
+
localip6.family = IPv6;
+ memset(&(localip6.ip.v6), 0, sizeof(localip6.ip.v6));
- if (iface == NULL) {
- /* reading from capfile */
- localip4.ip.v4 = 0;
- memset(&(localip6.ip.v6), 0, sizeof(localip6.ip.v6));
- return;
- }
+ if (iface == NULL)
+ return; /* reading from capfile */
- if (getifaddrs(&ifas) < 0)
- err(1, "can't get own IP address on interface \"%s\"", iface);
+#ifdef HAVE_IFADDRS_H
+ {
+ int got_v4 = 0, got_v6 = 0;
+ struct ifaddrs *ifas, *ifa;
- for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
- if (got_v4 && got_v6)
- break; /* Task is already complete. */
+ if (getifaddrs(&ifas) < 0) {
+ warn("can't getifaddrs() on interface \"%s\"", iface);
+ return;
+ }
- if (strncmp(ifa->ifa_name, iface, IFNAMSIZ))
- continue; /* Wrong interface. */
+ for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
+ if (got_v4 && got_v6)
+ break; /* Task is already complete. */
- /* 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;
- }
+ if (strncmp(ifa->ifa_name, iface, IFNAMSIZ))
+ continue; /* Wrong interface. */
- /* IPv6 needs some obvious exceptions. */
- if ( ifa->ifa_addr->sa_family == AF_INET6 ) {
- struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
+ if (!ifa->ifa_addr)
+ continue; /* This can be NULL, e.g. for ppp0. */
- if ( IN6_IS_ADDR_LINKLOCAL(&(sa6->sin6_addr))
- || IN6_IS_ADDR_SITELOCAL(&(sa6->sin6_addr)) )
+ /* 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;
+ }
+
+ /* 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;
+ /* Only standard IPv6 can reach this point. */
+ memcpy(&(localip6.ip.v6), &sa6->sin6_addr, sizeof(localip6.ip.v6));
+ got_v6 = 1;
+ }
}
- }
- freeifaddrs(ifas);
+ freeifaddrs(ifas);
+
+ if (!got_v4)
+ warnx("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
+ warn("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;
+ }
+ close(tmp);
+ }
+#endif
+}
- /* 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);
+void
+localip_update(void)
+{
+ localip_update_helper();
if (!addr_equal(&last_localip4, &localip4)) {
- verbosef("localip4 update(%s) = %s", iface, addr_to_str(&localip4));
+ verbosef("%s ip4 update: %s", iface, addr_to_str(&localip4));
last_localip4 = localip4;
}
if (!addr_equal(&last_localip6, &localip6)) {
- verbosef("localip6 update(%s) = %s", iface, addr_to_str(&localip6));
+ verbosef("%s ip6 update: %s", iface, addr_to_str(&localip6));
last_localip6 = localip6;
}
}