[tor-commits] [tor/master] Refactor code that looks up addresses from interfaces

nickm at torproject.org nickm at torproject.org
Fri Jan 23 15:13:43 UTC 2015


commit 3966145dff817adb67e5b46020632d55f19e289f
Author: rl1987 <rl1987 at sdf.lonestar.org>
Date:   Sat May 24 15:03:14 2014 +0300

    Refactor code that looks up addresses from interfaces
    
    Now the code has separate implementation and examination functions,
    uses smartlists sanely, and has relatively decent test coverage.
---
 changes/ticket12376_part2 |   11 ++
 src/common/address.c      |  227 +++++++++++++++-------
 src/common/address.h      |   53 +++++
 src/test/include.am       |    1 +
 src/test/test.c           |    2 +
 src/test/test_address.c   |  467 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 697 insertions(+), 64 deletions(-)

diff --git a/changes/ticket12376_part2 b/changes/ticket12376_part2
new file mode 100644
index 0000000..13f9bb5
--- /dev/null
+++ b/changes/ticket12376_part2
@@ -0,0 +1,11 @@
+  o Major refactoring:
+    - Refactor the get_interface_addresses_raw() Doom-function into
+      multiple smaller and easier to understand subfunctions. Cover the
+      resulting subfunctions with unit-tests. Fixes a significant portion 
+      of issue 12376.
+
+  o Minor bugfixes:
+    - Fix the ioctl()-based network interface lookup code so that it will
+      work on systems that have variable-length struct ifreq, for example
+      Mac OS X.
+
diff --git a/src/common/address.c b/src/common/address.c
index 2825b12..7b4584f 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -8,24 +8,26 @@
  * \brief Functions to use and manipulate the tor_addr_t structure.
  **/
 
-#include "orconfig.h"
-#include "compat.h"
-#include "util.h"
-#include "address.h"
-#include "torlog.h"
-#include "container.h"
-#include "sandbox.h"
+#define ADDRESS_PRIVATE
 
 #ifdef _WIN32
-#include <process.h>
-#include <windows.h>
-#include <winsock2.h>
 /* For access to structs needed by GetAdaptersAddresses */
 #undef _WIN32_WINNT
 #define _WIN32_WINNT 0x0501
+#include <process.h>
+#include <winsock2.h>
+#include <windows.h>
 #include <iphlpapi.h>
 #endif
 
+#include "orconfig.h"
+#include "compat.h"
+#include "util.h"
+#include "address.h"
+#include "torlog.h"
+#include "container.h"
+#include "sandbox.h"
+
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
@@ -122,7 +124,7 @@ tor_addr_to_sockaddr(const tor_addr_t *a,
 }
 
 /** Set the tor_addr_t in <b>a</b> to contain the socket address contained in
- * <b>sa</b>. */
+ * <b>sa</b>. Return 0 on success and -1 on failure. */
 int
 tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
                        uint16_t *port_out)
@@ -1192,26 +1194,17 @@ typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
               ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
 #endif
 
-/** Try to ask our network interfaces what addresses they are bound to.
- * Return a new smartlist of tor_addr_t on success, and NULL on failure.
- * (An empty smartlist indicates that we successfully learned that we have no
- * addresses.)  Log failure messages at <b>severity</b>. */
-static smartlist_t *
-get_interface_addresses_raw(int severity)
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+/*
+ * Convert a linked list consisting of <b>ifaddrs</b> structures
+ * into smartlist of <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+ifaddrs_to_smartlist(const struct ifaddrs *ifa)
 {
-#if defined(HAVE_GETIFADDRS)
-  /* Most free Unixy systems provide getifaddrs, which gives us a linked list
-   * of struct ifaddrs. */
-  struct ifaddrs *ifa = NULL;
+  smartlist_t *result = smartlist_new();
   const struct ifaddrs *i;
-  smartlist_t *result;
-  if (getifaddrs(&ifa) < 0) {
-    log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s",
-           strerror(errno));
-    return NULL;
-  }
 
