Loading src/feature/relay/circuitbuild_relay.c +61 −5 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -36,6 +38,7 @@ #include "feature/nodelist/nodelist.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" #include "feature/relay/selftest.h" Loading Loading @@ -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, Loading @@ -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)); Loading src/feature/relay/router.c +10 −1 Original line number Diff line number Diff line Loading @@ -1469,7 +1469,7 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options, AF_INET6); if (!addr || port == 0) { log_info(LD_CONFIG, "There is no advertised IPv6 ORPort."); log_debug(LD_CONFIG, "There is no advertised IPv6 ORPort."); return; } Loading @@ -1490,6 +1490,15 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options, ipv6_ap_out->port = port; } /** Returns true if this router has an advertised IPv6 ORPort. */ bool router_has_advertised_ipv6_orport(const or_options_t *options) { tor_addr_port_t ipv6_ap; router_get_advertised_ipv6_or_ap(options, &ipv6_ap); return tor_addr_port_is_valid_ap(&ipv6_ap, 0); } /** 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 Loading src/feature/relay/router.h +1 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ uint16_t router_get_active_listener_port_by_type_af(int listener_type, 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); bool router_has_advertised_ipv6_orport(const or_options_t *options); 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, Loading src/test/test_circuitbuild.c +31 −1 Original line number Diff line number Diff line Loading @@ -857,6 +857,10 @@ test_circuit_open_connection_for_extend(void *arg) circuit_t *circ = tor_malloc_zero(sizeof(circuit_t)); channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t)); or_options_t *fake_options = options_new(); MOCK(get_options, mock_get_options); mocked_options = fake_options; MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close_); mock_circuit_close_calls = 0; MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit); Loading Loading @@ -906,8 +910,30 @@ test_circuit_open_connection_for_extend(void *arg) tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2); tor_end_capture_bugs_(); mock_clean_saved_logs(); /* Fail, because neither address is valid */ mock_circuit_close_calls = 0; mock_channel_connect_calls = 0; tor_capture_bugs_(1); circuit_open_connection_for_extend(ec, circ, 0); /* Close the circuit, don't connect */ tt_int_op(mock_circuit_close_calls, OP_EQ, 1); tt_int_op(mock_channel_connect_calls, OP_EQ, 0); /* Check state */ tt_ptr_op(circ->n_hop, OP_EQ, NULL); tt_ptr_op(circ->n_chan_create_cell, OP_EQ, NULL); tt_int_op(circ->state, OP_EQ, 0); /* Cleanup */ tor_end_capture_bugs_(); mock_clean_saved_logs(); #endif /* !defined(ALL_BUGS_ARE_FATAL) */ /* Set up valid addresses */ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4); ec->orport_ipv4.port = VALID_PORT; tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6); ec->orport_ipv6.port = VALID_PORT; /* Succeed, but don't try to open a connection */ mock_circuit_close_calls = 0; mock_channel_connect_calls = 0; Loading Loading @@ -948,7 +974,7 @@ test_circuit_open_connection_for_extend(void *arg) mock_circuit_close_calls = 0; mock_channel_connect_calls = 0; circuit_open_connection_for_extend(ec, circ, 1); /* Try to connect, and succeed, leaving the circuit open */ /* Connection attempt succeeded, leaving the circuit open */ tt_int_op(mock_circuit_close_calls, OP_EQ, 0); tt_int_op(mock_channel_connect_calls, OP_EQ, 1); /* Check state */ Loading @@ -971,6 +997,10 @@ test_circuit_open_connection_for_extend(void *arg) UNMOCK(channel_connect_for_circuit); mock_channel_connect_calls = 0; UNMOCK(get_options); or_options_free(fake_options); mocked_options = NULL; tor_free(ec); tor_free(circ->n_hop); tor_free(circ->n_chan_create_cell); Loading Loading
src/feature/relay/circuitbuild_relay.c +61 −5 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -36,6 +38,7 @@ #include "feature/nodelist/nodelist.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" #include "feature/relay/selftest.h" Loading Loading @@ -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, Loading @@ -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)); Loading
src/feature/relay/router.c +10 −1 Original line number Diff line number Diff line Loading @@ -1469,7 +1469,7 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options, AF_INET6); if (!addr || port == 0) { log_info(LD_CONFIG, "There is no advertised IPv6 ORPort."); log_debug(LD_CONFIG, "There is no advertised IPv6 ORPort."); return; } Loading @@ -1490,6 +1490,15 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options, ipv6_ap_out->port = port; } /** Returns true if this router has an advertised IPv6 ORPort. */ bool router_has_advertised_ipv6_orport(const or_options_t *options) { tor_addr_port_t ipv6_ap; router_get_advertised_ipv6_or_ap(options, &ipv6_ap); return tor_addr_port_is_valid_ap(&ipv6_ap, 0); } /** 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 Loading
src/feature/relay/router.h +1 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ uint16_t router_get_active_listener_port_by_type_af(int listener_type, 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); bool router_has_advertised_ipv6_orport(const or_options_t *options); 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, Loading
src/test/test_circuitbuild.c +31 −1 Original line number Diff line number Diff line Loading @@ -857,6 +857,10 @@ test_circuit_open_connection_for_extend(void *arg) circuit_t *circ = tor_malloc_zero(sizeof(circuit_t)); channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t)); or_options_t *fake_options = options_new(); MOCK(get_options, mock_get_options); mocked_options = fake_options; MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close_); mock_circuit_close_calls = 0; MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit); Loading Loading @@ -906,8 +910,30 @@ test_circuit_open_connection_for_extend(void *arg) tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2); tor_end_capture_bugs_(); mock_clean_saved_logs(); /* Fail, because neither address is valid */ mock_circuit_close_calls = 0; mock_channel_connect_calls = 0; tor_capture_bugs_(1); circuit_open_connection_for_extend(ec, circ, 0); /* Close the circuit, don't connect */ tt_int_op(mock_circuit_close_calls, OP_EQ, 1); tt_int_op(mock_channel_connect_calls, OP_EQ, 0); /* Check state */ tt_ptr_op(circ->n_hop, OP_EQ, NULL); tt_ptr_op(circ->n_chan_create_cell, OP_EQ, NULL); tt_int_op(circ->state, OP_EQ, 0); /* Cleanup */ tor_end_capture_bugs_(); mock_clean_saved_logs(); #endif /* !defined(ALL_BUGS_ARE_FATAL) */ /* Set up valid addresses */ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4); ec->orport_ipv4.port = VALID_PORT; tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6); ec->orport_ipv6.port = VALID_PORT; /* Succeed, but don't try to open a connection */ mock_circuit_close_calls = 0; mock_channel_connect_calls = 0; Loading Loading @@ -948,7 +974,7 @@ test_circuit_open_connection_for_extend(void *arg) mock_circuit_close_calls = 0; mock_channel_connect_calls = 0; circuit_open_connection_for_extend(ec, circ, 1); /* Try to connect, and succeed, leaving the circuit open */ /* Connection attempt succeeded, leaving the circuit open */ tt_int_op(mock_circuit_close_calls, OP_EQ, 0); tt_int_op(mock_channel_connect_calls, OP_EQ, 1); /* Check state */ Loading @@ -971,6 +997,10 @@ test_circuit_open_connection_for_extend(void *arg) UNMOCK(channel_connect_for_circuit); mock_channel_connect_calls = 0; UNMOCK(get_options); or_options_free(fake_options); mocked_options = NULL; tor_free(ec); tor_free(circ->n_hop); tor_free(circ->n_chan_create_cell); Loading