commit ff68aeb49244d65398b5fabaf87d65da51343006 Author: Nick Mathewson nickm@torproject.org Date: Fri Jul 17 09:06:35 2020 -0400
When choosing an orport from an extendinfo, pick randomly.
(This is not fully general yet: we only pick randomly among _supported_ addresses, and each extendinfo contains at most one IPv4 address and at most one IPv6 address, no matter what the extend cell had.)
This change will help dual-stack relays do IPv6 reachability tests, in theory, by having them sometimes do IPv4 connections and sometimes do ipv6 connections.
Closes ticket 33220. --- changes/ticket33220 | 5 +++++ src/core/or/extendinfo.c | 33 +++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/changes/ticket33220 b/changes/ticket33220 new file mode 100644 index 0000000000..e064dcd1c1 --- /dev/null +++ b/changes/ticket33220 @@ -0,0 +1,5 @@ + o Major features (relay, IPv6): + - When a relay with IPv6 support opens a connection to another + relay, and the extend cell lists both IPv4 and IPv6 addresses, the + first relay now picks randomly which address to use. Closes + ticket 33220. diff --git a/src/core/or/extendinfo.c b/src/core/or/extendinfo.c index bcdb57d5a0..ffc88295cf 100644 --- a/src/core/or/extendinfo.c +++ b/src/core/or/extendinfo.c @@ -19,6 +19,9 @@ #include "core/or/policies.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/nodelist.h" +#include "feature/relay/router.h" +#include "feature/relay/routermode.h" +#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/extend_info_st.h" #include "feature/nodelist/node_st.h" @@ -274,16 +277,38 @@ extend_info_get_orport(const extend_info_t *ei, int family) const tor_addr_port_t * extend_info_pick_orport(const extend_info_t *ei) { - // XXXX S55 -- for now, we just pick the first. We'll work on - // XXXX more choices as we move forward. IF_BUG_ONCE(!ei) { return NULL; } + const or_options_t *options = get_options(); + if (!server_mode(options)) { + // If we aren't a server, just pick the first address we built into + // this extendinfo. + return &ei->orports[0]; + } + + const bool ipv6_ok = router_can_extend_over_ipv6(options); + + // Use 'usable' to collect the usable orports, then pick one. + const tor_addr_port_t *usable[EXTEND_INFO_MAX_ADDRS]; + int n_usable = 0; + for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) { + const tor_addr_port_t *a = &ei->orports[i]; + const int family = tor_addr_family(&a->addr); + if (family == AF_INET || (ipv6_ok && family == AF_INET6)) { + usable[n_usable++] = a; + } + }
- if (tor_addr_is_unspec(&ei->orports[0].addr)) { + if (n_usable == 0) { + // Need to bail out early, since nothing will work. return NULL; } - return &ei->orports[0]; + + crypto_fast_rng_t *rng = get_thread_fast_rng(); + const int idx = crypto_fast_rng_get_uint(rng, n_usable); + + return usable[idx]; }
/**
tor-commits@lists.torproject.org