|
@@ -22,6 +22,9 @@
|
|
|
#include "rephist.h"
|
|
|
#include "routerlist.h"
|
|
|
|
|
|
+static extend_info_t *rend_client_get_random_intro_impl(
|
|
|
+ const rend_data_t *rend_query, const int strict);
|
|
|
+
|
|
|
/** Called when we've established a circuit to an introduction point:
|
|
|
* send the introduction request. */
|
|
|
void
|
|
@@ -738,11 +741,32 @@ rend_client_desc_trynow(const char *query)
|
|
|
*/
|
|
|
extend_info_t *
|
|
|
rend_client_get_random_intro(const rend_data_t *rend_query)
|
|
|
+{
|
|
|
+ extend_info_t *result;
|
|
|
+ /* See if we can get a node that complies with ExcludeNodes */
|
|
|
+ if ((result = rend_client_get_random_intro_impl(rend_query, 1)))
|
|
|
+ return result;
|
|
|
+ /* If not, and StrictNodes is not set, see if we can return any old node
|
|
|
+ */
|
|
|
+ if (!get_options()->StrictNodes)
|
|
|
+ return rend_client_get_random_intro_impl(rend_query, 0);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/** As rend_client_get_random_intro, except assume that StrictNodes is set
|
|
|
+ * iff <b>strict</b> is true.
|
|
|
+ */
|
|
|
+static extend_info_t *
|
|
|
+rend_client_get_random_intro_impl(const rend_data_t *rend_query,
|
|
|
+ const int strict)
|
|
|
{
|
|
|
int i;
|
|
|
rend_cache_entry_t *entry;
|
|
|
rend_intro_point_t *intro;
|
|
|
routerinfo_t *router;
|
|
|
+ or_options_t *options = get_options();
|
|
|
+ smartlist_t *usable_nodes;
|
|
|
+ int n_excluded = 0;
|
|
|
|
|
|
if (rend_cache_lookup_entry(rend_query->onion_address, -1, &entry) < 1) {
|
|
|
log_warn(LD_REND,
|
|
@@ -750,13 +774,26 @@ rend_client_get_random_intro(const rend_data_t *rend_query)
|
|
|
safe_str_client(rend_query->onion_address));
|
|
|
return NULL;
|
|
|
}
|
|
|
+ /* We'll keep a separate list of the usable nodes. If this becomes empty,
|
|
|
+ * no nodes are usable. */
|
|
|
+ usable_nodes = smartlist_create();
|
|
|
+ smartlist_add_all(usable_nodes, entry->parsed->intro_nodes);
|
|
|
|
|
|
again:
|
|
|
- if (smartlist_len(entry->parsed->intro_nodes) == 0)
|
|
|
+ if (smartlist_len(usable_nodes) == 0) {
|
|
|
+ if (n_excluded && get_options()->StrictNodes) {
|
|
|
+ /* We only want to warn if StrictNodes is really set. Otherwise
|
|
|
+ * we're just about to retry anyways.
|
|
|
+ */
|
|
|
+ log_warn(LD_REND, "All introduction points for hidden service are "
|
|
|
+ "at excluded relays, and StrictNodes is set. Skipping.");
|
|
|
+ }
|
|
|
+ smartlist_free(usable_nodes);
|
|
|
return NULL;
|
|
|
+ }
|
|
|
|
|
|
- i = crypto_rand_int(smartlist_len(entry->parsed->intro_nodes));
|
|
|
- intro = smartlist_get(entry->parsed->intro_nodes, i);
|
|
|
+ i = crypto_rand_int(smartlist_len(usable_nodes));
|
|
|
+ intro = smartlist_get(usable_nodes, i);
|
|
|
/* Do we need to look up the router or is the extend info complete? */
|
|
|
if (!intro->extend_info->onion_key) {
|
|
|
if (tor_digest_is_zero(intro->extend_info->identity_digest))
|
|
@@ -766,13 +803,22 @@ rend_client_get_random_intro(const rend_data_t *rend_query)
|
|
|
if (!router) {
|
|
|
log_info(LD_REND, "Unknown router with nickname '%s'; trying another.",
|
|
|
intro->extend_info->nickname);
|
|
|
- rend_intro_point_free(intro);
|
|
|
- smartlist_del(entry->parsed->intro_nodes, i);
|
|
|
+ smartlist_del(usable_nodes, i);
|
|
|
goto again;
|
|
|
}
|
|
|
extend_info_free(intro->extend_info);
|
|
|
intro->extend_info = extend_info_from_router(router);
|
|
|
}
|
|
|
+ /* Check if we should refuse to talk to this router. */
|
|
|
+ if (options->ExcludeNodes && strict &&
|
|
|
+ routerset_contains_extendinfo(options->ExcludeNodes,
|
|
|
+ intro->extend_info)) {
|
|
|
+ n_excluded++;
|
|
|
+ smartlist_del(usable_nodes, i);
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
+ smartlist_free(usable_nodes);
|
|
|
return extend_info_dup(intro->extend_info);
|
|
|
}
|
|
|
|