diff options
Diffstat (limited to 'src/feature/hs/hs_service.c')
-rw-r--r-- | src/feature/hs/hs_service.c | 119 |
1 files changed, 100 insertions, 19 deletions
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index c29f39c6b4..908ac02044 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -16,6 +16,7 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" +#include "core/or/extendinfo.h" #include "core/or/relay.h" #include "feature/client/circpathbias.h" #include "feature/dirclient/dirclient.h" @@ -40,6 +41,7 @@ #include "feature/hs/hs_descriptor.h" #include "feature/hs/hs_ident.h" #include "feature/hs/hs_intropoint.h" +#include "feature/hs/hs_metrics.h" #include "feature/hs/hs_service.h" #include "feature/hs/hs_stats.h" #include "feature/hs/hs_ob.h" @@ -195,6 +197,10 @@ register_service(hs_service_ht *map, hs_service_t *service) if (map == hs_service_map) { hs_service_map_has_changed(); } + /* Setup metrics. This is done here because in order to initialize metrics, + * we require tor to have fully initialized a service so the ports of the + * service can be looked at for instance. */ + hs_metrics_service_init(service); return 0; } @@ -543,7 +549,7 @@ service_intro_point_remove(const hs_service_t *service, /* Trying all descriptors. */ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) { /* We'll try to remove the descriptor on both descriptors which is not - * very expensive to do instead of doing loopup + remove. */ + * very expensive to do instead of doing lookup + remove. */ digest256map_remove(desc->intro_points.map, ip->auth_key_kp.pubkey.pubkey); } FOR_EACH_DESCRIPTOR_END; @@ -564,7 +570,7 @@ service_intro_point_find(const hs_service_t *service, * * Even if we use the same node as intro point in both descriptors, the node * will have a different intro auth key for each descriptor since we generate - * a new one everytime we pick an intro point. + * a new one every time we pick an intro point. * * After #22893 gets implemented, intro points will be moved to be * per-service instead of per-descriptor so this function will need to @@ -781,7 +787,7 @@ close_service_rp_circuits(hs_service_t *service) ed25519_pubkey_eq(ô->hs_ident->identity_pk, &service->keys.identity_pk)) { /* Reason is FINISHED because service has been removed and thus the - * circuit is considered old/uneeded. When freed, it is removed from the + * circuit is considered old/unneeded. When freed, it is removed from the * hs circuitmap. */ circuit_mark_for_close(TO_CIRCUIT(ocirc), END_CIRC_REASON_FINISHED); } @@ -799,7 +805,7 @@ close_intro_circuits(hs_service_intropoints_t *intro_points) origin_circuit_t *ocirc = hs_circ_service_get_intro_circ(ip); if (ocirc) { /* Reason is FINISHED because service has been removed and thus the - * circuit is considered old/uneeded. When freed, the circuit is removed + * circuit is considered old/unneeded. When freed, the circuit is removed * from the HS circuitmap. */ circuit_mark_for_close(TO_CIRCUIT(ocirc), END_CIRC_REASON_FINISHED); } @@ -990,7 +996,7 @@ write_address_to_file(const hs_service_t *service, const char *fname_) tor_asprintf(&addr_buf, "%s.%s\n", service->onion_address, address_tld); /* Notice here that we use the given "fname_". */ fname = hs_path_from_filename(service->config.directory_path, fname_); - if (write_str_to_file(fname, addr_buf, 0) < 0) { + if (write_str_to_file_if_not_equal(fname, addr_buf)) { log_warn(LD_REND, "Could not write onion address to hostname file %s", escaped(fname)); goto end; @@ -1083,7 +1089,7 @@ load_service_keys(hs_service_t *service) goto end; } - /* Succes. */ + /* Success. */ ret = 0; end: tor_free(fname); @@ -1587,7 +1593,7 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp, memcpy(&desc_ip->onion_key, &ip->onion_key, sizeof(desc_ip->onion_key)); /* Key and certificate material. */ - desc_ip->auth_key_cert = tor_cert_create(signing_kp, + desc_ip->auth_key_cert = tor_cert_create_ed25519(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY, &ip->auth_key_kp.pubkey, nearest_hour, @@ -1638,7 +1644,7 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp, ed25519_public_key_from_curve25519_public_key(&ed25519_pubkey, &ip->enc_key_kp.pubkey, 0); - desc_ip->enc_key_cert = tor_cert_create(signing_kp, + desc_ip->enc_key_cert = tor_cert_create_ed25519(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS, &ed25519_pubkey, nearest_hour, HS_DESC_CERT_LIFETIME, @@ -1712,12 +1718,13 @@ build_desc_signing_key_cert(hs_service_descriptor_t *desc, time_t now) /* Fresh certificate for the signing key. */ plaintext->signing_key_cert = - tor_cert_create(&desc->blinded_kp, CERT_TYPE_SIGNING_HS_DESC, + tor_cert_create_ed25519(&desc->blinded_kp, CERT_TYPE_SIGNING_HS_DESC, &desc->signing_kp.pubkey, now, HS_DESC_CERT_LIFETIME, CERT_FLAG_INCLUDE_SIGNING_KEY); /* If the cert creation fails, the descriptor encoding will fail and thus * ultimately won't be uploaded. We'll get a stack trace to help us learn - * where the call came from and the tor_cert_create() will log the error. */ + * where the call came from and the tor_cert_create_ed25519() will log the + * error. */ tor_assert_nonfatal(plaintext->signing_key_cert); } @@ -2190,7 +2197,7 @@ pick_needed_intro_points(hs_service_t *service, } /* Build an exclude list of nodes of our intro point(s). The expiring intro - * points are OK to pick again because this is afterall a concept of round + * points are OK to pick again because this is after all a concept of round * robin so they are considered valid nodes to pick again. */ DIGEST256MAP_FOREACH(desc->intro_points.map, key, hs_service_intro_point_t *, ip) { @@ -2374,7 +2381,7 @@ should_remove_intro_point(hs_service_intro_point_t *ip, time_t now) tor_assert(ip); - /* Any one of the following needs to be True to furfill the criteria to + /* Any one of the following needs to be True to fulfill the criteria to * remove an intro point. */ bool has_no_retries = (ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES); @@ -2875,6 +2882,9 @@ upload_descriptor_to_hsdir(const hs_service_t *service, hsdir->hsdir_index.store_first; char *blinded_pubkey_log_str = tor_strdup(hex_str((char*)&desc->blinded_kp.pubkey.pubkey, 32)); + /* This log message is used by Chutney as part of its bootstrap + * detection mechanism. Please don't change without first checking + * Chutney. */ log_info(LD_REND, "Service %s %s descriptor of revision %" PRIu64 " initiated upload request to %s with index %s (%s)", safe_str_client(service->onion_address), @@ -2991,7 +3001,7 @@ upload_descriptor_to_all(const hs_service_t *service, /* Get our list of responsible HSDir. */ responsible_dirs = smartlist_new(); /* The parameter 0 means that we aren't a client so tell the function to use - * the spread store consensus paremeter. */ + * the spread store consensus parameter. */ hs_get_responsible_hsdirs(&desc->blinded_kp.pubkey, desc->time_period_num, service->desc_next == desc, 0, responsible_dirs); @@ -3226,7 +3236,7 @@ refresh_service_descriptor(const hs_service_t *service, hs_service_descriptor_t *desc, time_t now) { /* There are few fields that we consider "mutable" in the descriptor meaning - * we need to update them regurlarly over the lifetime fo the descriptor. + * we need to update them regularly over the lifetime for the descriptor. * The rest are set once and should not be modified. * * - Signing key certificate. @@ -3386,6 +3396,15 @@ service_rendezvous_circ_has_opened(origin_circuit_t *circ) /* If the cell can't be sent, the circuit will be closed within this * function. */ hs_circ_service_rp_has_opened(service, circ); + + /* Update metrics that we have an established rendezvous circuit. It is not + * entirely true until the client receives the RENDEZVOUS2 cell and starts + * sending but if that circuit collapes, we'll decrement the counter thus it + * will even out the metric. */ + if (TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { + hs_metrics_new_established_rdv(service); + } + goto done; err: @@ -3437,6 +3456,9 @@ service_handle_intro_established(origin_circuit_t *circ, goto err; } + /* Update metrics. */ + hs_metrics_new_established_intro(service); + log_info(LD_REND, "Successfully received an INTRO_ESTABLISHED cell " "on circuit %u for service %s", TO_CIRCUIT(circ)->n_circ_id, @@ -3489,6 +3511,8 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload, payload, payload_len) < 0) { goto err; } + /* Update metrics that a new introduction was successful. */ + hs_metrics_new_introduction(service); return 0; err: @@ -3510,7 +3534,7 @@ service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list) s_dir = service->config.directory_path; /* The hostname file. */ smartlist_add(list, hs_path_from_filename(s_dir, fname_hostname)); - /* The key files splitted in two. */ + /* The key files split in two. */ tor_snprintf(fname, sizeof(fname), "%s_secret_key", fname_keyfile_prefix); smartlist_add(list, hs_path_from_filename(s_dir, fname)); tor_snprintf(fname, sizeof(fname), "%s_public_key", fname_keyfile_prefix); @@ -3572,7 +3596,33 @@ 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 +/** Called when a circuit was just cleaned up. This is done right before the + * circuit is marked for close. */ +void +hs_service_circuit_cleanup_on_close(const circuit_t *circ) +{ + tor_assert(circ); + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + + switch (circ->purpose) { + case CIRCUIT_PURPOSE_S_INTRO: + /* About to close an established introduction circuit. Update the metrics + * to reflect how many we have at the moment. */ + hs_metrics_close_established_intro( + &CONST_TO_ORIGIN_CIRCUIT(circ)->hs_ident->identity_pk); + break; + case CIRCUIT_PURPOSE_S_REND_JOINED: + /* About to close an established rendezvous circuit. Update the metrics to + * reflect how many we have at the moment. */ + hs_metrics_close_established_rdv( + &CONST_TO_ORIGIN_CIRCUIT(circ)->hs_ident->identity_pk); + break; + default: + break; + } +} + +/** This is called every time the service map (v2 or v3) changes that is if an * element is added or removed. */ void hs_service_map_has_changed(void) @@ -3862,7 +3912,7 @@ hs_service_set_conn_addr_port(const origin_circuit_t *circ, goto err_no_close; } - /* Find a virtual port of that service mathcing the one in the connection if + /* Find a virtual port of that service matching the one in the connection if * successful, set the address in the connection. */ if (hs_set_conn_addr_port(service->config.ports, conn) < 0) { log_info(LD_REND, "No virtual port mapping exists for port %d for " @@ -3903,7 +3953,7 @@ hs_service_exports_circuit_id(const ed25519_public_key_t *pk) /** 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. */ + * used by the sandbox subsystem to allowlist those. */ void hs_service_lists_fnames_for_sandbox(smartlist_t *file_list, smartlist_t *dir_list) @@ -4167,7 +4217,35 @@ 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 +/** Return a newly allocated list of all the service's metrics store. */ +smartlist_t * +hs_service_get_metrics_stores(void) +{ + smartlist_t *list = smartlist_new(); + + if (hs_service_map) { + FOR_EACH_SERVICE_BEGIN(service) { + smartlist_add(list, service->metrics.store); + } FOR_EACH_SERVICE_END; + } + + return list; +} + +/** Lookup the global service map for the given identitiy public key and + * return the service object if found, NULL if not. */ +hs_service_t * +hs_service_find(const ed25519_public_key_t *identity_pk) +{ + tor_assert(identity_pk); + + if (!hs_service_map) { + return NULL; + } + return find_service(hs_service_map, identity_pk); +} + +/** Allocate and initialize 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 * @@ -4213,6 +4291,9 @@ hs_service_free_(hs_service_t *service) tor_free(service->state.ob_subcreds); } + /* Free metrics object. */ + hs_metrics_service_free(service); + /* Wipe service keys. */ memwipe(&service->keys.identity_sk, 0, sizeof(service->keys.identity_sk)); |