-  result = smartlist_new();
   for (i = ifa; i; i = i->ifa_next) {
     tor_addr_t tmp;
     if ((i->ifa_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
@@ -1226,9 +1219,72 @@ get_interface_addresses_raw(int severity)
     smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
   }
 
+  return result;
+}
+
+/** Use getiffaddrs() function to get list of current machine
+ * network interface addresses. Represent the result by smartlist of
+ * <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+get_interface_addresses_ifaddrs(int severity)
+{
+
+  /* Most free Unixy systems provide getifaddrs, which gives us a linked list
+   * of struct ifaddrs. */
+  struct ifaddrs *ifa = NULL;
+  smartlist_t *result;
+  if (getifaddrs(&ifa) < 0) {
+    log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s",
+           strerror(errno));
+    return NULL;
+  }
+
+  result = ifaddrs_to_smartlist(ifa);
+
   freeifaddrs(ifa);
+
+  return result;
+}
+#endif
+
+#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
+
+/** Convert a Windows-specific <b>addresses</b> linked list into smartlist
+ * of <b>tor_addr_t</b> structures.
+ */
+
+STATIC smartlist_t *
+ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses)
+{
+  smartlist_t *result = smartlist_new();
+  const IP_ADAPTER_ADDRESSES *address;
+
+  for (address = addresses; address; address = address->Next) {
+    const IP_ADAPTER_UNICAST_ADDRESS *a;
+    for (a = address->FirstUnicastAddress; a; a = a->Next) {
+      /* Yes, it's a linked list inside a linked list */
+      const struct sockaddr *sa = a->Address.lpSockaddr;
+      tor_addr_t tmp;
+      if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+        continue;
+      if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
+        continue;
+      smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+    }
+  }
+
   return result;
-#elif defined(_WIN32)
+}
+
+/** Windows only: use GetAdaptersInfo() function to retrieve network interface
+ * addresses of current machine and return them to caller as smartlist of
+ * <b>tor_addr_t</b>  structures.
+ */
+STATIC smartlist_t *
+get_interface_addresses_win32(int severity)
+{
+
   /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
      "GetAdaptersInfo", but that's deprecated; let's just try
      GetAdaptersAddresses and fall back to connect+getsockname.
@@ -1237,7 +1293,7 @@ get_interface_addresses_raw(int severity)
   smartlist_t *result = NULL;
   GetAdaptersAddresses_fn_t fn;
   ULONG size, res;
-  IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
+  IP_ADAPTER_ADDRESSES *addresses = NULL;
 
   (void) severity;
 
@@ -1272,63 +1328,106 @@ get_interface_addresses_raw(int severity)
     goto done;
   }
 
-  result = smartlist_new();
-  for (address = addresses; address; address = address->Next) {
-    IP_ADAPTER_UNICAST_ADDRESS *a;
-    for (a = address->FirstUnicastAddress; a; a = a->Next) {
-      /* Yes, it's a linked list inside a linked list */
-      struct sockaddr *sa = a->Address.lpSockaddr;
-      tor_addr_t tmp;
-      if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
-        continue;
-      if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
-        continue;
-      smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
-    }
-  }
+  result = ip_adapter_addresses_to_smartlist(addresses);
 
  done:
   if (lib)
     FreeLibrary(lib);
   tor_free(addresses);
   return result;
