hs: Refactor rend_data_t for multi version support

In order to implement proposal 224, we need the data structure rend_data_t to
be able to accomodate versionning that is the current version of hidden
service (2) and the new version (3) and future version.

For that, we implement a series of accessors and a downcast function to get
the v2 data structure. rend_data_t becomes a top level generic place holder.

The entire rend_data_t API has been moved to hs_common.{c|h} in order to
seperate code that is shared from between HS versions and unshared code (in
rendcommon.c).

Closes #19024

Signed-off-by: David Goulet <dgoulet@torproject.org>
Signed-off-by: George Kadianakis <desnacked@riseup.net>
This commit is contained in:
David Goulet 2016-05-31 14:51:30 -04:00
parent 8fe410e875
commit 8293356ad9
20 changed files with 635 additions and 361 deletions

View File

@ -23,6 +23,7 @@
#include "connection_or.h"
#include "control.h"
#include "main.h"
#include "hs_common.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "onion.h"
@ -1311,9 +1312,11 @@ circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
if (!circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if (ocirc->rend_data &&
!rend_cmp_service_ids(rend_data->onion_address,
ocirc->rend_data->onion_address) &&
if (ocirc->rend_data == NULL) {
continue;
}
if (!rend_cmp_service_ids(rend_data_get_address(rend_data),
rend_data_get_address(ocirc->rend_data)) &&
tor_memeq(ocirc->rend_data->rend_cookie,
rend_data->rend_cookie,
REND_COOKIE_LEN))
@ -1325,13 +1328,14 @@ circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
}
/** Return the first circuit originating here in global_circuitlist after
* <b>start</b> whose purpose is <b>purpose</b>, and where
* <b>digest</b> (if set) matches the rend_pk_digest field. Return NULL if no
* circuit is found. If <b>start</b> is NULL, begin at the start of the list.
* <b>start</b> whose purpose is <b>purpose</b>, and where <b>digest</b> (if
* set) matches the private key digest of the rend data associated with the
* circuit. Return NULL if no circuit is found. If <b>start</b> is NULL,
* begin at the start of the list.
*/
origin_circuit_t *
circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
const char *digest, uint8_t purpose)
const uint8_t *digest, uint8_t purpose)
{
int idx;
smartlist_t *lst = circuit_get_global_list();
@ -1343,17 +1347,23 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
for ( ; idx < smartlist_len(lst); ++idx) {
circuit_t *circ = smartlist_get(lst, idx);
origin_circuit_t *ocirc;
if (circ->marked_for_close)
continue;
if (circ->purpose != purpose)
continue;
/* At this point we should be able to get a valid origin circuit because
* the origin purpose we are looking for matches this circuit. */
if (BUG(!CIRCUIT_PURPOSE_IS_ORIGIN(circ->purpose))) {
break;
}
ocirc = TO_ORIGIN_CIRCUIT(circ);
if (!digest)
return TO_ORIGIN_CIRCUIT(circ);
else if (TO_ORIGIN_CIRCUIT(circ)->rend_data &&
tor_memeq(TO_ORIGIN_CIRCUIT(circ)->rend_data->rend_pk_digest,
digest, DIGEST_LEN))
return TO_ORIGIN_CIRCUIT(circ);
return ocirc;
if (rend_circuit_pk_digest_eq(ocirc, digest)) {
return ocirc;
}
}
return NULL;
}
@ -1831,7 +1841,7 @@ circuit_about_to_free(circuit_t *circ)
if (orig_reason != END_CIRC_REASON_IP_NOW_REDUNDANT) {
/* treat this like getting a nack from it */
log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s",
safe_str_client(ocirc->rend_data->onion_address),
safe_str_client(rend_data_get_address(ocirc->rend_data)),
safe_str_client(build_state_get_exit_nickname(ocirc->build_state)),
timed_out ? "Recording timeout." : "Removing from descriptor.");
rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
@ -1848,7 +1858,7 @@ circuit_about_to_free(circuit_t *circ)
log_info(LD_REND, "Failed intro circ %s to %s "
"(building circuit to intro point). "
"Marking intro point as possibly unreachable.",
safe_str_client(ocirc->rend_data->onion_address),
safe_str_client(rend_data_get_address(ocirc->rend_data)),
safe_str_client(build_state_get_exit_nickname(
ocirc->build_state)));
rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,

View File

@ -45,7 +45,7 @@ origin_circuit_t *circuit_get_by_global_id(uint32_t id);
origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data(
const rend_data_t *rend_data);
origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
const char *digest, uint8_t purpose);
const uint8_t *digest, uint8_t purpose);
or_circuit_t *circuit_get_rendezvous(const uint8_t *cookie);
or_circuit_t *circuit_get_intro_point(const uint8_t *digest);
void circuit_set_rendezvous_cookie(or_circuit_t *circ, const uint8_t *cookie);

View File

@ -22,6 +22,7 @@
#include "connection_edge.h"
#include "control.h"
#include "entrynodes.h"
#include "hs_common.h"
#include "nodelist.h"
#include "networkstatus.h"
#include "policies.h"
@ -154,8 +155,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
if ((edge_conn->rend_data && !origin_circ->rend_data) ||
(!edge_conn->rend_data && origin_circ->rend_data) ||
(edge_conn->rend_data && origin_circ->rend_data &&
rend_cmp_service_ids(edge_conn->rend_data->onion_address,
origin_circ->rend_data->onion_address))) {
rend_cmp_service_ids(rend_data_get_address(edge_conn->rend_data),
rend_data_get_address(origin_circ->rend_data)))) {
/* this circ is not for this conn */
return 0;
}
@ -1989,7 +1990,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if (!extend_info) {
log_info(LD_REND,
"No intro points for '%s': re-fetching service descriptor.",
safe_str_client(rend_data->onion_address));
safe_str_client(rend_data_get_address(rend_data)));
rend_client_refetch_v2_renddesc(rend_data);
connection_ap_mark_as_non_pending_circuit(conn);
ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_RENDDESC_WAIT;
@ -1997,7 +1998,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
}
log_info(LD_REND,"Chose %s as intro point for '%s'.",
extend_info_describe(extend_info),
safe_str_client(rend_data->onion_address));
safe_str_client(rend_data_get_address(rend_data)));
}
/* If we have specified a particular exit node for our

View File

@ -38,6 +38,7 @@
#include "ext_orport.h"
#include "geoip.h"
#include "main.h"
#include "hs_common.h"
#include "nodelist.h"
#include "policies.h"
#include "reasons.h"
@ -4082,12 +4083,12 @@ connection_get_by_type_state_rendquery(int type, int state,
(type == CONN_TYPE_DIR &&
TO_DIR_CONN(conn)->rend_data &&
!rend_cmp_service_ids(rendquery,
TO_DIR_CONN(conn)->rend_data->onion_address))
rend_data_get_address(TO_DIR_CONN(conn)->rend_data)))
||
(CONN_IS_EDGE(conn) &&
TO_EDGE_CONN(conn)->rend_data &&
!rend_cmp_service_ids(rendquery,
TO_EDGE_CONN(conn)->rend_data->onion_address))
rend_data_get_address(TO_EDGE_CONN(conn)->rend_data)))
));
}

View File

@ -29,6 +29,7 @@
#include "dnsserv.h"
#include "dirserv.h"
#include "hibernate.h"
#include "hs_common.h"
#include "main.h"
#include "nodelist.h"
#include "policies.h"
@ -1707,21 +1708,22 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
if (rend_data == NULL) {
return -1;
}
const char *onion_address = rend_data_get_address(rend_data);
log_info(LD_REND,"Got a hidden service request for ID '%s'",
safe_str_client(rend_data->onion_address));
safe_str_client(onion_address));
/* Lookup the given onion address. If invalid, stop right now else we
* might have it in the cache or not, it will be tested later on. */
unsigned int refetch_desc = 0;
rend_cache_entry_t *entry = NULL;
const int rend_cache_lookup_result =
rend_cache_lookup_entry(rend_data->onion_address, -1, &entry);
rend_cache_lookup_entry(onion_address, -1, &entry);
if (rend_cache_lookup_result < 0) {
switch (-rend_cache_lookup_result) {
case EINVAL:
/* We should already have rejected this address! */
log_warn(LD_BUG,"Invalid service name '%s'",
safe_str_client(rend_data->onion_address));
safe_str_client(onion_address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
case ENOENT:
@ -1745,7 +1747,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
connection_ap_mark_as_non_pending_circuit(conn);
base_conn->state = AP_CONN_STATE_RENDDESC_WAIT;
log_info(LD_REND, "Unknown descriptor %s. Fetching.",
safe_str_client(rend_data->onion_address));
safe_str_client(onion_address));
rend_client_refetch_v2_renddesc(rend_data);
return 0;
}

View File

@ -33,6 +33,7 @@
#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
#include "hs_common.h"
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
@ -2515,7 +2516,7 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
if (circ->rend_data != NULL) {
smartlist_add_asprintf(descparts, "REND_QUERY=%s",
circ->rend_data->onion_address);
rend_data_get_address(circ->rend_data));
}
{
@ -6810,8 +6811,10 @@ control_event_hs_descriptor_requested(const rend_data_t *rend_query,
send_control_event(EVENT_HS_DESC,
"650 HS_DESC REQUESTED %s %s %s %s\r\n",
rend_hsaddress_str_or_unknown(rend_query->onion_address),
rend_auth_type_to_string(rend_query->auth_type),
rend_hsaddress_str_or_unknown(
rend_data_get_address(rend_query)),
rend_auth_type_to_string(
TO_REND_DATA_V2(rend_query)->auth_type),
node_describe_longname_by_id(id_digest),
desc_id_base32);
}
@ -6827,11 +6830,12 @@ get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp)
{
int replica;
const char *desc_id = NULL;
const rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data);
/* Possible if the fetch was done using a descriptor ID. This means that
* the HSFETCH command was used. */
if (!tor_digest_is_zero(rend_data->desc_id_fetch)) {
desc_id = rend_data->desc_id_fetch;
if (!tor_digest_is_zero(rend_data_v2->desc_id_fetch)) {
desc_id = rend_data_v2->desc_id_fetch;
goto end;
}
@ -6839,7 +6843,7 @@ get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp)
* is the one associated with the HSDir fingerprint. */
for (replica = 0; replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
replica++) {
const char *digest = rend_data->descriptor_id[replica];
const char *digest = rend_data_get_desc_id(rend_data, replica, NULL);
SMARTLIST_FOREACH_BEGIN(rend_data->hsdirs_fp, char *, fingerprint) {
if (tor_memcmp(fingerprint, hsdir_fp, DIGEST_LEN) == 0) {
@ -6948,7 +6952,8 @@ control_event_hs_descriptor_receive_end(const char *action,
"650 HS_DESC %s %s %s %s%s%s\r\n",
action,
rend_hsaddress_str_or_unknown(onion_address),
rend_auth_type_to_string(rend_data->auth_type),
rend_auth_type_to_string(
TO_REND_DATA_V2(rend_data)->auth_type),
node_describe_longname_by_id(id_digest),
desc_id_field ? desc_id_field : "",
reason_field ? reason_field : "");
@ -7045,7 +7050,7 @@ control_event_hs_descriptor_failed(const rend_data_t *rend_data,
return;
}
control_event_hs_descriptor_receive_end("FAILED",
rend_data->onion_address,
rend_data_get_address(rend_data),
rend_data, id_digest, reason);
}

View File

@ -16,6 +16,7 @@
#include "dirvote.h"
#include "entrynodes.h"
#include "geoip.h"
#include "hs_common.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@ -2346,7 +2347,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
conn->identity_digest, \
reason) )
#define SEND_HS_DESC_FAILED_CONTENT() ( \
control_event_hs_descriptor_content(conn->rend_data->onion_address, \
control_event_hs_descriptor_content(rend_data_get_address(conn->rend_data), \
conn->requested_resource, \
conn->identity_digest, \
NULL) )
@ -2422,7 +2423,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
#define SEND_HS_DESC_UPLOAD_FAILED_EVENT(reason) ( \
control_event_hs_descriptor_upload_failed( \
conn->identity_digest, \
conn->rend_data->onion_address, \
rend_data_get_address(conn->rend_data), \
reason) )
log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
"(%s))",
@ -2436,7 +2437,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"Uploading rendezvous descriptor: finished with status "
"200 (%s)", escaped(reason));
control_event_hs_descriptor_uploaded(conn->identity_digest,
conn->rend_data->onion_address);
rend_data_get_address(conn->rend_data));
rend_service_desc_has_uploaded(conn->rend_data);
break;
case 400:
@ -2547,7 +2548,8 @@ connection_dir_about_to_close(dir_connection_t *dir_conn)
* refetching is unnecessary.) */
if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 &&
dir_conn->rend_data &&
strlen(dir_conn->rend_data->onion_address) == REND_SERVICE_ID_LEN_BASE32)
strlen(rend_data_get_address(dir_conn->rend_data)) ==
REND_SERVICE_ID_LEN_BASE32)
rend_client_refetch_v2_renddesc(dir_conn->rend_data);
}

