diff --git a/changes/feature9777 b/changes/feature9777 new file mode 100644 index 0000000000..312b5e034e --- /dev/null +++ b/changes/feature9777 @@ -0,0 +1,3 @@ + o Minor features: + - Avoid using circuit paths if no node in the path supports the ntor + circuit extension handshake. Implements ticket 9777. diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 43d2ffe4db..e47a2780af 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -72,6 +72,9 @@ static void pathbias_count_use_failed(origin_circuit_t *circ); static void pathbias_measure_use_rate(entry_guard_t *guard); static void pathbias_measure_close_rate(entry_guard_t *guard); static void pathbias_scale_use_rates(entry_guard_t *guard); +#ifdef CURVE25519_ENABLED +static int circuits_can_use_ntor(void); +#endif /** This function tries to get a channel to the specified endpoint, * and then calls command_setup_channel() to give it the right @@ -284,21 +287,74 @@ circuit_rep_hist_note_result(origin_circuit_t *circ) } while (hop!=circ->cpath); } +#ifdef CURVE25519_ENABLED +/** Return 1 iff at least one node in circ's cpath supports ntor. */ +static int +circuit_cpath_supports_ntor(const origin_circuit_t *circ) +{ + crypt_path_t *head = circ->cpath, *cpath = circ->cpath; + + cpath = head; + do { + if (cpath->extend_info && + !tor_mem_is_zero( + (const char*)cpath->extend_info->curve25519_onion_key.public_key, + CURVE25519_PUBKEY_LEN)) + return 1; + + cpath = cpath->next; + } while (cpath != head); + + return 0; +} +#else +#define circuit_cpath_supports_ntor(circ) 0 +#endif + /** Pick all the entries in our cpath. Stop and return 0 when we're * happy, or return -1 if an error occurs. */ static int onion_populate_cpath(origin_circuit_t *circ) { - int r; - again: - r = onion_extend_cpath(circ); - if (r < 0) { - log_info(LD_CIRC,"Generating cpath hop failed."); - return -1; + int n_tries = 0; +#ifdef CURVE25519_ENABLED + const int using_ntor = circuits_can_use_ntor(); +#else + const int using_ntor = 0; +#endif + +#define MAX_POPULATE_ATTEMPTS 32 + + while (1) { + int r = onion_extend_cpath(circ); + if (r < 0) { + log_info(LD_CIRC,"Generating cpath hop failed."); + return -1; + } + if (r == 1) { + /* This circuit doesn't need/shouldn't be forced to have an ntor hop */ + if (circ->build_state->desired_path_len <= 1 || ! using_ntor) + return 0; + + /* This circuit has an ntor hop. great! */ + if (circuit_cpath_supports_ntor(circ)) + return 0; + + /* No node in the circuit supports ntor. Have we already tried too many + * times? */ + if (++n_tries >= MAX_POPULATE_ATTEMPTS) + break; + + /* Clear the path and retry */ + circuit_clear_cpath(circ); + } } - if (r == 0) - goto again; - return 0; /* if r == 1 */ + log_warn(LD_CIRC, "I tried for %d times, but I couldn't build a %d-hop " + "circuit with at least one node that supports ntor.", + MAX_POPULATE_ATTEMPTS, + circ->build_state->desired_path_len); + + return -1; } /** Create and return a new origin circuit. Initialize its purpose and @@ -3475,6 +3531,9 @@ onion_next_hop_in_cpath(crypt_path_t *cpath) /** Choose a suitable next hop in the cpath head_ptr, * based on state. Append the hop info to head_ptr. + * + * Return 1 if the path is complete, 0 if we successfully added a hop, + * and -1 on error. */ static int onion_extend_cpath(origin_circuit_t *circ) diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index b0e24a5fee..c7b15e40ba 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -709,7 +709,7 @@ circuit_free_cpath(crypt_path_t *cpath) if (!cpath) return; - /* it's a doubly linked list, so we have to notice when we've + /* it's a circular list, so we have to notice when we've * gone through it once. */ while (cpath->next && cpath->next != head) { victim = cpath; @@ -720,6 +720,14 @@ circuit_free_cpath(crypt_path_t *cpath) circuit_free_cpath_node(cpath); } +/** Remove all the items in the cpath on circ.*/ +void +circuit_clear_cpath(origin_circuit_t *circ) +{ + circuit_free_cpath(circ->cpath); + circ->cpath = NULL; +} + /** Release all storage held by circuits. */ void circuit_free_all(void) diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 874f68cd22..acc4b81fcd 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -50,6 +50,7 @@ void circuit_mark_all_dirty_circs_as_unusable(void); void circuit_mark_for_close_(circuit_t *circ, int reason, int line, const char *file); int circuit_get_cpath_len(origin_circuit_t *circ); +void circuit_clear_cpath(origin_circuit_t *circ); crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum); void circuit_get_all_pending_on_channel(smartlist_t *out, channel_t *chan);