aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorDavid Goulet <dgoulet@torproject.org>2017-10-04 16:22:49 -0400
committerNick Mathewson <nickm@torproject.org>2017-10-31 12:14:11 -0400
commit5dbcd48f0ee2f57557f6bcce6ee3ec11a76727e4 (patch)
tree72f3357325a41bef64b6ed18c5403a530c1155f2 /src/or
parent469ee6e6fe0dbc9bb7b3c8ceed8aa7c494fd4ac3 (diff)
downloadtor-5dbcd48f0ee2f57557f6bcce6ee3ec11a76727e4.tar.gz
tor-5dbcd48f0ee2f57557f6bcce6ee3ec11a76727e4.zip
hs-v3: Attempt descriptor refetch when dirinfo changes
When the directory information changes, callback to the HS client subsystem so it can check if any pending SOCKS connections are waiting for a descriptor. If yes, attempt a refetch for those. Fixes #23762 Signed-off-by: David Goulet <dgoulet@torproject.org>
Diffstat (limited to 'src/or')
-rw-r--r--src/or/connection_edge.c9
-rw-r--r--src/or/hs_client.c59
-rw-r--r--src/or/hs_client.h1
-rw-r--r--src/or/nodelist.c2
4 files changed, 66 insertions, 5 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 77dac62b09..b9d8eeaff6 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1571,10 +1571,10 @@ connection_ap_handle_onion(entry_connection_t *conn,
int ret = hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk);
switch (ret) {
case HS_CLIENT_FETCH_MISSING_INFO:
- /* By going to the end, the connection is put in waiting for a circuit
- * state which means that it will be retried and consider as a pending
- * connection. */
- goto end;
+ /* Keeping the connection in descriptor wait state is fine because
+ * once we get enough dirinfo or a new live consensus, the HS client
+ * subsystem is notified and every connection in that state will
+ * trigger a fetch for the service key. */
case HS_CLIENT_FETCH_LAUNCHED:
case HS_CLIENT_FETCH_PENDING:
case HS_CLIENT_FETCH_HAVE_DESC:
@@ -1591,7 +1591,6 @@ connection_ap_handle_onion(entry_connection_t *conn,
/* We have the descriptor! So launch a connection to the HS. */
log_info(LD_REND, "Descriptor is here. Great.");
- end:
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
/* We'll try to attach it at the next event loop, or whenever
* we call connection_ap_attach_pending() */
diff --git a/src/or/hs_client.c b/src/or/hs_client.c
index d66e563528..18b76e8b38 100644
--- a/src/or/hs_client.c
+++ b/src/or/hs_client.c
@@ -233,6 +233,55 @@ close_all_socks_conns_waiting_for_desc(const ed25519_public_key_t *identity_pk,
smartlist_free(conns);
}
+/* Find all pending SOCKS connection waiting for a descriptor and retry them
+ * all. This is called when the directory information changed. */
+static void
+retry_all_socks_conn_waiting_for_desc(void)
+{
+ smartlist_t *conns =
+ connection_list_by_type_state(CONN_TYPE_AP, AP_CONN_STATE_RENDDESC_WAIT);
+
+ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
+ hs_client_fetch_status_t status;
+ const edge_connection_t *edge_conn =
+ ENTRY_TO_EDGE_CONN(TO_ENTRY_CONN(base_conn));
+
+ /* Ignore non HS or non v3 connection. */
+ if (edge_conn->hs_ident == NULL) {
+ continue;
+ }
+ /* In this loop, we will possibly try to fetch a descriptor for the
+ * pending connections because we just got more directory information.
+ * However, the refetch process can cleanup all SOCKS request so the same
+ * service if an internal error happens. Thus, we can end up with closed
+ * connections in our list. */
+ if (base_conn->marked_for_close) {
+ continue;
+ }
+
+ /* XXX: There is an optimization we could do which is that for a service
+ * key, we could check if we can fetch and remember that decision. */
+
+ /* Order a refetch in case it works this time. */
+ status = hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk);
+ if (BUG(status == HS_CLIENT_FETCH_HAVE_DESC)) {
+ /* This case is unique because it can NOT happen in theory. Once we get
+ * a new descriptor, the HS client subsystem is notified immediately and
+ * the connections waiting for it are handled which means the state will
+ * change from renddesc wait state. Log this and continue to next
+ * connection. */
+ continue;
+ }
+ /* In the case of an error, either all SOCKS connections have been
+ * closed or we are still missing directory information. Leave the
+ * connection in renddesc wait state so when we get more info, we'll be
+ * able to try it again. */
+ } SMARTLIST_FOREACH_END(base_conn);
+
+ /* We don't have ownership of those objects. */
+ smartlist_free(conns);
+}
+
/* A v3 HS circuit successfully connected to the hidden service. Update the
* stream state at <b>hs_conn_ident</b> appropriately. */
static void
@@ -1529,3 +1578,13 @@ hs_client_purge_state(void)
log_info(LD_REND, "Hidden service client state has been purged.");
}
+/* Called when our directory information has changed. */
+void
+hs_client_dir_info_changed(void)
+{
+ /* We have possibly reached the minimum directory information or new
+ * consensus so retry all pending SOCKS connection in
+ * AP_CONN_STATE_RENDDESC_WAIT state in order to fetch the descriptor. */
+ retry_all_socks_conn_waiting_for_desc();
+}
+
diff --git a/src/or/hs_client.h b/src/or/hs_client.h
index 164accc0e6..2523568ad1 100644
--- a/src/or/hs_client.h
+++ b/src/or/hs_client.h
@@ -41,6 +41,7 @@ int hs_client_decode_descriptor(
int hs_client_any_intro_points_usable(const ed25519_public_key_t *service_pk,
const hs_descriptor_t *desc);
int hs_client_refetch_hsdesc(const ed25519_public_key_t *identity_pk);
+void hs_client_dir_info_changed(void);
int hs_client_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ);
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index eae74e18b5..fd5a8f0c0d 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -48,6 +48,7 @@
#include "entrynodes.h"
#include "geoip.h"
#include "hs_common.h"
+#include "hs_client.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@@ -1973,6 +1974,7 @@ router_dir_info_changed(void)
need_to_update_have_min_dir_info = 1;
rend_hsdir_routers_changed();
hs_service_dir_info_changed();
+ hs_client_dir_info_changed();
}
/** Return a string describing what we're missing before we have enough