264
src/or/hs_common.c Normal file
View File

@ -0,0 +1,264 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file hs_common.c
* \brief Contains code shared between different HS protocol version as well
* as useful data structures and accessors used by other subsystems.
* The rendcommon.c should only contains code relating to the v2
* protocol.
**/
#include "or.h"
#include "hs_common.h"
#include "rendcommon.h"
/* Create a new rend_data_t for a specific given <b>version</b>.
* Return a pointer to the newly allocated data structure. */
static rend_data_t *
rend_data_alloc(uint32_t version)
{
rend_data_t *rend_data = NULL;
switch (version) {
case HS_VERSION_TWO:
{
rend_data_v2_t *v2 = tor_malloc_zero(sizeof(*v2));
v2->base_.version = HS_VERSION_TWO;
v2->base_.hsdirs_fp = smartlist_new();
rend_data = &v2->base_;
break;
}
default:
tor_assert(0);
break;
}
return rend_data;
}
/** Free all storage associated with <b>data</b> */
void
rend_data_free(rend_data_t *data)
{
if (!data) {
return;
}
/* By using our allocation function, this should always be set. */
tor_assert(data->hsdirs_fp);
/* Cleanup the HSDir identity digest. */
SMARTLIST_FOREACH(data->hsdirs_fp, char *, d, tor_free(d));
smartlist_free(data->hsdirs_fp);
/* Depending on the version, cleanup. */
switch (data->version) {
case HS_VERSION_TWO:
{
rend_data_v2_t *v2_data = TO_REND_DATA_V2(data);
tor_free(v2_data);
break;
}
default:
tor_assert(0);
}
}
/* Allocate and return a deep copy of <b>data</b>. */
rend_data_t *
rend_data_dup(const rend_data_t *data)
{
rend_data_t *data_dup = NULL;
smartlist_t *hsdirs_fp = smartlist_new();
tor_assert(data);
tor_assert(data->hsdirs_fp);
SMARTLIST_FOREACH(data->hsdirs_fp, char *, fp,
smartlist_add(hsdirs_fp, tor_memdup(fp, DIGEST_LEN)));
switch (data->version) {
case HS_VERSION_TWO:
{
rend_data_v2_t *v2_data = tor_memdup(TO_REND_DATA_V2(data),
sizeof(*v2_data));
data_dup = &v2_data->base_;
data_dup->hsdirs_fp = hsdirs_fp;
break;
}
default:
tor_assert(0);
break;
}
return data_dup;
}
/* Compute the descriptor ID for each HS descriptor replica and save them. A
* valid onion address must be present in the <b>rend_data</b>.
*
* Return 0 on success else -1. */
static int
compute_desc_id(rend_data_t *rend_data)
{
int ret = 0;
unsigned replica;
time_t now = time(NULL);
tor_assert(rend_data);
switch (rend_data->version) {
case HS_VERSION_TWO:
{
rend_data_v2_t *v2_data = TO_REND_DATA_V2(rend_data);
/* Compute descriptor ID for each replicas. */
for (replica = 0; replica < ARRAY_LENGTH(v2_data->descriptor_id);
replica++) {
ret = rend_compute_v2_desc_id(v2_data->descriptor_id[replica],
v2_data->onion_address,
v2_data->descriptor_cookie,
now, replica);
if (ret < 0) {
goto end;
}
}
break;
}
default:
tor_assert(0);
}
end:
return ret;
}
/* Allocate and initialize a rend_data_t object for a service using the
* provided arguments. All arguments are optional (can be NULL), except from
* <b>onion_address</b> which MUST be set.
*
* Return a valid rend_data_t pointer. This only returns a version 2 object of
* rend_data_t. */
rend_data_t *
rend_data_service_create(const char *onion_address, const char *pk_digest,
const uint8_t *cookie, rend_auth_type_t auth_type)
{
/* Create a rend_data_t object for version 2. */
rend_data_t *rend_data = rend_data_alloc(HS_VERSION_TWO);
rend_data_v2_t *v2= TO_REND_DATA_V2(rend_data);
/* We need at least one else the call is wrong. */
tor_assert(onion_address != NULL);
if (pk_digest) {
memcpy(v2->rend_pk_digest, pk_digest, sizeof(v2->rend_pk_digest));
}
if (cookie) {
memcpy(rend_data->rend_cookie, cookie, sizeof(rend_data->rend_cookie));
}
strlcpy(v2->onion_address, onion_address, sizeof(v2->onion_address));
v2->auth_type = auth_type;
return rend_data;
}
/* Allocate and initialize a rend_data_t object for a client request using
* the given arguments. Either an onion address or a descriptor ID is
* needed. Both can be given but only the onion address will be used to make
* the descriptor fetch.
*
* Return a valid rend_data_t pointer or NULL on error meaning the
* descriptor IDs couldn't be computed from the given data. */
rend_data_t *
rend_data_client_create(const char *onion_address, const char *desc_id,
const char *cookie, rend_auth_type_t auth_type)
{
/* Create a rend_data_t object for version 2. */
rend_data_t *rend_data = rend_data_alloc(HS_VERSION_TWO);
rend_data_v2_t *v2= TO_REND_DATA_V2(rend_data);
/* We need at least one else the call is wrong. */
tor_assert(onion_address != NULL || desc_id != NULL);
if (cookie) {
memcpy(v2->descriptor_cookie, cookie, sizeof(v2->descriptor_cookie));
}
if (desc_id) {
memcpy(v2->desc_id_fetch, desc_id, sizeof(v2->desc_id_fetch));
}
if (onion_address) {
strlcpy(v2->onion_address, onion_address, sizeof(v2->onion_address));
if (compute_desc_id(rend_data) < 0) {
goto error;
}
}
v2->auth_type = auth_type;
return rend_data;
error:
rend_data_free(rend_data);
return NULL;
}
/* Return the onion address from the rend data. Depending on the version,
* the size of the address can vary but it's always NUL terminated. */
const char *
rend_data_get_address(const rend_data_t *rend_data)
{
tor_assert(rend_data);
switch (rend_data->version) {
case HS_VERSION_TWO:
return TO_REND_DATA_V2(rend_data)->onion_address;
default:
/* We should always have a supported version. */
tor_assert(0);
}
}
/* Return the descriptor ID for a specific replica number from the rend
* data. The returned data is a binary digest and depending on the version its
* size can vary. The size of the descriptor ID is put in <b>len_out</b> if
* non NULL. */
const char *
rend_data_get_desc_id(const rend_data_t *rend_data, uint8_t replica,
size_t *len_out)
{
tor_assert(rend_data);
switch (rend_data->version) {
case HS_VERSION_TWO:
tor_assert(replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS);
if (len_out) {
*len_out = DIGEST_LEN;
}
return TO_REND_DATA_V2(rend_data)->descriptor_id[replica];
default:
/* We should always have a supported version. */
tor_assert(0);
}
}
/* Return the public key digest using the given <b>rend_data</b>. The size of
* the digest is put in <b>len_out</b> (if set) which can differ depending on
* the version. */
const uint8_t *
rend_data_get_pk_digest(const rend_data_t *rend_data, size_t *len_out)
{
tor_assert(rend_data);
switch (rend_data->version) {
case HS_VERSION_TWO:
{
const rend_data_v2_t *v2_data = TO_REND_DATA_V2(rend_data);
if (len_out) {
*len_out = sizeof(v2_data->rend_pk_digest);
}
return (const uint8_t *) v2_data->rend_pk_digest;
}
default:
/* We should always have a supported version. */
tor_assert(0);
}
}

