relay: Refactor circuit_open_connection_for_extend()

Refactor circuit_open_connection_for_extend(), splitting out the IP
address choice code into a new function.

Adds unit tests. No behaviour changes in tor.

Part of 33817.
This commit is contained in:
teor 2020-04-29 20:29:15 +10:00
parent cab05a84cd
commit 9a6186c267
2 changed files with 51 additions and 29 deletions

View File

@ -239,6 +239,50 @@ circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
return 0;
}
/* If possible, return a supported, non-NULL IP address.
*
* If both addresses are supported and non-NULL, choose one uniformly at
* random.
*
* If we have an IPv6-only extend, but IPv6 is not supported, returns NULL.
* If both addresses are NULL, also returns NULL. */
STATIC const tor_addr_port_t *
circuit_choose_ip_ap_for_extend(const tor_addr_port_t *ipv4_ap,
const tor_addr_port_t *ipv6_ap)
{
/* 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
/* IPv4 is always supported */
const bool ipv6_supported = router_has_advertised_ipv6_orport(get_options());
if (ipv4_ap && ipv6_ap && 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) {
return ipv6_ap;
} else {
return ipv4_ap;
}
} else if (ipv6_ap && ipv6_supported) {
/* There's only one valid address: try to use it */
return ipv6_ap;
} else if (ipv4_ap) {
return ipv4_ap;
} else {
/* IPv6-only extend, but IPv6 is not supported. */
return NULL;
}
}
/* 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.
*
@ -278,35 +322,10 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
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 {
const tor_addr_port_t *chosen_ap = circuit_choose_ip_ap_for_extend(
ipv4_valid ? &ec->orport_ipv4 : NULL,
ipv6_valid ? &ec->orport_ipv6 : NULL);
if (!chosen_ap) {
/* 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.");

View File

@ -75,6 +75,9 @@ STATIC int circuit_extend_state_valid_helper(const struct circuit_t *circ);
STATIC int circuit_extend_add_ed25519_helper(struct extend_cell_t *ec);
STATIC int circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
const struct circuit_t *circ);
STATIC const tor_addr_port_t * circuit_choose_ip_ap_for_extend(
const tor_addr_port_t *ipv4_ap,
const tor_addr_port_t *ipv6_ap);
STATIC void circuit_open_connection_for_extend(const struct extend_cell_t *ec,
struct circuit_t *circ,
int should_launch);