diff options
Diffstat (limited to 'src/or/circuituse.c')
-rw-r--r-- | src/or/circuituse.c | 144 |
1 files changed, 105 insertions, 39 deletions
diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 9f9d3abf7c..c229c84d96 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -42,6 +42,9 @@ #include "control.h" #include "entrynodes.h" #include "hs_common.h" +#include "hs_client.h" +#include "hs_circuit.h" +#include "hs_ident.h" #include "nodelist.h" #include "networkstatus.h" #include "policies.h" @@ -55,6 +58,36 @@ static void circuit_expire_old_circuits_clientside(void); static void circuit_increment_failure_count(void); +/** Check whether the hidden service destination of the stream at + * <b>edge_conn</b> is the same as the destination of the circuit at + * <b>origin_circ</b>. */ +static int +circuit_matches_with_rend_stream(const edge_connection_t *edge_conn, + const origin_circuit_t *origin_circ) +{ + /* Check if this is a v2 rendezvous circ/stream */ + if ((edge_conn->rend_data && !origin_circ->rend_data) || + (!edge_conn->rend_data && origin_circ->rend_data) || + (edge_conn->rend_data && origin_circ->rend_data && + rend_cmp_service_ids(rend_data_get_address(edge_conn->rend_data), + rend_data_get_address(origin_circ->rend_data)))) { + /* this circ is not for this conn */ + return 0; + } + + /* Check if this is a v3 rendezvous circ/stream */ + if ((edge_conn->hs_ident && !origin_circ->hs_ident) || + (!edge_conn->hs_ident && origin_circ->hs_ident) || + (edge_conn->hs_ident && origin_circ->hs_ident && + !ed25519_pubkey_eq(&edge_conn->hs_ident->identity_pk, + &origin_circ->hs_ident->identity_pk))) { + /* this circ is not for this conn */ + return 0; + } + + return 1; +} + /** Return 1 if <b>circ</b> could be returned by circuit_get_best(). * Else return 0. */ @@ -169,14 +202,9 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, /* can't exit from this router */ return 0; } - } else { /* not general */ + } else { /* not general: this might be a rend circuit */ const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); - if ((edge_conn->rend_data && !origin_circ->rend_data) || - (!edge_conn->rend_data && origin_circ->rend_data) || - (edge_conn->rend_data && origin_circ->rend_data && - rend_cmp_service_ids(rend_data_get_address(edge_conn->rend_data), - rend_data_get_address(origin_circ->rend_data)))) { - /* this circ is not for this conn */ + if (!circuit_matches_with_rend_stream(edge_conn, origin_circ)) { return 0; } } @@ -309,7 +337,8 @@ circuit_get_best(const entry_connection_t *conn, /* Log an info message if we're going to launch a new intro circ in * parallel */ if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT && - !must_be_open && origin_circ->hs_circ_has_timed_out) { + !must_be_open && origin_circ->hs_circ_has_timed_out && + !circ->marked_for_close) { intro_going_on_but_too_old = 1; continue; } @@ -622,6 +651,7 @@ circuit_expire_building(void) * because that's set when they switch purposes */ if (TO_ORIGIN_CIRCUIT(victim)->rend_data || + TO_ORIGIN_CIRCUIT(victim)->hs_ident || victim->timestamp_dirty > cutoff.tv_sec) continue; break; @@ -755,7 +785,7 @@ circuit_expire_building(void) victim->state, circuit_state_to_string(victim->state), victim->purpose); TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; - rend_service_relaunch_rendezvous(TO_ORIGIN_CIRCUIT(victim)); + hs_circ_retry_service_rendezvous_point(TO_ORIGIN_CIRCUIT(victim)); continue; } @@ -1086,11 +1116,32 @@ needs_exit_circuits(time_t now, int *needs_uptime, int *needs_capacity) /* Return true if we need any more hidden service server circuits. * HS servers only need an internal circuit. */ STATIC int -needs_hs_server_circuits(int num_uptime_internal) +needs_hs_server_circuits(time_t now, int num_uptime_internal) { - return (num_rend_services() && - num_uptime_internal < SUFFICIENT_UPTIME_INTERNAL_HS_SERVERS && - router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN); + if (!rend_num_services() && !hs_service_get_num_services()) { + /* No services, we don't need anything. */ + goto no_need; + } + + if (num_uptime_internal >= SUFFICIENT_UPTIME_INTERNAL_HS_SERVERS) { + /* We have sufficient amount of internal circuit. */ + goto no_need; + } + + if (router_have_consensus_path() == CONSENSUS_PATH_UNKNOWN) { + /* Consensus hasn't been checked or might be invalid so requesting + * internal circuits is not wise. */ + goto no_need; + } + + /* At this point, we need a certain amount of circuits and we will most + * likely use them for rendezvous so we note down the use of internal + * circuit for our prediction for circuit needing uptime and capacity. */ + rep_hist_note_used_internal(now, 1, 1); + + return 1; + no_need: + return 0; } /* We need at least this many internal circuits for hidden service clients */ @@ -1189,7 +1240,7 @@ circuit_predict_and_launch_new(void) return; } - if (needs_hs_server_circuits(num_uptime_internal)) { + if (needs_hs_server_circuits(now, num_uptime_internal)) { flags = (CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL); @@ -1253,11 +1304,6 @@ circuit_build_needed_circs(time_t now) if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) connection_ap_rescan_and_attach_pending(); - /* make sure any hidden services have enough intro points - * HS intro point streams only require an internal circuit */ - if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) - rend_consider_services_intro_points(); - circuit_expire_old_circs_as_needed(now); if (!options->DisablePredictedCircuits) @@ -1339,8 +1385,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) * number of streams on the circuit associated with the rend service. */ if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { - tor_assert(origin_circ->rend_data); - origin_circ->rend_data->nr_streams--; + hs_dec_rdv_stream_counter(origin_circ); } return; } @@ -1593,7 +1638,7 @@ circuit_has_opened(origin_circuit_t *circ) switch (TO_CIRCUIT(circ)->purpose) { case CIRCUIT_PURPOSE_C_ESTABLISH_REND: - rend_client_rendcirc_has_opened(circ); + hs_client_circuit_has_opened(circ); /* Start building an intro circ if we don't have one yet. */ connection_ap_attach_pending(1); /* This isn't a call to circuit_try_attaching_streams because a @@ -1605,7 +1650,7 @@ circuit_has_opened(origin_circuit_t *circ) * state. */ break; case CIRCUIT_PURPOSE_C_INTRODUCING: - rend_client_introcirc_has_opened(circ); + hs_client_circuit_has_opened(circ); break; case CIRCUIT_PURPOSE_C_GENERAL: /* Tell any AP connections that have been waiting for a new @@ -1614,11 +1659,11 @@ circuit_has_opened(origin_circuit_t *circ) break; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: /* at the service, waiting for introductions */ - rend_service_intro_has_opened(circ); + hs_service_circuit_has_opened(circ); break; case CIRCUIT_PURPOSE_S_CONNECT_REND: /* at the service, connecting to rend point */ - rend_service_rendezvous_has_opened(circ); + hs_service_circuit_has_opened(circ); break; case CIRCUIT_PURPOSE_TESTING: circuit_testing_opened(circ); @@ -1768,7 +1813,7 @@ circuit_build_failed(origin_circuit_t *circ) "(%s hop failed).", escaped(build_state_get_exit_nickname(circ->build_state)), failed_at_last_hop?"last":"non-last"); - rend_service_relaunch_rendezvous(circ); + hs_circ_retry_service_rendezvous_point(circ); break; /* default: * This won't happen in normal operation, but might happen if the @@ -2131,22 +2176,25 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, /* If this is a hidden service trying to start an introduction point, * handle that case. */ if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { + const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); /* need to pick an intro point */ - rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data; - tor_assert(rend_data); - extend_info = rend_client_get_random_intro(rend_data); + extend_info = hs_client_get_random_intro_from_edge(edge_conn); if (!extend_info) { - log_info(LD_REND, - "No intro points for '%s': re-fetching service descriptor.", - safe_str_client(rend_data_get_address(rend_data))); - rend_client_refetch_v2_renddesc(rend_data); + log_info(LD_REND, "No intro points: re-fetching service descriptor."); + if (edge_conn->rend_data) { + rend_client_refetch_v2_renddesc(edge_conn->rend_data); + } else { + hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk); + } connection_ap_mark_as_non_pending_circuit(conn); ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_RENDDESC_WAIT; return 0; } log_info(LD_REND,"Chose %s as intro point for '%s'.", extend_info_describe(extend_info), - safe_str_client(rend_data_get_address(rend_data))); + (edge_conn->rend_data) ? + safe_str_client(rend_data_get_address(edge_conn->rend_data)) : + "service"); } /* If we have specified a particular exit node for our @@ -2242,6 +2290,16 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, if (want_onehop) flags |= CIRCLAUNCH_ONEHOP_TUNNEL; if (need_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; if (need_internal) flags |= CIRCLAUNCH_IS_INTERNAL; + + /* If we are about to pick a v3 RP right now, make sure we pick a + * rendezvous point that supports the v3 protocol! */ + if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED && + new_circ_purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && + ENTRY_TO_EDGE_CONN(conn)->hs_ident) { + flags |= CIRCLAUNCH_IS_V3_RP; + log_info(LD_GENERAL, "Getting rendezvous circuit to v3 service!"); + } + circ = circuit_launch_by_extend_info(new_circ_purpose, extend_info, flags); } @@ -2265,8 +2323,15 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, /* help predict this next time */ rep_hist_note_used_internal(time(NULL), need_uptime, 1); if (circ) { - /* write the service_id into circ */ - circ->rend_data = rend_data_dup(ENTRY_TO_EDGE_CONN(conn)->rend_data); + const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); + if (edge_conn->rend_data) { + /* write the service_id into circ */ + circ->rend_data = rend_data_dup(edge_conn->rend_data); + } else if (edge_conn->hs_ident) { + circ->hs_ident = + hs_ident_circuit_new(&edge_conn->hs_ident->identity_pk, + HS_IDENT_CIRCUIT_INTRO); + } if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && circ->base_.state == CIRCUIT_STATE_OPEN) circuit_has_opened(circ); @@ -2348,8 +2413,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ, /* We are attaching a stream to a rendezvous circuit. That means * that an attempt to connect to a hidden service just * succeeded. Tell rendclient.c. */ - rend_client_note_connection_attempt_ended( - ENTRY_TO_EDGE_CONN(apconn)->rend_data); + hs_client_note_connection_attempt_succeeded(ENTRY_TO_EDGE_CONN(apconn)); } if (cpath) { /* we were given one; use it */ @@ -2695,12 +2759,14 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn) tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); if (introcirc->base_.state == CIRCUIT_STATE_OPEN) { + int ret; log_info(LD_REND,"found open intro circ %u (rend %u); sending " "introduction. (stream %d sec old)", (unsigned)introcirc->base_.n_circ_id, (unsigned)rendcirc->base_.n_circ_id, conn_age); - switch (rend_client_send_introduction(introcirc, rendcirc)) { + ret = hs_client_send_introduce1(introcirc, rendcirc); + switch (ret) { case 0: /* success */ rendcirc->base_.timestamp_dirty = time(NULL); introcirc->base_.timestamp_dirty = time(NULL); |