aboutsummaryrefslogtreecommitdiff
path: root/src/feature/relay/circuitbuild_relay.c
diff options
context:
space:
mode:
authorteor <teor@torproject.org>2020-04-29 15:56:40 +1000
committerteor <teor@torproject.org>2020-04-29 22:43:09 +1000
commitc3e058dfac1cbc7cb0dee5cdb1bdc61c1dc0f4fa (patch)
treec696127643a2626613b144a4e7d7e15434da24c3 /src/feature/relay/circuitbuild_relay.c
parenta0b12f3cd40fc00c9bdbb1ff01b0d074673a7524 (diff)
downloadtor-c3e058dfac1cbc7cb0dee5cdb1bdc61c1dc0f4fa.tar.gz
tor-c3e058dfac1cbc7cb0dee5cdb1bdc61c1dc0f4fa.zip
relay: Choose between IPv4 and IPv6 extends at random
When an EXTEND2 cell has an IPv4 and an IPv6 address, choose one of them uniformly at random. Part of 33817.
Diffstat (limited to 'src/feature/relay/circuitbuild_relay.c')
-rw-r--r--src/feature/relay/circuitbuild_relay.c66
1 files changed, 61 insertions, 5 deletions
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
index d6ea22ca70..261fbc7e45 100644
--- a/src/feature/relay/circuitbuild_relay.c
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -18,6 +18,8 @@
#include "orconfig.h"
#include "feature/relay/circuitbuild_relay.h"
+#include "lib/crypt_ops/crypto_rand.h"
+
#include "core/or/or.h"
#include "app/config/config.h"
@@ -36,6 +38,7 @@
#include "feature/nodelist/nodelist.h"
+#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
@@ -237,9 +240,14 @@ circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
}
/* When there is no open channel for an extend cell <b>ec</b>, set up the
- * circuit <b>circ</b> to wait for a new connection. If <b>should_launch</b>
- * is true, open a new connection. (Otherwise, we are already waiting for a
- * new connection to the same relay.)
+ * circuit <b>circ</b> to wait for a new connection.
+ *
+ * If <b>should_launch</b> is true, open a new connection. (Otherwise, we are
+ * already waiting for a new connection to the same relay.)
+ *
+ * Check if IPv6 extends are supported by our current configuration. If they
+ * are, new connections may be made over IPv4 or IPv6. (IPv4 connections are
+ * always supported.)
*/
STATIC void
circuit_open_connection_for_extend(const struct extend_cell_t *ec,
@@ -258,13 +266,61 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
return;
}
+ /* Check the addresses, without logging */
+ const int ipv4_valid =
+ (circuit_extend_addr_port_helper(&ec->orport_ipv4, false, false, 0) == 0);
+ const int ipv6_valid =
+ (circuit_extend_addr_port_helper(&ec->orport_ipv6, false, false, 0) == 0);
+
+ IF_BUG_ONCE(!ipv4_valid && !ipv6_valid) {
+ /* circuit_extend_lspec_valid_helper() should have caught this */
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+
+ /* If we could make an IPv4 or an IPv6 connection, make an IPv6 connection
+ * at random, with probability 1 in N.
+ * 1 means "always IPv6 (and no IPv4)"
+ * 2 means "equal probability of IPv4 or IPv6"
+ * ... (and so on) ...
+ * (UINT_MAX - 1) means "almost always IPv4 (and almost never IPv6)"
+ * To disable IPv6, set ipv6_supported to 0.
+ */
+#define IPV6_CONNECTION_ONE_IN_N 2
+
+ const bool ipv6_supported = router_has_advertised_ipv6_orport(get_options());
+ const tor_addr_port_t *chosen_ap = NULL;
+
+ /* IPv4 is always supported */
+ if (ipv4_valid && ipv6_valid && ipv6_supported) {
+ /* Choose between IPv4 and IPv6 at random */
+ bool choose_ipv6 = crypto_fast_rng_one_in_n(get_thread_fast_rng(),
+ IPV6_CONNECTION_ONE_IN_N);
+ if (choose_ipv6) {
+ chosen_ap = &ec->orport_ipv6;
+ } else {
+ chosen_ap = &ec->orport_ipv4;
+ }
+ } else if (ipv6_valid && ipv6_supported) {
+ /* There's only one valid address: try to use it */
+ chosen_ap = &ec->orport_ipv6;
+ } else if (ipv4_valid) {
+ chosen_ap = &ec->orport_ipv4;
+ } else {
+ /* An IPv6-only extend, but IPv6 is not supported */
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received IPv6-only extend, but we don't have an IPv6 ORPort.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+
circ->n_hop = extend_info_new(NULL /*nickname*/,
(const char*)ec->node_id,
&ec->ed_pubkey,
NULL, /*onion_key*/
NULL, /*curve25519_key*/
- &ec->orport_ipv4.addr,
- ec->orport_ipv4.port);
+ &chosen_ap->addr,
+ chosen_ap->port);
circ->n_chan_create_cell = tor_memdup(&ec->create_cell,
sizeof(ec->create_cell));