aboutsummaryrefslogtreecommitdiff
path: root/src/or/rendclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/rendclient.c')
-rw-r--r--src/or/rendclient.c461
1 files changed, 315 insertions, 146 deletions
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 162e0ac53e..a39e518e99 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -38,6 +38,7 @@ void
rend_client_purge_state(void)
{
rend_cache_purge();
+ rend_cache_failure_purge();
rend_client_cancel_descriptor_fetches();
rend_client_purge_last_hid_serv_requests();
}
@@ -141,7 +142,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
int r, v3_shift = 0;
char payload[RELAY_PAYLOAD_SIZE];
char tmp[RELAY_PAYLOAD_SIZE];
- rend_cache_entry_t *entry;
+ rend_cache_entry_t *entry = NULL;
crypt_path_t *cpath;
off_t dh_offset;
crypto_pk_t *intro_key = NULL;
@@ -158,8 +159,13 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
tor_assert(!(rendcirc->build_state->onehop_tunnel));
#endif
- if (rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
- &entry) < 1) {
+ r = rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
+ &entry);
+ /* An invalid onion address is not possible else we have a big issue. */
+ tor_assert(r != -EINVAL);
+ if (r < 0 || !rend_client_any_intro_points_usable(entry)) {
+ /* If the descriptor is not found or the intro points are not usable
+ * anymore, trigger a fetch. */
log_info(LD_REND,
"query %s didn't have valid rend desc in cache. "
"Refetching descriptor.",
@@ -469,9 +475,8 @@ rend_client_introduction_acked(origin_circuit_t *circ,
/** Contains the last request times to hidden service directories for
* certain queries; each key is a string consisting of the
- * concatenation of a base32-encoded HS directory identity digest, a
- * base32-encoded HS descriptor ID, and a hidden service address
- * (without the ".onion" part); each value is a pointer to a time_t
+ * concatenation of a base32-encoded HS directory identity digest and
+ * base32-encoded HS descriptor ID; each value is a pointer to a time_t
* holding the time of the last request for that descriptor ID to that
* HS directory. */
static strmap_t *last_hid_serv_requests_ = NULL;
@@ -487,19 +492,16 @@ get_last_hid_serv_requests(void)
}
#define LAST_HID_SERV_REQUEST_KEY_LEN (REND_DESC_ID_V2_LEN_BASE32 + \
- REND_DESC_ID_V2_LEN_BASE32 + \
- REND_SERVICE_ID_LEN_BASE32)
+ REND_DESC_ID_V2_LEN_BASE32)
/** Look up the last request time to hidden service directory <b>hs_dir</b>
- * for descriptor ID <b>desc_id_base32</b> for the service specified in
- * <b>rend_query</b>. If <b>set</b> is non-zero,
- * assign the current time <b>now</b> and return that. Otherwise, return
- * the most recent request time, or 0 if no such request has been sent
- * before. */
+ * for descriptor ID <b>desc_id_base32</b>. If <b>set</b> is non-zero,
+ * assign the current time <b>now</b> and return that. Otherwise, return the
+ * most recent request time, or 0 if no such request has been sent before.
+ */
static time_t
lookup_last_hid_serv_request(routerstatus_t *hs_dir,
const char *desc_id_base32,
- const rend_data_t *rend_query,
time_t now, int set)
{
char hsdir_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
@@ -508,10 +510,9 @@ lookup_last_hid_serv_request(routerstatus_t *hs_dir,
strmap_t *last_hid_serv_requests = get_last_hid_serv_requests();
base32_encode(hsdir_id_base32, sizeof(hsdir_id_base32),
hs_dir->identity_digest, DIGEST_LEN);
- tor_snprintf(hsdir_desc_comb_id, sizeof(hsdir_desc_comb_id), "%s%s%s",
+ tor_snprintf(hsdir_desc_comb_id, sizeof(hsdir_desc_comb_id), "%s%s",
hsdir_id_base32,
- desc_id_base32,
- rend_query->onion_address);
+ desc_id_base32);
/* XXX023 tor_assert(strlen(hsdir_desc_comb_id) ==
LAST_HID_SERV_REQUEST_KEY_LEN); */
if (set) {
@@ -552,20 +553,23 @@ directory_clean_last_hid_serv_requests(time_t now)
}
}
-/** Remove all requests related to the hidden service named
- * <b>onion_address</b> from the history of times of requests to
- * hidden service directories.
+/** Remove all requests related to the descriptor ID <b>desc_id</b> from the
+ * history of times of requests to hidden service directories.
+ * <b>desc_id</b> is an unencoded descriptor ID of size DIGEST_LEN.
*
* This is called from rend_client_note_connection_attempt_ended(), which
- * must be idempotent, so any future changes to this function must leave
- * it idempotent too.
- */
+ * must be idempotent, so any future changes to this function must leave it
+ * idempotent too. */
static void
-purge_hid_serv_from_last_hid_serv_requests(const char *onion_address)
+purge_hid_serv_from_last_hid_serv_requests(const char *desc_id)
{
strmap_iter_t *iter;
strmap_t *last_hid_serv_requests = get_last_hid_serv_requests();
- /* XXX023 tor_assert(strlen(onion_address) == REND_SERVICE_ID_LEN_BASE32); */
+ char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+
+ /* Key is stored with the base32 encoded desc_id. */
+ base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
+ DIGEST_LEN);
for (iter = strmap_iter_init(last_hid_serv_requests);
!strmap_iter_done(iter); ) {
const char *key;
@@ -573,9 +577,9 @@ purge_hid_serv_from_last_hid_serv_requests(const char *onion_address)
strmap_iter_get(iter, &key, &val);
/* XXX023 tor_assert(strlen(key) == LAST_HID_SERV_REQUEST_KEY_LEN); */
if (tor_memeq(key + LAST_HID_SERV_REQUEST_KEY_LEN -
- REND_SERVICE_ID_LEN_BASE32,
- onion_address,
- REND_SERVICE_ID_LEN_BASE32)) {
+ REND_DESC_ID_V2_LEN_BASE32,
+ desc_id_base32,
+ REND_DESC_ID_V2_LEN_BASE32)) {
iter = strmap_iter_next_rmv(last_hid_serv_requests, iter);
tor_free(val);
} else {
@@ -604,64 +608,53 @@ rend_client_purge_last_hid_serv_requests(void)
}
}
-/** Determine the responsible hidden service directories for <b>desc_id</b>
- * and fetch the descriptor with that ID from one of them. Only
- * send a request to a hidden service directory that we have not yet tried
- * during this attempt to connect to this hidden service; on success, return 1,
- * in the case that no hidden service directory is left to ask for the
- * descriptor, return 0, and in case of a failure -1. */
-static int
-directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query)
+/** This returns a good valid hs dir that should be used for the given
+ * descriptor id.
+ *
+ * Return NULL on error else the hsdir node pointer. */
+static routerstatus_t *
+pick_hsdir(const char *desc_id, const char *desc_id_base32)
{
smartlist_t *responsible_dirs = smartlist_new();
smartlist_t *usable_responsible_dirs = smartlist_new();
const or_options_t *options = get_options();
routerstatus_t *hs_dir;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
time_t now = time(NULL);
- char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
-#ifdef ENABLE_TOR2WEB_MODE
- const int tor2web_mode = options->Tor2webMode;
- const int how_to_fetch = tor2web_mode ? DIRIND_ONEHOP : DIRIND_ANONYMOUS;
-#else
- const int how_to_fetch = DIRIND_ANONYMOUS;
-#endif
int excluded_some;
- tor_assert(desc_id);
- tor_assert(rend_query);
- /* Determine responsible dirs. Even if we can't get all we want,
- * work with the ones we have. If it's empty, we'll notice below. */
- hid_serv_get_responsible_directories(responsible_dirs, desc_id);
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- desc_id, DIGEST_LEN);
+ tor_assert(desc_id);
+ tor_assert(desc_id_base32);
- /* Only select those hidden service directories to which we did not send
- * a request recently and for which we have a router descriptor here. */
+ /* Determine responsible dirs. Even if we can't get all we want, work with
+ * the ones we have. If it's empty, we'll notice below. */
+ hid_serv_get_responsible_directories(responsible_dirs, desc_id);
/* Clean request history first. */
directory_clean_last_hid_serv_requests(now);
- SMARTLIST_FOREACH(responsible_dirs, routerstatus_t *, dir, {
- time_t last = lookup_last_hid_serv_request(
- dir, desc_id_base32, rend_query, 0, 0);
- const node_t *node = node_get_by_id(dir->identity_digest);
- if (last + REND_HID_SERV_DIR_REQUERY_PERIOD >= now ||
- !node || !node_has_descriptor(node)) {
- SMARTLIST_DEL_CURRENT(responsible_dirs, dir);
- continue;
- }
- if (! routerset_contains_node(options->ExcludeNodes, node)) {
- smartlist_add(usable_responsible_dirs, dir);
- }
- });
+ /* Only select those hidden service directories to which we did not send a
+ * request recently and for which we have a router descriptor here. */
+ SMARTLIST_FOREACH_BEGIN(responsible_dirs, routerstatus_t *, dir) {
+ time_t last = lookup_last_hid_serv_request(dir, desc_id_base32,
+ 0, 0);
+ const node_t *node = node_get_by_id(dir->identity_digest);
+ if (last + REND_HID_SERV_DIR_REQUERY_PERIOD >= now ||
+ !node || !node_has_descriptor(node)) {
+ SMARTLIST_DEL_CURRENT(responsible_dirs, dir);
+ continue;
+ }
+ if (!routerset_contains_node(options->ExcludeNodes, node)) {
+ smartlist_add(usable_responsible_dirs, dir);
+ }
+ } SMARTLIST_FOREACH_END(dir);
excluded_some =
smartlist_len(usable_responsible_dirs) < smartlist_len(responsible_dirs);
hs_dir = smartlist_choose(usable_responsible_dirs);
- if (! hs_dir && ! options->StrictNodes)
+ if (!hs_dir && !options->StrictNodes) {
hs_dir = smartlist_choose(responsible_dirs);
+ }
smartlist_free(responsible_dirs);
smartlist_free(usable_responsible_dirs);
@@ -674,23 +667,69 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query)
"requested hidden service: they are all either down or "
"excluded, and StrictNodes is set.");
}
- return 0;
+ } else {
+ /* Remember that we are requesting a descriptor from this hidden service
+ * directory now. */
+ lookup_last_hid_serv_request(hs_dir, desc_id_base32, now, 1);
+ }
+
+ return hs_dir;
+}
+
+/** Determine the responsible hidden service directories for <b>desc_id</b>
+ * and fetch the descriptor with that ID from one of them. Only
+ * send a request to a hidden service directory that we have not yet tried
+ * during this attempt to connect to this hidden service; on success, return 1,
+ * in the case that no hidden service directory is left to ask for the
+ * descriptor, return 0, and in case of a failure -1. */
+static int
+directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query,
+ routerstatus_t *rs_hsdir)
+{
+ routerstatus_t *hs_dir = rs_hsdir;
+ char *hsdir_fp;
+ char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+ char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
+#ifdef ENABLE_TOR2WEB_MODE
+ const int tor2web_mode = get_options()->Tor2webMode;
+ const int how_to_fetch = tor2web_mode ? DIRIND_ONEHOP : DIRIND_ANONYMOUS;
+#else
+ const int how_to_fetch = DIRIND_ANONYMOUS;
+#endif
+
+ tor_assert(desc_id);
+
+ base32_encode(desc_id_base32, sizeof(desc_id_base32),
+ desc_id, DIGEST_LEN);
+
+ /* Automatically pick an hs dir if none given. */
+ if (!rs_hsdir) {
+ hs_dir = pick_hsdir(desc_id, desc_id_base32);
+ if (!hs_dir) {
+ /* No suitable hs dir can be found, stop right now. */
+ return 0;
+ }
}
- /* Remember that we are requesting a descriptor from this hidden service
- * directory now. */
- lookup_last_hid_serv_request(hs_dir, desc_id_base32, rend_query, now, 1);
+ /* Add a copy of the HSDir identity digest to the query so we can track it
+ * on the control port. */
+ hsdir_fp = tor_memdup(hs_dir->identity_digest,
+ sizeof(hs_dir->identity_digest));
+ smartlist_add(rend_query->hsdirs_fp, hsdir_fp);
- /* Encode descriptor cookie for logging purposes. */
+ /* Encode descriptor cookie for logging purposes. Also, if the cookie is
+ * malformed, no fetch is triggered thus this needs to be done before the
+ * fetch request. */
if (rend_query->auth_type != REND_NO_AUTH) {
if (base64_encode(descriptor_cookie_base64,
sizeof(descriptor_cookie_base64),
- rend_query->descriptor_cookie, REND_DESC_COOKIE_LEN)<0) {
+ rend_query->descriptor_cookie, REND_DESC_COOKIE_LEN,
+ 0)<0) {
log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
return 0;
}
- /* Remove == signs and newline. */
- descriptor_cookie_base64[strlen(descriptor_cookie_base64)-3] = '\0';
+ /* Remove == signs. */
+ descriptor_cookie_base64[strlen(descriptor_cookie_base64)-2] = '\0';
} else {
strlcpy(descriptor_cookie_base64, "(none)",
sizeof(descriptor_cookie_base64));
@@ -721,16 +760,144 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query)
return 1;
}
+/** Fetch a v2 descriptor using the given descriptor id. If any hsdir(s) are
+ * given, they will be used instead.
+ *
+ * On success, 1 is returned. If no hidden service is left to ask, return 0.
+ * On error, -1 is returned. */
+static int
+fetch_v2_desc_by_descid(const char *desc_id, const rend_data_t *rend_query,
+ smartlist_t *hsdirs)
+{
+ int ret;
+
+ tor_assert(rend_query);
+
+ if (!hsdirs) {
+ ret = directory_get_from_hs_dir(desc_id, rend_query, NULL);
+ goto end; /* either success or failure, but we're done */
+ }
+
+ /* Using the given hsdir list, trigger a fetch on each of them. */
+ SMARTLIST_FOREACH_BEGIN(hsdirs, routerstatus_t *, hs_dir) {
+ /* This should always be a success. */
+ ret = directory_get_from_hs_dir(desc_id, rend_query, hs_dir);
+ tor_assert(ret);
+ } SMARTLIST_FOREACH_END(hs_dir);
+
+ /* Everything went well. */
+ ret = 0;
+
+ end:
+ return ret;
+}
+
+/** Fetch a v2 descriptor using the onion address in the given query object.
+ * This will compute the descriptor id for each replicas and fetch it on the
+ * given hsdir(s) if any or the responsible ones that are choosen
+ * automatically.
+ *
+ * On success, 1 is returned. If no hidden service is left to ask, return 0.
+ * On error, -1 is returned. */
+static int
+fetch_v2_desc_by_addr(rend_data_t *query, smartlist_t *hsdirs)
+{
+ char descriptor_id[DIGEST_LEN];
+ int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
+ int i, tries_left, ret;
+
+ tor_assert(query);
+
+ /* Randomly iterate over the replicas until a descriptor can be fetched
+ * from one of the consecutive nodes, or no options are left. */
+ for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++) {
+ replicas_left_to_try[i] = i;
+ }
+
+ tries_left = REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
+ while (tries_left > 0) {
+ int rand = crypto_rand_int(tries_left);
+ int chosen_replica = replicas_left_to_try[rand];
+ replicas_left_to_try[rand] = replicas_left_to_try[--tries_left];
+
+ ret = rend_compute_v2_desc_id(descriptor_id, query->onion_address,
+ query->auth_type == REND_STEALTH_AUTH ?
+ query->descriptor_cookie : NULL,
+ time(NULL), chosen_replica);
+ if (ret < 0) {
+ /* Normally, on failure the descriptor_id is untouched but let's be
+ * safe in general in case the function changes at some point. */
+ goto end;
+ }
+
+ if (tor_memcmp(descriptor_id, query->descriptor_id[chosen_replica],
+ sizeof(descriptor_id)) != 0) {
+ /* Not equal from what we currently have so purge the last hid serv
+ * request cache and update the descriptor ID with the new value. */
+ purge_hid_serv_from_last_hid_serv_requests(
+ query->descriptor_id[chosen_replica]);
+ memcpy(query->descriptor_id[chosen_replica], descriptor_id,
+ sizeof(query->descriptor_id[chosen_replica]));
+ }
+
+ /* Trigger the fetch with the computed descriptor ID. */
+ ret = fetch_v2_desc_by_descid(descriptor_id, query, hsdirs);
+ if (ret != 0) {
+ /* Either on success or failure, as long as we tried a fetch we are
+ * done here. */
+ goto end;
+ }
+ }
+
+ /* If we come here, there are no hidden service directories left. */
+ log_info(LD_REND, "Could not pick one of the responsible hidden "
+ "service directories to fetch descriptors, because "
+ "we already tried them all unsuccessfully.");
+ ret = 0;
+
+ end:
+ memwipe(descriptor_id, 0, sizeof(descriptor_id));
+ return ret;
+}
+
+/** Fetch a v2 descriptor using the given query. If any hsdir are specified,
+ * use them for the fetch.
+ *
+ * On success, 1 is returned. If no hidden service is left to ask, return 0.
+ * On error, -1 is returned. */
+int
+rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs)
+{
+ int ret;
+
+ tor_assert(query);
+
+ /* Depending on what's available in the rend data query object, we will
+ * trigger a fetch by HS address or using a descriptor ID. */
+
+ if (query->onion_address[0] != '\0') {
+ ret = fetch_v2_desc_by_addr(query, hsdirs);
+ } else if (!tor_digest_is_zero(query->desc_id_fetch)) {
+ ret = fetch_v2_desc_by_descid(query->desc_id_fetch, query, hsdirs);
+ } else {
+ /* Query data is invalid. */
+ ret = -1;
+ goto error;
+ }
+
+ error:
+ return ret;
+}
+
/** Unless we already have a descriptor for <b>rend_query</b> with at least
* one (possibly) working introduction point in it, start a connection to a
* hidden service directory to fetch a v2 rendezvous service descriptor. */
void
-rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
+rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
{
- char descriptor_id[DIGEST_LEN];
- int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
- int i, tries_left;
+ int ret;
rend_cache_entry_t *e = NULL;
+
tor_assert(rend_query);
/* Are we configured to fetch descriptors? */
if (!get_options()->FetchHidServDescriptors) {
@@ -739,7 +906,7 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
return;
}
/* Before fetching, check if we already have a usable descriptor here. */
- if (rend_cache_lookup_entry(rend_query->onion_address, -1, &e) > 0 &&
+ if (rend_cache_lookup_entry(rend_query->onion_address, -1, &e) == 0 &&
rend_client_any_intro_points_usable(e)) {
log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we "
"already have a usable descriptor here. Not fetching.");
@@ -747,44 +914,12 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
}
log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s",
safe_str_client(rend_query->onion_address));
- /* Randomly iterate over the replicas until a descriptor can be fetched
- * from one of the consecutive nodes, or no options are left. */
- tries_left = REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
- for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++)
- replicas_left_to_try[i] = i;
- while (tries_left > 0) {
- int rand = crypto_rand_int(tries_left);
- int chosen_replica = replicas_left_to_try[rand];
- replicas_left_to_try[rand] = replicas_left_to_try[--tries_left];
- if (rend_compute_v2_desc_id(descriptor_id, rend_query->onion_address,
- rend_query->auth_type == REND_STEALTH_AUTH ?
- rend_query->descriptor_cookie : NULL,
- time(NULL), chosen_replica) < 0) {
- log_warn(LD_REND, "Internal error: Computing v2 rendezvous "
- "descriptor ID did not succeed.");
- /*
- * Hmm, can this write anything to descriptor_id and still fail?
- * Let's clear it just to be safe.
- *
- * From here on, any returns should goto done which clears
- * descriptor_id so we don't leave key-derived material on the stack.
- */
- goto done;
- }
- if (directory_get_from_hs_dir(descriptor_id, rend_query) != 0)
- goto done; /* either success or failure, but we're done */
+ ret = rend_client_fetch_v2_desc(rend_query, NULL);
+ if (ret <= 0) {
+ /* Close pending connections on error or if no hsdir can be found. */
+ rend_client_desc_trynow(rend_query->onion_address);
}
- /* If we come here, there are no hidden service directories left. */
- log_info(LD_REND, "Could not pick one of the responsible hidden "
- "service directories to fetch descriptors, because "
- "we already tried them all unsuccessfully.");
- /* Close pending connections. */
- rend_client_desc_trynow(rend_query->onion_address);
-
- done:
- memwipe(descriptor_id, 0, sizeof(descriptor_id));
-
return;
}
@@ -845,7 +980,7 @@ rend_client_cancel_descriptor_fetches(void)
*/
int
rend_client_report_intro_point_failure(extend_info_t *failed_intro,
- const rend_data_t *rend_query,
+ rend_data_t *rend_query,
unsigned int failure_type)
{
int i, r;
@@ -853,17 +988,26 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro,
connection_t *conn;
r = rend_cache_lookup_entry(rend_query->onion_address, -1, &ent);
- if (r<0) {
- log_warn(LD_BUG, "Malformed service ID %s.",
- escaped_safe_str_client(rend_query->onion_address));
- return -1;
- }
- if (r==0) {
- log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
- escaped_safe_str_client(rend_query->onion_address));
- rend_client_refetch_v2_renddesc(rend_query);
- return 0;
+ if (r < 0) {
+ /* Either invalid onion address or cache entry not found. */
+ switch (-r) {
+ case EINVAL:
+ log_warn(LD_BUG, "Malformed service ID %s.",
+ escaped_safe_str_client(rend_query->onion_address));
+ return -1;
+ case ENOENT:
+ log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
+ escaped_safe_str_client(rend_query->onion_address));
+ rend_client_refetch_v2_renddesc(rend_query);
+ return 0;
+ default:
+ log_warn(LD_BUG, "Unknown cache lookup returned code: %d", r);
+ return -1;
+ }
}
+ /* The intro points are not checked here if they are usable or not because
+ * this is called when an intro point circuit is closed thus there must be
+ * at least one intro point that is usable and is about to be flagged. */
for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) {
rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i);
@@ -876,6 +1020,9 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro,
tor_fragile_assert();
/* fall through */
case INTRO_POINT_FAILURE_GENERIC:
+ rend_cache_intro_failure_note(failure_type,
+ (uint8_t *)failed_intro->identity_digest,
+ rend_query->onion_address);
rend_intro_point_free(intro);
smartlist_del(ent->parsed->intro_nodes, i);
break;
@@ -891,6 +1038,10 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro,
intro->unreachable_count,
zap_intro_point ? " Removing from descriptor.": "");
if (zap_intro_point) {
+ rend_cache_intro_failure_note(
+ failure_type,
+ (uint8_t *) failed_intro->identity_digest,
+ rend_query->onion_address);
rend_intro_point_free(intro);
smartlist_del(ent->parsed->intro_nodes, i);
}
@@ -1062,7 +1213,7 @@ rend_client_desc_trynow(const char *query)
continue;
assert_connection_ok(base_conn, now);
if (rend_cache_lookup_entry(rend_data->onion_address, -1,
- &entry) == 1 &&
+ &entry) == 0 &&
rend_client_any_intro_points_usable(entry)) {
/* either this fetch worked, or it failed but there was a
* valid entry from before which we should reuse */
@@ -1086,27 +1237,28 @@ rend_client_desc_trynow(const char *query)
"unavailable (try again later).",
safe_str_client(query));
connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
- rend_client_note_connection_attempt_ended(query);
+ rend_client_note_connection_attempt_ended(rend_data);
}
} SMARTLIST_FOREACH_END(base_conn);
}
-/** Clear temporary state used only during an attempt to connect to
- * the hidden service named <b>onion_address</b>. Called when a
- * connection attempt has ended; it is possible for this to be called
- * multiple times while handling an ended connection attempt, and
- * any future changes to this function must ensure it remains
- * idempotent.
- */
+/** Clear temporary state used only during an attempt to connect to the
+ * hidden service with <b>rend_data</b>. Called when a connection attempt
+ * has ended; it is possible for this to be called multiple times while
+ * handling an ended connection attempt, and any future changes to this
+ * function must ensure it remains idempotent. */
void
-rend_client_note_connection_attempt_ended(const char *onion_address)
+rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
{
+ unsigned int have_onion = 0;
rend_cache_entry_t *cache_entry = NULL;
- rend_cache_lookup_entry(onion_address, -1, &cache_entry);
- log_info(LD_REND, "Connection attempt for %s has ended; "
- "cleaning up temporary state.",
- safe_str_client(onion_address));
+ if (*rend_data->onion_address != '\0') {
+ /* Ignore return value; we find an entry, or we don't. */
+ (void) rend_cache_lookup_entry(rend_data->onion_address, -1,
+ &cache_entry);
+ have_onion = 1;
+ }
/* Clear the timed_out flag on all remaining intro points for this HS. */
if (cache_entry != NULL) {
@@ -1116,7 +1268,20 @@ rend_client_note_connection_attempt_ended(const char *onion_address)
}
/* Remove the HS's entries in last_hid_serv_requests. */
- purge_hid_serv_from_last_hid_serv_requests(onion_address);
+ if (have_onion) {
+ unsigned int replica;
+ for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
+ replica++) {
+ const char *desc_id = rend_data->descriptor_id[replica];
+ purge_hid_serv_from_last_hid_serv_requests(desc_id);
+ }
+ log_info(LD_REND, "Connection attempt for %s has ended; "
+ "cleaning up temporary state.",
+ safe_str_client(rend_data->onion_address));
+ } else {
+ /* We only have an ID for a fetch. Probably used by HSFETCH. */
+ purge_hid_serv_from_last_hid_serv_requests(rend_data->desc_id_fetch);
+ }
}
/** Return a newly allocated extend_info_t* for a randomly chosen introduction
@@ -1126,13 +1291,17 @@ rend_client_note_connection_attempt_ended(const char *onion_address)
extend_info_t *
rend_client_get_random_intro(const rend_data_t *rend_query)
{
+ int ret;
extend_info_t *result;
rend_cache_entry_t *entry;
- if (rend_cache_lookup_entry(rend_query->onion_address, -1, &entry) < 1) {
- log_warn(LD_REND,
- "Query '%s' didn't have valid rend desc in cache. Failing.",
- safe_str_client(rend_query->onion_address));
+ ret = rend_cache_lookup_entry(rend_query->onion_address, -1, &entry);
+ if (ret < 0 || !rend_client_any_intro_points_usable(entry)) {
+ log_warn(LD_REND,
+ "Query '%s' didn't have valid rend desc in cache. Failing.",
+ safe_str_client(rend_query->onion_address));
+ /* XXX: Should we refetch the descriptor here if the IPs are not usable
+ * anymore ?. */
return NULL;
}