summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/circuitlist.c30
-rw-r--r--src/or/circuitlist.h2
-rw-r--r--src/or/hs_circuit.c28
-rw-r--r--src/or/hs_circuit.h3
-rw-r--r--src/or/hs_common.c1
-rw-r--r--src/or/hs_common.h2
-rw-r--r--src/or/hs_service.c15
7 files changed, 56 insertions, 25 deletions
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 82b9b84c1e..f074025a39 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -67,7 +67,6 @@
#include "main.h"
#include "hs_circuit.h"
#include "hs_circuitmap.h"
-#include "hs_common.h"
#include "hs_ident.h"
#include "networkstatus.h"
#include "nodelist.h"
@@ -995,6 +994,12 @@ circuit_free_(circuit_t *circ)
circuit_clear_testing_cell_stats(circ);
+ /* Cleanup circuit from anything HS v3 related. We also do this when the
+ * circuit is closed. This is to avoid any code path that free registered
+ * circuits without closing them before. This needs to be done before the
+ * hs identifier is freed. */
+ hs_circ_cleanup(circ);
+
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
mem = ocirc;
@@ -1020,7 +1025,11 @@ circuit_free_(circuit_t *circ)
crypto_pk_free(ocirc->intro_key);
rend_data_free(ocirc->rend_data);
+
+ /* Finally, free the identifier of the circuit and nullify it so multiple
+ * cleanup will work. */
hs_ident_circuit_free(ocirc->hs_ident);
+ ocirc->hs_ident = NULL;
tor_free(ocirc->dest_address);
if (ocirc->socks_username) {
@@ -1079,11 +1088,6 @@ circuit_free_(circuit_t *circ)
/* Remove from map. */
circuit_set_n_circid_chan(circ, 0, NULL);
- /* Clear HS circuitmap token from this circ (if any) */
- if (circ->hs_token) {
- hs_circuitmap_remove_circuit(circ);
- }
-
/* Clear cell queue _after_ removing it from the map. Otherwise our
* "active" checks will be violated. */
cell_queue_clear(&circ->n_chan_cells);
@@ -1993,6 +1997,9 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
}
}
+ /* Notify the HS subsystem that this circuit is closing. */
+ hs_circ_cleanup(circ);
+
if (circuits_pending_close == NULL)
circuits_pending_close = smartlist_new();
@@ -2073,13 +2080,6 @@ circuit_about_to_free(circuit_t *circ)
orig_reason);
}
- /* Notify the HS subsystem for any intro point circuit closing so it can be
- * dealt with cleanly. */
- if (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
- circ->purpose == CIRCUIT_PURPOSE_S_INTRO) {
- hs_service_intro_circ_has_closed(TO_ORIGIN_CIRCUIT(circ));
- }
-
if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
int timed_out = (reason == END_CIRC_REASON_TIMEOUT);
@@ -2556,8 +2556,8 @@ assert_cpath_ok(const crypt_path_t *cp)
/** Verify that circuit <b>c</b> has all of its invariants
* correct. Trigger an assert if anything is invalid.
*/
-void
-assert_circuit_ok(const circuit_t *c)
+MOCK_IMPL(void,
+assert_circuit_ok,(const circuit_t *c))
{
edge_connection_t *conn;
const or_circuit_t *or_circ = NULL;
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index 8868646d59..246f0c8815 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -73,7 +73,7 @@ int circuit_count_pending_on_channel(channel_t *chan);
circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__)
void assert_cpath_layer_ok(const crypt_path_t *cp);
-void assert_circuit_ok(const circuit_t *c);
+MOCK_DECL(void, assert_circuit_ok,(const circuit_t *c));
void circuit_free_all(void);
void circuits_handle_oom(size_t current_allocation);
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
index a232a40c80..95073522ed 100644
--- a/src/or/hs_circuit.c
+++ b/src/or/hs_circuit.c
@@ -1212,3 +1212,31 @@ hs_circ_send_establish_rendezvous(origin_circuit_t *circ)
return -1;
}
+/* We are about to close or free this <b>circ</b>. Clean it up from any
+ * related HS data structures. This function can be called multiple times
+ * safely for the same circuit. */
+void
+hs_circ_cleanup(circuit_t *circ)
+{
+ tor_assert(circ);
+
+ /* If it's a service-side intro circ, notify the HS subsystem for the intro
+ * point circuit closing so it can be dealt with cleanly. */
+ if (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
+ circ->purpose == CIRCUIT_PURPOSE_S_INTRO) {
+ hs_service_intro_circ_has_closed(TO_ORIGIN_CIRCUIT(circ));
+ }
+
+ /* Clear HS circuitmap token for this circ (if any). Very important to be
+ * done after the HS subsystem has been notified of the close else the
+ * circuit will not be found.
+ *
+ * We do this at the close if possible because from that point on, the
+ * circuit is good as dead. We can't rely on removing it in the circuit
+ * free() function because we open a race window between the close and free
+ * where we can't register a new circuit for the same intro point. */
+ if (circ->hs_token) {
+ hs_circuitmap_remove_circuit(circ);
+ }
+}
+
diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h
index b92fb4e494..2f5beaa168 100644
--- a/src/or/hs_circuit.h
+++ b/src/or/hs_circuit.h
@@ -15,6 +15,9 @@
#include "hs_service.h"
+/* Cleanup function when the circuit is closed or/and freed. */
+void hs_circ_cleanup(circuit_t *circ);
+
/* Circuit API. */
int hs_circ_service_intro_has_opened(hs_service_t *service,
hs_service_intro_point_t *ip,
diff --git a/src/or/hs_common.c b/src/or/hs_common.c
index fcc524ae1c..2c0c2aecd2 100644
--- a/src/or/hs_common.c
+++ b/src/or/hs_common.c
@@ -22,6 +22,7 @@
#include "hs_client.h"
#include "hs_ident.h"
#include "hs_service.h"
+#include "hs_circuitmap.h"
#include "policies.h"
#include "rendcommon.h"
#include "rendservice.h"
diff --git a/src/or/hs_common.h b/src/or/hs_common.h
index 40fa1bc466..97fd504d06 100644
--- a/src/or/hs_common.h
+++ b/src/or/hs_common.h
@@ -172,6 +172,8 @@ typedef struct hsdir_index_t {
void hs_init(void);
void hs_free_all(void);
+void hs_cleanup_circ(circuit_t *circ);
+
int hs_check_service_private_dir(const char *username, const char *path,
unsigned int dir_group_readable,
unsigned int create);
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 4190f1a038..0d208daa45 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -1843,6 +1843,12 @@ cleanup_intro_points(hs_service_t *service, time_t now)
(node == NULL) ? " fell off the consensus" : "",
ip->circuit_retries);
+ /* We've retried too many times, remember it as a failed intro point
+ * so we don't pick it up again for INTRO_CIRC_RETRY_PERIOD sec. */
+ if (ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES) {
+ remember_failing_intro_point(ip, desc, approx_time());
+ }
+
/* Remove intro point from descriptor map. We'll add it to the failed
* map if we retried it too many times. */
MAP_DEL_CURRENT(key);
@@ -3131,15 +3137,6 @@ hs_service_intro_circ_has_closed(origin_circuit_t *circ)
* keeping the object in the descriptor, we'll be able to retry. */
ip->circuit_established = 0;
- /* We've retried too many times, remember it as a failed intro point so we
- * don't pick it up again. It will be retried in INTRO_CIRC_RETRY_PERIOD
- * seconds. */
- if (ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES) {
- remember_failing_intro_point(ip, desc, approx_time());
- service_intro_point_remove(service, ip);
- service_intro_point_free(ip);
- }
-
end:
return;
}