summaryrefslogtreecommitdiff
path: root/src/or/circuituse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/circuituse.c')
-rw-r--r--src/or/circuituse.c144
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);