aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/or/hs_service.c81
-rw-r--r--src/or/hs_service.h6
2 files changed, 86 insertions, 1 deletions
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 85610de572..42523ed852 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -889,6 +889,7 @@ service_descriptor_free(hs_service_descriptor_t *desc)
smartlist_free(desc->hsdir_missing_info);
/* Cleanup all intro points. */
digest256map_free(desc->intro_points.map, service_intro_point_free_);
+ digestmap_free(desc->intro_points.failed_id, tor_free_);
tor_free(desc);
}
@@ -900,10 +901,71 @@ service_descriptor_new(void)
sdesc->desc = tor_malloc_zero(sizeof(hs_descriptor_t));
/* Initialize the intro points map. */
sdesc->intro_points.map = digest256map_new();
+ sdesc->intro_points.failed_id = digestmap_new();
sdesc->hsdir_missing_info = smartlist_new();
return sdesc;
}
+/* From the given service, remove all expired failing intro points for each
+ * descriptor. */
+static void
+remove_expired_failing_intro(hs_service_t *service, time_t now)
+{
+ tor_assert(service);
+
+ /* For both descriptors, cleanup the failing intro points list. */
+ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) {
+ DIGESTMAP_FOREACH_MODIFY(desc->intro_points.failed_id, key, time_t *, t) {
+ time_t failure_time = *t;
+ if ((failure_time + INTRO_CIRC_RETRY_PERIOD) <= now) {
+ MAP_DEL_CURRENT(key);
+ tor_free(t);
+ }
+ } DIGESTMAP_FOREACH_END;
+ } FOR_EACH_DESCRIPTOR_END;
+}
+
+/* For the given descriptor desc, put all node_t object found from its failing
+ * intro point list and put them in the given node_list. */
+static void
+setup_intro_point_exclude_list(const hs_service_descriptor_t *desc,
+ smartlist_t *node_list)
+{
+ tor_assert(desc);
+ tor_assert(node_list);
+
+ DIGESTMAP_FOREACH(desc->intro_points.failed_id, key, time_t *, t) {
+ (void) t; /* Make gcc happy. */
+ const node_t *node = node_get_by_id(key);
+ if (node) {
+ smartlist_add(node_list, (void *) node);
+ }
+ } DIGESTMAP_FOREACH_END;
+}
+
+/* For the given failing intro point ip, we add its time of failure to the
+ * failed map and index it by identity digest (legacy ID) in the descriptor
+ * desc failed id map. */
+static void
+remember_failing_intro_point(const hs_service_intro_point_t *ip,
+ hs_service_descriptor_t *desc, time_t now)
+{
+ time_t *time_of_failure, *prev_ptr;
+ const hs_desc_link_specifier_t *legacy_ls;
+
+ tor_assert(ip);
+ tor_assert(desc);
+
+ time_of_failure = tor_malloc_zero(sizeof(time_t));
+ *time_of_failure = now;
+ legacy_ls = get_link_spec_by_type(ip, LS_LEGACY_ID);
+ tor_assert(legacy_ls);
+ prev_ptr = digestmap_set(desc->intro_points.failed_id,
+ (const char *) legacy_ls->u.legacy_id,
+ time_of_failure);
+ tor_free(prev_ptr);
+}
+
/* Copy the descriptor link specifier object from src to dst. */
static void
link_specifier_copy(hs_desc_link_specifier_t *dst,
@@ -1318,6 +1380,9 @@ pick_needed_intro_points(hs_service_t *service,
hs_service_intro_point_t *, ip) {
smartlist_add(exclude_nodes, (void *) get_node_from_intro_point(ip));
} DIGEST256MAP_FOREACH_END;
+ /* Also, add the failing intro points that our descriptor encounteered in
+ * the exclude node list. */
+ setup_intro_point_exclude_list(desc, exclude_nodes);
for (i = 0; i < num_needed_ip; i++) {
hs_service_intro_point_t *ip;
@@ -1462,9 +1527,19 @@ cleanup_intro_points(hs_service_t *service, time_t now)
* reached the maximum number of retry with a non existing circuit. */
if (has_expired || node == NULL ||
(ocirc == NULL &&
- ip->circuit_retries >= MAX_INTRO_POINT_CIRCUIT_RETRIES)) {
+ ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES)) {
+ /* 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);
+
+ /* We've retried too many times, remember it has 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, now);
+ }
service_intro_point_free(ip);
+
/* XXX: Legacy code does NOT do that, it keeps the circuit open until
* a new descriptor is uploaded and then closed all expiring intro
* point circuit. Here, we close immediately and because we just
@@ -1550,6 +1625,10 @@ run_housekeeping_event(time_t now)
/* Cleanup invalid intro points from the service descriptor. */
cleanup_intro_points(service, now);
+ /* Remove expired failing intro point from the descriptor failed list. We
+ * reset them at each INTRO_CIRC_RETRY_PERIOD. */
+ remove_expired_failing_intro(service, now);
+
/* At this point, the service is now ready to go through the scheduled
* events guaranteeing a valid state. Intro points might be missing from
* the descriptors after the cleanup but the update/build process will
diff --git a/src/or/hs_service.h b/src/or/hs_service.h
index ba805117eb..be24bb4e31 100644
--- a/src/or/hs_service.h
+++ b/src/or/hs_service.h
@@ -87,6 +87,12 @@ typedef struct hs_service_intropoints_t {
/* Contains the current hs_service_intro_point_t objects indexed by
* authentication public key. */
digest256map_t *map;
+
+ /* Contains node's identity key digest that were introduction point for this
+ * descriptor but were retried to many times. We keep those so we avoid
+ * re-picking them over and over for a circuit retry period.
+ * XXX: Once we have #22173, change this to only use ed25519 identity. */
+ digestmap_t *failed_id;
} hs_service_intropoints_t;
/* Representation of a service descriptor. */