diff options
Diffstat (limited to 'src/feature/rend')
-rw-r--r-- | src/feature/rend/.may_include | 1 | ||||
-rw-r--r-- | src/feature/rend/feature_rend.md | 7 | ||||
-rw-r--r-- | src/feature/rend/include.am | 22 | ||||
-rw-r--r-- | src/feature/rend/rend_authorized_client_st.h | 10 | ||||
-rw-r--r-- | src/feature/rend/rend_encoded_v2_service_descriptor_st.h | 10 | ||||
-rw-r--r-- | src/feature/rend/rend_intro_point_st.h | 9 | ||||
-rw-r--r-- | src/feature/rend/rend_service_descriptor_st.h | 10 | ||||
-rw-r--r-- | src/feature/rend/rendcache.c | 38 | ||||
-rw-r--r-- | src/feature/rend/rendcache.h | 4 | ||||
-rw-r--r-- | src/feature/rend/rendclient.c | 111 | ||||
-rw-r--r-- | src/feature/rend/rendclient.h | 5 | ||||
-rw-r--r-- | src/feature/rend/rendcommon.c | 27 | ||||
-rw-r--r-- | src/feature/rend/rendcommon.h | 2 | ||||
-rw-r--r-- | src/feature/rend/rendmid.c | 38 | ||||
-rw-r--r-- | src/feature/rend/rendmid.h | 2 | ||||
-rw-r--r-- | src/feature/rend/rendparse.c | 19 | ||||
-rw-r--r-- | src/feature/rend/rendparse.h | 8 | ||||
-rw-r--r-- | src/feature/rend/rendservice.c | 284 | ||||
-rw-r--r-- | src/feature/rend/rendservice.h | 5 |
19 files changed, 398 insertions, 214 deletions
diff --git a/src/feature/rend/.may_include b/src/feature/rend/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/rend/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/rend/feature_rend.md b/src/feature/rend/feature_rend.md new file mode 100644 index 0000000000..bfd8ae3dbc --- /dev/null +++ b/src/feature/rend/feature_rend.md @@ -0,0 +1,7 @@ +@dir /feature/rend +@brief feature/rend: version 2 (old) hidden services + +This directory implements the v2 onion service protocol, +as specified in +[rend-spec-v2.txt](https://gitweb.torproject.org/torspec.git/tree/rend-spec-v2.txt). + diff --git a/src/feature/rend/include.am b/src/feature/rend/include.am new file mode 100644 index 0000000000..fb12439a90 --- /dev/null +++ b/src/feature/rend/include.am @@ -0,0 +1,22 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/rend/rendcache.c \ + src/feature/rend/rendclient.c \ + src/feature/rend/rendcommon.c \ + src/feature/rend/rendmid.c \ + src/feature/rend/rendparse.c \ + src/feature/rend/rendservice.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/rend/rend_authorized_client_st.h \ + src/feature/rend/rend_encoded_v2_service_descriptor_st.h \ + src/feature/rend/rend_intro_point_st.h \ + src/feature/rend/rend_service_descriptor_st.h \ + src/feature/rend/rendcache.h \ + src/feature/rend/rendclient.h \ + src/feature/rend/rendcommon.h \ + src/feature/rend/rendmid.h \ + src/feature/rend/rendparse.h \ + src/feature/rend/rendservice.h diff --git a/src/feature/rend/rend_authorized_client_st.h b/src/feature/rend/rend_authorized_client_st.h index 7bd4f2fe8c..c6a6676da9 100644 --- a/src/feature/rend/rend_authorized_client_st.h +++ b/src/feature/rend/rend_authorized_client_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file rend_authorized_client_st.h + * @brief Hidden-service authorized client structure. + **/ + #ifndef REND_AUTHORIZED_CLIENT_ST_H #define REND_AUTHORIZED_CLIENT_ST_H @@ -14,5 +19,4 @@ struct rend_authorized_client_t { crypto_pk_t *client_key; }; -#endif - +#endif /* !defined(REND_AUTHORIZED_CLIENT_ST_H) */ diff --git a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h index 05ff145d53..fea91b876a 100644 --- a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h +++ b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file rend_encoded_v2_service_descriptor_st.h + * @brief Encoded v2 HS descriptor structure. + **/ + #ifndef REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H #define REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H @@ -13,5 +18,4 @@ struct rend_encoded_v2_service_descriptor_t { char *desc_str; /**< Descriptor string. */ }; -#endif - +#endif /* !defined(REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H) */ diff --git a/src/feature/rend/rend_intro_point_st.h b/src/feature/rend/rend_intro_point_st.h index de6987e569..4f0aa01523 100644 --- a/src/feature/rend/rend_intro_point_st.h +++ b/src/feature/rend/rend_intro_point_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file rend_intro_point_st.h + * @brief v2 hidden service introduction point structure. + **/ + #ifndef REND_INTRO_POINT_ST_H #define REND_INTRO_POINT_ST_H @@ -73,4 +78,4 @@ struct rend_intro_point_t { unsigned int circuit_established:1; }; -#endif +#endif /* !defined(REND_INTRO_POINT_ST_H) */ diff --git a/src/feature/rend/rend_service_descriptor_st.h b/src/feature/rend/rend_service_descriptor_st.h index aeb3178064..80c8034f46 100644 --- a/src/feature/rend/rend_service_descriptor_st.h +++ b/src/feature/rend/rend_service_descriptor_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file rend_service_descriptor_st.h + * @brief Parsed v2 HS descriptor structure. + **/ + #ifndef REND_SERVICE_DESCRIPTOR_ST_H #define REND_SERVICE_DESCRIPTOR_ST_H @@ -30,5 +35,4 @@ struct rend_service_descriptor_t { smartlist_t *successful_uploads; }; -#endif - +#endif /* !defined(REND_SERVICE_DESCRIPTOR_ST_H) */ diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c index 1c3badaff3..0890a81d8f 100644 --- a/src/feature/rend/rendcache.c +++ b/src/feature/rend/rendcache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Tor Project, Inc. */ +/* Copyright (c) 2015-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,6 +19,8 @@ #include "feature/rend/rend_intro_point_st.h" #include "feature/rend/rend_service_descriptor_st.h" +#include "lib/ctime/di_ops.h" + /** Map from service id (as generated by rend_get_service_id) to * rend_cache_entry_t. */ STATIC strmap_t *rend_cache = NULL; @@ -45,7 +47,7 @@ STATIC digestmap_t *rend_cache_v2_dir = NULL; * looked up in this cache and if present, it is discarded from the fetched * descriptor. At the end, all IP(s) in the cache, for a specific service * ID, that were NOT present in the descriptor are removed from this cache. - * Which means that if at least one IP was not in this cache, thus usuable, + * Which means that if at least one IP was not in this cache, thus usable, * it's considered a new descriptor so we keep it. Else, if all IPs were in * this cache, we discard the descriptor as it's considered unusable. * @@ -226,6 +228,17 @@ rend_cache_entry_free_void(void *p) rend_cache_entry_free_(p); } +/** Check if a failure cache entry exists for the given intro point. */ +bool +rend_cache_intro_failure_exists(const char *service_id, + const uint8_t *intro_identity) +{ + tor_assert(service_id); + tor_assert(intro_identity); + + return cache_failure_intro_lookup(intro_identity, service_id, NULL); +} + /** Free all storage held by the service descriptor cache. */ void rend_cache_free_all(void) @@ -513,9 +526,16 @@ rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e) rend_cache_entry_t *entry = NULL; static const int default_version = 2; - tor_assert(rend_cache); tor_assert(query); + /* This is possible if we are in the shutdown process and the cache was + * freed while some other subsystem might do a lookup to the cache for + * cleanup reasons such HS circuit cleanup for instance. */ + if (!rend_cache) { + ret = -ENOENT; + goto end; + } + if (!rend_valid_v2_service_id(query)) { ret = -EINVAL; goto end; @@ -593,10 +613,10 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc) char desc_id_digest[DIGEST_LEN]; tor_assert(rend_cache_v2_dir); if (base32_decode(desc_id_digest, DIGEST_LEN, - desc_id, REND_DESC_ID_V2_LEN_BASE32) < 0) { + desc_id, REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_REND, "Rejecting v2 rendezvous descriptor request -- descriptor ID " - "contains illegal characters: %s", + "has wrong length or illegal characters: %s", safe_str(desc_id)); return -1; } @@ -854,7 +874,8 @@ rend_cache_store_v2_desc_as_client(const char *desc, *entry = NULL; } if (base32_decode(want_desc_id, sizeof(want_desc_id), - desc_id_base32, strlen(desc_id_base32)) != 0) { + desc_id_base32, strlen(desc_id_base32)) != + sizeof(want_desc_id)) { log_warn(LD_BUG, "Couldn't decode base32 %s for descriptor id.", escaped_safe_str_client(desc_id_base32)); goto err; @@ -888,8 +909,8 @@ rend_cache_store_v2_desc_as_client(const char *desc, if (intro_content && intro_size > 0) { int n_intro_points; if (rend_data->auth_type != REND_NO_AUTH && - !tor_mem_is_zero(rend_data->descriptor_cookie, - sizeof(rend_data->descriptor_cookie))) { + !safe_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, @@ -1005,4 +1026,3 @@ rend_cache_store_v2_desc_as_client(const char *desc, tor_free(intro_content); return retval; } - diff --git a/src/feature/rend/rendcache.h b/src/feature/rend/rendcache.h index aec97eabb8..45410610b4 100644 --- a/src/feature/rend/rendcache.h +++ b/src/feature/rend/rendcache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Tor Project, Inc. */ +/* Copyright (c) 2015-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -80,6 +80,8 @@ int rend_cache_store_v2_desc_as_client(const char *desc, rend_cache_entry_t **entry); size_t rend_cache_get_total_allocation(void); +bool rend_cache_intro_failure_exists(const char *service_id, + const uint8_t *intro_identity); void rend_cache_intro_failure_note(rend_intro_point_failure_t failure, const uint8_t *identity, const char *service_id); diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c index 6e95142c0b..427491e3a8 100644 --- a/src/feature/rend/rendclient.c +++ b/src/feature/rend/rendclient.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,7 +17,7 @@ #include "core/or/connection_edge.h" #include "core/or/relay.h" #include "feature/client/circpathbias.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/hs/hs_circuit.h" @@ -119,7 +119,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc, char tmp[RELAY_PAYLOAD_SIZE]; rend_cache_entry_t *entry = NULL; crypt_path_t *cpath; - off_t dh_offset; + ptrdiff_t dh_offset; crypto_pk_t *intro_key = NULL; int status = 0; const char *onion_address; @@ -403,14 +403,23 @@ rend_client_introduction_acked(origin_circuit_t *circ, } else { log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); } + /* Save the rend data digest to a temporary object so that we don't access + * it after we mark the circuit for close. */ + const uint8_t *rend_digest_tmp = NULL; + size_t digest_len; + uint8_t *cached_rend_digest = NULL; + rend_digest_tmp = rend_data_get_pk_digest(circ->rend_data, &digest_len); + cached_rend_digest = tor_malloc_zero(digest_len); + memcpy(cached_rend_digest, rend_digest_tmp, digest_len); + /* close the circuit: we won't need it anymore. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCE_ACKED); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); /* close any other intros launched in parallel */ - rend_client_close_other_intros(rend_data_get_pk_digest(circ->rend_data, - NULL)); + rend_client_close_other_intros(cached_rend_digest); + tor_free(cached_rend_digest); /* free the temporary digest */ } else { /* It's a NAK; the introduction point didn't relay our request. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING); @@ -469,16 +478,19 @@ directory_get_from_hs_dir(const char *desc_id, /* Automatically pick an hs dir if none given. */ if (!rs_hsdir) { + bool rate_limited = false; + /* Determine responsible dirs. Even if we can't get all we want, work with * the ones we have. If it's empty, we'll notice in hs_pick_hsdir(). */ smartlist_t *responsible_dirs = smartlist_new(); hid_serv_get_responsible_directories(responsible_dirs, desc_id); - hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32); + hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32, &rate_limited); if (!hs_dir) { /* No suitable hs dir can be found, stop right now. */ - control_event_hsv2_descriptor_failed(rend_query, NULL, - "QUERY_NO_HSDIR"); + const char *query_response = (rate_limited) ? "QUERY_RATE_LIMITED" : + "QUERY_NO_HSDIR"; + control_event_hsv2_descriptor_failed(rend_query, NULL, query_response); control_event_hs_descriptor_content(rend_data_get_address(rend_query), desc_id_base32, NULL, NULL); return 0; @@ -1036,18 +1048,30 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, const or_options_t *options = get_options(); smartlist_t *usable_nodes; int n_excluded = 0; + char service_id[REND_SERVICE_ID_LEN_BASE32 + 1]; /* We'll keep a separate list of the usable nodes. If this becomes empty, * no nodes are usable. */ usable_nodes = smartlist_new(); smartlist_add_all(usable_nodes, entry->parsed->intro_nodes); + /* Get service ID so we can use it to query the failure cache. If we fail to + * parse it, this cache entry is no good. */ + if (BUG(rend_get_service_id(entry->parsed->pk, service_id) < 0)) { + smartlist_free(usable_nodes); + return NULL; + } + /* Remove the intro points that have timed out during this HS * connection attempt from our list of usable nodes. */ - SMARTLIST_FOREACH(usable_nodes, rend_intro_point_t *, ip, - if (ip->timed_out) { - SMARTLIST_DEL_CURRENT(usable_nodes, ip); - }); + SMARTLIST_FOREACH_BEGIN(usable_nodes, const rend_intro_point_t *, ip) { + bool failed_intro = + rend_cache_intro_failure_exists(service_id, + (const uint8_t *) ip->extend_info->identity_digest); + if (ip->timed_out || failed_intro) { + SMARTLIST_DEL_CURRENT(usable_nodes, ip); + }; + } SMARTLIST_FOREACH_END(ip); again: if (smartlist_len(usable_nodes) == 0) { @@ -1226,3 +1250,66 @@ rend_parse_service_authorization(const or_options_t *options, } return res; } + +/** The given circuit is being freed. Take appropriate action if it is of + * interest to the client subsystem. */ +void +rend_client_circuit_cleanup_on_free(const circuit_t *circ) +{ + int reason, orig_reason; + bool has_timed_out, ip_is_redundant; + const origin_circuit_t *ocirc = NULL; + + tor_assert(circ); + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + + reason = circ->marked_for_close_reason; + orig_reason = circ->marked_for_close_orig_reason; + ocirc = CONST_TO_ORIGIN_CIRCUIT(circ); + tor_assert(ocirc->rend_data); + + has_timed_out = (reason == END_CIRC_REASON_TIMEOUT); + ip_is_redundant = (orig_reason == END_CIRC_REASON_IP_NOW_REDUNDANT); + + switch (circ->purpose) { + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + { + if (ip_is_redundant) { + break; + } + tor_assert(circ->state == CIRCUIT_STATE_OPEN); + tor_assert(ocirc->build_state->chosen_exit); + /* Treat this like getting a nack from it */ + log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s", + safe_str_client(rend_data_get_address(ocirc->rend_data)), + safe_str_client(build_state_get_exit_nickname(ocirc->build_state)), + has_timed_out ? "Recording timeout." : "Removing from descriptor."); + rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, + ocirc->rend_data, + has_timed_out ? + INTRO_POINT_FAILURE_TIMEOUT : + INTRO_POINT_FAILURE_GENERIC); + break; + } + case CIRCUIT_PURPOSE_C_INTRODUCING: + { + /* Ignore if we were introducing and it timed out, we didn't pick an exit + * point yet (IP) or the reason indicate that it was a redundant IP. */ + if (has_timed_out || !ocirc->build_state->chosen_exit || ip_is_redundant) { + break; + } + log_info(LD_REND, "Failed intro circ %s to %s " + "(building circuit to intro point). " + "Marking intro point as possibly unreachable.", + 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, + ocirc->rend_data, + INTRO_POINT_FAILURE_UNREACHABLE); + break; + } + default: + break; + } +} diff --git a/src/feature/rend/rendclient.h b/src/feature/rend/rendclient.h index e5f333238e..b7aa212487 100644 --- a/src/feature/rend/rendclient.h +++ b/src/feature/rend/rendclient.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,7 @@ #ifndef TOR_RENDCLIENT_H #define TOR_RENDCLIENT_H +#include "feature/hs/hs_circuit.h" #include "feature/rend/rendcache.h" void rend_client_purge_state(void); @@ -47,5 +48,7 @@ rend_service_authorization_t *rend_client_lookup_service_authorization( const char *onion_address); void rend_service_authorization_free_all(void); +void rend_client_circuit_cleanup_on_free(const circuit_t *circ); + #endif /* !defined(TOR_RENDCLIENT_H) */ diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c index de48af795f..5d04755819 100644 --- a/src/feature/rend/rendcommon.c +++ b/src/feature/rend/rendcommon.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,7 +15,7 @@ #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "app/config/config.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/hs/hs_client.h" @@ -171,9 +171,10 @@ rend_compute_v2_desc_id(char *desc_id_out, const char *service_id, } /* Convert service ID to binary. */ if (base32_decode(service_id_binary, REND_SERVICE_ID_LEN, - service_id, REND_SERVICE_ID_LEN_BASE32) < 0) { + service_id, REND_SERVICE_ID_LEN_BASE32) != + REND_SERVICE_ID_LEN) { log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Illegal characters in service ID: %s", + "Illegal characters or wrong length for service ID: %s", safe_str_client(service_id)); return -1; } @@ -785,39 +786,39 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, switch (command) { case RELAY_COMMAND_ESTABLISH_INTRO: if (or_circ) - r = hs_intro_received_establish_intro(or_circ,payload,length); + r = hs_intro_received_establish_intro(or_circ, payload, length); break; case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: if (or_circ) - r = rend_mid_establish_rendezvous(or_circ,payload,length); + r = rend_mid_establish_rendezvous(or_circ, payload, length); break; case RELAY_COMMAND_INTRODUCE1: if (or_circ) - r = hs_intro_received_introduce1(or_circ,payload,length); + r = hs_intro_received_introduce1(or_circ, payload, length); break; case RELAY_COMMAND_INTRODUCE2: if (origin_circ) - r = hs_service_receive_introduce2(origin_circ,payload,length); + r = hs_service_receive_introduce2(origin_circ, payload, length); break; case RELAY_COMMAND_INTRODUCE_ACK: if (origin_circ) - r = hs_client_receive_introduce_ack(origin_circ,payload,length); + r = hs_client_receive_introduce_ack(origin_circ, payload, length); break; case RELAY_COMMAND_RENDEZVOUS1: if (or_circ) - r = rend_mid_rendezvous(or_circ,payload,length); + r = rend_mid_rendezvous(or_circ, payload, length); break; case RELAY_COMMAND_RENDEZVOUS2: if (origin_circ) - r = hs_client_receive_rendezvous2(origin_circ,payload,length); + r = hs_client_receive_rendezvous2(origin_circ, payload, length); break; case RELAY_COMMAND_INTRO_ESTABLISHED: if (origin_circ) - r = hs_service_receive_intro_established(origin_circ,payload,length); + r = hs_service_receive_intro_established(origin_circ, payload, length); break; case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: if (origin_circ) - r = hs_client_receive_rendezvous_acked(origin_circ,payload,length); + r = hs_client_receive_rendezvous_acked(origin_circ, payload, length); break; default: tor_fragile_assert(); diff --git a/src/feature/rend/rendcommon.h b/src/feature/rend/rendcommon.h index f136863c7a..d8281e0578 100644 --- a/src/feature/rend/rendcommon.h +++ b/src/feature/rend/rendcommon.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c index af02b34e6b..b497362857 100644 --- a/src/feature/rend/rendmid.c +++ b/src/feature/rend/rendmid.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,6 +18,7 @@ #include "feature/rend/rendmid.h" #include "feature/stats/rephist.h" #include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_dos.h" #include "feature/hs/hs_intropoint.h" #include "core/or/or_circuit_st.h" @@ -58,7 +59,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, pk = crypto_pk_asn1_decode((char*)(request+2), asn1len); if (!pk) { reason = END_CIRC_REASON_TORPROTOCOL; - log_warn(LD_PROTOCOL, "Couldn't decode public key."); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Couldn't decode public key."); goto err; } @@ -80,7 +81,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, (char*)request, 2+asn1len+DIGEST_LEN, (char*)(request+2+DIGEST_LEN+asn1len), request_len-(2+DIGEST_LEN+asn1len))<0) { - log_warn(LD_PROTOCOL, + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Incorrect signature on ESTABLISH_INTRO cell; rejecting."); reason = END_CIRC_REASON_TORPROTOCOL; goto err; @@ -117,6 +118,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, /* Now, set up this circuit. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); hs_circuitmap_register_intro_circ_v2_relay_side(circ, (uint8_t *)pk_digest); + hs_dos_setup_default_intro2_defenses(circ); log_info(LD_REND, "Established introduction point on circuit %u for service %s", @@ -160,9 +162,9 @@ rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request, if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+ DH1024_KEY_LEN+CIPHER_KEY_LEN+ PKCS1_OAEP_PADDING_OVERHEAD)) { - log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %u; " - "responding with nack.", - (unsigned)circ->p_circ_id); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Impossibly short INTRODUCE1 cell on circuit %u; " + "responding with nack.", (unsigned)circ->p_circ_id); goto err; } @@ -181,6 +183,14 @@ rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request, goto err; } + /* Before sending, lets make sure this cell can be sent on the service + * circuit asking the DoS defenses. */ + if (!hs_dos_can_send_intro2(intro_circ)) { + log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v2 cell due to DoS " + "limitations. Sending NACK to client."); + goto err; + } + log_info(LD_REND, "Sending introduction request for service %s " "from circ %u to circ %u", @@ -237,8 +247,8 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, goto err; } - /* Check if we are configured to accept established rendezvous cells from - * client or in other words Tor2Web clients. */ + /* Check if we are configured to defend ourselves from clients that + * attempt to establish rendezvous points directly to us. */ if (channel_is_client(circ->p_chan) && dos_should_refuse_single_hop_client()) { /* Note it down for the heartbeat log purposes. */ @@ -248,7 +258,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, } if (circ->base_.n_chan) { - log_warn(LD_PROTOCOL, + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Tried to establish rendezvous on non-edge circuit"); goto err; } @@ -260,8 +270,8 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, } if (hs_circuitmap_get_rend_circ_relay_side(request)) { - log_warn(LD_PROTOCOL, - "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); goto err; } @@ -303,9 +313,9 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, int reason = END_CIRC_REASON_INTERNAL; if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { - log_info(LD_REND, - "Tried to complete rendezvous on non-OR or non-edge circuit %u.", - (unsigned)circ->p_circ_id); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Tried to complete rendezvous on non-OR or non-edge circuit %u.", + (unsigned)circ->p_circ_id); reason = END_CIRC_REASON_TORPROTOCOL; goto err; } diff --git a/src/feature/rend/rendmid.h b/src/feature/rend/rendmid.h index 8ae1fa16b8..789596d855 100644 --- a/src/feature/rend/rendmid.h +++ b/src/feature/rend/rendmid.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c index abd0feb448..0979d767a7 100644 --- a/src/feature/rend/rendparse.c +++ b/src/feature/rend/rendparse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -143,8 +143,9 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, goto err; } if (base32_decode(desc_id_out, DIGEST_LEN, - tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) { - log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", + tok->args[0], REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) { + log_warn(LD_REND, + "Descriptor ID has wrong length or illegal characters: %s", tok->args[0]); goto err; } @@ -174,8 +175,10 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]); goto err; } - if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) { - log_warn(LD_REND, "Secret ID part contains illegal characters: %s", + if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) != + DIGEST_LEN) { + log_warn(LD_REND, + "Secret ID part has wrong length or illegal characters: %s", tok->args[0]); goto err; } @@ -429,8 +432,10 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed, /* Parse identifier. */ tok = find_by_keyword(tokens, R_IPO_IDENTIFIER); if (base32_decode(info->identity_digest, DIGEST_LEN, - tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) { - log_warn(LD_REND, "Identity digest contains illegal characters: %s", + tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) != + DIGEST_LEN) { + log_warn(LD_REND, + "Identity digest has wrong length or illegal characters: %s", tok->args[0]); rend_intro_point_free(intro); goto err; diff --git a/src/feature/rend/rendparse.h b/src/feature/rend/rendparse.h index 0cef931e90..75109c204d 100644 --- a/src/feature/rend/rendparse.h +++ b/src/feature/rend/rendparse.h @@ -1,12 +1,12 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file rend_parse.h - * \brief Header file for rend_parse.c. + * \file rendparse.h + * \brief Header file for rendparse.c. **/ #ifndef TOR_REND_PARSE_H @@ -29,4 +29,4 @@ int rend_parse_introduction_points(rend_service_descriptor_t *parsed, size_t intro_points_encoded_size); int rend_parse_client_keys(strmap_t *parsed_clients, const char *str); -#endif +#endif /* !defined(TOR_REND_PARSE_H) */ diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c index eaf0432a7d..83388a72eb 100644 --- a/src/feature/rend/rendservice.c +++ b/src/feature/rend/rendservice.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,8 +18,9 @@ #include "core/or/circuituse.h" #include "core/or/policies.h" #include "core/or/relay.h" +#include "core/or/crypt_path.h" #include "feature/client/circpathbias.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/hs/hs_common.h" @@ -48,6 +49,7 @@ #include "core/or/crypt_path_reference_st.h" #include "core/or/edge_connection_st.h" #include "core/or/extend_info_st.h" +#include "feature/hs/hs_opts_st.h" #include "feature/nodelist/networkstatus_st.h" #include "core/or/origin_circuit_st.h" #include "feature/rend/rend_authorized_client_st.h" @@ -729,22 +731,20 @@ service_config_shadow_copy(rend_service_t *service, config->ports = NULL; } -/* Parse the hidden service configuration starting at <b>line_</b> using the +/* Parse the hidden service configuration from <b>hs_opts</b> using the * already configured generic service configuration in <b>config</b>. This * function will translate the config object to a rend_service_t and add it to * the temporary list if valid. If <b>validate_only</b> is set, parse, warn * and return as normal but don't actually add the service to the list. */ int -rend_config_service(const config_line_t *line_, +rend_config_service(const hs_opts_t *hs_opts, const or_options_t *options, hs_service_config_t *config) { - const config_line_t *line; rend_service_t *service = NULL; - /* line_ can be NULL which would mean that the service configuration only - * have one line that is the directory directive. */ tor_assert(options); + tor_assert(hs_opts); tor_assert(config); /* We are about to configure a version 2 service. Warn of deprecation. */ @@ -764,126 +764,109 @@ rend_config_service(const config_line_t *line_, * options, we'll copy over the useful data to the rend_service_t object. */ service_config_shadow_copy(service, config); - for (line = line_; line; line = line->next) { - if (!strcasecmp(line->key, "HiddenServiceDir")) { - /* We just hit the next hidden service, stop right now. */ - break; + /* Number of introduction points. */ + if (hs_opts->HiddenServiceNumIntroductionPoints > NUM_INTRO_POINTS_MAX) { + log_warn(LD_CONFIG, "HiddenServiceNumIntroductionPoints must be " + "between 0 and %d, not %d.", + NUM_INTRO_POINTS_MAX, + hs_opts->HiddenServiceNumIntroductionPoints); + goto err; + } + service->n_intro_points_wanted = hs_opts->HiddenServiceNumIntroductionPoints; + log_info(LD_CONFIG, "HiddenServiceNumIntroductionPoints=%d for %s", + service->n_intro_points_wanted, escaped(service->directory)); + + /* Client authorization */ + if (hs_opts->HiddenServiceAuthorizeClient) { + /* Parse auth type and comma-separated list of client names and add a + * rend_authorized_client_t for each client to the service's list + * of authorized clients. */ + smartlist_t *type_names_split, *clients; + const char *authname; + type_names_split = smartlist_new(); + smartlist_split_string(type_names_split, + hs_opts->HiddenServiceAuthorizeClient, " ", 0, 2); + if (smartlist_len(type_names_split) < 1) { + log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This " + "should have been prevented when parsing the " + "configuration."); + smartlist_free(type_names_split); + goto err; } - /* Number of introduction points. */ - if (!strcasecmp(line->key, "HiddenServiceNumIntroductionPoints")) { - int ok = 0; - /* Those are specific defaults for version 2. */ - service->n_intro_points_wanted = - (unsigned int) tor_parse_long(line->value, 10, - 0, NUM_INTRO_POINTS_MAX, &ok, NULL); - if (!ok) { - log_warn(LD_CONFIG, - "HiddenServiceNumIntroductionPoints " - "should be between %d and %d, not %s", - 0, NUM_INTRO_POINTS_MAX, line->value); - goto err; - } - log_info(LD_CONFIG, "HiddenServiceNumIntroductionPoints=%d for %s", - service->n_intro_points_wanted, escaped(service->directory)); - continue; + authname = smartlist_get(type_names_split, 0); + if (!strcasecmp(authname, "basic")) { + service->auth_type = REND_BASIC_AUTH; + } else if (!strcasecmp(authname, "stealth")) { + service->auth_type = REND_STEALTH_AUTH; + } else { + log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains " + "unrecognized auth-type '%s'. Only 'basic' or 'stealth' " + "are recognized.", + (char *) smartlist_get(type_names_split, 0)); + SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); + smartlist_free(type_names_split); + goto err; } - if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) { - /* Parse auth type and comma-separated list of client names and add a - * rend_authorized_client_t for each client to the service's list - * of authorized clients. */ - smartlist_t *type_names_split, *clients; - const char *authname; - if (service->auth_type != REND_NO_AUTH) { - log_warn(LD_CONFIG, "Got multiple HiddenServiceAuthorizeClient " - "lines for a single service."); - goto err; - } - type_names_split = smartlist_new(); - smartlist_split_string(type_names_split, line->value, " ", 0, 2); - if (smartlist_len(type_names_split) < 1) { - log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This " - "should have been prevented when parsing the " - "configuration."); - smartlist_free(type_names_split); - goto err; - } - authname = smartlist_get(type_names_split, 0); - if (!strcasecmp(authname, "basic")) { - service->auth_type = REND_BASIC_AUTH; - } else if (!strcasecmp(authname, "stealth")) { - service->auth_type = REND_STEALTH_AUTH; - } else { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains " - "unrecognized auth-type '%s'. Only 'basic' or 'stealth' " - "are recognized.", - (char *) smartlist_get(type_names_split, 0)); - SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); - smartlist_free(type_names_split); - goto err; - } - service->clients = smartlist_new(); - if (smartlist_len(type_names_split) < 2) { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains " - "auth-type '%s', but no client names.", - service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth"); - SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); - smartlist_free(type_names_split); - continue; - } - clients = smartlist_new(); - smartlist_split_string(clients, smartlist_get(type_names_split, 1), - ",", SPLIT_SKIP_SPACE, 0); + service->clients = smartlist_new(); + if (smartlist_len(type_names_split) < 2) { + log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains " + "auth-type '%s', but no client names.", + service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth"); SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); smartlist_free(type_names_split); - /* Remove duplicate client names. */ - { - int num_clients = smartlist_len(clients); - smartlist_sort_strings(clients); - smartlist_uniq_strings(clients); - if (smartlist_len(clients) < num_clients) { - log_info(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d " - "duplicate client name(s); removing.", - num_clients - smartlist_len(clients)); - } - } - SMARTLIST_FOREACH_BEGIN(clients, const char *, client_name) - { - rend_authorized_client_t *client; - if (!rend_valid_client_name(client_name)) { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an " - "illegal client name: '%s'. Names must be " - "between 1 and %d characters and contain " - "only [A-Za-z0-9+_-].", - client_name, REND_CLIENTNAME_MAX_LEN); - SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp)); - smartlist_free(clients); - goto err; - } - client = tor_malloc_zero(sizeof(rend_authorized_client_t)); - client->client_name = tor_strdup(client_name); - smartlist_add(service->clients, client); - log_debug(LD_REND, "Adding client name '%s'", client_name); + goto err; + } + clients = smartlist_new(); + smartlist_split_string(clients, smartlist_get(type_names_split, 1), + ",", SPLIT_SKIP_SPACE, 0); + SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); + smartlist_free(type_names_split); + /* Remove duplicate client names. */ + { + int num_clients = smartlist_len(clients); + smartlist_sort_strings(clients); + smartlist_uniq_strings(clients); + if (smartlist_len(clients) < num_clients) { + log_info(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d " + "duplicate client name(s); removing.", + num_clients - smartlist_len(clients)); } - SMARTLIST_FOREACH_END(client_name); - SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp)); - smartlist_free(clients); - /* Ensure maximum number of clients. */ - if ((service->auth_type == REND_BASIC_AUTH && - smartlist_len(service->clients) > 512) || - (service->auth_type == REND_STEALTH_AUTH && - smartlist_len(service->clients) > 16)) { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d " - "client authorization entries, but only a " - "maximum of %d entries is allowed for " - "authorization type '%s'.", - smartlist_len(service->clients), - service->auth_type == REND_BASIC_AUTH ? 512 : 16, - service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth"); + } + SMARTLIST_FOREACH_BEGIN(clients, const char *, client_name) { + rend_authorized_client_t *client; + if (!rend_valid_client_name(client_name)) { + log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an " + "illegal client name: '%s'. Names must be " + "between 1 and %d characters and contain " + "only [A-Za-z0-9+_-].", + client_name, REND_CLIENTNAME_MAX_LEN); + SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp)); + smartlist_free(clients); goto err; } - continue; + client = tor_malloc_zero(sizeof(rend_authorized_client_t)); + client->client_name = tor_strdup(client_name); + smartlist_add(service->clients, client); + log_debug(LD_REND, "Adding client name '%s'", client_name); + } SMARTLIST_FOREACH_END(client_name); + SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp)); + smartlist_free(clients); + /* Ensure maximum number of clients. */ + if ((service->auth_type == REND_BASIC_AUTH && + smartlist_len(service->clients) > 512) || + (service->auth_type == REND_STEALTH_AUTH && + smartlist_len(service->clients) > 16)) { + log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d " + "client authorization entries, but only a " + "maximum of %d entries is allowed for " + "authorization type '%s'.", + smartlist_len(service->clients), + service->auth_type == REND_BASIC_AUTH ? 512 : 16, + service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth"); + goto err; } } + /* Validate the service just parsed. */ if (rend_validate_service(rend_service_staging_list, service) < 0) { /* Service is in the staging list so don't try to free it. */ @@ -2145,7 +2128,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, * * We only use a one-hop path on the first attempt. If the first attempt * fails, we use a 3-hop path for reachability / reliability. - * See the comment in rend_service_relauch_rendezvous() for details. */ + * See the comment in rend_service_relaunch_rendezvous() for details. */ if (rend_service_use_direct_connection(options, rp) && i == 0) { flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; } @@ -2186,7 +2169,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, cpath->rend_dh_handshake_state = dh; dh = NULL; - if (circuit_init_cpath_crypto(cpath, + if (cpath_init_circuit_crypto(cpath, keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN, 1, 0)<0) goto err; @@ -3035,6 +3018,10 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) { origin_circuit_t *newcirc; cpath_build_state_t *newstate, *oldstate; + const char *rend_pk_digest; + rend_service_t *service = NULL; + + int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); oldstate = oldcirc->build_state; @@ -3049,13 +3036,31 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", safe_str(extend_info_describe(oldstate->chosen_exit))); + /* Look up the service. */ + rend_pk_digest = (char *) rend_data_get_pk_digest(oldcirc->rend_data, NULL); + service = rend_service_get_by_pk_digest(rend_pk_digest); + + if (!service) { + char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; + base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, + rend_pk_digest, REND_SERVICE_ID_LEN); + + log_warn(LD_BUG, "Internal error: Trying to relaunch a rendezvous circ " + "for an unrecognized service %s.", + safe_str_client(serviceid)); + return; + } + + if (hs_service_requires_uptime_circ(service->ports)) { + flags |= CIRCLAUNCH_NEED_UPTIME; + } + /* You'd think Single Onion Services would want to retry the rendezvous * using a direct connection. But if it's blocked by a firewall, or the * service is IPv6-only, or the rend point avoiding becoming a one-hop * proxy, we need a 3-hop connection. */ newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, - oldstate->chosen_exit, - CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); + oldstate->chosen_exit, flags); if (!newcirc) { log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.", @@ -3555,7 +3560,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; - onion_append_to_cpath(&circuit->cpath, hop); + cpath_extend_linked_list(&circuit->cpath, hop); circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */ /* Change the circuit purpose. */ @@ -3729,20 +3734,23 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, base32_encode(desc_id_base32, sizeof(desc_id_base32), desc->desc_id, DIGEST_LEN); hs_dir_ip = tor_dup_ip(hs_dir->addr); - log_info(LD_REND, "Launching upload for v2 descriptor for " - "service '%s' with descriptor ID '%s' with validity " - "of %d seconds to hidden service directory '%s' on " - "%s:%d.", - safe_str_client(service_id), - safe_str_client(desc_id_base32), - seconds_valid, - hs_dir->nickname, - hs_dir_ip, - hs_dir->or_port); + if (hs_dir_ip) { + log_info(LD_REND, "Launching upload for v2 descriptor for " + "service '%s' with descriptor ID '%s' with validity " + "of %d seconds to hidden service directory '%s' on " + "%s:%d.", + safe_str_client(service_id), + safe_str_client(desc_id_base32), + seconds_valid, + hs_dir->nickname, + hs_dir_ip, + hs_dir->or_port); + tor_free(hs_dir_ip); + } + control_event_hs_descriptor_upload(service_id, hs_dir->identity_digest, desc_id_base32, NULL); - tor_free(hs_dir_ip); /* Remember successful upload to this router for next time. */ if (!smartlist_contains_digest(successful_uploads, hs_dir->identity_digest)) @@ -3995,7 +4003,7 @@ remove_invalid_intro_points(rend_service_t *service, * accounted for when considiring uploading a descriptor. */ intro->circuit_established = 0; - /* Node is gone or we've reached our maximum circuit creationg retry + /* Node is gone or we've reached our maximum circuit creation retry * count, clean up everything, we'll find a new one. */ if (node == NULL || intro->circuit_retries >= MAX_INTRO_POINT_CIRCUIT_RETRIES) { @@ -4235,6 +4243,7 @@ rend_consider_services_intro_points(time_t now) * directly ourselves. */ intro->extend_info = extend_info_from_node(node, 0); if (BUG(intro->extend_info == NULL)) { + tor_free(intro); break; } intro->intro_key = crypto_pk_new(); @@ -4364,17 +4373,16 @@ rend_consider_descriptor_republication(void) void rend_service_dump_stats(int severity) { - int i,j; rend_service_t *service; rend_intro_point_t *intro; const char *safe_name; origin_circuit_t *circ; - for (i=0; i < smartlist_len(rend_service_list); ++i) { + for (int i = 0; i < smartlist_len(rend_service_list); ++i) { service = smartlist_get(rend_service_list, i); tor_log(severity, LD_GENERAL, "Service configured in %s:", rend_service_escaped_dir(service)); - for (j=0; j < smartlist_len(service->intro_nodes); ++j) { + for (int j = 0; j < smartlist_len(service->intro_nodes); ++j) { intro = smartlist_get(service->intro_nodes, j); safe_name = safe_str_client(intro->extend_info->nickname); diff --git a/src/feature/rend/rendservice.h b/src/feature/rend/rendservice.h index a8eb28bee2..012afc0f9f 100644 --- a/src/feature/rend/rendservice.h +++ b/src/feature/rend/rendservice.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -139,7 +139,8 @@ STATIC void rend_service_prune_list_impl_(void); #endif /* defined(RENDSERVICE_PRIVATE) */ int rend_num_services(void); -int rend_config_service(const struct config_line_t *line_, +struct hs_opts_t; +int rend_config_service(const struct hs_opts_t *hs_opts, const or_options_t *options, hs_service_config_t *config); void rend_service_prune_list(void); |