summaryrefslogtreecommitdiff
path: root/src/feature/relay/relay_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/relay/relay_config.c')
-rw-r--r--src/feature/relay/relay_config.c92
1 files changed, 81 insertions, 11 deletions
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index e8c29fa7ed..bfc5ac2612 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -151,7 +151,7 @@ describe_portnum(int port)
/** Return a static buffer containing the human readable logging string that
* describes the given port object. */
-static const char *
+STATIC const char *
describe_relay_port(const port_cfg_t *port)
{
IF_BUG_ONCE(!port) {
@@ -188,6 +188,41 @@ describe_relay_port(const port_cfg_t *port)
return buf;
}
+/** Return true iff port p1 is equal to p2.
+ *
+ * This does a field by field comparaison. */
+static bool
+port_cfg_eq(const port_cfg_t *p1, const port_cfg_t *p2)
+{
+ bool ret = true;
+
+ tor_assert(p1);
+ tor_assert(p2);
+
+ /* Address, port and type. */
+ ret &= tor_addr_eq(&p1->addr, &p2->addr);
+ ret &= (p1->port == p2->port);
+ ret &= (p1->type == p2->type);
+
+ /* Mode. */
+ ret &= (p1->is_unix_addr == p2->is_unix_addr);
+ ret &= (p1->is_group_writable == p2->is_group_writable);
+ ret &= (p1->is_world_writable == p2->is_world_writable);
+ ret &= (p1->relax_dirmode_check == p2->relax_dirmode_check);
+ ret &= (p1->explicit_addr == p2->explicit_addr);
+
+ /* Entry config flags. */
+ ret &= tor_memeq(&p1->entry_cfg, &p2->entry_cfg,
+ sizeof(entry_port_cfg_t));
+ /* Server config flags. */
+ ret &= tor_memeq(&p1->server_cfg, &p2->server_cfg,
+ sizeof(server_port_cfg_t));
+ /* Unix address path if any. */
+ ret &= !strcmp(p1->unix_addr, p2->unix_addr);
+
+ return ret;
+}
+
/** Attempt to find duplicate ORPort that would be superseded by another and
* remove them from the given ports list. This is possible if we have for
* instance:
@@ -198,6 +233,16 @@ describe_relay_port(const port_cfg_t *port)
* First one binds to both v4 and v6 address but second one is specific to an
* address superseding the global bind one.
*
+ * Another example is this one:
+ *
+ * ORPort 9001
+ * ORPort [4242::1]:9002
+ * ORPort [4242::2]:9003
+ *
+ * In this case, all IPv4 and IPv6 are kept since we do allow multiple ORPorts
+ * but the published port will be the first explicit one if any to be
+ * published or else the implicit.
+ *
* The following is O(n^2) but it is done at bootstrap or config reload and
* the list is not very long usually. */
STATIC void
@@ -231,17 +276,42 @@ remove_duplicate_orports(smartlist_t *ports)
if (next->type != CONN_TYPE_OR_LISTENER) {
continue;
}
- /* Same address family and same port number, we have a match. */
- if (tor_addr_family(&current->addr) == tor_addr_family(&next->addr) &&
- current->port == next->port) {
- /* Remove current because next is explicitly set. */
- removing[i] = true;
+ /* Remove duplicates. */
+ if (port_cfg_eq(current, next)) {
+ removing[j] = true;
+ continue;
+ }
+ /* Don't compare addresses of different family. */
+ if (tor_addr_family(&current->addr) != tor_addr_family(&next->addr)) {
+ continue;
+ }
+ /* At this point, we have a port of the same type and same address
+ * family. Now, we want to avoid comparing addresses that are different
+ * but are both explicit. As an example, these are not duplicates:
+ *
+ * ORPort 127.0.0.:9001 NoAdvertise
+ * ORPort 1.2.3.4:9001 NoListen
+ *
+ * Any implicit address must be considered for removal since an explicit
+ * one will always supersedes it. */
+ if (!tor_addr_eq(&current->addr, &next->addr) &&
+ current->explicit_addr && next->explicit_addr) {
+ continue;
+ }
+
+ /* Port value is the same so we either have a duplicate or a port that
+ * supersedes another. */
+ if (current->port == next->port) {
+ /* Do not remove the explicit address. As stated before above, we keep
+ * explicit addresses which supersedes implicit ones. */
if (!current->explicit_addr && next->explicit_addr) {
- char *next_str = tor_strdup(describe_relay_port(next));
- log_warn(LD_CONFIG, "Configuration port %s superseded by %s",
- describe_relay_port(current), next_str);
- tor_free(next_str);
+ continue;
}
+ removing[j] = true;
+ char *next_str = tor_strdup(describe_relay_port(next));
+ log_warn(LD_CONFIG, "Configuration port %s superseded by %s",
+ next_str, describe_relay_port(current));
+ tor_free(next_str);
}
}
}