commit fe6b049651c3b3e968e339756e621815f4ae702c Author: David Goulet dgoulet@torproject.org Date: Tue Jun 30 10:22:01 2020 -0400
test: Unit tests for find_my_address() IPv6
Signed-off-by: David Goulet dgoulet@torproject.org --- src/test/test_config.c | 415 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+)
diff --git a/src/test/test_config.c b/src/test/test_config.c index fe102eea9..616145667 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -1004,7 +1004,13 @@ tor_addr_lookup_01010101(const char *name, uint16_t family, tor_addr_t *addr) if (name && addr) { tor_addr_from_ipv4h(addr, 0x01010101); } + } else if (family == AF_INET6) { + if (name && addr) { + int ret = tor_addr_parse(addr, "0101::0101"); + tt_int_op(ret, OP_EQ, AF_INET6); + } } + done: return 0; }
@@ -1024,7 +1030,13 @@ tor_addr_lookup_localhost(const char *name, uint16_t family, tor_addr_t *addr) if (name && addr) { tor_addr_from_ipv4h(addr, 0x7f000001); } + } else if (family == AF_INET6) { + if (name && addr) { + int ret = tor_addr_parse(addr, "::1"); + tt_int_op(ret, OP_EQ, AF_INET6); + } } + done: return 0; }
@@ -1119,7 +1131,13 @@ get_interface_address6_08080808(int severity, sa_family_t family, if (addr) { tor_addr_from_ipv4h(addr, 0x08080808); } + } else if (family == AF_INET6) { + if (addr) { + int ret = tor_addr_parse(addr, "0808::0808"); + tt_int_op(ret, OP_EQ, AF_INET6); + } } + done: return 0; }
@@ -1169,6 +1187,402 @@ get_interface_address6_failure(int severity, sa_family_t family, return -1; }
+static void +test_config_find_my_address_v6(void *arg) +{ + or_options_t *options; + tor_addr_t resolved_addr, test_addr; + const char *method_used; + char *hostname_out = NULL; + bool 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_address6; + int prev_n_get_interface_address6_failure; + + (void)arg; + + options = options_new(); + + options_init(options); + + /* + * CASE 1: + * If options->Address is a valid IPv6 address string, we want + * the corresponding address to be parsed and returned. + */ + config_line_append(&options->Address, "Address", + "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19"); + tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19"); + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(retval == true); + tt_want_str_op(method_used, OP_EQ, "CONFIGURED"); + tt_want(hostname_out == NULL); + tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); + + config_free_lines(options->Address); + + /* + * CASE 2: + * If options->Address is a valid DNS address, we want find_my_address() + * function to ask tor_addr_lookup() for help with resolving it + * and return the address that was resolved (in host order). + */ + + MOCK(tor_addr_lookup, tor_addr_lookup_01010101); + + config_line_append(&options->Address, "Address", "www.torproject.org"); + tor_addr_parse(&test_addr, "0101::0101"); + + prev_n_hostname_01010101 = n_hostname_01010101; + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(retval == true); + tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1); + tt_want_str_op(method_used, OP_EQ, "RESOLVED"); + tt_want_str_op(hostname_out, OP_EQ, "www.torproject.org"); + tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); + + UNMOCK(tor_addr_lookup); + + config_free_lines(options->Address); + tor_free(hostname_out); + + /* + * CASE 3: + * Given that options->Address is NULL, we want find_my_address() + * to try and use tor_gethostname() to get hostname AND use + * tor_addr_lookup() to get IP address. + */ + + tor_addr_make_unspec(&resolved_addr); + options->Address = NULL; + tor_addr_parse(&test_addr, "0101::0101"); + + MOCK(tor_gethostname, tor_gethostname_replacement); + MOCK(tor_addr_lookup, tor_addr_lookup_01010101); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_hostname_01010101 = n_hostname_01010101; + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(retval == true); + 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, OP_EQ, "GETHOSTNAME"); + tt_want_str_op(hostname_out, OP_EQ, "onionrouter!"); + tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); + + UNMOCK(tor_gethostname); + UNMOCK(tor_addr_lookup); + + tor_free(hostname_out); + + /* + * CASE 4: + * Given that options->Address is a local host address, we want + * find_my_address() function to fail. + */ + + tor_addr_make_unspec(&resolved_addr); + config_line_append(&options->Address, "Address", "::1"); + tor_addr_parse(&test_addr, "::1"); + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(tor_addr_is_null(&resolved_addr) == 1); + tt_want(retval == false); + + config_free_lines(options->Address); + tor_free(hostname_out); + + /* + * CASE 5: + * We want find_my_address() to fail if DNS address in options->Address + * cannot be resolved. + */ + + MOCK(tor_addr_lookup, tor_addr_lookup_failure); + + prev_n_hostname_failure = n_hostname_failure; + + config_line_append(&options->Address, "Address", "www.tor-project.org"); + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(n_hostname_failure == prev_n_hostname_failure + 1); + tt_want(tor_addr_is_null(&resolved_addr) == 1); + tt_want(retval == false); + + UNMOCK(tor_addr_lookup); + + config_free_lines(options->Address); + options->Address = NULL; + tor_free(hostname_out); + + /* + * CASE 6: + * If options->Address is NULL AND gettting local hostname fails, we want + * find_my_address() to fail as well. + */ + + MOCK(tor_gethostname,tor_gethostname_failure); + + prev_n_gethostname_failure = n_gethostname_failure; + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(n_gethostname_failure == prev_n_gethostname_failure + 1); + tt_want(tor_addr_is_null(&resolved_addr) == 1); + tt_want(retval == false); + + UNMOCK(tor_gethostname); + tor_free(hostname_out); + + /* + * CASE 7: + * We want find_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(tor_addr_lookup, tor_addr_lookup_failure); + MOCK(get_interface_address6, get_interface_address6_08080808); + + tor_addr_parse(&test_addr, "0808::0808"); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_get_interface_address6 = n_get_interface_address6; + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(retval == true); + tt_want_int_op(n_gethostname_replacement, OP_EQ, + prev_n_gethostname_replacement + 1); + tt_want_int_op(n_get_interface_address6, OP_EQ, + prev_n_get_interface_address6 + 1); + tt_want_str_op(method_used, OP_EQ, "INTERFACE"); + tt_want(hostname_out == NULL); + tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); + + UNMOCK(get_interface_address); + tor_free(hostname_out); + + /* + * CASE 8: + * Suppose options->Address is NULL AND hostname returned by + * tor_gethostname() is unresolvable. We want find_my_address to fail if + * get_interface_address() fails. + */ + + MOCK(get_interface_address6, get_interface_address6_failure); + + prev_n_get_interface_address6_failure = n_get_interface_address6_failure; + prev_n_gethostname_replacement = n_gethostname_replacement; + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(n_get_interface_address6_failure == + prev_n_get_interface_address6_failure + 1); + tt_want(n_gethostname_replacement == + prev_n_gethostname_replacement + 1); + tt_want(retval == false); + + UNMOCK(get_interface_address); + tor_free(hostname_out); + + /* + * CASE 9: + * Given that options->Address is NULL AND tor_addr_lookup() + * fails AND hostname returned by gethostname() resolves + * to local IP address, we want find_my_address() function to + * call get_interface_address6(.,AF_INET6,.) and return IP address + * the latter function has found. + */ + + MOCK(tor_addr_lookup, tor_addr_lookup_failure); + MOCK(tor_gethostname, tor_gethostname_replacement); + MOCK(get_interface_address6, get_interface_address6_08080808); + + tor_addr_parse(&test_addr, "0808::0808"); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_hostname_failure = n_hostname_failure; + prev_n_get_interface_address6 = n_get_interface_address6; + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(last_address6_family == AF_INET6); + 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 == true); + tt_want_str_op(method_used, OP_EQ, "INTERFACE"); + tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); + + UNMOCK(tor_addr_lookup); + UNMOCK(tor_gethostname); + UNMOCK(get_interface_address6); + + tor_free(hostname_out); + + /* + * CASE 10: We want find_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_addr_lookup() fails to resolve the + * options->Address + */ + + MOCK(tor_addr_lookup, tor_addr_lookup_failure); + + prev_n_hostname_failure = n_hostname_failure; + + config_line_append(&options->Address, "Address", "some_hostname"); + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_want(n_hostname_failure == prev_n_hostname_failure + 1); + tt_want(retval == false); + + UNMOCK(tor_gethostname); + UNMOCK(tor_addr_lookup); + + tor_free(hostname_out); + + /* + * 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_addr_lookup() succeeds 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. + */ + + config_free_lines(options->Address); + options->Address = NULL; + tor_addr_parse(&test_addr, "0808::0808"); + + MOCK(tor_gethostname, tor_gethostname_replacement); + MOCK(tor_addr_lookup, tor_addr_lookup_localhost); + MOCK(get_interface_address6, get_interface_address6_08080808); + + prev_n_gethostname_replacement = n_gethostname_replacement; + prev_n_hostname_localhost = n_hostname_localhost; + prev_n_get_interface_address6 = n_get_interface_address6; + + retval = find_my_address(options, AF_INET6, LOG_NOTICE, &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, OP_EQ, "INTERFACE"); + tt_ptr_op(hostname_out, OP_EQ, NULL); + tt_want(retval == true); + tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); + + /* + * CASE 11b: + * 1-5 as above. + * 6. get_interface_address6() fails. + * + * In this subcase, we want find_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 = find_my_address(options, AF_INET6, LOG_DEBUG, &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_want(retval == false); + + UNMOCK(tor_gethostname); + UNMOCK(tor_addr_lookup); + UNMOCK(get_interface_address6); + + /* CASE 12: + * Suppose the following happens: + * 1. options->Address is NULL AND options->DirAuthorities is non-NULL + * 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 find_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 = find_my_address(options, AF_INET6, LOG_DEBUG, &resolved_addr, + &method_used, &hostname_out); + + tt_want(n_gethostname_localhost == prev_n_gethostname_localhost + 1); + tt_want(retval == false); + + UNMOCK(tor_gethostname); + + done: + config_free_lines(options->Address); + tor_free(options->DirAuthorities); + or_options_free(options); + tor_free(hostname_out); + + UNMOCK(tor_gethostname); + UNMOCK(tor_addr_lookup); + UNMOCK(get_interface_address); + UNMOCK(get_interface_address6); + UNMOCK(tor_gethostname); +} + static void test_config_find_my_address_v4(void *arg) { @@ -6246,6 +6660,7 @@ struct testcase_t config_tests[] = { CONFIG_TEST(default_dir_servers, TT_FORK), CONFIG_TEST(default_fallback_dirs, 0), CONFIG_TEST(find_my_address_v4, TT_FORK), + CONFIG_TEST(find_my_address_v6, TT_FORK), CONFIG_TEST(addressmap, 0), CONFIG_TEST(parse_bridge_line, 0), CONFIG_TEST(parse_transport_options_line, 0),
tor-commits@lists.torproject.org