2007-12-12 22:09:01 +01:00
|
|
|
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
2017-03-15 21:13:17 +01:00
|
|
|
* Copyright (c) 2007-2017, The Tor Project, Inc. */
|
2004-04-03 00:23:15 +02:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/**
|
|
|
|
* \file rendclient.c
|
2004-12-01 04:48:14 +01:00
|
|
|
* \brief Client code to access location-hidden services.
|
2004-05-09 18:47:25 +02:00
|
|
|
**/
|
2004-05-05 23:32:43 +02:00
|
|
|
|
2004-04-03 00:23:15 +02:00
|
|
|
#include "or.h"
|
2013-10-31 19:33:34 +01:00
|
|
|
#include "circpathbias.h"
|
2010-07-22 01:21:00 +02:00
|
|
|
#include "circuitbuild.h"
|
2010-07-22 09:46:23 +02:00
|
|
|
#include "circuitlist.h"
|
2010-07-22 10:03:40 +02:00
|
|
|
#include "circuituse.h"
|
2010-07-22 10:22:51 +02:00
|
|
|
#include "config.h"
|
2010-07-22 10:32:52 +02:00
|
|
|
#include "connection.h"
|
2010-07-22 10:43:02 +02:00
|
|
|
#include "connection_edge.h"
|
2010-07-22 11:54:50 +02:00
|
|
|
#include "directory.h"
|
2016-05-31 20:51:30 +02:00
|
|
|
#include "hs_common.h"
|
2010-07-23 19:58:06 +02:00
|
|
|
#include "main.h"
|
2013-09-18 00:05:48 +02:00
|
|
|
#include "networkstatus.h"
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
#include "nodelist.h"
|
2010-07-23 21:53:11 +02:00
|
|
|
#include "relay.h"
|
2010-07-22 00:13:51 +02:00
|
|
|
#include "rendclient.h"
|
2010-07-21 17:52:54 +02:00
|
|
|
#include "rendcommon.h"
|
2010-07-23 22:57:20 +02:00
|
|
|
#include "rephist.h"
|
2011-05-16 03:58:46 +02:00
|
|
|
#include "router.h"
|
2010-07-21 17:08:11 +02:00
|
|
|
#include "routerlist.h"
|
2012-09-13 18:46:39 +02:00
|
|
|
#include "routerset.h"
|
2013-10-09 17:13:06 +02:00
|
|
|
#include "control.h"
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2009-10-18 00:52:18 +02:00
|
|
|
static extend_info_t *rend_client_get_random_intro_impl(
|
2011-04-20 22:49:41 +02:00
|
|
|
const rend_cache_entry_t *rend_query,
|
|
|
|
const int strict, const int warnings);
|
2009-10-18 00:52:18 +02:00
|
|
|
|
2011-06-02 11:57:29 +02:00
|
|
|
/** Purge all potentially remotely-detectable state held in the hidden
|
|
|
|
* service client code. Called on SIGNAL NEWNYM. */
|
|
|
|
void
|
|
|
|
rend_client_purge_state(void)
|
|
|
|
{
|
|
|
|
rend_cache_purge();
|
2015-06-25 21:11:40 +02:00
|
|
|
rend_cache_failure_purge();
|
2011-06-02 11:57:29 +02:00
|
|
|
rend_client_cancel_descriptor_fetches();
|
|
|
|
rend_client_purge_last_hid_serv_requests();
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Called when we've established a circuit to an introduction point:
|
2004-05-05 23:32:43 +02:00
|
|
|
* send the introduction request. */
|
2004-04-03 00:23:15 +02:00
|
|
|
void
|
2006-07-23 09:37:35 +02:00
|
|
|
rend_client_introcirc_has_opened(origin_circuit_t *circ)
|
2004-04-03 00:23:15 +02:00
|
|
|
{
|
2012-10-12 18:22:13 +02:00
|
|
|
tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
|
2004-10-17 00:14:52 +02:00
|
|
|
tor_assert(circ->cpath);
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND,"introcirc is open");
|
2015-11-17 14:49:30 +01:00
|
|
|
connection_ap_attach_pending(1);
|
2004-04-03 00:23:15 +02:00
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Send the establish-rendezvous cell along a rendezvous circuit. if
|
2004-05-05 23:32:43 +02:00
|
|
|
* it fails, mark the circ for close and return -1. else return 0.
|
2004-04-05 09:41:31 +02:00
|
|
|
*/
|
2004-05-12 22:58:27 +02:00
|
|
|
static int
|
2006-07-23 09:37:35 +02:00
|
|
|
rend_client_send_establish_rendezvous(origin_circuit_t *circ)
|
2004-04-03 06:22:22 +02:00
|
|
|
{
|
2012-10-12 18:22:13 +02:00
|
|
|
tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
|
2008-09-24 16:44:29 +02:00
|
|
|
tor_assert(circ->rend_data);
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
|
2004-04-03 06:22:22 +02:00
|
|
|
|
2015-11-25 16:42:00 +01:00
|
|
|
crypto_rand(circ->rend_data->rend_cookie, REND_COOKIE_LEN);
|
2012-12-08 03:57:51 +01:00
|
|
|
|
|
|
|
/* Set timestamp_dirty, because circuit_expire_building expects it,
|
|
|
|
* and the rend cookie also means we've used the circ. */
|
|
|
|
circ->base_.timestamp_dirty = time(NULL);
|
|
|
|
|
2013-01-19 04:37:16 +01:00
|
|
|
/* We've attempted to use this circuit. Probe it if we fail */
|
|
|
|
pathbias_count_use_attempt(circ);
|
|
|
|
|
2007-03-24 16:57:51 +01:00
|
|
|
if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
|
2004-04-03 06:22:22 +02:00
|
|
|
RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
|
2008-09-24 16:44:29 +02:00
|
|
|
circ->rend_data->rend_cookie,
|
|
|
|
REND_COOKIE_LEN,
|
2004-04-03 06:22:22 +02:00
|
|
|
circ->cpath->prev)<0) {
|
2004-04-05 09:41:31 +02:00
|
|
|
/* circ is already marked for close */
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell");
|
2004-04-03 06:22:22 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-26 11:21:25 +02:00
|
|
|
/** Extend the introduction circuit <b>circ</b> to another valid
|
|
|
|
* introduction point for the hidden service it is trying to connect
|
|
|
|
* to, or mark it and launch a new circuit if we can't extend it.
|
2011-10-10 14:33:53 +02:00
|
|
|
* Return 0 on success or possible success. Return -1 and mark the
|
|
|
|
* introduction circuit for close on permanent failure.
|
2011-04-26 11:21:25 +02:00
|
|
|
*
|
|
|
|
* On failure, the caller is responsible for marking the associated
|
|
|
|
* rendezvous circuit for close. */
|
|
|
|
static int
|
|
|
|
rend_client_reextend_intro_circuit(origin_circuit_t *circ)
|
|
|
|
{
|
|
|
|
extend_info_t *extend_info;
|
|
|
|
int result;
|
|
|
|
extend_info = rend_client_get_random_intro(circ->rend_data);
|
|
|
|
if (!extend_info) {
|
|
|
|
log_warn(LD_REND,
|
|
|
|
"No usable introduction points left for %s. Closing.",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(rend_data_get_address(circ->rend_data)));
|
2011-04-26 11:21:25 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
|
|
|
|
return -1;
|
|
|
|
}
|
2012-12-08 03:57:51 +01:00
|
|
|
// XXX: should we not re-extend if hs_circ_has_timed_out?
|
2011-04-26 11:21:25 +02:00
|
|
|
if (circ->remaining_relay_early_cells) {
|
|
|
|
log_info(LD_REND,
|
2013-03-10 13:32:58 +01:00
|
|
|
"Re-extending circ %u, this time to %s.",
|
|
|
|
(unsigned)circ->base_.n_circ_id,
|
2011-05-16 03:58:46 +02:00
|
|
|
safe_str_client(extend_info_describe(extend_info)));
|
2011-04-26 11:21:25 +02:00
|
|
|
result = circuit_extend_to_new_exit(circ, extend_info);
|
|
|
|
} else {
|
|
|
|
log_info(LD_REND,
|
2013-03-10 13:32:58 +01:00
|
|
|
"Closing intro circ %u (out of RELAY_EARLY cells).",
|
|
|
|
(unsigned)circ->base_.n_circ_id);
|
2011-04-26 11:21:25 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
|
2011-10-10 05:24:27 +02:00
|
|
|
/* connection_ap_handshake_attach_circuit will launch a new intro circ. */
|
|
|
|
result = 0;
|
2011-04-26 11:21:25 +02:00
|
|
|
}
|
|
|
|
extend_info_free(extend_info);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell
|
2004-04-06 05:44:36 +02:00
|
|
|
* down introcirc if possible.
|
|
|
|
*/
|
2004-04-05 09:41:31 +02:00
|
|
|
int
|
2006-07-23 09:37:35 +02:00
|
|
|
rend_client_send_introduction(origin_circuit_t *introcirc,
|
|
|
|
origin_circuit_t *rendcirc)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2016-07-14 06:04:02 +02:00
|
|
|
const or_options_t *options = get_options();
|
2004-10-14 04:47:09 +02:00
|
|
|
size_t payload_len;
|
2008-09-24 16:44:29 +02:00
|
|
|
int r, v3_shift = 0;
|
2004-04-05 23:15:14 +02:00
|
|
|
char payload[RELAY_PAYLOAD_SIZE];
|
2005-06-29 23:46:55 +02:00
|
|
|
char tmp[RELAY_PAYLOAD_SIZE];
|
2015-01-26 23:42:42 +01:00
|
|
|
rend_cache_entry_t *entry = NULL;
|
2004-04-05 22:30:53 +02:00
|
|
|
crypt_path_t *cpath;
|
2005-06-29 23:46:55 +02:00
|
|
|
off_t dh_offset;
|
2012-01-18 21:53:30 +01:00
|
|
|
crypto_pk_t *intro_key = NULL;
|
2012-06-16 06:25:25 +02:00
|
|
|
int status = 0;
|
2016-05-31 20:51:30 +02:00
|
|
|
const char *onion_address;
|
2004-04-05 09:41:31 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
|
|
|
|
tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY);
|
2008-09-24 16:44:29 +02:00
|
|
|
tor_assert(introcirc->rend_data);
|
|
|
|
tor_assert(rendcirc->rend_data);
|
2016-05-31 20:51:30 +02:00
|
|
|
tor_assert(!rend_cmp_service_ids(rend_data_get_address(introcirc->rend_data),
|
2016-08-25 00:44:34 +02:00
|
|
|
rend_data_get_address(rendcirc->rend_data)));
|
2016-07-14 06:04:02 +02:00
|
|
|
assert_circ_anonymity_ok(introcirc, options);
|
|
|
|
assert_circ_anonymity_ok(rendcirc, options);
|
2016-05-31 20:51:30 +02:00
|
|
|
onion_address = rend_data_get_address(introcirc->rend_data);
|
2004-04-05 09:41:31 +02:00
|
|
|
|
2016-05-31 20:51:30 +02:00
|
|
|
r = rend_cache_lookup_entry(onion_address, -1, &entry);
|
2015-01-26 23:42:42 +01:00
|
|
|
/* 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. */
|
2011-04-25 15:38:35 +02:00
|
|
|
log_info(LD_REND,
|
|
|
|
"query %s didn't have valid rend desc in cache. "
|
|
|
|
"Refetching descriptor.",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(onion_address));
|
2011-04-25 15:38:35 +02:00
|
|
|
rend_client_refetch_v2_renddesc(introcirc->rend_data);
|
|
|
|
{
|
|
|
|
connection_t *conn;
|
|
|
|
|
|
|
|
while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
|
2016-05-31 20:51:30 +02:00
|
|
|
AP_CONN_STATE_CIRCUIT_WAIT, onion_address))) {
|
2015-11-27 18:54:57 +01:00
|
|
|
connection_ap_mark_as_non_pending_circuit(TO_ENTRY_CONN(conn));
|
2011-04-25 15:38:35 +02:00
|
|
|
conn->state = AP_CONN_STATE_RENDDESC_WAIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -1;
|
|
|
|
goto cleanup;
|
2004-04-05 09:41:31 +02:00
|
|
|
}
|
|
|
|
|
2016-01-26 03:48:31 +01:00
|
|
|
/* first 20 bytes of payload are the hash of the service's pk */
|
2009-06-12 02:05:21 +02:00
|
|
|
intro_key = NULL;
|
|
|
|
SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
|
|
|
|
intro, {
|
2011-05-11 22:23:42 +02:00
|
|
|
if (tor_memeq(introcirc->build_state->chosen_exit->identity_digest,
|
2009-06-12 02:05:21 +02:00
|
|
|
intro->extend_info->identity_digest, DIGEST_LEN)) {
|
|
|
|
intro_key = intro->intro_key;
|
|
|
|
break;
|
2007-11-29 16:25:04 +01:00
|
|
|
}
|
2009-06-12 02:05:21 +02:00
|
|
|
});
|
|
|
|
if (!intro_key) {
|
2011-04-26 11:21:25 +02:00
|
|
|
log_info(LD_REND, "Could not find intro key for %s at %s; we "
|
|
|
|
"have a v2 rend desc with %d intro points. "
|
|
|
|
"Trying a different intro point...",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(onion_address),
|
2011-05-16 03:58:46 +02:00
|
|
|
safe_str_client(extend_info_describe(
|
|
|
|
introcirc->build_state->chosen_exit)),
|
2009-07-02 16:20:20 +02:00
|
|
|
smartlist_len(entry->parsed->intro_nodes));
|
2011-04-26 11:21:25 +02:00
|
|
|
|
|
|
|
if (rend_client_reextend_intro_circuit(introcirc)) {
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -2;
|
2011-04-26 11:21:25 +02:00
|
|
|
goto perm_err;
|
|
|
|
} else {
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -1;
|
|
|
|
goto cleanup;
|
2011-04-26 11:21:25 +02:00
|
|
|
}
|
2007-11-01 04:43:02 +01:00
|
|
|
}
|
|
|
|
if (crypto_pk_get_digest(intro_key, payload)<0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG, "Internal error: couldn't hash public key.");
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -2;
|
2011-04-25 17:36:02 +02:00
|
|
|
goto perm_err;
|
2004-04-05 09:41:31 +02:00
|
|
|
}
|
|
|
|
|
2004-04-05 22:30:53 +02:00
|
|
|
/* Initialize the pending_final_cpath and start the DH handshake. */
|
2004-04-13 05:19:58 +02:00
|
|
|
cpath = rendcirc->build_state->pending_final_cpath;
|
|
|
|
if (!cpath) {
|
|
|
|
cpath = rendcirc->build_state->pending_final_cpath =
|
|
|
|
tor_malloc_zero(sizeof(crypt_path_t));
|
2005-03-23 07:21:48 +01:00
|
|
|
cpath->magic = CRYPT_PATH_MAGIC;
|
2012-12-05 03:27:07 +01:00
|
|
|
if (!(cpath->rend_dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -2;
|
2011-04-25 17:36:02 +02:00
|
|
|
goto perm_err;
|
2004-04-13 05:19:58 +02:00
|
|
|
}
|
2012-12-05 03:27:07 +01:00
|
|
|
if (crypto_dh_generate_public(cpath->rend_dh_handshake_state)<0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -2;
|
2011-04-25 17:36:02 +02:00
|
|
|
goto perm_err;
|
2004-04-13 05:19:58 +02:00
|
|
|
}
|
2004-04-05 22:30:53 +02:00
|
|
|
}
|
|
|
|
|
2008-09-24 16:44:29 +02:00
|
|
|
/* If version is 3, write (optional) auth data and timestamp. */
|
|
|
|
if (entry->parsed->protocols & (1<<3)) {
|
|
|
|
tmp[0] = 3; /* version 3 of the cell format */
|
2016-05-31 20:51:30 +02:00
|
|
|
/* auth type, if any */
|
|
|
|
tmp[1] = (uint8_t) TO_REND_DATA_V2(introcirc->rend_data)->auth_type;
|
2008-09-24 16:44:29 +02:00
|
|
|
v3_shift = 1;
|
2016-05-31 20:51:30 +02:00
|
|
|
if (tmp[1] != REND_NO_AUTH) {
|
2008-09-24 16:44:29 +02:00
|
|
|
set_uint16(tmp+2, htons(REND_DESC_COOKIE_LEN));
|
2016-05-31 20:51:30 +02:00
|
|
|
memcpy(tmp+4, TO_REND_DATA_V2(introcirc->rend_data)->descriptor_cookie,
|
2008-09-24 16:44:29 +02:00
|
|
|
REND_DESC_COOKIE_LEN);
|
|
|
|
v3_shift += 2+REND_DESC_COOKIE_LEN;
|
|
|
|
}
|
2014-11-17 17:52:10 +01:00
|
|
|
/* Once this held a timestamp. */
|
|
|
|
set_uint32(tmp+v3_shift+1, 0);
|
2008-09-24 16:44:29 +02:00
|
|
|
v3_shift += 4;
|
|
|
|
} /* if version 2 only write version number */
|
|
|
|
else if (entry->parsed->protocols & (1<<2)) {
|
|
|
|
tmp[0] = 2; /* version 2 of the cell format */
|
|
|
|
}
|
|
|
|
|
2004-04-05 09:41:31 +02:00
|
|
|
/* write the remaining items into tmp */
|
2008-09-24 16:44:29 +02:00
|
|
|
if (entry->parsed->protocols & (1<<3) || entry->parsed->protocols & (1<<2)) {
|
2005-06-29 23:46:55 +02:00
|
|
|
/* version 2 format */
|
|
|
|
extend_info_t *extend_info = rendcirc->build_state->chosen_exit;
|
|
|
|
int klen;
|
|
|
|
/* nul pads */
|
2014-09-14 03:49:37 +02:00
|
|
|
set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4n(&extend_info->addr));
|
2008-09-24 16:44:29 +02:00
|
|
|
set_uint16(tmp+v3_shift+5, htons(extend_info->port));
|
|
|
|
memcpy(tmp+v3_shift+7, extend_info->identity_digest, DIGEST_LEN);
|
|
|
|
klen = crypto_pk_asn1_encode(extend_info->onion_key,
|
|
|
|
tmp+v3_shift+7+DIGEST_LEN+2,
|
|
|
|
sizeof(tmp)-(v3_shift+7+DIGEST_LEN+2));
|
2017-08-09 15:24:16 +02:00
|
|
|
if (klen < 0) {
|
|
|
|
log_warn(LD_BUG,"Internal error: can't encode public key.");
|
|
|
|
status = -2;
|
|
|
|
goto perm_err;
|
|
|
|
}
|
2008-09-24 16:44:29 +02:00
|
|
|
set_uint16(tmp+v3_shift+7+DIGEST_LEN, htons(klen));
|
|
|
|
memcpy(tmp+v3_shift+7+DIGEST_LEN+2+klen, rendcirc->rend_data->rend_cookie,
|
2006-07-23 09:37:35 +02:00
|
|
|
REND_COOKIE_LEN);
|
2008-09-24 16:44:29 +02:00
|
|
|
dh_offset = v3_shift+7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
|
2005-06-29 23:46:55 +02:00
|
|
|
} else {
|
|
|
|
/* Version 0. */
|
2005-12-14 21:40:40 +01:00
|
|
|
strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
|
|
|
|
(MAX_NICKNAME_LEN+1)); /* nul pads */
|
2008-09-24 16:44:29 +02:00
|
|
|
memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_data->rend_cookie,
|
2006-07-23 09:37:35 +02:00
|
|
|
REND_COOKIE_LEN);
|
2005-06-29 23:46:55 +02:00
|
|
|
dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
|
|
|
|
}
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
|
2012-12-05 03:27:07 +01:00
|
|
|
if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset,
|
2004-04-06 05:44:36 +02:00
|
|
|
DH_KEY_LEN)<0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -2;
|
2011-04-25 17:36:02 +02:00
|
|
|
goto perm_err;
|
2004-04-05 22:30:53 +02:00
|
|
|
}
|
2004-04-05 09:41:31 +02:00
|
|
|
|
2006-10-31 20:17:07 +01:00
|
|
|
note_crypto_pk_op(REND_CLIENT);
|
2004-10-24 21:08:07 +02:00
|
|
|
/*XXX maybe give crypto_pk_public_hybrid_encrypt a max_len arg,
|
|
|
|
* to avoid buffer overflows? */
|
2007-11-01 04:43:02 +01:00
|
|
|
r = crypto_pk_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN,
|
2011-01-13 20:36:41 +01:00
|
|
|
sizeof(payload)-DIGEST_LEN,
|
2005-12-14 21:40:40 +01:00
|
|
|
tmp,
|
2006-11-14 02:07:52 +01:00
|
|
|
(int)(dh_offset+DH_KEY_LEN),
|
2004-04-06 22:55:46 +02:00
|
|
|
PK_PKCS1_OAEP_PADDING, 0);
|
2004-04-05 23:15:14 +02:00
|
|
|
if (r<0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -2;
|
2011-04-25 17:36:02 +02:00
|
|
|
goto perm_err;
|
2004-04-05 09:41:31 +02:00
|
|
|
}
|
|
|
|
|
2004-04-06 05:44:36 +02:00
|
|
|
payload_len = DIGEST_LEN + r;
|
2007-05-15 23:17:48 +02:00
|
|
|
tor_assert(payload_len <= RELAY_PAYLOAD_SIZE); /* we overran something */
|
2004-04-05 23:15:14 +02:00
|
|
|
|
2011-12-22 15:45:45 +01:00
|
|
|
/* Copy the rendezvous cookie from rendcirc to introcirc, so that
|
|
|
|
* when introcirc gets an ack, we can change the state of the right
|
|
|
|
* rendezvous circuit. */
|
2012-01-10 07:03:04 +01:00
|
|
|
memcpy(introcirc->rend_data->rend_cookie, rendcirc->rend_data->rend_cookie,
|
2011-12-22 15:45:45 +01:00
|
|
|
REND_COOKIE_LEN);
|
|
|
|
|
2007-08-11 16:13:25 +02:00
|
|
|
log_info(LD_REND, "Sending an INTRODUCE1 cell");
|
2007-03-24 16:57:51 +01:00
|
|
|
if (relay_send_command_from_edge(0, TO_CIRCUIT(introcirc),
|
2004-04-05 09:41:31 +02:00
|
|
|
RELAY_COMMAND_INTRODUCE1,
|
2004-04-05 23:15:14 +02:00
|
|
|
payload, payload_len,
|
2004-04-05 09:41:31 +02:00
|
|
|
introcirc->cpath->prev)<0) {
|
|
|
|
/* introcirc is already marked for close. leave rendcirc alone. */
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
|
2012-06-16 06:25:25 +02:00
|
|
|
status = -2;
|
|
|
|
goto cleanup;
|
2004-04-05 09:41:31 +02:00
|
|
|
}
|
|
|
|
|
2004-04-13 03:41:39 +02:00
|
|
|
/* Now, we wait for an ACK or NAK on this circuit. */
|
2011-11-24 15:52:38 +01:00
|
|
|
circuit_change_purpose(TO_CIRCUIT(introcirc),
|
|
|
|
CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT);
|
2011-05-29 17:03:41 +02:00
|
|
|
/* Set timestamp_dirty, because circuit_expire_building expects it
|
|
|
|
* to specify when a circuit entered the _C_INTRODUCE_ACK_WAIT
|
|
|
|
* state. */
|
2012-10-12 18:22:13 +02:00
|
|
|
introcirc->base_.timestamp_dirty = time(NULL);
|
2004-04-05 17:17:34 +02:00
|
|
|
|
2013-01-19 04:37:16 +01:00
|
|
|
pathbias_count_use_attempt(introcirc);
|
|
|
|
|
2012-06-16 06:25:25 +02:00
|
|
|
goto cleanup;
|
|
|
|
|
2011-05-06 03:53:46 +02:00
|
|
|
perm_err:
|
2012-10-12 18:22:13 +02:00
|
|
|
if (!introcirc->base_.marked_for_close)
|
2011-04-26 11:21:25 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
|
2006-10-09 17:47:27 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
|
2012-06-16 06:25:25 +02:00
|
|
|
cleanup:
|
2012-11-08 23:00:36 +01:00
|
|
|
memwipe(payload, 0, sizeof(payload));
|
|
|
|
memwipe(tmp, 0, sizeof(tmp));
|
2012-06-16 06:25:25 +02:00
|
|
|
|
|
|
|
return status;
|
2004-04-05 09:41:31 +02:00
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Called when a rendezvous circuit is open; sends a establish
|
2004-05-05 23:32:43 +02:00
|
|
|
* rendezvous circuit as appropriate. */
|
2004-04-03 00:23:15 +02:00
|
|
|
void
|
2006-07-23 09:37:35 +02:00
|
|
|
rend_client_rendcirc_has_opened(origin_circuit_t *circ)
|
2004-04-03 00:23:15 +02:00
|
|
|
{
|
2012-10-12 18:22:13 +02:00
|
|
|
tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND,"rendcirc is open");
|
2004-04-03 05:06:06 +02:00
|
|
|
|
2004-04-05 02:47:48 +02:00
|
|
|
/* generate a rendezvous cookie, store it in circ */
|
|
|
|
if (rend_client_send_establish_rendezvous(circ) < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2004-04-03 05:06:06 +02:00
|
|
|
|
2012-12-08 03:57:51 +01:00
|
|
|
/**
|
2014-11-10 20:38:53 +01:00
|
|
|
* Called to close other intro circuits we launched in parallel.
|
2012-12-08 03:57:51 +01:00
|
|
|
*/
|
|
|
|
static void
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_client_close_other_intros(const uint8_t *rend_pk_digest)
|
2012-12-08 03:57:51 +01:00
|
|
|
{
|
|
|
|
/* abort parallel intro circs, if any */
|
2014-08-15 22:23:22 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) {
|
2012-12-08 03:57:51 +01:00
|
|
|
if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
|
|
|
|
c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) &&
|
|
|
|
!c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) {
|
|
|
|
origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(c);
|
|
|
|
if (oc->rend_data &&
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_circuit_pk_digest_eq(oc, rend_pk_digest)) {
|
2012-12-08 03:57:51 +01:00
|
|
|
log_info(LD_REND|LD_CIRC, "Closing introduction circuit %d that we "
|
|
|
|
"built in parallel (Purpose %d).", oc->global_identifier,
|
|
|
|
c->purpose);
|
2014-11-10 20:38:53 +01:00
|
|
|
circuit_mark_for_close(c, END_CIRC_REASON_IP_NOW_REDUNDANT);
|
2012-12-08 03:57:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-08-15 22:23:22 +02:00
|
|
|
SMARTLIST_FOREACH_END(c);
|
2012-12-08 03:57:51 +01:00
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
|
2004-04-13 01:33:47 +02:00
|
|
|
*/
|
|
|
|
int
|
2006-07-23 09:37:35 +02:00
|
|
|
rend_client_introduction_acked(origin_circuit_t *circ,
|
2010-12-14 01:34:01 +01:00
|
|
|
const uint8_t *request, size_t request_len)
|
2004-04-13 01:33:47 +02:00
|
|
|
{
|
2016-07-14 06:04:02 +02:00
|
|
|
const or_options_t *options = get_options();
|
2006-07-26 21:05:34 +02:00
|
|
|
origin_circuit_t *rendcirc;
|
2006-06-05 00:42:13 +02:00
|
|
|
(void) request; // XXXX Use this.
|
2004-04-13 04:31:52 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
if (circ->base_.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_PROTOCOL,
|
2013-03-10 13:32:58 +01:00
|
|
|
"Received REND_INTRODUCE_ACK on unexpected circuit %u.",
|
|
|
|
(unsigned)circ->base_.n_circ_id);
|
2006-10-09 17:47:27 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
2004-04-13 03:41:39 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-07-14 06:04:02 +02:00
|
|
|
tor_assert(circ->build_state);
|
2005-06-29 23:46:55 +02:00
|
|
|
tor_assert(circ->build_state->chosen_exit);
|
2016-07-14 06:04:02 +02:00
|
|
|
assert_circ_anonymity_ok(circ, options);
|
2008-09-24 16:44:29 +02:00
|
|
|
tor_assert(circ->rend_data);
|
2004-04-13 04:31:52 +02:00
|
|
|
|
2012-12-08 00:50:31 +01:00
|
|
|
/* For path bias: This circuit was used successfully. Valid
|
|
|
|
* nacks and acks count. */
|
2013-01-19 04:37:16 +01:00
|
|
|
pathbias_mark_use_success(circ);
|
2012-12-08 00:50:31 +01:00
|
|
|
|
2004-04-13 01:33:47 +02:00
|
|
|
if (request_len == 0) {
|
|
|
|
/* It's an ACK; the introduction point relayed our introduction request. */
|
2004-04-14 00:56:24 +02:00
|
|
|
/* Locate the rend circ which is waiting to hear about this ack,
|
|
|
|
* and tell it.
|
|
|
|
*/
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND,"Received ack. Telling rend circ...");
|
2011-12-22 16:15:24 +01:00
|
|
|
rendcirc = circuit_get_ready_rend_circ_by_rend_data(circ->rend_data);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (rendcirc) { /* remember the ack */
|
2016-07-14 06:04:02 +02:00
|
|
|
assert_circ_anonymity_ok(rendcirc, options);
|
2011-11-24 15:52:38 +01:00
|
|
|
circuit_change_purpose(TO_CIRCUIT(rendcirc),
|
|
|
|
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED);
|
2011-05-29 17:03:41 +02:00
|
|
|
/* Set timestamp_dirty, because circuit_expire_building expects
|
|
|
|
* it to specify when a circuit entered the
|
|
|
|
* _C_REND_READY_INTRO_ACKED state. */
|
2012-10-12 18:22:13 +02:00
|
|
|
rendcirc->base_.timestamp_dirty = time(NULL);
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
} else {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
|
2004-04-14 00:56:24 +02:00
|
|
|
}
|
|
|
|
/* close the circuit: we won't need it anymore. */
|
2011-11-24 15:52:38 +01:00
|
|
|
circuit_change_purpose(TO_CIRCUIT(circ),
|
|
|
|
CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
|
2006-10-17 17:20:00 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
|
2012-12-08 03:57:51 +01:00
|
|
|
|
|
|
|
/* close any other intros launched in parallel */
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_client_close_other_intros(rend_data_get_pk_digest(circ->rend_data,
|
|
|
|
NULL));
|
2004-04-13 01:33:47 +02:00
|
|
|
} else {
|
|
|
|
/* It's a NAK; the introduction point didn't relay our request. */
|
2011-11-24 15:52:38 +01:00
|
|
|
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING);
|
2004-04-18 09:37:16 +02:00
|
|
|
/* Remove this intro point from the set of viable introduction
|
|
|
|
* points. If any remain, extend to a new one and try again.
|
|
|
|
* If none remain, refetch the service descriptor.
|
2004-04-13 03:41:39 +02:00
|
|
|
*/
|
2011-04-26 11:21:25 +02:00
|
|
|
log_info(LD_REND, "Got nack for %s from %s...",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(rend_data_get_address(circ->rend_data)),
|
2011-05-16 03:58:46 +02:00
|
|
|
safe_str_client(extend_info_describe(circ->build_state->chosen_exit)));
|
2011-09-17 12:19:29 +02:00
|
|
|
if (rend_client_report_intro_point_failure(circ->build_state->chosen_exit,
|
2011-10-11 17:30:01 +02:00
|
|
|
circ->rend_data,
|
|
|
|
INTRO_POINT_FAILURE_GENERIC)>0) {
|
2005-07-14 10:43:19 +02:00
|
|
|
/* There are introduction points left. Re-extend the circuit to
|
2004-04-13 04:31:52 +02:00
|
|
|
* another intro point and try again. */
|
2011-04-26 11:21:25 +02:00
|
|
|
int result = rend_client_reextend_intro_circuit(circ);
|
|
|
|
/* XXXX If that call failed, should we close the rend circuit,
|
|
|
|
* too? */
|
2005-06-29 23:46:55 +02:00
|
|
|
return result;
|
2015-01-16 23:43:33 +01:00
|
|
|
} else {
|
2015-01-19 16:23:58 +01:00
|
|
|
/* Close circuit because no more intro points are usable thus not
|
|
|
|
* useful anymore. Change it's purpose before so we don't report an
|
|
|
|
* intro point failure again triggering an extra descriptor fetch. */
|
|
|
|
circuit_change_purpose(TO_CIRCUIT(circ),
|
|
|
|
CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
|
2015-01-16 23:43:33 +01:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
|
2004-04-13 04:31:52 +02:00
|
|
|
}
|
2004-04-13 01:33:47 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-26 01:42:13 +01:00
|
|
|
/** The period for which a hidden service directory cannot be queried for
|
|
|
|
* the same descriptor ID again. */
|
|
|
|
#define REND_HID_SERV_DIR_REQUERY_PERIOD (15 * 60)
|
2016-07-18 05:25:15 +02:00
|
|
|
/** Test networks generate a new consensus every 5 or 10 seconds.
|
|
|
|
* So allow them to requery HSDirs much faster. */
|
|
|
|
#define REND_HID_SERV_DIR_REQUERY_PERIOD_TESTING (5)
|
|
|
|
|
|
|
|
/** Return the period for which a hidden service directory cannot be queried
|
|
|
|
* for the same descriptor ID again, taking TestingTorNetwork into account. */
|
|
|
|
static time_t
|
|
|
|
hsdir_requery_period(const or_options_t *options)
|
|
|
|
{
|
|
|
|
tor_assert(options);
|
|
|
|
|
|
|
|
if (options->TestingTorNetwork) {
|
|
|
|
return REND_HID_SERV_DIR_REQUERY_PERIOD_TESTING;
|
|
|
|
} else {
|
|
|
|
return REND_HID_SERV_DIR_REQUERY_PERIOD;
|
|
|
|
}
|
|
|
|
}
|
2008-01-26 01:42:13 +01:00
|
|
|
|
|
|
|
/** Contains the last request times to hidden service directories for
|
2011-09-20 12:50:45 +02:00
|
|
|
* certain queries; each key is a string consisting of the
|
2015-04-27 22:21:47 +02:00
|
|
|
* concatenation of a base32-encoded HS directory identity digest and
|
|
|
|
* base32-encoded HS descriptor ID; each value is a pointer to a time_t
|
2011-09-20 12:50:45 +02:00
|
|
|
* holding the time of the last request for that descriptor ID to that
|
|
|
|
* HS directory. */
|
2011-06-02 11:24:18 +02:00
|
|
|
static strmap_t *last_hid_serv_requests_ = NULL;
|
|
|
|
|
|
|
|
/** Returns last_hid_serv_requests_, initializing it to a new strmap if
|
|
|
|
* necessary. */
|
|
|
|
static strmap_t *
|
|
|
|
get_last_hid_serv_requests(void)
|
|
|
|
{
|
|
|
|
if (!last_hid_serv_requests_)
|
|
|
|
last_hid_serv_requests_ = strmap_new();
|
|
|
|
return last_hid_serv_requests_;
|
|
|
|
}
|
2008-01-26 01:42:13 +01:00
|
|
|
|
2011-09-20 12:50:45 +02:00
|
|
|
#define LAST_HID_SERV_REQUEST_KEY_LEN (REND_DESC_ID_V2_LEN_BASE32 + \
|
2015-04-27 22:21:47 +02:00
|
|
|
REND_DESC_ID_V2_LEN_BASE32)
|
2011-09-20 12:50:45 +02:00
|
|
|
|
2008-01-26 01:42:13 +01:00
|
|
|
/** Look up the last request time to hidden service directory <b>hs_dir</b>
|
2015-03-23 18:07:51 +01:00
|
|
|
* 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.
|
|
|
|
*/
|
2008-01-26 01:42:13 +01:00
|
|
|
static time_t
|
|
|
|
lookup_last_hid_serv_request(routerstatus_t *hs_dir,
|
2011-09-20 12:50:45 +02:00
|
|
|
const char *desc_id_base32,
|
|
|
|
time_t now, int set)
|
2008-01-26 01:42:13 +01:00
|
|
|
{
|
|
|
|
char hsdir_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
|
2011-09-20 12:50:45 +02:00
|
|
|
char hsdir_desc_comb_id[LAST_HID_SERV_REQUEST_KEY_LEN + 1];
|
2008-01-26 01:42:13 +01:00
|
|
|
time_t *last_request_ptr;
|
2011-06-02 11:24:18 +02:00
|
|
|
strmap_t *last_hid_serv_requests = get_last_hid_serv_requests();
|
2008-01-26 01:42:13 +01:00
|
|
|
base32_encode(hsdir_id_base32, sizeof(hsdir_id_base32),
|
|
|
|
hs_dir->identity_digest, DIGEST_LEN);
|
2015-03-11 18:43:07 +01:00
|
|
|
tor_snprintf(hsdir_desc_comb_id, sizeof(hsdir_desc_comb_id), "%s%s",
|
2011-09-20 12:50:45 +02:00
|
|
|
hsdir_id_base32,
|
2015-03-11 18:43:07 +01:00
|
|
|
desc_id_base32);
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXX++?? tor_assert(strlen(hsdir_desc_comb_id) ==
|
2011-09-20 12:50:45 +02:00
|
|
|
LAST_HID_SERV_REQUEST_KEY_LEN); */
|
2008-01-26 01:42:13 +01:00
|
|
|
if (set) {
|
2010-02-07 06:30:55 +01:00
|
|
|
time_t *oldptr;
|
|
|
|
last_request_ptr = tor_malloc_zero(sizeof(time_t));
|
2008-01-26 01:42:13 +01:00
|
|
|
*last_request_ptr = now;
|
2010-02-07 06:30:55 +01:00
|
|
|
oldptr = strmap_set(last_hid_serv_requests, hsdir_desc_comb_id,
|
|
|
|
last_request_ptr);
|
|
|
|
tor_free(oldptr);
|
2008-01-26 01:42:13 +01:00
|
|
|
} else
|
|
|
|
last_request_ptr = strmap_get_lc(last_hid_serv_requests,
|
|
|
|
hsdir_desc_comb_id);
|
|
|
|
return (last_request_ptr) ? *last_request_ptr : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Clean the history of request times to hidden service directories, so that
|
|
|
|
* it does not contain requests older than REND_HID_SERV_DIR_REQUERY_PERIOD
|
|
|
|
* seconds any more. */
|
|
|
|
static void
|
2011-02-07 16:43:41 +01:00
|
|
|
directory_clean_last_hid_serv_requests(time_t now)
|
2008-01-26 01:42:13 +01:00
|
|
|
{
|
|
|
|
strmap_iter_t *iter;
|
2016-07-18 05:25:15 +02:00
|
|
|
time_t cutoff = now - hsdir_requery_period(get_options());
|
2011-06-02 11:24:18 +02:00
|
|
|
strmap_t *last_hid_serv_requests = get_last_hid_serv_requests();
|
2008-01-26 01:42:13 +01:00
|
|
|
for (iter = strmap_iter_init(last_hid_serv_requests);
|
|
|
|
!strmap_iter_done(iter); ) {
|
|
|
|
const char *key;
|
|
|
|
void *val;
|
|
|
|
time_t *ent;
|
|
|
|
strmap_iter_get(iter, &key, &val);
|
|
|
|
ent = (time_t *) val;
|
|
|
|
if (*ent < cutoff) {
|
|
|
|
iter = strmap_iter_next_rmv(last_hid_serv_requests, iter);
|
|
|
|
tor_free(ent);
|
|
|
|
} else {
|
|
|
|
iter = strmap_iter_next(last_hid_serv_requests, iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-27 22:21:47 +02:00
|
|
|
/** 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.
|
2015-01-15 16:19:31 +01:00
|
|
|
*
|
|
|
|
* This is called from rend_client_note_connection_attempt_ended(), which
|
2015-04-27 22:21:47 +02:00
|
|
|
* must be idempotent, so any future changes to this function must leave it
|
|
|
|
* idempotent too. */
|
2011-09-20 13:26:09 +02:00
|
|
|
static void
|
2015-04-27 22:21:47 +02:00
|
|
|
purge_hid_serv_from_last_hid_serv_requests(const char *desc_id)
|
2011-09-20 13:26:09 +02:00
|
|
|
{
|
|
|
|
strmap_iter_t *iter;
|
|
|
|
strmap_t *last_hid_serv_requests = get_last_hid_serv_requests();
|
2015-04-27 22:21:47 +02:00
|
|
|
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);
|
2011-09-20 13:26:09 +02:00
|
|
|
for (iter = strmap_iter_init(last_hid_serv_requests);
|
|
|
|
!strmap_iter_done(iter); ) {
|
|
|
|
const char *key;
|
|
|
|
void *val;
|
|
|
|
strmap_iter_get(iter, &key, &val);
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXX++?? tor_assert(strlen(key) == LAST_HID_SERV_REQUEST_KEY_LEN); */
|
2011-09-20 13:26:09 +02:00
|
|
|
if (tor_memeq(key + LAST_HID_SERV_REQUEST_KEY_LEN -
|
2015-04-27 22:21:47 +02:00
|
|
|
REND_DESC_ID_V2_LEN_BASE32,
|
|
|
|
desc_id_base32,
|
|
|
|
REND_DESC_ID_V2_LEN_BASE32)) {
|
2011-09-20 13:26:09 +02:00
|
|
|
iter = strmap_iter_next_rmv(last_hid_serv_requests, iter);
|
|
|
|
tor_free(val);
|
|
|
|
} else {
|
|
|
|
iter = strmap_iter_next(last_hid_serv_requests, iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-02 11:46:04 +02:00
|
|
|
/** Purge the history of request times to hidden service directories,
|
|
|
|
* so that future lookups of an HS descriptor will not fail because we
|
|
|
|
* accessed all of the HSDir relays responsible for the descriptor
|
|
|
|
* recently. */
|
|
|
|
void
|
|
|
|
rend_client_purge_last_hid_serv_requests(void)
|
|
|
|
{
|
|
|
|
/* Don't create the table if it doesn't exist yet (and it may very
|
|
|
|
* well not exist if the user hasn't accessed any HSes)... */
|
|
|
|
strmap_t *old_last_hid_serv_requests = last_hid_serv_requests_;
|
|
|
|
/* ... and let get_last_hid_serv_requests re-create it for us if
|
|
|
|
* necessary. */
|
|
|
|
last_hid_serv_requests_ = NULL;
|
|
|
|
|
|
|
|
if (old_last_hid_serv_requests != NULL) {
|
2011-06-02 12:07:09 +02:00
|
|
|
log_info(LD_REND, "Purging client last-HS-desc-request-time table");
|
2012-10-12 18:22:13 +02:00
|
|
|
strmap_free(old_last_hid_serv_requests, tor_free_);
|
2011-06-02 11:46:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/** 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 *
|
2015-03-23 18:07:51 +01:00
|
|
|
pick_hsdir(const char *desc_id, const char *desc_id_base32)
|
2008-01-26 01:42:13 +01:00
|
|
|
{
|
2012-01-18 21:53:30 +01:00
|
|
|
smartlist_t *responsible_dirs = smartlist_new();
|
2014-01-24 18:56:10 +01:00
|
|
|
smartlist_t *usable_responsible_dirs = smartlist_new();
|
|
|
|
const or_options_t *options = get_options();
|
2008-01-26 01:42:13 +01:00
|
|
|
routerstatus_t *hs_dir;
|
|
|
|
time_t now = time(NULL);
|
2014-01-24 18:56:10 +01:00
|
|
|
int excluded_some;
|
2008-01-26 01:42:13 +01:00
|
|
|
|
|
|
|
tor_assert(desc_id);
|
2015-03-23 18:07:51 +01:00
|
|
|
tor_assert(desc_id_base32);
|
2008-01-26 01:42:13 +01:00
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/* 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);
|
2011-02-07 16:43:41 +01:00
|
|
|
|
|
|
|
/* Clean request history first. */
|
|
|
|
directory_clean_last_hid_serv_requests(now);
|
2008-01-26 01:42:13 +01:00
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/* 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);
|
2016-07-18 05:25:15 +02:00
|
|
|
if (last + hsdir_requery_period(options) >= now ||
|
2015-03-10 21:46:56 +01:00
|
|
|
!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);
|
2008-01-26 01:42:13 +01:00
|
|
|
|
2014-01-24 18:56:10 +01:00
|
|
|
excluded_some =
|
|
|
|
smartlist_len(usable_responsible_dirs) < smartlist_len(responsible_dirs);
|
|
|
|
|
|
|
|
hs_dir = smartlist_choose(usable_responsible_dirs);
|
2015-03-10 21:46:56 +01:00
|
|
|
if (!hs_dir && !options->StrictNodes) {
|
2014-01-24 18:56:10 +01:00
|
|
|
hs_dir = smartlist_choose(responsible_dirs);
|
2015-03-10 21:46:56 +01:00
|
|
|
}
|
2014-01-24 18:56:10 +01:00
|
|
|
|
2008-01-26 01:42:13 +01:00
|
|
|
smartlist_free(responsible_dirs);
|
2014-01-24 18:56:10 +01:00
|
|
|
smartlist_free(usable_responsible_dirs);
|
2008-01-26 01:42:13 +01:00
|
|
|
if (!hs_dir) {
|
|
|
|
log_info(LD_REND, "Could not pick one of the responsible hidden "
|
|
|
|
"service directories, because we requested them all "
|
|
|
|
"recently without success.");
|
2014-01-24 18:56:10 +01:00
|
|
|
if (options->StrictNodes && excluded_some) {
|
2014-02-16 18:11:07 +01:00
|
|
|
log_warn(LD_REND, "Could not pick a hidden service directory for the "
|
|
|
|
"requested hidden service: they are all either down or "
|
|
|
|
"excluded, and StrictNodes is set.");
|
2014-01-24 18:56:10 +01:00
|
|
|
}
|
2015-03-10 21:46:56 +01:00
|
|
|
} 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);
|
2008-01-26 01:42:13 +01:00
|
|
|
}
|
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
return hs_dir;
|
|
|
|
}
|
2008-01-26 01:42:13 +01:00
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/** 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
|
2016-05-31 20:51:30 +02:00
|
|
|
directory_get_from_hs_dir(const char *desc_id,
|
|
|
|
const rend_data_t *rend_query,
|
2015-03-10 21:46:56 +01:00
|
|
|
routerstatus_t *rs_hsdir)
|
|
|
|
{
|
|
|
|
routerstatus_t *hs_dir = rs_hsdir;
|
2015-04-30 18:28:11 +02:00
|
|
|
char *hsdir_fp;
|
2015-03-10 21:46:56 +01:00
|
|
|
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
|
|
|
|
char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
|
2016-05-31 20:51:30 +02:00
|
|
|
const rend_data_v2_t *rend_data;
|
2015-03-10 21:46:56 +01:00
|
|
|
#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);
|
2016-05-31 20:51:30 +02:00
|
|
|
tor_assert(rend_query);
|
|
|
|
rend_data = TO_REND_DATA_V2(rend_query);
|
2015-03-10 21:46:56 +01:00
|
|
|
|
|
|
|
base32_encode(desc_id_base32, sizeof(desc_id_base32),
|
|
|
|
desc_id, DIGEST_LEN);
|
2008-01-26 01:42:13 +01:00
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/* Automatically pick an hs dir if none given. */
|
|
|
|
if (!rs_hsdir) {
|
2015-03-23 18:07:51 +01:00
|
|
|
hs_dir = pick_hsdir(desc_id, desc_id_base32);
|
2015-03-10 21:46:56 +01:00
|
|
|
if (!hs_dir) {
|
|
|
|
/* No suitable hs dir can be found, stop right now. */
|
2017-04-25 17:55:44 +02:00
|
|
|
control_event_hs_descriptor_failed(rend_query, NULL, "QUERY_NO_HSDIR");
|
|
|
|
control_event_hs_descriptor_content(rend_data_get_address(rend_query),
|
|
|
|
desc_id_base32, NULL, NULL);
|
2015-03-10 21:46:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-30 18:28:11 +02:00
|
|
|
/* 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);
|
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/* 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. */
|
2016-05-31 20:51:30 +02:00
|
|
|
if (rend_data->auth_type != REND_NO_AUTH) {
|
2008-12-18 05:27:23 +01:00
|
|
|
if (base64_encode(descriptor_cookie_base64,
|
|
|
|
sizeof(descriptor_cookie_base64),
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_data->descriptor_cookie,
|
|
|
|
REND_DESC_COOKIE_LEN,
|
2015-04-10 13:25:08 +02:00
|
|
|
0)<0) {
|
2008-12-18 05:27:23 +01:00
|
|
|
log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
|
2017-04-25 17:55:44 +02:00
|
|
|
control_event_hs_descriptor_failed(rend_query, hsdir_fp, "BAD_DESC");
|
|
|
|
control_event_hs_descriptor_content(rend_data_get_address(rend_query),
|
|
|
|
desc_id_base32, hsdir_fp, NULL);
|
2008-12-18 05:27:23 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-04-10 13:25:08 +02:00
|
|
|
/* Remove == signs. */
|
|
|
|
descriptor_cookie_base64[strlen(descriptor_cookie_base64)-2] = '\0';
|
2008-12-18 05:27:23 +01:00
|
|
|
} else {
|
|
|
|
strlcpy(descriptor_cookie_base64, "(none)",
|
|
|
|
sizeof(descriptor_cookie_base64));
|
2008-09-24 16:44:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Send fetch request. (Pass query and possibly descriptor cookie so that
|
|
|
|
* they can be written to the directory connection and be referred to when
|
|
|
|
* the response arrives. */
|
2017-04-21 21:08:28 +02:00
|
|
|
directory_request_t *req =
|
|
|
|
directory_request_new(DIR_PURPOSE_FETCH_RENDDESC_V2);
|
|
|
|
directory_request_set_routerstatus(req, hs_dir);
|
|
|
|
directory_request_set_indirection(req, how_to_fetch);
|
|
|
|
directory_request_set_resource(req, desc_id_base32);
|
|
|
|
directory_request_set_rend_query(req, rend_query);
|
|
|
|
directory_initiate_request(req);
|
|
|
|
directory_request_free(req);
|
|
|
|
|
2008-01-26 01:42:13 +01:00
|
|
|
log_info(LD_REND, "Sending fetch request for v2 descriptor for "
|
2008-09-24 16:44:29 +02:00
|
|
|
"service '%s' with descriptor ID '%s', auth type %d, "
|
|
|
|
"and descriptor cookie '%s' to hidden service "
|
2011-05-16 03:58:46 +02:00
|
|
|
"directory %s",
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_data->onion_address, desc_id_base32,
|
|
|
|
rend_data->auth_type,
|
|
|
|
(rend_data->auth_type == REND_NO_AUTH ? "[none]" :
|
2011-05-16 03:58:46 +02:00
|
|
|
escaped_safe_str_client(descriptor_cookie_base64)),
|
|
|
|
routerstatus_describe(hs_dir));
|
2013-10-09 17:13:06 +02:00
|
|
|
control_event_hs_descriptor_requested(rend_query,
|
2014-02-05 01:33:48 +01:00
|
|
|
hs_dir->identity_digest,
|
2013-10-09 17:13:06 +02:00
|
|
|
desc_id_base32);
|
2008-01-26 01:42:13 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/** 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
|
2016-05-31 20:51:30 +02:00
|
|
|
fetch_v2_desc_by_descid(const char *desc_id,
|
|
|
|
const rend_data_t *rend_query, smartlist_t *hsdirs)
|
2015-03-10 21:46:56 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2015-04-30 19:38:39 +02:00
|
|
|
end:
|
2015-03-10 21:46:56 +01:00
|
|
|
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
|
2016-05-31 20:51:30 +02:00
|
|
|
fetch_v2_desc_by_addr(rend_data_t *rend_query, smartlist_t *hsdirs)
|
2015-03-10 21:46:56 +01:00
|
|
|
{
|
|
|
|
char descriptor_id[DIGEST_LEN];
|
|
|
|
int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
|
|
|
|
int i, tries_left, ret;
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_data_v2_t *rend_data = TO_REND_DATA_V2(rend_query);
|
2015-03-10 21:46:56 +01:00
|
|
|
|
|
|
|
/* 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) {
|
2016-07-28 16:22:10 +02:00
|
|
|
int rand_val = crypto_rand_int(tries_left);
|
|
|
|
int chosen_replica = replicas_left_to_try[rand_val];
|
|
|
|
replicas_left_to_try[rand_val] = replicas_left_to_try[--tries_left];
|
2015-03-10 21:46:56 +01:00
|
|
|
|
2016-05-31 20:51:30 +02:00
|
|
|
ret = rend_compute_v2_desc_id(descriptor_id,
|
|
|
|
rend_data->onion_address,
|
|
|
|
rend_data->auth_type == REND_STEALTH_AUTH ?
|
|
|
|
rend_data->descriptor_cookie : NULL,
|
2015-03-10 21:46:56 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-05-31 20:51:30 +02:00
|
|
|
if (tor_memcmp(descriptor_id, rend_data->descriptor_id[chosen_replica],
|
2015-04-28 16:22:14 +02:00
|
|
|
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(
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_data->descriptor_id[chosen_replica]);
|
|
|
|
memcpy(rend_data->descriptor_id[chosen_replica], descriptor_id,
|
|
|
|
sizeof(rend_data->descriptor_id[chosen_replica]));
|
2015-04-28 16:22:14 +02:00
|
|
|
}
|
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/* Trigger the fetch with the computed descriptor ID. */
|
2016-05-31 20:51:30 +02:00
|
|
|
ret = fetch_v2_desc_by_descid(descriptor_id, rend_query, hsdirs);
|
2015-03-10 21:46:56 +01:00
|
|
|
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;
|
|
|
|
|
2015-04-30 19:38:39 +02:00
|
|
|
end:
|
2015-03-10 21:46:56 +01:00
|
|
|
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
|
2015-04-28 16:22:14 +02:00
|
|
|
rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs)
|
2015-03-10 21:46:56 +01:00
|
|
|
{
|
|
|
|
int ret;
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_data_v2_t *rend_data;
|
|
|
|
const char *onion_address;
|
2015-03-10 21:46:56 +01:00
|
|
|
|
|
|
|
tor_assert(query);
|
|
|
|
|
2016-05-31 20:51:30 +02:00
|
|
|
/* Get the version 2 data structure of the query. */
|
|
|
|
rend_data = TO_REND_DATA_V2(query);
|
|
|
|
onion_address = rend_data_get_address(query);
|
|
|
|
|
2015-03-10 21:46:56 +01:00
|
|
|
/* Depending on what's available in the rend data query object, we will
|
|
|
|
* trigger a fetch by HS address or using a descriptor ID. */
|
|
|
|
|
2016-05-31 20:51:30 +02:00
|
|
|
if (onion_address[0] != '\0') {
|
2015-03-10 21:46:56 +01:00
|
|
|
ret = fetch_v2_desc_by_addr(query, hsdirs);
|
2016-05-31 20:51:30 +02:00
|
|
|
} else if (!tor_digest_is_zero(rend_data->desc_id_fetch)) {
|
|
|
|
ret = fetch_v2_desc_by_descid(rend_data->desc_id_fetch, query,
|
|
|
|
hsdirs);
|
2015-03-10 21:46:56 +01:00
|
|
|
} else {
|
|
|
|
/* Query data is invalid. */
|
|
|
|
ret = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-04-30 19:38:39 +02:00
|
|
|
error:
|
2015-03-10 21:46:56 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-06-13 12:21:58 +02:00
|
|
|
/** 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. */
|
2007-11-01 04:43:02 +01:00
|
|
|
void
|
2015-04-28 16:22:14 +02:00
|
|
|
rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
|
2007-11-01 04:43:02 +01:00
|
|
|
{
|
2008-02-17 17:47:47 +01:00
|
|
|
rend_cache_entry_t *e = NULL;
|
2016-05-31 20:51:30 +02:00
|
|
|
const char *onion_address = rend_data_get_address(rend_query);
|
2015-03-10 21:46:56 +01:00
|
|
|
|
2008-09-24 16:44:29 +02:00
|
|
|
tor_assert(rend_query);
|
2011-09-29 05:00:24 +02:00
|
|
|
/* Before fetching, check if we already have a usable descriptor here. */
|
2016-05-31 20:51:30 +02:00
|
|
|
if (rend_cache_lookup_entry(onion_address, -1, &e) == 0 &&
|
2011-09-29 05:00:24 +02:00
|
|
|
rend_client_any_intro_points_usable(e)) {
|
2008-02-17 17:47:47 +01:00
|
|
|
log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we "
|
2011-09-29 05:00:24 +02:00
|
|
|
"already have a usable descriptor here. Not fetching.");
|
2008-02-17 17:47:47 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-06-15 15:54:59 +02:00
|
|
|
/* Are we configured to fetch descriptors? */
|
|
|
|
if (!get_options()->FetchHidServDescriptors) {
|
|
|
|
log_warn(LD_REND, "We received an onion address for a v2 rendezvous "
|
|
|
|
"service descriptor, but are not fetching service descriptors.");
|
|
|
|
return;
|
|
|
|
}
|
2007-11-01 04:43:02 +01:00
|
|
|
log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(onion_address));
|
2008-01-24 04:28:50 +01:00
|
|
|
|
2016-03-14 16:00:46 +01:00
|
|
|
rend_client_fetch_v2_desc(rend_query, NULL);
|
|
|
|
/* We don't need to look the error code because either on failure or
|
|
|
|
* success, the necessary steps to continue the HS connection will be
|
|
|
|
* triggered once the descriptor arrives or if all fetch failed. */
|
2007-11-01 04:43:02 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-04-20 11:27:58 +02:00
|
|
|
/** Cancel all rendezvous descriptor fetches currently in progress.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
rend_client_cancel_descriptor_fetches(void)
|
|
|
|
{
|
|
|
|
smartlist_t *connection_array = get_connection_array();
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
|
|
|
|
if (conn->type == CONN_TYPE_DIR &&
|
2014-02-12 14:36:08 +01:00
|
|
|
conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
|
2011-04-20 11:27:58 +02:00
|
|
|
/* It's a rendezvous descriptor fetch in progress -- cancel it
|
|
|
|
* by marking the connection for close.
|
|
|
|
*
|
|
|
|
* Even if this connection has already reached EOF, this is
|
|
|
|
* enough to make sure that if the descriptor hasn't been
|
|
|
|
* processed yet, it won't be. See the end of
|
|
|
|
* connection_handle_read; connection_reached_eof (indirectly)
|
|
|
|
* processes whatever response the connection received. */
|
|
|
|
|
|
|
|
const rend_data_t *rd = (TO_DIR_CONN(conn))->rend_data;
|
|
|
|
if (!rd) {
|
|
|
|
log_warn(LD_BUG | LD_REND,
|
|
|
|
"Marking for close dir conn fetching rendezvous "
|
|
|
|
"descriptor for unknown service!");
|
|
|
|
} else {
|
2011-04-28 19:00:34 +02:00
|
|
|
log_debug(LD_REND, "Marking for close dir conn fetching "
|
2011-04-20 11:27:58 +02:00
|
|
|
"rendezvous descriptor for service %s",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str(rend_data_get_address(rd)));
|
2011-04-20 11:27:58 +02:00
|
|
|
}
|
|
|
|
connection_mark_for_close(conn);
|
|
|
|
}
|
|
|
|
} SMARTLIST_FOREACH_END(conn);
|
|
|
|
}
|
|
|
|
|
2011-09-17 12:19:29 +02:00
|
|
|
/** Mark <b>failed_intro</b> as a failed introduction point for the
|
|
|
|
* hidden service specified by <b>rend_query</b>. If the HS now has no
|
|
|
|
* usable intro points, or we do not have an HS descriptor for it,
|
|
|
|
* then launch a new renddesc fetch.
|
|
|
|
*
|
|
|
|
* If <b>failure_type</b> is INTRO_POINT_FAILURE_GENERIC, remove the
|
|
|
|
* intro point from (our parsed copy of) the HS descriptor.
|
2004-04-18 09:37:16 +02:00
|
|
|
*
|
2011-09-17 12:19:29 +02:00
|
|
|
* If <b>failure_type</b> is INTRO_POINT_FAILURE_TIMEOUT, mark the
|
|
|
|
* intro point as 'timed out'; it will not be retried until the
|
|
|
|
* current hidden service connection attempt has ended or it has
|
|
|
|
* appeared in a newly fetched rendezvous descriptor.
|
2004-04-18 09:37:16 +02:00
|
|
|
*
|
2011-09-17 12:53:07 +02:00
|
|
|
* If <b>failure_type</b> is INTRO_POINT_FAILURE_UNREACHABLE,
|
|
|
|
* increment the intro point's reachability-failure count; if it has
|
|
|
|
* now failed MAX_INTRO_POINT_REACHABILITY_FAILURES or more times,
|
|
|
|
* remove the intro point from (our parsed copy of) the HS descriptor.
|
|
|
|
*
|
2011-09-17 12:19:29 +02:00
|
|
|
* Return -1 if error, 0 if no usable intro points remain or service
|
2004-04-18 09:37:16 +02:00
|
|
|
* unrecognized, 1 if recognized and some intro points remain.
|
|
|
|
*/
|
|
|
|
int
|
2011-09-17 12:19:29 +02:00
|
|
|
rend_client_report_intro_point_failure(extend_info_t *failed_intro,
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_data_t *rend_data,
|
2011-09-17 12:19:29 +02:00
|
|
|
unsigned int failure_type)
|
2004-04-18 09:37:16 +02:00
|
|
|
{
|
|
|
|
int i, r;
|
|
|
|
rend_cache_entry_t *ent;
|
2005-01-20 00:15:59 +01:00
|
|
|
connection_t *conn;
|
2016-05-31 20:51:30 +02:00
|
|
|
const char *onion_address = rend_data_get_address(rend_data);
|
2004-04-18 09:37:16 +02:00
|
|
|
|
2016-05-31 20:51:30 +02:00
|
|
|
r = rend_cache_lookup_entry(onion_address, -1, &ent);
|
2015-01-26 23:42:42 +01:00
|
|
|
if (r < 0) {
|
|
|
|
/* Either invalid onion address or cache entry not found. */
|
|
|
|
switch (-r) {
|
|
|
|
case EINVAL:
|
|
|
|
log_warn(LD_BUG, "Malformed service ID %s.",
|
2016-05-31 20:51:30 +02:00
|
|
|
escaped_safe_str_client(onion_address));
|
2015-01-26 23:42:42 +01:00
|
|
|
return -1;
|
|
|
|
case ENOENT:
|
|
|
|
log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
|
2016-05-31 20:51:30 +02:00
|
|
|
escaped_safe_str_client(onion_address));
|
|
|
|
rend_client_refetch_v2_renddesc(rend_data);
|
2015-01-26 23:42:42 +01:00
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
log_warn(LD_BUG, "Unknown cache lookup returned code: %d", r);
|
|
|
|
return -1;
|
|
|
|
}
|
2004-04-18 09:37:16 +02:00
|
|
|
}
|
2015-01-26 23:42:42 +01:00
|
|
|
/* 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. */
|
2004-04-18 09:37:16 +02:00
|
|
|
|
2007-12-21 10:28:22 +01:00
|
|
|
for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) {
|
|
|
|
rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i);
|
2011-05-10 22:23:43 +02:00
|
|
|
if (tor_memeq(failed_intro->identity_digest,
|
2007-12-21 10:28:22 +01:00
|
|
|
intro->extend_info->identity_digest, DIGEST_LEN)) {
|
2011-09-17 12:19:29 +02:00
|
|
|
switch (failure_type) {
|
|
|
|
default:
|
|
|
|
log_warn(LD_BUG, "Unknown failure type %u. Removing intro point.",
|
|
|
|
failure_type);
|
|
|
|
tor_fragile_assert();
|
|
|
|
/* fall through */
|
|
|
|
case INTRO_POINT_FAILURE_GENERIC:
|
2015-06-18 22:09:18 +02:00
|
|
|
rend_cache_intro_failure_note(failure_type,
|
2015-08-20 20:28:47 +02:00
|
|
|
(uint8_t *)failed_intro->identity_digest,
|
2016-05-31 20:51:30 +02:00
|
|
|
onion_address);
|
2011-09-17 12:19:29 +02:00
|
|
|
rend_intro_point_free(intro);
|
|
|
|
smartlist_del(ent->parsed->intro_nodes, i);
|
|
|
|
break;
|
|
|
|
case INTRO_POINT_FAILURE_TIMEOUT:
|
|
|
|
intro->timed_out = 1;
|
|
|
|
break;
|
2011-09-17 12:53:07 +02:00
|
|
|
case INTRO_POINT_FAILURE_UNREACHABLE:
|
|
|
|
++(intro->unreachable_count);
|
|
|
|
{
|
|
|
|
int zap_intro_point =
|
|
|
|
intro->unreachable_count >= MAX_INTRO_POINT_REACHABILITY_FAILURES;
|
|
|
|
log_info(LD_REND, "Failed to reach this intro point %u times.%s",
|
|
|
|
intro->unreachable_count,
|
|
|
|
zap_intro_point ? " Removing from descriptor.": "");
|
|
|
|
if (zap_intro_point) {
|
2015-08-20 20:28:47 +02:00
|
|
|
rend_cache_intro_failure_note(
|
|
|
|
failure_type,
|
2016-05-31 20:51:30 +02:00
|
|
|
(uint8_t *) failed_intro->identity_digest, onion_address);
|
2011-09-17 12:53:07 +02:00
|
|
|
rend_intro_point_free(intro);
|
|
|
|
smartlist_del(ent->parsed->intro_nodes, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2011-09-17 12:19:29 +02:00
|
|
|
}
|
2007-12-21 10:28:22 +01:00
|
|
|
break;
|
2004-04-18 09:37:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-20 22:49:41 +02:00
|
|
|
if (! rend_client_any_intro_points_usable(ent)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND,
|
|
|
|
"No more intro points remain for %s. Re-fetching descriptor.",
|
2016-05-31 20:51:30 +02:00
|
|
|
escaped_safe_str_client(onion_address));
|
|
|
|
rend_client_refetch_v2_renddesc(rend_data);
|
2005-01-20 00:15:59 +01:00
|
|
|
|
|
|
|
/* move all pending streams back to renddesc_wait */
|
2015-11-27 18:54:57 +01:00
|
|
|
/* NOTE: We can now do this faster, if we use pending_entry_connections */
|
2005-01-20 00:15:59 +01:00
|
|
|
while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
|
2008-09-24 16:44:29 +02:00
|
|
|
AP_CONN_STATE_CIRCUIT_WAIT,
|
2016-05-31 20:51:30 +02:00
|
|
|
onion_address))) {
|
2015-11-27 18:54:57 +01:00
|
|
|
connection_ap_mark_as_non_pending_circuit(TO_ENTRY_CONN(conn));
|
2005-01-20 00:15:59 +01:00
|
|
|
conn->state = AP_CONN_STATE_RENDDESC_WAIT;
|
|
|
|
}
|
|
|
|
|
2004-04-18 09:37:16 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND,"%d options left for %s.",
|
2008-09-24 16:44:29 +02:00
|
|
|
smartlist_len(ent->parsed->intro_nodes),
|
2016-05-31 20:51:30 +02:00
|
|
|
escaped_safe_str_client(onion_address));
|
2004-04-18 09:37:16 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Called when we receive a RENDEZVOUS_ESTABLISHED cell; changes the state of
|
2004-04-06 05:44:36 +02:00
|
|
|
* the circuit to C_REND_READY.
|
|
|
|
*/
|
2004-04-05 02:47:48 +02:00
|
|
|
int
|
2010-12-14 01:34:01 +01:00
|
|
|
rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request,
|
2005-12-14 21:40:40 +01:00
|
|
|
size_t request_len)
|
2004-04-05 02:47:48 +02:00
|
|
|
{
|
2006-06-05 00:42:13 +02:00
|
|
|
(void) request;
|
|
|
|
(void) request_len;
|
2004-04-05 02:47:48 +02:00
|
|
|
/* we just got an ack for our establish-rendezvous. switch purposes. */
|
2012-10-12 18:22:13 +02:00
|
|
|
if (circ->base_.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
|
|
|
|
"Closing circ.");
|
2006-10-09 17:47:27 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
2004-04-05 02:47:48 +02:00
|
|
|
return -1;
|
2004-04-03 05:06:06 +02:00
|
|
|
}
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
|
|
|
|
"rendezvous.");
|
2011-11-24 15:52:38 +01:00
|
|
|
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_READY);
|
2011-05-29 17:03:41 +02:00
|
|
|
/* Set timestamp_dirty, because circuit_expire_building expects it
|
|
|
|
* to specify when a circuit entered the _C_REND_READY state. */
|
2012-10-12 18:22:13 +02:00
|
|
|
circ->base_.timestamp_dirty = time(NULL);
|
2012-12-08 21:07:58 +01:00
|
|
|
|
|
|
|
/* From a path bias point of view, this circuit is now successfully used.
|
2016-01-26 03:48:31 +01:00
|
|
|
* Waiting any longer opens us up to attacks from malicious hidden services.
|
|
|
|
* They could induce the client to attempt to connect to their hidden
|
|
|
|
* service and never reply to the client's rend requests */
|
2013-01-19 04:37:16 +01:00
|
|
|
pathbias_mark_use_success(circ);
|
2012-12-08 21:07:58 +01:00
|
|
|
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXXX++ This is a pretty brute-force approach. It'd be better to
|
2008-07-06 20:34:45 +02:00
|
|
|
* attach only the connections that are waiting on this circuit, rather
|
2009-01-06 18:37:22 +01:00
|
|
|
* than trying to attach them all. See comments bug 743. */
|
2008-07-06 20:47:27 +02:00
|
|
|
/* If we already have the introduction circuit built, make sure we send
|
2008-07-06 20:34:45 +02:00
|
|
|
* the INTRODUCE cell _now_ */
|
2015-11-17 14:49:30 +01:00
|
|
|
connection_ap_attach_pending(1);
|
2004-04-05 02:47:48 +02:00
|
|
|
return 0;
|
2004-04-03 00:23:15 +02:00
|
|
|
}
|
|
|
|
|
2016-01-26 03:48:31 +01:00
|
|
|
/** The service sent us a rendezvous cell; join the circuits. */
|
2004-04-05 09:41:31 +02:00
|
|
|
int
|
2010-12-14 01:34:01 +01:00
|
|
|
rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
|
2005-12-14 21:40:40 +01:00
|
|
|
size_t request_len)
|
2004-04-03 00:23:15 +02:00
|
|
|
{
|
2004-04-05 22:53:50 +02:00
|
|
|
crypt_path_t *hop;
|
|
|
|
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
if ((circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
|
|
|
|
circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
|
2004-04-14 07:18:21 +02:00
|
|
|
|| !circ->build_state->pending_final_cpath) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
|
|
|
|
"expecting it. Closing.");
|
2006-10-09 17:47:27 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
2004-04-05 09:41:31 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2004-04-05 22:53:50 +02:00
|
|
|
if (request_len != DH_KEY_LEN+DIGEST_LEN) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_PROTOCOL,"Incorrect length (%d) on RENDEZVOUS2 cell.",
|
|
|
|
(int)request_len);
|
2004-04-05 22:53:50 +02:00
|
|
|
goto err;
|
|
|
|
}
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2007-08-11 16:13:25 +02:00
|
|
|
log_info(LD_REND,"Got RENDEZVOUS2 cell from hidden service.");
|
|
|
|
|
2016-01-26 03:48:31 +01:00
|
|
|
/* first DH_KEY_LEN bytes are g^y from the service. Finish the dh
|
|
|
|
* handshake...*/
|
2004-10-17 00:14:52 +02:00
|
|
|
tor_assert(circ->build_state);
|
|
|
|
tor_assert(circ->build_state->pending_final_cpath);
|
2004-04-05 22:53:50 +02:00
|
|
|
hop = circ->build_state->pending_final_cpath;
|
2012-12-05 03:27:07 +01:00
|
|
|
tor_assert(hop->rend_dh_handshake_state);
|
2010-12-16 04:47:28 +01:00
|
|
|
if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN,
|
2012-12-05 03:27:07 +01:00
|
|
|
hop->rend_dh_handshake_state, (char*)request,
|
2010-12-14 01:34:01 +01:00
|
|
|
DH_KEY_LEN,
|
2004-04-05 22:53:50 +02:00
|
|
|
keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
|
2004-04-05 22:53:50 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
/* ... and set up cpath. */
|
|
|
|
if (circuit_init_cpath_crypto(hop, keys+DIGEST_LEN, 0)<0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* Check whether the digest is right... */
|
2011-05-10 22:58:38 +02:00
|
|
|
if (tor_memneq(keys, request+DH_KEY_LEN, DIGEST_LEN)) {
|
2006-02-13 11:33:00 +01:00
|
|
|
log_warn(LD_PROTOCOL, "Incorrect digest of key material.");
|
2004-04-05 22:53:50 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-12-05 03:27:07 +01:00
|
|
|
crypto_dh_free(hop->rend_dh_handshake_state);
|
|
|
|
hop->rend_dh_handshake_state = NULL;
|
2004-04-06 22:23:58 +02:00
|
|
|
|
2004-04-05 22:53:50 +02:00
|
|
|
/* All is well. Extend the circuit. */
|
2011-11-24 15:52:38 +01:00
|
|
|
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_JOINED);
|
2004-04-06 01:40:59 +02:00
|
|
|
hop->state = CPATH_STATE_OPEN;
|
2004-04-06 23:25:11 +02:00
|
|
|
/* set the windows to default. these are the windows
|
2016-01-26 03:48:31 +01:00
|
|
|
* that the client thinks the service has.
|
2004-04-06 23:25:11 +02:00
|
|
|
*/
|
2009-09-15 12:33:33 +02:00
|
|
|
hop->package_window = circuit_initial_package_window();
|
2004-04-06 23:25:11 +02:00
|
|
|
hop->deliver_window = CIRCWINDOW_START;
|
|
|
|
|
2011-12-23 14:25:17 +01:00
|
|
|
/* Now that this circuit has finished connecting to its destination,
|
|
|
|
* make sure circuit_get_open_circ_or_launch is willing to return it
|
|
|
|
* so we can actually use it. */
|
|
|
|
circ->hs_circ_has_timed_out = 0;
|
|
|
|
|
2004-04-05 22:53:50 +02:00
|
|
|
onion_append_to_cpath(&circ->cpath, hop);
|
|
|
|
circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
|
2011-12-06 14:02:58 +01:00
|
|
|
|
|
|
|
circuit_try_attaching_streams(circ);
|
|
|
|
|
2012-11-07 22:09:58 +01:00
|
|
|
memwipe(keys, 0, sizeof(keys));
|
2004-04-05 09:41:31 +02:00
|
|
|
return 0;
|
2004-04-05 22:53:50 +02:00
|
|
|
err:
|
2012-11-07 22:09:58 +01:00
|
|
|
memwipe(keys, 0, sizeof(keys));
|
2006-10-09 17:47:27 +02:00
|
|
|
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
2004-04-05 22:53:50 +02:00
|
|
|
return -1;
|
2004-04-05 09:41:31 +02:00
|
|
|
}
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2009-05-28 22:19:05 +02:00
|
|
|
/** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that are
|
|
|
|
* waiting on <b>query</b>. If there's a working cache entry here with at
|
|
|
|
* least one intro point, move them to the next state. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
2009-05-28 22:19:05 +02:00
|
|
|
rend_client_desc_trynow(const char *query)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_connection_t *conn;
|
2004-04-08 00:41:00 +02:00
|
|
|
rend_cache_entry_t *entry;
|
2011-07-20 18:55:42 +02:00
|
|
|
const rend_data_t *rend_data;
|
2005-04-27 00:36:00 +02:00
|
|
|
time_t now = time(NULL);
|
2009-05-03 00:09:18 +02:00
|
|
|
|
2007-05-22 17:49:14 +02:00
|
|
|
smartlist_t *conns = get_connection_array();
|
2011-07-20 18:55:42 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
|
|
|
|
if (base_conn->type != CONN_TYPE_AP ||
|
|
|
|
base_conn->state != AP_CONN_STATE_RENDDESC_WAIT ||
|
|
|
|
base_conn->marked_for_close)
|
2006-07-26 21:07:26 +02:00
|
|
|
continue;
|
2011-07-20 18:55:42 +02:00
|
|
|
conn = TO_ENTRY_CONN(base_conn);
|
|
|
|
rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data;
|
|
|
|
if (!rend_data)
|
2008-09-24 16:44:29 +02:00
|
|
|
continue;
|
2016-05-31 20:51:30 +02:00
|
|
|
const char *onion_address = rend_data_get_address(rend_data);
|
|
|
|
if (rend_cmp_service_ids(query, onion_address))
|
2006-01-17 05:16:59 +01:00
|
|
|
continue;
|
2011-07-20 18:55:42 +02:00
|
|
|
assert_connection_ok(base_conn, now);
|
2016-05-31 20:51:30 +02:00
|
|
|
if (rend_cache_lookup_entry(onion_address, -1,
|
2015-01-26 23:42:42 +01:00
|
|
|
&entry) == 0 &&
|
2011-04-20 22:49:41 +02:00
|
|
|
rend_client_any_intro_points_usable(entry)) {
|
2004-04-08 00:41:00 +02:00
|
|
|
/* either this fetch worked, or it failed but there was a
|
|
|
|
* valid entry from before which we should reuse */
|
2006-02-13 11:33:00 +01:00
|
|
|
log_info(LD_REND,"Rend desc is usable. Launching circuits.");
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
2005-04-27 00:36:00 +02:00
|
|
|
|
|
|
|
/* restart their timeout values, so they get a fair shake at
|
|
|
|
* connecting to the hidden service. */
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->timestamp_created = now;
|
|
|
|
base_conn->timestamp_lastread = now;
|
|
|
|
base_conn->timestamp_lastwritten = now;
|
2005-04-27 00:36:00 +02:00
|
|
|
|
2015-11-13 19:38:01 +01:00
|
|
|
connection_ap_mark_as_pending_circuit(conn);
|
2004-04-08 00:41:00 +02:00
|
|
|
} else { /* 404, or fetch didn't get that far */
|
2009-05-28 22:19:05 +02:00
|
|
|
log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is "
|
2009-09-28 15:08:32 +02:00
|
|
|
"unavailable (try again later).",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(query));
|
2009-05-28 22:19:05 +02:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
|
2015-04-27 22:21:47 +02:00
|
|
|
rend_client_note_connection_attempt_ended(rend_data);
|
2004-04-03 01:38:26 +02:00
|
|
|
}
|
2011-07-20 18:55:42 +02:00
|
|
|
} SMARTLIST_FOREACH_END(base_conn);
|
2004-04-03 00:23:15 +02:00
|
|
|
}
|
|
|
|
|
2015-04-27 22:21:47 +02:00
|
|
|
/** 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. */
|
2011-09-17 12:23:26 +02:00
|
|
|
void
|
2015-04-27 22:21:47 +02:00
|
|
|
rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
|
2011-09-17 12:23:26 +02:00
|
|
|
{
|
2015-04-27 22:21:47 +02:00
|
|
|
unsigned int have_onion = 0;
|
2011-09-17 12:23:26 +02:00
|
|
|
rend_cache_entry_t *cache_entry = NULL;
|
2016-05-31 20:51:30 +02:00
|
|
|
const char *onion_address = rend_data_get_address(rend_data);
|
|
|
|
rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data);
|
2011-09-17 12:23:26 +02:00
|
|
|
|
2016-05-31 20:51:30 +02:00
|
|
|
if (onion_address[0] != '\0') {
|
2015-04-27 22:21:47 +02:00
|
|
|
/* Ignore return value; we find an entry, or we don't. */
|
2016-05-31 20:51:30 +02:00
|
|
|
(void) rend_cache_lookup_entry(onion_address, -1, &cache_entry);
|
2015-04-27 22:21:47 +02:00
|
|
|
have_onion = 1;
|
|
|
|
}
|
2011-09-17 12:23:26 +02:00
|
|
|
|
|
|
|
/* Clear the timed_out flag on all remaining intro points for this HS. */
|
|
|
|
if (cache_entry != NULL) {
|
|
|
|
SMARTLIST_FOREACH(cache_entry->parsed->intro_nodes,
|
|
|
|
rend_intro_point_t *, ip,
|
|
|
|
ip->timed_out = 0; );
|
|
|
|
}
|
2011-09-20 13:26:09 +02:00
|
|
|
|
|
|
|
/* Remove the HS's entries in last_hid_serv_requests. */
|
2015-04-27 22:21:47 +02:00
|
|
|
if (have_onion) {
|
|
|
|
unsigned int replica;
|
2016-05-31 20:51:30 +02:00
|
|
|
for (replica = 0; replica < ARRAY_LENGTH(rend_data_v2->descriptor_id);
|
2015-04-27 22:21:47 +02:00
|
|
|
replica++) {
|
2016-05-31 20:51:30 +02:00
|
|
|
const char *desc_id = rend_data_v2->descriptor_id[replica];
|
2015-04-27 22:21:47 +02:00
|
|
|
purge_hid_serv_from_last_hid_serv_requests(desc_id);
|
|
|
|
}
|
|
|
|
log_info(LD_REND, "Connection attempt for %s has ended; "
|
|
|
|
"cleaning up temporary state.",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(onion_address));
|
2015-04-27 22:21:47 +02:00
|
|
|
} else {
|
|
|
|
/* We only have an ID for a fetch. Probably used by HSFETCH. */
|
2016-05-31 20:51:30 +02:00
|
|
|
purge_hid_serv_from_last_hid_serv_requests(rend_data_v2->desc_id_fetch);
|
2015-04-27 22:21:47 +02:00
|
|
|
}
|
2011-09-17 12:23:26 +02:00
|
|
|
}
|
|
|
|
|
2005-06-29 23:46:55 +02:00
|
|
|
/** Return a newly allocated extend_info_t* for a randomly chosen introduction
|
|
|
|
* point for the named hidden service. Return NULL if all introduction points
|
|
|
|
* have been tried and failed.
|
2004-04-05 02:47:48 +02:00
|
|
|
*/
|
2005-06-29 23:46:55 +02:00
|
|
|
extend_info_t *
|
2008-09-24 16:44:29 +02:00
|
|
|
rend_client_get_random_intro(const rend_data_t *rend_query)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2015-01-26 23:42:42 +01:00
|
|
|
int ret;
|
2009-10-18 00:52:18 +02:00
|
|
|
extend_info_t *result;
|
2004-04-08 04:11:49 +02:00
|
|
|
rend_cache_entry_t *entry;
|
2016-05-31 20:51:30 +02:00
|
|
|
const char *onion_address = rend_data_get_address(rend_query);
|
2004-04-05 02:47:48 +02:00
|
|
|
|
2016-05-31 20:51:30 +02:00
|
|
|
ret = rend_cache_lookup_entry(onion_address, -1, &entry);
|
2015-01-26 23:42:42 +01:00
|
|
|
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.",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(onion_address));
|
2015-01-26 23:42:42 +01:00
|
|
|
/* XXX: Should we refetch the descriptor here if the IPs are not usable
|
|
|
|
* anymore ?. */
|
2004-04-05 02:47:48 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-10-18 00:52:18 +02:00
|
|
|
/* See if we can get a node that complies with ExcludeNodes */
|
2011-04-20 22:49:41 +02:00
|
|
|
if ((result = rend_client_get_random_intro_impl(entry, 1, 1)))
|
2009-10-18 00:52:18 +02:00
|
|
|
return result;
|
|
|
|
/* If not, and StrictNodes is not set, see if we can return any old node
|
|
|
|
*/
|
|
|
|
if (!get_options()->StrictNodes)
|
2011-04-20 22:49:41 +02:00
|
|
|
return rend_client_get_random_intro_impl(entry, 0, 1);
|
2009-10-18 00:52:18 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** As rend_client_get_random_intro, except assume that StrictNodes is set
|
2011-04-27 19:43:11 +02:00
|
|
|
* iff <b>strict</b> is true. If <b>warnings</b> is false, don't complain
|
|
|
|
* to the user when we're out of nodes, even if StrictNodes is true.
|
2009-10-18 00:52:18 +02:00
|
|
|
*/
|
|
|
|
static extend_info_t *
|
2011-04-20 22:49:41 +02:00
|
|
|
rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
|
|
|
|
const int strict,
|
|
|
|
const int warnings)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-04-05 02:47:48 +02:00
|
|
|
int i;
|
2011-04-20 22:49:41 +02:00
|
|
|
|
2007-12-21 10:28:22 +01:00
|
|
|
rend_intro_point_t *intro;
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2009-10-18 00:52:18 +02:00
|
|
|
smartlist_t *usable_nodes;
|
|
|
|
int n_excluded = 0;
|
2004-04-05 02:47:48 +02:00
|
|
|
|
2009-10-18 00:52:18 +02:00
|
|
|
/* We'll keep a separate list of the usable nodes. If this becomes empty,
|
|
|
|
* no nodes are usable. */
|
2012-01-18 21:53:30 +01:00
|
|
|
usable_nodes = smartlist_new();
|
2009-10-18 00:52:18 +02:00
|
|
|
smartlist_add_all(usable_nodes, entry->parsed->intro_nodes);
|
2004-04-05 02:47:48 +02:00
|
|
|
|
2011-09-17 12:19:29 +02:00
|
|
|
/* Remove the intro points that have timed out during this HS
|
|
|
|
* connection attempt from our list of usable nodes. */
|
|
|
|
SMARTLIST_FOREACH(usable_nodes, rend_intro_point_t *, ip,
|
|
|
|
if (ip->timed_out) {
|
|
|
|
SMARTLIST_DEL_CURRENT(usable_nodes, ip);
|
|
|
|
});
|
|
|
|
|
2005-06-29 23:46:55 +02:00
|
|
|
again:
|
2009-10-18 00:52:18 +02:00
|
|
|
if (smartlist_len(usable_nodes) == 0) {
|
2011-04-20 22:49:41 +02:00
|
|
|
if (n_excluded && get_options()->StrictNodes && warnings) {
|
2009-10-18 00:52:18 +02:00
|
|
|
/* 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);
|
2005-06-29 23:46:55 +02:00
|
|
|
return NULL;
|
2009-10-18 00:52:18 +02:00
|
|
|
}
|
2004-04-05 02:47:48 +02:00
|
|
|
|
2009-10-18 00:52:18 +02:00
|
|
|
i = crypto_rand_int(smartlist_len(usable_nodes));
|
|
|
|
intro = smartlist_get(usable_nodes, i);
|
2016-07-08 06:46:00 +02:00
|
|
|
if (BUG(!intro->extend_info)) {
|
|
|
|
/* This should never happen, but it isn't fatal, just try another */
|
|
|
|
smartlist_del(usable_nodes, i);
|
|
|
|
goto again;
|
|
|
|
}
|
2016-08-31 07:10:58 +02:00
|
|
|
/* All version 2 HS descriptors come with a TAP onion key.
|
|
|
|
* Clients used to try to get the TAP onion key from the consensus, but this
|
|
|
|
* meant that hidden services could discover which consensus clients have. */
|
2016-07-08 06:46:00 +02:00
|
|
|
if (!extend_info_supports_tap(intro->extend_info)) {
|
2016-08-31 07:10:58 +02:00
|
|
|
log_info(LD_REND, "The HS descriptor is missing a TAP onion key for the "
|
|
|
|
"intro-point relay '%s'; trying another.",
|
|
|
|
safe_str_client(extend_info_describe(intro->extend_info)));
|
|
|
|
smartlist_del(usable_nodes, i);
|
|
|
|
goto again;
|
2004-04-08 05:18:03 +02:00
|
|
|
}
|
2009-10-18 00:52:18 +02:00
|
|
|
/* Check if we should refuse to talk to this router. */
|
2011-07-07 17:52:13 +02:00
|
|
|
if (strict &&
|
2009-10-18 00:52:18 +02:00
|
|
|
routerset_contains_extendinfo(options->ExcludeNodes,
|
|
|
|
intro->extend_info)) {
|
|
|
|
n_excluded++;
|
|
|
|
smartlist_del(usable_nodes, i);
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
|
|
|
smartlist_free(usable_nodes);
|
2007-12-21 10:28:22 +01:00
|
|
|
return extend_info_dup(intro->extend_info);
|
2004-04-05 02:47:48 +02:00
|
|
|
}
|
2005-06-09 21:03:31 +02:00
|
|
|
|
2011-04-20 22:49:41 +02:00
|
|
|
/** Return true iff any introduction points still listed in <b>entry</b> are
|
|
|
|
* usable. */
|
|
|
|
int
|
|
|
|
rend_client_any_intro_points_usable(const rend_cache_entry_t *entry)
|
|
|
|
{
|
2011-11-07 17:35:51 +01:00
|
|
|
extend_info_t *extend_info =
|
|
|
|
rend_client_get_random_intro_impl(entry, get_options()->StrictNodes, 0);
|
|
|
|
|
2011-11-07 17:46:51 +01:00
|
|
|
int rv = (extend_info != NULL);
|
2011-11-07 17:35:51 +01:00
|
|
|
|
2011-11-07 17:46:51 +01:00
|
|
|
extend_info_free(extend_info);
|
2011-11-07 17:35:51 +01:00
|
|
|
return rv;
|
2011-04-20 22:49:41 +02:00
|
|
|
}
|
|
|
|
|
2008-08-12 18:12:26 +02:00
|
|
|
/** Client-side authorizations for hidden services; map of onion address to
|
|
|
|
* rend_service_authorization_t*. */
|
|
|
|
static strmap_t *auth_hid_servs = NULL;
|
|
|
|
|
|
|
|
/** Look up the client-side authorization for the hidden service with
|
|
|
|
* <b>onion_address</b>. Return NULL if no authorization is available for
|
|
|
|
* that address. */
|
|
|
|
rend_service_authorization_t*
|
|
|
|
rend_client_lookup_service_authorization(const char *onion_address)
|
|
|
|
{
|
|
|
|
tor_assert(onion_address);
|
|
|
|
if (!auth_hid_servs) return NULL;
|
|
|
|
return strmap_get(auth_hid_servs, onion_address);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Helper: Free storage held by rend_service_authorization_t. */
|
|
|
|
static void
|
|
|
|
rend_service_authorization_free(rend_service_authorization_t *auth)
|
|
|
|
{
|
|
|
|
tor_free(auth);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Helper for strmap_free. */
|
|
|
|
static void
|
|
|
|
rend_service_authorization_strmap_item_free(void *service_auth)
|
|
|
|
{
|
|
|
|
rend_service_authorization_free(service_auth);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Release all the storage held in auth_hid_servs.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
rend_service_authorization_free_all(void)
|
|
|
|
{
|
|
|
|
if (!auth_hid_servs) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
strmap_free(auth_hid_servs, rend_service_authorization_strmap_item_free);
|
|
|
|
auth_hid_servs = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Parse <b>config_line</b> as a client-side authorization for a hidden
|
|
|
|
* service and add it to the local map of hidden service authorizations.
|
|
|
|
* Return 0 for success and -1 for failure. */
|
|
|
|
int
|
2011-06-14 19:01:38 +02:00
|
|
|
rend_parse_service_authorization(const or_options_t *options,
|
|
|
|
int validate_only)
|
2008-08-12 18:12:26 +02:00
|
|
|
{
|
|
|
|
config_line_t *line;
|
|
|
|
int res = -1;
|
|
|
|
strmap_t *parsed = strmap_new();
|
2012-01-18 21:53:30 +01:00
|
|
|
smartlist_t *sl = smartlist_new();
|
2008-09-05 22:52:15 +02:00
|
|
|
rend_service_authorization_t *auth = NULL;
|
2015-04-14 05:35:06 +02:00
|
|
|
char *err_msg = NULL;
|
2008-08-12 18:12:26 +02:00
|
|
|
|
|
|
|
for (line = options->HidServAuth; line; line = line->next) {
|
|
|
|
char *onion_address, *descriptor_cookie;
|
2008-09-05 22:52:15 +02:00
|
|
|
auth = NULL;
|
2008-08-12 18:12:26 +02:00
|
|
|
SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
|
|
|
|
smartlist_clear(sl);
|
|
|
|
smartlist_split_string(sl, line->value, " ",
|
|
|
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
|
|
|
|
if (smartlist_len(sl) < 2) {
|
|
|
|
log_warn(LD_CONFIG, "Configuration line does not consist of "
|
|
|
|
"\"onion-address authorization-cookie [service-name]\": "
|
|
|
|
"'%s'", line->value);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
auth = tor_malloc_zero(sizeof(rend_service_authorization_t));
|
|
|
|
/* Parse onion address. */
|
|
|
|
onion_address = smartlist_get(sl, 0);
|
|
|
|
if (strlen(onion_address) != REND_SERVICE_ADDRESS_LEN ||
|
|
|
|
strcmpend(onion_address, ".onion")) {
|
|
|
|
log_warn(LD_CONFIG, "Onion address has wrong format: '%s'",
|
|
|
|
onion_address);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
strlcpy(auth->onion_address, onion_address, REND_SERVICE_ID_LEN_BASE32+1);
|
|
|
|
if (!rend_valid_service_id(auth->onion_address)) {
|
|
|
|
log_warn(LD_CONFIG, "Onion address has wrong format: '%s'",
|
|
|
|
onion_address);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
/* Parse descriptor cookie. */
|
|
|
|
descriptor_cookie = smartlist_get(sl, 1);
|
2015-04-14 05:35:06 +02:00
|
|
|
if (rend_auth_decode_cookie(descriptor_cookie, auth->descriptor_cookie,
|
|
|
|
&auth->auth_type, &err_msg) < 0) {
|
|
|
|
tor_assert(err_msg);
|
|
|
|
log_warn(LD_CONFIG, "%s", err_msg);
|
|
|
|
tor_free(err_msg);
|
2008-08-12 18:12:26 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (strmap_get(parsed, auth->onion_address)) {
|
|
|
|
log_warn(LD_CONFIG, "Duplicate authorization for the same hidden "
|
|
|
|
"service.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
strmap_set(parsed, auth->onion_address, auth);
|
2008-09-05 22:52:15 +02:00
|
|
|
auth = NULL;
|
2008-08-12 18:12:26 +02:00
|
|
|
}
|
|
|
|
res = 0;
|
|
|
|
goto done;
|
|
|
|
err:
|
|
|
|
res = -1;
|
|
|
|
done:
|
2009-12-12 08:07:59 +01:00
|
|
|
rend_service_authorization_free(auth);
|
2008-08-12 18:12:26 +02:00
|
|
|
SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
|
|
|
|
smartlist_free(sl);
|
|
|
|
if (!validate_only && res == 0) {
|
|
|
|
rend_service_authorization_free_all();
|
|
|
|
auth_hid_servs = parsed;
|
|
|
|
} else {
|
|
|
|
strmap_free(parsed, rend_service_authorization_strmap_item_free);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2016-07-14 06:04:02 +02:00
|
|
|
/* Can Tor client code make direct (non-anonymous) connections to introduction
|
|
|
|
* or rendezvous points?
|
|
|
|
* Returns true if tor was compiled with NON_ANONYMOUS_MODE_ENABLED, and is
|
|
|
|
* configured in Tor2web mode. */
|
|
|
|
int
|
|
|
|
rend_client_allow_non_anonymous_connection(const or_options_t *options)
|
|
|
|
{
|
|
|
|
/* Tor2web support needs to be compiled in to a tor binary. */
|
|
|
|
#ifdef NON_ANONYMOUS_MODE_ENABLED
|
|
|
|
/* Tor2web */
|
|
|
|
return options->Tor2webMode ? 1 : 0;
|
|
|
|
#else
|
|
|
|
(void)options;
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* At compile-time, was non-anonymous mode enabled via
|
|
|
|
* NON_ANONYMOUS_MODE_ENABLED ? */
|
|
|
|
int
|
|
|
|
rend_client_non_anonymous_mode_enabled(const or_options_t *options)
|
|
|
|
{
|
|
|
|
(void)options;
|
|
|
|
/* Tor2web support needs to be compiled in to a tor binary. */
|
|
|
|
#ifdef NON_ANONYMOUS_MODE_ENABLED
|
|
|
|
/* Tor2web */
|
|
|
|
return 1;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|