diff options
Diffstat (limited to 'src/feature')
33 files changed, 403 insertions, 387 deletions
diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index a0375828a7..f4f7ac23a3 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -316,7 +316,8 @@ addr_is_a_configured_bridge(const tor_addr_t *addr, /** If we have a bridge configured whose digest matches * <b>ei->identity_digest</b>, or a bridge with no known digest whose address * matches <b>ei->addr</b>:<b>ei->port</b>, return 1. Else return 0. - * If <b>ei->onion_key</b> is NULL, check for address/port matches only. + * If <b>ei</b> has no onion key configured, check for address/port matches + * only. * * Note that if the extend_info_t contains multiple addresses, we return true * only if _every_ address is a bridge. @@ -324,7 +325,8 @@ addr_is_a_configured_bridge(const tor_addr_t *addr, int extend_info_is_a_configured_bridge(const extend_info_t *ei) { - const char *digest = ei->onion_key ? ei->identity_digest : NULL; + const char *digest = curve25519_public_key_is_ok(&ei->curve25519_onion_key) + ? ei->identity_digest : NULL; const tor_addr_port_t *ap1 = NULL, *ap2 = NULL; if (! tor_addr_is_null(&ei->orports[0].addr)) ap1 = &ei->orports[0]; diff --git a/src/feature/client/dnsserv.c b/src/feature/client/dnsserv.c index f0bb0af100..237a6ee3d3 100644 --- a/src/feature/client/dnsserv.c +++ b/src/feature/client/dnsserv.c @@ -319,6 +319,7 @@ evdns_get_orig_address(const struct evdns_server_request *req, break; case RESOLVED_TYPE_ERROR: case RESOLVED_TYPE_ERROR_TRANSIENT: + case RESOLVED_TYPE_NOERROR: /* Addr doesn't matter, since we're not sending it back in the reply.*/ return addr; default: @@ -379,6 +380,8 @@ dnsserv_resolved(entry_connection_t *conn, tor_free(ans); } else if (answer_type == RESOLVED_TYPE_ERROR) { err = DNS_ERR_NOTEXIST; + } else if (answer_type == RESOLVED_TYPE_NOERROR) { + err = DNS_ERR_NONE; } else { /* answer_type == RESOLVED_TYPE_ERROR_TRANSIENT */ err = DNS_ERR_SERVERFAILED; } diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 7c469ea84a..dee41fefa8 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -2169,7 +2169,7 @@ select_primary_guard_for_circuit(guard_selection_t *gs, static ratelim_t guardlog = RATELIM_INIT(60); log_fn_ratelim(&guardlog, LOG_NOTICE, LD_GUARD, "All current guards excluded by path restriction " - "type %d; using an additonal guard.", + "type %d; using an additional guard.", rst->type); } else { break; diff --git a/src/feature/dirauth/dirauth_config.c b/src/feature/dirauth/dirauth_config.c index f98513ef75..9378b0ffe6 100644 --- a/src/feature/dirauth/dirauth_config.c +++ b/src/feature/dirauth/dirauth_config.c @@ -16,9 +16,12 @@ #include "lib/encoding/confline.h" #include "lib/confmgt/confmgt.h" #include "lib/conf/confdecl.h" +#include "lib/version/torversion.h" /* Required for dirinfo_type_t in or_options_t */ #include "core/or/or.h" +#include "core/or/tor_version_st.h" +#include "core/or/versions.h" #include "app/config/config.h" #include "app/config/resolve_addr.h" @@ -426,6 +429,7 @@ static int dirauth_options_validate(const void *arg, char **msg) { const dirauth_options_t *options = arg; + tor_version_t minimal_accepted_server_version, recommended_version; if (options->VersioningAuthoritativeDirectory && (!options->RecommendedClientVersions || @@ -439,12 +443,53 @@ dirauth_options_validate(const void *arg, char **msg) REJECT("Guard bandwdith threshold fraction is invalid."); } - char *t; + if (tor_version_parse(options->MinimalAcceptedServerVersion, + &minimal_accepted_server_version) != 0) { + REJECT("Invalid MinimalAcceptedServerVersion"); + } + + tor_assertf(tor_version_parse(get_short_version(), + &recommended_version) == 0, + "We failed to parse our own version"); + if (tor_version_compare(&recommended_version, + &minimal_accepted_server_version) < 0) { + REJECT("MinimalAcceptedServerVersion wants to reject the version " + "this node is running"); + } + + char *recommended_versions; + int found_recommended_rejected_version = 0; /* Call these functions to produce warnings only. */ - t = format_recommended_version_list(options->RecommendedClientVersions, 1); - tor_free(t); - t = format_recommended_version_list(options->RecommendedServerVersions, 1); - tor_free(t); + recommended_versions = format_recommended_version_list( + options->RecommendedClientVersions, 1); + tor_free(recommended_versions); + + recommended_versions = format_recommended_version_list( + options->RecommendedServerVersions, 1); + + smartlist_t *version_sl = smartlist_new(); + smartlist_split_string(version_sl, recommended_versions, ",", + SPLIT_SKIP_SPACE, 0); + SMARTLIST_FOREACH_BEGIN(version_sl, const char *, version) { + if (version[0] != '\0' && tor_version_parse(version, + &recommended_version) != 0) { + COMPLAIN("Found unparseable version in RecommendedServerVersions"); + continue; + } + + if (tor_version_compare(&recommended_version, + &minimal_accepted_server_version) < 0) { + found_recommended_rejected_version = 1; + break; + } + } SMARTLIST_FOREACH_END(version); + + SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version)); + smartlist_free(version_sl); + tor_free(recommended_versions); + if (found_recommended_rejected_version) + REJECT("MinimalAcceptedServerVersion wants to reject a recommended " + "version"); if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) { COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high."); diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc index e2056c9cc7..c6f9c09213 100644 --- a/src/feature/dirauth/dirauth_options.inc +++ b/src/feature/dirauth/dirauth_options.inc @@ -76,6 +76,9 @@ CONF_VAR(RecommendedClientVersions, LINELIST, 0, NULL) /** Which versions of tor should we tell users to run on relays? */ CONF_VAR(RecommendedServerVersions, LINELIST, 0, NULL) +/** Which minimal version of tor do we accept relay descriptors from? */ +CONF_VAR(MinimalAcceptedServerVersion, STRING, 0, "0.4.8.0-alpha-dev") + /** Relays which should be voted Guard regardless of uptime and bandwidth. */ CONF_VAR(AuthDirVoteGuard, ROUTERSET, 0, NULL) diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index 0783fb1e91..42c0802433 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -1631,7 +1631,11 @@ networkstatus_compute_consensus(smartlist_t *votes, n_versioning_servers); client_versions = compute_consensus_versions_list(combined_client_versions, n_versioning_clients); - packages = compute_consensus_package_lines(votes); + + if (consensus_method < MIN_METHOD_TO_OMIT_PACKAGE_FINGERPRINTS) + packages = tor_strdup(""); + else + packages = compute_consensus_package_lines(votes); SMARTLIST_FOREACH(combined_server_versions, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(combined_client_versions, char *, cp, tor_free(cp)); @@ -1776,15 +1780,10 @@ networkstatus_compute_consensus(smartlist_t *votes, } { - if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) { - max_unmeasured_bw_kb = (int32_t) extract_param_buggy( - params, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB); - } else { - max_unmeasured_bw_kb = dirvote_get_intermediate_param_value( - param_list, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB); - if (max_unmeasured_bw_kb < 1) - max_unmeasured_bw_kb = 1; - } + max_unmeasured_bw_kb = dirvote_get_intermediate_param_value( + param_list, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB); + if (max_unmeasured_bw_kb < 1) + max_unmeasured_bw_kb = 1; } /* Add the actual router entries. */ @@ -2130,7 +2129,7 @@ networkstatus_compute_consensus(smartlist_t *votes, /* Starting with consensus method 32, we handle the middle-only * flag specially: when it is present, we clear some flags, and * set others. */ - if (is_middle_only && consensus_method >= MIN_METHOD_FOR_MIDDLEONLY) { + if (is_middle_only) { remove_flag(chosen_flags, "Exit"); remove_flag(chosen_flags, "V2Dir"); remove_flag(chosen_flags, "Guard"); @@ -2367,15 +2366,10 @@ networkstatus_compute_consensus(smartlist_t *votes, { int64_t weight_scale; - if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) { - weight_scale = extract_param_buggy(params, "bwweightscale", - BW_WEIGHT_SCALE); - } else { - weight_scale = dirvote_get_intermediate_param_value( - param_list, "bwweightscale", BW_WEIGHT_SCALE); - if (weight_scale < 1) - weight_scale = 1; - } + weight_scale = dirvote_get_intermediate_param_value( + param_list, "bwweightscale", BW_WEIGHT_SCALE); + if (weight_scale < 1) + weight_scale = 1; added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T, weight_scale); } @@ -2477,53 +2471,6 @@ networkstatus_compute_consensus(smartlist_t *votes, return result; } -/** Extract the value of a parameter from a string encoding a list of - * parameters, badly. - * - * This is a deliberately buggy implementation, for backward compatibility - * with versions of Tor affected by #19011. Once all authorities have - * upgraded to consensus method 31 or later, then we can throw away this - * function. */ -STATIC int64_t -extract_param_buggy(const char *params, - const char *param_name, - int64_t default_value) -{ - int64_t value = default_value; - const char *param_str = NULL; - - if (params) { - char *prefix1 = NULL, *prefix2=NULL; - tor_asprintf(&prefix1, "%s=", param_name); - tor_asprintf(&prefix2, " %s=", param_name); - if (strcmpstart(params, prefix1) == 0) - param_str = params; - else - param_str = strstr(params, prefix2); - tor_free(prefix1); - tor_free(prefix2); - } - - if (param_str) { - int ok=0; - char *eq = strchr(param_str, '='); - if (eq) { - value = tor_parse_long(eq+1, 10, 1, INT32_MAX, &ok, NULL); - if (!ok) { - log_warn(LD_DIR, "Bad element '%s' in %s", - escaped(param_str), param_name); - value = default_value; - } - } else { - log_warn(LD_DIR, "Bad element '%s' in %s", - escaped(param_str), param_name); - value = default_value; - } - } - - return value; -} - /** Given a list of networkstatus_t for each vote, return a newly allocated * string containing the "package" lines for the vote. */ STATIC char * @@ -3919,13 +3866,18 @@ dirvote_get_vote(const char *fp, int flags) STATIC microdesc_t * dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) { + (void) consensus_method; // Currently unneeded... microdesc_t *result = NULL; char *key = NULL, *summary = NULL, *family = NULL; size_t keylen; smartlist_t *chunks = smartlist_new(); char *output = NULL; - crypto_pk_t *rsa_pubkey = router_get_rsa_onion_pkey(ri->onion_pkey, - ri->onion_pkey_len); + crypto_pk_t *rsa_pubkey = router_get_rsa_onion_pkey(ri->tap_onion_pkey, + ri->tap_onion_pkey_len); + if (!rsa_pubkey) { + /* We do not yet support creating MDs for relays without TAP onion keys. */ + goto done; + } if (crypto_pk_write_public_key_to_string(rsa_pubkey, &key, &keylen)<0) goto done; @@ -3937,20 +3889,15 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) if (ri->onion_curve25519_pkey) { char kbuf[CURVE25519_BASE64_PADDED_LEN + 1]; - bool add_padding = (consensus_method < MIN_METHOD_FOR_UNPADDED_NTOR_KEY); - curve25519_public_to_base64(kbuf, ri->onion_curve25519_pkey, add_padding); + curve25519_public_to_base64(kbuf, ri->onion_curve25519_pkey, false); smartlist_add_asprintf(chunks, "ntor-onion-key %s\n", kbuf); } if (family) { - if (consensus_method < MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS) { - smartlist_add_asprintf(chunks, "family %s\n", family); - } else { - const uint8_t *id = (const uint8_t *)ri->cache_info.identity_digest; - char *canonical_family = nodefamily_canonicalize(family, id, 0); - smartlist_add_asprintf(chunks, "family %s\n", canonical_family); - tor_free(canonical_family); - } + const uint8_t *id = (const uint8_t *)ri->cache_info.identity_digest; + char *canonical_family = nodefamily_canonicalize(family, id, 0); + smartlist_add_asprintf(chunks, "family %s\n", canonical_family); + tor_free(canonical_family); } if (summary && strcmp(summary, "reject 1-65535")) @@ -4048,10 +3995,6 @@ static const struct consensus_method_range_t { int high; } microdesc_consensus_methods[] = { {MIN_SUPPORTED_CONSENSUS_METHOD, - MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1}, - {MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS, - MIN_METHOD_FOR_UNPADDED_NTOR_KEY - 1}, - {MIN_METHOD_FOR_UNPADDED_NTOR_KEY, MAX_SUPPORTED_CONSENSUS_METHOD}, {-1, -1} }; diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index ae8d43a6f0..6ac07f171a 100644 --- a/src/feature/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -50,29 +50,10 @@ ((MIN_VOTE_SECONDS_TESTING)+(MIN_DIST_SECONDS_TESTING)+1) /** The lowest consensus method that we currently support. */ -#define MIN_SUPPORTED_CONSENSUS_METHOD 28 +#define MIN_SUPPORTED_CONSENSUS_METHOD 32 /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 33 - -/** - * Lowest consensus method where microdescriptor lines are put in canonical - * form for improved compressibility and ease of storage. See proposal 298. - **/ -#define MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS 29 - -/** Lowest consensus method where an unpadded base64 onion-key-ntor is allowed - * See #7869 */ -#define MIN_METHOD_FOR_UNPADDED_NTOR_KEY 30 - -/** Lowest consensus method for which we use the correct algorithm for - * extracting the bwweightscale= and maxunmeasuredbw= parameters. See #19011. - */ -#define MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE 31 - -/** Lowest consensus method for which we handle the MiddleOnly flag specially. - */ -#define MIN_METHOD_FOR_MIDDLEONLY 32 +#define MAX_SUPPORTED_CONSENSUS_METHOD 34 /** * Lowest consensus method for which we suppress the published time in @@ -80,6 +61,12 @@ */ #define MIN_METHOD_TO_SUPPRESS_MD_PUBLISHED 33 +/** + * Lowest (supported) consensus method for which we do not include + * any "package" lines. + **/ +#define MIN_METHOD_TO_OMIT_PACKAGE_FINGERPRINTS 34 + /** Default bandwidth to clip unmeasured bandwidths to using method >= * MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not * get confused with the above macros.) */ @@ -274,9 +261,6 @@ STATIC char *networkstatus_get_detached_signatures(smartlist_t *consensuses); STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method); -STATIC int64_t extract_param_buggy(const char *params, - const char *param_name, - int64_t default_value); #endif /* defined(DIRVOTE_PRIVATE) */ diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c index fafb781330..5b76e937ab 100644 --- a/src/feature/dirauth/process_descs.c +++ b/src/feature/dirauth/process_descs.c @@ -404,8 +404,8 @@ dirserv_rejects_tor_version(const char *platform, static const char please_upgrade_string[] = "Tor version is insecure or unsupported. Please upgrade!"; - /* Anything before 0.4.8.0 is unsupported. Reject them. */ - if (!tor_version_as_new_as(platform,"0.4.8.0-alpha-dev")) { + if (!tor_version_as_new_as(platform, + dirauth_get_options()->MinimalAcceptedServerVersion)) { if (msg) { *msg = please_upgrade_string; } @@ -762,6 +762,16 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source) log_info(LD_DIR, "Assessing new descriptor: %s: %s", ri->nickname, ri->platform); + /* For now, TAP keys are still required. */ + if (! ri->tap_onion_pkey) { + log_info(LD_DIRSERV, "Rejecting descriptor from %s (source: %s); " + "it has no TAP key.", + router_describe(ri), source); + *msg = "Missing TAP key in descriptor."; + r = ROUTER_AUTHDIR_REJECTS; + goto fail; + } + /* Check whether this descriptor is semantically identical to the last one * from this server. (We do this here and not in router_add_to_routerlist * because we want to be able to accept the newest router descriptor that diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c index 71ee03e265..2fbac47b30 100644 --- a/src/feature/dirauth/voteflags.c +++ b/src/feature/dirauth/voteflags.c @@ -112,8 +112,7 @@ dirserv_thinks_router_is_unreliable(time_t now, } /** Return 1 if <b>ri</b>'s descriptor is "active" -- running, valid, - * not hibernating, having observed bw greater 0, and not too old. Else - * return 0. + * not hibernating, and not too old. Else return 0. */ static int router_is_active(const routerinfo_t *ri, const node_t *node, time_t now) @@ -125,20 +124,6 @@ router_is_active(const routerinfo_t *ri, const node_t *node, time_t now) if (!node->is_running || !node->is_valid || ri->is_hibernating) { return 0; } - /* Only require bandwidth capacity in non-test networks, or - * if TestingTorNetwork, and TestingMinExitFlagThreshold is non-zero */ - if (!ri->bandwidthcapacity) { - if (get_options()->TestingTorNetwork) { - if (dirauth_get_options()->TestingMinExitFlagThreshold > 0) { - /* If we're in a TestingTorNetwork, and TestingMinExitFlagThreshold is, - * then require bandwidthcapacity */ - return 0; - } - } else { - /* If we're not in a TestingTorNetwork, then require bandwidthcapacity */ - return 0; - } - } return 1; } diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c index beb38bda30..eef52f14f3 100644 --- a/src/feature/dirparse/microdesc_parse.c +++ b/src/feature/dirparse/microdesc_parse.c @@ -30,7 +30,7 @@ /** List of tokens recognized in microdescriptors */ // clang-format off static token_rule_t microdesc_token_table[] = { - T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024), + T1_START("onion-key", K_ONION_KEY, NO_ARGS, OPT_KEY_1024), T1("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ), T0N("id", K_ID, GE(2), NO_OBJ ), T0N("a", K_A, GE(1), NO_OBJ ), @@ -200,14 +200,11 @@ microdesc_parse_fields(microdesc_t *md, } tok = find_by_keyword(tokens, K_ONION_KEY); - if (!crypto_pk_public_exponent_ok(tok->key)) { + if (tok && tok->key && !crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_DIR, "Relay's onion key had invalid exponent."); goto err; } - md->onion_pkey = tor_memdup(tok->object_body, tok->object_size); - md->onion_pkey_len = tok->object_size; - crypto_pk_free(tok->key); if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) { curve25519_public_key_t k; diff --git a/src/feature/dirparse/parsecommon.c b/src/feature/dirparse/parsecommon.c index d7a6d65346..be1457b730 100644 --- a/src/feature/dirparse/parsecommon.c +++ b/src/feature/dirparse/parsecommon.c @@ -215,6 +215,16 @@ token_check_object(memarea_t *area, const char *kwd, RET_ERR(ebuf); } break; + case OPT_KEY_1024: + /* If there is anything, it must be a 1024-bit RSA key. */ + if (tok->object_body && !tok->key) { + tor_snprintf(ebuf, sizeof(ebuf), "Unexpected object for %s", kwd); + RET_ERR(ebuf); + } + if (!tok->key) { + break; + } + FALLTHROUGH; case NEED_KEY_1024: /* There must be a 1024-bit public key. */ if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) { tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits", @@ -395,7 +405,8 @@ get_next_token(memarea_t *area, } if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */ - if (o_syn != NEED_KEY && o_syn != NEED_KEY_1024 && o_syn != OBJ_OK) { + if (o_syn != OPT_KEY_1024 && o_syn != NEED_KEY && + o_syn != NEED_KEY_1024 && o_syn != OBJ_OK) { RET_ERR("Unexpected public key."); } tok->key = crypto_pk_asn1_decode(tok->object_body, tok->object_size); diff --git a/src/feature/dirparse/parsecommon.h b/src/feature/dirparse/parsecommon.h index 9333ec4b27..d48d27499f 100644 --- a/src/feature/dirparse/parsecommon.h +++ b/src/feature/dirparse/parsecommon.h @@ -220,6 +220,7 @@ typedef struct directory_token_t { typedef enum { NO_OBJ, /**< No object, ever. */ NEED_OBJ, /**< Object is required. */ + OPT_KEY_1024, /**< If object is present, it must be a 1024 bit public key */ NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */ NEED_KEY, /**< Object is required, and must be a public key. */ OBJ_OK, /**< Object is optional. */ diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c index 844057c47e..6289b4c018 100644 --- a/src/feature/dirparse/routerparse.c +++ b/src/feature/dirparse/routerparse.c @@ -90,7 +90,7 @@ const token_rule_t routerdesc_token_table[] = { T1_START( "router", K_ROUTER, GE(5), NO_OBJ ), T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ), T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ), - T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ), + T01("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ), T1("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ), T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ), T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), @@ -107,7 +107,7 @@ const token_rule_t routerdesc_token_table[] = { T1("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ), T1("master-key-ed25519", K_MASTER_KEY_ED25519, GE(1), NO_OBJ ), T1("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ), - T1("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ), + T01("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ), T1("ntor-onion-key-crosscert", K_NTOR_ONION_KEY_CROSSCERT, EQ(1), NEED_OBJ ), @@ -595,15 +595,17 @@ router_parse_entry_from_string(const char *s, const char *end, if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0) goto err; - tok = find_by_keyword(tokens, K_ONION_KEY); - if (!crypto_pk_public_exponent_ok(tok->key)) { - log_warn(LD_DIR, - "Relay's onion key had invalid exponent."); - goto err; + tok = find_opt_by_keyword(tokens, K_ONION_KEY); + if (tok) { + if (!crypto_pk_public_exponent_ok(tok->key)) { + log_warn(LD_DIR, + "Relay's onion key had invalid exponent."); + goto err; + } + router->tap_onion_pkey = tor_memdup(tok->object_body, tok->object_size); + router->tap_onion_pkey_len = tok->object_size; + crypto_pk_free(tok->key); } - router->onion_pkey = tor_memdup(tok->object_body, tok->object_size); - router->onion_pkey_len = tok->object_size; - crypto_pk_free(tok->key); if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) { curve25519_public_key_t k; @@ -627,26 +629,68 @@ router_parse_entry_from_string(const char *s, const char *end, { directory_token_t *ed_sig_tok, *ed_cert_tok, *cc_tap_tok, *cc_ntor_tok, *master_key_tok; - ed_sig_tok = find_opt_by_keyword(tokens, K_ROUTER_SIG_ED25519); - ed_cert_tok = find_opt_by_keyword(tokens, K_IDENTITY_ED25519); - master_key_tok = find_opt_by_keyword(tokens, K_MASTER_KEY_ED25519); + ed_sig_tok = find_by_keyword(tokens, K_ROUTER_SIG_ED25519); + ed_cert_tok = find_by_keyword(tokens, K_IDENTITY_ED25519); + master_key_tok = find_by_keyword(tokens, K_MASTER_KEY_ED25519); + cc_ntor_tok = find_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT); + /* This, and only this, is optional. */ cc_tap_tok = find_opt_by_keyword(tokens, K_ONION_KEY_CROSSCERT); - cc_ntor_tok = find_opt_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT); - int n_ed_toks = !!ed_sig_tok + !!ed_cert_tok + - !!cc_tap_tok + !!cc_ntor_tok; - if ((n_ed_toks != 0 && n_ed_toks != 4) || - (n_ed_toks == 4 && !router->onion_curve25519_pkey)) { - log_warn(LD_DIR, "Router descriptor with only partial ed25519/" - "cross-certification support"); + + if (bool_neq(cc_tap_tok==NULL, router->tap_onion_pkey==NULL)) { + log_warn(LD_DIR, "Router descriptor had only one of (onion-key, " + "onion-key-crosscert)."); goto err; } - if (master_key_tok && !ed_sig_tok) { - log_warn(LD_DIR, "Router descriptor has ed25519 master key but no " - "certificate"); + + IF_BUG_ONCE(! (ed_sig_tok && ed_cert_tok&& cc_ntor_tok &&master_key_tok)) { goto err; } - if (ed_sig_tok) { - tor_assert(ed_cert_tok && cc_tap_tok && cc_ntor_tok); + + tor_cert_t *cert; + { + /* Parse the identity certificate */ + cert = tor_cert_parse( + (const uint8_t*)ed_cert_tok->object_body, + ed_cert_tok->object_size); + if (! cert) { + log_warn(LD_DIR, "Couldn't parse ed25519 cert"); + goto err; + } + /* makes sure it gets freed. */ + router->cache_info.signing_key_cert = cert; + + if (cert->cert_type != CERT_TYPE_ID_SIGNING || + ! cert->signing_key_included) { + log_warn(LD_DIR, "Invalid form for ed25519 cert"); + goto err; + } + } + + if (cc_tap_tok) { + rsa_pubkey = router_get_rsa_onion_pkey(router->tap_onion_pkey, + router->tap_onion_pkey_len); + if (rsa_pubkey == NULL) { + log_warn(LD_DIR, "No pubkey for TAP cross-verification."); + goto err; + } + if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) { + log_warn(LD_DIR, "Wrong object type on onion-key-crosscert " + "in descriptor"); + goto err; + } + if (check_tap_onion_key_crosscert( + (const uint8_t*)cc_tap_tok->object_body, + (int)cc_tap_tok->object_size, + rsa_pubkey, + &cert->signing_key, + (const uint8_t*)router->cache_info.identity_digest)<0) { + log_warn(LD_DIR, "Incorrect TAP cross-verification"); + goto err; + } + } + + { + tor_assert(ed_sig_tok && ed_cert_tok && cc_ntor_tok); const int ed_cert_token_pos = smartlist_pos(tokens, ed_cert_tok); if (ed_cert_token_pos == -1 || router_token_pos == -1 || (ed_cert_token_pos != router_token_pos + 1 && @@ -668,35 +712,14 @@ router_parse_entry_from_string(const char *s, const char *end, "in descriptor"); goto err; } - if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) { - log_warn(LD_DIR, "Wrong object type on onion-key-crosscert " - "in descriptor"); - goto err; - } if (strcmp(cc_ntor_tok->args[0], "0") && strcmp(cc_ntor_tok->args[0], "1")) { log_warn(LD_DIR, "Bad sign bit on ntor-onion-key-crosscert"); goto err; } int ntor_cc_sign_bit = !strcmp(cc_ntor_tok->args[0], "1"); - uint8_t d256[DIGEST256_LEN]; const char *signed_start, *signed_end; - tor_cert_t *cert = tor_cert_parse( - (const uint8_t*)ed_cert_tok->object_body, - ed_cert_tok->object_size); - if (! cert) { - log_warn(LD_DIR, "Couldn't parse ed25519 cert"); - goto err; - } - /* makes sure it gets freed. */ - router->cache_info.signing_key_cert = cert; - - if (cert->cert_type != CERT_TYPE_ID_SIGNING || - ! cert->signing_key_included) { - log_warn(LD_DIR, "Invalid form for ed25519 cert"); - goto err; - } if (master_key_tok) { /* This token is optional, but if it's present, it must match @@ -746,6 +769,7 @@ router_parse_entry_from_string(const char *s, const char *end, crypto_digest_add_bytes(d, ED_DESC_SIGNATURE_PREFIX, strlen(ED_DESC_SIGNATURE_PREFIX)); crypto_digest_add_bytes(d, signed_start, signed_end-signed_start); + crypto_digest_get_digest(d, (char*)d256, sizeof(d256)); crypto_digest_free(d); @@ -776,18 +800,6 @@ router_parse_entry_from_string(const char *s, const char *end, goto err; } - rsa_pubkey = router_get_rsa_onion_pkey(router->onion_pkey, - router->onion_pkey_len); - if (check_tap_onion_key_crosscert( - (const uint8_t*)cc_tap_tok->object_body, - (int)cc_tap_tok->object_size, - rsa_pubkey, - &cert->signing_key, - (const uint8_t*)router->cache_info.identity_digest)<0) { - log_warn(LD_DIR, "Incorrect TAP cross-verification"); - goto err; - } - /* We check this before adding it to the routerlist. */ router->cert_expiration_time = expires; } diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index cd7e4890d1..e16ec89ccb 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1686,7 +1686,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, /* We do have everything for which we think we can connect successfully. */ info = extend_info_new(NULL, legacy_id, - (have_ed25519_id) ? &ed25519_pk : NULL, NULL, + (have_ed25519_id) ? &ed25519_pk : NULL, onion_key, &ap.addr, ap.port, NULL, false); done: return info; diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 3cc8c23e0b..3fb0220cc0 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -410,11 +410,6 @@ get_intro_point_max_introduce2(void) static int32_t get_intro_point_min_lifetime(void) { -#define MIN_INTRO_POINT_LIFETIME_TESTING 10 - if (get_options()->TestingTorNetwork) { - return MIN_INTRO_POINT_LIFETIME_TESTING; - } - /* The [0, 2147483647] range is quite large to accommodate anything we decide * in the future. */ return networkstatus_get_param(NULL, "hs_intro_min_lifetime", @@ -427,11 +422,6 @@ get_intro_point_min_lifetime(void) static int32_t get_intro_point_max_lifetime(void) { -#define MAX_INTRO_POINT_LIFETIME_TESTING 30 - if (get_options()->TestingTorNetwork) { - return MAX_INTRO_POINT_LIFETIME_TESTING; - } - /* The [0, 2147483647] range is quite large to accommodate anything we decide * in the future. */ return networkstatus_get_param(NULL, "hs_intro_max_lifetime", @@ -2163,7 +2153,7 @@ build_all_descriptors(time_t now) continue; } - /* Reaching this point means we are pass bootup so at runtime. We should + /* Reaching this point means we are past bootup so at runtime. We should * *never* have an empty current descriptor. If the next descriptor is * empty, we'll try to build it for the next time period. This only * happens when we rotate meaning that we are guaranteed to have a new SRV @@ -2185,7 +2175,7 @@ build_all_descriptors(time_t now) /** 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. + * unusable from that point on. * * If direct_conn is set, try to pick a node that our local firewall/policy * allows us to connect to directly. If we can't find any, return NULL. @@ -3039,13 +3029,6 @@ 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 - * creation and rotation and so on can actually be tested without limit. */ -#define MAX_INTRO_POINT_CIRCUIT_RETRIES_TESTING -1 - if (get_options()->TestingTorNetwork) { - return MAX_INTRO_POINT_CIRCUIT_RETRIES_TESTING; - } - num_wanted_ip = service->config.num_intro_points; /* The calculation is as follow. We have a number of intro points that we diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h index 36d67719ca..b3a4117461 100644 --- a/src/feature/hs/hs_service.h +++ b/src/feature/hs/hs_service.h @@ -113,7 +113,7 @@ typedef struct hs_service_intropoints_t { digest256map_t *map; /** Contains node's identity key digest that were introduction point for this - * descriptor but were retried to many times. We keep those so we avoid + * descriptor but were retried too many times. We keep those so we avoid * re-picking them over and over for a circuit retry period. * XXX: Once we have #22173, change this to only use ed25519 identity. */ digestmap_t *failed_id; diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c index 9e5f0bb9a4..3fd0f23fb5 100644 --- a/src/feature/nodelist/microdesc.c +++ b/src/feature/nodelist/microdesc.c @@ -909,8 +909,6 @@ microdesc_free_(microdesc_t *md, const char *fname, int lineno) //tor_assert(md->held_in_map == 0); //tor_assert(md->held_by_nodes == 0); - if (md->onion_pkey) - tor_free(md->onion_pkey); tor_free(md->onion_curve25519_pkey); tor_free(md->ed25519_identity_pkey); if (md->body && md->saved_location != SAVED_IN_CACHE) diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h index ad56b6d6c2..c642e6e12b 100644 --- a/src/feature/nodelist/microdesc_st.h +++ b/src/feature/nodelist/microdesc_st.h @@ -63,14 +63,6 @@ struct microdesc_t { /* Fields in the microdescriptor. */ - /** - * Public RSA TAP key for onions, ASN.1 encoded. We store this - * in its encoded format since storing it as a crypto_pk_t uses - * significantly more memory. */ - char *onion_pkey; - /** Length of onion_pkey, in bytes. */ - size_t onion_pkey_len; - /** As routerinfo_t.onion_curve25519_pkey */ struct curve25519_public_key_t *onion_curve25519_pkey; /** Ed25519 identity key, if included. */ diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index bbaa51a407..735361d417 100644 --- a/src/feature/nodelist/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -2034,37 +2034,6 @@ node_get_curve25519_onion_key(const node_t *node) return NULL; } -/* Return a newly allocacted RSA onion public key taken from the given node. - * - * Return NULL if node is NULL or no RSA onion public key can be found. It is - * the caller responsibility to free the returned object. */ -crypto_pk_t * -node_get_rsa_onion_key(const node_t *node) -{ - crypto_pk_t *pk = NULL; - const char *onion_pkey; - size_t onion_pkey_len; - - if (!node) { - goto end; - } - - if (node->ri) { - onion_pkey = node->ri->onion_pkey; - onion_pkey_len = node->ri->onion_pkey_len; - } else if (node->rs && node->md) { - onion_pkey = node->md->onion_pkey; - onion_pkey_len = node->md->onion_pkey_len; - } else { - /* No descriptor or microdescriptor. */ - goto end; - } - pk = router_get_rsa_onion_pkey(onion_pkey, onion_pkey_len); - - end: - return pk; -} - /** Refresh the country code of <b>ri</b>. This function MUST be called on * each router when the GeoIP database is reloaded, and on all new routers. */ void diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h index 3d5ad9c0ea..948a293f0c 100644 --- a/src/feature/nodelist/nodelist.h +++ b/src/feature/nodelist/nodelist.h @@ -109,7 +109,6 @@ void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out); int node_has_curve25519_onion_key(const node_t *node); const struct curve25519_public_key_t *node_get_curve25519_onion_key( const node_t *node); -crypto_pk_t *node_get_rsa_onion_key(const node_t *node); MOCK_DECL(const smartlist_t *, nodelist_get_list, (void)); diff --git a/src/feature/nodelist/routerinfo_st.h b/src/feature/nodelist/routerinfo_st.h index 50134b2b96..a5c00c85c5 100644 --- a/src/feature/nodelist/routerinfo_st.h +++ b/src/feature/nodelist/routerinfo_st.h @@ -33,10 +33,13 @@ struct routerinfo_t { /** * Public RSA TAP key for onions, ASN.1 encoded. We store this * in its encoded format since storing it as a crypto_pk_t uses - * significantly more memory. */ - char *onion_pkey; + * significantly more memory. + * + * This may be absent. + */ + char *tap_onion_pkey; /** Length of onion_pkey, in bytes. */ - size_t onion_pkey_len; + size_t tap_onion_pkey_len; crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ /** Public curve25519 key for onions */ diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index 63de68dda7..7904f7d032 100644 --- a/src/feature/nodelist/routerlist.c +++ b/src/feature/nodelist/routerlist.c @@ -930,8 +930,8 @@ routerinfo_free_(routerinfo_t *router) tor_free(router->platform); tor_free(router->protocol_list); tor_free(router->contact_info); - if (router->onion_pkey) - tor_free(router->onion_pkey); + if (router->tap_onion_pkey) + tor_free(router->tap_onion_pkey); tor_free(router->onion_curve25519_pkey); if (router->identity_pkey) crypto_pk_free(router->identity_pkey); @@ -2957,6 +2957,24 @@ router_reset_descriptor_download_failures(void) /** We allow uptime to vary from how much it ought to be by this much. */ #define ROUTER_ALLOW_UPTIME_DRIFT (6*60*60) +/** Return true iff r1 and r2 have the same TAP onion keys. */ +static int +router_tap_onion_keys_eq(const routerinfo_t *r1, const routerinfo_t *r2) +{ + if (r1->tap_onion_pkey_len != r2->tap_onion_pkey_len) + return 0; + + if ((r1->tap_onion_pkey == NULL) && (r2->tap_onion_pkey == NULL)) { + return 1; + } else if ((r1->tap_onion_pkey != NULL) && (r2->tap_onion_pkey != NULL)) { + return tor_memeq(r1->tap_onion_pkey, r2->tap_onion_pkey, + r1->tap_onion_pkey_len); + } else { + /* One is NULL; one is not. */ + return 0; + } +} + /** Return true iff the only differences between r1 and r2 are such that * would not cause a recent (post 0.1.1.6) dirserver to republish. */ @@ -2982,8 +3000,7 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2) r1->ipv6_orport != r2->ipv6_orport || r1->ipv4_dirport != r2->ipv4_dirport || r1->purpose != r2->purpose || - r1->onion_pkey_len != r2->onion_pkey_len || - !tor_memeq(r1->onion_pkey, r2->onion_pkey, r1->onion_pkey_len) || + !router_tap_onion_keys_eq(r1,r2) || !crypto_pk_eq_keys(r1->identity_pkey, r2->identity_pkey) || strcasecmp(r1->platform, r2->platform) || (r1->contact_info && !r2->contact_info) || /* contact_info is optional */ diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c index ce6cbe6df4..5ece5b4adc 100644 --- a/src/feature/relay/circuitbuild_relay.c +++ b/src/feature/relay/circuitbuild_relay.c @@ -389,7 +389,6 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec, circ->n_hop = extend_info_new(NULL /*nickname*/, (const char*)ec->node_id, &ec->ed_pubkey, - NULL, /*onion_key*/ NULL, /*curve25519_key*/ &chosen_ap->addr, chosen_ap->port, @@ -443,6 +442,12 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ) relay_header_unpack(&rh, cell->payload); + /* We no longer accept EXTEND messages; only EXTEND2. */ + if (rh.command == RELAY_COMMAND_EXTEND) { + /* TODO: Should we log this? */ + return -1; + } + if (extend_cell_parse(&ec, rh.command, cell->payload+RELAY_HEADER_SIZE, rh.length) < 0) { diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c index f6a020d061..eb31678189 100644 --- a/src/feature/relay/dns.c +++ b/src/feature/relay/dns.c @@ -563,6 +563,12 @@ send_resolved_cell,(edge_connection_t *conn, uint8_t answer_type, connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen); } +void +dns_send_resolved_error_cell(edge_connection_t *conn, uint8_t answer_type) +{ + send_resolved_cell(conn, answer_type, NULL); +} + /** Send a response to the RESOLVE request of a connection for an in-addr.arpa * address on connection <b>conn</b> which yielded the result <b>hostname</b>. * The answer type will be RESOLVED_HOSTNAME. @@ -1178,8 +1184,8 @@ dns_found_answer(const char *address, uint8_t query_type, * resolution. * * Do this by sending a RELAY_RESOLVED cell (if the pending stream had sent us - * RELAY_RESOLVE cell), or by launching an exit connection (if the pending - * stream had send us a RELAY_BEGIN cell). + * a RELAY_RESOLVE cell), or by launching an exit connection (if the pending + * stream had sent us a RELAY_BEGIN cell). */ static void inform_pending_connections(cached_resolve_t *resolve) diff --git a/src/feature/relay/dns.h b/src/feature/relay/dns.h index 3f8519bd97..5de70039d4 100644 --- a/src/feature/relay/dns.h +++ b/src/feature/relay/dns.h @@ -20,6 +20,8 @@ int dns_reset(void); void connection_dns_remove(edge_connection_t *conn); void assert_connection_edge_not_dns_pending(edge_connection_t *conn); int dns_resolve(edge_connection_t *exitconn); +void dns_send_resolved_error_cell(edge_connection_t *conn, + uint8_t answer_type); int dns_seems_to_be_broken(void); int dns_seems_to_be_broken_for_ipv6(void); void dns_reset_correctness_checks(void); @@ -36,6 +38,8 @@ void dns_launch_correctness_checks(void); #else /* !defined(HAVE_MODULE_RELAY) */ #define dns_init() (0) +#define dns_send_resolved_error_cell(conn, answer_type) \ + ((void)(conn), (void)(answer_type)) #define dns_seems_to_be_broken() (0) #define has_dns_init_failed() (0) #define dns_cache_total_allocation() (0) diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c index f3f4b169f4..9632b51063 100644 --- a/src/feature/relay/onion_queue.c +++ b/src/feature/relay/onion_queue.c @@ -50,10 +50,6 @@ #define ONION_QUEUE_MAX_DELAY_MIN 1 #define ONION_QUEUE_MAX_DELAY_MAX INT32_MAX -#define NUM_NTORS_PER_TAP_DEFAULT 10 -#define NUM_NTORS_PER_TAP_MIN 1 -#define NUM_NTORS_PER_TAP_MAX 100000 - /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ typedef struct onion_queue_t { @@ -84,17 +80,9 @@ static int ol_entries[MAX_QUEUE_IDX+1]; static void onion_queue_entry_remove(onion_queue_t *victim); /** Consensus parameters. */ -static int32_t ns_num_ntors_per_tap = NUM_NTORS_PER_TAP_DEFAULT; static time_t ns_onion_queue_wait_cutoff = ONION_QUEUE_WAIT_CUTOFF_DEFAULT; static uint32_t ns_onion_queue_max_delay = ONION_QUEUE_MAX_DELAY_DEFAULT; -/** Return the number of ntors per tap from the cached parameter. */ -static inline int32_t -get_num_ntors_per_tap(void) -{ - return ns_num_ntors_per_tap; -} - /** Return the onion queue wait cutoff value from the cached parameter. */ static inline time_t get_onion_queue_wait_cutoff(void) @@ -146,8 +134,12 @@ have_room_for_onionskin(uint16_t type) const or_options_t *options = get_options(); int num_cpus; uint64_t max_onion_queue_delay; - uint64_t tap_usec, ntor_usec; - uint64_t ntor_during_tap_usec, tap_during_ntor_usec; + uint64_t ntor_usec; + + /* We never allow TAP. */ + if (type == ONION_HANDSHAKE_TYPE_TAP) { + return 0; + } /* If we've got fewer than 50 entries, we always have room for one more. */ if (ol_entries[type] < 50) @@ -164,44 +156,15 @@ have_room_for_onionskin(uint16_t type) /* Compute how many microseconds we'd expect to need to clear all * onionskins in various combinations of the queues. */ - /* How long would it take to process all the TAP cells in the queue? */ - tap_usec = estimated_usec_for_onionskins( - ol_entries[ONION_HANDSHAKE_TYPE_TAP], - ONION_HANDSHAKE_TYPE_TAP) / num_cpus; - /* How long would it take to process all the NTor cells in the queue? */ ntor_usec = estimated_usec_for_onionskins( ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; - /* How long would it take to process the tap cells that we expect to - * process while draining the ntor queue? */ - tap_during_ntor_usec = estimated_usec_for_onionskins( - MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP], - ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / get_num_ntors_per_tap()), - ONION_HANDSHAKE_TYPE_TAP) / num_cpus; - - /* How long would it take to process the ntor cells that we expect to - * process while draining the tap queue? */ - ntor_during_tap_usec = estimated_usec_for_onionskins( - MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR], - ol_entries[ONION_HANDSHAKE_TYPE_TAP] * get_num_ntors_per_tap()), - ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; - /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue * this. */ if (type == ONION_HANDSHAKE_TYPE_NTOR && - (ntor_usec + tap_during_ntor_usec) / 1000 > max_onion_queue_delay) - return 0; - - if (type == ONION_HANDSHAKE_TYPE_TAP && - (tap_usec + ntor_during_tap_usec) / 1000 > max_onion_queue_delay) - return 0; - - /* If we support the ntor handshake, then don't let TAP handshakes use - * more than 2/3 of the space on the queue. */ - if (type == ONION_HANDSHAKE_TYPE_TAP && - tap_usec / 1000 > max_onion_queue_delay * 2 / 3) + (ntor_usec / 1000) > max_onion_queue_delay) return 0; return 1; @@ -292,38 +255,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) static uint16_t decide_next_handshake_type(void) { - /* The number of times we've chosen ntor lately when both were available. */ - static int recently_chosen_ntors = 0; - - if (!ol_entries[ONION_HANDSHAKE_TYPE_NTOR]) - return ONION_HANDSHAKE_TYPE_TAP; /* no ntors? try tap */ - - if (!ol_entries[ONION_HANDSHAKE_TYPE_TAP]) { - - /* Nick wants us to prioritize new tap requests when there aren't - * any in the queue and we've processed k ntor cells since the last - * tap cell. This strategy is maybe a good idea, since it starves tap - * less in the case where tap is rare, or maybe a poor idea, since it - * makes the new tap cell unfairly jump in front of ntor cells that - * got here first. In any case this edge case will only become relevant - * once tap is rare. We should reevaluate whether we like this decision - * once tap gets more rare. */ - if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] && - recently_chosen_ntors <= get_num_ntors_per_tap()) - ++recently_chosen_ntors; - - return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */ - } - - /* They both have something queued. Pick ntor if we haven't done that - * too much lately. */ - if (++recently_chosen_ntors <= get_num_ntors_per_tap()) { - return ONION_HANDSHAKE_TYPE_NTOR; - } - - /* Else, it's time to let tap have its turn. */ - recently_chosen_ntors = 0; - return ONION_HANDSHAKE_TYPE_TAP; + return ONION_HANDSHAKE_TYPE_NTOR; } /** Remove the highest priority item from ol_list[] and return it, or @@ -445,10 +377,4 @@ onion_consensus_has_changed(const networkstatus_t *ns) ONION_QUEUE_WAIT_CUTOFF_DEFAULT, ONION_QUEUE_WAIT_CUTOFF_MIN, ONION_QUEUE_WAIT_CUTOFF_MAX); - - ns_num_ntors_per_tap = - networkstatus_get_param(ns, "NumNTorsPerTAP", - NUM_NTORS_PER_TAP_DEFAULT, - NUM_NTORS_PER_TAP_MIN, - NUM_NTORS_PER_TAP_MAX); } diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c index 0b02461318..320ce8d13a 100644 --- a/src/feature/relay/relay_config.c +++ b/src/feature/relay/relay_config.c @@ -1151,8 +1151,8 @@ options_validate_relay_mode(const or_options_t *old_options, REJECT("BridgeRelay is 1, ORPort is not set. This is an invalid " "combination."); - if (options->BridgeRelay == 1 && (options->ExitRelay == 1 || - !policy_using_default_exit_options(options))) { + if (options->BridgeRelay == 1 && !(options->ExitRelay == 0 || + policy_using_default_exit_options(options))) { log_warn(LD_CONFIG, "BridgeRelay is 1, but ExitRelay is 1 or an " "ExitPolicy is configured. Tor will start, but it will not " "function as an exit relay."); diff --git a/src/feature/relay/relay_metrics.c b/src/feature/relay/relay_metrics.c index 8f3b82bd96..492a5945b8 100644 --- a/src/feature/relay/relay_metrics.c +++ b/src/feature/relay/relay_metrics.c @@ -13,6 +13,7 @@ #include "core/or/or.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" +#include "core/or/command.h" #include "core/or/congestion_control_common.h" #include "core/or/congestion_control_vegas.h" #include "core/or/congestion_control_flow.h" @@ -54,6 +55,9 @@ static void fill_socket_values(void); static void fill_onionskins_values(void); static void fill_oom_values(void); static void fill_streams_values(void); +static void fill_relay_circ_proto_violation(void); +static void fill_relay_destroy_cell(void); +static void fill_relay_drop_cell(void); static void fill_relay_flags(void); static void fill_tcp_exhaustion_values(void); static void fill_traffic_values(void); @@ -217,6 +221,27 @@ static const relay_metrics_entry_t base_metrics[] = .help = "Total number of REND1 cells we received", .fill_fn = fill_rend1_cells, }, + { + .key = RELAY_METRICS_CIRC_DESTROY_CELL, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_destroy_cell_total), + .help = "Total number of DESTROY cell we received", + .fill_fn = fill_relay_destroy_cell, + }, + { + .key = RELAY_METRICS_CIRC_PROTO_VIOLATION, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_circ_proto_violation_total), + .help = "Total number of circuit protocol violation", + .fill_fn = fill_relay_circ_proto_violation, + }, + { + .key = RELAY_METRICS_CIRC_DROP_CELL, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_drop_cell_total), + .help = "Total number of DROP cell we received", + .fill_fn = fill_relay_drop_cell, + }, }; static const size_t num_base_metrics = ARRAY_LENGTH(base_metrics); @@ -433,6 +458,12 @@ fill_dos_values(void) metrics_store_entry_add_label(sentry, metrics_format_label("type", "introduce2_rejected")); metrics_store_entry_update(sentry, hs_dos_get_intro2_rejected_count()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "stream_rejected")); + metrics_store_entry_update(sentry, dos_get_num_stream_rejected()); } /** Fill function for the RELAY_METRICS_CC_COUNTERS metric. */ @@ -1200,6 +1231,46 @@ fill_rend1_cells(void) } } +/** Fill the metrics store for the RELAY_METRICS_CIRC_DESTROY_CELL counter. */ +static void +fill_relay_destroy_cell(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CIRC_DESTROY_CELL]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_update(sentry, + (int64_t) stats_n_destroy_cells_processed); +} + +/** Fill the metrics store for the RELAY_METRICS_CIRC_DROP_CELL counter. */ +static void +fill_relay_drop_cell(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CIRC_DROP_CELL]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_update(sentry, rep_hist_get_drop_cell_received_count()); +} + +/** Fill the metrics store for the RELAY_METRICS_CIRC_PROTO_VIOLATION. */ +static void +fill_relay_circ_proto_violation(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CIRC_PROTO_VIOLATION]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help, 0, NULL); + metrics_store_entry_update(sentry, circ_n_proto_violation); +} + /** Reset the global store and fill it with all the metrics from base_metrics * and their associated values. * diff --git a/src/feature/relay/relay_metrics.h b/src/feature/relay/relay_metrics.h index cf9dddf955..e7b5b660fa 100644 --- a/src/feature/relay/relay_metrics.h +++ b/src/feature/relay/relay_metrics.h @@ -57,6 +57,12 @@ typedef enum { RELAY_METRICS_NUM_INTRO1_CELLS, /** Number of times we received a REND1 cell */ RELAY_METRICS_NUM_REND1_CELLS, + /** Number of circuit closed by receiving a DESTROY cell. */ + RELAY_METRICS_CIRC_DESTROY_CELL, + /** Number of circuits closed due to protocol violation. */ + RELAY_METRICS_CIRC_PROTO_VIOLATION, + /** Number of drop cell seen. */ + RELAY_METRICS_CIRC_DROP_CELL, } relay_metrics_key_t; /** The metadata of a relay metric. */ diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 1ed9630e09..ab5fe697bc 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -211,8 +211,13 @@ set_onion_key(crypto_pk_t *k) mark_my_descriptor_dirty("set onion key"); } -/** Return the current onion key. Requires that the onion key has been - * loaded or generated. */ +/** Return the current TAP onion key. Requires that the onion key has been + * loaded or generated. + * + * Note that this key is no longer used for anything; we only keep it around + * because (as of June 2024) other Tor instances all expect to find it in + * our routerdescs. + **/ MOCK_IMPL(crypto_pk_t *, get_onion_key,(void)) { @@ -220,6 +225,25 @@ get_onion_key,(void)) return onionkey; } +/** + * Return true iff we should include our TAP onion key in our router + * descriptor. + */ +static int +should_publish_tap_onion_key(void) +{ +#define SHOULD_PUBLISH_TAP_MIN 0 +#define SHOULD_PUBLISH_TAP_MAX 1 + /* Note that we err on the side of publishing. */ +#define SHOULD_PUBLISH_TAP_DFLT 1 + + return networkstatus_get_param(NULL, + "publish-dummy-tap-key", + SHOULD_PUBLISH_TAP_DFLT, + SHOULD_PUBLISH_TAP_MIN, + SHOULD_PUBLISH_TAP_MAX); +} + /** Store a full copy of the current onion key into *<b>key</b>, and a full * copy of the most recent onion key into *<b>last</b>. Store NULL into * a pointer if the corresponding key does not exist. @@ -2138,9 +2162,12 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)) ri->supports_tunnelled_dir_requests = directory_permits_begindir_requests(options); ri->cache_info.published_on = time(NULL); - /* get_onion_key() must invoke from main thread */ - router_set_rsa_onion_pkey(get_onion_key(), &ri->onion_pkey, - &ri->onion_pkey_len); + + if (should_publish_tap_onion_key()) { + /* get_onion_key() must invoke from main thread */ + router_set_rsa_onion_pkey(get_onion_key(), &ri->tap_onion_pkey, + &ri->tap_onion_pkey_len); + } ri->onion_curve25519_pkey = tor_memdup(&get_current_curve25519_keypair()->pubkey, @@ -2777,7 +2804,7 @@ router_dump_router_to_string(routerinfo_t *router, char published[ISO_TIME_LEN+1]; char fingerprint[FINGERPRINT_LEN+1]; char *extra_info_line = NULL; - size_t onion_pkeylen, identity_pkeylen; + size_t onion_pkeylen=0, identity_pkeylen; char *family_line = NULL; char *extra_or_address = NULL; const or_options_t *options = get_options(); @@ -2835,12 +2862,14 @@ router_dump_router_to_string(routerinfo_t *router, } /* PEM-encode the onion key */ - rsa_pubkey = router_get_rsa_onion_pkey(router->onion_pkey, - router->onion_pkey_len); - if (crypto_pk_write_public_key_to_string(rsa_pubkey, - &onion_pkey,&onion_pkeylen)<0) { - log_warn(LD_BUG,"write onion_pkey to string failed!"); - goto err; + rsa_pubkey = router_get_rsa_onion_pkey(router->tap_onion_pkey, + router->tap_onion_pkey_len); + if (rsa_pubkey) { + if (crypto_pk_write_public_key_to_string(rsa_pubkey, + &onion_pkey,&onion_pkeylen)<0) { + log_warn(LD_BUG,"write onion_pkey to string failed!"); + goto err; + } } /* PEM-encode the identity key */ @@ -2851,7 +2880,7 @@ router_dump_router_to_string(routerinfo_t *router, } /* Cross-certify with RSA key */ - if (tap_key && router->cache_info.signing_key_cert && + if (tap_key && rsa_pubkey && router->cache_info.signing_key_cert && router->cache_info.signing_key_cert->signing_key_included) { char buf[256]; int tap_cc_len = 0; @@ -2976,7 +3005,7 @@ router_dump_router_to_string(routerinfo_t *router, "uptime %ld\n" "bandwidth %d %d %d\n" "%s%s" - "onion-key\n%s" + "%s%s" "signing-key\n%s" "%s%s" "%s%s%s", @@ -2997,7 +3026,8 @@ router_dump_router_to_string(routerinfo_t *router, extra_info_line ? extra_info_line : "", (options->DownloadExtraInfo || options->V3AuthoritativeDir) ? "caches-extra-info\n" : "", - onion_pkey, identity_pkey, + onion_pkey?"onion-key\n":"", onion_pkey?onion_pkey:"", + identity_pkey, rsa_tap_cc_line ? rsa_tap_cc_line : "", ntor_cc_line ? ntor_cc_line : "", family_line, diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c index 399b6bca6e..0a80a5d47e 100644 --- a/src/feature/relay/selftest.c +++ b/src/feature/relay/selftest.c @@ -201,7 +201,6 @@ have_orport_for_family(int family) static extend_info_t * extend_info_from_router(const routerinfo_t *r, int family) { - crypto_pk_t *rsa_pubkey; extend_info_t *info; tor_addr_port_t ap; @@ -224,15 +223,14 @@ extend_info_from_router(const routerinfo_t *r, int family) /* We don't have an ORPort for the requested family. */ return NULL; } - rsa_pubkey = router_get_rsa_onion_pkey(r->onion_pkey, r->onion_pkey_len); info = extend_info_new(r->nickname, r->cache_info.identity_digest, ed_id_key, - rsa_pubkey, r->onion_curve25519_pkey, + r->onion_curve25519_pkey, &ap.addr, ap.port, /* TODO-324: Should self-test circuits use * congestion control? */ NULL, false); - crypto_pk_free(rsa_pubkey); + return info; } diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c index 8f4f33151a..055081fc7c 100644 --- a/src/feature/stats/rephist.c +++ b/src/feature/stats/rephist.c @@ -280,6 +280,9 @@ static dns_stats_t dns_AAAA_stats; /** DNS query statistics store. It covers all type of queries. */ static dns_stats_t dns_all_stats; +/** Counter of the total number of DROP cell received. */ +static uint64_t relay_circ_n_drop_cell_received = 0; + /** Return the point to the DNS statistics store. Ignore the type for now * because of a libevent problem. */ static inline dns_stats_t * @@ -2290,19 +2293,14 @@ typedef struct { /** Keep track of the onionskin requests for an assessment period. */ static overload_onionskin_assessment_t overload_onionskin_assessment; -/** - * We combine ntorv3 and ntor into the same stat, so we must - * use this function to convert the cell type to a stat index. +/** This function ensures that we clamp the maximum value of the given input + * <b>type</b> to NTOR in case the input is out of range. */ static inline uint16_t onionskin_type_to_stat(uint16_t type) { - if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) { - return ONION_HANDSHAKE_TYPE_NTOR; - } - if (BUG(type > MAX_ONION_STAT_TYPE)) { - return MAX_ONION_STAT_TYPE; // use ntor if out of range + return MAX_ONION_STAT_TYPE; // use ntor_v3 if out of range } return type; @@ -2371,7 +2369,8 @@ rep_hist_note_circuit_handshake_requested(uint16_t type) onion_handshakes_requested[stat]++; /* Only relays get to record requested onionskins. */ - if (stat == ONION_HANDSHAKE_TYPE_NTOR) { + if (stat == ONION_HANDSHAKE_TYPE_NTOR || + stat == ONION_HANDSHAKE_TYPE_NTOR_V3) { /* Assess if we've reached the overload general signal. */ overload_general_onionskin_assessment(); @@ -2398,7 +2397,8 @@ rep_hist_note_circuit_handshake_dropped(uint16_t type) stats_n_onionskin_dropped[stat]++; /* Only relays get to record requested onionskins. */ - if (stat == ONION_HANDSHAKE_TYPE_NTOR) { + if (stat == ONION_HANDSHAKE_TYPE_NTOR || + stat == ONION_HANDSHAKE_TYPE_NTOR_V3) { /* Note the dropped ntor in the overload assessment object. */ overload_onionskin_assessment.n_ntor_dropped++; } @@ -2438,11 +2438,13 @@ rep_hist_log_circuit_handshake_stats(time_t now) { (void)now; log_notice(LD_HEARTBEAT, "Circuit handshake stats since last time: " - "%d/%d TAP, %d/%d NTor.", + "%d/%d TAP, %d/%d NTor, %d/%d NTor (v3).", onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_TAP], onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP], onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR], - onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR]); + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR], + onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR_V3], + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR_V3]); memset(onion_handshakes_assigned, 0, sizeof(onion_handshakes_assigned)); memset(onion_handshakes_requested, 0, sizeof(onion_handshakes_requested)); } @@ -2816,6 +2818,8 @@ rep_hist_padding_count_write(padding_type_t type) switch (type) { case PADDING_TYPE_DROP: padding_current.write_drop_cell_count++; + /* Padding stats get reset thus why we have two counters. */ + relay_circ_n_drop_cell_received++; break; case PADDING_TYPE_CELL: padding_current.write_pad_cell_count++; @@ -3023,6 +3027,13 @@ rep_hist_consensus_has_changed(const networkstatus_t *ns) OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MAX); } +/** Relay Only: return the total number of DROP cell received. */ +uint64_t +rep_hist_get_drop_cell_received_count(void) +{ + return relay_circ_n_drop_cell_received; +} + #ifdef TOR_UNIT_TESTS /* only exists for unit tests: get HSv2 stats object */ const hs_v2_stats_t * diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h index fbfab4c451..f595459580 100644 --- a/src/feature/stats/rephist.h +++ b/src/feature/stats/rephist.h @@ -102,8 +102,8 @@ void rep_hist_note_dns_error(int type, uint8_t error); void rep_hist_consensus_has_changed(const networkstatus_t *ns); /** We combine ntor and ntorv3 stats, so we have 3 stat types: - * tap, fast, and ntor. The max type is ntor (2) */ -#define MAX_ONION_STAT_TYPE ONION_HANDSHAKE_TYPE_NTOR + * tap, fast, and ntor. The max type is ntor_v3 (3) */ +#define MAX_ONION_STAT_TYPE MAX_ONION_HANDSHAKE_TYPE extern uint64_t rephist_total_alloc; extern uint32_t rephist_total_num; @@ -192,6 +192,8 @@ uint64_t rep_hist_get_n_tcp_exhaustion(void); uint64_t rep_hist_get_n_read_limit_reached(void); uint64_t rep_hist_get_n_write_limit_reached(void); +uint64_t rep_hist_get_drop_cell_received_count(void); + #ifdef TOR_UNIT_TESTS struct hs_v2_stats_t; const struct hs_v2_stats_t *rep_hist_get_hs_v2_stats(void); |