summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2020-06-29 12:56:39 -0400
committerNick Mathewson <nickm@torproject.org>2020-06-29 12:56:39 -0400
commit3008255aea7c0c0ca4aa368e2fc975b932241ee3 (patch)
tree06a5c95b12b7118355227ec7d72d6d0af0f9bb65 /src
parent183d0d30d66aaae058cd180292779d770182ef80 (diff)
parent52f61ec83ea8fd2641ca8cae111b2437d8114aa1 (diff)
downloadtor-3008255aea7c0c0ca4aa368e2fc975b932241ee3.tar.gz
tor-3008255aea7c0c0ca4aa368e2fc975b932241ee3.zip
Merge remote-tracking branch 'tor-github/pr/1829/head' into maint-0.4.3
Diffstat (limited to 'src')
-rw-r--r--src/app/config/config.c5
-rw-r--r--src/app/config/config.h4
-rw-r--r--src/feature/relay/router.c77
-rw-r--r--src/feature/relay/router.h2
-rw-r--r--src/test/test_config.c66
-rw-r--r--src/test/test_router.c117
6 files changed, 239 insertions, 32 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c
index c7ac9d6315..7ed60c4745 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -823,9 +823,6 @@ static char *get_windows_conf_root(void);
static int options_check_transition_cb(const void *old,
const void *new,
char **msg);
-static int parse_ports(or_options_t *options, int validate_only,
- char **msg_out, int *n_ports_out,
- int *world_writable_control_socket);
static int validate_data_directories(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
@@ -6557,7 +6554,7 @@ port_count_real_listeners(const smartlist_t *ports, int listenertype,
* If <b>validate_only</b> is false, set configured_client_ports to the
* new list of ports parsed from <b>options</b>.
**/
-static int
+STATIC int
parse_ports(or_options_t *options, int validate_only,
char **msg, int *n_ports_out,
int *world_writable_control_socket)
diff --git a/src/app/config/config.h b/src/app/config/config.h
index 04d877e9da..311e27917a 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -319,6 +319,10 @@ int options_validate(const or_options_t *old_options,
char **msg);
#endif
+STATIC int parse_ports(or_options_t *options, int validate_only,
+ char **msg, int *n_ports_out,
+ int *world_writable_control_socket);
+
#endif /* defined(CONFIG_PRIVATE) */
#endif /* !defined(TOR_CONFIG_H) */
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index e24e499971..3e92f202e6 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -1446,6 +1446,50 @@ router_get_advertised_or_port_by_af(const or_options_t *options,
return port;
}
+/** As router_get_advertised_or_port(), but returns the IPv6 address and
+ * port in ipv6_ap_out, which must not be NULL. Returns a null address and
+ * zero port, if no ORPort is found. */
+void
+router_get_advertised_ipv6_or_ap(const or_options_t *options,
+ tor_addr_port_t *ipv6_ap_out)
+{
+ /* Bug in calling function, we can't return a sensible result, and it
+ * shouldn't use the NULL pointer once we return. */
+ tor_assert(ipv6_ap_out);
+
+ /* If there is no valid IPv6 ORPort, return a null address and port. */
+ tor_addr_make_null(&ipv6_ap_out->addr, AF_INET6);
+ ipv6_ap_out->port = 0;
+
+ const tor_addr_t *addr = get_first_advertised_addr_by_type_af(
+ CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ const uint16_t port = router_get_advertised_or_port_by_af(
+ options,
+ AF_INET6);
+
+ if (!addr || port == 0) {
+ log_info(LD_CONFIG, "There is no advertised IPv6 ORPort.");
+ return;
+ }
+
+ /* If the relay is configured using the default authorities, disallow
+ * internal IPs. Otherwise, allow them. For IPv4 ORPorts and DirPorts,
+ * this check is done in resolve_my_address(). See #33681. */
+ const int default_auth = using_default_dir_authorities(options);
+ if (tor_addr_is_internal(addr, 0) && default_auth) {
+ log_warn(LD_CONFIG,
+ "Unable to use configured IPv6 ORPort \"%s\" in a "
+ "descriptor. Skipping it. "
+ "Try specifying a globally reachable address explicitly.",
+ fmt_addrport(addr, port));
+ return;
+ }
+
+ tor_addr_copy(&ipv6_ap_out->addr, addr);
+ ipv6_ap_out->port = port;
+}
+
/** Return the port that we should advertise as our DirPort;
* this is one of three possibilities:
* The one that is passed as <b>dirport</b> if the DirPort option is 0, or
@@ -1990,34 +2034,11 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
sizeof(curve25519_public_key_t));
/* For now, at most one IPv6 or-address is being advertised. */
- {
- const port_cfg_t *ipv6_orport = NULL;
- SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
- if (p->type == CONN_TYPE_OR_LISTENER &&
- ! p->server_cfg.no_advertise &&
- ! p->server_cfg.bind_ipv4_only &&
- tor_addr_family(&p->addr) == AF_INET6) {
- /* Like IPv4, if the relay is configured using the default
- * authorities, disallow internal IPs. Otherwise, allow them. */
- const int default_auth = using_default_dir_authorities(options);
- if (! tor_addr_is_internal(&p->addr, 0) || ! default_auth) {
- ipv6_orport = p;
- break;
- } else {
- char addrbuf[TOR_ADDR_BUF_LEN];
- log_warn(LD_CONFIG,
- "Unable to use configured IPv6 address \"%s\" in a "
- "descriptor. Skipping it. "
- "Try specifying a globally reachable address explicitly.",
- tor_addr_to_str(addrbuf, &p->addr, sizeof(addrbuf), 1));
- }
- }
- } SMARTLIST_FOREACH_END(p);
- if (ipv6_orport) {
- tor_addr_copy(&ri->ipv6_addr, &ipv6_orport->addr);
- ri->ipv6_orport = ipv6_orport->port;
- }
- }
+ tor_addr_port_t ipv6_orport;
+ router_get_advertised_ipv6_or_ap(options, &ipv6_orport);
+ /* If there is no valud IPv6 ORPort, the address and port are null. */
+ tor_addr_copy(&ri->ipv6_addr, &ipv6_orport.addr);
+ ri->ipv6_orport = ipv6_orport.port;
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (BUG(crypto_pk_get_digest(ri->identity_pkey,
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 782609d8ab..061daa0628 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -66,6 +66,8 @@ int init_keys_client(void);
uint16_t router_get_active_listener_port_by_type_af(int listener_type,
sa_family_t family);
uint16_t router_get_advertised_or_port(const or_options_t *options);
+void router_get_advertised_ipv6_or_ap(const or_options_t *options,
+ tor_addr_port_t *ipv6_ap_out);
uint16_t router_get_advertised_or_port_by_af(const or_options_t *options,
sa_family_t family);
uint16_t router_get_advertised_dir_port(const or_options_t *options,
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 7b9812f550..ae3f04de11 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -4956,6 +4956,71 @@ test_config_parse_port_config__ports__server_options(void *data)
}
static void
+test_config_get_first_advertised(void *data)
+{
+ (void)data;
+ int r, w=0, n=0;
+ char *msg=NULL;
+ or_options_t *opts = options_new();
+ int port;
+ const tor_addr_t *addr;
+
+ // no ports are configured? We get NULL.
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET);
+ tt_int_op(port, OP_EQ, 0);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET);
+ tt_ptr_op(addr, OP_EQ, NULL);
+
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ tt_int_op(port, OP_EQ, 0);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ tt_ptr_op(addr, OP_EQ, NULL);
+
+ config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:8080");
+ config_line_append(&opts->ORPort_lines, "ORPort",
+ "1.2.3.4:9999 noadvertise");
+ config_line_append(&opts->ORPort_lines, "ORPort",
+ "5.6.7.8:9911 nolisten");
+
+ r = parse_ports(opts, 0, &msg, &n, &w);
+ tt_assert(r == 0);
+
+ // UNSPEC gets us nothing.
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_UNSPEC);
+ tt_int_op(port, OP_EQ, 0);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_UNSPEC);
+ tt_ptr_op(addr, OP_EQ, NULL);
+
+ // Try AF_INET.
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET);
+ tt_int_op(port, OP_EQ, 9911);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET);
+ tt_ptr_op(addr, OP_NE, NULL);
+ tt_str_op(fmt_addrport(addr,port), OP_EQ, "5.6.7.8:9911");
+
+ // Try AF_INET6
+ port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ tt_int_op(port, OP_EQ, 8080);
+ addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ AF_INET6);
+ tt_ptr_op(addr, OP_NE, NULL);
+ tt_str_op(fmt_addrport(addr,port), OP_EQ, "[1234::5678]:8080");
+
+ done:
+ or_options_free(opts);
+ config_free_all();
+}
+
+static void
test_config_parse_log_severity(void *data)
{
int ret;
@@ -6203,6 +6268,7 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(parse_port_config__ports__no_ports_given, 0),
CONFIG_TEST(parse_port_config__ports__server_options, 0),
CONFIG_TEST(parse_port_config__ports__ports_given, 0),
+ CONFIG_TEST(get_first_advertised, TT_FORK),
CONFIG_TEST(parse_log_severity, 0),
CONFIG_TEST(include_limit, 0),
CONFIG_TEST(include_does_not_exist, 0),
diff --git a/src/test/test_router.c b/src/test/test_router.c
index 572ddceaa7..cf0c2b3dd1 100644
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@ -8,11 +8,13 @@
**/
#define CONFIG_PRIVATE
+#define CONNECTION_PRIVATE
#define ROUTER_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/mainloop/mainloop.h"
+#include "core/mainloop/connection.h"
#include "feature/hibernate/hibernate.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -27,6 +29,8 @@
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/encoding/confline.h"
+#include "core/or/listener_connection_st.h"
+
/* Test suite stuff */
#include "test/test.h"
#include "test/log_test_helpers.h"
@@ -486,6 +490,117 @@ test_router_get_my_family(void *arg)
#undef CLEAR
}
+static smartlist_t *fake_connection_array = NULL;
+static smartlist_t *
+mock_get_connection_array(void)
+{
+ return fake_connection_array;
+}
+
+static void
+test_router_get_advertised_or_port(void *arg)
+{
+ (void)arg;
+ int r, w=0, n=0;
+ char *msg=NULL;
+ or_options_t *opts = options_new();
+ listener_connection_t *listener = NULL;
+ tor_addr_port_t ipv6;
+
+ // Test one failing case of router_get_advertised_ipv6_or_ap().
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
+
+ // And one failing case of router_get_advertised_or_port().
+ tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(0, OP_EQ, router_get_advertised_or_port(opts));
+
+ // Set up a couple of configured ports.
+ config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:auto");
+ config_line_append(&opts->ORPort_lines, "ORPort", "5.6.7.8:9999");
+ r = parse_ports(opts, 0, &msg, &n, &w);
+ tt_assert(r == 0);
+
+ // There are no listeners, so the "auto" case will turn up no results.
+ tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
+
+ // This will return the matching value from the configured port.
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts));
+
+ // Now set up a dummy listener.
+ MOCK(get_connection_array, mock_get_connection_array);
+ fake_connection_array = smartlist_new();
+ listener = listener_connection_new(CONN_TYPE_OR_LISTENER, AF_INET6);
+ TO_CONN(listener)->port = 54321;
+ smartlist_add(fake_connection_array, TO_CONN(listener));
+
+ // We should get a port this time.
+ tt_int_op(54321, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+
+ // Test one succeeding case of router_get_advertised_ipv6_or_ap().
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ,
+ "[1234::5678]:54321");
+
+ // This will return the matching value from the configured port.
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts));
+
+ done:
+ or_options_free(opts);
+ config_free_all();
+ smartlist_free(fake_connection_array);
+ connection_free_minimal(TO_CONN(listener));
+ UNMOCK(get_connection_array);
+}
+
+static void
+test_router_get_advertised_or_port_localhost(void *arg)
+{
+ (void)arg;
+ int r, w=0, n=0;
+ char *msg=NULL;
+ or_options_t *opts = options_new();
+ tor_addr_port_t ipv6;
+
+ // Set up a couple of configured ports on localhost.
+ config_line_append(&opts->ORPort_lines, "ORPort", "[::1]:9999");
+ config_line_append(&opts->ORPort_lines, "ORPort", "127.0.0.1:8888");
+ r = parse_ports(opts, 0, &msg, &n, &w);
+ tt_assert(r == 0);
+
+ // We should refuse to advertise them, since we have default dirauths.
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
+ // But the lower-level function should still report the correct value
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+
+ // The IPv4 checks are done in resolve_my_address(), which doesn't use
+ // ORPorts so we can't test them here. (See #33681.) Both these lower-level
+ // functions should still report the correct value.
+ tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts));
+
+ // Now try with a fake authority set up.
+ config_line_append(&opts->DirAuthorities, "DirAuthority",
+ "127.0.0.1:1066 "
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+
+ tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+ router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::1]:9999");
+
+ tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
+ tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts));
+
+ done:
+ or_options_free(opts);
+ config_free_all();
+}
+
#define ROUTER_TEST(name, flags) \
{ #name, test_router_ ## name, flags, NULL, NULL }
@@ -494,5 +609,7 @@ struct testcase_t router_tests[] = {
ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method, TT_FORK),
ROUTER_TEST(mark_if_too_old, TT_FORK),
ROUTER_TEST(get_my_family, TT_FORK),
+ ROUTER_TEST(get_advertised_or_port, TT_FORK),
+ ROUTER_TEST(get_advertised_or_port_localhost, TT_FORK),
END_OF_TESTCASES
};