diff options
Diffstat (limited to 'src')
34 files changed, 567 insertions, 404 deletions
diff --git a/src/common/aes.c b/src/common/aes.c index 5d0841dfa3..95737cffcc 100644 --- a/src/common/aes.c +++ b/src/common/aes.c @@ -116,7 +116,11 @@ aes_cipher_free_(aes_cnt_cipher_t *cipher_) if (!cipher_) return; EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) + EVP_CIPHER_CTX_reset(cipher); +#else EVP_CIPHER_CTX_cleanup(cipher); +#endif EVP_CIPHER_CTX_free(cipher); } void diff --git a/src/common/crypto.c b/src/common/crypto.c index 9fcd17742c..c98a968757 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -43,6 +43,7 @@ DISABLE_GCC_WARNING(redundant-decls) #include <openssl/dh.h> #include <openssl/conf.h> #include <openssl/hmac.h> +#include <openssl/ssl.h> ENABLE_GCC_WARNING(redundant-decls) @@ -204,8 +205,15 @@ crypto_early_init(void) crypto_early_initialized_ = 1; +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | + OPENSSL_INIT_LOAD_CRYPTO_STRINGS | + OPENSSL_INIT_ADD_ALL_CIPHERS | + OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); +#else ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); +#endif setup_openssl_threading(); @@ -1660,11 +1668,15 @@ memwipe(void *mem, uint8_t byte, size_t sz) int crypto_global_cleanup(void) { +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) EVP_cleanup(); +#endif #ifndef NEW_THREAD_API ERR_remove_thread_state(NULL); #endif +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) ERR_free_strings(); +#endif if (dh_param_p) BN_clear_free(dh_param_p); @@ -1676,11 +1688,15 @@ crypto_global_cleanup(void) dh_param_p = dh_param_p_tls = dh_param_g = NULL; #ifndef DISABLE_ENGINES +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) ENGINE_cleanup(); #endif +#endif CONF_modules_unload(1); +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) CRYPTO_cleanup_all_ex_data(); +#endif crypto_openssl_free_all(); diff --git a/src/common/torint.h b/src/common/torint.h index 0b8061d24f..fc7818fe2c 100644 --- a/src/common/torint.h +++ b/src/common/torint.h @@ -40,6 +40,8 @@ #include <inttypes.h> #endif +#include <stdbool.h> + #if (SIZEOF_INT8_T != 0) #define HAVE_INT8_T #endif diff --git a/src/common/tortls.c b/src/common/tortls.c index 05e29e22ff..cd236363f8 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -56,10 +56,25 @@ ENABLE_GCC_WARNING(redundant-decls) #include "container.h" #include <string.h> +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) +#define X509_get_notBefore_const(cert) \ + X509_get0_notBefore(cert) +#define X509_get_notAfter_const(cert) \ + X509_get0_notAfter(cert) +#ifndef X509_get_notBefore +#define X509_get_notBefore(cert) \ + X509_getm_notBefore(cert) +#endif +#ifndef X509_get_notAfter +#define X509_get_notAfter(cert) \ + X509_getm_notAfter(cert) +#endif +#else /* ! OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */ #define X509_get_notBefore_const(cert) \ ((const ASN1_TIME*) X509_get_notBefore((X509 *)cert)) #define X509_get_notAfter_const(cert) \ ((const ASN1_TIME*) X509_get_notAfter((X509 *)cert)) +#endif /* Copied from or.h */ #define LEGAL_NICKNAME_CHARACTERS \ @@ -355,8 +370,12 @@ tor_tls_init(void) check_no_tls_errors(); if (!tls_library_is_initialized) { +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); +#else SSL_library_init(); SSL_load_error_strings(); +#endif #if (SIZEOF_VOID_P >= 8 && \ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1)) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index c33dbbeb2d..24c32b710c 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -2802,16 +2802,13 @@ extend_info_from_node(const node_t *node, int for_direct_connect) return NULL; } - /* Choose a preferred address first, but fall back to an allowed address. - * choose_address returns 1 on success, but get_prim_orport returns 0. */ + /* Choose a preferred address first, but fall back to an allowed address. */ if (for_direct_connect) - valid_addr = fascist_firewall_choose_address_node(node, - FIREWALL_OR_CONNECTION, - 0, &ap); + fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, &ap); else { node_get_prim_orport(node, &ap); - valid_addr = tor_addr_port_is_valid_ap(&ap, 0); } + valid_addr = tor_addr_port_is_valid_ap(&ap, 0); if (valid_addr) log_debug(LD_CIRC, "using %s for %s", diff --git a/src/or/config.c b/src/or/config.c index 8f5839e2d5..3719ac8847 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -127,6 +127,11 @@ static const char unix_socket_prefix[] = "unix:"; * configuration. */ static const char unix_q_socket_prefix[] = "unix:\""; +/** macro to help with the bulk rename of *DownloadSchedule to + * *DowloadInitialDelay . */ +#define DOWNLOAD_SCHEDULE(name) \ + { #name "DownloadSchedule", #name "DownloadInitialDelay", 0, 1 } + /** A list of abbreviations and aliases to map command-line options, obsolete * option names, or alternative option names, to their current values. */ static config_abbrev_t option_abbrevs_[] = { @@ -176,6 +181,16 @@ static config_abbrev_t option_abbrevs_[] = { { "_HSLayer2Nodes", "HSLayer2Nodes", 0, 1 }, { "_HSLayer3Nodes", "HSLayer3Nodes", 0, 1 }, + DOWNLOAD_SCHEDULE(ClientBootstrapConsensusAuthority), + DOWNLOAD_SCHEDULE(ClientBootstrapConsensusAuthorityOnly), + DOWNLOAD_SCHEDULE(ClientBootstrapConsensusFallback), + DOWNLOAD_SCHEDULE(TestingBridge), + DOWNLOAD_SCHEDULE(TestingBridgeBootstrap), + DOWNLOAD_SCHEDULE(TestingClient), + DOWNLOAD_SCHEDULE(TestingClientConsensus), + DOWNLOAD_SCHEDULE(TestingServer), + DOWNLOAD_SCHEDULE(TestingServerConsensus), + { NULL, NULL, 0, 0}, }; @@ -458,6 +473,7 @@ static config_var_t option_vars_[] = { V(NumCPUs, UINT, "0"), V(NumDirectoryGuards, UINT, "0"), V(NumEntryGuards, UINT, "0"), + V(NumPrimaryGuards, UINT, "0"), V(OfflineMasterKey, BOOL, "0"), OBSOLETE("ORListenAddress"), VPORT(ORPort), @@ -600,16 +616,10 @@ static config_var_t option_vars_[] = { VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL), VAR("__OwningControllerFD",INT,OwningControllerFD, "-1"), V(MinUptimeHidServDirectoryV2, INTERVAL, "96 hours"), - V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, " - "300, 900, 2147483647"), - V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 60, 300, 600, " - "2147483647"), - V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, " - "300, 600, 1800, 1800, 1800, 1800, " - "1800, 3600, 7200"), - V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, " - "300, 600, 1800, 3600, 3600, 3600, " - "10800, 21600, 43200"), + V(TestingServerDownloadInitialDelay, CSV_INTERVAL, "0"), + V(TestingClientDownloadInitialDelay, CSV_INTERVAL, "0"), + V(TestingServerConsensusDownloadInitialDelay, CSV_INTERVAL, "0"), + V(TestingClientConsensusDownloadInitialDelay, CSV_INTERVAL, "0"), /* With the ClientBootstrapConsensus*Download* below: * Clients with only authorities will try: * - at least 3 authorities over 10 seconds, then exponentially backoff, @@ -625,13 +635,11 @@ static config_var_t option_vars_[] = { * * When clients have authorities and fallbacks available, they use these * schedules: (we stagger the times to avoid thundering herds) */ - V(ClientBootstrapConsensusAuthorityDownloadSchedule, CSV_INTERVAL, - "6, 11, 3600, 10800, 25200, 54000, 111600, 262800" /* 3 days + 1 hour */), - V(ClientBootstrapConsensusFallbackDownloadSchedule, CSV_INTERVAL, - "0, 1, 4, 11, 3600, 10800, 25200, 54000, 111600, 262800"), + V(ClientBootstrapConsensusAuthorityDownloadInitialDelay, CSV_INTERVAL, "6"), + V(ClientBootstrapConsensusFallbackDownloadInitialDelay, CSV_INTERVAL, "0"), /* When clients only have authorities available, they use this schedule: */ - V(ClientBootstrapConsensusAuthorityOnlyDownloadSchedule, CSV_INTERVAL, - "0, 3, 7, 3600, 10800, 25200, 54000, 111600, 262800"), + V(ClientBootstrapConsensusAuthorityOnlyDownloadInitialDelay, CSV_INTERVAL, + "0"), /* We don't want to overwhelm slow networks (or mirrors whose replies are * blocked), but we also don't want to fail if only some mirrors are * blackholed. Clients will try 3 directories simultaneously. @@ -639,14 +647,12 @@ static config_var_t option_vars_[] = { V(ClientBootstrapConsensusMaxInProgressTries, UINT, "3"), /* When a client has any running bridges, check each bridge occasionally, * whether or not that bridge is actually up. */ - V(TestingBridgeDownloadSchedule, CSV_INTERVAL, - "10800, 25200, 54000, 111600, 262800"), + V(TestingBridgeDownloadInitialDelay, CSV_INTERVAL,"10800"), /* When a client is just starting, or has no running bridges, check each * bridge a few times quickly, and then try again later. These schedules * are much longer than the other schedules, because we try each and every * configured bridge with this schedule. */ - V(TestingBridgeBootstrapDownloadSchedule, CSV_INTERVAL, - "0, 30, 90, 600, 3600, 10800, 25200, 54000, 111600, 262800"), + V(TestingBridgeBootstrapDownloadInitialDelay, CSV_INTERVAL, "0"), V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "10 minutes"), V(TestingDirConnectionMaxStall, INTERVAL, "5 minutes"), OBSOLETE("TestingConsensusMaxDownloadTries"), @@ -673,12 +679,10 @@ static const config_var_t testing_tor_network_defaults[] = { V(EnforceDistinctSubnets, BOOL, "0"), V(AssumeReachable, BOOL, "1"), V(AuthDirMaxServersPerAddr, UINT, "0"), - V(ClientBootstrapConsensusAuthorityDownloadSchedule, CSV_INTERVAL, - "0, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 16, 32, 60"), - V(ClientBootstrapConsensusFallbackDownloadSchedule, CSV_INTERVAL, - "0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 16, 32, 60"), - V(ClientBootstrapConsensusAuthorityOnlyDownloadSchedule, CSV_INTERVAL, - "0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 16, 32, 60"), + V(ClientBootstrapConsensusAuthorityDownloadInitialDelay, CSV_INTERVAL, "0"), + V(ClientBootstrapConsensusFallbackDownloadInitialDelay, CSV_INTERVAL, "0"), + V(ClientBootstrapConsensusAuthorityOnlyDownloadInitialDelay, CSV_INTERVAL, + "0"), V(ClientDNSRejectInternalAddresses, BOOL,"0"), V(ClientRejectInternalAddresses, BOOL, "0"), V(CountPrivateBandwidth, BOOL, "1"), @@ -693,17 +697,12 @@ static const config_var_t testing_tor_network_defaults[] = { V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"), V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"), V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"), - V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 5, 10, 15, " - "20, 30, 60"), - V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, 15, 20, " - "30, 60"), - V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, " - "15, 20, 30, 60"), - V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, " - "15, 20, 30, 60"), - V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "10, 30, 60"), - V(TestingBridgeBootstrapDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, " - "15, 20, 30, 60"), + V(TestingServerDownloadInitialDelay, CSV_INTERVAL, "0"), + V(TestingClientDownloadInitialDelay, CSV_INTERVAL, "0"), + V(TestingServerConsensusDownloadInitialDelay, CSV_INTERVAL, "0"), + V(TestingClientConsensusDownloadInitialDelay, CSV_INTERVAL, "0"), + V(TestingBridgeDownloadInitialDelay, CSV_INTERVAL, "10"), + V(TestingBridgeBootstrapDownloadInitialDelay, CSV_INTERVAL, "0"), V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "5 seconds"), V(TestingDirConnectionMaxStall, INTERVAL, "30 seconds"), V(TestingEnableConnBwEvent, BOOL, "1"), @@ -3776,6 +3775,11 @@ options_validate(or_options_t *old_options, or_options_t *options, "http://freehaven.net/anonbib/#hs-attack06 for details."); } + if (options->NumPrimaryGuards && options->NumEntryGuards && + options->NumEntryGuards > options->NumPrimaryGuards) { + REJECT("NumEntryGuards must not be greater than NumPrimaryGuards."); + } + if (options->EntryNodes && routerset_is_list(options->EntryNodes) && (routerset_len(options->EntryNodes) == 1) && @@ -4374,12 +4378,12 @@ options_validate(or_options_t *old_options, or_options_t *options, CHECK_DEFAULT(TestingV3AuthVotingStartOffset); CHECK_DEFAULT(TestingAuthDirTimeToLearnReachability); CHECK_DEFAULT(TestingEstimatedDescriptorPropagationTime); - CHECK_DEFAULT(TestingServerDownloadSchedule); - CHECK_DEFAULT(TestingClientDownloadSchedule); - CHECK_DEFAULT(TestingServerConsensusDownloadSchedule); - CHECK_DEFAULT(TestingClientConsensusDownloadSchedule); - CHECK_DEFAULT(TestingBridgeDownloadSchedule); - CHECK_DEFAULT(TestingBridgeBootstrapDownloadSchedule); + CHECK_DEFAULT(TestingServerDownloadInitialDelay); + CHECK_DEFAULT(TestingClientDownloadInitialDelay); + CHECK_DEFAULT(TestingServerConsensusDownloadInitialDelay); + CHECK_DEFAULT(TestingClientConsensusDownloadInitialDelay); + CHECK_DEFAULT(TestingBridgeDownloadInitialDelay); + CHECK_DEFAULT(TestingBridgeBootstrapDownloadInitialDelay); CHECK_DEFAULT(TestingClientMaxIntervalWithoutRequest); CHECK_DEFAULT(TestingDirConnectionMaxStall); CHECK_DEFAULT(TestingAuthKeyLifetime); @@ -8102,7 +8106,10 @@ getinfo_helper_config(control_connection_t *conn, case CONFIG_TYPE_ISOTIME: type = "Time"; break; case CONFIG_TYPE_ROUTERSET: type = "RouterList"; break; case CONFIG_TYPE_CSV: type = "CommaList"; break; - case CONFIG_TYPE_CSV_INTERVAL: type = "TimeIntervalCommaList"; break; + /* This type accepts more inputs than TimeInterval, but it ignores + * everything after the first entry, so we may as well pretend + * it's a TimeInterval. */ + case CONFIG_TYPE_CSV_INTERVAL: type = "TimeInterval"; break; case CONFIG_TYPE_LINELIST: type = "LineList"; break; case CONFIG_TYPE_LINELIST_S: type = "Dependent"; break; case CONFIG_TYPE_LINELIST_V: type = "Virtual"; break; diff --git a/src/or/confparse.c b/src/or/confparse.c index 64ed9ee6bb..6bab790945 100644 --- a/src/or/confparse.c +++ b/src/or/confparse.c @@ -162,8 +162,6 @@ config_assign_value(const config_format_t *fmt, void *options, int i, ok; const config_var_t *var; void *lvalue; - int *csv_int; - smartlist_t *csv_str; CONFIG_CHECK(fmt, options); @@ -195,6 +193,30 @@ config_assign_value(const config_format_t *fmt, void *options, *(int *)lvalue = i; break; + case CONFIG_TYPE_CSV_INTERVAL: { + /* We used to have entire smartlists here. But now that all of our + * download schedules use exponential backoff, only the first part + * matters. */ + const char *comma = strchr(c->value, ','); + const char *val = c->value; + char *tmp = NULL; + if (comma) { + tmp = tor_strndup(c->value, comma - c->value); + val = tmp; + } + + i = config_parse_interval(val, &ok); + if (!ok) { + tor_asprintf(msg, + "Interval '%s %s' is malformed or out of bounds.", + c->key, c->value); + return -1; + } + *(int *)lvalue = i; + tor_free(tmp); + break; + } + case CONFIG_TYPE_INTERVAL: { i = config_parse_interval(c->value, &ok); if (!ok) { @@ -298,36 +320,6 @@ config_assign_value(const config_format_t *fmt, void *options, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); break; - case CONFIG_TYPE_CSV_INTERVAL: - if (*(smartlist_t**)lvalue) { - SMARTLIST_FOREACH(*(smartlist_t**)lvalue, int *, cp, tor_free(cp)); - smartlist_clear(*(smartlist_t**)lvalue); - } else { - *(smartlist_t**)lvalue = smartlist_new(); - } - csv_str = smartlist_new(); - smartlist_split_string(csv_str, c->value, ",", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH_BEGIN(csv_str, char *, str) - { - i = config_parse_interval(str, &ok); - if (!ok) { - tor_asprintf(msg, - "Interval in '%s %s' is malformed or out of bounds.", - c->key, c->value); - SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); - smartlist_free(csv_str); - return -1; - } - csv_int = tor_malloc_zero(sizeof(int)); - *csv_int = i; - smartlist_add(*(smartlist_t**)lvalue, csv_int); - } - SMARTLIST_FOREACH_END(str); - SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); - smartlist_free(csv_str); - break; - case CONFIG_TYPE_LINELIST: case CONFIG_TYPE_LINELIST_S: { @@ -528,7 +520,6 @@ config_get_assigned_option(const config_format_t *fmt, const void *options, const config_var_t *var; const void *value; config_line_t *result; - smartlist_t *csv_str; tor_assert(options && key); CONFIG_CHECK(fmt, options); @@ -571,6 +562,7 @@ config_get_assigned_option(const config_format_t *fmt, const void *options, break; } /* fall through */ + case CONFIG_TYPE_CSV_INTERVAL: case CONFIG_TYPE_INTERVAL: case CONFIG_TYPE_MSEC_INTERVAL: case CONFIG_TYPE_UINT: @@ -611,20 +603,6 @@ config_get_assigned_option(const config_format_t *fmt, const void *options, else result->value = tor_strdup(""); break; - case CONFIG_TYPE_CSV_INTERVAL: - if (*(smartlist_t**)value) { - csv_str = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(*(smartlist_t**)value, int *, i) - { - smartlist_add_asprintf(csv_str, "%d", *i); - } - SMARTLIST_FOREACH_END(i); - result->value = smartlist_join_strings(csv_str, ",", 0, NULL); - SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); - smartlist_free(csv_str); - } else - result->value = tor_strdup(""); - break; case CONFIG_TYPE_OBSOLETE: log_fn(LOG_INFO, LD_CONFIG, "You asked me for the value of an obsolete config option '%s'.", @@ -789,6 +767,7 @@ config_clear(const config_format_t *fmt, void *options, case CONFIG_TYPE_ISOTIME: *(time_t*)lvalue = 0; break; + case CONFIG_TYPE_CSV_INTERVAL: case CONFIG_TYPE_INTERVAL: case CONFIG_TYPE_MSEC_INTERVAL: case CONFIG_TYPE_UINT: @@ -816,13 +795,6 @@ config_clear(const config_format_t *fmt, void *options, *(smartlist_t **)lvalue = NULL; } break; - case CONFIG_TYPE_CSV_INTERVAL: - if (*(smartlist_t**)lvalue) { - SMARTLIST_FOREACH(*(smartlist_t **)lvalue, int *, cp, tor_free(cp)); - smartlist_free(*(smartlist_t **)lvalue); - *(smartlist_t **)lvalue = NULL; - } - break; case CONFIG_TYPE_LINELIST: case CONFIG_TYPE_LINELIST_S: config_free_lines(*(config_line_t **)lvalue); diff --git a/src/or/confparse.h b/src/or/confparse.h index f1f2030343..4b4bf0adb4 100644 --- a/src/or/confparse.h +++ b/src/or/confparse.h @@ -28,7 +28,9 @@ typedef enum config_type_t { * optional whitespace. */ CONFIG_TYPE_CSV_INTERVAL, /**< A list of strings, separated by commas and * optional whitespace, representing intervals in - * seconds, with optional units */ + * seconds, with optional units. We allow + * multiple values here for legacy reasons, but + * ignore every value after the first. */ CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */ CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines, * mixed with other keywords. */ @@ -62,7 +64,7 @@ typedef union { int *AUTOBOOL; time_t *ISOTIME; smartlist_t **CSV; - smartlist_t **CSV_INTERVAL; + int *CSV_INTERVAL; config_line_t **LINELIST; config_line_t **LINELIST_S; config_line_t **LINELIST_V; diff --git a/src/or/directory.c b/src/or/directory.c index ea38f005e4..2c5ee23f3a 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -795,9 +795,9 @@ directory_choose_address_routerstatus(const routerstatus_t *status, * Use the preferred address and port if they are reachable, otherwise, * use the alternate address and port (if any). */ - have_or = fascist_firewall_choose_address_rs(status, - FIREWALL_OR_CONNECTION, 0, - use_or_ap); + fascist_firewall_choose_address_rs(status, FIREWALL_OR_CONNECTION, 0, + use_or_ap); + have_or = tor_addr_port_is_valid_ap(use_or_ap, 0); } /* DirPort connections @@ -806,9 +806,9 @@ directory_choose_address_routerstatus(const routerstatus_t *status, indirection == DIRIND_ANON_DIRPORT || (indirection == DIRIND_ONEHOP && !directory_must_use_begindir(options))) { - have_dir = fascist_firewall_choose_address_rs(status, - FIREWALL_DIR_CONNECTION, 0, - use_dir_ap); + fascist_firewall_choose_address_rs(status, FIREWALL_DIR_CONNECTION, 0, + use_dir_ap); + have_dir = tor_addr_port_is_valid_ap(use_dir_ap, 0); } /* We rejected all addresses in the relay's status. This means we can't @@ -5257,84 +5257,71 @@ connection_dir_finished_connecting(dir_connection_t *conn) /** Decide which download schedule we want to use based on descriptor type * in <b>dls</b> and <b>options</b>. - * Then return a list of int pointers defining download delays in seconds. + * + * Then, return the initial delay for that download schedule, in seconds. + * * Helper function for download_status_increment_failure(), * download_status_reset(), and download_status_increment_attempt(). */ -STATIC const smartlist_t * -find_dl_schedule(const download_status_t *dls, const or_options_t *options) +STATIC int +find_dl_min_delay(const download_status_t *dls, const or_options_t *options) { + tor_assert(dls); + tor_assert(options); + switch (dls->schedule) { case DL_SCHED_GENERIC: /* Any other directory document */ if (dir_server_mode(options)) { /* A directory authority or directory mirror */ - return options->TestingServerDownloadSchedule; + return options->TestingServerDownloadInitialDelay; } else { - return options->TestingClientDownloadSchedule; + return options->TestingClientDownloadInitialDelay; } case DL_SCHED_CONSENSUS: if (!networkstatus_consensus_can_use_multiple_directories(options)) { /* A public relay */ - return options->TestingServerConsensusDownloadSchedule; + return options->TestingServerConsensusDownloadInitialDelay; } else { /* A client or bridge */ if (networkstatus_consensus_is_bootstrapping(time(NULL))) { /* During bootstrapping */ if (!networkstatus_consensus_can_use_extra_fallbacks(options)) { /* A bootstrapping client without extra fallback directories */ - return - options->ClientBootstrapConsensusAuthorityOnlyDownloadSchedule; + return options-> + ClientBootstrapConsensusAuthorityOnlyDownloadInitialDelay; } else if (dls->want_authority) { /* A bootstrapping client with extra fallback directories, but * connecting to an authority */ return - options->ClientBootstrapConsensusAuthorityDownloadSchedule; + options->ClientBootstrapConsensusAuthorityDownloadInitialDelay; } else { /* A bootstrapping client connecting to extra fallback directories */ return - options->ClientBootstrapConsensusFallbackDownloadSchedule; + options->ClientBootstrapConsensusFallbackDownloadInitialDelay; } } else { /* A client with a reasonably live consensus, with or without * certificates */ - return options->TestingClientConsensusDownloadSchedule; + return options->TestingClientConsensusDownloadInitialDelay; } } case DL_SCHED_BRIDGE: if (options->UseBridges && num_bridges_usable(0) > 0) { /* A bridge client that is sure that one or more of its bridges are * running can afford to wait longer to update bridge descriptors. */ - return options->TestingBridgeDownloadSchedule; + return options->TestingBridgeDownloadInitialDelay; } else { /* A bridge client which might have no running bridges, must try to * get bridge descriptors straight away. */ - return options->TestingBridgeBootstrapDownloadSchedule; + return options->TestingBridgeBootstrapDownloadInitialDelay; } default: tor_assert(0); } /* Impossible, but gcc will fail with -Werror without a `return`. */ - return NULL; -} - -/** Decide which minimum delay step we want to use based on - * descriptor type in <b>dls</b> and <b>options</b>. - * Helper function for download_status_schedule_get_delay(). */ -STATIC int -find_dl_min_delay(download_status_t *dls, const or_options_t *options) -{ - tor_assert(dls); - tor_assert(options); - - /* - * For now, just use the existing schedule config stuff and pick the - * first/last entries off to get min/max delay for backoff purposes - */ - const smartlist_t *schedule = find_dl_schedule(dls, options); - tor_assert(schedule != NULL && smartlist_len(schedule) >= 2); - return *(int *)(smartlist_get(schedule, 0)); + return 0; } /** As next_random_exponential_delay() below, but does not compute a random @@ -5591,10 +5578,9 @@ download_status_increment_attempt(download_status_t *dls, const char *item, static time_t download_status_get_initial_delay_from_now(const download_status_t *dls) { - const smartlist_t *schedule = find_dl_schedule(dls, get_options()); /* We use constant initial delays, even in exponential backoff * schedules. */ - return time(NULL) + *(int *)smartlist_get(schedule, 0); + return time(NULL) + find_dl_min_delay(dls, get_options()); } /** Reset <b>dls</b> so that it will be considered downloadable diff --git a/src/or/directory.h b/src/or/directory.h index aa4d29a5bb..5f5ff7eca6 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -259,9 +259,7 @@ STATIC char* authdir_type_to_string(dirinfo_type_t auth); STATIC const char * dir_conn_purpose_to_string(int purpose); STATIC int should_use_directory_guards(const or_options_t *options); STATIC compression_level_t choose_compression_level(ssize_t n_bytes); -STATIC const smartlist_t *find_dl_schedule(const download_status_t *dls, - const or_options_t *options); -STATIC int find_dl_min_delay(download_status_t *dls, +STATIC int find_dl_min_delay(const download_status_t *dls, const or_options_t *options); STATIC int next_random_exponential_delay(int delay, diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 96e6ccaace..2c2bf99925 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -432,14 +432,15 @@ get_guard_confirmed_min_lifetime(void) STATIC int get_n_primary_guards(void) { - const int n = get_options()->NumEntryGuards; - const int n_dir = get_options()->NumDirectoryGuards; - if (n > 5) { - return MAX(n_dir, n + n / 2); - } else if (n >= 1) { - return MAX(n_dir, n * 2); + /* If the user has explicitly configured the number of primary guards, do + * what the user wishes to do */ + const int configured_primaries = get_options()->NumPrimaryGuards; + if (configured_primaries) { + return configured_primaries; } + /* otherwise check for consensus parameter and if that's not set either, just + * use the default value. */ return networkstatus_get_param(NULL, "guard-n-primary-guards", DFLT_N_PRIMARY_GUARDS, 1, INT32_MAX); @@ -454,6 +455,9 @@ get_n_primary_guards_to_use(guard_usage_t usage) int configured; const char *param_name; int param_default; + + /* If the user has explicitly configured the amount of guards, use + that. Otherwise, fall back to the default value. */ if (usage == GUARD_USAGE_DIRGUARD) { configured = get_options()->NumDirectoryGuards; param_name = "guard-n-primary-dir-guards-to-use"; diff --git a/src/or/hs_common.c b/src/or/hs_common.c index 8cc7d08911..46903a2960 100644 --- a/src/or/hs_common.c +++ b/src/or/hs_common.c @@ -103,7 +103,7 @@ compare_digest_to_fetch_hsdir_index(const void *_key, const void **_member) { const char *key = _key; const node_t *node = *_member; - return tor_memcmp(key, node->hsdir_index->fetch, DIGEST256_LEN); + return tor_memcmp(key, node->hsdir_index.fetch, DIGEST256_LEN); } /* Helper function: The key is a digest that we compare to a node_t object @@ -114,7 +114,7 @@ compare_digest_to_store_first_hsdir_index(const void *_key, { const char *key = _key; const node_t *node = *_member; - return tor_memcmp(key, node->hsdir_index->store_first, DIGEST256_LEN); + return tor_memcmp(key, node->hsdir_index.store_first, DIGEST256_LEN); } /* Helper function: The key is a digest that we compare to a node_t object @@ -125,7 +125,7 @@ compare_digest_to_store_second_hsdir_index(const void *_key, { const char *key = _key; const node_t *node = *_member; - return tor_memcmp(key, node->hsdir_index->store_second, DIGEST256_LEN); + return tor_memcmp(key, node->hsdir_index.store_second, DIGEST256_LEN); } /* Helper function: Compare two node_t objects current hsdir_index. */ @@ -134,8 +134,8 @@ compare_node_fetch_hsdir_index(const void **a, const void **b) { const node_t *node1= *a; const node_t *node2 = *b; - return tor_memcmp(node1->hsdir_index->fetch, - node2->hsdir_index->fetch, + return tor_memcmp(node1->hsdir_index.fetch, + node2->hsdir_index.fetch, DIGEST256_LEN); } @@ -145,8 +145,8 @@ compare_node_store_first_hsdir_index(const void **a, const void **b) { const node_t *node1= *a; const node_t *node2 = *b; - return tor_memcmp(node1->hsdir_index->store_first, - node2->hsdir_index->store_first, + return tor_memcmp(node1->hsdir_index.store_first, + node2->hsdir_index.store_first, DIGEST256_LEN); } @@ -156,8 +156,8 @@ compare_node_store_second_hsdir_index(const void **a, const void **b) { const node_t *node1= *a; const node_t *node2 = *b; - return tor_memcmp(node1->hsdir_index->store_second, - node2->hsdir_index->store_second, + return tor_memcmp(node1->hsdir_index.store_second, + node2->hsdir_index.store_second, DIGEST256_LEN); } @@ -1288,18 +1288,15 @@ node_has_hsdir_index(const node_t *node) /* At this point, since the node has a desc, this node must also have an * hsdir index. If not, something went wrong, so BUG out. */ - if (BUG(node->hsdir_index == NULL)) { - return 0; - } - if (BUG(tor_mem_is_zero((const char*)node->hsdir_index->fetch, + if (BUG(tor_mem_is_zero((const char*)node->hsdir_index.fetch, DIGEST256_LEN))) { return 0; } - if (BUG(tor_mem_is_zero((const char*)node->hsdir_index->store_first, + if (BUG(tor_mem_is_zero((const char*)node->hsdir_index.store_first, DIGEST256_LEN))) { return 0; } - if (BUG(tor_mem_is_zero((const char*)node->hsdir_index->store_second, + if (BUG(tor_mem_is_zero((const char*)node->hsdir_index.store_second, DIGEST256_LEN))) { return 0; } diff --git a/src/or/hs_common.h b/src/or/hs_common.h index 83ba1b8599..ef7d5dca2b 100644 --- a/src/or/hs_common.h +++ b/src/or/hs_common.h @@ -156,19 +156,6 @@ typedef struct rend_service_port_config_t { char unix_addr[FLEXIBLE_ARRAY_MEMBER]; } rend_service_port_config_t; -/* Hidden service directory index used in a node_t which is set once we set - * the consensus. */ -typedef struct hsdir_index_t { - /* HSDir index to use when fetching a descriptor. */ - uint8_t fetch[DIGEST256_LEN]; - - /* HSDir index used by services to store their first and second - * descriptor. The first descriptor is chronologically older than the second - * one and uses older TP and SRV values. */ - uint8_t store_first[DIGEST256_LEN]; - uint8_t store_second[DIGEST256_LEN]; -} hsdir_index_t; - void hs_init(void); void hs_free_all(void); diff --git a/src/or/hs_control.c b/src/or/hs_control.c index 87b4e3fca8..eca9ed1dd5 100644 --- a/src/or/hs_control.c +++ b/src/or/hs_control.c @@ -39,9 +39,8 @@ hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk, * can't pick a node without an hsdir_index. */ hsdir_node = node_get_by_id(hsdir_rs->identity_digest); tor_assert(hsdir_node); - tor_assert(hsdir_node->hsdir_index); /* This is a fetch event. */ - hsdir_index = hsdir_node->hsdir_index->fetch; + hsdir_index = hsdir_node->hsdir_index.fetch; /* Trigger the event. */ control_event_hs_descriptor_requested(onion_address, REND_NO_AUTH, diff --git a/src/or/hs_service.c b/src/or/hs_service.c index 4ac0df2add..c4a473a5f7 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -80,6 +80,7 @@ static smartlist_t *hs_service_staging_list; * reupload if needed */ static int consider_republishing_hs_descriptors = 0; +/* Static declaration. */ static void set_descriptor_revision_counter(hs_descriptor_t *hs_desc); static void move_descriptors(hs_service_t *src, hs_service_t *dst); @@ -152,6 +153,12 @@ register_service(hs_service_ht *map, hs_service_t *service) } /* Taking ownership of the object at this point. */ HT_INSERT(hs_service_ht, map, service); + + /* If we just modified the global map, we notify. */ + if (map == hs_service_map) { + hs_service_map_has_changed(); + } + return 0; } @@ -178,6 +185,11 @@ remove_service(hs_service_ht *map, hs_service_t *service) "while removing service %s", escaped(service->config.directory_path)); } + + /* If we just modified the global map, we notify. */ + if (map == hs_service_map) { + hs_service_map_has_changed(); + } } /* Set the default values for a service configuration object <b>c</b>. */ @@ -916,6 +928,11 @@ register_all_services(void) smartlist_clear(hs_service_staging_list); service_free_all(); hs_service_map = new_service_map; + /* We've just register services into the new map and now we've replaced the + * global map with it so we have to notify that the change happened. When + * registering a service, the notify is only triggered if the destination + * map is the global map for which in here it was not. */ + hs_service_map_has_changed(); } /* Write the onion address of a given service to the given filename fname_ in @@ -2287,8 +2304,8 @@ upload_descriptor_to_hsdir(const hs_service_t *service, /* Logging so we know where it was sent. */ { int is_next_desc = (service->desc_next == desc); - const uint8_t *idx = (is_next_desc) ? hsdir->hsdir_index->store_second: - hsdir->hsdir_index->store_first; + const uint8_t *idx = (is_next_desc) ? hsdir->hsdir_index.store_second: + hsdir->hsdir_index.store_first; log_info(LD_REND, "Service %s %s descriptor of revision %" PRIu64 " initiated upload request to %s with index %s", safe_str_client(service->onion_address), @@ -2936,6 +2953,17 @@ service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list) /* Public API */ /* ========== */ +/* 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) +{ + /* If we now have services where previously we had not, we need to enable + * the HS service main loop event. If we changed to having no services, we + * need to disable the event. */ + rescan_periodic_events(get_options()); +} + /* 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 diff --git a/src/or/hs_service.h b/src/or/hs_service.h index d163eeef28..2e27d8a899 100644 --- a/src/or/hs_service.h +++ b/src/or/hs_service.h @@ -260,6 +260,7 @@ void hs_service_lists_fnames_for_sandbox(smartlist_t *file_list, int hs_service_set_conn_addr_port(const origin_circuit_t *circ, edge_connection_t *conn); +void hs_service_map_has_changed(void); void hs_service_dir_info_changed(void); void hs_service_run_scheduled_events(time_t now); void hs_service_circuit_has_opened(origin_circuit_t *circ); diff --git a/src/or/main.c b/src/or/main.c index b7b7b71624..1160f377e4 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1356,6 +1356,7 @@ CALLBACK(retry_listeners); CALLBACK(rotate_onion_key); CALLBACK(rotate_x509_certificate); CALLBACK(save_stability); +CALLBACK(save_state); CALLBACK(write_bridge_ns); CALLBACK(write_stats_file); @@ -1377,6 +1378,7 @@ STATIC periodic_event_item_t periodic_events[] = { CALLBACK(reset_padding_counts, PERIODIC_EVENT_ROLE_ALL, 0), CALLBACK(retry_listeners, PERIODIC_EVENT_ROLE_ALL, PERIODIC_EVENT_FLAG_NEED_NET), + CALLBACK(save_state, PERIODIC_EVENT_ROLE_ALL, 0), CALLBACK(rotate_x509_certificate, PERIODIC_EVENT_ROLE_ALL, 0), CALLBACK(write_stats_file, PERIODIC_EVENT_ROLE_ALL, 0), @@ -1387,7 +1389,6 @@ STATIC periodic_event_item_t periodic_events[] = { CALLBACK(check_for_reachability_bw, PERIODIC_EVENT_ROLE_ROUTER, PERIODIC_EVENT_FLAG_NEED_NET), CALLBACK(check_onion_keys_expiry_time, PERIODIC_EVENT_ROLE_ROUTER, 0), - CALLBACK(clean_consdiffmgr, PERIODIC_EVENT_ROLE_ROUTER, 0), CALLBACK(expire_old_ciruits_serverside, PERIODIC_EVENT_ROLE_ROUTER, PERIODIC_EVENT_FLAG_NEED_NET), CALLBACK(retry_dns, PERIODIC_EVENT_ROLE_ROUTER, 0), @@ -1421,6 +1422,9 @@ STATIC periodic_event_item_t periodic_events[] = { /* Bridge Authority only. */ CALLBACK(write_bridge_ns, PERIODIC_EVENT_ROLE_BRIDGEAUTH, 0), + /* Directory server only. */ + CALLBACK(clean_consdiffmgr, PERIODIC_EVENT_ROLE_DIRSERVER, 0), + END_OF_PERIODIC_EVENTS }; #undef CALLBACK @@ -1433,6 +1437,7 @@ static periodic_event_item_t *check_descriptor_event=NULL; static periodic_event_item_t *fetch_networkstatus_event=NULL; static periodic_event_item_t *launch_descriptor_fetches_event=NULL; static periodic_event_item_t *check_dns_honesty_event=NULL; +static periodic_event_item_t *save_state_event=NULL; /** Reset all the periodic events so we'll do all our actions again as if we * just started up. @@ -1477,6 +1482,7 @@ get_my_roles(const or_options_t *options) int is_bridgeauth = authdir_mode_bridge(options); int is_hidden_service = !!hs_service_get_num_services() || !!rend_num_services(); + int is_dirserver = dir_server_mode(options); if (is_bridge) roles |= PERIODIC_EVENT_ROLE_BRIDGE; if (is_client) roles |= PERIODIC_EVENT_ROLE_CLIENT; @@ -1484,6 +1490,7 @@ get_my_roles(const or_options_t *options) if (is_dirauth) roles |= PERIODIC_EVENT_ROLE_DIRAUTH; if (is_bridgeauth) roles |= PERIODIC_EVENT_ROLE_BRIDGEAUTH; if (is_hidden_service) roles |= PERIODIC_EVENT_ROLE_HS_SERVICE; + if (is_dirserver) roles |= PERIODIC_EVENT_ROLE_DIRSERVER; return roles; } @@ -1529,6 +1536,7 @@ initialize_periodic_events(void) NAMED_CALLBACK(fetch_networkstatus); NAMED_CALLBACK(launch_descriptor_fetches); NAMED_CALLBACK(check_dns_honesty); + NAMED_CALLBACK(save_state); struct timeval one_second = { 1, 0 }; initialize_periodic_events_event = tor_evtimer_new( @@ -1554,6 +1562,13 @@ rescan_periodic_events(const or_options_t *options) { tor_assert(options); + /* Avoid scanning the event list if we haven't initialized it yet. This is + * particularly useful for unit tests in order to avoid initializing main + * loop events everytime. */ + if (!periodic_events_initialized) { + return; + } + int roles = get_my_roles(options); for (int i = 0; periodic_events[i].name; ++i) { @@ -1599,8 +1614,9 @@ periodic_events_on_new_options(const or_options_t *options) void reschedule_descriptor_update_check(void) { - tor_assert(check_descriptor_event); - periodic_event_reschedule(check_descriptor_event); + if (check_descriptor_event) { + periodic_event_reschedule(check_descriptor_event); + } } /** @@ -1746,10 +1762,6 @@ run_scheduled_events(time_t now) run_connection_housekeeping(i, now); } - /* 8b. And if anything in our state is ready to get flushed to disk, we - * flush it. */ - or_state_save(now); - /* 11b. check pending unconfigured managed proxies */ if (!net_is_disabled() && pt_proxies_configuration_pending()) pt_configure_remaining_proxies(); @@ -1984,6 +1996,37 @@ check_expired_networkstatus_callback(time_t now, const or_options_t *options) } /** + * Scheduled callback: Save the state file to disk if appropriate. + */ +static int +save_state_callback(time_t now, const or_options_t *options) +{ + (void) options; + (void) or_state_save(now); // only saves if appropriate + const time_t next_write = get_or_state()->next_write; + if (next_write == TIME_MAX) { + return 86400; + } else if (BUG(next_write <= now)) { + /* This can't happen due to clock jumps, since the value of next_write + * is based on the same "now" that we passed to or_state_save(). + */ + return PERIODIC_EVENT_NO_UPDATE; + } else { + return (int)(next_write - now); + } +} + +/** Reschedule the event for saving the state file. + * + * Run this when the state becomes dirty. */ +void +reschedule_or_state_save(void) +{ + tor_assert(save_state_event); + periodic_event_reschedule(save_state_event); +} + +/** * Periodic callback: Write statistics to disk if appropriate. */ static int @@ -2335,7 +2378,7 @@ static int clean_consdiffmgr_callback(time_t now, const or_options_t *options) { (void)now; - if (server_mode(options)) { + if (dir_server_mode(options)) { consdiffmgr_cleanup(); } return CDM_CLEAN_CALLBACK_INTERVAL; diff --git a/src/or/main.h b/src/or/main.h index 2447339fb5..836dbf1cad 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -61,6 +61,7 @@ void dns_servers_relaunch_checks(void); void reset_all_main_loop_timers(void); void reschedule_descriptor_update_check(void); void reschedule_directory_downloads(void); +void reschedule_or_state_save(void); void mainloop_schedule_postloop_cleanup(void); void rescan_periodic_events(const or_options_t *options); diff --git a/src/or/nodelist.c b/src/or/nodelist.c index e7342f9799..675cbb0056 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -225,7 +225,6 @@ node_get_or_create(const char *identity_digest) smartlist_add(the_nodelist->nodes, node); node->nodelist_idx = smartlist_len(the_nodelist->nodes) - 1; - node->hsdir_index = tor_malloc_zero(sizeof(hsdir_index_t)); node->country = -1; @@ -350,26 +349,26 @@ node_set_hsdir_index(node_t *node, const networkstatus_t *ns) /* Build the fetch index. */ hs_build_hsdir_index(node_identity_pk, fetch_srv, fetch_tp, - node->hsdir_index->fetch); + node->hsdir_index.fetch); /* If we are in the time segment between SRV#N and TP#N, the fetch index is the same as the first store index */ if (!hs_in_period_between_tp_and_srv(ns, now)) { - memcpy(node->hsdir_index->store_first, node->hsdir_index->fetch, - sizeof(node->hsdir_index->store_first)); + memcpy(node->hsdir_index.store_first, node->hsdir_index.fetch, + sizeof(node->hsdir_index.store_first)); } else { hs_build_hsdir_index(node_identity_pk, store_first_srv, store_first_tp, - node->hsdir_index->store_first); + node->hsdir_index.store_first); } /* If we are in the time segment between TP#N and SRV#N+1, the fetch index is the same as the second store index */ if (hs_in_period_between_tp_and_srv(ns, now)) { - memcpy(node->hsdir_index->store_second, node->hsdir_index->fetch, - sizeof(node->hsdir_index->store_second)); + memcpy(node->hsdir_index.store_second, node->hsdir_index.fetch, + sizeof(node->hsdir_index.store_second)); } else { hs_build_hsdir_index(node_identity_pk, store_second_srv, store_second_tp, - node->hsdir_index->store_second); + node->hsdir_index.store_second); } done: @@ -720,7 +719,6 @@ node_free_(node_t *node) if (node->md) node->md->held_by_nodes--; tor_assert(node->nodelist_idx == -1); - tor_free(node->hsdir_index); tor_free(node); } diff --git a/src/or/or.h b/src/or/or.h index e27f25197b..cd77b21056 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -57,7 +57,6 @@ #ifdef HAVE_TIME_H #include <time.h> #endif -#include <stdbool.h> #ifdef _WIN32 #include <winsock2.h> @@ -895,8 +894,19 @@ rend_data_v2_t *TO_REND_DATA_V2(const rend_data_t *d) struct hs_ident_edge_conn_t; struct hs_ident_dir_conn_t; struct hs_ident_circuit_t; -/* Stub because we can't include hs_common.h. */ -struct hsdir_index_t; + +/* Hidden service directory index used in a node_t which is set once we set + * the consensus. */ +typedef struct hsdir_index_t { + /* HSDir index to use when fetching a descriptor. */ + uint8_t fetch[DIGEST256_LEN]; + + /* HSDir index used by services to store their first and second + * descriptor. The first descriptor is chronologically older than the second + * one and uses older TP and SRV values. */ + uint8_t store_first[DIGEST256_LEN]; + uint8_t store_second[DIGEST256_LEN]; +} hsdir_index_t; /** Time interval for tracking replays of DH public keys received in * INTRODUCE2 cells. Used only to avoid launching multiple @@ -2562,7 +2572,7 @@ typedef struct node_t { /* Hidden service directory index data. This is used by a service or client * in order to know what's the hs directory index for this node at the time * the consensus is set. */ - struct hsdir_index_t *hsdir_index; + struct hsdir_index_t hsdir_index; } node_t; /** Linked list of microdesc hash lines for a single router in a directory @@ -4149,6 +4159,8 @@ typedef struct { int NumDirectoryGuards; /**< How many dir guards do we try to establish? * If 0, use value from NumEntryGuards. */ + int NumPrimaryGuards; /**< How many primary guards do we want? */ + int RephistTrackTime; /**< How many seconds do we keep rephist info? */ /** Should we always fetch our dir info on the mirror schedule (which * means directly from the authorities) no matter our other config? */ @@ -4317,19 +4329,19 @@ typedef struct { /** Schedule for when servers should download things in general. Only * altered on testing networks. */ - smartlist_t *TestingServerDownloadSchedule; + int TestingServerDownloadInitialDelay; /** Schedule for when clients should download things in general. Only * altered on testing networks. */ - smartlist_t *TestingClientDownloadSchedule; + int TestingClientDownloadInitialDelay; /** Schedule for when servers should download consensuses. Only altered * on testing networks. */ - smartlist_t *TestingServerConsensusDownloadSchedule; + int TestingServerConsensusDownloadInitialDelay; /** Schedule for when clients should download consensuses. Only altered * on testing networks. */ - smartlist_t *TestingClientConsensusDownloadSchedule; + int TestingClientConsensusDownloadInitialDelay; /** Schedule for when clients should download consensuses from authorities * if they are bootstrapping (that is, they don't have a usable, reasonably @@ -4339,7 +4351,7 @@ typedef struct { * This schedule is incremented by (potentially concurrent) connection * attempts, unlike other schedules, which are incremented by connection * failures. Only altered on testing networks. */ - smartlist_t *ClientBootstrapConsensusAuthorityDownloadSchedule; + int ClientBootstrapConsensusAuthorityDownloadInitialDelay; /** Schedule for when clients should download consensuses from fallback * directory mirrors if they are bootstrapping (that is, they don't have a @@ -4349,7 +4361,7 @@ typedef struct { * This schedule is incremented by (potentially concurrent) connection * attempts, unlike other schedules, which are incremented by connection * failures. Only altered on testing networks. */ - smartlist_t *ClientBootstrapConsensusFallbackDownloadSchedule; + int ClientBootstrapConsensusFallbackDownloadInitialDelay; /** Schedule for when clients should download consensuses from authorities * if they are bootstrapping (that is, they don't have a usable, reasonably @@ -4359,15 +4371,15 @@ typedef struct { * This schedule is incremented by (potentially concurrent) connection * attempts, unlike other schedules, which are incremented by connection * failures. Only altered on testing networks. */ - smartlist_t *ClientBootstrapConsensusAuthorityOnlyDownloadSchedule; + int ClientBootstrapConsensusAuthorityOnlyDownloadInitialDelay; /** Schedule for when clients should download bridge descriptors. Only * altered on testing networks. */ - smartlist_t *TestingBridgeDownloadSchedule; + int TestingBridgeDownloadInitialDelay; /** Schedule for when clients should download bridge descriptors when they * have no running bridges. Only altered on testing networks. */ - smartlist_t *TestingBridgeBootstrapDownloadSchedule; + int TestingBridgeBootstrapDownloadInitialDelay; /** When directory clients have only a few descriptors to request, they * batch them until they have more, or until this amount of time has @@ -4745,15 +4757,6 @@ typedef struct { time_t LastRotatedOnionKey; } or_state_t; -/** Change the next_write time of <b>state</b> to <b>when</b>, unless the - * state is already scheduled to be written to disk earlier than <b>when</b>. - */ -static inline void or_state_mark_dirty(or_state_t *state, time_t when) -{ - if (state->next_write > when) - state->next_write = when; -} - #define MAX_SOCKS_REPLY_LEN 1024 #define MAX_SOCKS_ADDR_LEN 256 #define SOCKS_NO_AUTH 0x00 diff --git a/src/or/periodic.h b/src/or/periodic.h index a044b34fdd..e8208b2475 100644 --- a/src/or/periodic.h +++ b/src/or/periodic.h @@ -14,6 +14,7 @@ #define PERIODIC_EVENT_ROLE_DIRAUTH (1U << 3) #define PERIODIC_EVENT_ROLE_BRIDGEAUTH (1U << 4) #define PERIODIC_EVENT_ROLE_HS_SERVICE (1U << 5) +#define PERIODIC_EVENT_ROLE_DIRSERVER (1U << 6) /* Helper macro to make it a bit less annoying to defined groups of roles that * are often used. */ diff --git a/src/or/policies.c b/src/or/policies.c index f718ded326..e0dbb021c6 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -825,9 +825,8 @@ fascist_firewall_choose_address(const tor_addr_port_t *a, * If pref_only, only choose preferred addresses. In either case, choose * a preferred address before an address that's not preferred. * If both addresses could be chosen (they are both preferred or both allowed) - * choose IPv6 if pref_ipv6 is true, otherwise choose IPv4. - * If neither address is chosen, return 0, else return 1. */ -static int + * choose IPv6 if pref_ipv6 is true, otherwise choose IPv4. */ +static void fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr, uint16_t ipv4_orport, uint16_t ipv4_dirport, @@ -845,6 +844,9 @@ fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr, tor_assert(ipv6_addr); tor_assert(ap); + tor_addr_make_null(&ap->addr, AF_UNSPEC); + ap->port = 0; + tor_addr_port_t ipv4_ap; tor_addr_copy(&ipv4_ap.addr, ipv4_addr); ipv4_ap.port = (fw_connection == FIREWALL_OR_CONNECTION @@ -865,17 +867,12 @@ fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr, if (result) { tor_addr_copy(&ap->addr, &result->addr); ap->port = result->port; - return 1; - } else { - tor_addr_make_null(&ap->addr, AF_UNSPEC); - ap->port = 0; - return 0; } } /** Like fascist_firewall_choose_address_base(), but takes a host-order IPv4 * address as the first parameter. */ -static int +static void fascist_firewall_choose_address_ipv4h(uint32_t ipv4h_addr, uint16_t ipv4_orport, uint16_t ipv4_dirport, @@ -889,11 +886,16 @@ fascist_firewall_choose_address_ipv4h(uint32_t ipv4h_addr, { tor_addr_t ipv4_addr; tor_addr_from_ipv4h(&ipv4_addr, ipv4h_addr); - return fascist_firewall_choose_address_base(&ipv4_addr, ipv4_orport, - ipv4_dirport, ipv6_addr, - ipv6_orport, ipv6_dirport, - fw_connection, pref_only, - pref_ipv6, ap); + tor_assert(ap); + + tor_addr_make_null(&ap->addr, AF_UNSPEC); + ap->port = 0; + + fascist_firewall_choose_address_base(&ipv4_addr, ipv4_orport, + ipv4_dirport, ipv6_addr, + ipv6_orport, ipv6_dirport, + fw_connection, pref_only, + pref_ipv6, ap); } /* Some microdescriptor consensus methods have no IPv6 addresses in rs: they @@ -944,23 +946,25 @@ node_awaiting_ipv6(const or_options_t* options, const node_t *node) * This should only happen when there's no valid consensus, and rs doesn't * correspond to a bridge client's bridge. */ -int +void fascist_firewall_choose_address_rs(const routerstatus_t *rs, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap) { + tor_assert(ap); + + tor_addr_make_null(&ap->addr, AF_UNSPEC); + ap->port = 0; + if (!rs) { - return 0; + return; } - tor_assert(ap); - const or_options_t *options = get_options(); const node_t *node = node_get_by_id(rs->identity_digest); if (node && !node_awaiting_ipv6(options, node)) { - return fascist_firewall_choose_address_node(node, fw_connection, pref_only, - ap); + fascist_firewall_choose_address_node(node, fw_connection, pref_only, ap); } else { /* There's no node-specific IPv6 preference, so use the generic IPv6 * preference instead. */ @@ -970,33 +974,31 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs, /* Assume IPv4 and IPv6 DirPorts are the same. * Assume the IPv6 OR and Dir addresses are the same. */ - return fascist_firewall_choose_address_ipv4h(rs->addr, - rs->or_port, - rs->dir_port, - &rs->ipv6_addr, - rs->ipv6_orport, - rs->dir_port, - fw_connection, - pref_only, - pref_ipv6, - ap); + fascist_firewall_choose_address_ipv4h(rs->addr, rs->or_port, rs->dir_port, + &rs->ipv6_addr, rs->ipv6_orport, + rs->dir_port, fw_connection, + pref_only, pref_ipv6, ap); } } /** Like fascist_firewall_choose_address_base(), but takes <b>node</b>, and * looks up the node's IPv6 preference rather than taking an argument * for pref_ipv6. */ -int +void fascist_firewall_choose_address_node(const node_t *node, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t *ap) { + tor_assert(ap); + + tor_addr_make_null(&ap->addr, AF_UNSPEC); + ap->port = 0; + if (!node) { - return 0; + return; } node_assert_ok(node); - /* Calling fascist_firewall_choose_address_node() when the node is missing * IPv6 information breaks IPv6-only clients. * If the node is a hard-coded fallback directory or authority, call @@ -1006,7 +1008,7 @@ fascist_firewall_choose_address_node(const node_t *node, * descriptor (routerinfo), or is one of our configured bridges before * calling this function. */ if (BUG(node_awaiting_ipv6(get_options(), node))) { - return 0; + return; } const int pref_ipv6_node = (fw_connection == FIREWALL_OR_CONNECTION @@ -1024,27 +1026,27 @@ fascist_firewall_choose_address_node(const node_t *node, node_get_pref_ipv6_dirport(node, &ipv6_dir_ap); /* Assume the IPv6 OR and Dir addresses are the same. */ - return fascist_firewall_choose_address_base(&ipv4_or_ap.addr, - ipv4_or_ap.port, - ipv4_dir_ap.port, - &ipv6_or_ap.addr, - ipv6_or_ap.port, - ipv6_dir_ap.port, - fw_connection, - pref_only, - pref_ipv6_node, - ap); + fascist_firewall_choose_address_base(&ipv4_or_ap.addr, ipv4_or_ap.port, + ipv4_dir_ap.port, &ipv6_or_ap.addr, + ipv6_or_ap.port, ipv6_dir_ap.port, + fw_connection, pref_only, + pref_ipv6_node, ap); } /** Like fascist_firewall_choose_address_rs(), but takes <b>ds</b>. */ -int +void fascist_firewall_choose_address_dir_server(const dir_server_t *ds, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t *ap) { + tor_assert(ap); + + tor_addr_make_null(&ap->addr, AF_UNSPEC); + ap->port = 0; + if (!ds) { - return 0; + return; } /* A dir_server_t always has a fake_status. As long as it has the same @@ -1052,8 +1054,8 @@ fascist_firewall_choose_address_dir_server(const dir_server_t *ds, * (See #17867.) * This function relies on fascist_firewall_choose_address_rs looking up the * node if it can, because that will get the latest info for the relay. */ - return fascist_firewall_choose_address_rs(&ds->fake_status, fw_connection, - pref_only, ap); + fascist_firewall_choose_address_rs(&ds->fake_status, fw_connection, + pref_only, ap); } /** Return 1 if <b>addr</b> is permitted to connect to our dir port, diff --git a/src/or/policies.h b/src/or/policies.h index 35220a812f..4879acdd8d 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -55,13 +55,13 @@ int fascist_firewall_allows_dir_server(const dir_server_t *ds, firewall_connection_t fw_connection, int pref_only); -int fascist_firewall_choose_address_rs(const routerstatus_t *rs, - firewall_connection_t fw_connection, - int pref_only, tor_addr_port_t* ap); -int fascist_firewall_choose_address_node(const node_t *node, - firewall_connection_t fw_connection, - int pref_only, tor_addr_port_t* ap); -int fascist_firewall_choose_address_dir_server(const dir_server_t *ds, +void fascist_firewall_choose_address_rs(const routerstatus_t *rs, + firewall_connection_t fw_connection, + int pref_only, tor_addr_port_t* ap); +void fascist_firewall_choose_address_node(const node_t *node, + firewall_connection_t fw_connection, + int pref_only, tor_addr_port_t* ap); +void fascist_firewall_choose_address_dir_server(const dir_server_t *ds, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 1a93c36433..afaeabe5dc 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -348,6 +348,13 @@ rend_add_service(smartlist_t *service_list, rend_service_t *service) /* The service passed all the checks */ tor_assert(s_list); smartlist_add(s_list, service); + + /* Notify that our global service list has changed only if this new service + * went into our global list. If not, when we move service from the staging + * list to the new list, a notify is triggered. */ + if (s_list == rend_service_list) { + hs_service_map_has_changed(); + } return 0; } @@ -609,6 +616,8 @@ rend_service_prune_list_impl_(void) circuit_mark_for_close(TO_CIRCUIT(ocirc), END_CIRC_REASON_FINISHED); } smartlist_free(surviving_services); + /* Notify that our global service list has changed. */ + hs_service_map_has_changed(); } /* Try to prune our main service list using the temporary one that we just @@ -958,6 +967,8 @@ rend_service_del_ephemeral(const char *service_id) } } SMARTLIST_FOREACH_END(circ); smartlist_remove(rend_service_list, s); + /* Notify that we just removed a service from our global list. */ + hs_service_map_has_changed(); rend_service_free(s); log_debug(LD_CONFIG, "Removed ephemeral Onion Service: %s", service_id); diff --git a/src/or/rephist.c b/src/or/rephist.c index ac3e9f502e..bac2efb1f4 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -85,8 +85,8 @@ #include "routerlist.h" #include "ht.h" #include "channelpadding.h" - #include "connection_or.h" +#include "statefile.h" static void bw_arrays_init(void); static void predicted_ports_alloc(void); diff --git a/src/or/statefile.c b/src/or/statefile.c index cc114f0a2b..c81ea44e06 100644 --- a/src/or/statefile.c +++ b/src/or/statefile.c @@ -37,6 +37,7 @@ #include "control.h" #include "entrynodes.h" #include "hibernate.h" +#include "main.h" #include "rephist.h" #include "router.h" #include "sandbox.h" @@ -680,6 +681,18 @@ save_transport_to_state(const char *transport, tor_free(transport_addrport); } +/** Change the next_write time of <b>state</b> to <b>when</b>, unless the + * state is already scheduled to be written to disk earlier than <b>when</b>. + */ +void +or_state_mark_dirty(or_state_t *state, time_t when) +{ + if (state->next_write > when) { + state->next_write = when; + reschedule_or_state_save(); + } +} + STATIC void or_state_free_(or_state_t *state) { diff --git a/src/or/statefile.h b/src/or/statefile.h index b4cc4d1dc6..5aa2ca9320 100644 --- a/src/or/statefile.h +++ b/src/or/statefile.h @@ -17,6 +17,7 @@ char *get_stored_bindaddr_for_server_transport(const char *transport); int or_state_load(void); int or_state_loaded(void); void or_state_free_all(void); +void or_state_mark_dirty(or_state_t *state, time_t when); #ifdef STATEFILE_PRIVATE STATIC config_line_t *get_transport_in_state_by_name(const char *transport); diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 74153c671a..84fdb96e45 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -4065,34 +4065,19 @@ test_dir_download_status_increment(void *arg) DL_WANT_ANY_DIRSERVER, DL_SCHED_INCREMENT_ATTEMPT, 0, 0 }; - int no_delay = 0; - int delay0 = -1; - int delay1 = -1; - int delay2 = -1; - smartlist_t *schedule = smartlist_new(); - smartlist_t *schedule_no_initial_delay = smartlist_new(); or_options_t test_options; time_t current_time = time(NULL); - /* Provide some values for the schedules */ - delay0 = 10; - delay1 = 99; - delay2 = 20; - - /* Make the schedules */ - smartlist_add(schedule, (void *)&delay0); - smartlist_add(schedule, (void *)&delay1); - smartlist_add(schedule, (void *)&delay2); - - smartlist_add(schedule_no_initial_delay, (void *)&no_delay); - smartlist_add(schedule_no_initial_delay, (void *)&delay1); - smartlist_add(schedule_no_initial_delay, (void *)&delay2); + const int delay0 = 10; + const int no_delay = 0; + const int schedule = 10; + const int schedule_no_initial_delay = 0; /* Put it in the options */ mock_options = &test_options; reset_options(mock_options, &mock_get_options_calls); - mock_options->TestingBridgeBootstrapDownloadSchedule = schedule; - mock_options->TestingClientDownloadSchedule = schedule; + mock_options->TestingBridgeBootstrapDownloadInitialDelay = schedule; + mock_options->TestingClientDownloadInitialDelay = schedule; MOCK(get_options, mock_get_options); @@ -4100,13 +4085,13 @@ test_dir_download_status_increment(void *arg) * whether or not it was reset before being used */ /* regression test for 17750: no initial delay */ - mock_options->TestingClientDownloadSchedule = schedule_no_initial_delay; + mock_options->TestingClientDownloadInitialDelay = schedule_no_initial_delay; mock_get_options_calls = 0; /* we really want to test that it's equal to time(NULL) + delay0, but that's * an unrealiable test, because time(NULL) might change. */ /* regression test for 17750: exponential, no initial delay */ - mock_options->TestingClientDownloadSchedule = schedule_no_initial_delay; + mock_options->TestingClientDownloadInitialDelay = schedule_no_initial_delay; mock_get_options_calls = 0; /* we really want to test that it's equal to time(NULL) + delay0, but that's * an unrealiable test, because time(NULL) might change. */ @@ -4119,7 +4104,7 @@ test_dir_download_status_increment(void *arg) tt_int_op(mock_get_options_calls, OP_GE, 1); /* regression test for 17750: exponential, initial delay */ - mock_options->TestingClientDownloadSchedule = schedule; + mock_options->TestingClientDownloadInitialDelay = schedule; mock_get_options_calls = 0; /* we really want to test that it's equal to time(NULL) + delay0, but that's * an unrealiable test, because time(NULL) might change. */ @@ -4132,9 +4117,6 @@ test_dir_download_status_increment(void *arg) tt_int_op(mock_get_options_calls, OP_GE, 1); done: - /* the pointers in schedule are allocated on the stack */ - smartlist_free(schedule); - smartlist_free(schedule_no_initial_delay); UNMOCK(get_options); mock_options = NULL; mock_get_options_calls = 0; @@ -5452,7 +5434,7 @@ mock_num_bridges_usable(int use_maybe_reachable) * fallbacks. */ static void -test_dir_find_dl_schedule(void* data) +test_dir_find_dl_min_delay(void* data) { const char *str = (const char *)data; @@ -5485,44 +5467,45 @@ test_dir_find_dl_schedule(void* data) mock_num_bridges_usable); download_status_t dls; - smartlist_t server, client, server_cons, client_cons; - smartlist_t client_boot_auth_only_cons, client_boot_auth_cons; - smartlist_t client_boot_fallback_cons, bridge, bridge_bootstrap; + + const int server=10, client=20, server_cons=30, client_cons=40; + const int client_boot_auth_only_cons=50, client_boot_auth_cons=60; + const int client_boot_fallback_cons=70, bridge=80, bridge_bootstrap=90; mock_options = tor_malloc(sizeof(or_options_t)); reset_options(mock_options, &mock_get_options_calls); MOCK(get_options, mock_get_options); - mock_options->TestingServerDownloadSchedule = &server; - mock_options->TestingClientDownloadSchedule = &client; - mock_options->TestingServerConsensusDownloadSchedule = &server_cons; - mock_options->TestingClientConsensusDownloadSchedule = &client_cons; - mock_options->ClientBootstrapConsensusAuthorityOnlyDownloadSchedule = - &client_boot_auth_only_cons; - mock_options->ClientBootstrapConsensusAuthorityDownloadSchedule = - &client_boot_auth_cons; - mock_options->ClientBootstrapConsensusFallbackDownloadSchedule = - &client_boot_fallback_cons; - mock_options->TestingBridgeDownloadSchedule = &bridge; - mock_options->TestingBridgeBootstrapDownloadSchedule = &bridge_bootstrap; + mock_options->TestingServerDownloadInitialDelay = server; + mock_options->TestingClientDownloadInitialDelay = client; + mock_options->TestingServerConsensusDownloadInitialDelay = server_cons; + mock_options->TestingClientConsensusDownloadInitialDelay = client_cons; + mock_options->ClientBootstrapConsensusAuthorityOnlyDownloadInitialDelay = + client_boot_auth_only_cons; + mock_options->ClientBootstrapConsensusAuthorityDownloadInitialDelay = + client_boot_auth_cons; + mock_options->ClientBootstrapConsensusFallbackDownloadInitialDelay = + client_boot_fallback_cons; + mock_options->TestingBridgeDownloadInitialDelay = bridge; + mock_options->TestingBridgeBootstrapDownloadInitialDelay = bridge_bootstrap; dls.schedule = DL_SCHED_GENERIC; /* client */ mock_options->ClientOnly = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &client); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, client); mock_options->ClientOnly = 0; /* dir mode */ mock_options->DirPort_set = 1; mock_options->DirCache = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &server); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, server); mock_options->DirPort_set = 0; mock_options->DirCache = 0; dls.schedule = DL_SCHED_CONSENSUS; /* public server mode */ mock_options->ORPort_set = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &server_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, server_cons); mock_options->ORPort_set = 0; /* client and bridge modes */ @@ -5531,30 +5514,30 @@ test_dir_find_dl_schedule(void* data) dls.want_authority = 1; /* client */ mock_options->ClientOnly = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, - &client_boot_auth_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, + client_boot_auth_cons); mock_options->ClientOnly = 0; /* bridge relay */ mock_options->ORPort_set = 1; mock_options->BridgeRelay = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, - &client_boot_auth_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, + client_boot_auth_cons); mock_options->ORPort_set = 0; mock_options->BridgeRelay = 0; dls.want_authority = 0; /* client */ mock_options->ClientOnly = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, - &client_boot_fallback_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, + client_boot_fallback_cons); mock_options->ClientOnly = 0; /* bridge relay */ mock_options->ORPort_set = 1; mock_options->BridgeRelay = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, - &client_boot_fallback_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, + client_boot_fallback_cons); mock_options->ORPort_set = 0; mock_options->BridgeRelay = 0; @@ -5562,30 +5545,30 @@ test_dir_find_dl_schedule(void* data) /* dls.want_authority is ignored */ /* client */ mock_options->ClientOnly = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, - &client_boot_auth_only_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, + client_boot_auth_only_cons); mock_options->ClientOnly = 0; /* bridge relay */ mock_options->ORPort_set = 1; mock_options->BridgeRelay = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, - &client_boot_auth_only_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, + client_boot_auth_only_cons); mock_options->ORPort_set = 0; mock_options->BridgeRelay = 0; } } else { /* client */ mock_options->ClientOnly = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, - &client_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, + client_cons); mock_options->ClientOnly = 0; /* bridge relay */ mock_options->ORPort_set = 1; mock_options->BridgeRelay = 1; - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, - &client_cons); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, + client_cons); mock_options->ORPort_set = 0; mock_options->BridgeRelay = 0; } @@ -5595,9 +5578,9 @@ test_dir_find_dl_schedule(void* data) mock_options->ClientOnly = 1; mock_options->UseBridges = 1; if (num_bridges_usable(0) > 0) { - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &bridge); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, bridge); } else { - tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &bridge_bootstrap); + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, bridge_bootstrap); } done: @@ -5871,14 +5854,14 @@ struct testcase_t dir_tests[] = { DIR(dump_unparseable_descriptors, 0), DIR(populate_dump_desc_fifo, 0), DIR(populate_dump_desc_fifo_2, 0), - DIR_ARG(find_dl_schedule, TT_FORK, "bfd"), - DIR_ARG(find_dl_schedule, TT_FORK, "bad"), - DIR_ARG(find_dl_schedule, TT_FORK, "cfd"), - DIR_ARG(find_dl_schedule, TT_FORK, "cad"), - DIR_ARG(find_dl_schedule, TT_FORK, "bfr"), - DIR_ARG(find_dl_schedule, TT_FORK, "bar"), - DIR_ARG(find_dl_schedule, TT_FORK, "cfr"), - DIR_ARG(find_dl_schedule, TT_FORK, "car"), + DIR_ARG(find_dl_min_delay, TT_FORK, "bfd"), + DIR_ARG(find_dl_min_delay, TT_FORK, "bad"), + DIR_ARG(find_dl_min_delay, TT_FORK, "cfd"), + DIR_ARG(find_dl_min_delay, TT_FORK, "cad"), + DIR_ARG(find_dl_min_delay, TT_FORK, "bfr"), + DIR_ARG(find_dl_min_delay, TT_FORK, "bar"), + DIR_ARG(find_dl_min_delay, TT_FORK, "cfr"), + DIR_ARG(find_dl_min_delay, TT_FORK, "car"), DIR(assumed_flags, 0), DIR(networkstatus_compute_bw_weights_v10, 0), DIR(platform_str, 0), diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 92a860360d..f55e9f0173 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -2679,6 +2679,23 @@ test_enty_guard_should_expire_waiting(void *arg) tor_free(fake_state); } +/** Test that the number of primary guards can be controlled using torrc */ +static void +test_entry_guard_number_of_primaries(void *arg) +{ + (void) arg; + + /* Get default value */ + tt_int_op(get_n_primary_guards(), OP_EQ, DFLT_N_PRIMARY_GUARDS); + + /* Set number of primaries using torrc */ + get_options_mutable()->NumPrimaryGuards = 42; + tt_int_op(get_n_primary_guards(), OP_EQ, 42); + + done: + ; +} + static void mock_directory_initiate_request(directory_request_t *req) { @@ -2826,6 +2843,8 @@ struct testcase_t entrynodes_tests[] = { test_entry_guard_parse_from_state_broken, TT_FORK, NULL, NULL }, { "get_guard_selection_by_name", test_entry_guard_get_guard_selection_by_name, TT_FORK, NULL, NULL }, + { "number_of_primaries", + test_entry_guard_number_of_primaries, TT_FORK, NULL, NULL }, BFN_TEST(choose_selection_initial), BFN_TEST(add_single_guard), BFN_TEST(node_filter), diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c index 207a55de6d..308843e9b8 100644 --- a/src/test/test_hs_control.c +++ b/src/test/test_hs_control.c @@ -76,9 +76,8 @@ mock_node_get_by_id(const char *digest) { static node_t node; memcpy(node.identity, digest, DIGEST_LEN); - node.hsdir_index = tor_malloc_zero(sizeof(hsdir_index_t)); - memset(node.hsdir_index->fetch, 'C', DIGEST256_LEN); - memset(node.hsdir_index->store_first, 'D', DIGEST256_LEN); + memset(node.hsdir_index.fetch, 'C', DIGEST256_LEN); + memset(node.hsdir_index.store_first, 'D', DIGEST256_LEN); return &node; } diff --git a/src/test/test_options.c b/src/test/test_options.c index 9974ed2575..65564f324c 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -2067,12 +2067,12 @@ test_options_validate__testing(void *ignored) ENSURE_DEFAULT(TestingV3AuthVotingStartOffset, 3000); ENSURE_DEFAULT(TestingAuthDirTimeToLearnReachability, 3000); ENSURE_DEFAULT(TestingEstimatedDescriptorPropagationTime, 3000); - ENSURE_DEFAULT(TestingServerDownloadSchedule, 3000); - ENSURE_DEFAULT(TestingClientDownloadSchedule, 3000); - ENSURE_DEFAULT(TestingServerConsensusDownloadSchedule, 3000); - ENSURE_DEFAULT(TestingClientConsensusDownloadSchedule, 3000); - ENSURE_DEFAULT(TestingBridgeDownloadSchedule, 3000); - ENSURE_DEFAULT(TestingBridgeBootstrapDownloadSchedule, 3000); + ENSURE_DEFAULT(TestingServerDownloadInitialDelay, 3000); + ENSURE_DEFAULT(TestingClientDownloadInitialDelay, 3000); + ENSURE_DEFAULT(TestingServerConsensusDownloadInitialDelay, 3000); + ENSURE_DEFAULT(TestingClientConsensusDownloadInitialDelay, 3000); + ENSURE_DEFAULT(TestingBridgeDownloadInitialDelay, 3000); + ENSURE_DEFAULT(TestingBridgeBootstrapDownloadInitialDelay, 3000); ENSURE_DEFAULT(TestingClientMaxIntervalWithoutRequest, 3000); ENSURE_DEFAULT(TestingDirConnectionMaxStall, 3000); ENSURE_DEFAULT(TestingAuthKeyLifetime, 3000); diff --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c index bebbb5e584..34689b64f4 100644 --- a/src/test/test_periodic_event.c +++ b/src/test/test_periodic_event.c @@ -69,7 +69,7 @@ test_pe_initialize(void *arg) static void test_pe_launch(void *arg) { - hs_service_t service; + hs_service_t service, *to_remove = NULL; or_options_t *options; (void) arg; @@ -118,6 +118,10 @@ test_pe_launch(void *arg) options->ORPort_set = 1; periodic_events_on_new_options(options); + unsigned roles = get_my_roles(options); + tt_uint_op(roles, OP_EQ, + PERIODIC_EVENT_ROLE_RELAY|PERIODIC_EVENT_ROLE_DIRSERVER); + for (int i = 0; periodic_events[i].name; ++i) { periodic_event_item_t *item = &periodic_events[i]; /* Only Client role should be disabled. */ @@ -130,8 +134,8 @@ test_pe_launch(void *arg) tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1); tt_u64_op(item->last_action_time, OP_NE, 0); } - /* Non Relay role should be disabled! */ - if (!(item->roles & PERIODIC_EVENT_ROLE_RELAY)) { + /* Non Relay role should be disabled, except for Dirserver. */ + if (!(item->roles & roles)) { tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0); } } @@ -152,8 +156,11 @@ test_pe_launch(void *arg) options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1; register_dummy_hidden_service(&service); periodic_events_on_new_options(options); - /* Remove it now so the hs_free_all() doesn't try to free stack memory. */ - remove_service(get_hs_service_map(), &service); + /* Note down the reference because we need to remove this service from the + * global list before the hs_free_all() call so it doesn't try to free + * memory on the stack. Furthermore, we can't remove it now else it will + * trigger a rescan of the event disabling the HS service event. */ + to_remove = &service; for (int i = 0; periodic_events[i].name; ++i) { periodic_event_item_t *item = &periodic_events[i]; @@ -161,6 +168,9 @@ test_pe_launch(void *arg) } done: + if (to_remove) { + remove_service(get_hs_service_map(), to_remove); + } hs_free_all(); } @@ -190,19 +200,21 @@ test_pe_get_roles(void *arg) options->ORPort_set = 1; roles = get_my_roles(options); tt_int_op(roles, OP_EQ, - (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY)); + (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY | + PERIODIC_EVENT_ROLE_DIRSERVER)); /* Now add a Bridge. */ options->BridgeRelay = 1; roles = get_my_roles(options); tt_int_op(roles, OP_EQ, (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY | - PERIODIC_EVENT_ROLE_BRIDGE)); + PERIODIC_EVENT_ROLE_BRIDGE | PERIODIC_EVENT_ROLE_DIRSERVER)); tt_assert(roles & PERIODIC_EVENT_ROLE_ROUTER); /* Unset client so we can solely test Router role. */ options->SocksPort_set = 0; roles = get_my_roles(options); - tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_ROUTER); + tt_int_op(roles, OP_EQ, + PERIODIC_EVENT_ROLE_ROUTER | PERIODIC_EVENT_ROLE_DIRSERVER); /* Reset options so we can test authorities. */ options->SocksPort_set = 0; @@ -212,24 +224,28 @@ test_pe_get_roles(void *arg) tt_int_op(roles, OP_EQ, 0); /* Now upgrade to Dirauth. */ + options->DirPort_set = 1; options->AuthoritativeDir = 1; options->V3AuthoritativeDir = 1; roles = get_my_roles(options); - tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_DIRAUTH); + tt_int_op(roles, OP_EQ, + PERIODIC_EVENT_ROLE_DIRAUTH|PERIODIC_EVENT_ROLE_DIRSERVER); tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES); /* Now Bridge Authority. */ options->V3AuthoritativeDir = 0; options->BridgeAuthoritativeDir = 1; roles = get_my_roles(options); - tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_BRIDGEAUTH); + tt_int_op(roles, OP_EQ, + PERIODIC_EVENT_ROLE_BRIDGEAUTH|PERIODIC_EVENT_ROLE_DIRSERVER); tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES); /* Move that bridge auth to become a relay. */ options->ORPort_set = 1; roles = get_my_roles(options); tt_int_op(roles, OP_EQ, - (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY)); + (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY + | PERIODIC_EVENT_ROLE_DIRSERVER)); tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES); /* And now an Hidden service. */ @@ -240,13 +256,69 @@ test_pe_get_roles(void *arg) remove_service(get_hs_service_map(), &service); tt_int_op(roles, OP_EQ, (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY | - PERIODIC_EVENT_ROLE_HS_SERVICE)); + PERIODIC_EVENT_ROLE_HS_SERVICE | PERIODIC_EVENT_ROLE_DIRSERVER)); tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES); done: hs_free_all(); } +static void +test_pe_hs_service(void *arg) +{ + hs_service_t service, *to_remove = NULL; + + (void) arg; + + hs_init(); + /* We need to put tor in hibernation live state so the events requiring + * network gets enabled. */ + consider_hibernation(time(NULL)); + /* Initialize the events so we can enable them */ + initialize_periodic_events(); + + /* Hack: We'll set a dumb fn() of each events so they don't get called when + * dispatching them. We just want to test the state of the callbacks, not + * the whole code path. */ + for (int i = 0; periodic_events[i].name; ++i) { + periodic_event_item_t *item = &periodic_events[i]; + item->fn = dumb_event_fn; + } + + /* This should trigger a rescan of the list and enable the HS service + * events. */ + register_dummy_hidden_service(&service); + /* Note down the reference because we need to remove this service from the + * global list before the hs_free_all() call so it doesn't try to free + * memory on the stack. Furthermore, we can't remove it now else it will + * trigger a rescan of the event disabling the HS service event. */ + to_remove = &service; + + for (int i = 0; periodic_events[i].name; ++i) { + periodic_event_item_t *item = &periodic_events[i]; + if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) { + tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1); + } + } + to_remove = NULL; + + /* Remove the service from the global map, it should trigger a rescan and + * disable the HS service events. */ + remove_service(get_hs_service_map(), &service); + for (int i = 0; periodic_events[i].name; ++i) { + periodic_event_item_t *item = &periodic_events[i]; + if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) { + tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0); + } + } + + done: + if (to_remove) { + remove_service(get_hs_service_map(), to_remove); + } + hs_free_all(); +} + #define PE_TEST(name) \ { #name, test_pe_## name , TT_FORK, NULL, NULL } @@ -254,6 +326,7 @@ struct testcase_t periodic_event_tests[] = { PE_TEST(initialize), PE_TEST(launch), PE_TEST(get_roles), + PE_TEST(hs_service), END_OF_TESTCASES }; diff --git a/src/test/test_policy.c b/src/test/test_policy.c index f8aa8ac40b..f180585861 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -1923,11 +1923,8 @@ test_policies_fascist_firewall_allows_address(void *arg) tor_addr_port_t chosen_rs_ap; \ tor_addr_make_null(&chosen_rs_ap.addr, AF_INET); \ chosen_rs_ap.port = 0; \ - tt_int_op(fascist_firewall_choose_address_rs(&(fake_rs), \ - (fw_connection), \ - (pref_only), \ - &chosen_rs_ap), \ - OP_EQ, (expect_rv)); \ + fascist_firewall_choose_address_rs(&(fake_rs), (fw_connection), \ + (pref_only), &chosen_rs_ap); \ tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_rs_ap.addr)); \ tt_int_op((expect_ap).port, OP_EQ, chosen_rs_ap.port); \ STMT_END @@ -1940,11 +1937,8 @@ test_policies_fascist_firewall_allows_address(void *arg) tor_addr_port_t chosen_node_ap; \ tor_addr_make_null(&chosen_node_ap.addr, AF_INET); \ chosen_node_ap.port = 0; \ - tt_int_op(fascist_firewall_choose_address_node(&(fake_node), \ - (fw_connection), \ - (pref_only), \ - &chosen_node_ap), \ - OP_EQ, (expect_rv)); \ + fascist_firewall_choose_address_node(&(fake_node),(fw_connection), \ + (pref_only), &chosen_node_ap); \ tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_node_ap.addr)); \ tt_int_op((expect_ap).port, OP_EQ, chosen_node_ap.port); \ STMT_END diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c index 29f7cc9c37..ef1be139a6 100644 --- a/src/test/test_tortls.c +++ b/src/test/test_tortls.c @@ -203,6 +203,17 @@ test_tortls_tor_tls_get_error(void *data) } static void +library_init(void) +{ +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); +#else + SSL_library_init(); + SSL_load_error_strings(); +#endif +} + +static void test_tortls_get_state_description(void *ignored) { (void)ignored; @@ -210,9 +221,7 @@ test_tortls_get_state_description(void *ignored) char *buf; SSL_CTX *ctx; - SSL_library_init(); - SSL_load_error_strings(); - + library_init(); ctx = SSL_CTX_new(SSLv23_method()); buf = tor_malloc_zero(1000); @@ -274,8 +283,7 @@ test_tortls_get_by_ssl(void *ignored) SSL_CTX *ctx; SSL *ssl; - SSL_library_init(); - SSL_load_error_strings(); + library_init(); tor_tls_allocate_tor_tls_object_ex_data_index(); ctx = SSL_CTX_new(SSLv23_method()); @@ -322,8 +330,7 @@ test_tortls_log_one_error(void *ignored) SSL_CTX *ctx; SSL *ssl = NULL; - SSL_library_init(); - SSL_load_error_strings(); + library_init(); ctx = SSL_CTX_new(SSLv23_method()); tls = tor_malloc_zero(sizeof(tor_tls_t)); @@ -415,8 +422,7 @@ test_tortls_get_error(void *ignored) int ret; SSL_CTX *ctx; - SSL_library_init(); - SSL_load_error_strings(); + library_init(); ctx = SSL_CTX_new(SSLv23_method()); setup_capture_of_logs(LOG_INFO); @@ -792,8 +798,8 @@ test_tortls_classify_client_ciphers(void *ignored) STACK_OF(SSL_CIPHER) *ciphers; SSL_CIPHER *tmp_cipher; - SSL_library_init(); - SSL_load_error_strings(); + library_init(); + tor_tls_allocate_tor_tls_object_ex_data_index(); tls = tor_malloc_zero(sizeof(tor_tls_t)); @@ -897,8 +903,7 @@ test_tortls_client_is_using_v2_ciphers(void *ignored) SSL_SESSION *sess; STACK_OF(SSL_CIPHER) *ciphers; - SSL_library_init(); - SSL_load_error_strings(); + library_init(); ctx = SSL_CTX_new(TLSv1_method()); ssl = SSL_new(ctx); @@ -1541,8 +1546,8 @@ test_tortls_session_secret_cb(void *ignored) STACK_OF(SSL_CIPHER) *ciphers = NULL; SSL_CIPHER *one; - SSL_library_init(); - SSL_load_error_strings(); + library_init(); + tor_tls_allocate_tor_tls_object_ex_data_index(); tls = tor_malloc_zero(sizeof(tor_tls_t)); @@ -1733,8 +1738,7 @@ test_tortls_find_cipher_by_id(void *ignored) fixed_cipher2 = tor_malloc_zero(sizeof(SSL_CIPHER)); fixed_cipher2->id = 0xC00A; - SSL_library_init(); - SSL_load_error_strings(); + library_init(); ctx = SSL_CTX_new(m); ssl = SSL_new(ctx); @@ -1825,8 +1829,7 @@ test_tortls_server_info_callback(void *ignored) SSL_CTX *ctx; SSL *ssl; - SSL_library_init(); - SSL_load_error_strings(); + library_init(); ctx = SSL_CTX_new(TLSv1_method()); ssl = SSL_new(ctx); |