commit e2e1c07fd25c96a83b38f5d84d2c063b98ed8f46 Author: teor teor@torproject.org Date: Fri Aug 23 16:17:47 2019 +1000
hs: v3 single onion services fall back to 3-hop intro for unreachable nodes
Previously, v3 single onion services failed when all intro nodes were unreachable via a 1-hop path. Now, we select intros that are only available via a 3-hop path, and use a 3-hop path to connect to them.
Fixes bug 23507; bugfix on 0.3.2.1-alpha. --- src/feature/hs/hs_circuit.c | 25 +++++++++++++++---------- src/feature/hs/hs_circuit.h | 3 ++- src/feature/hs/hs_service.c | 30 +++++++++++++++++++++++------- 3 files changed, 40 insertions(+), 18 deletions(-)
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index d74b088f0..8acfcbd65 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -758,13 +758,16 @@ hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ) }
/* For a given service and a service intro point, launch a circuit to the - * extend info ei. If the service is a single onion, a one-hop circuit will be - * requested. Return 0 if the circuit was successfully launched and tagged + * extend info ei. If the service is a single onion, and direct_conn is true, + * a one-hop circuit will be requested. + * + * Return 0 if the circuit was successfully launched and tagged * with the correct identifier. On error, a negative value is returned. */ int hs_circ_launch_intro_point(hs_service_t *service, const hs_service_intro_point_t *ip, - extend_info_t *ei) + extend_info_t *ei, + bool direct_conn) { /* Standard flags for introduction circuit. */ int ret = -1, circ_flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL; @@ -775,15 +778,17 @@ hs_circ_launch_intro_point(hs_service_t *service, tor_assert(ei);
/* Update circuit flags in case of a single onion service that requires a - * direct connection. - * - * We only use a one-hop path on the first attempt. If the first attempt + * direct connection. */ + tor_assert_nonfatal(ip->circuit_retries > 0); + /* Only single onion services can make direct conns */ + if (BUG(!service->config.is_single_onion && direct_conn)) { + goto end; + } + /* We only use a one-hop path on the first attempt. If the first attempt * fails, we use a 3-hop path for reachability / reliability. * (Unlike v2, retries is incremented by the caller before it calls this - * function.) - */ - tor_assert_nonfatal(ip->circuit_retries > 0); - if (service->config.is_single_onion && ip->circuit_retries == 1) { + * function.) */ + if (direct_conn && ip->circuit_retries == 1) { circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL; }
diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h index b8d8b25ad..e168b301f 100644 --- a/src/feature/hs/hs_circuit.h +++ b/src/feature/hs/hs_circuit.h @@ -26,7 +26,8 @@ void hs_circ_service_rp_has_opened(const hs_service_t *service, origin_circuit_t *circ); int hs_circ_launch_intro_point(hs_service_t *service, const hs_service_intro_point_t *ip, - extend_info_t *ei); + extend_info_t *ei, + bool direct_conn); int hs_circ_launch_rendezvous_point(const hs_service_t *service, const curve25519_public_key_t *onion_key, const uint8_t *rendezvous_cookie); diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 402929036..b05f20366 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -2105,6 +2105,7 @@ build_all_descriptors(time_t now) static hs_service_intro_point_t * pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) { + const or_options_t *options = get_options(); const node_t *node; extend_info_t *info = NULL; hs_service_intro_point_t *ip = NULL; @@ -2113,11 +2114,19 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) /* Single onion flags. */ router_crn_flags_t direct_flags = flags | CRN_PREF_ADDR | CRN_DIRECT_CONN;
- node = router_choose_random_node(exclude_nodes, get_options()->ExcludeNodes, + node = router_choose_random_node(exclude_nodes, options->ExcludeNodes, direct_conn ? direct_flags : flags); - /* Unable to find a node. When looking for a node for a direct connection, - * we could try a 3-hop path instead. We'll add support for this in a later - * release. */ + + /* If we are in single onion mode, retry node selection for a 3-hop + * path */ + if (direct_conn && !node) { + log_info(LD_REND, + "Unable to find an intro point that we can connect to " + "directly, falling back to a 3-hop path."); + node = router_choose_random_node(exclude_nodes, options->ExcludeNodes, + flags); + } + if (!node) { goto err; } @@ -2644,7 +2653,7 @@ launch_intro_point_circuits(hs_service_t *service) * circuits using the current map. */ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) { /* Keep a ref on if we need a direct connection. We use this often. */ - unsigned int direct_conn = service->config.is_single_onion; + bool direct_conn = service->config.is_single_onion;
DIGEST256MAP_FOREACH_MODIFY(desc->intro_points.map, key, hs_service_intro_point_t *, ip) { @@ -2655,8 +2664,15 @@ launch_intro_point_circuits(hs_service_t *service) if (hs_circ_service_get_intro_circ(ip)) { continue; } - ei = get_extend_info_from_intro_point(ip, direct_conn); + + /* If we can't connect directly to the intro point, get an extend_info + * for a multi-hop path instead. */ + if (ei == NULL && direct_conn) { + direct_conn = false; + ei = get_extend_info_from_intro_point(ip, 0); + } + if (ei == NULL) { /* This is possible if we can get a node_t but not the extend info out * of it. In this case, we remove the intro point and a new one will @@ -2668,7 +2684,7 @@ launch_intro_point_circuits(hs_service_t *service)
/* Launch a circuit to the intro point. */ ip->circuit_retries++; - if (hs_circ_launch_intro_point(service, ip, ei) < 0) { + if (hs_circ_launch_intro_point(service, ip, ei, direct_conn) < 0) { log_info(LD_REND, "Unable to launch intro circuit to node %s " "for service %s.", safe_str_client(extend_info_describe(ei)),
tor-commits@lists.torproject.org