commit 8293356ad993e06c66e6b56534be91fb912c9b5a Author: David Goulet dgoulet@torproject.org Date: Tue May 31 14:51:30 2016 -0400
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 --- src/or/circuitlist.c | 38 ++++--- src/or/circuitlist.h | 2 +- src/or/circuituse.c | 9 +- src/or/connection.c | 5 +- src/or/connection_edge.c | 10 +- src/or/control.c | 21 ++-- src/or/directory.c | 10 +- src/or/hs_common.c | 264 +++++++++++++++++++++++++++++++++++++++++++++ src/or/hs_common.h | 34 ++++++ src/or/include.am | 2 + src/or/or.h | 42 +++++--- src/or/rendcache.c | 16 +-- src/or/rendclient.c | 148 ++++++++++++++----------- src/or/rendclient.h | 2 +- src/or/rendcommon.c | 147 +++++-------------------- src/or/rendcommon.h | 24 +---- src/or/rendservice.c | 87 ++++++++------- src/test/test_connection.c | 12 +-- src/test/test_hs.c | 102 ++++++++++-------- src/test/test_rendcache.c | 21 ++-- 20 files changed, 635 insertions(+), 361 deletions(-)
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 5c69164..7c6dbc5 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -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, diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 2707b42..2e9ce89 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -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); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index f344703..44bf94c 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -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 diff --git a/src/or/connection.c b/src/or/connection.c index 5ecd1ad..73a8691 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -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))) )); }
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index dc6b093..2726349 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -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; } diff --git a/src/or/control.c b/src/or/control.c index 1337af4..1cc2e14 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -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); }
diff --git a/src/or/directory.c b/src/or/directory.c index d37b5c2..49efeef 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -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); }
diff --git a/src/or/hs_common.c b/src/or/hs_common.c new file mode 100644 index 0000000..2166005 --- /dev/null +++ b/src/or/hs_common.c @@ -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); + } +} diff --git a/src/or/hs_common.h b/src/or/hs_common.h new file mode 100644 index 0000000..e74fdc9 --- /dev/null +++ b/src/or/hs_common.h @@ -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 */ diff --git a/src/or/include.am b/src/or/include.am index 3988eef..f9199dd 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -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 \ diff --git a/src/or/or.h b/src/or/or.h index be58fa0..88f5363 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -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_)) diff --git a/src/or/rendcache.c b/src/or/rendcache.c index e61a96b..709aaff 100644 --- a/src/or/rendcache.c +++ b/src/or/rendcache.c @@ -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 " diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 3468b07..ad47ca6 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -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; diff --git a/src/or/rendclient.h b/src/or/rendclient.h index e90dac0..459988d 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -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, diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 01b0766..e6a7bbc 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -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; +} diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h index 88cf512..1a893e1 100644 --- a/src/or/rendcommon.h +++ b/src/or/rendcommon.h @@ -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); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 4c88f1f..21e88eb 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -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.", diff --git a/src/test/test_connection.c b/src/test/test_connection.c index bf95b0b..d7342e3 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -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, diff --git a/src/test/test_hs.c b/src/test/test_hs.c index 1daa155..a09e99f 100644 --- a/src/test/test_hs.c +++ b/src/test/test_hs.c @@ -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); diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c index e210e05..05a0bcd 100644 --- a/src/test/test_rendcache.c +++ b/src/test/test_rendcache.c @@ -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,
tor-commits@lists.torproject.org