diff options
author | Nick Mathewson <nickm@torproject.org> | 2015-01-23 10:13:37 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2015-01-23 10:13:37 -0500 |
commit | 420037dcefade09f43e4a6e44282ed04f9f3ac52 (patch) | |
tree | 18a1f5b09b41cada52537b763740e4b3b39c0b13 | |
parent | 0b121433464804889240a6884179fa4631f0d7b0 (diff) | |
parent | 3966145dff817adb67e5b46020632d55f19e289f (diff) | |
download | tor-420037dcefade09f43e4a6e44282ed04f9f3ac52.tar.gz tor-420037dcefade09f43e4a6e44282ed04f9f3ac52.zip |
Merge branch 'if_addr_refactoring_squashed'
Conflicts:
src/test/include.am
src/test/test.c
-rw-r--r-- | changes/ticket12376_part2 | 11 | ||||
-rw-r--r-- | src/common/address.c | 227 | ||||
-rw-r--r-- | src/common/address.h | 53 | ||||
-rw-r--r-- | src/test/include.am | 1 | ||||
-rw-r--r-- | src/test/test.c | 2 | ||||
-rw-r--r-- | 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 0000000000..13f9bb54dc --- /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 1c3777fa82..3b4be1d601 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 @@ -131,7 +133,7 @@ tor_addr_make_af_unix(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) @@ -1225,26 +1227,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)) @@ -1259,9 +1252,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. @@ -1270,7 +1326,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; @@ -1305,63 +1361,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 d70bb9c508..8c6ee5abbb 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; @@ -241,5 +272,27 @@ MOCK_DECL(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 f07c78b95c..d206033009 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -19,6 +19,7 @@ src_test_test_SOURCES = \ src/test/test.c \ src/test/test_accounting.c \ src/test/test_addr.c \ + src/test/test_address.c \ src/test/test_buffers.c \ src/test/test_cell_formats.c \ src/test/test_cell_queue.c \ diff --git a/src/test/test.c b/src/test/test.c index debee0a059..d752336156 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1296,6 +1296,7 @@ static struct testcase_t test_array[] = { extern struct testcase_t accounting_tests[]; extern struct testcase_t addr_tests[]; +extern struct testcase_t address_tests[]; extern struct testcase_t buffer_tests[]; extern struct testcase_t cell_format_tests[]; extern struct testcase_t cell_queue_tests[]; @@ -1338,6 +1339,7 @@ static struct testgroup_t testgroups[] = { { "", test_array }, { "accounting/", accounting_tests }, { "addr/", addr_tests }, + { "address/", address_tests }, { "buffer/", buffer_tests }, { "cellfmt/", cell_format_tests }, { "cellqueue/", cell_queue_tests }, diff --git a/src/test/test_address.c b/src/test/test_address.c new file mode 100644 index 0000000000..971618dd82 --- /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 +}; + |