From a56511e594b14e8c97605c8e12084a91028d3747 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 26 Apr 2014 16:53:28 +0300 Subject: [PATCH 1/6] Fix a few comments --- src/common/compat.c | 4 ++-- src/common/testsupport.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/compat.c b/src/common/compat.c index c5945fbd22..470e860f52 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -2061,8 +2061,8 @@ get_environment(void) #endif } -/** Set *addr to the IP address (in dotted-quad notation) stored in c. - * Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr), +/** Set *addr to the IP address (in dotted-quad notation) stored in *str. + * Return 1 on success, 0 if *str is badly formatted. (Like inet_aton(str,addr), * but works on Windows and Solaris.) */ int diff --git a/src/common/testsupport.h b/src/common/testsupport.h index 4a4f50b69b..59f7b19a03 100644 --- a/src/common/testsupport.h +++ b/src/common/testsupport.h @@ -20,8 +20,8 @@ * * and implement it as: * - * MOCK_IMPL(void - * writebuf,(size_t n, char *buf) + * MOCK_IMPL(void, + * writebuf,(size_t n, char *buf)) * { * ... * } From 28217b969eec213e7eb01bc8382fb1236eb4bbdd Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 28 Apr 2014 23:20:58 +0300 Subject: [PATCH 2/6] Adding comprehensive test cases for resolve_my_address. Also, improve comments on resolve_my_address to explain what it actually does. --- src/common/address.c | 8 +- src/common/address.h | 5 +- src/common/compat.c | 20 +- src/common/compat.h | 3 +- src/or/config.c | 36 ++- src/test/test_config.c | 569 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 628 insertions(+), 13 deletions(-) diff --git a/src/common/address.c b/src/common/address.c index e5930dedca..c9b5cf4d9b 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -1354,8 +1354,8 @@ tor_addr_is_multicast(const tor_addr_t *a) * connects to the Internet. This address should only be used in checking * whether our address has changed. Return 0 on success, -1 on failure. */ -int -get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr) +MOCK_IMPL(int, +get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) { /* XXX really, this function should yield a smartlist of addresses. */ smartlist_t *addrs; @@ -1684,8 +1684,8 @@ tor_dup_ip(uint32_t addr) * checking whether our address has changed. Return 0 on success, -1 on * failure. */ -int -get_interface_address(int severity, uint32_t *addr) +MOCK_IMPL(int, +get_interface_address,(int severity, uint32_t *addr)) { tor_addr_t local_addr; int r; diff --git a/src/common/address.h b/src/common/address.h index 8dc63b71c1..ecb7adcf52 100644 --- a/src/common/address.h +++ b/src/common/address.h @@ -148,7 +148,8 @@ char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC; const char *fmt_addr_impl(const tor_addr_t *addr, int decorate); const char *fmt_addrport(const tor_addr_t *addr, uint16_t port); const char * fmt_addr32(uint32_t addr); -int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr); +MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family, +tor_addr_t *addr)); /** Flag to specify how to do a comparison between addresses. In an "exact" * comparison, addresses are equivalent only if they are in the same family @@ -225,7 +226,7 @@ int addr_mask_get_bits(uint32_t mask); #define INET_NTOA_BUF_LEN 16 int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); char *tor_dup_ip(uint32_t addr) ATTR_MALLOC; -int get_interface_address(int severity, uint32_t *addr); +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); diff --git a/src/common/compat.c b/src/common/compat.c index 470e860f52..9b040f1877 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -2061,9 +2061,20 @@ get_environment(void) #endif } +/** Get name of current host and write it to name array, whose + * length is specified by namelen argument. Return 0 upon + * successfull completion; otherwise return return -1. (Currently, + * this function is merely a mockable wrapper for POSIX gethostname().) + */ +MOCK_IMPL(int, +tor_gethostname,(char *name, size_t namelen)) +{ + return gethostname(name,namelen); +} + /** Set *addr to the IP address (in dotted-quad notation) stored in *str. - * Return 1 on success, 0 if *str is badly formatted. (Like inet_aton(str,addr), - * but works on Windows and Solaris.) + * Return 1 on success, 0 if *str is badly formatted. + * (Like inet_aton(str,addr), but works on Windows and Solaris.) */ int tor_inet_aton(const char *str, struct in_addr* addr) @@ -2281,8 +2292,9 @@ tor_inet_pton(int af, const char *src, void *dst) * (This function exists because standard windows gethostbyname * doesn't treat raw IP addresses properly.) */ -int -tor_lookup_hostname(const char *name, uint32_t *addr) + +MOCK_IMPL(int, +tor_lookup_hostname,(const char *name, uint32_t *addr)) { tor_addr_t myaddr; int ret; diff --git a/src/common/compat.h b/src/common/compat.h index 9a381fb97f..4e614c0580 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -537,10 +537,11 @@ struct sockaddr_in6 { }; #endif +MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen)); int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2)); const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); int tor_inet_pton(int af, const char *src, void *dst); -int tor_lookup_hostname(const char *name, uint32_t *addr) ATTR_NONNULL((1,2)); +MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr)); int set_socket_nonblocking(tor_socket_t socket); int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]); int network_init(void); diff --git a/src/or/config.c b/src/or/config.c index a5407dd4ea..e0a2460685 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -11,6 +11,7 @@ #define CONFIG_PRIVATE #include "or.h" +#include "compat.h" #include "addressmap.h" #include "channel.h" #include "circuitbuild.h" @@ -2051,7 +2052,33 @@ get_last_resolved_addr(void) } /** - * Use options-\>Address to guess our public IP address. + * Attempt getting our non-local (as judged by tor_addr_is_internal() + * function) IP address using following techniques, listed in + * order from best (most desirable, try first) to worst (least + * desirable, try if everything else fails). + * + * First, attempt using options-\>Address to get our + * non-local IP address. + * + * If options-\>Address represents a non-local IP address, + * consider it ours. + * + * If options-\>Address is a DNS name that resolves to + * a non-local IP address, consider this IP address ours. + * + * If options-\>Address is NULL, fall back to getting local + * hostname and using it in above-described ways to try and + * get our IP address. + * + * In case local hostname cannot be resolved to a non-local IP + * address, try getting an IP address of network interface + * in hopes it will be non-local one. + * + * Fail if one or more of the following is true: + * - DNS name in options-\>Address cannot be resolved. + * - options-\>Address is a local host address. + * - Attempt to getting local hostname fails. + * - Attempt to getting network interface address fails. * * Return 0 if all is well, or -1 if we can't find a suitable * public IP address. @@ -2060,6 +2087,11 @@ get_last_resolved_addr(void) * - Put our public IP address (in host order) into *addr_out. * - If method_out is non-NULL, set *method_out to a static * string describing how we arrived at our answer. + * - "CONFIGURED" - parsed from IP address string in + * options-\>Address + * - "RESOLVED" - resolved from DNS name in options-\>Address + * - "GETHOSTNAME" - resolved from a local hostname. + * - "INTERFACE" - retrieved from a network interface. * - If hostname_out is non-NULL, and we resolved a hostname to * get our address, set *hostname_out to a newly allocated string * holding that hostname. (If we didn't get our address by resolving a @@ -2098,7 +2130,7 @@ resolve_my_address(int warn_severity, const or_options_t *options, explicit_ip = 0; /* it's implicit */ explicit_hostname = 0; /* it's implicit */ - if (gethostname(hostname, sizeof(hostname)) < 0) { + if (tor_gethostname(hostname, sizeof(hostname)) < 0) { log_fn(warn_severity, LD_NET,"Error obtaining local hostname"); return -1; } diff --git a/src/test/test_config.c b/src/test/test_config.c index dbb50798b8..fa68129126 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -578,10 +578,579 @@ test_config_fix_my_family(void *arg) or_options_free(defaults); } +static int n_hostname_01010101 = 0; + +/** This mock function is meant to replace tor_lookup_hostname(). + * It answers with 1.1.1.1 as IP adddress that resulted from lookup. + * This function increments n_hostname_01010101 counter by one + * every time it is called. + */ +static int +tor_lookup_hostname_01010101(const char *name, uint32_t *addr) +{ + n_hostname_01010101++; + + if (name && addr) { + *addr = ntohl(0x01010101); + } + + return 0; +} + +static int n_hostname_localhost = 0; + +/** This mock function is meant to replace tor_lookup_hostname(). + * It answers with 127.0.0.1 as IP adddress that resulted from lookup. + * This function increments n_hostname_localhost counter by one + * every time it is called. + */ +static int +tor_lookup_hostname_localhost(const char *name, uint32_t *addr) +{ + n_hostname_localhost++; + + if (name && addr) { + *addr = 0x7f000001; + } + + return 0; +} + +static int n_hostname_failure = 0; + +/** This mock function is meant to replace tor_lookup_hostname(). + * It pretends to fail by returning -1 to caller. Also, this function + * increments n_hostname_failure every time it is called. + */ +static int +tor_lookup_hostname_failure(const char *name, uint32_t *addr) +{ + (void)name; + (void)addr; + + n_hostname_failure++; + + return -1; +} + +static int n_gethostname_replacement = 0; + +/** This mock function is meant to replace tor_gethostname(). It + * responds with string "onionrouter" as hostname. This function + * increments n_gethostname_replacement by one every time + * it is called. + */ +static int +tor_gethostname_replacement(char *name, size_t namelen) +{ + n_gethostname_replacement++; + + if (name && namelen) { + strlcpy(name,"onionrouter",namelen); + } + + return 0; +} + +static int n_gethostname_localhost = 0; + +/** This mock function is meant to replace tor_gethostname(). It + * responds with string "127.0.0.1" as hostname. This function + * increments n_gethostname_localhost by one every time + * it is called. + */ +static int +tor_gethostname_localhost(char *name, size_t namelen) +{ + n_gethostname_localhost++; + + if (name && namelen) { + strlcpy(name,"127.0.0.1",namelen); + } + + return 0; +} + +static int n_gethostname_failure = 0; + +/** This mock function is meant to replace tor_gethostname. + * It pretends to fail by returning -1. This function increments + * n_gethostname_failure by one every time it is called. + */ +static int +tor_gethostname_failure(char *name, size_t namelen) +{ + n_gethostname_failure++; + + return -1; +} + +static int n_get_interface_address = 0; + +/** This mock function is meant to replace get_interface_address(). + * It answers with address 8.8.8.8. This function increments + * n_get_interface_address by one every time it is called. + */ +static int +get_interface_address_08080808(int severity, uint32_t *addr) +{ + (void)severity; + + n_get_interface_address++; + + if (addr) { + *addr = ntohl(0x08080808); + } + + return 0; +} + +static int n_get_interface_address6 = 0; +static sa_family_t last_address6_family; + +/** This mock function is meant to replace get_interface_address6(). + * It answers with IP address 9.9.9.9 iff both of the following are true: + * - family is AF_INET + * - addr pointer is not NULL. + * This function increments n_get_interface_address6 by one every + * time it is called. + */ +static int +get_interface_address6_replacement(int severity, sa_family_t family, + tor_addr_t *addr) +{ + (void)severity; + + last_address6_family = family; + n_get_interface_address6++; + + if ((family != AF_INET) || !addr) { + return -1; + } + + tor_addr_from_ipv4h(addr,0x09090909); + + return 0; +} + +static int n_get_interface_address_failure = 0; + +/** + * This mock function is meant to replace get_interface_address(). + * It pretends to fail getting interface address by returning -1. + * n_get_interface_address_failure is incremented by one + * every time this function is called. + */ +static int +get_interface_address_failure(int severity, uint32_t *addr) +{ + (void)severity; + (void)addr; + + n_get_interface_address_failure++; + + return -1; +} + +static int n_get_interface_address6_failure = 0; + +/** + * This mock function is meant to replace get_interface_addres6(). + * It will pretent to fail by return -1. + * n_get_interface_address6_failure is incremented by one + * every time this function is called and last_address6_family + * is assigned the value of family argument. + */ +static int +get_interface_address6_failure(int severity, sa_family_t family, + tor_addr_t *addr) +{ + n_get_interface_address6_failure++; + last_address6_family = family; + + return -1; +} + +static void +test_config_resolve_my_address(void *arg) +{ + (void)arg; + + or_options_t *options; + uint32_t resolved_addr; + const char *method_used; + char *hostname_out; + int retval; + int prev_n_hostname_01010101; + int prev_n_hostname_localhost; + int prev_n_hostname_failure; + int prev_n_gethostname_replacement; + int prev_n_gethostname_failure; + int prev_n_gethostname_localhost; + int prev_n_get_interface_address; + int prev_n_get_interface_address_failure; + int prev_n_get_interface_address6; + int prev_n_get_interface_address6_failure; + + options = options_new(); + + options_init(options); + + /* + * CASE 1: + * If options->Address is a valid IPv4 address string, we want + * the corresponding address to be parsed and returned. + */ + + options->Address = tor_strdup("128.52.128.105"); + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(retval == 0); + tt_want_str_op(method_used,==,"CONFIGURED"); + tt_want(hostname_out == NULL); + tt_assert(htonl(resolved_addr) == 0x69803480); + + tor_free(options->Address); + +/* + * CASE 2: + * If options->Address is a valid DNS address, we want resolve_my_address() + * function to ask tor_lookup_hostname() for help with resolving it + * and return the address that was resolved (in host order). + */ + + MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101); + + tor_free(options->Address); + options->Address = tor_strdup("www.torproject.org"); + + prev_n_hostname_01010101 = n_hostname_01010101; + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(retval == 0); + tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1); + tt_want_str_op(method_used,==,"RESOLVED"); + tt_want_str_op(hostname_out,==,"www.torproject.org"); + tt_assert(htonl(resolved_addr) == 0x01010101); + + UNMOCK(tor_lookup_hostname); + + tor_free(options->Address); + +/* + * CASE 3: + * Given that options->Address is NULL, we want resolve_my_address() + * to try and use tor_gethostname() to get hostname AND use + * tor_lookup_hostname() to get IP address. + */ + + resolved_addr = 0; + tor_free(options->Address); + options->Address = NULL; + + MOCK(tor_gethostname,tor_gethostname_replacement); + MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_hostname_01010101 = n_hostname_01010101; + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(retval == 0); + tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1); + tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1); + tt_want_str_op(method_used,==,"GETHOSTNAME"); + tt_want_str_op(hostname_out,==,"onionrouter"); + tt_assert(htonl(resolved_addr) == 0x01010101); + + UNMOCK(tor_gethostname); + UNMOCK(tor_lookup_hostname); + +/* + * CASE 4: + * Given that options->Address is a local host address, we want + * resolve_my_address() function to fail. + */ + + resolved_addr = 0; + tor_free(options->Address); + options->Address = tor_strdup("127.0.0.1"); + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(resolved_addr == 0); + tt_assert(retval == -1); + + tor_free(options->Address); + +/* + * CASE 5: + * We want resolve_my_address() to fail if DNS address in options->Address + * cannot be resolved. + */ + + MOCK(tor_lookup_hostname,tor_lookup_hostname_failure); + + prev_n_hostname_failure = n_hostname_failure; + + tor_free(options->Address); + options->Address = tor_strdup("www.tor-project.org"); + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(n_hostname_failure == prev_n_hostname_failure + 1); + tt_assert(retval == -1); + + UNMOCK(tor_lookup_hostname); + + tor_free(options->Address); + options->Address = NULL; + +/* + * CASE 6: + * If options->Address is NULL AND gettting local hostname fails, we want + * resolve_my_address() to fail as well. + */ + + MOCK(tor_gethostname,tor_gethostname_failure); + + prev_n_gethostname_failure = n_gethostname_failure; + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(n_gethostname_failure == prev_n_gethostname_failure + 1); + tt_assert(retval == -1); + + UNMOCK(tor_gethostname); + +/* + * CASE 7: + * We want resolve_my_address() to try and get network interface address via + * get_interface_address() if hostname returned by tor_gethostname() cannot be + * resolved into IP address. + */ + + MOCK(tor_gethostname,tor_gethostname_replacement); + MOCK(get_interface_address,get_interface_address_08080808); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_get_interface_address = n_get_interface_address; + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(retval == 0); + tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1); + tt_want(n_get_interface_address == prev_n_get_interface_address + 1); + tt_want_str_op(method_used,==,"INTERFACE"); + tt_want(hostname_out == NULL); + tt_assert(resolved_addr == ntohl(0x08080808)); + + UNMOCK(get_interface_address); + +/* + * CASE 8: + * Suppose options->Address is NULL AND hostname returned by tor_gethostname() + * is unresolvable. We want resolve_my_address to fail if + * get_interface_address() fails. + */ + + MOCK(get_interface_address,get_interface_address_failure); + + prev_n_get_interface_address_failure = n_get_interface_address_failure; + prev_n_gethostname_replacement = n_gethostname_replacement; + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(n_get_interface_address_failure == + prev_n_get_interface_address_failure + 1); + tt_want(n_gethostname_replacement == + prev_n_gethostname_replacement + 1); + tt_assert(retval == -1); + + UNMOCK(get_interface_address); + +/* + * CASE 9: + * Given that options->Address is NULL AND tor_lookup_hostname() + * fails AND hostname returned by gethostname() resolves + * to local IP address, we want resolve_my_address() function to + * call get_interface_address6(.,AF_INET,.) and return IP address + * the latter function has found. + */ + + MOCK(tor_lookup_hostname,tor_lookup_hostname_failure); + MOCK(tor_gethostname,tor_gethostname_replacement); + MOCK(get_interface_address6,get_interface_address6_replacement); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_hostname_failure = n_hostname_failure; + prev_n_get_interface_address6 = n_get_interface_address6; + + retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr, + &method_used,&hostname_out); + + tt_want(last_address6_family == AF_INET); + tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1); + tt_want(n_hostname_failure == prev_n_hostname_failure + 1); + tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1); + tt_want(retval == 0); + tt_want_str_op(method_used,==,"INTERFACE"); + tt_assert(htonl(resolved_addr) == 0x09090909); + + UNMOCK(tor_lookup_hostname); + UNMOCK(tor_gethostname); + UNMOCK(get_interface_address6); + + /* + * CASE 10: We want resolve_my_address() to fail if all of the following + * are true: + * 1. options->Address is not NULL + * 2. ... but it cannot be converted to struct in_addr by + * tor_inet_aton() + * 3. ... and tor_lookup_hostname() fails to resolve the + * options->Address + */ + + MOCK(tor_lookup_hostname,tor_lookup_hostname_failure); + + prev_n_hostname_failure = n_hostname_failure; + + tor_free(options->Address); + options->Address = tor_strdup("some_hostname"); + + retval = resolve_my_address(LOG_NOTICE, options, &resolved_addr, + &method_used,&hostname_out); + + tt_want(n_hostname_failure == prev_n_hostname_failure + 1); + tt_assert(retval == -1); + + UNMOCK(tor_gethostname); + UNMOCK(tor_lookup_hostname); + + /* + * CASE 11: + * Suppose the following sequence of events: + * 1. options->Address is NULL + * 2. tor_gethostname() succeeds to get hostname of machine Tor + * if running on. + * 3. Hostname from previous step cannot be converted to + * address by using tor_inet_aton() function. + * 4. However, tor_lookup_hostname() succeds in resolving the + * hostname from step 2. + * 5. Unfortunately, tor_addr_is_internal() deems this address + * to be internal. + * 6. get_interface_address6(.,AF_INET,.) returns non-internal + * IPv4 + * + * We want resolve_my_addr() to succeed with method "INTERFACE" + * and address from step 6. + */ + + tor_free(options->Address); + options->Address = NULL; + + MOCK(tor_gethostname,tor_gethostname_replacement); + MOCK(tor_lookup_hostname,tor_lookup_hostname_localhost); + MOCK(get_interface_address6,get_interface_address6_replacement); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_hostname_localhost = n_hostname_localhost; + prev_n_get_interface_address6 = n_get_interface_address6; + + retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr, + &method_used,&hostname_out); + + tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1); + tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1); + tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1); + + tt_str_op(method_used,==,"INTERFACE"); + tt_assert(!hostname_out); + tt_assert(retval == 0); + + /* + * CASE 11b: + * 1-5 as above. + * 6. get_interface_address6() fails. + * + * In this subcase, we want resolve_my_address() to fail. + */ + + UNMOCK(get_interface_address6); + MOCK(get_interface_address6,get_interface_address6_failure); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_hostname_localhost = n_hostname_localhost; + prev_n_get_interface_address6_failure = n_get_interface_address6_failure; + + retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr, + &method_used,&hostname_out); + + tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1); + tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1); + tt_want(n_get_interface_address6_failure == + prev_n_get_interface_address6_failure + 1); + + tt_assert(retval == -1); + + UNMOCK(tor_gethostname); + UNMOCK(tor_lookup_hostname); + UNMOCK(get_interface_address6); + + /* CASE 12: + * Suppose the following happens: + * 1. options->Address is NULL AND options->DirAuthorities is 1. + * 2. tor_gethostname() succeeds in getting hostname of a machine ... + * 3. ... which is successfully parsed by tor_inet_aton() ... + * 4. into IPv4 address that tor_addr_is_inernal() considers to be + * internal. + * + * In this case, we want resolve_my_address() to fail. + */ + + tor_free(options->Address); + options->Address = NULL; + options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t)); + + MOCK(tor_gethostname,tor_gethostname_localhost); + + prev_n_gethostname_localhost = n_gethostname_localhost; + + retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr, + &method_used,&hostname_out); + + tt_want(n_gethostname_localhost == prev_n_gethostname_localhost + 1); + tt_assert(retval == -1); + + UNMOCK(tor_gethostname); + + done: + tor_free(options->Address); + tor_free(options->DirAuthorities); + or_options_free(options); + + UNMOCK(tor_gethostname); + UNMOCK(tor_lookup_hostname); + UNMOCK(get_interface_address); + UNMOCK(get_interface_address6); + UNMOCK(tor_gethostname); +} + #define CONFIG_TEST(name, flags) \ { #name, test_config_ ## name, flags, NULL, NULL } struct testcase_t config_tests[] = { + CONFIG_TEST(resolve_my_address, TT_FORK), CONFIG_TEST(addressmap, 0), CONFIG_TEST(parse_bridge_line, 0), CONFIG_TEST(parse_transport_options_line, 0), From c07747be2e5bd4b9311c260b49f4007975138005 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 29 Dec 2014 09:29:32 -0500 Subject: [PATCH 3/6] Fix compilation errors in resolvemyaddr tests --- src/test/test_config.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/test_config.c b/src/test/test_config.c index fa68129126..4217720174 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -680,6 +680,8 @@ static int n_gethostname_failure = 0; static int tor_gethostname_failure(char *name, size_t namelen) { + (void)name; + (void)namelen; n_gethostname_failure++; return -1; @@ -765,6 +767,8 @@ static int get_interface_address6_failure(int severity, sa_family_t family, tor_addr_t *addr) { + (void)severity; + (void)addr; n_get_interface_address6_failure++; last_address6_family = family; @@ -774,8 +778,6 @@ get_interface_address6_failure(int severity, sa_family_t family, static void test_config_resolve_my_address(void *arg) { - (void)arg; - or_options_t *options; uint32_t resolved_addr; const char *method_used; @@ -792,6 +794,8 @@ test_config_resolve_my_address(void *arg) int prev_n_get_interface_address6; int prev_n_get_interface_address6_failure; + (void)arg; + options = options_new(); options_init(options); From 3538dfc91fa34c1cf4e34a334c76de65883bbc0e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 29 Dec 2014 09:33:36 -0500 Subject: [PATCH 4/6] Fix memory leaks in resolvemyaddr tests --- src/test/test_config.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/test/test_config.c b/src/test/test_config.c index 4217720174..b9a0672aba 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -781,7 +781,7 @@ test_config_resolve_my_address(void *arg) or_options_t *options; uint32_t resolved_addr; const char *method_used; - char *hostname_out; + char *hostname_out = NULL; int retval; int prev_n_hostname_01010101; int prev_n_hostname_localhost; @@ -844,6 +844,7 @@ test_config_resolve_my_address(void *arg) UNMOCK(tor_lookup_hostname); tor_free(options->Address); + tor_free(hostname_out); /* * CASE 3: @@ -875,6 +876,8 @@ test_config_resolve_my_address(void *arg) UNMOCK(tor_gethostname); UNMOCK(tor_lookup_hostname); + tor_free(hostname_out); + /* * CASE 4: * Given that options->Address is a local host address, we want @@ -892,6 +895,7 @@ test_config_resolve_my_address(void *arg) tt_assert(retval == -1); tor_free(options->Address); + tor_free(hostname_out); /* * CASE 5: @@ -915,7 +919,7 @@ test_config_resolve_my_address(void *arg) UNMOCK(tor_lookup_hostname); tor_free(options->Address); - options->Address = NULL; + tor_free(hostname_out); /* * CASE 6: @@ -934,6 +938,8 @@ test_config_resolve_my_address(void *arg) tt_assert(retval == -1); UNMOCK(tor_gethostname); + tor_free(hostname_out); + /* * CASE 7: @@ -959,6 +965,7 @@ test_config_resolve_my_address(void *arg) tt_assert(resolved_addr == ntohl(0x08080808)); UNMOCK(get_interface_address); + tor_free(hostname_out); /* * CASE 8: @@ -982,6 +989,7 @@ test_config_resolve_my_address(void *arg) tt_assert(retval == -1); UNMOCK(get_interface_address); + tor_free(hostname_out); /* * CASE 9: @@ -1015,6 +1023,8 @@ test_config_resolve_my_address(void *arg) UNMOCK(tor_gethostname); UNMOCK(get_interface_address6); + tor_free(hostname_out); + /* * CASE 10: We want resolve_my_address() to fail if all of the following * are true: @@ -1041,6 +1051,8 @@ test_config_resolve_my_address(void *arg) UNMOCK(tor_gethostname); UNMOCK(tor_lookup_hostname); + tor_free(hostname_out); + /* * CASE 11: * Suppose the following sequence of events: @@ -1138,10 +1150,11 @@ test_config_resolve_my_address(void *arg) UNMOCK(tor_gethostname); - done: + done: tor_free(options->Address); tor_free(options->DirAuthorities); or_options_free(options); + tor_free(hostname_out); UNMOCK(tor_gethostname); UNMOCK(tor_lookup_hostname); From feed26d037608a3a40c1f4fd8450ea59f0091321 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 29 Dec 2014 09:41:37 -0500 Subject: [PATCH 5/6] Make the resolvemyaddr unit tests pass when local dns is hijacked If you are in a coffee shop that returns a helpful redirect page for "onionrouter", or on an ISP that does the same, the test as written would fail. --- src/test/test_config.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/test/test_config.c b/src/test/test_config.c index b9a0672aba..f8161b1c58 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -636,7 +636,7 @@ tor_lookup_hostname_failure(const char *name, uint32_t *addr) static int n_gethostname_replacement = 0; /** This mock function is meant to replace tor_gethostname(). It - * responds with string "onionrouter" as hostname. This function + * responds with string "onionrouter!" as hostname. This function * increments n_gethostname_replacement by one every time * it is called. */ @@ -646,7 +646,7 @@ tor_gethostname_replacement(char *name, size_t namelen) n_gethostname_replacement++; if (name && namelen) { - strlcpy(name,"onionrouter",namelen); + strlcpy(name,"onionrouter!",namelen); } return 0; @@ -870,7 +870,7 @@ test_config_resolve_my_address(void *arg) tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1); tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1); tt_want_str_op(method_used,==,"GETHOSTNAME"); - tt_want_str_op(hostname_out,==,"onionrouter"); + tt_want_str_op(hostname_out,==,"onionrouter!"); tt_assert(htonl(resolved_addr) == 0x01010101); UNMOCK(tor_gethostname); @@ -949,6 +949,7 @@ test_config_resolve_my_address(void *arg) */ MOCK(tor_gethostname,tor_gethostname_replacement); + MOCK(tor_lookup_hostname,tor_lookup_hostname_failure); MOCK(get_interface_address,get_interface_address_08080808); prev_n_gethostname_replacement = n_gethostname_replacement; @@ -958,8 +959,10 @@ test_config_resolve_my_address(void *arg) &method_used,&hostname_out); tt_want(retval == 0); - tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1); - tt_want(n_get_interface_address == prev_n_get_interface_address + 1); + tt_want_int_op(n_gethostname_replacement, ==, + prev_n_gethostname_replacement + 1); + tt_want_int_op(n_get_interface_address, ==, + prev_n_get_interface_address + 1); tt_want_str_op(method_used,==,"INTERFACE"); tt_want(hostname_out == NULL); tt_assert(resolved_addr == ntohl(0x08080808)); From de432d55657ee124bce0e9a4d5f5842088e2e13b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 29 Dec 2014 09:44:28 -0500 Subject: [PATCH 6/6] changes file for resolvemyaddr tests --- changes/resolvemyaddr-tests | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/resolvemyaddr-tests diff --git a/changes/resolvemyaddr-tests b/changes/resolvemyaddr-tests new file mode 100644 index 0000000000..c019bb831e --- /dev/null +++ b/changes/resolvemyaddr-tests @@ -0,0 +1,3 @@ + o Testing: + - Add unit tests for resolve_my_addr(). Part of ticket 12376; + patch by 'rl1987'.