diff options
Diffstat (limited to 'src/feature/hs/hs_service.c')
-rw-r--r-- | src/feature/hs/hs_service.c | 554 |
1 files changed, 245 insertions, 309 deletions
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 6d32cae86c..b366ce83d9 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -30,7 +30,6 @@ #include "feature/rend/rendservice.h" #include "lib/crypt_ops/crypto_ope.h" #include "lib/crypt_ops/crypto_rand.h" -#include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/hs/hs_circuit.h" @@ -67,7 +66,8 @@ #include <unistd.h> #endif -/* Helper macro. Iterate over every service in the global map. The var is the +#ifndef COCCI +/** Helper macro. Iterate over every service in the global map. The var is the * name of the service pointer. */ #define FOR_EACH_SERVICE_BEGIN(var) \ STMT_BEGIN \ @@ -76,7 +76,7 @@ var = *var##_iter; #define FOR_EACH_SERVICE_END } STMT_END ; -/* Helper macro. Iterate over both current and previous descriptor of a +/** Helper macro. Iterate over both current and previous descriptor of a * service. The var is the name of the descriptor pointer. This macro skips * any descriptor object of the service that is NULL. */ #define FOR_EACH_DESCRIPTOR_BEGIN(service, var) \ @@ -88,6 +88,7 @@ (var = service->desc_next); \ if (var == NULL) continue; #define FOR_EACH_DESCRIPTOR_END } STMT_END ; +#endif /* !defined(COCCI) */ /* Onion service directory file names. */ static const char fname_keyfile_prefix[] = "hs_ed25519"; @@ -95,7 +96,7 @@ static const char dname_client_pubkeys[] = "authorized_clients"; static const char fname_hostname[] = "hostname"; static const char address_tld[] = "onion"; -/* Staging list of service object. When configuring service, we add them to +/** Staging list of service object. When configuring service, we add them to * this list considered a staging area and they will get added to our global * map once the keys have been loaded. These two steps are separated because * loading keys requires that we are an actual running tor process. */ @@ -118,7 +119,7 @@ static int service_encode_descriptor(const hs_service_t *service, const ed25519_keypair_t *signing_kp, char **encoded_out); -/* Helper: Function to compare two objects in the service map. Return 1 if the +/** Helper: Function to compare two objects in the service map. Return 1 if the * two service have the same master public identity key. */ static inline int hs_service_ht_eq(const hs_service_t *first, const hs_service_t *second) @@ -130,7 +131,7 @@ hs_service_ht_eq(const hs_service_t *first, const hs_service_t *second) &second->keys.identity_pk); } -/* Helper: Function for the service hash table code below. The key used is the +/** Helper: Function for the service hash table code below. The key used is the * master public identity key which is ultimately the onion address. */ static inline unsigned int hs_service_ht_hash(const hs_service_t *service) @@ -140,7 +141,7 @@ hs_service_ht_hash(const hs_service_t *service) sizeof(service->keys.identity_pk.pubkey)); } -/* This is _the_ global hash map of hidden services which indexed the service +/** This is _the_ global hash map of hidden services which indexed the service * contained in it by master public identity key which is roughly the onion * address of the service. */ static struct hs_service_ht *hs_service_map; @@ -156,7 +157,7 @@ HT_GENERATE2(hs_service_ht, hs_service_t, hs_service_node, hs_service_ht_hash, hs_service_ht_eq, 0.6, tor_reallocarray, tor_free_) -/* Query the given service map with a public key and return a service object +/** Query the given service map with a public key and return a service object * if found else NULL. It is also possible to set a directory path in the * search query. If pk is NULL, then it will be set to zero indicating the * hash table to compare the directory path instead. */ @@ -171,7 +172,7 @@ find_service(hs_service_ht *map, const ed25519_public_key_t *pk) return HT_FIND(hs_service_ht, map, &dummy_service); } -/* Register the given service in the given map. If the service already exists +/** Register the given service in the given map. If the service already exists * in the map, -1 is returned. On success, 0 is returned and the service * ownership has been transferred to the global map. */ STATIC int @@ -196,7 +197,7 @@ register_service(hs_service_ht *map, hs_service_t *service) return 0; } -/* Remove a given service from the given map. If service is NULL or the +/** Remove a given service from the given map. If service is NULL or the * service key is unset, return gracefully. */ STATIC void remove_service(hs_service_ht *map, hs_service_t *service) @@ -226,7 +227,7 @@ remove_service(hs_service_ht *map, hs_service_t *service) } } -/* Set the default values for a service configuration object <b>c</b>. */ +/** Set the default values for a service configuration object <b>c</b>. */ static void set_service_default_config(hs_service_config_t *c, const or_options_t *options) @@ -242,9 +243,12 @@ set_service_default_config(hs_service_config_t *c, c->is_single_onion = 0; c->dir_group_readable = 0; c->is_ephemeral = 0; + c->has_dos_defense_enabled = HS_CONFIG_V3_DOS_DEFENSE_DEFAULT; + c->intro_dos_rate_per_sec = HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT; + c->intro_dos_burst_per_sec = HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT; } -/* From a service configuration object config, clear everything from it +/** From a service configuration object config, clear everything from it * meaning free allocated pointers and reset the values. */ STATIC void service_clear_config(hs_service_config_t *config) @@ -266,7 +270,7 @@ service_clear_config(hs_service_config_t *config) memset(config, 0, sizeof(*config)); } -/* Helper function to return a human readable description of the given intro +/** Helper function to return a human readable description of the given intro * point object. * * This function is not thread-safe. Each call to this invalidates the @@ -280,9 +284,10 @@ describe_intro_point(const hs_service_intro_point_t *ip) const char *legacy_id = NULL; SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - const hs_desc_link_specifier_t *, lspec) { - if (lspec->type == LS_LEGACY_ID) { - legacy_id = (const char *) lspec->u.legacy_id; + const link_specifier_t *, lspec) { + if (link_specifier_get_ls_type(lspec) == LS_LEGACY_ID) { + legacy_id = (const char *) + link_specifier_getconstarray_un_legacy_id(lspec); break; } } SMARTLIST_FOREACH_END(lspec); @@ -297,7 +302,7 @@ describe_intro_point(const hs_service_intro_point_t *ip) return buf; } -/* Return the lower bound of maximum INTRODUCE2 cells per circuit before we +/** Return the lower bound of maximum INTRODUCE2 cells per circuit before we * rotate intro point (defined by a consensus parameter or the default * value). */ static int32_t @@ -310,7 +315,7 @@ get_intro_point_min_introduce2(void) 0, INT32_MAX); } -/* Return the upper bound of maximum INTRODUCE2 cells per circuit before we +/** Return the upper bound of maximum INTRODUCE2 cells per circuit before we * rotate intro point (defined by a consensus parameter or the default * value). */ static int32_t @@ -323,8 +328,8 @@ get_intro_point_max_introduce2(void) 0, INT32_MAX); } -/* Return the minimum lifetime in seconds of an introduction point defined by a - * consensus parameter or the default value. */ +/** Return the minimum lifetime in seconds of an introduction point defined by + * a consensus parameter or the default value. */ static int32_t get_intro_point_min_lifetime(void) { @@ -340,8 +345,8 @@ get_intro_point_min_lifetime(void) 0, INT32_MAX); } -/* Return the maximum lifetime in seconds of an introduction point defined by a - * consensus parameter or the default value. */ +/** Return the maximum lifetime in seconds of an introduction point defined by + * a consensus parameter or the default value. */ static int32_t get_intro_point_max_lifetime(void) { @@ -357,7 +362,7 @@ get_intro_point_max_lifetime(void) 0, INT32_MAX); } -/* Return the number of extra introduction point defined by a consensus +/** Return the number of extra introduction point defined by a consensus * parameter or the default value. */ static int32_t get_intro_point_num_extra(void) @@ -368,7 +373,7 @@ get_intro_point_num_extra(void) NUM_INTRO_POINTS_EXTRA, 0, 128); } -/* Helper: Function that needs to return 1 for the HT for each loop which +/** Helper: Function that needs to return 1 for the HT for each loop which * frees every service in an hash map. */ static int ht_free_service_(struct hs_service_t *service, void *data) @@ -380,7 +385,7 @@ ht_free_service_(struct hs_service_t *service, void *data) return 1; } -/* Free every service that can be found in the global map. Once done, clear +/** Free every service that can be found in the global map. Once done, clear * and free the global map. */ static void service_free_all(void) @@ -402,7 +407,7 @@ service_free_all(void) } } -/* Free a given service intro point object. */ +/** Free a given service intro point object. */ STATIC void service_intro_point_free_(hs_service_intro_point_t *ip) { @@ -417,7 +422,7 @@ service_intro_point_free_(hs_service_intro_point_t *ip) tor_free(ip); } -/* Helper: free an hs_service_intro_point_t object. This function is used by +/** Helper: free an hs_service_intro_point_t object. This function is used by * digest256map_free() which requires a void * pointer. */ static void service_intro_point_free_void(void *obj) @@ -425,24 +430,17 @@ service_intro_point_free_void(void *obj) service_intro_point_free_(obj); } -/* Return a newly allocated service intro point and fully initialized from the - * given extend_info_t ei if non NULL. - * If is_legacy is true, we also generate the legacy key. - * If supports_ed25519_link_handshake_any is true, we add the relay's ed25519 - * key to the link specifiers. +/** Return a newly allocated service intro point and fully initialized from the + * given node_t node, if non NULL. * - * If ei is NULL, returns a hs_service_intro_point_t with an empty link + * If node is NULL, returns a hs_service_intro_point_t with an empty link * specifier list and no onion key. (This is used for testing.) * On any other error, NULL is returned. * - * ei must be an extend_info_t containing an IPv4 address. (We will add supoort - * for IPv6 in a later release.) When calling extend_info_from_node(), pass - * 0 in for_direct_connection to make sure ei always has an IPv4 address. */ + * node must be an node_t with an IPv4 address. */ STATIC hs_service_intro_point_t * -service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, - unsigned int supports_ed25519_link_handshake_any) +service_intro_point_new(const node_t *node) { - hs_desc_link_specifier_t *ls; hs_service_intro_point_t *ip; ip = tor_malloc_zero(sizeof(*ip)); @@ -472,12 +470,17 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, ip->replay_cache = replaycache_new(0, 0); /* Initialize the base object. We don't need the certificate object. */ - ip->base.link_specifiers = smartlist_new(); + ip->base.link_specifiers = node_get_link_specifier_smartlist(node, 0); + + if (node == NULL) { + goto done; + } /* Generate the encryption key for this intro point. */ curve25519_keypair_generate(&ip->enc_key_kp, 0); - /* Figure out if this chosen node supports v3 or is legacy only. */ - if (is_legacy) { + /* Figure out if this chosen node supports v3 or is legacy only. + * NULL nodes are used in the unit tests. */ + if (!node_supports_ed25519_hs_intro(node)) { ip->base.is_only_legacy = 1; /* Legacy mode that is doesn't support v3+ with ed25519 auth key. */ ip->legacy_key = crypto_pk_new(); @@ -490,40 +493,13 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, } } - if (ei == NULL) { - goto done; - } + /* Flag if this intro point supports the INTRO2 dos defenses. */ + ip->support_intro2_dos_defense = + node_supports_establish_intro_dos_extension(node); - /* We'll try to add all link specifiers. Legacy is mandatory. - * IPv4 or IPv6 is required, and we always send IPv4. */ - ls = hs_desc_link_specifier_new(ei, LS_IPV4); - /* It is impossible to have an extend info object without a v4. */ - if (BUG(!ls)) { - goto err; - } - smartlist_add(ip->base.link_specifiers, ls); - - ls = hs_desc_link_specifier_new(ei, LS_LEGACY_ID); - /* It is impossible to have an extend info object without an identity - * digest. */ - if (BUG(!ls)) { - goto err; - } - smartlist_add(ip->base.link_specifiers, ls); - - /* ed25519 identity key is optional for intro points. If the node supports - * ed25519 link authentication, we include it. */ - if (supports_ed25519_link_handshake_any) { - ls = hs_desc_link_specifier_new(ei, LS_ED25519_ID); - if (ls) { - smartlist_add(ip->base.link_specifiers, ls); - } - } - - /* IPv6 is not supported in this release. */ - - /* Finally, copy onion key from the extend_info_t object. */ - memcpy(&ip->onion_key, &ei->curve25519_onion_key, sizeof(ip->onion_key)); + /* Finally, copy onion key from the node. */ + memcpy(&ip->onion_key, node_get_curve25519_onion_key(node), + sizeof(ip->onion_key)); done: return ip; @@ -532,7 +508,7 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, return NULL; } -/* Add the given intro point object to the given intro point map. The intro +/** Add the given intro point object to the given intro point map. The intro * point MUST have its RSA encryption key set if this is a legacy type or the * authentication key set otherwise. */ STATIC void @@ -548,7 +524,7 @@ service_intro_point_add(digest256map_t *map, hs_service_intro_point_t *ip) tor_assert_nonfatal(!old_ip_entry); } -/* For a given service, remove the intro point from that service's descriptors +/** For a given service, remove the intro point from that service's descriptors * (check both current and next descriptor) */ STATIC void service_intro_point_remove(const hs_service_t *service, @@ -566,7 +542,7 @@ service_intro_point_remove(const hs_service_t *service, } FOR_EACH_DESCRIPTOR_END; } -/* For a given service and authentication key, return the intro point or NULL +/** For a given service and authentication key, return the intro point or NULL * if not found. This will check both descriptors in the service. */ STATIC hs_service_intro_point_t * service_intro_point_find(const hs_service_t *service, @@ -597,7 +573,7 @@ service_intro_point_find(const hs_service_t *service, return ip; } -/* For a given service and intro point, return the descriptor for which the +/** For a given service and intro point, return the descriptor for which the * intro point is assigned to. NULL is returned if not found. */ STATIC hs_service_descriptor_t * service_desc_find_by_intro(const hs_service_t *service, @@ -619,7 +595,7 @@ service_desc_find_by_intro(const hs_service_t *service, return descp; } -/* From a circuit identifier, get all the possible objects associated with the +/** From a circuit identifier, get all the possible objects associated with the * ident. If not NULL, service, ip or desc are set if the object can be found. * They are untouched if they can't be found. * @@ -652,20 +628,20 @@ get_objects_from_ident(const hs_ident_circuit_t *ident, } } -/* From a given intro point, return the first link specifier of type +/** From a given intro point, return the first link specifier of type * encountered in the link specifier list. Return NULL if it can't be found. * * The caller does NOT have ownership of the object, the intro point does. */ -static hs_desc_link_specifier_t * +static link_specifier_t * get_link_spec_by_type(const hs_service_intro_point_t *ip, uint8_t type) { - hs_desc_link_specifier_t *lnk_spec = NULL; + link_specifier_t *lnk_spec = NULL; tor_assert(ip); SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - hs_desc_link_specifier_t *, ls) { - if (ls->type == type) { + link_specifier_t *, ls) { + if (link_specifier_get_ls_type(ls) == type) { lnk_spec = ls; goto end; } @@ -675,13 +651,13 @@ get_link_spec_by_type(const hs_service_intro_point_t *ip, uint8_t type) return lnk_spec; } -/* Given a service intro point, return the node_t associated to it. This can +/** Given a service intro point, return the node_t associated to it. This can * return NULL if the given intro point has no legacy ID or if the node can't * be found in the consensus. */ STATIC const node_t * get_node_from_intro_point(const hs_service_intro_point_t *ip) { - const hs_desc_link_specifier_t *ls; + const link_specifier_t *ls; tor_assert(ip); @@ -690,10 +666,11 @@ get_node_from_intro_point(const hs_service_intro_point_t *ip) return NULL; } /* XXX In the future, we want to only use the ed25519 ID (#22173). */ - return node_get_by_id((const char *) ls->u.legacy_id); + return node_get_by_id( + (const char *) link_specifier_getconstarray_un_legacy_id(ls)); } -/* Given a service intro point, return the extend_info_t for it. This can +/** Given a service intro point, return the extend_info_t for it. This can * return NULL if the node can't be found for the intro point or the extend * info can't be created for the found node. If direct_conn is set, the extend * info is validated on if we can connect directly. */ @@ -722,7 +699,7 @@ get_extend_info_from_intro_point(const hs_service_intro_point_t *ip, return info; } -/* Return the number of introduction points that are established for the +/** Return the number of introduction points that are established for the * given descriptor. */ static unsigned int count_desc_circuit_established(const hs_service_descriptor_t *desc) @@ -733,13 +710,13 @@ count_desc_circuit_established(const hs_service_descriptor_t *desc) DIGEST256MAP_FOREACH(desc->intro_points.map, key, const hs_service_intro_point_t *, ip) { - count += ip->circuit_established; + count += !!hs_circ_service_get_established_intro_circ(ip); } DIGEST256MAP_FOREACH_END; return count; } -/* For a given service and descriptor of that service, close all active +/** For a given service and descriptor of that service, close all active * directory connections. */ static void close_directory_connections(const hs_service_t *service, @@ -774,7 +751,7 @@ close_directory_connections(const hs_service_t *service, smartlist_free(dir_conns); } -/* Close all rendezvous circuits for the given service. */ +/** Close all rendezvous circuits for the given service. */ static void close_service_rp_circuits(hs_service_t *service) { @@ -804,7 +781,7 @@ close_service_rp_circuits(hs_service_t *service) } } -/* Close the circuit(s) for the given map of introduction points. */ +/** Close the circuit(s) for the given map of introduction points. */ static void close_intro_circuits(hs_service_intropoints_t *intro_points) { @@ -822,7 +799,7 @@ close_intro_circuits(hs_service_intropoints_t *intro_points) } DIGEST256MAP_FOREACH_END; } -/* Close all introduction circuits for the given service. */ +/** Close all introduction circuits for the given service. */ static void close_service_intro_circuits(hs_service_t *service) { @@ -833,7 +810,7 @@ close_service_intro_circuits(hs_service_t *service) } FOR_EACH_DESCRIPTOR_END; } -/* Close any circuits related to the given service. */ +/** Close any circuits related to the given service. */ static void close_service_circuits(hs_service_t *service) { @@ -849,7 +826,7 @@ close_service_circuits(hs_service_t *service) close_service_rp_circuits(service); } -/* Move every ephemeral services from the src service map to the dst service +/** Move every ephemeral services from the src service map to the dst service * map. It is possible that a service can't be register to the dst map which * won't stop the process of moving them all but will trigger a log warn. */ static void @@ -879,7 +856,7 @@ move_ephemeral_services(hs_service_ht *src, hs_service_ht *dst) } } -/* Return a const string of the directory path escaped. If this is an +/** Return a const string of the directory path escaped. If this is an * ephemeral service, it returns "[EPHEMERAL]". This can only be called from * the main thread because escaped() uses a static variable. */ static const char * @@ -913,7 +890,7 @@ move_hs_state(hs_service_t *src_service, hs_service_t *dst_service) src->replay_cache_rend_cookie = NULL; /* steal pointer reference */ } -/* Register services that are in the staging list. Once this function returns, +/** Register services that are in the staging list. Once this function returns, * the global service map will be set with the right content and all non * surviving services will be cleaned up. */ static void @@ -981,7 +958,7 @@ register_all_services(void) hs_service_map_has_changed(); } -/* Write the onion address of a given service to the given filename fname_ in +/** Write the onion address of a given service to the given filename fname_ in * the service directory. Return 0 on success else -1 on error. */ STATIC int write_address_to_file(const hs_service_t *service, const char *fname_) @@ -1022,7 +999,7 @@ write_address_to_file(const hs_service_t *service, const char *fname_) return ret; } -/* Load and/or generate private keys for the given service. On success, the +/** Load and/or generate private keys for the given service. On success, the * hostname file will be written to disk along with the master private key iff * the service is not configured for offline keys. Return 0 on success else -1 * on failure. */ @@ -1098,7 +1075,7 @@ load_service_keys(hs_service_t *service) return ret; } -/* Check if the client file name is valid or not. Return 1 if valid, +/** Check if the client file name is valid or not. Return 1 if valid, * otherwise return 0. */ STATIC int client_filename_is_valid(const char *filename) @@ -1120,7 +1097,7 @@ client_filename_is_valid(const char *filename) return ret; } -/* Parse an authorized client from a string. The format of a client string +/** Parse an authorized client from a string. The format of a client string * looks like (see rend-spec-v3.txt): * * <auth-type>:<key-type>:<base32-encoded-public-key> @@ -1179,7 +1156,8 @@ parse_authorized_client(const char *client_key_str) client = tor_malloc_zero(sizeof(hs_service_authorized_client_t)); if (base32_decode((char *) client->client_pk.public_key, sizeof(client->client_pk.public_key), - pubkey_b32, strlen(pubkey_b32)) < 0) { + pubkey_b32, strlen(pubkey_b32)) != + sizeof(client->client_pk.public_key)) { log_warn(LD_REND, "Client authorization public key cannot be decoded: %s", pubkey_b32); goto err; @@ -1201,7 +1179,7 @@ parse_authorized_client(const char *client_key_str) return client; } -/* Load all the client public keys for the given service. Return 0 on +/** Load all the client public keys for the given service. Return 0 on * success else -1 on failure. */ static int load_client_keys(hs_service_t *service) @@ -1261,7 +1239,7 @@ load_client_keys(hs_service_t *service) client_key_str = read_file_to_str(client_key_file_path, 0, NULL); /* If we cannot read the file, continue with the next file. */ - if (!client_key_str) { + if (!client_key_str) { log_warn(LD_REND, "Client authorization file %s can't be read. " "Corrupted or verify permission? Ignoring.", client_key_file_path); @@ -1304,6 +1282,7 @@ load_client_keys(hs_service_t *service) return ret; } +/** Release all storage held in <b>client</b>. */ STATIC void service_authorized_client_free_(hs_service_authorized_client_t *client) { @@ -1314,7 +1293,7 @@ service_authorized_client_free_(hs_service_authorized_client_t *client) tor_free(client); } -/* Free a given service descriptor object and all key material is wiped. */ +/** Free a given service descriptor object and all key material is wiped. */ STATIC void service_descriptor_free_(hs_service_descriptor_t *desc) { @@ -1335,7 +1314,7 @@ service_descriptor_free_(hs_service_descriptor_t *desc) tor_free(desc); } -/* Return a newly allocated service descriptor object. */ +/** Return a newly allocated service descriptor object. */ STATIC hs_service_descriptor_t * service_descriptor_new(void) { @@ -1348,7 +1327,7 @@ service_descriptor_new(void) return sdesc; } -/* Allocate and return a deep copy of client. */ +/** Allocate and return a deep copy of client. */ static hs_service_authorized_client_t * service_authorized_client_dup(const hs_service_authorized_client_t *client) { @@ -1366,7 +1345,7 @@ service_authorized_client_dup(const hs_service_authorized_client_t *client) return client_dup; } -/* If two authorized clients are equal, return 0. If the first one should come +/** If two authorized clients are equal, return 0. If the first one should come * before the second, return less than zero. If the first should come after * the second, return greater than zero. */ static int @@ -1383,7 +1362,7 @@ service_authorized_client_cmp(const hs_service_authorized_client_t *client1, CURVE25519_PUBKEY_LEN); } -/* Helper for sorting authorized clients. */ +/** Helper for sorting authorized clients. */ static int compare_service_authorzized_client_(const void **_a, const void **_b) { @@ -1391,7 +1370,7 @@ compare_service_authorzized_client_(const void **_a, const void **_b) return service_authorized_client_cmp(a, b); } -/* If the list of hs_service_authorized_client_t's is different between +/** If the list of hs_service_authorized_client_t's is different between * src and dst, return 1. Otherwise, return 0. */ STATIC int service_authorized_client_config_equal(const hs_service_config_t *config1, @@ -1452,7 +1431,7 @@ service_authorized_client_config_equal(const hs_service_config_t *config1, return ret; } -/* Move descriptor(s) from the src service to the dst service and modify their +/** Move descriptor(s) from the src service to the dst service and modify their * content if necessary. We do this during SIGHUP when we re-create our * hidden services. */ static void @@ -1511,7 +1490,7 @@ move_descriptors(hs_service_t *src, hs_service_t *dst) service_descriptor_free(dst->desc_next); } -/* From the given service, remove all expired failing intro points for each +/** From the given service, remove all expired failing intro points for each * descriptor. */ static void remove_expired_failing_intro(hs_service_t *service, time_t now) @@ -1530,7 +1509,7 @@ remove_expired_failing_intro(hs_service_t *service, time_t now) } FOR_EACH_DESCRIPTOR_END; } -/* For the given descriptor desc, put all node_t object found from its failing +/** For the given descriptor desc, put all node_t object found from its failing * intro point list and put them in the given node_list. */ static void setup_intro_point_exclude_list(const hs_service_descriptor_t *desc, @@ -1548,7 +1527,7 @@ setup_intro_point_exclude_list(const hs_service_descriptor_t *desc, } DIGESTMAP_FOREACH_END; } -/* For the given failing intro point ip, we add its time of failure to the +/** For the given failing intro point ip, we add its time of failure to the * failed map and index it by identity digest (legacy ID) in the descriptor * desc failed id map. */ static void @@ -1556,7 +1535,7 @@ remember_failing_intro_point(const hs_service_intro_point_t *ip, hs_service_descriptor_t *desc, time_t now) { time_t *time_of_failure, *prev_ptr; - const hs_desc_link_specifier_t *legacy_ls; + const link_specifier_t *legacy_ls; tor_assert(ip); tor_assert(desc); @@ -1565,23 +1544,14 @@ remember_failing_intro_point(const hs_service_intro_point_t *ip, *time_of_failure = now; legacy_ls = get_link_spec_by_type(ip, LS_LEGACY_ID); tor_assert(legacy_ls); - prev_ptr = digestmap_set(desc->intro_points.failed_id, - (const char *) legacy_ls->u.legacy_id, - time_of_failure); + prev_ptr = digestmap_set( + desc->intro_points.failed_id, + (const char *) link_specifier_getconstarray_un_legacy_id(legacy_ls), + time_of_failure); tor_free(prev_ptr); } -/* Copy the descriptor link specifier object from src to dst. */ -static void -link_specifier_copy(hs_desc_link_specifier_t *dst, - const hs_desc_link_specifier_t *src) -{ - tor_assert(dst); - tor_assert(src); - memcpy(dst, src, sizeof(hs_desc_link_specifier_t)); -} - -/* Using a given descriptor signing keypair signing_kp, a service intro point +/** Using a given descriptor signing keypair signing_kp, a service intro point * object ip and the time now, setup the content of an already allocated * descriptor intro desc_ip. * @@ -1615,9 +1585,14 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp, /* Copy link specifier(s). */ SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - const hs_desc_link_specifier_t *, ls) { - hs_desc_link_specifier_t *copy = tor_malloc_zero(sizeof(*copy)); - link_specifier_copy(copy, ls); + const link_specifier_t *, ls) { + if (BUG(!ls)) { + goto done; + } + link_specifier_t *copy = link_specifier_dup(ls); + if (BUG(!copy)) { + goto done; + } smartlist_add(desc_ip->link_specifiers, copy); } SMARTLIST_FOREACH_END(ls); @@ -1665,7 +1640,7 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp, return ret; } -/* Using the given descriptor from the given service, build the descriptor +/** Using the given descriptor from the given service, build the descriptor * intro point list so we can then encode the descriptor for publication. This * function does not pick intro points, they have to be in the descriptor * current map. Cryptographic material (keys) must be initialized in the @@ -1686,7 +1661,7 @@ build_desc_intro_points(const hs_service_t *service, DIGEST256MAP_FOREACH(desc->intro_points.map, key, const hs_service_intro_point_t *, ip) { - if (!ip->circuit_established) { + if (!hs_circ_service_get_established_intro_circ(ip)) { /* Ignore un-established intro points. They can linger in that list * because their circuit has not opened and they haven't been removed * yet even though we have enough intro circuits. @@ -1705,7 +1680,7 @@ build_desc_intro_points(const hs_service_t *service, } DIGEST256MAP_FOREACH_END; } -/* Build the descriptor signing key certificate. */ +/** Build the descriptor signing key certificate. */ static void build_desc_signing_key_cert(hs_service_descriptor_t *desc, time_t now) { @@ -1731,7 +1706,7 @@ build_desc_signing_key_cert(hs_service_descriptor_t *desc, time_t now) tor_assert_nonfatal(plaintext->signing_key_cert); } -/* Populate the descriptor encrypted section from the given service object. +/** Populate the descriptor encrypted section from the given service object. * This will generate a valid list of introduction points that can be used * after for circuit creation. Return 0 on success else -1 on error. */ static int @@ -1761,7 +1736,7 @@ build_service_desc_encrypted(const hs_service_t *service, return 0; } -/* Populate the descriptor superencrypted section from the given service +/** Populate the descriptor superencrypted section from the given service * object. This will generate a valid list of hs_desc_authorized_client_t * of clients that are authorized to use the service. Return 0 on success * else -1 on error. */ @@ -1789,7 +1764,7 @@ build_service_desc_superencrypted(const hs_service_t *service, sizeof(curve25519_public_key_t)); /* Test that subcred is not zero because we might use it below */ - if (BUG(tor_mem_is_zero((char*)desc->desc->subcredential, DIGEST256_LEN))) { + if (BUG(fast_mem_is_zero((char*)desc->desc->subcredential, DIGEST256_LEN))) { return -1; } @@ -1844,7 +1819,7 @@ build_service_desc_superencrypted(const hs_service_t *service, return 0; } -/* Populate the descriptor plaintext section from the given service object. +/** Populate the descriptor plaintext section from the given service object. * The caller must make sure that the keys in the descriptors are valid that * is are non-zero. This can't fail. */ static void @@ -1855,9 +1830,9 @@ build_service_desc_plaintext(const hs_service_t *service, tor_assert(service); tor_assert(desc); - tor_assert(!tor_mem_is_zero((char *) &desc->blinded_kp, + tor_assert(!fast_mem_is_zero((char *) &desc->blinded_kp, sizeof(desc->blinded_kp))); - tor_assert(!tor_mem_is_zero((char *) &desc->signing_kp, + tor_assert(!fast_mem_is_zero((char *) &desc->signing_kp, sizeof(desc->signing_kp))); /* Set the subcredential. */ @@ -1895,7 +1870,7 @@ generate_ope_cipher_for_desc(const hs_service_descriptor_t *hs_desc) return crypto_ope_new(key); } -/* For the given service and descriptor object, create the key material which +/** For the given service and descriptor object, create the key material which * is the blinded keypair, the descriptor signing keypair, the ephemeral * keypair, and the descriptor cookie. Return 0 on success else -1 on error * where the generated keys MUST be ignored. */ @@ -1907,7 +1882,7 @@ build_service_desc_keys(const hs_service_t *service, ed25519_keypair_t kp; tor_assert(desc); - tor_assert(!tor_mem_is_zero((char *) &service->keys.identity_pk, + tor_assert(!fast_mem_is_zero((char *) &service->keys.identity_pk, ED25519_PUBKEY_LEN)); /* XXX: Support offline key feature (#18098). */ @@ -1957,7 +1932,7 @@ build_service_desc_keys(const hs_service_t *service, return ret; } -/* Given a service and the current time, build a descriptor for the service. +/** Given a service and the current time, build a descriptor for the service. * This function does not pick introduction point, this needs to be done by * the update function. On success, desc_out will point to the newly allocated * descriptor object. @@ -2014,7 +1989,7 @@ build_service_descriptor(hs_service_t *service, uint64_t time_period_num, service_descriptor_free(desc); } -/* Build both descriptors for the given service that has just booted up. +/** Build both descriptors for the given service that has just booted up. * Because it's a special case, it deserves its special function ;). */ static void build_descriptors_for_new_service(hs_service_t *service, time_t now) @@ -2064,7 +2039,7 @@ build_descriptors_for_new_service(hs_service_t *service, time_t now) safe_str_client(service->onion_address)); } -/* Build descriptors for each service if needed. There are conditions to build +/** Build descriptors for each service if needed. There are conditions to build * a descriptor which are details in the function. */ STATIC void build_all_descriptors(time_t now) @@ -2097,7 +2072,7 @@ build_all_descriptors(time_t now) } FOR_EACH_DESCRIPTOR_END; } -/* Randomly pick a node to become an introduction point but not present in the +/** Randomly pick a node to become an introduction point but not present in the * given exclude_nodes list. The chosen node is put in the exclude list * regardless of success or not because in case of failure, the node is simply * unsusable from that point on. @@ -2116,7 +2091,6 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) { const or_options_t *options = get_options(); const node_t *node; - extend_info_t *info = NULL; hs_service_intro_point_t *ip = NULL; /* Normal 3-hop introduction point flags. */ router_crn_flags_t flags = CRN_NEED_UPTIME | CRN_NEED_DESC; @@ -2145,47 +2119,21 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) * we don't want to use that node anymore. */ smartlist_add(exclude_nodes, (void *) node); - /* We do this to ease our life but also this call makes appropriate checks - * of the node object such as validating ntor support for instance. - * - * We must provide an extend_info for clients to connect over a 3-hop path, - * so we don't pass direct_conn here. */ - info = extend_info_from_node(node, 0); - if (BUG(info == NULL)) { - goto err; - } + /* Create our objects and populate them with the node information. */ + ip = service_intro_point_new(node); - /* Let's do a basic sanity check here so that we don't end up advertising the - * ed25519 identity key of relays that don't actually support the link - * protocol */ - if (!node_supports_ed25519_link_authentication(node, 0)) { - tor_assert_nonfatal(ed25519_public_key_is_zero(&info->ed_identity)); - } else { - /* Make sure we *do* have an ed key if we support the link authentication. - * Sending an empty key would result in a failure to extend. */ - tor_assert_nonfatal(!ed25519_public_key_is_zero(&info->ed_identity)); - } - - /* Create our objects and populate them with the node information. - * We don't care if the intro's link auth is compatible with us, because - * we are sending the ed25519 key to a remote client via the descriptor. */ - ip = service_intro_point_new(info, !node_supports_ed25519_hs_intro(node), - node_supports_ed25519_link_authentication(node, - 0)); if (ip == NULL) { goto err; } - log_info(LD_REND, "Picked intro point: %s", extend_info_describe(info)); - extend_info_free(info); + log_info(LD_REND, "Picked intro point: %s", node_describe(node)); return ip; err: service_intro_point_free(ip); - extend_info_free(info); return NULL; } -/* For a given descriptor from the given service, pick any needed intro points +/** For a given descriptor from the given service, pick any needed intro points * and update the current map with those newly picked intro points. Return the * number node that might have been added to the descriptor current map. */ static unsigned int @@ -2309,7 +2257,7 @@ service_desc_schedule_upload(hs_service_descriptor_t *desc, } } -/* Pick missing intro points for this descriptor if needed. */ +/** Pick missing intro points for this descriptor if needed. */ static void update_service_descriptor_intro_points(hs_service_t *service, hs_service_descriptor_t *desc, time_t now) @@ -2350,7 +2298,7 @@ update_service_descriptor_intro_points(hs_service_t *service, } } -/* Update descriptor intro points for each service if needed. We do this as +/** Update descriptor intro points for each service if needed. We do this as * part of the periodic event because we need to establish intro point circuits * before we publish descriptors. */ STATIC void @@ -2365,7 +2313,7 @@ update_all_descriptors_intro_points(time_t now) } FOR_EACH_SERVICE_END; } -/* Return true iff the given intro point has expired that is it has been used +/** Return true iff the given intro point has expired that is it has been used * for too long or we've reached our max seen INTRODUCE2 cell. */ STATIC int intro_point_should_expire(const hs_service_intro_point_t *ip, @@ -2387,15 +2335,66 @@ intro_point_should_expire(const hs_service_intro_point_t *ip, return 1; } -/* Go over the given set of intro points for each service and remove any - * invalid ones. The conditions for removal are: +/** Return true iff we should remove the intro point ip from its service. * - * - The node doesn't exists anymore (not in consensus) - * OR - * - The intro point maximum circuit retry count has been reached and no - * circuit can be found associated with it. - * OR - * - The intro point has expired and we should pick a new one. + * We remove an intro point from the service descriptor list if one of + * these criteria is met: + * - It has expired (either in INTRO2 count or in time). + * - No node was found (fell off the consensus). + * - We are over the maximum amount of retries. + * + * If an established or pending circuit is found for the given ip object, this + * return false indicating it should not be removed. */ +static bool +should_remove_intro_point(hs_service_intro_point_t *ip, time_t now) +{ + bool ret = false; + + tor_assert(ip); + + /* Any one of the following needs to be True to furfill the criteria to + * remove an intro point. */ + bool has_no_retries = (ip->circuit_retries > + MAX_INTRO_POINT_CIRCUIT_RETRIES); + bool has_no_node = (get_node_from_intro_point(ip) == NULL); + bool has_expired = intro_point_should_expire(ip, now); + + /* If the node fell off the consensus or the IP has expired, we have to + * remove it now. */ + if (has_no_node || has_expired) { + ret = true; + goto end; + } + + /* Pass this point, even though we might be over the retry limit, we check + * if a circuit (established or pending) exists. In that case, we should not + * remove it because it might simply be valid and opened at the previous + * scheduled event for the last retry. */ + + /* Do we simply have an existing circuit regardless of its state? */ + if (hs_circ_service_get_intro_circ(ip)) { + goto end; + } + + /* Getting here means we have _no_ circuits so then return if we have any + * remaining retries. */ + ret = has_no_retries; + + end: + /* Meaningful log in case we are about to remove the IP. */ + if (ret) { + log_info(LD_REND, "Intro point %s%s (retried: %u times). " + "Removing it.", + describe_intro_point(ip), + has_expired ? " has expired" : + (has_no_node) ? " fell off the consensus" : "", + ip->circuit_retries); + } + return ret; +} + +/** Go over the given set of intro points for each service and remove any + * invalid ones. * * If an intro point is removed, the circuit (if any) is immediately close. * If a circuit can't be found, the intro point is kept if it hasn't reached @@ -2404,12 +2403,10 @@ static void cleanup_intro_points(hs_service_t *service, time_t now) { /* List of intro points to close. We can't mark the intro circuits for close - * in the modify loop because doing so calls - * hs_service_intro_circ_has_closed() which does a digest256map_get() on the - * intro points map (that we are iterating over). This can't be done in a - * single iteration after a MAP_DEL_CURRENT, the object will still be - * returned leading to a use-after-free. So, we close the circuits and free - * the intro points after the loop if any. */ + * in the modify loop because doing so calls back into the HS subsystem and + * we need to keep that code path outside of the service/desc loop so those + * maps don't get modified during the close making us in a possible + * use-after-free situation. */ smartlist_t *ips_to_free = smartlist_new(); tor_assert(service); @@ -2420,21 +2417,7 @@ cleanup_intro_points(hs_service_t *service, time_t now) * valid and remove any of them that aren't. */ DIGEST256MAP_FOREACH_MODIFY(desc->intro_points.map, key, hs_service_intro_point_t *, ip) { - const node_t *node = get_node_from_intro_point(ip); - int has_expired = intro_point_should_expire(ip, now); - - /* We cleanup an intro point if it has expired or if we do not know the - * node_t anymore (removed from our latest consensus) or if we've - * reached the maximum number of retry with a non existing circuit. */ - if (has_expired || node == NULL || - ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES) { - log_info(LD_REND, "Intro point %s%s (retried: %u times). " - "Removing it.", - describe_intro_point(ip), - has_expired ? " has expired" : - (node == NULL) ? " fell off the consensus" : "", - ip->circuit_retries); - + if (should_remove_intro_point(ip, now)) { /* We've retried too many times, remember it as a failed intro point * so we don't pick it up again for INTRO_CIRC_RETRY_PERIOD sec. */ if (ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES) { @@ -2471,7 +2454,7 @@ cleanup_intro_points(hs_service_t *service, time_t now) smartlist_free(ips_to_free); } -/* Set the next rotation time of the descriptors for the given service for the +/** Set the next rotation time of the descriptors for the given service for the * time now. */ static void set_rotation_time(hs_service_t *service) @@ -2490,7 +2473,7 @@ set_rotation_time(hs_service_t *service) } } -/* Return true iff the service should rotate its descriptor. The time now is +/** Return true iff the service should rotate its descriptor. The time now is * only used to fetch the live consensus and if none can be found, this * returns false. */ static unsigned int @@ -2542,7 +2525,7 @@ should_rotate_descriptors(hs_service_t *service, time_t now) return 1; } -/* Rotate the service descriptors of the given service. The current descriptor +/** Rotate the service descriptors of the given service. The current descriptor * will be freed, the next one put in as the current and finally the next * descriptor pointer is NULLified. */ static void @@ -2564,7 +2547,7 @@ rotate_service_descriptors(hs_service_t *service) set_rotation_time(service); } -/* Rotate descriptors for each service if needed. A non existing current +/** Rotate descriptors for each service if needed. A non existing current * descriptor will trigger a descriptor build for the next time period. */ STATIC void rotate_all_descriptors(time_t now) @@ -2593,7 +2576,7 @@ rotate_all_descriptors(time_t now) } FOR_EACH_SERVICE_END; } -/* Scheduled event run from the main loop. Make sure all our services are up +/** Scheduled event run from the main loop. Make sure all our services are up * to date and ready for the other scheduled events. This includes looking at * the introduction points status and descriptor rotation time. */ STATIC void @@ -2628,7 +2611,7 @@ run_housekeeping_event(time_t now) } FOR_EACH_SERVICE_END; } -/* Scheduled event run from the main loop. Make sure all descriptors are up to +/** Scheduled event run from the main loop. Make sure all descriptors are up to * date. Once this returns, each service descriptor needs to be considered for * new introduction circuits and then for upload. */ static void @@ -2651,7 +2634,7 @@ run_build_descriptor_event(time_t now) update_all_descriptors_intro_points(now); } -/* For the given service, launch any intro point circuits that could be +/** For the given service, launch any intro point circuits that could be * needed. This considers every descriptor of the service. */ static void launch_intro_point_circuits(hs_service_t *service) @@ -2705,7 +2688,7 @@ launch_intro_point_circuits(hs_service_t *service) } FOR_EACH_DESCRIPTOR_END; } -/* Don't try to build more than this many circuits before giving up for a +/** Don't try to build more than this many circuits before giving up for a * while. Dynamically calculated based on the configured number of intro * points for the given service and how many descriptor exists. The default * use case of 3 introduction points and two descriptors will allow 28 @@ -2721,7 +2704,7 @@ get_max_intro_circ_per_period(const hs_service_t *service) tor_assert(service->config.num_intro_points <= HS_CONFIG_V3_MAX_INTRO_POINTS); -/* For a testing network, allow to do it for the maximum amount so circuit +/** For a testing network, allow to do it for the maximum amount so circuit * creation and rotation and so on can actually be tested without limit. */ #define MAX_INTRO_POINT_CIRCUIT_RETRIES_TESTING -1 if (get_options()->TestingTorNetwork) { @@ -2750,7 +2733,7 @@ get_max_intro_circ_per_period(const hs_service_t *service) return (count * multiplier); } -/* For the given service, return 1 if the service is allowed to launch more +/** For the given service, return 1 if the service is allowed to launch more * introduction circuits else 0 if the maximum has been reached for the retry * period of INTRO_CIRC_RETRY_PERIOD. */ STATIC int @@ -2796,7 +2779,7 @@ can_service_launch_intro_circuit(hs_service_t *service, time_t now) return 1; } -/* Scheduled event run from the main loop. Make sure we have all the circuits +/** Scheduled event run from the main loop. Make sure we have all the circuits * we need for each service. */ static void run_build_circuit_event(time_t now) @@ -2826,7 +2809,7 @@ run_build_circuit_event(time_t now) } FOR_EACH_SERVICE_END; } -/* Encode and sign the service descriptor desc and upload it to the given +/** Encode and sign the service descriptor desc and upload it to the given * hidden service directory. This does nothing if PublishHidServDescriptors * is false. */ static void @@ -2956,13 +2939,13 @@ set_descriptor_revision_counter(hs_service_descriptor_t *hs_desc, time_t now, /* The OPE module returns CRYPTO_OPE_ERROR in case of errors. */ tor_assert_nonfatal(rev_counter < CRYPTO_OPE_ERROR); - log_info(LD_REND, "Encrypted revision counter %d to %ld", - (int) seconds_since_start_of_srv, (long int) rev_counter); + log_info(LD_REND, "Encrypted revision counter %d to %" PRIu64, + (int) seconds_since_start_of_srv, rev_counter); hs_desc->desc->plaintext_data.revision_counter = rev_counter; } -/* Encode and sign the service descriptor desc and upload it to the +/** Encode and sign the service descriptor desc and upload it to the * responsible hidden service directories. If for_next_period is true, the set * of directories are selected using the next hsdir_index. This does nothing * if PublishHidServDescriptors is false. */ @@ -3059,7 +3042,7 @@ service_desc_hsdirs_changed(const hs_service_t *service, return should_reupload; } -/* Return 1 if the given descriptor from the given service can be uploaded +/** Return 1 if the given descriptor from the given service can be uploaded * else return 0 if it can not. */ static int should_service_upload_descriptor(const hs_service_t *service, @@ -3116,7 +3099,7 @@ should_service_upload_descriptor(const hs_service_t *service, return 0; } -/* Refresh the given service descriptor meaning this will update every mutable +/** Refresh the given service descriptor meaning this will update every mutable * field that needs to be updated before we upload. * * This should ONLY be called before uploading a descriptor. It assumes that @@ -3147,7 +3130,7 @@ refresh_service_descriptor(const hs_service_t *service, set_descriptor_revision_counter(desc, now, service->desc_current == desc); } -/* Scheduled event run from the main loop. Try to upload the descriptor for +/** Scheduled event run from the main loop. Try to upload the descriptor for * each service. */ STATIC void run_upload_descriptor_event(time_t now) @@ -3196,7 +3179,7 @@ run_upload_descriptor_event(time_t now) consider_republishing_hs_descriptors = 0; } -/* Called when the introduction point circuit is done building and ready to be +/** Called when the introduction point circuit is done building and ready to be * used. */ static void service_intro_circ_has_opened(origin_circuit_t *circ) @@ -3254,7 +3237,7 @@ service_intro_circ_has_opened(origin_circuit_t *circ) return; } -/* Called when a rendezvous circuit is done building and ready to be used. */ +/** Called when a rendezvous circuit is done building and ready to be used. */ static void service_rendezvous_circ_has_opened(origin_circuit_t *circ) { @@ -3295,7 +3278,7 @@ service_rendezvous_circ_has_opened(origin_circuit_t *circ) return; } -/* We've been expecting an INTRO_ESTABLISHED cell on this circuit and it just +/** We've been expecting an INTRO_ESTABLISHED cell on this circuit and it just * arrived. Handle the INTRO_ESTABLISHED cell arriving on the given * introduction circuit. Return 0 on success else a negative value. */ static int @@ -3338,11 +3321,6 @@ service_handle_intro_established(origin_circuit_t *circ, goto err; } - /* Flag that we have an established circuit for this intro point. This value - * is what indicates the upload scheduled event if we are ready to build the - * intro point into the descriptor and upload. */ - ip->circuit_established = 1; - log_info(LD_REND, "Successfully received an INTRO_ESTABLISHED cell " "on circuit %u for service %s", TO_CIRCUIT(circ)->n_circ_id, @@ -3353,7 +3331,7 @@ service_handle_intro_established(origin_circuit_t *circ, return -1; } -/* We just received an INTRODUCE2 cell on the established introduction circuit +/** We just received an INTRODUCE2 cell on the established introduction circuit * circ. Handle the cell and return 0 on success else a negative value. */ static int service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload, @@ -3401,7 +3379,7 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload, return -1; } -/* Add to list every filename used by service. This is used by the sandbox +/** Add to list every filename used by service. This is used by the sandbox * subsystem. */ static void service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list) @@ -3423,7 +3401,7 @@ service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list) smartlist_add(list, hs_path_from_filename(s_dir, fname)); } -/* Return true iff the given service identity key is present on disk. */ +/** Return true iff the given service identity key is present on disk. */ static int service_key_on_disk(const char *directory_path) { @@ -3447,7 +3425,7 @@ service_key_on_disk(const char *directory_path) return ret; } -/* This is a proxy function before actually calling hs_desc_encode_descriptor +/** This is a proxy function before actually calling hs_desc_encode_descriptor * because we need some preprocessing here */ static int service_encode_descriptor(const hs_service_t *service, @@ -3478,7 +3456,7 @@ service_encode_descriptor(const hs_service_t *service, /* Public API */ /* ========== */ -/* This is called everytime the service map (v2 or v3) changes that is if an +/** This is called everytime the service map (v2 or v3) changes that is if an * element is added or removed. */ void hs_service_map_has_changed(void) @@ -3489,7 +3467,7 @@ hs_service_map_has_changed(void) rescan_periodic_events(get_options()); } -/* Upload an encoded descriptor in encoded_desc of the given version. This +/** Upload an encoded descriptor in encoded_desc of the given version. This * descriptor is for the service identity_pk and blinded_pk used to setup the * directory connection identifier. It is uploaded to the directory hsdir_rs * routerstatus_t object. @@ -3537,7 +3515,7 @@ hs_service_upload_desc_to_dir(const char *encoded_desc, directory_request_free(dir_req); } -/* Add the ephemeral service using the secret key sk and ports. Both max +/** Add the ephemeral service using the secret key sk and ports. Both max * streams parameter will be set in the newly created service. * * Ownership of sk and ports is passed to this routine. Regardless of @@ -3623,7 +3601,7 @@ hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports, return ret; } -/* For the given onion address, delete the ephemeral service. Return 0 on +/** For the given onion address, delete the ephemeral service. Return 0 on * success else -1 on error. */ int hs_service_del_ephemeral(const char *address) @@ -3673,7 +3651,7 @@ hs_service_del_ephemeral(const char *address) return -1; } -/* Using the ed25519 public key pk, find a service for that key and return the +/** Using the ed25519 public key pk, find a service for that key and return the * current encoded descriptor as a newly allocated string or NULL if not * found. This is used by the control port subsystem. */ char * @@ -3699,9 +3677,9 @@ hs_service_lookup_current_desc(const ed25519_public_key_t *pk) return NULL; } -/* Return the number of service we have configured and usable. */ -unsigned int -hs_service_get_num_services(void) +/** Return the number of service we have configured and usable. */ +MOCK_IMPL(unsigned int, +hs_service_get_num_services,(void)) { if (hs_service_map == NULL) { return 0; @@ -3709,49 +3687,7 @@ hs_service_get_num_services(void) return HT_SIZE(hs_service_map); } -/* Called once an introduction circuit is closed. If the circuit doesn't have - * a v3 identifier, it is ignored. */ -void -hs_service_intro_circ_has_closed(origin_circuit_t *circ) -{ - hs_service_t *service = NULL; - hs_service_intro_point_t *ip = NULL; - hs_service_descriptor_t *desc = NULL; - - tor_assert(circ); - - if (circ->hs_ident == NULL) { - /* This is not a v3 circuit, ignore. */ - goto end; - } - - get_objects_from_ident(circ->hs_ident, &service, &ip, &desc); - if (service == NULL) { - /* This is possible if the circuits are closed and the service is - * immediately deleted. */ - log_info(LD_REND, "Unable to find any hidden service associated " - "identity key %s on intro circuit %u.", - ed25519_fmt(&circ->hs_ident->identity_pk), - TO_CIRCUIT(circ)->n_circ_id); - goto end; - } - if (ip == NULL) { - /* The introduction point object has already been removed probably by our - * cleanup process so ignore. */ - goto end; - } - /* Can't have an intro point object without a descriptor. */ - tor_assert(desc); - - /* Circuit disappeared so make sure the intro point is updated. By - * keeping the object in the descriptor, we'll be able to retry. */ - ip->circuit_established = 0; - - end: - return; -} - -/* Given conn, a rendezvous edge connection acting as an exit stream, look up +/** Given conn, a rendezvous edge connection acting as an exit stream, look up * the hidden service for the circuit circ, and look up the port and address * based on the connection port. Assign the actual connection address. * @@ -3849,7 +3785,7 @@ hs_service_exports_circuit_id(const ed25519_public_key_t *pk) return service->config.circuit_id_protocol; } -/* Add to file_list every filename used by a configured hidden service, and to +/** Add to file_list every filename used by a configured hidden service, and to * dir_list every directory path used by a configured hidden service. This is * used by the sandbox subsystem to whitelist those. */ void @@ -3874,7 +3810,7 @@ hs_service_lists_fnames_for_sandbox(smartlist_t *file_list, } FOR_EACH_DESCRIPTOR_END; } -/* Called when our internal view of the directory has changed. We might have +/** Called when our internal view of the directory has changed. We might have * received a new batch of descriptors which might affect the shape of the * HSDir hash ring. Signal that we should reexamine the hash ring and * re-upload our HS descriptors if needed. */ @@ -3891,7 +3827,7 @@ hs_service_dir_info_changed(void) } } -/* Called when we get an INTRODUCE2 cell on the circ. Respond to the cell and +/** Called when we get an INTRODUCE2 cell on the circ. Respond to the cell and * launch a circuit to the rendezvous point. */ int hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload, @@ -3922,7 +3858,7 @@ hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload, return ret; } -/* Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an +/** Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an * established introduction point. Return 0 on success else a negative value * and the circuit is closed. */ int @@ -3959,7 +3895,7 @@ hs_service_receive_intro_established(origin_circuit_t *circ, return -1; } -/* Called when any kind of hidden service circuit is done building thus +/** Called when any kind of hidden service circuit is done building thus * opened. This is the entry point from the circuit subsystem. */ void hs_service_circuit_has_opened(origin_circuit_t *circ) @@ -3988,7 +3924,7 @@ hs_service_circuit_has_opened(origin_circuit_t *circ) } } -/* Return the service version by looking at the key in the service directory. +/** Return the service version by looking at the key in the service directory. * If the key is not found or unrecognized, -1 is returned. Else, the service * version is returned. */ int @@ -4018,7 +3954,7 @@ hs_service_get_version_from_key(const hs_service_t *service) return version; } -/* Load and/or generate keys for all onion services including the client +/** Load and/or generate keys for all onion services including the client * authorization if any. Return 0 on success, -1 on failure. */ int hs_service_load_all_keys(void) @@ -4054,7 +3990,7 @@ hs_service_load_all_keys(void) return -1; } -/* Put all service object in the given service list. After this, the caller +/** Put all service object in the given service list. After this, the caller * looses ownership of every elements in the list and responsible to free the * list pointer. */ void @@ -4071,7 +4007,7 @@ hs_service_stage_services(const smartlist_t *service_list) smartlist_add_all(hs_service_staging_list, service_list); } -/* Allocate and initilize a service object. The service configuration will +/** Allocate and initilize a service object. The service configuration will * contain the default values. Return the newly allocated object pointer. This * function can't fail. */ hs_service_t * @@ -4089,7 +4025,7 @@ hs_service_new(const or_options_t *options) return service; } -/* Free the given <b>service</b> object and all its content. This function +/** Free the given <b>service</b> object and all its content. This function * also takes care of wiping service keys from memory. It is safe to pass a * NULL pointer. */ void @@ -4118,7 +4054,7 @@ hs_service_free_(hs_service_t *service) tor_free(service); } -/* Periodic callback. Entry point from the main loop to the HS service +/** Periodic callback. Entry point from the main loop to the HS service * subsystem. This is call every second. This is skipped if tor can't build a * circuit or the network is disabled. */ void @@ -4141,7 +4077,7 @@ hs_service_run_scheduled_events(time_t now) run_upload_descriptor_event(now); } -/* Initialize the service HS subsystem. */ +/** Initialize the service HS subsystem. */ void hs_service_init(void) { @@ -4158,7 +4094,7 @@ hs_service_init(void) hs_service_staging_list = smartlist_new(); } -/* Release all global storage of the hidden service subsystem. */ +/** Release all global storage of the hidden service subsystem. */ void hs_service_free_all(void) { @@ -4168,14 +4104,14 @@ hs_service_free_all(void) #ifdef TOR_UNIT_TESTS -/* Return the global service map size. Only used by unit test. */ +/** Return the global service map size. Only used by unit test. */ STATIC unsigned int get_hs_service_map_size(void) { return HT_SIZE(hs_service_map); } -/* Return the staging list size. Only used by unit test. */ +/** Return the staging list size. Only used by unit test. */ STATIC int get_hs_service_staging_list_size(void) { |