diff options
author | rl1987 <rl1987@sdf.lonestar.org> | 2014-05-24 15:03:14 +0300 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2015-01-23 10:07:17 -0500 |
commit | 3966145dff817adb67e5b46020632d55f19e289f (patch) | |
tree | 2dc45c468a33e3f5c661890b074830497e9c04be | |
parent | fef65fa64341fb70df0e7b34d91d3b08a74e7aad (diff) | |
download | tor-3966145dff817adb67e5b46020632d55f19e289f.tar.gz tor-3966145dff817adb67e5b46020632d55f19e289f.zip |
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.
-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 2825b123da..7b4584f157 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 8dc63b71c1..934c3f5005 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 fba439a616..371f06326e 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 c96b396599..ed3013ce14 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 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 +}; + |