aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/ticket332364
-rw-r--r--src/app/config/resolve_addr.c58
-rw-r--r--src/app/config/resolve_addr.h6
-rw-r--r--src/test/test_config.c90
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);