34
src/or/hs_common.h Normal file
View File

@ -0,0 +1,34 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file hs_common.h
* \brief Header file for hs_common.c.
**/
#ifndef TOR_HS_COMMON_H
#define TOR_HS_COMMON_H
#include "or.h"
/* Protocol version 2. Use this instead of hardcoding "2" in the code base,
* this adds a clearer semantic to the value when used. */
#define HS_VERSION_TWO 2
void rend_data_free(rend_data_t *data);
rend_data_t *rend_data_dup(const rend_data_t *data);
rend_data_t *rend_data_client_create(const char *onion_address,
const char *desc_id,
const char *cookie,
rend_auth_type_t auth_type);
rend_data_t *rend_data_service_create(const char *onion_address,
const char *pk_digest,
const uint8_t *cookie,
rend_auth_type_t auth_type);
const char *rend_data_get_address(const rend_data_t *rend_data);
const char *rend_data_get_desc_id(const rend_data_t *rend_data,
uint8_t replica, size_t *len_out);
const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data,
size_t *len_out);
#endif /* TOR_HS_COMMON_H */

View File

@ -48,6 +48,7 @@ LIBTOR_A_SOURCES = \
src/or/entrynodes.c \
src/or/ext_orport.c \
src/or/hibernate.c \
src/or/hs_common.c \
src/or/keypin.c \
src/or/main.c \
src/or/microdesc.c \
@ -156,6 +157,7 @@ ORHEADERS = \
src/or/geoip.h \
src/or/entrynodes.h \
src/or/hibernate.h \
src/or/hs_common.h \
src/or/keypin.h \
src/or/main.h \
src/or/microdesc.h \

View File

@ -114,6 +114,9 @@
#define NON_ANONYMOUS_MODE_ENABLED 1
#endif
/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */
#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_))
/** Length of longest allowable configured nickname. */
#define MAX_NICKNAME_LEN 19
/** Length of a router identity encoded as a hexadecimal digest, plus
@ -779,6 +782,24 @@ typedef struct rend_service_authorization_t {
* establishment. Not all fields contain data depending on where this struct
* is used. */
typedef struct rend_data_t {
/* Hidden service protocol version of this base object. */
uint32_t version;
/** List of HSDir fingerprints on which this request has been sent to. This
* contains binary identity digest of the directory of size DIGEST_LEN. */
smartlist_t *hsdirs_fp;
/** Rendezvous cookie used by both, client and service. */
char rend_cookie[REND_COOKIE_LEN];
/** Number of streams associated with this rendezvous circuit. */
int nr_streams;
} rend_data_t;
typedef struct rend_data_v2_t {
/* Rendezvous base data. */
rend_data_t base_;
/** Onion address (without the .onion part) that a client requests. */
char onion_address[REND_SERVICE_ID_LEN_BASE32+1];
@ -800,17 +821,16 @@ typedef struct rend_data_t {
/** Hash of the hidden service's PK used by a service. */
char rend_pk_digest[DIGEST_LEN];
} rend_data_v2_t;
/** Rendezvous cookie used by both, client and service. */
char rend_cookie[REND_COOKIE_LEN];
/** List of HSDir fingerprints on which this request has been sent to.
* This contains binary identity digest of the directory. */
smartlist_t *hsdirs_fp;
/** Number of streams associated with this rendezvous circuit. */
int nr_streams;
} rend_data_t;
/* From a base rend_data_t object <b>d</d>, return the v2 object. */
static inline
rend_data_v2_t *TO_REND_DATA_V2(const rend_data_t *d)
{
tor_assert(d);
tor_assert(d->version == 2);
return DOWNCAST(rend_data_v2_t, d);
}
/** Time interval for tracking replays of DH public keys received in
* INTRODUCE2 cells. Used only to avoid launching multiple
@ -1759,8 +1779,6 @@ typedef struct control_connection_t {
/** Cast a connection_t subtype pointer to a connection_t **/
#define TO_CONN(c) (&(((c)->base_)))
/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */
#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_))
/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/
#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_))

View File

