Merge branch 'if_addr_refactoring_squashed'

Conflicts:
	src/test/include.am
	src/test/test.c
This commit is contained in:
Nick Mathewson 2015-01-23 10:13:37 -05:00
commit 420037dcef
6 changed files with 698 additions and 65 deletions

11
changes/ticket12376_part2 Normal file
View File

@ -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.

View File

@ -8,6 +8,18 @@
* \brief Functions to use and manipulate the tor_addr_t structure.
**/
#define ADDRESS_PRIVATE
#ifdef _WIN32
/* 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"
@ -16,16 +28,6 @@
#include "container.h"
#include "sandbox.h"
#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 <iphlpapi.h>
#endif
#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)));
}
freeifaddrs(ifa);
return result;
#elif defined(_WIN32)
}
/** 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;
}
/** 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;

View File

@ -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

View File

@ -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 \

View File

@ -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 },

467
src/test/test_address.c Normal file
View File

@ -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
};