-#elif defined(SIOCGIFCONF) && defined(HAVE_IOCTL)
+}
+
+#endif
+
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+
+/* This is defined on Mac OS X */
+#ifndef _SIZEOF_ADDR_IFREQ
+#define _SIZEOF_ADDR_IFREQ sizeof
+#endif
+
+/** Convert <b>*ifr</b>, an ifreq structure array of size <b>buflen</b>
+ * into smartlist of <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+ifreq_to_smartlist(const struct ifreq *ifr, size_t buflen)
+{
+  smartlist_t *result = smartlist_new();
+
+  struct ifreq *r = (struct ifreq *)ifr;
+
+  while ((char *)r < (char *)ifr+buflen) {
+    const struct sockaddr *sa = &r->ifr_addr;
+    tor_addr_t tmp;
+    int valid_sa_family = (sa->sa_family == AF_INET ||
+                           sa->sa_family == AF_INET6);
+
+    int conversion_success = (tor_addr_from_sockaddr(&tmp, sa, NULL) == 0);
+
+    if (valid_sa_family && conversion_success)
+      smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+
+    r = (struct ifreq *)((char *)r + _SIZEOF_ADDR_IFREQ(*r));
+  }
+
+  return result;
+}
+
+/** Use ioctl(.,SIOCGIFCONF,.) to get a list of current machine
+ * network interface addresses. Represent the result by smartlist of
+ * <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+get_interface_addresses_ioctl(int severity)
+{
   /* Some older unixy systems make us use ioctl(SIOCGIFCONF) */
   struct ifconf ifc;
-  int fd, i, sz, n;
+  int fd, sz;
+  void *databuf = NULL;
   smartlist_t *result = NULL;
+
   /* This interface, AFAICT, only supports AF_INET addresses */
   fd = socket(AF_INET, SOCK_DGRAM, 0);
   if (fd < 0) {
     tor_log(severity, LD_NET, "socket failed: %s", strerror(errno));
     goto done;
   }
+
   /* Guess how much space we need. */
-  ifc.ifc_len = sz = 15*1024;
-  ifc.ifc_ifcu.ifcu_req = tor_malloc(sz);
+  ifc.ifc_len = sz = 4096;
+  databuf = tor_malloc_zero(sz);
+  ifc.ifc_buf = databuf;
+
   if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
     tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
     close(fd);
     goto done;
   }
-  close(fd);
-  result = smartlist_new();
-  if (ifc.ifc_len < sz)
-    sz = ifc.ifc_len;
-  n = sz / sizeof(struct ifreq);
-  for (i = 0; i < n ; ++i) {
-    struct ifreq *r = &ifc.ifc_ifcu.ifcu_req[i];
-    struct sockaddr *sa = &r->ifr_addr;
-    tor_addr_t tmp;
-    if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
-      continue; /* should be impossible */
-    if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
-      continue;
-    smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
-  }
+
+  result = ifreq_to_smartlist(databuf, ifc.ifc_len);
+
  done:
-  tor_free(ifc.ifc_ifcu.ifcu_req);
+  close(fd);
+  tor_free(databuf);
   return result;
+}
+#endif
+
+/** Try to ask our network interfaces what addresses they are bound to.
+ * Return a new smartlist of tor_addr_t on success, and NULL on failure.
+ * (An empty smartlist indicates that we successfully learned that we have no
+ * addresses.)  Log failure messages at <b>severity</b>. */
+STATIC smartlist_t *
+get_interface_addresses_raw(int severity)
+{
+#if defined(HAVE_IFADDRS_TO_SMARTLIST)
+  return get_interface_addresses_ifaddrs(severity);
+#endif
+#if defined(HAVE_IP_ADAPTER_TO_SMARTLIST)
+  return get_interface_addresses_win32(severity);
+#endif
+#if defined(HAVE_IFCONF_TO_SMARTLIST)
+  return get_interface_addresses_ioctl(severity);
 #else
   (void) severity;
   return NULL;
diff --git a/src/common/address.h b/src/common/address.h
index 8dc63b7..934c3f5 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -11,10 +11,41 @@
 #ifndef TOR_ADDRESS_H
 #define TOR_ADDRESS_H
 
+//#include <sys/sockio.h>
 #include "orconfig.h"
 #include "torint.h"
 #include "compat.h"
 
+#ifdef ADDRESS_PRIVATE
+
+#if defined(HAVE_SYS_IOCTL_H)
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_GETIFADDRS
+#define HAVE_IFADDRS_TO_SMARTLIST
+#endif
+
+#ifdef _WIN32
+#define HAVE_IP_ADAPTER_TO_SMARTLIST
+#endif
+
+#if defined(SIOCGIFCONF) && defined(HAVE_IOCTL)
+#define HAVE_IFCONF_TO_SMARTLIST
+#endif
+
+#if defined(HAVE_NET_IF_H)
+#include <net/if.h> // for struct ifconf
+#endif
+
+#if defined(HAVE_IFADDRS_TO_SMARTLIST)
+#include <ifaddrs.h>
+#endif
+
+// TODO win32 specific includes
+#include "container.h"
+#endif // ADDRESS_PRIVATE
+
 /** The number of bits from an address to consider while doing a masked
  * comparison. */
 typedef uint8_t maskbits_t;
@@ -229,5 +260,27 @@ int get_interface_address(int severity, uint32_t *addr);
 
 tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
 
+#ifdef ADDRESS_PRIVATE
+STATIC smartlist_t *get_interface_addresses_raw(int severity);
+
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa);
+STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity);
+#endif
+
+#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
+STATIC smartlist_t *ip_adapter_addresses_to_smartlist(
+                                        const IP_ADAPTER_ADDRESSES *addresses);
+STATIC smartlist_t *get_interface_addresses_win32(int severity);
+#endif
+
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+STATIC smartlist_t *ifreq_to_smartlist(const struct ifreq *ifr,
+                                       size_t buflen);
+STATIC smartlist_t *get_interface_addresses_ioctl(int severity);
+#endif
+
+#endif // ADDRESS_PRIVATE
+
 #endif
 