@ -849,6 +849,8 @@ rend_cache_store_v2_desc_as_client(const char *desc,
char want_desc_id[DIGEST_LEN];
rend_cache_entry_t *e;
int retval = -1;
rend_data_v2_t *rend_data = TO_REND_DATA_V2(rend_query);
tor_assert(rend_cache);
tor_assert(desc);
tor_assert(desc_id_base32);
@ -874,11 +876,11 @@ rend_cache_store_v2_desc_as_client(const char *desc,
log_warn(LD_REND, "Couldn't compute service ID.");
goto err;
}
if (rend_query->onion_address[0] != '\0' &&
strcmp(rend_query->onion_address, service_id)) {
if (rend_data->onion_address[0] != '\0' &&
strcmp(rend_data->onion_address, service_id)) {
log_warn(LD_REND, "Received service descriptor for service ID %s; "
"expected descriptor for service ID %s.",
service_id, safe_str(rend_query->onion_address));
service_id, safe_str(rend_data->onion_address));
goto err;
}
if (tor_memneq(desc_id, want_desc_id, DIGEST_LEN)) {
@ -890,14 +892,14 @@ rend_cache_store_v2_desc_as_client(const char *desc,
/* Decode/decrypt introduction points. */
if (intro_content && intro_size > 0) {
int n_intro_points;
if (rend_query->auth_type != REND_NO_AUTH &&
!tor_mem_is_zero(rend_query->descriptor_cookie,
sizeof(rend_query->descriptor_cookie))) {
if (rend_data->auth_type != REND_NO_AUTH &&
!tor_mem_is_zero(rend_data->descriptor_cookie,
sizeof(rend_data->descriptor_cookie))) {
char *ipos_decrypted = NULL;
size_t ipos_decrypted_size;
if (rend_decrypt_introduction_points(&ipos_decrypted,
&ipos_decrypted_size,
rend_query->descriptor_cookie,
rend_data->descriptor_cookie,
intro_content,
intro_size) < 0) {
log_warn(LD_REND, "Failed to decrypt introduction points. We are "

View File

@ -16,6 +16,7 @@
#include "connection.h"
#include "connection_edge.h"
#include "directory.h"
#include "hs_common.h"
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
@ -104,7 +105,7 @@ rend_client_reextend_intro_circuit(origin_circuit_t *circ)
if (!extend_info) {
log_warn(LD_REND,
"No usable introduction points left for %s. Closing.",
safe_str_client(circ->rend_data->onion_address));
safe_str_client(rend_data_get_address(circ->rend_data)));
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return -1;
}
@ -143,20 +144,21 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
off_t dh_offset;
crypto_pk_t *intro_key = NULL;
int status = 0;
const char *onion_address;
tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY);
tor_assert(introcirc->rend_data);
tor_assert(rendcirc->rend_data);
tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address,
rendcirc->rend_data->onion_address));
tor_assert(!rend_cmp_service_ids(rend_data_get_address(introcirc->rend_data),
rend_data_get_address(rendcirc->rend_data)));
#ifndef NON_ANONYMOUS_MODE_ENABLED
tor_assert(!(introcirc->build_state->onehop_tunnel));
tor_assert(!(rendcirc->build_state->onehop_tunnel));
#endif
onion_address = rend_data_get_address(introcirc->rend_data);
r = rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
&entry);
r = rend_cache_lookup_entry(onion_address, -1, &entry);
/* An invalid onion address is not possible else we have a big issue. */
tor_assert(r != -EINVAL);
if (r < 0 || !rend_client_any_intro_points_usable(entry)) {
@ -165,14 +167,13 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
log_info(LD_REND,
"query %s didn't have valid rend desc in cache. "
"Refetching descriptor.",
safe_str_client(introcirc->rend_data->onion_address));
safe_str_client(onion_address));
rend_client_refetch_v2_renddesc(introcirc->rend_data);
{
connection_t *conn;
while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
AP_CONN_STATE_CIRCUIT_WAIT,
introcirc->rend_data->onion_address))) {
AP_CONN_STATE_CIRCUIT_WAIT, onion_address))) {
connection_ap_mark_as_non_pending_circuit(TO_ENTRY_CONN(conn));
conn->state = AP_CONN_STATE_RENDDESC_WAIT;
}
@ -196,7 +197,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
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...",
safe_str_client(introcirc->rend_data->onion_address),
safe_str_client(onion_address),
safe_str_client(extend_info_describe(
introcirc->build_state->chosen_exit)),
smartlist_len(entry->parsed->intro_nodes));
@ -236,11 +237,12 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
/* 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 */
tmp[1] = (uint8_t)introcirc->rend_data->auth_type; /* auth type, if any */
/* auth type, if any */
tmp[1] = (uint8_t) TO_REND_DATA_V2(introcirc->rend_data)->auth_type;
v3_shift = 1;
if (introcirc->rend_data->auth_type != REND_NO_AUTH) {
if (tmp[1] != REND_NO_AUTH) {
set_uint16(tmp+2, htons(REND_DESC_COOKIE_LEN));
memcpy(tmp+4, introcirc->rend_data->descriptor_cookie,
memcpy(tmp+4, TO_REND_DATA_V2(introcirc->rend_data)->descriptor_cookie,
REND_DESC_COOKIE_LEN);
v3_shift += 2+REND_DESC_COOKIE_LEN;
}
@ -360,7 +362,7 @@ rend_client_rendcirc_has_opened(origin_circuit_t *circ)
* Called to close other intro circuits we launched in parallel.
*/
static void
rend_client_close_other_intros(const char *onion_address)
rend_client_close_other_intros(const uint8_t *rend_pk_digest)
{
/* abort parallel intro circs, if any */
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) {
@ -369,8 +371,7 @@ rend_client_close_other_intros(const char *onion_address)
!c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) {
origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(c);
if (oc->rend_data &&
!rend_cmp_service_ids(onion_address,
oc->rend_data->onion_address)) {
rend_circuit_pk_digest_eq(oc, rend_pk_digest)) {
log_info(LD_REND|LD_CIRC, "Closing introduction circuit %d that we "
"built in parallel (Purpose %d).", oc->global_identifier,
c->purpose);
@ -434,7 +435,8 @@ rend_client_introduction_acked(origin_circuit_t *circ,
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
/* close any other intros launched in parallel */
rend_client_close_other_intros(circ->rend_data->onion_address);
rend_client_close_other_intros(rend_data_get_pk_digest(circ->rend_data,
NULL));
} else {
/* It's a NAK; the introduction point didn't relay our request. */
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING);
@ -443,7 +445,7 @@ rend_client_introduction_acked(origin_circuit_t *circ,
* If none remain, refetch the service descriptor.
*/
log_info(LD_REND, "Got nack for %s from %s...",
safe_str_client(circ->rend_data->onion_address),
safe_str_client(rend_data_get_address(circ->rend_data)),
safe_str_client(extend_info_describe(circ->build_state->chosen_exit)));
if (rend_client_report_intro_point_failure(circ->build_state->chosen_exit,
circ->rend_data,
@ -697,13 +699,15 @@ pick_hsdir(const char *desc_id, const char *desc_id_base32)
* in the case that no hidden service directory is left to ask for the
* descriptor, return 0, and in case of a failure -1. */
static int
directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query,
directory_get_from_hs_dir(const char *desc_id,
const rend_data_t *rend_query,
routerstatus_t *rs_hsdir)
{
routerstatus_t *hs_dir = rs_hsdir;
char *hsdir_fp;
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
const rend_data_v2_t *rend_data;
#ifdef ENABLE_TOR2WEB_MODE
const int tor2web_mode = get_options()->Tor2webMode;
const int how_to_fetch = tor2web_mode ? DIRIND_ONEHOP : DIRIND_ANONYMOUS;
@ -712,6 +716,8 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query,
#endif
tor_assert(desc_id);
tor_assert(rend_query);
rend_data = TO_REND_DATA_V2(rend_query);
base32_encode(desc_id_base32, sizeof(desc_id_base32),
desc_id, DIGEST_LEN);
@ -734,10 +740,11 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query,
/* Encode descriptor cookie for logging purposes. Also, if the cookie is
* malformed, no fetch is triggered thus this needs to be done before the
* fetch request. */
if (rend_query->auth_type != REND_NO_AUTH) {
if (rend_data->auth_type != REND_NO_AUTH) {
if (base64_encode(descriptor_cookie_base64,
sizeof(descriptor_cookie_base64),
rend_query->descriptor_cookie, REND_DESC_COOKIE_LEN,
rend_data->descriptor_cookie,
REND_DESC_COOKIE_LEN,
0)<0) {
log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
return 0;
@ -763,9 +770,9 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query,
"service '%s' with descriptor ID '%s', auth type %d, "
"and descriptor cookie '%s' to hidden service "
"directory %s",
rend_query->onion_address, desc_id_base32,
rend_query->auth_type,
(rend_query->auth_type == REND_NO_AUTH ? "[none]" :
rend_data->onion_address, desc_id_base32,
rend_data->auth_type,
(rend_data->auth_type == REND_NO_AUTH ? "[none]" :
escaped_safe_str_client(descriptor_cookie_base64)),
routerstatus_describe(hs_dir));
control_event_hs_descriptor_requested(rend_query,
@ -780,8 +787,8 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query,
* On success, 1 is returned. If no hidden service is left to ask, return 0.
* On error, -1 is returned. */
static int
fetch_v2_desc_by_descid(const char *desc_id, const rend_data_t *rend_query,
smartlist_t *hsdirs)
fetch_v2_desc_by_descid(const char *desc_id,
const rend_data_t *rend_query, smartlist_t *hsdirs)
{
int ret;
@ -814,13 +821,12 @@ fetch_v2_desc_by_descid(const char *desc_id, const rend_data_t *rend_query,
* On success, 1 is returned. If no hidden service is left to ask, return 0.
* On error, -1 is returned. */
static int
fetch_v2_desc_by_addr(rend_data_t *query, smartlist_t *hsdirs)
fetch_v2_desc_by_addr(rend_data_t *rend_query, smartlist_t *hsdirs)
{
char descriptor_id[DIGEST_LEN];
int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
int i, tries_left, ret;
tor_assert(query);
rend_data_v2_t *rend_data = TO_REND_DATA_V2(rend_query);
/* Randomly iterate over the replicas until a descriptor can be fetched
* from one of the consecutive nodes, or no options are left. */
@ -834,9 +840,10 @@ fetch_v2_desc_by_addr(rend_data_t *query, smartlist_t *hsdirs)
int chosen_replica = replicas_left_to_try[rand_val];
replicas_left_to_try[rand_val] = replicas_left_to_try[--tries_left];
ret = rend_compute_v2_desc_id(descriptor_id, query->onion_address,
query->auth_type == REND_STEALTH_AUTH ?
query->descriptor_cookie : NULL,
ret = rend_compute_v2_desc_id(descriptor_id,
rend_data->onion_address,
rend_data->auth_type == REND_STEALTH_AUTH ?
rend_data->descriptor_cookie : NULL,
time(NULL), chosen_replica);
if (ret < 0) {
/* Normally, on failure the descriptor_id is untouched but let's be
@ -844,18 +851,18 @@ fetch_v2_desc_by_addr(rend_data_t *query, smartlist_t *hsdirs)
goto end;
}
if (tor_memcmp(descriptor_id, query->descriptor_id[chosen_replica],
if (tor_memcmp(descriptor_id, rend_data->descriptor_id[chosen_replica],
sizeof(descriptor_id)) != 0) {
/* Not equal from what we currently have so purge the last hid serv
* request cache and update the descriptor ID with the new value. */
purge_hid_serv_from_last_hid_serv_requests(
query->descriptor_id[chosen_replica]);
memcpy(query->descriptor_id[chosen_replica], descriptor_id,
sizeof(query->descriptor_id[chosen_replica]));
rend_data->descriptor_id[chosen_replica]);
memcpy(rend_data->descriptor_id[chosen_replica], descriptor_id,
sizeof(rend_data->descriptor_id[chosen_replica]));
}
/* Trigger the fetch with the computed descriptor ID. */
ret = fetch_v2_desc_by_descid(descriptor_id, query, hsdirs);
ret = fetch_v2_desc_by_descid(descriptor_id, rend_query, hsdirs);
if (ret != 0) {
/* Either on success or failure, as long as we tried a fetch we are
* done here. */
@ -883,16 +890,23 @@ int
rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs)
{
int ret;
rend_data_v2_t *rend_data;
const char *onion_address;
tor_assert(query);
/* Get the version 2 data structure of the query. */
rend_data = TO_REND_DATA_V2(query);
onion_address = rend_data_get_address(query);
/* Depending on what's available in the rend data query object, we will
* trigger a fetch by HS address or using a descriptor ID. */
if (query->onion_address[0] != '\0') {
if (onion_address[0] != '\0') {
ret = fetch_v2_desc_by_addr(query, hsdirs);
} else if (!tor_digest_is_zero(query->desc_id_fetch)) {
ret = fetch_v2_desc_by_descid(query->desc_id_fetch, query, hsdirs);
} else if (!tor_digest_is_zero(rend_data->desc_id_fetch)) {
ret = fetch_v2_desc_by_descid(rend_data->desc_id_fetch, query,
hsdirs);
} else {
/* Query data is invalid. */
ret = -1;
@ -910,10 +924,11 @@ void
rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
{
rend_cache_entry_t *e = NULL;
const char *onion_address = rend_data_get_address(rend_query);
tor_assert(rend_query);
/* Before fetching, check if we already have a usable descriptor here. */
if (rend_cache_lookup_entry(rend_query->onion_address, -1, &e) == 0 &&
if (rend_cache_lookup_entry(onion_address, -1, &e) == 0 &&
rend_client_any_intro_points_usable(e)) {
log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we "
"already have a usable descriptor here. Not fetching.");
@ -926,7 +941,7 @@ rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
return;
}
log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s",
safe_str_client(rend_query->onion_address));
safe_str_client(onion_address));
rend_client_fetch_v2_desc(rend_query, NULL);
/* We don't need to look the error code because either on failure or
@ -962,7 +977,7 @@ rend_client_cancel_descriptor_fetches(void)
} else {
log_debug(LD_REND, "Marking for close dir conn fetching "
"rendezvous descriptor for service %s",
safe_str(rd->onion_address));
safe_str(rend_data_get_address(rd)));
}
connection_mark_for_close(conn);
}
@ -992,25 +1007,26 @@ rend_client_cancel_descriptor_fetches(void)
*/
int
rend_client_report_intro_point_failure(extend_info_t *failed_intro,
rend_data_t *rend_query,
rend_data_t *rend_data,
unsigned int failure_type)
{
int i, r;
rend_cache_entry_t *ent;
connection_t *conn;
const char *onion_address = rend_data_get_address(rend_data);
r = rend_cache_lookup_entry(rend_query->onion_address, -1, &ent);
r = rend_cache_lookup_entry(onion_address, -1, &ent);
if (r < 0) {
/* Either invalid onion address or cache entry not found. */
switch (-r) {
case EINVAL:
log_warn(LD_BUG, "Malformed service ID %s.",
escaped_safe_str_client(rend_query->onion_address));
escaped_safe_str_client(onion_address));
return -1;
case ENOENT:
log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
escaped_safe_str_client(rend_query->onion_address));
rend_client_refetch_v2_renddesc(rend_query);
escaped_safe_str_client(onion_address));
rend_client_refetch_v2_renddesc(rend_data);
return 0;
default:
log_warn(LD_BUG, "Unknown cache lookup returned code: %d", r);
@ -1034,7 +1050,7 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro,
case INTRO_POINT_FAILURE_GENERIC:
rend_cache_intro_failure_note(failure_type,
(uint8_t *)failed_intro->identity_digest,
rend_query->onion_address);
onion_address);
rend_intro_point_free(intro);
smartlist_del(ent->parsed->intro_nodes, i);
break;
@ -1052,8 +1068,7 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro,
if (zap_intro_point) {
rend_cache_intro_failure_note(
failure_type,
(uint8_t *) failed_intro->identity_digest,
rend_query->onion_address);
(uint8_t *) failed_intro->identity_digest, onion_address);
rend_intro_point_free(intro);
smartlist_del(ent->parsed->intro_nodes, i);
}
@ -1067,14 +1082,14 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro,
if (! rend_client_any_intro_points_usable(ent)) {
log_info(LD_REND,
"No more intro points remain for %s. Re-fetching descriptor.",
escaped_safe_str_client(rend_query->onion_address));
rend_client_refetch_v2_renddesc(rend_query);
escaped_safe_str_client(onion_address));
rend_client_refetch_v2_renddesc(rend_data);
/* move all pending streams back to renddesc_wait */
/* NOTE: We can now do this faster, if we use pending_entry_connections */
while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
AP_CONN_STATE_CIRCUIT_WAIT,
rend_query->onion_address))) {
onion_address))) {
connection_ap_mark_as_non_pending_circuit(TO_ENTRY_CONN(conn));
conn->state = AP_CONN_STATE_RENDDESC_WAIT;
}
@ -1083,7 +1098,7 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro,
}
log_info(LD_REND,"%d options left for %s.",
smartlist_len(ent->parsed->intro_nodes),
escaped_safe_str_client(rend_query->onion_address));
escaped_safe_str_client(onion_address));
return 1;
}
@ -1224,10 +1239,11 @@ rend_client_desc_trynow(const char *query)
rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data;
if (!rend_data)
continue;
if (rend_cmp_service_ids(query, rend_data->onion_address))
const char *onion_address = rend_data_get_address(rend_data);
if (rend_cmp_service_ids(query, onion_address))
continue;
assert_connection_ok(base_conn, now);
if (rend_cache_lookup_entry(rend_data->onion_address, -1,
if (rend_cache_lookup_entry(onion_address, -1,
&entry) == 0 &&
rend_client_any_intro_points_usable(entry)) {
/* either this fetch worked, or it failed but there was a
@ -1262,11 +1278,12 @@ rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
{
unsigned int have_onion = 0;
rend_cache_entry_t *cache_entry = NULL;
const char *onion_address = rend_data_get_address(rend_data);
rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data);
if (*rend_data->onion_address != '\0') {
if (onion_address[0] != '\0') {
/* Ignore return value; we find an entry, or we don't. */
(void) rend_cache_lookup_entry(rend_data->onion_address, -1,
&cache_entry);
(void) rend_cache_lookup_entry(onion_address, -1, &cache_entry);
have_onion = 1;
}
@ -1280,17 +1297,17 @@ rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
/* Remove the HS's entries in last_hid_serv_requests. */
if (have_onion) {
unsigned int replica;
for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
for (replica = 0; replica < ARRAY_LENGTH(rend_data_v2->descriptor_id);
replica++) {
const char *desc_id = rend_data->descriptor_id[replica];
const char *desc_id = rend_data_v2->descriptor_id[replica];
purge_hid_serv_from_last_hid_serv_requests(desc_id);
}
log_info(LD_REND, "Connection attempt for %s has ended; "
"cleaning up temporary state.",
safe_str_client(rend_data->onion_address));
safe_str_client(onion_address));
} else {
/* We only have an ID for a fetch. Probably used by HSFETCH. */
purge_hid_serv_from_last_hid_serv_requests(rend_data->desc_id_fetch);
purge_hid_serv_from_last_hid_serv_requests(rend_data_v2->desc_id_fetch);
}
}
@ -1304,12 +1321,13 @@ rend_client_get_random_intro(const rend_data_t *rend_query)
int ret;
extend_info_t *result;
rend_cache_entry_t *entry;
const char *onion_address = rend_data_get_address(rend_query);
ret = rend_cache_lookup_entry(rend_query->onion_address, -1, &entry);
ret = rend_cache_lookup_entry(onion_address, -1, &entry);
if (ret < 0 || !rend_client_any_intro_points_usable(entry)) {
log_warn(LD_REND,
"Query '%s' didn't have valid rend desc in cache. Failing.",
safe_str_client(rend_query->onion_address));
safe_str_client(onion_address));
/* XXX: Should we refetch the descriptor here if the IPs are not usable
* anymore ?. */
return NULL;

View File

@ -27,7 +27,7 @@ void rend_client_cancel_descriptor_fetches(void);
void rend_client_purge_last_hid_serv_requests(void);
int rend_client_report_intro_point_failure(extend_info_t *failed_intro,
rend_data_t *rend_query,
rend_data_t *rend_data,
unsigned int failure_type);
int rend_client_rendezvous_acked(origin_circuit_t *circ,

View File

@ -12,6 +12,7 @@
#include "circuitbuild.h"
#include "config.h"
#include "control.h"
#include "hs_common.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rendmid.h"
@ -804,124 +805,6 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
command);
}
/** Allocate and return a new rend_data_t with the same
* contents as <b>query</b>. */
rend_data_t *
rend_data_dup(const rend_data_t *data)
{
rend_data_t *data_dup;
tor_assert(data);
data_dup = tor_memdup(data, sizeof(rend_data_t));
data_dup->hsdirs_fp = smartlist_new();
SMARTLIST_FOREACH(data->hsdirs_fp, char *, fp,
smartlist_add(data_dup->hsdirs_fp,
tor_memdup(fp, DIGEST_LEN)));
return data_dup;
}
/** Compute descriptor ID for each replicas and save them. A valid onion
* address must be present in the <b>rend_data</b>.
*
* Return 0 on success else -1. */
static int
compute_desc_id(rend_data_t *rend_data)
{
int ret = 0;
unsigned replica;
time_t now = time(NULL);
tor_assert(rend_data);
/* Compute descriptor ID for each replicas. */
for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
replica++) {
ret = rend_compute_v2_desc_id(rend_data->descriptor_id[replica],
rend_data->onion_address,
rend_data->descriptor_cookie,
now, replica);
if (ret < 0) {
goto end;
}
}
end:
return ret;
}
/** Allocate and initialize a rend_data_t object for a service using the
* given arguments. Only the <b>onion_address</b> is not optional.
*
* Return a valid rend_data_t pointer. */
rend_data_t *
rend_data_service_create(const char *onion_address, const char *pk_digest,
const uint8_t *cookie, rend_auth_type_t auth_type)
{
rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));
/* We need at least one else the call is wrong. */
tor_assert(onion_address != NULL);
if (pk_digest) {
memcpy(rend_data->rend_pk_digest, pk_digest,
sizeof(rend_data->rend_pk_digest));
}
if (cookie) {
memcpy(rend_data->rend_cookie, cookie,
sizeof(rend_data->rend_cookie));
}
strlcpy(rend_data->onion_address, onion_address,
sizeof(rend_data->onion_address));
rend_data->auth_type = auth_type;
/* Won't be used but still need to initialize it for rend_data dup and
* free. */
rend_data->hsdirs_fp = smartlist_new();
return rend_data;
}
/** Allocate and initialize a rend_data_t object for a client request using
* the given arguments. Either an onion address or a descriptor ID is
* needed. Both can be given but only the onion address will be used to make
* the descriptor fetch.
*
* Return a valid rend_data_t pointer or NULL on error meaning the
* descriptor IDs couldn't be computed from the given data. */
rend_data_t *
rend_data_client_create(const char *onion_address, const char *desc_id,
const char *cookie, rend_auth_type_t auth_type)
{
rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));
/* We need at least one else the call is wrong. */
tor_assert(onion_address != NULL || desc_id != NULL);
if (cookie) {
memcpy(rend_data->descriptor_cookie, cookie,
sizeof(rend_data->descriptor_cookie));
}
if (desc_id) {
memcpy(rend_data->desc_id_fetch, desc_id,
sizeof(rend_data->desc_id_fetch));
}
if (onion_address) {
strlcpy(rend_data->onion_address, onion_address,
sizeof(rend_data->onion_address));
if (compute_desc_id(rend_data) < 0) {
goto error;
}
}
rend_data->auth_type = auth_type;
rend_data->hsdirs_fp = smartlist_new();
return rend_data;
error:
rend_data_free(rend_data);
return NULL;
}
/** Determine the routers that are responsible for <b>id</b> (binary) and
* add pointers to those routers' routerstatus_t to <b>responsible_dirs</b>.
* Return -1 if we're returning an empty smartlist, else return 0.
@ -1067,3 +950,31 @@ rend_auth_decode_cookie(const char *cookie_in, uint8_t *cookie_out,
return res;
}
/* Return 1 iff the given <b>digest</b> of a permenanent hidden service key is
* equal to the digest in the origin circuit <b>ocirc</b> of its rend data .
* If the rend data doesn't exist, 0 is returned. This function is agnostic to
* the rend data version. */
int
rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc,
const uint8_t *digest)
{
size_t rend_pk_digest_len;
const uint8_t *rend_pk_digest;
tor_assert(ocirc);
tor_assert(digest);
if (ocirc->rend_data == NULL) {
goto no_match;
}
rend_pk_digest = rend_data_get_pk_digest(ocirc->rend_data,
&rend_pk_digest_len);
if (tor_memeq(rend_pk_digest, digest, rend_pk_digest_len)) {
goto match;
}
no_match:
return 0;
match:
return 1;
}

