aboutsummaryrefslogtreecommitdiff
path: root/src/feature/hs
diff options
context:
space:
mode:
authorGeorge Kadianakis <desnacked@riseup.net>2020-04-08 18:15:37 +0300
committerGeorge Kadianakis <desnacked@riseup.net>2020-04-08 18:15:37 +0300
commit7a82c972efacb5004431ae81326b3a8e55d5fac7 (patch)
tree8ac7a83885ac9bfc1fab2d3661a5c6f61873705c /src/feature/hs
parentc1bf819a31d729abee8cf1440cefb7b4776248cc (diff)
parent92ae8cea30d5c4b3cd5283abf571ffdb5ed06bcb (diff)
downloadtor-7a82c972efacb5004431ae81326b3a8e55d5fac7.tar.gz
tor-7a82c972efacb5004431ae81326b3a8e55d5fac7.zip
Merge branch 'tor-github/pr/1857'
Diffstat (limited to 'src/feature/hs')
-rw-r--r--src/feature/hs/hs_circuit.c18
-rw-r--r--src/feature/hs/hs_client.c110
-rw-r--r--src/feature/hs/hs_client.h1
3 files changed, 129 insertions, 0 deletions
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index dc13c7045e..53f574c14a 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -622,6 +622,20 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
}
/** Helper: cleanup function for client circuit. This is for every HS version.
+ * It is called from hs_circ_cleanup_on_close() entry point. */
+static void
+cleanup_on_close_client_circ(circuit_t *circ)
+{
+ tor_assert(circ);
+
+ if (circuit_is_hs_v3(circ)) {
+ hs_client_circuit_cleanup_on_close(circ);
+ }
+ /* It is possible the circuit has an HS purpose but no identifier (rend_data
+ * or hs_ident). Thus possible that this passess through. */
+}
+
+/** Helper: cleanup function for client circuit. This is for every HS version.
* It is called from hs_circ_cleanup_on_free() entry point. */
static void
cleanup_on_free_client_circ(circuit_t *circ)
@@ -1293,6 +1307,10 @@ hs_circ_cleanup_on_close(circuit_t *circ)
{
tor_assert(circ);
+ if (circuit_purpose_is_hs_client(circ->purpose)) {
+ cleanup_on_close_client_circ(circ);
+ }
+
/* On close, we simply remove it from the circuit map. It can not be used
* anymore. We keep this code path fast and lean. */
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index cc1b01d2ef..40647ac256 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -961,6 +961,81 @@ client_get_random_intro(const ed25519_public_key_t *service_pk)
return ei;
}
+/** Return true iff all intro points for the given service have timed out. */
+static bool
+intro_points_all_timed_out(const ed25519_public_key_t *service_pk)
+{
+ bool ret = false;
+
+ tor_assert(service_pk);
+
+ const hs_descriptor_t *desc = hs_cache_lookup_as_client(service_pk);
+
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ const hs_desc_intro_point_t *, ip) {
+ const hs_cache_intro_state_t *state =
+ hs_cache_client_intro_state_find(service_pk,
+ &ip->auth_key_cert->signed_key);
+ if (!state || !state->timed_out) {
+ /* No state or if this intro point has not timed out, we are done since
+ * clearly not all of them have timed out. */
+ goto end;
+ }
+ } SMARTLIST_FOREACH_END(ip);
+
+ /* Exiting the loop here means that all intro points we've looked at have
+ * timed out. Note that we can _not_ have a descriptor without intro points
+ * in the client cache. */
+ ret = true;
+
+ end:
+ return ret;
+}
+
+/** Called when a rendezvous circuit has timed out. Every streams attached to
+ * the circuit will get set with the SOCKS5_HS_REND_FAILED (0xF3) extended
+ * error code so if the connection to the rendezvous point ends up not
+ * working, this code could be sent back as a reason. */
+static void
+socks_report_rend_circuit_timed_out(const origin_circuit_t *rend_circ)
+{
+ tor_assert(rend_circ);
+
+ /* For each entry connections attached to this rendezvous circuit, report
+ * the error. */
+ for (edge_connection_t *edge = rend_circ->p_streams; edge;
+ edge = edge->next_stream) {
+ entry_connection_t *entry = EDGE_TO_ENTRY_CONN(edge);
+ if (entry->socks_request) {
+ entry->socks_request->socks_extended_error_code =
+ SOCKS5_HS_REND_FAILED;
+ }
+ }
+}
+
+/** Called when introduction has failed meaning there is no more usable
+ * introduction points to be used (either NACKed or failed) for the given
+ * entry connection.
+ *
+ * This function only reports back the SOCKS5_HS_INTRO_FAILED (0xF2) code or
+ * SOCKS5_HS_INTRO_TIMEDOUT (0xF7) if all intros have timed out. The caller
+ * has to make sure to close the entry connections. */
+static void
+socks_report_introduction_failed(entry_connection_t *conn,
+ const ed25519_public_key_t *identity_pk)
+{
+ socks5_reply_status_t code = SOCKS5_HS_INTRO_FAILED;
+
+ tor_assert(conn);
+ tor_assert(conn->socks_request);
+ tor_assert(identity_pk);
+
+ if (intro_points_all_timed_out(identity_pk)) {
+ code = SOCKS5_HS_INTRO_TIMEDOUT;
+ }
+ conn->socks_request->socks_extended_error_code = code;
+}
+
/** For this introduction circuit, we'll look at if we have any usable
* introduction point left for this service. If so, we'll use the circuit to
* re-extend to a new intro point. Else, we'll close the circuit and its
@@ -1313,6 +1388,10 @@ client_desc_has_arrived(const smartlist_t *entry_conns)
if (!hs_client_any_intro_points_usable(identity_pk, desc)) {
log_info(LD_REND, "Hidden service descriptor is unusable. "
"Closing streams.");
+ /* Report the extended socks error code that we were unable to introduce
+ * to the service. */
+ socks_report_introduction_failed(entry_conn, identity_pk);
+
connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_RESOLVEFAILED);
/* We are unable to use the descriptor so remove the directory request
@@ -1762,6 +1841,37 @@ get_hs_client_auths_map(void)
/* ========== */
/** Called when a circuit was just cleaned up. This is done right before the
+ * circuit is marked for close. */
+void
+hs_client_circuit_cleanup_on_close(const circuit_t *circ)
+{
+ bool has_timed_out;
+
+ tor_assert(circ);
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+
+ has_timed_out =
+ (circ->marked_for_close_orig_reason == END_CIRC_REASON_TIMEOUT);
+
+ switch (circ->purpose) {
+ case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
+ case CIRCUIT_PURPOSE_C_REND_READY:
+ case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
+ case CIRCUIT_PURPOSE_C_REND_JOINED:
+ /* Report extended SOCKS error code when a rendezvous circuit timeouts.
+ * This MUST be done on_close() because it is possible the entry
+ * connection would get closed before the circuit is freed and thus
+ * failing to report the error code. */
+ if (has_timed_out) {
+ socks_report_rend_circuit_timed_out(CONST_TO_ORIGIN_CIRCUIT(circ));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/** Called when a circuit was just cleaned up. This is done right before the
* circuit is freed. */
void
hs_client_circuit_cleanup_on_free(const circuit_t *circ)
diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h
index 3660bfa96c..685b10f955 100644
--- a/src/feature/hs/hs_client.h
+++ b/src/feature/hs/hs_client.h
@@ -110,6 +110,7 @@ int hs_client_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ);
void hs_client_circuit_has_opened(origin_circuit_t *circ);
+void hs_client_circuit_cleanup_on_close(const circuit_t *circ);
void hs_client_circuit_cleanup_on_free(const circuit_t *circ);
int hs_client_receive_rendezvous_acked(origin_circuit_t *circ,