diff options
-rw-r--r-- | changes/ticket33236 | 4 | ||||
-rw-r--r-- | src/app/config/resolve_addr.c | 58 | ||||
-rw-r--r-- | src/app/config/resolve_addr.h | 6 | ||||
-rw-r--r-- | src/test/test_config.c | 90 |
4 files changed, 149 insertions, 9 deletions
diff --git a/changes/ticket33236 b/changes/ticket33236 new file mode 100644 index 0000000000..d2b1d7e4da --- /dev/null +++ b/changes/ticket33236 @@ -0,0 +1,4 @@ + o Minor feature (relay, address discovery): + - If Address is not found in torrc, attempt to learn our address with the + configured ORPort address if any. Closes ticket 33236. + diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c index 808c5ddf0b..caca5a37d9 100644 --- a/src/app/config/resolve_addr.c +++ b/src/app/config/resolve_addr.c @@ -370,6 +370,63 @@ get_address_from_interface(const or_options_t *options, int warn_severity, return FN_RET_OK; } +/** @brief Get IP address from the ORPort (if any). + * + * @param options Global configuration options. + * @param warn_severity Log level that should be used on error. + * @param family IP address family. Only AF_INET and AF_INET6 are supported. + * @param method_out OUT: Always "CONFIGURED_ORPORT" on success which is + * detailed in the control-spec.txt as actions + * for "STATUS_SERVER". + * @param hostname_out OUT: String containing the ORPort hostname if any. + * @param addr_out OUT: Tor address found if any. + * + * @return Return 0 on success that is an address has been found. Return + * error code ERR_* found at the top of the file. + */ +static fn_address_ret_t +get_address_from_orport(const or_options_t *options, int warn_severity, + int family, const char **method_out, + char **hostname_out, tor_addr_t *addr_out) +{ + int ret; + const tor_addr_t *addr; + + tor_assert(method_out); + tor_assert(hostname_out); + tor_assert(addr_out); + + log_debug(LD_CONFIG, "Attempting to get address from ORPort"); + + if (!options->ORPort_set) { + log_info(LD_CONFIG, "No ORPort found in configuration."); + /* No ORPort statement, inform caller to try next method. */ + return FN_RET_NEXT; + } + + /* Get ORPort for requested family. */ + addr = get_orport_addr(family); + if (!addr) { + /* No address configured for the ORPort. Ignore. */ + return FN_RET_NEXT; + } + + /* We found the ORPort address. Just make sure it can be used. */ + ret = address_can_be_used(addr, options, warn_severity, true); + if (ret < 0) { + /* Unable to use address. Inform caller to try next method. */ + return FN_RET_NEXT; + } + + /* Found it! */ + *method_out = "CONFIGURED_ORPORT"; + tor_addr_copy(addr_out, addr); + + log_fn(warn_severity, LD_CONFIG, "Address found from ORPort: %s", + fmt_addr(addr_out)); + return FN_RET_OK; +} + /** @brief Update the last resolved address cache using the given address. * * A log notice is emitted if the given address has changed from before. Not @@ -450,6 +507,7 @@ static fn_address_ret_t { /* These functions are in order for our find address algorithm. */ get_address_from_config, + get_address_from_orport, get_address_from_interface, get_address_from_hostname, }; diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h index 54f55ba36c..e6f8a72554 100644 --- a/src/app/config/resolve_addr.h +++ b/src/app/config/resolve_addr.h @@ -9,8 +9,14 @@ #ifndef TOR_CONFIG_RESOLVE_ADDR_H #define TOR_CONFIG_RESOLVE_ADDR_H +#include "app/config/config.h" +#include "core/mainloop/connection.h" + #include "app/config/or_options_st.h" +#define get_orport_addr(family) \ + (get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, family)) + bool find_my_address(const or_options_t *options, int family, int warn_severity, tor_addr_t *addr_out, const char **method_out, char **hostname_out); diff --git a/src/test/test_config.c b/src/test/test_config.c index 765db03c04..0862ba5c44 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -1256,13 +1256,15 @@ get_interface_address6_failure(int severity, sa_family_t family, /** Helper macro: Cleanup the address and variables used after a * find_my_address() call. */ #undef CLEANUP_FOUND_ADDRESS -#define CLEANUP_FOUND_ADDRESS \ - do { \ - config_free_lines(options->Address); \ - tor_free(options->DirAuthorities); \ - tor_free(hostname_out); \ - tor_addr_make_unspec(&resolved_addr); \ - tor_addr_make_unspec(&test_addr); \ +#define CLEANUP_FOUND_ADDRESS \ + do { \ + config_free_lines(options->Address); \ + config_free_lines(options->ORPort_lines); \ + options->ORPort_set = 0; \ + tor_free(options->DirAuthorities); \ + tor_free(hostname_out); \ + tor_addr_make_unspec(&resolved_addr); \ + tor_addr_make_unspec(&test_addr); \ } while (0) /** Test both IPv4 and IPv6 coexisting together in the configuration. */ @@ -1418,6 +1420,7 @@ typedef struct find_my_address_params_t { int family; const char *public_ip; const char *internal_ip; + const char *orport; } find_my_address_params_t; static find_my_address_params_t addr_param_v4 = { @@ -1430,8 +1433,8 @@ static find_my_address_params_t addr_param_v4 = { static find_my_address_params_t addr_param_v6 = { .idx = 1, .family = AF_INET6, - .public_ip = "4242::4242", - .internal_ip = "::1", + .public_ip = "[4242::4242]", + .internal_ip = "[::1]", }; static void @@ -1733,6 +1736,75 @@ test_config_find_my_address(void *arg) VALIDATE_FOUND_ADDRESS(false, NULL, NULL); CLEANUP_FOUND_ADDRESS; + /* + * Case 13: + * 1. Address is NULL. + * 2. ORPort has a valid public address. + */ + { + char *msg = NULL; + int n, w, ret; + char *orport_line = NULL; + + options->Address = NULL; + tor_asprintf(&orport_line, "%s:9001", p->public_ip); + config_line_append(&options->ORPort_lines, "ORPort", orport_line); + tor_free(orport_line); + + if (p->family == AF_INET6) { + /* XXX: Tor does _not_ allow an IPv6 only ORPort thus we need to add a + * bogus IPv4 at the moment. */ + config_line_append(&options->ORPort_lines, "ORPort", "1.1.1.1:9001"); + } + + ret = parse_ports(options, 0, &msg, &n, &w); + tt_int_op(ret, OP_EQ, 0); + tor_addr_parse(&test_addr, p->public_ip); + } + + retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + VALIDATE_FOUND_ADDRESS(true, "CONFIGURED_ORPORT", NULL); + CLEANUP_FOUND_ADDRESS; + + /* + * Case 14: + * 1. Address is NULL. + * 2. ORPort has an internal address thus fails. + * 3. Interface as a valid address. + */ + { + char *msg = NULL; + int n, w, ret; + char *orport_line = NULL; + + options->Address = NULL; + tor_asprintf(&orport_line, "%s:9001", p->internal_ip); + config_line_append(&options->ORPort_lines, "ORPort", orport_line); + tor_free(orport_line); + + if (p->family == AF_INET6) { + /* XXX: Tor does _not_ allow an IPv6 only ORPort thus we need to add a + * bogus IPv4 at the moment. */ + config_line_append(&options->ORPort_lines, "ORPort", "1.1.1.1:9001"); + } + + ret = parse_ports(options, 0, &msg, &n, &w); + tt_int_op(ret, OP_EQ, 0); + } + tor_addr_parse(&test_addr, ret_get_interface_address6_08080808[p->idx]); + + MOCK(get_interface_address6, get_interface_address6_08080808); + + prev_n_get_interface_address6 = n_get_interface_address6; + + retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + + tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6); + VALIDATE_FOUND_ADDRESS(true, "INTERFACE", NULL); + CLEANUP_FOUND_ADDRESS; + UNMOCK(get_interface_address6); UNMOCK(tor_gethostname); UNMOCK(tor_addr_lookup); |