View File

@ -18,19 +18,6 @@ typedef enum rend_intro_point_failure_t {
INTRO_POINT_FAILURE_UNREACHABLE = 2,
} rend_intro_point_failure_t;
/** Free all storage associated with <b>data</b> */
static inline void
rend_data_free(rend_data_t *data)
{
if (!data) {
return;
}
/* Cleanup the HSDir identity digest. */
SMARTLIST_FOREACH(data->hsdirs_fp, char *, d, tor_free(d));
smartlist_free(data->hsdirs_fp);
tor_free(data);
}
int rend_cmp_service_ids(const char *one, const char *two);
void rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
@ -60,15 +47,8 @@ void rend_get_descriptor_id_bytes(char *descriptor_id_out,
int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
const char *id);
rend_data_t *rend_data_dup(const rend_data_t *data);
rend_data_t *rend_data_client_create(const char *onion_address,
const char *desc_id,
const char *cookie,
rend_auth_type_t auth_type);
rend_data_t *rend_data_service_create(const char *onion_address,
const char *pk_digest,
const uint8_t *cookie,
rend_auth_type_t auth_type);
int rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc,
const uint8_t *digest);
char *rend_auth_encode_cookie(const uint8_t *cookie_in,
rend_auth_type_t auth_type);

View File

@ -17,6 +17,7 @@
#include "config.h"
#include "control.h"
#include "directory.h"
#include "hs_common.h"
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
@ -792,8 +793,7 @@ rend_config_services(const or_options_t *options, int validate_only)
int keep_it = 0;
tor_assert(oc->rend_data);
SMARTLIST_FOREACH(surviving_services, rend_service_t *, ptr, {
if (tor_memeq(ptr->pk_digest, oc->rend_data->rend_pk_digest,
DIGEST_LEN)) {
if (rend_circuit_pk_digest_eq(oc, (uint8_t *) ptr->pk_digest)) {
keep_it = 1;
break;
}
@ -803,7 +803,7 @@ rend_config_services(const or_options_t *options, int validate_only)
log_info(LD_REND, "Closing intro point %s for service %s.",
safe_str_client(extend_info_describe(
oc->build_state->chosen_exit)),
oc->rend_data->onion_address);
rend_data_get_address(oc->rend_data));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
/* XXXX Is there another reason we should use here? */
}
@ -930,12 +930,13 @@ rend_service_del_ephemeral(const char *service_id)
circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) {
origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
tor_assert(oc->rend_data);
if (!tor_memeq(s->pk_digest, oc->rend_data->rend_pk_digest, DIGEST_LEN))
if (!rend_circuit_pk_digest_eq(oc, (uint8_t *) s->pk_digest)) {
continue;
}
log_debug(LD_REND, "Closing intro point %s for service %s.",
safe_str_client(extend_info_describe(
oc->build_state->chosen_exit)),
oc->rend_data->onion_address);
rend_data_get_address(oc->rend_data));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
}
} SMARTLIST_FOREACH_END(circ);
@ -1441,7 +1442,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit,
const or_options_t *options = get_options();
char *err_msg = NULL;
int err_msg_severity = LOG_WARN;
const char *stage_descr = NULL;
const char *stage_descr = NULL, *rend_pk_digest;
int reason = END_CIRC_REASON_TORPROTOCOL;
/* Service/circuit/key stuff we can learn before parsing */
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
@ -1477,14 +1478,15 @@ rend_service_receive_introduction(origin_circuit_t *circuit,
tor_assert(!(circuit->build_state->onehop_tunnel));
#endif
tor_assert(circuit->rend_data);
/* XXX: This is version 2 specific (only one supported). */
rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, NULL);
/* We'll use this in a bazillion log messages */
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
rend_pk_digest, REND_SERVICE_ID_LEN);
/* look up service depending on circuit. */
service =
rend_service_get_by_pk_digest(circuit->rend_data->rend_pk_digest);
service = rend_service_get_by_pk_digest(rend_pk_digest);
if (!service) {
log_warn(LD_BUG,
"Internal error: Got an INTRODUCE2 cell on an intro "
@ -1702,8 +1704,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit,
/* Fill in the circuit's state. */
launched->rend_data =
rend_data_service_create(service->service_id,
circuit->rend_data->rend_pk_digest,
rend_data_service_create(service->service_id, rend_pk_digest,
parsed_req->rc, service->auth_type);
launched->build_state->service_pending_final_cpath_ref =
@ -2679,9 +2680,9 @@ count_intro_point_circuits(const rend_service_t *service)
circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) {
origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
if (oc->rend_data &&
!rend_cmp_service_ids(service->service_id,
oc->rend_data->onion_address))
rend_circuit_pk_digest_eq(oc, (uint8_t *) service->pk_digest)) {
num_ipos++;
}
}
}
SMARTLIST_FOREACH_END(circ);
@ -2701,6 +2702,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
char auth[DIGEST_LEN + 9];
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
int reason = END_CIRC_REASON_TORPROTOCOL;
const char *rend_pk_digest;
tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
#ifndef NON_ANONYMOUS_MODE_ENABLED
@ -2708,12 +2710,13 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
#endif
tor_assert(circuit->cpath);
tor_assert(circuit->rend_data);
/* XXX: This is version 2 specific (only on supported). */
rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, NULL);
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
rend_pk_digest, REND_SERVICE_ID_LEN);
service = rend_service_get_by_pk_digest(
circuit->rend_data->rend_pk_digest);
service = rend_service_get_by_pk_digest(rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %u.",
safe_str_client(serviceid), (unsigned)circuit->base_.n_circ_id);
@ -2754,9 +2757,8 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_C_GENERAL);
{
rend_data_t *rend_data = circuit->rend_data;
rend_data_free(circuit->rend_data);
circuit->rend_data = NULL;
rend_data_free(rend_data);
}
{
crypto_pk_t *intro_key = circuit->intro_key;
@ -2839,15 +2841,17 @@ rend_service_intro_established(origin_circuit_t *circuit,
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
(void) request;
(void) request_len;
tor_assert(circuit->rend_data);
/* XXX: This is version 2 specific (only supported one for now). */
const char *rend_pk_digest =
(char *) rend_data_get_pk_digest(circuit->rend_data, NULL);
if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_warn(LD_PROTOCOL,
"received INTRO_ESTABLISHED cell on non-intro circuit.");
goto err;
}
tor_assert(circuit->rend_data);
service = rend_service_get_by_pk_digest(
circuit->rend_data->rend_pk_digest);
service = rend_service_get_by_pk_digest(rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unknown service on introduction circuit %u.",
(unsigned)circuit->base_.n_circ_id);
@ -2870,7 +2874,7 @@ rend_service_intro_established(origin_circuit_t *circuit,
circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_S_INTRO);
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32 + 1,
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
rend_pk_digest, REND_SERVICE_ID_LEN);
log_info(LD_REND,
"Received INTRO_ESTABLISHED cell on circuit %u for service %s",
(unsigned)circuit->base_.n_circ_id, serviceid);
@ -2897,6 +2901,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
char hexcookie[9];
int reason;
const char *rend_cookie, *rend_pk_digest;
tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
tor_assert(circuit->cpath);
@ -2906,6 +2911,11 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
#endif
tor_assert(circuit->rend_data);
/* XXX: This is version 2 specific (only one supported). */
rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data,
NULL);
rend_cookie = circuit->rend_data->rend_cookie;
/* Declare the circuit dirty to avoid reuse, and for path-bias */
if (!circuit->base_.timestamp_dirty)
circuit->base_.timestamp_dirty = time(NULL);
@ -2915,9 +2925,9 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
hop = circuit->build_state->service_pending_final_cpath_ref->cpath;
base16_encode(hexcookie,9,circuit->rend_data->rend_cookie,4);
base16_encode(hexcookie,9, rend_cookie,4);
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
rend_pk_digest, REND_SERVICE_ID_LEN);
log_info(LD_REND,
"Done building circuit %u to rendezvous with "
@ -2945,8 +2955,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
circuit->build_state->pending_final_cpath = hop;
circuit->build_state->service_pending_final_cpath_ref->cpath = NULL;
service = rend_service_get_by_pk_digest(
circuit->rend_data->rend_pk_digest);
service = rend_service_get_by_pk_digest(rend_pk_digest);
if (!service) {
log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
"rendezvous circuit.");
@ -2955,7 +2964,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
}
/* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
memcpy(buf, circuit->rend_data->rend_cookie, REND_COOKIE_LEN);
memcpy(buf, rend_cookie, REND_COOKIE_LEN);
if (crypto_dh_get_public(hop->rend_dh_handshake_state,
buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
log_warn(LD_GENERAL,"Couldn't get DH public key.");
@ -3019,8 +3028,8 @@ find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest)
origin_circuit_t *circ = NULL;
tor_assert(intro);
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_INTRO))) {
while ((circ = circuit_get_next_by_pk_and_purpose(circ,
(uint8_t *) pk_digest, CIRCUIT_PURPOSE_S_INTRO))) {
if (tor_memeq(circ->build_state->chosen_exit->identity_digest,
intro->extend_info->identity_digest, DIGEST_LEN) &&
circ->rend_data) {
@ -3029,8 +3038,9 @@ find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest)
}
circ = NULL;
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
while ((circ = circuit_get_next_by_pk_and_purpose(circ,
(uint8_t *) pk_digest,
CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
if (tor_memeq(circ->build_state->chosen_exit->identity_digest,
intro->extend_info->identity_digest, DIGEST_LEN) &&
circ->rend_data) {
@ -3069,7 +3079,7 @@ find_intro_point(origin_circuit_t *circ)
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO);
tor_assert(circ->rend_data);
serviceid = circ->rend_data->onion_address;
serviceid = rend_data_get_address(circ->rend_data);
SMARTLIST_FOREACH(rend_service_list, rend_service_t *, s,
if (tor_memeq(s->service_id, serviceid, REND_SERVICE_ID_LEN_BASE32)) {
@ -3454,10 +3464,13 @@ void
rend_service_desc_has_uploaded(const rend_data_t *rend_data)
{
rend_service_t *service;
const char *onion_address;
tor_assert(rend_data);
service = rend_service_get_by_service_id(rend_data->onion_address);
onion_address = rend_data_get_address(rend_data);
service = rend_service_get_by_service_id(onion_address);
if (service == NULL) {
return;
}
@ -3815,14 +3828,16 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
smartlist_t *matching_ports;
rend_service_port_config_t *chosen_port;
unsigned int warn_once = 0;
const char *rend_pk_digest;
tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
tor_assert(circ->rend_data);
log_debug(LD_REND,"beginning to hunt for addr/port");
/* XXX: This is version 2 specific (only one supported). */
rend_pk_digest = (char *) rend_data_get_pk_digest(circ->rend_data, NULL);
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circ->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
service = rend_service_get_by_pk_digest(
circ->rend_data->rend_pk_digest);
rend_pk_digest, REND_SERVICE_ID_LEN);
service = rend_service_get_by_pk_digest(rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
"rendezvous circuit %u; closing.",

View File

@ -10,6 +10,7 @@
#include "test.h"
#include "connection.h"
#include "hs_common.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@ -239,13 +240,9 @@ test_conn_get_rend_setup(const struct testcase_t *tc)
rend_cache_init();
/* TODO: use directory_initiate_command_rend() to do this - maybe? */
conn->rend_data = tor_malloc_zero(sizeof(rend_data_t));
tor_assert(strlen(TEST_CONN_REND_ADDR) == REND_SERVICE_ID_LEN_BASE32);
memcpy(conn->rend_data->onion_address,
TEST_CONN_REND_ADDR,
REND_SERVICE_ID_LEN_BASE32+1);
conn->rend_data->hsdirs_fp = smartlist_new();
conn->rend_data = rend_data_client_create(TEST_CONN_REND_ADDR, NULL, NULL,
REND_NO_AUTH);
assert_connection_ok(&conn->base_, time(NULL));
return conn;
@ -528,7 +525,8 @@ test_conn_get_rend(void *arg)
tt_assert(connection_get_by_type_state_rendquery(
conn->base_.type,
conn->base_.state,
conn->rend_data->onion_address)
rend_data_get_address(
conn->rend_data))
== TO_CONN(conn));
tt_assert(connection_get_by_type_state_rendquery(
TEST_CONN_TYPE,

View File

@ -13,6 +13,7 @@
#include "test.h"
#include "control.h"
#include "config.h"
#include "hs_common.h"
#include "rendcommon.h"
#include "routerset.h"
#include "circuitbuild.h"
@ -134,7 +135,7 @@ test_hs_desc_event(void *arg)
#define STR_DESC_ID_BASE32 "hba3gmcgpfivzfhx5rtfqkfdhv65yrj3"
int ret;
rend_data_t rend_query;
rend_data_v2_t rend_query;
const char *expected_msg;
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
@ -146,12 +147,13 @@ test_hs_desc_event(void *arg)
/* setup rend_query struct */
memset(&rend_query, 0, sizeof(rend_query));
rend_query.base_.version = 2;
strncpy(rend_query.onion_address, STR_HS_ADDR,
REND_SERVICE_ID_LEN_BASE32+1);
rend_query.auth_type = REND_NO_AUTH;
rend_query.hsdirs_fp = smartlist_new();
smartlist_add(rend_query.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID,
DIGEST_LEN));
rend_query.base_.hsdirs_fp = smartlist_new();
smartlist_add(rend_query.base_.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID,
DIGEST_LEN));
/* Compute descriptor ID for replica 0, should be STR_DESC_ID_BASE32. */
ret = rend_compute_v2_desc_id(rend_query.descriptor_id[0],
@ -165,7 +167,7 @@ test_hs_desc_event(void *arg)
sizeof(desc_id_base32));
/* test request event */
control_event_hs_descriptor_requested(&rend_query, HSDIR_EXIST_ID,
control_event_hs_descriptor_requested(&rend_query.base_, HSDIR_EXIST_ID,
STR_DESC_ID_BASE32);
expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\
STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32 "\r\n";
@ -176,7 +178,7 @@ test_hs_desc_event(void *arg)
/* test received event */
rend_query.auth_type = REND_BASIC_AUTH;
control_event_hs_descriptor_received(rend_query.onion_address,
&rend_query, HSDIR_EXIST_ID);
&rend_query.base_, HSDIR_EXIST_ID);
expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\
STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32"\r\n";
tt_assert(received_msg);
@ -185,7 +187,7 @@ test_hs_desc_event(void *arg)
/* test failed event */
rend_query.auth_type = REND_STEALTH_AUTH;
control_event_hs_descriptor_failed(&rend_query,
control_event_hs_descriptor_failed(&rend_query.base_,
HSDIR_NONE_EXIST_ID,
"QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\
@ -196,7 +198,7 @@ test_hs_desc_event(void *arg)
/* test invalid auth type */
rend_query.auth_type = 999;
control_event_hs_descriptor_failed(&rend_query,
control_event_hs_descriptor_failed(&rend_query.base_,
HSDIR_EXIST_ID,
"QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\
@ -219,8 +221,8 @@ test_hs_desc_event(void *arg)
tt_str_op(received_msg, OP_EQ, exp_msg);
tor_free(received_msg);
tor_free(exp_msg);
SMARTLIST_FOREACH(rend_query.hsdirs_fp, char *, d, tor_free(d));
smartlist_free(rend_query.hsdirs_fp);
SMARTLIST_FOREACH(rend_query.base_.hsdirs_fp, char *, d, tor_free(d));
smartlist_free(rend_query.base_.hsdirs_fp);
done:
UNMOCK(queue_control_event_string);
@ -320,42 +322,45 @@ test_hs_rend_data(void *arg)
client = rend_data_client_create(STR_HS_ADDR, desc_id, client_cookie,
REND_NO_AUTH);
tt_assert(client);
tt_int_op(client->auth_type, ==, REND_NO_AUTH);
tt_str_op(client->onion_address, OP_EQ, STR_HS_ADDR);
tt_mem_op(client->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
tt_mem_op(client->descriptor_cookie, OP_EQ, client_cookie,
rend_data_v2_t *client_v2 = TO_REND_DATA_V2(client);
tt_int_op(client_v2->auth_type, ==, REND_NO_AUTH);
tt_str_op(client_v2->onion_address, OP_EQ, STR_HS_ADDR);
tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
tt_mem_op(client_v2->descriptor_cookie, OP_EQ, client_cookie,
sizeof(client_cookie));
tt_assert(client->hsdirs_fp);
tt_int_op(smartlist_len(client->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
int ret = rend_compute_v2_desc_id(desc_id, client->onion_address,
client->descriptor_cookie, now, rep);
int ret = rend_compute_v2_desc_id(desc_id, client_v2->onion_address,
client_v2->descriptor_cookie, now, rep);
/* That shouldn't never fail. */
tt_int_op(ret, ==, 0);
tt_mem_op(client->descriptor_id[rep], OP_EQ, desc_id, sizeof(desc_id));
tt_mem_op(client_v2->descriptor_id[rep], OP_EQ, desc_id,
sizeof(desc_id));
}
/* The rest should be zeroed because this is a client request. */
tt_int_op(tor_digest_is_zero(client->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client->rend_cookie), ==, 1);
/* Test dup(). */
client_dup = rend_data_dup(client);
tt_assert(client_dup);
tt_int_op(client_dup->auth_type, ==, client->auth_type);
tt_str_op(client_dup->onion_address, OP_EQ, client->onion_address);
tt_mem_op(client_dup->desc_id_fetch, OP_EQ, client->desc_id_fetch,
sizeof(client_dup->desc_id_fetch));
tt_mem_op(client_dup->descriptor_cookie, OP_EQ, client->descriptor_cookie,
sizeof(client_dup->descriptor_cookie));
rend_data_v2_t *client_dup_v2 = TO_REND_DATA_V2(client_dup);
tt_int_op(client_dup_v2->auth_type, ==, client_v2->auth_type);
tt_str_op(client_dup_v2->onion_address, OP_EQ, client_v2->onion_address);
tt_mem_op(client_dup_v2->desc_id_fetch, OP_EQ, client_v2->desc_id_fetch,
sizeof(client_dup_v2->desc_id_fetch));
tt_mem_op(client_dup_v2->descriptor_cookie, OP_EQ, client_v2->descriptor_cookie,
sizeof(client_dup_v2->descriptor_cookie));
tt_assert(client_dup->hsdirs_fp);
tt_int_op(smartlist_len(client_dup->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
tt_mem_op(client_dup->descriptor_id[rep], OP_EQ,
client->descriptor_id[rep], DIGEST_LEN);
tt_mem_op(client_dup_v2->descriptor_id[rep], OP_EQ,
client_v2->descriptor_id[rep], DIGEST_LEN);
}
/* The rest should be zeroed because this is a client request. */
tt_int_op(tor_digest_is_zero(client_dup->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client_dup_v2->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client_dup->rend_cookie), ==, 1);
rend_data_free(client);
client = NULL;
@ -371,18 +376,19 @@ test_hs_rend_data(void *arg)
* zeroed out. */
client = rend_data_client_create(NULL, desc_id, NULL, REND_BASIC_AUTH);
tt_assert(client);
tt_int_op(client->auth_type, ==, REND_BASIC_AUTH);
tt_int_op(strlen(client->onion_address), ==, 0);
tt_mem_op(client->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
tt_int_op(tor_mem_is_zero(client->descriptor_cookie,
sizeof(client->descriptor_cookie)), ==, 1);
client_v2 = TO_REND_DATA_V2(client);
tt_int_op(client_v2->auth_type, ==, REND_BASIC_AUTH);
tt_int_op(strlen(client_v2->onion_address), ==, 0);
tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
tt_int_op(tor_mem_is_zero(client_v2->descriptor_cookie,
sizeof(client_v2->descriptor_cookie)), ==, 1);
tt_assert(client->hsdirs_fp);
tt_int_op(smartlist_len(client->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
tt_int_op(tor_digest_is_zero(client->descriptor_id[rep]), ==, 1);
tt_int_op(tor_digest_is_zero(client_v2->descriptor_id[rep]), ==, 1);
}
/* The rest should be zeroed because this is a client request. */
tt_int_op(tor_digest_is_zero(client->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), ==, 1);
tt_int_op(tor_digest_is_zero(client->rend_cookie), ==, 1);
rend_data_free(client);
client = NULL;
@ -396,37 +402,39 @@ test_hs_rend_data(void *arg)
service = rend_data_service_create(STR_HS_ADDR, rend_pk_digest,
rend_cookie, REND_NO_AUTH);
tt_assert(service);
tt_int_op(service->auth_type, ==, REND_NO_AUTH);
tt_str_op(service->onion_address, OP_EQ, STR_HS_ADDR);
tt_mem_op(service->rend_pk_digest, OP_EQ, rend_pk_digest,
rend_data_v2_t *service_v2 = TO_REND_DATA_V2(service);
tt_int_op(service_v2->auth_type, ==, REND_NO_AUTH);
tt_str_op(service_v2->onion_address, OP_EQ, STR_HS_ADDR);
tt_mem_op(service_v2->rend_pk_digest, OP_EQ, rend_pk_digest,
sizeof(rend_pk_digest));
tt_mem_op(service->rend_cookie, OP_EQ, rend_cookie, sizeof(rend_cookie));
tt_assert(service->hsdirs_fp);
tt_int_op(smartlist_len(service->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
tt_int_op(tor_digest_is_zero(service->descriptor_id[rep]), ==, 1);
tt_int_op(tor_digest_is_zero(service_v2->descriptor_id[rep]), ==, 1);
}
/* The rest should be zeroed because this is a service request. */
tt_int_op(tor_digest_is_zero(service->descriptor_cookie), ==, 1);
tt_int_op(tor_digest_is_zero(service->desc_id_fetch), ==, 1);
tt_int_op(tor_digest_is_zero(service_v2->descriptor_cookie), ==, 1);
tt_int_op(tor_digest_is_zero(service_v2->desc_id_fetch), ==, 1);
/* Test dup(). */
service_dup = rend_data_dup(service);
rend_data_v2_t *service_dup_v2 = TO_REND_DATA_V2(service_dup);
tt_assert(service_dup);
tt_int_op(service_dup->auth_type, ==, service->auth_type);
tt_str_op(service_dup->onion_address, OP_EQ, service->onion_address);
tt_mem_op(service_dup->rend_pk_digest, OP_EQ, service->rend_pk_digest,
sizeof(service_dup->rend_pk_digest));
tt_int_op(service_dup_v2->auth_type, ==, service_v2->auth_type);
tt_str_op(service_dup_v2->onion_address, OP_EQ, service_v2->onion_address);
tt_mem_op(service_dup_v2->rend_pk_digest, OP_EQ, service_v2->rend_pk_digest,
sizeof(service_dup_v2->rend_pk_digest));
tt_mem_op(service_dup->rend_cookie, OP_EQ, service->rend_cookie,
sizeof(service_dup->rend_cookie));
tt_assert(service_dup->hsdirs_fp);
tt_int_op(smartlist_len(service_dup->hsdirs_fp), ==, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
tt_int_op(tor_digest_is_zero(service_dup->descriptor_id[rep]), ==, 1);
tt_int_op(tor_digest_is_zero(service_dup_v2->descriptor_id[rep]), ==, 1);
}
/* The rest should be zeroed because this is a service request. */
tt_int_op(tor_digest_is_zero(service_dup->descriptor_cookie), ==, 1);
tt_int_op(tor_digest_is_zero(service_dup->desc_id_fetch), ==, 1);
tt_int_op(tor_digest_is_zero(service_dup_v2->descriptor_cookie), ==, 1);
tt_int_op(tor_digest_is_zero(service_dup_v2->desc_id_fetch), ==, 1);
done:
rend_data_free(service);

View File

@ -10,6 +10,7 @@
#include "router.h"
#include "routerlist.h"
#include "config.h"
#include "hs_common.h"
#include <openssl/rsa.h>
#include "rend_test_helpers.h"
@ -23,15 +24,16 @@ static const int TIME_IN_THE_FUTURE = REND_CACHE_MAX_SKEW + 60;
static rend_data_t *
mock_rend_data(const char *onion_address)
{
rend_data_t *rend_query = tor_malloc_zero(sizeof(rend_data_t));
rend_data_v2_t *v2_data = tor_malloc_zero(sizeof(*v2_data));
rend_data_t *rend_query = &v2_data->base_;
rend_query->version = 2;
strlcpy(rend_query->onion_address, onion_address,
sizeof(rend_query->onion_address));
rend_query->auth_type = REND_NO_AUTH;
strlcpy(v2_data->onion_address, onion_address,
sizeof(v2_data->onion_address));
v2_data->auth_type = REND_NO_AUTH;
rend_query->hsdirs_fp = smartlist_new();
smartlist_add(rend_query->hsdirs_fp, tor_memdup("aaaaaaaaaaaaaaaaaaaaaaaa",
DIGEST_LEN));
return rend_query;
}
@ -143,7 +145,8 @@ test_rend_cache_store_v2_desc_as_client(void *data)
// Test mismatch between service ID and onion address
rend_cache_init();
strncpy(mock_rend_query->onion_address, "abc", REND_SERVICE_ID_LEN_BASE32+1);
strncpy(TO_REND_DATA_V2(mock_rend_query)->onion_address, "abc",
REND_SERVICE_ID_LEN_BASE32+1);
ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
desc_id_base32,
mock_rend_query, NULL);
@ -229,9 +232,9 @@ test_rend_cache_store_v2_desc_as_client(void *data)
generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
mock_rend_query = mock_rend_data(service_id);
mock_rend_query->auth_type = REND_BASIC_AUTH;
TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH;
client_cookie[0] = 'A';
memcpy(mock_rend_query->descriptor_cookie, client_cookie,
memcpy(TO_REND_DATA_V2(mock_rend_query)->descriptor_cookie, client_cookie,
REND_DESC_COOKIE_LEN);
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
DIGEST_LEN);
@ -249,7 +252,7 @@ test_rend_cache_store_v2_desc_as_client(void *data)
generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
mock_rend_query = mock_rend_data(service_id);
mock_rend_query->auth_type = REND_BASIC_AUTH;
TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH;
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
DIGEST_LEN);
ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,