diff --git a/src/test/include.am b/src/test/include.am
index fba439a..371f063 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -45,6 +45,7 @@ src_test_test_SOURCES = \
 	src/test/test_nodelist.c \
 	src/test/test_policy.c \
 	src/test/test_status.c \
+        src/test/test_address.c \
 	src/ext/tinytest.c
 
 src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
diff --git a/src/test/test.c b/src/test/test.c
index c96b396..ed3013c 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1287,6 +1287,7 @@ static struct testcase_t test_array[] = {
 };
 
 extern struct testcase_t addr_tests[];
+extern struct testcase_t address_tests[];
 extern struct testcase_t buffer_tests[];
 extern struct testcase_t crypto_tests[];
 extern struct testcase_t container_tests[];
@@ -1319,6 +1320,7 @@ static struct testgroup_t testgroups[] = {
   { "buffer/", buffer_tests },
   { "socks/", socks_tests },
   { "addr/", addr_tests },
+  { "address/", address_tests },
   { "crypto/", crypto_tests },
   { "container/", container_tests },
   { "util/", util_tests },
diff --git a/src/test/test_address.c b/src/test/test_address.c
new file mode 100644
index 0000000..971618d
--- /dev/null
+++ b/src/test/test_address.c
@@ -0,0 +1,467 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define ADDRESS_PRIVATE
+
+#ifdef _WIN32
+#include <winsock2.h>
+/* For access to structs needed by GetAdaptersAddresses */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#include <iphlpapi.h>
+#endif
+
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+#include <net/if.h>
+#include <ifaddrs.h>
+#endif
+
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <net/if.h>
+#endif
+
+#include "or.h"
+#include "address.h"
+#include "test.h"
+
+/** Return 1 iff <b>sockaddr1</b> and <b>sockaddr2</b> represent
+ * the same IP address and port combination. Otherwise, return 0.
+ */
+static uint8_t
+sockaddr_in_are_equal(struct sockaddr_in *sockaddr1,
+                      struct sockaddr_in *sockaddr2)
+{
+   return ((sockaddr1->sin_family == sockaddr2->sin_family) &&
+           (sockaddr1->sin_port == sockaddr2->sin_port) &&
+           (sockaddr1->sin_addr.s_addr == sockaddr2->sin_addr.s_addr));
+}
+
+/** Return 1 iff <b>sockaddr1</b> and <b>sockaddr2</b> represent
+ * the same IP address and port combination. Otherwise, return 0.
+ */
+static uint8_t
+sockaddr_in6_are_equal(struct sockaddr_in6 *sockaddr1,
+                       struct sockaddr_in6 *sockaddr2)
+{
+   return ((sockaddr1->sin6_family == sockaddr2->sin6_family) &&
+           (sockaddr1->sin6_port == sockaddr2->sin6_port) &&
+           (tor_memeq(sockaddr1->sin6_addr.s6_addr,
+                      sockaddr2->sin6_addr.s6_addr,16)));
+}
+
+/** Create a sockaddr_in structure from IP address string <b>ip_str</b>.
+ *
+ * If <b>out</b> is not NULL, write the result
+ * to the memory address in <b>out</b>. Otherwise, allocate the memory
+ * for result. On success, return pointer to result. Otherwise, return
+ * NULL.
+ */
+static struct sockaddr_in *
+sockaddr_in_from_string(const char *ip_str, struct sockaddr_in *out)
+{
+  // [FIXME: add some error checking?]
+  if (!out)
+    out = tor_malloc_zero(sizeof(struct sockaddr_in));
+
+  out->sin_family = AF_INET;
+  out->sin_port = 0;
+  tor_inet_pton(AF_INET,ip_str,&(out->sin_addr));
+
+  return out;
+}
+
+/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure
+ * that points to 127.0.0.1. Otherwise, return 0.
+ */
+static int
+smartlist_contains_localhost_tor_addr(smartlist_t *smartlist)
+{
+  int found_localhost = 0;
+
+  struct sockaddr_in *sockaddr_localhost;
+  struct sockaddr_storage *sockaddr_to_check;
+
+  sockaddr_localhost = sockaddr_in_from_string("127.0.0.1",NULL);
+
+  sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in));
+
+  SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) {
+    tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+                         sizeof(struct sockaddr_in));
+
+    if (sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check,
+                              sockaddr_localhost)) {
+      found_localhost = 1;
+      break;
+    }
+  } SMARTLIST_FOREACH_END(tor_addr);
+
+  tor_free(sockaddr_localhost);
+  tor_free(sockaddr_to_check);
+
+  return found_localhost;
+}
+
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+static void
+test_address_ifaddrs_to_smartlist(void *arg)
+{
+   struct ifaddrs *ifa = NULL;
+   struct ifaddrs *ifa_ipv4 = NULL;
+   struct ifaddrs *ifa_ipv6 = NULL;
+   struct sockaddr_in *ipv4_sockaddr_local = NULL;
+   struct sockaddr_in *netmask_slash8 = NULL;
+   struct sockaddr_in *ipv4_sockaddr_remote = NULL;
+   struct sockaddr_in6 *ipv6_sockaddr = NULL;
+   smartlist_t *smartlist = NULL;
+   tor_addr_t *tor_addr = NULL;
+   struct sockaddr *sockaddr_to_check = NULL;
+   socklen_t addr_len;
+
+   (void)arg;
+
+   netmask_slash8 = sockaddr_in_from_string("255.0.0.0",NULL);
+   ipv4_sockaddr_local = sockaddr_in_from_string("127.0.0.1",NULL);
+   ipv4_sockaddr_remote = sockaddr_in_from_string("128.52.160.20",NULL);
+
+   ipv6_sockaddr = tor_malloc(sizeof(struct sockaddr_in6));
+   ipv6_sockaddr->sin6_family = AF_INET6;
+   ipv6_sockaddr->sin6_port = 0;
+   inet_pton(AF_INET6, "2001:db8:8714:3a90::12",
+             &(ipv6_sockaddr->sin6_addr));
+
+   ifa = tor_malloc(sizeof(struct ifaddrs));
+   ifa_ipv4 = tor_malloc(sizeof(struct ifaddrs));
+   ifa_ipv6 = tor_malloc(sizeof(struct ifaddrs));
+
+   ifa->ifa_next = ifa_ipv4;
+   ifa->ifa_name = tor_strdup("eth0");
+   ifa->ifa_flags = IFF_UP | IFF_RUNNING;
+   ifa->ifa_addr = (struct sockaddr *)ipv4_sockaddr_local;
+   ifa->ifa_netmask = (struct sockaddr *)netmask_slash8;
+   ifa->ifa_dstaddr = NULL;
+   ifa->ifa_data = NULL;
+
+   ifa_ipv4->ifa_next = ifa_ipv6;
+   ifa_ipv4->ifa_name = tor_strdup("eth1");
+   ifa_ipv4->ifa_flags = IFF_UP | IFF_RUNNING;
+   ifa_ipv4->ifa_addr = (struct sockaddr *)ipv4_sockaddr_remote;
+   ifa_ipv4->ifa_netmask = (struct sockaddr *)netmask_slash8;
+   ifa_ipv4->ifa_dstaddr = NULL;
+   ifa_ipv4->ifa_data = NULL;
+
+   ifa_ipv6->ifa_next = NULL;
+   ifa_ipv6->ifa_name = tor_strdup("eth2");
+   ifa_ipv6->ifa_flags = IFF_UP | IFF_RUNNING;
+   ifa_ipv6->ifa_addr = (struct sockaddr *)ipv6_sockaddr;
+   ifa_ipv6->ifa_netmask = NULL;
+   ifa_ipv6->ifa_dstaddr = NULL;
+   ifa_ipv6->ifa_data = NULL;
+
+   smartlist = ifaddrs_to_smartlist(ifa);
+
+   tt_assert(smartlist);
+   tt_assert(smartlist_len(smartlist) == 3);
+
+   sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in6));
+
+   tor_addr = smartlist_get(smartlist,0);
+   addr_len =
+   tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
+                        sizeof(struct sockaddr_in));
+
+   tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+   tt_assert(sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check,
+                                   ipv4_sockaddr_local));
+
+   tor_addr = smartlist_get(smartlist,1);
+   addr_len =
+   tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
+                        sizeof(struct sockaddr_in));
+
+   tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+   tt_assert(sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check,
+                                   ipv4_sockaddr_remote));
+
+   tor_addr = smartlist_get(smartlist,2);
+   addr_len =
+   tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
+                        sizeof(struct sockaddr_in6));
+
+   tt_int_op(addr_len,==,sizeof(struct sockaddr_in6));
+   tt_assert(sockaddr_in6_are_equal((struct sockaddr_in6*)sockaddr_to_check,
+                                    ipv6_sockaddr));
+
+   done:
+   tor_free(netmask_slash8);
+   tor_free(ipv4_sockaddr_local);
+   tor_free(ipv4_sockaddr_remote);
+   tor_free(ipv6_sockaddr);
+   tor_free(ifa);
+   tor_free(ifa_ipv4);
+   tor_free(ifa_ipv6);
+   tor_free(sockaddr_to_check);
+   SMARTLIST_FOREACH(smartlist, tor_addr_t *, t, tor_free(t));
+   smartlist_free(smartlist);
+
+   return;
+}
+
+static void
+test_address_get_if_addrs_ifaddrs(void *arg)
+{
+
+  smartlist_t *results = NULL;
+
+  (void)arg;
+
+  results = get_interface_addresses_ifaddrs(0);
+
+  tt_int_op(smartlist_len(results),>=,1);
+  tt_assert(smartlist_contains_localhost_tor_addr(results));
+
+  done:
+  SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
+  tor_free(results);
+  return;
+}
+
+#endif
+
+#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
+
+static void
+test_address_get_if_addrs_win32(void *arg)
+{
+
+  smartlist_t *results = NULL;
+
+  (void)arg;
+
+  results = get_interface_addresses_win32(0);
+
+  tt_int_op(smartlist_len(results),>=,1);
+  tt_assert(smartlist_contains_localhost_tor_addr(results));
+
+  done:
+  SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
+  tor_free(results);
+  return;
+}
+
+static void
+test_address_ip_adapter_addresses_to_smartlist(void *arg)
+{
+
+  IP_ADAPTER_ADDRESSES *addrs1;
+  IP_ADAPTER_ADDRESSES *addrs2;
+
+  IP_ADAPTER_UNICAST_ADDRESS *unicast11;
+  IP_ADAPTER_UNICAST_ADDRESS *unicast12;
+  IP_ADAPTER_UNICAST_ADDRESS *unicast21;
+
+  smartlist_t *result = NULL;
+
+  struct sockaddr_in *sockaddr_test1;
+  struct sockaddr_in *sockaddr_test2;
+  struct sockaddr_in *sockaddr_localhost;
+  struct sockaddr_in *sockaddr_to_check;
+
+  tor_addr_t *tor_addr;
+
+  (void)arg;
+  (void)sockaddr_in6_are_equal;
+
+  sockaddr_to_check = tor_malloc_zero(sizeof(struct sockaddr_in));
+
+  addrs1 =
+  tor_malloc_zero(sizeof(IP_ADAPTER_ADDRESSES));
+
+  addrs1->FirstUnicastAddress =
+  unicast11 = tor_malloc_zero(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
+  sockaddr_test1 = sockaddr_in_from_string("86.59.30.40",NULL);
+  unicast11->Address.lpSockaddr = (LPSOCKADDR)sockaddr_test1;
+
+  unicast11->Next = unicast12 =
+  tor_malloc_zero(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
+  sockaddr_test2 = sockaddr_in_from_string("93.95.227.222", NULL);
+  unicast12->Address.lpSockaddr = (LPSOCKADDR)sockaddr_test2;
+
+  addrs1->Next = addrs2 =
+  tor_malloc_zero(sizeof(IP_ADAPTER_ADDRESSES));
+
+  addrs2->FirstUnicastAddress =
+  unicast21 = tor_malloc_zero(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
+  sockaddr_localhost = sockaddr_in_from_string("127.0.0.1", NULL);
+  unicast21->Address.lpSockaddr = (LPSOCKADDR)sockaddr_localhost;
+
+  result = ip_adapter_addresses_to_smartlist(addrs1);
+
+  tt_assert(result);
+  tt_assert(smartlist_len(result) == 3);
+
+  tor_addr = smartlist_get(result,0);
+
+  tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+                       sizeof(struct sockaddr_in));
+
+  tt_assert(sockaddr_in_are_equal(sockaddr_test1,sockaddr_to_check));
+
+  tor_addr = smartlist_get(result,1);
+
+  tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+                       sizeof(struct sockaddr_in));
+
+  tt_assert(sockaddr_in_are_equal(sockaddr_test2,sockaddr_to_check));
+
+  tor_addr = smartlist_get(result,2);
+
+  tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+                       sizeof(struct sockaddr_in));
+
+  tt_assert(sockaddr_in_are_equal(sockaddr_localhost,sockaddr_to_check));
+
+  done:
+  SMARTLIST_FOREACH(result, tor_addr_t *, t, tor_free(t));
+  smartlist_free(result);
+  tor_free(addrs1);
+  tor_free(addrs2);
+  tor_free(unicast11->Address.lpSockaddr);
+  tor_free(unicast11);
+  tor_free(unicast12->Address.lpSockaddr);
+  tor_free(unicast12);
+  tor_free(unicast21->Address.lpSockaddr);
+  tor_free(unicast21);
+  tor_free(sockaddr_to_check);
+  return;
+}
+#endif
+
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+
+static void
+test_address_ifreq_to_smartlist(void *arg)
+{
+  smartlist_t *results = NULL;
+  tor_addr_t *tor_addr = NULL;
+  struct sockaddr_in *sockaddr = NULL;
+  struct sockaddr_in *sockaddr_eth1 = NULL;
+  struct sockaddr_in *sockaddr_to_check = NULL;
+
+  struct ifconf *ifc;
+  struct ifreq *ifr;
+  struct ifreq *ifr_next;
+
+  socklen_t addr_len;
+
+  (void)arg;
+
+  sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in));
+
+  ifr = tor_malloc(sizeof(struct ifreq));
+  memset(ifr,0,sizeof(struct ifreq));
+  strlcpy(ifr->ifr_name,"lo",3);
+  sockaddr = (struct sockaddr_in *) &(ifr->ifr_ifru.ifru_addr);
+  sockaddr_in_from_string("127.0.0.1",sockaddr);
+
+  ifc = tor_malloc(sizeof(struct ifconf));
+  memset(ifc,0,sizeof(struct ifconf));
+  ifc->ifc_len = sizeof(struct ifreq);
+  ifc->ifc_ifcu.ifcu_req = ifr;
+
+  results = ifreq_to_smartlist((struct ifreq *)ifc->ifc_buf,ifc->ifc_len);
+  tt_int_op(smartlist_len(results),==,1);
+
+  tor_addr = smartlist_get(results, 0);
+  addr_len =
+  tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+                       sizeof(struct sockaddr_in));
+
+  tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+  tt_assert(sockaddr_in_are_equal(sockaddr,sockaddr_to_check));
+
+  ifr = tor_realloc(ifr,2*sizeof(struct ifreq));
+  ifr_next = ifr+1;
+  strlcpy(ifr_next->ifr_name,"eth1",5);
+  ifc->ifc_len = 2*sizeof(struct ifreq);
+  ifc->ifc_ifcu.ifcu_req = ifr;
+  sockaddr = (struct sockaddr_in *) &(ifr->ifr_ifru.ifru_addr);
+
+  sockaddr_eth1 = (struct sockaddr_in *) &(ifr_next->ifr_ifru.ifru_addr);
+  sockaddr_in_from_string("192.168.10.55",sockaddr_eth1);
+
+  smartlist_free(results);
+
+  results = ifreq_to_smartlist((struct ifreq *)ifc->ifc_buf,ifc->ifc_len);
+  tt_int_op(smartlist_len(results),==,2);
+
+  tor_addr = smartlist_get(results, 0);
+  addr_len =
+  tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+                       sizeof(struct sockaddr_in));
+
+  tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+  tt_assert(sockaddr_in_are_equal(sockaddr,sockaddr_to_check));
+
+  tor_addr = smartlist_get(results, 1);
+  addr_len =
+  tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+                       sizeof(struct sockaddr_in));
+
+  tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+  tt_assert(sockaddr_in_are_equal(sockaddr_eth1,sockaddr_to_check));
+
+  done:
+  tor_free(sockaddr_to_check);
+  smartlist_free(results);
+  tor_free(tor_addr);
+  tor_free(ifc);
+  tor_free(ifr);
+  return;
+}
+
+static void
+test_address_get_if_addrs_ioctl(void *arg)
+{
+
+  smartlist_t *result = NULL;
+
+  (void)arg;
+
+  result = get_interface_addresses_ioctl(LOG_ERR);
+
+  tt_assert(result);
+  tt_int_op(smartlist_len(result),>=,1);
+
+  tt_assert(smartlist_contains_localhost_tor_addr(result));
+
+  done:
+  SMARTLIST_FOREACH(result, tor_addr_t *, t, tor_free(t));
+  smartlist_free(result);
+  return;
+}
+
+#endif
+
+#define ADDRESS_TEST(name, flags) \
+  { #name, test_address_ ## name, flags, NULL, NULL }
+
+struct testcase_t address_tests[] = {
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+  ADDRESS_TEST(get_if_addrs_ifaddrs, TT_FORK),
+  ADDRESS_TEST(ifaddrs_to_smartlist, 0),
+#endif
+#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
+  ADDRESS_TEST(get_if_addrs_win32, TT_FORK),
+  ADDRESS_TEST(ip_adapter_addresses_to_smartlist, 0),
+#endif
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+  ADDRESS_TEST(get_if_addrs_ioctl, TT_FORK),
+  ADDRESS_TEST(ifreq_to_smartlist, 0),
+#endif
+  END_OF_TESTCASES
+};
+





More information about the tor-commits mailing list