From b27dc1cfb5867ad5853548acc6e1167a49395917 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 3 Apr 2018 15:06:34 -0400 Subject: [PATCH 01/20] mod: Build system changes for dirauth module Make our build system support a disable dirauth module option. It can only be disabled explicitly with: $ ./configure --disable-module-dirauth If *not* specified that is enabled, an automake conditional variable is set to true and a defined value for the C code: AM_CONDITIONAL: BUILD_MODULE_DIRAUTH AC_DEFINE: HAVE_MODULE_DIRAUTH=1 This introduces the dirauth/ module directory in src/or/ for which .c files are only compiled if the BUILD_MODULE_DIRAUTH is set. All the header files are compiled in regardless of the support so we can use the alternative entry point functions of the dirauth subsystem. Signed-off-by: David Goulet --- configure.ac | 13 +++++++++++++ src/or/include.am | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/configure.ac b/configure.ac index 878f5a88bb..b423ea95e5 100644 --- a/configure.ac +++ b/configure.ac @@ -230,6 +230,19 @@ if test "x$enable_android" = "xyes"; then fi +dnl --- +dnl Tor modules options. These options are namespaced with --disable-module-XXX +dnl --- + +dnl Directory Authority module. +AC_ARG_ENABLE([module-dirauth], + AS_HELP_STRING([--disable-module-dirauth], + [Do not build tor with the dirauth module]), + [], dnl Action if-given + AC_DEFINE([HAVE_MODULE_DIRAUTH], [1], + [Compile with Directory Authority feature support])) +AM_CONDITIONAL(BUILD_MODULE_DIRAUTH, [test "x$enable_module_dirauth" != "xno"]) + dnl check for the correct "ar" when cross-compiling. dnl (AM_PROG_AR was new in automake 1.11.2, which we do not yet require, dnl so kludge up a replacement for the case where it isn't there yet.) diff --git a/src/or/include.am b/src/or/include.am index 9a68df5c3e..56d41e47dd 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -114,6 +114,16 @@ LIBTOR_A_SOURCES = \ src/or/onion_ntor.c \ $(tor_platform_source) +# +# Modules are conditionnally compiled in tor starting here. We add the C files +# only if the modules has been enabled at configure time. +# + +# The Directory Authority module. +if BUILD_MODULE_DIRAUTH +#LIBTOR_A_SOURCES += +endif + src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES) src_or_libtor_testing_a_SOURCES = $(LIBTOR_A_SOURCES) @@ -259,6 +269,12 @@ ORHEADERS = \ src/or/torcert.h \ src/or/tor_api_internal.h +# We add the headers of the modules even though they are disabled so we can +# properly compiled the entry points stub. + +# The Directory Authority module headers. +#ORHEADERS += + # This may someday want to be an installed file? noinst_HEADERS += src/or/tor_api.h From f0838e7257482e87a90f6844cb832a4ddf2197e5 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 5 Apr 2018 09:17:12 -0400 Subject: [PATCH 02/20] config: Make circuit_build_times_disabled() use authdir_mode() Don't access the AuthoritativeDir options directly. We do this so we can move authdir_mode() to the dirauth module. Signed-off-by: David Goulet --- src/or/circuitstats.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index 6438319273..6015bcf851 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -35,6 +35,7 @@ #include "networkstatus.h" #include "rendclient.h" #include "rendservice.h" +#include "router.h" #include "statefile.h" #include "circuitlist.h" #include "circuituse.h" @@ -125,7 +126,7 @@ circuit_build_times_disabled_(const or_options_t *options, ignore_consensus ? 0 : networkstatus_get_param(NULL, "cbtdisabled", 0, 0, 1); int config_disabled = !options->LearnCircuitBuildTimeout; - int dirauth_disabled = options->AuthoritativeDir; + int dirauth_disabled = authdir_mode(options); int state_disabled = did_last_state_file_write_fail() ? 1 : 0; /* LearnCircuitBuildTimeout and Tor2web/Single Onion Services are * incompatible in two ways: From d177067860c1c23fd3fe109e621710560fc6c43d Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 5 Apr 2018 11:18:47 -0400 Subject: [PATCH 03/20] dirvote: Trim down the public API Many functions become static to the C file or exposed to the tests within the PRIVATE define of dirvote.h. This commit moves a function to the top. No code behavior change. Signed-off-by: David Goulet --- src/or/dirvote.c | 104 +++++++++++++++++++------------------- src/or/dirvote.h | 42 +++++++-------- src/test/test_microdesc.c | 1 + 3 files changed, 72 insertions(+), 75 deletions(-) diff --git a/src/or/dirvote.c b/src/or/dirvote.c index f3b8a19f00..9f4893c37d 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -351,6 +351,53 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, * Consensus generation * ===== */ +/** If vrs has a hash made for the consensus method method with + * the digest algorithm alg, decode it and copy it into + * digest256_out and return 0. Otherwise return -1. */ +static int +vote_routerstatus_find_microdesc_hash(char *digest256_out, + const vote_routerstatus_t *vrs, + int method, + digest_algorithm_t alg) +{ + /* XXXX only returns the sha256 method. */ + const vote_microdesc_hash_t *h; + char mstr[64]; + size_t mlen; + char dstr[64]; + + tor_snprintf(mstr, sizeof(mstr), "%d", method); + mlen = strlen(mstr); + tor_snprintf(dstr, sizeof(dstr), " %s=", + crypto_digest_algorithm_get_name(alg)); + + for (h = vrs->microdesc; h; h = h->next) { + const char *cp = h->microdesc_hash_line; + size_t num_len; + /* cp looks like \d+(,\d+)* (digesttype=val )+ . Let's hunt for mstr in + * the first part. */ + while (1) { + num_len = strspn(cp, "1234567890"); + if (num_len == mlen && fast_memeq(mstr, cp, mlen)) { + /* This is the line. */ + char buf[BASE64_DIGEST256_LEN+1]; + /* XXXX ignores extraneous stuff if the digest is too long. This + * seems harmless enough, right? */ + cp = strstr(cp, dstr); + if (!cp) + return -1; + cp += strlen(dstr); + strlcpy(buf, cp, sizeof(buf)); + return digest256_from_base64(digest256_out, buf); + } + if (num_len == 0 || cp[num_len] != ',') + break; + cp += num_len + 1; + } + } + return -1; +} + /** Given a vote vote (not a consensus!), return its associated * networkstatus_voter_info_t. */ static networkstatus_voter_info_t * @@ -1328,7 +1375,7 @@ compute_nth_protocol_set(int n, int n_voters, const smartlist_t *votes) * behavior, and make the new behavior conditional on a new-enough * consensus_method. **/ -char * +STATIC char * networkstatus_compute_consensus(smartlist_t *votes, int total_authorities, crypto_pk_t *identity_key, @@ -2372,7 +2419,7 @@ compute_consensus_package_lines(smartlist_t *votes) * new signature is verifiable.) Return the number of signatures added or * changed, or -1 if the document signed by sigs isn't the same * document as target. */ -int +STATIC int networkstatus_add_detached_signatures(networkstatus_t *target, ns_detached_signatures_t *sigs, const char *source, @@ -2564,7 +2611,7 @@ networkstatus_format_signatures(networkstatus_t *consensus, * corresponding to the signatures on consensuses, which must contain * exactly one FLAV_NS consensus, and no more than one consensus for each * other flavor. */ -char * +STATIC char * networkstatus_get_detached_signatures(smartlist_t *consensuses) { smartlist_t *elements; @@ -3798,7 +3845,7 @@ dirvote_get_vote(const char *fp, int flags) /** Construct and return a new microdescriptor from a routerinfo ri * according to consensus_method. **/ -microdesc_t * +STATIC microdesc_t * dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) { microdesc_t *result = NULL; @@ -3893,7 +3940,7 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) * in a consensus vote document. Write it into the out_len-byte buffer * in out. Return -1 on failure and the number of characters written * on success. */ -ssize_t +static ssize_t dirvote_format_microdesc_vote_line(char *out_buf, size_t out_buf_len, const microdesc_t *md, int consensus_method_low, @@ -4001,50 +4048,3 @@ dirvote_format_all_microdesc_vote_lines(const routerinfo_t *ri, time_t now, return result; } -/** If vrs has a hash made for the consensus method method with - * the digest algorithm alg, decode it and copy it into - * digest256_out and return 0. Otherwise return -1. */ -int -vote_routerstatus_find_microdesc_hash(char *digest256_out, - const vote_routerstatus_t *vrs, - int method, - digest_algorithm_t alg) -{ - /* XXXX only returns the sha256 method. */ - const vote_microdesc_hash_t *h; - char mstr[64]; - size_t mlen; - char dstr[64]; - - tor_snprintf(mstr, sizeof(mstr), "%d", method); - mlen = strlen(mstr); - tor_snprintf(dstr, sizeof(dstr), " %s=", - crypto_digest_algorithm_get_name(alg)); - - for (h = vrs->microdesc; h; h = h->next) { - const char *cp = h->microdesc_hash_line; - size_t num_len; - /* cp looks like \d+(,\d+)* (digesttype=val )+ . Let's hunt for mstr in - * the first part. */ - while (1) { - num_len = strspn(cp, "1234567890"); - if (num_len == mlen && fast_memeq(mstr, cp, mlen)) { - /* This is the line. */ - char buf[BASE64_DIGEST256_LEN+1]; - /* XXXX ignores extraneous stuff if the digest is too long. This - * seems harmless enough, right? */ - cp = strstr(cp, dstr); - if (!cp) - return -1; - cp += strlen(dstr); - strlcpy(buf, cp, sizeof(buf)); - return digest256_from_base64(digest256_out, buf); - } - if (num_len == 0 || cp[num_len] != ',') - break; - cp += num_len + 1; - } - } - return -1; -} - diff --git a/src/or/dirvote.h b/src/or/dirvote.h index 8a317deb47..dd388fd961 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -89,19 +89,6 @@ void dirvote_free_all(void); /* vote manipulation */ -char *networkstatus_compute_consensus(smartlist_t *votes, - int total_authorities, - crypto_pk_t *identity_key, - crypto_pk_t *signing_key, - const char *legacy_identity_key_digest, - crypto_pk_t *legacy_signing_key, - consensus_flavor_t flavor); -int networkstatus_add_detached_signatures(networkstatus_t *target, - ns_detached_signatures_t *sigs, - const char *source, - int severity, - const char **msg_out); -char *networkstatus_get_detached_signatures(smartlist_t *consensuses); void ns_detached_signatures_free_(ns_detached_signatures_t *s); #define ns_detached_signatures_free(s) \ FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s)) @@ -178,21 +165,11 @@ networkstatus_t * dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, authority_cert_t *cert); -microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, - int consensus_method); -ssize_t dirvote_format_microdesc_vote_line(char *out, size_t out_len, - const microdesc_t *md, - int consensus_method_low, - int consensus_method_high); vote_microdesc_hash_t *dirvote_format_all_microdesc_vote_lines( const routerinfo_t *ri, time_t now, smartlist_t *microdescriptors_out); -int vote_routerstatus_find_microdesc_hash(char *digest256_out, - const vote_routerstatus_t *vrs, - int method, - digest_algorithm_t alg); document_signature_t *voter_get_sig_by_algorithm( const networkstatus_voter_info_t *voter, digest_algorithm_t alg); @@ -212,6 +189,25 @@ STATIC int networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, int64_t M, int64_t E, int64_t D, int64_t T, int64_t weight_scale); +STATIC +char *networkstatus_compute_consensus(smartlist_t *votes, + int total_authorities, + crypto_pk_t *identity_key, + crypto_pk_t *signing_key, + const char *legacy_identity_key_digest, + crypto_pk_t *legacy_signing_key, + consensus_flavor_t flavor); +STATIC +int networkstatus_add_detached_signatures(networkstatus_t *target, + ns_detached_signatures_t *sigs, + const char *source, + int severity, + const char **msg_out); +STATIC +char *networkstatus_get_detached_signatures(smartlist_t *consensuses); +STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, + int consensus_method); + #endif /* defined(DIRVOTE_PRIVATE) */ #endif /* !defined(TOR_DIRVOTE_H) */ diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 3d02fc1a59..94b4d5e51f 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -5,6 +5,7 @@ #include "or.h" #include "config.h" +#define DIRVOTE_PRIVATE #include "dirvote.h" #include "microdesc.h" #include "networkstatus.h" From 5e1e906a5c479ba9294d345b0221c99725d45d8c Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 5 Apr 2018 11:27:39 -0400 Subject: [PATCH 04/20] dirvote: Move voting_schedule_t to dirvote.c Signed-off-by: David Goulet --- src/or/dirvote.c | 34 ++++++++++++++++++++++++++++++++++ src/or/dirvote.h | 36 ------------------------------------ 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 9f4893c37d..67ab1d4ffb 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -72,6 +72,40 @@ typedef struct pending_consensus_t { networkstatus_t *consensus; } pending_consensus_t; +/** Scheduling information for a voting interval. */ +typedef struct { + /** When do we generate and distribute our vote for this interval? */ + time_t voting_starts; + /** When do we send an HTTP request for any votes that we haven't + * been posted yet?*/ + time_t fetch_missing_votes; + /** When do we give up on getting more votes and generate a consensus? */ + time_t voting_ends; + /** When do we send an HTTP request for any signatures we're expecting to + * see on the consensus? */ + time_t fetch_missing_signatures; + /** When do we publish the consensus? */ + time_t interval_starts; + + /* True iff we have generated and distributed our vote. */ + int have_voted; + /* True iff we've requested missing votes. */ + int have_fetched_missing_votes; + /* True iff we have built a consensus and sent the signatures around. */ + int have_built_consensus; + /* True iff we've fetched missing signatures. */ + int have_fetched_missing_signatures; + /* True iff we have published our consensus. */ + int have_published_consensus; + + /* True iff this voting schedule was set on demand meaning not through the + * normal vote operation of a dirauth or when a consensus is set. This only + * applies to a directory authority that needs to recalculate the voting + * timings only for the first vote even though this object was initilized + * prior to voting. */ + int created_on_demand; +} voting_schedule_t; + /* DOCDOC dirvote_add_signatures_to_all_pending_consensuses */ static int dirvote_add_signatures_to_all_pending_consensuses( const char *detached_signatures_body, diff --git a/src/or/dirvote.h b/src/or/dirvote.h index dd388fd961..88d0d56ff2 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -96,42 +96,6 @@ void ns_detached_signatures_free_(ns_detached_signatures_t *s); /* cert manipulation */ authority_cert_t *authority_cert_dup(authority_cert_t *cert); -/* vote scheduling */ - -/** Scheduling information for a voting interval. */ -typedef struct { - /** When do we generate and distribute our vote for this interval? */ - time_t voting_starts; - /** When do we send an HTTP request for any votes that we haven't - * been posted yet?*/ - time_t fetch_missing_votes; - /** When do we give up on getting more votes and generate a consensus? */ - time_t voting_ends; - /** When do we send an HTTP request for any signatures we're expecting to - * see on the consensus? */ - time_t fetch_missing_signatures; - /** When do we publish the consensus? */ - time_t interval_starts; - - /* True iff we have generated and distributed our vote. */ - int have_voted; - /* True iff we've requested missing votes. */ - int have_fetched_missing_votes; - /* True iff we have built a consensus and sent the signatures around. */ - int have_built_consensus; - /* True iff we've fetched missing signatures. */ - int have_fetched_missing_signatures; - /* True iff we have published our consensus. */ - int have_published_consensus; - - /* True iff this voting schedule was set on demand meaning not through the - * normal vote operation of a dirauth or when a consensus is set. This only - * applies to a directory authority that needs to recalculate the voting - * timings only for the first vote even though this object was initilized - * prior to voting. */ - int created_on_demand; -} voting_schedule_t; - void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); time_t dirvote_get_start_of_next_interval(time_t now, int interval, From 35d86b088dd97c65e0af48b4f186682fb011f283 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 5 Apr 2018 11:38:37 -0400 Subject: [PATCH 05/20] dirvote: Reorganize the dirvote.h file Remove useless include. Clearly identify functions that are used by other part of Tor, functions that are only used by the dirauth subsystem and functions that are exposed for unit tests. This will help us in the dirauth modularization effort. Signed-off-by: David Goulet --- src/or/dirvote.h | 54 ++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/src/or/dirvote.h b/src/or/dirvote.h index 88d0d56ff2..4f1f35d856 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -12,8 +12,6 @@ #ifndef TOR_DIRVOTE_H #define TOR_DIRVOTE_H -#include "testsupport.h" - /* * Ideally, assuming synced clocks, we should only need 1 second for each of: * - Vote @@ -86,41 +84,53 @@ * get confused with the above macros.) */ #define DEFAULT_MAX_UNMEASURED_BW_KB 20 +/* Directory Get Vote (DGV) flags for dirvote_get_vote(). */ +#define DGV_BY_ID 1 +#define DGV_INCLUDE_PENDING 2 +#define DGV_INCLUDE_PREVIOUS 4 + +/* + * Public API. Used outside of the dirauth subsystem. + */ + void dirvote_free_all(void); -/* vote manipulation */ +/* Vote manipulation */ void ns_detached_signatures_free_(ns_detached_signatures_t *s); #define ns_detached_signatures_free(s) \ FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s)) -/* cert manipulation */ -authority_cert_t *authority_cert_dup(authority_cert_t *cert); - -void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); -time_t dirvote_get_start_of_next_interval(time_t now, - int interval, - int offset); void dirvote_recalculate_timing(const or_options_t *options, time_t now); void dirvote_act(const or_options_t *options, time_t now); -time_t dirvote_get_next_valid_after_time(void); - -/* invoked on timers and by outside triggers. */ +/* Invoked on timers and by outside triggers. */ struct pending_vote_t * dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out); int dirvote_add_signatures(const char *detached_signatures_body, const char *source, const char **msg_out); - /* Item access */ MOCK_DECL(const char*, dirvote_get_pending_consensus, (consensus_flavor_t flav)); MOCK_DECL(const char*, dirvote_get_pending_detached_signatures, (void)); - -#define DGV_BY_ID 1 -#define DGV_INCLUDE_PENDING 2 -#define DGV_INCLUDE_PREVIOUS 4 const cached_dir_t *dirvote_get_vote(const char *fp, int flags); +document_signature_t *voter_get_sig_by_algorithm( + const networkstatus_voter_info_t *voter, + digest_algorithm_t alg); + +/* + * API used _only_ by the dirauth subsystem. + */ + +/* Cert manipulation */ +authority_cert_t *authority_cert_dup(authority_cert_t *cert); + +void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); +time_t dirvote_get_start_of_next_interval(time_t now, + int interval, + int offset); +time_t dirvote_get_next_valid_after_time(void); + void set_routerstatus_from_routerinfo(routerstatus_t *rs, node_t *node, routerinfo_t *ri, time_t now, @@ -134,11 +144,11 @@ vote_microdesc_hash_t *dirvote_format_all_microdesc_vote_lines( time_t now, smartlist_t *microdescriptors_out); -document_signature_t *voter_get_sig_by_algorithm( - const networkstatus_voter_info_t *voter, - digest_algorithm_t alg); - +/* + * Exposed functions for unit tests. + */ #ifdef DIRVOTE_PRIVATE + STATIC int32_t dirvote_get_intermediate_param_value( const smartlist_t *param_list, const char *keyword, From 2115a54b4ab91d6d573691fc7368fcb8a2db32af Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 5 Apr 2018 14:27:30 -0400 Subject: [PATCH 06/20] mod: Move dirauth specific files to its own module This is a pretty big commit but it only moves these files to src/or/dirauth: dircollate.c dirvote.c shared_random.c shared_random_state.c dircollate.h dirvote.h shared_random.h shared_random_state.h Then many files are modified to change the include line for those header files that have moved into a new directory. Without using --disable-module-dirauth, everything builds fine. When using the flag to disable the module, tor doesn't build due to linking errors. This will be addressed in the next commit(s). No code behavior change. Signed-off-by: David Goulet --- src/or/config.c | 3 ++- src/or/control.c | 2 +- src/or/{ => dirauth}/dircollate.c | 0 src/or/{ => dirauth}/dircollate.h | 0 src/or/{ => dirauth}/dirvote.c | 0 src/or/{ => dirauth}/dirvote.h | 0 src/or/{ => dirauth}/shared_random.c | 3 ++- src/or/{ => dirauth}/shared_random.h | 0 src/or/{ => dirauth}/shared_random_state.c | 3 ++- src/or/{ => dirauth}/shared_random_state.h | 0 src/or/directory.c | 5 +++-- src/or/dirserv.c | 3 ++- src/or/hs_common.c | 4 ++-- src/or/hs_service.c | 2 +- src/or/include.am | 20 ++++++++++---------- src/or/main.c | 5 +++-- src/or/networkstatus.c | 5 +++-- src/or/routerlist.c | 3 ++- src/or/routerparse.c | 5 +++-- src/test/test_config.c | 2 +- src/test/test_dir.c | 4 ++-- src/test/test_dir_common.c | 2 +- src/test/test_dir_handle_get.c | 2 +- src/test/test_hs_common.c | 4 ++-- src/test/test_hs_service.c | 4 ++-- src/test/test_microdesc.c | 2 +- src/test/test_routerlist.c | 4 ++-- src/test/test_shared_random.c | 6 +++--- 28 files changed, 51 insertions(+), 42 deletions(-) rename src/or/{ => dirauth}/dircollate.c (100%) rename src/or/{ => dirauth}/dircollate.h (100%) rename src/or/{ => dirauth}/dirvote.c (100%) rename src/or/{ => dirauth}/dirvote.h (100%) rename src/or/{ => dirauth}/shared_random.c (99%) rename src/or/{ => dirauth}/shared_random.h (100%) rename src/or/{ => dirauth}/shared_random_state.c (99%) rename src/or/{ => dirauth}/shared_random_state.h (100%) diff --git a/src/or/config.c b/src/or/config.c index 87a3588db7..8f5839e2d5 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -79,7 +79,6 @@ #include "confparse.h" #include "cpuworker.h" #include "dirserv.h" -#include "dirvote.h" #include "dns.h" #include "dos.h" #include "entrynodes.h" @@ -110,6 +109,8 @@ #include "procmon.h" +#include "dirauth/dirvote.h" + #ifdef HAVE_SYSTEMD # if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) /* Systemd's use of gcc's __INCLUDE_LEVEL__ extension macro appears to confuse diff --git a/src/or/control.c b/src/or/control.c index dda8872182..3e643c2d76 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -76,7 +76,7 @@ #include "router.h" #include "routerlist.h" #include "routerparse.h" -#include "shared_random.h" +#include "dirauth/shared_random.h" #ifndef _WIN32 #include diff --git a/src/or/dircollate.c b/src/or/dirauth/dircollate.c similarity index 100% rename from src/or/dircollate.c rename to src/or/dirauth/dircollate.c diff --git a/src/or/dircollate.h b/src/or/dirauth/dircollate.h similarity index 100% rename from src/or/dircollate.h rename to src/or/dirauth/dircollate.h diff --git a/src/or/dirvote.c b/src/or/dirauth/dirvote.c similarity index 100% rename from src/or/dirvote.c rename to src/or/dirauth/dirvote.c diff --git a/src/or/dirvote.h b/src/or/dirauth/dirvote.h similarity index 100% rename from src/or/dirvote.h rename to src/or/dirauth/dirvote.h diff --git a/src/or/shared_random.c b/src/or/dirauth/shared_random.c similarity index 99% rename from src/or/shared_random.c rename to src/or/dirauth/shared_random.c index 13416d6bc7..e9644adf9e 100644 --- a/src/or/shared_random.c +++ b/src/or/dirauth/shared_random.c @@ -91,7 +91,6 @@ #include "shared_random.h" #include "config.h" #include "confparse.h" -#include "dirvote.h" #include "networkstatus.h" #include "routerkeys.h" #include "router.h" @@ -99,6 +98,8 @@ #include "shared_random_state.h" #include "util.h" +#include "dirauth/dirvote.h" + /* String prefix of shared random values in votes/consensuses. */ static const char previous_srv_str[] = "shared-rand-previous-value"; static const char current_srv_str[] = "shared-rand-current-value"; diff --git a/src/or/shared_random.h b/src/or/dirauth/shared_random.h similarity index 100% rename from src/or/shared_random.h rename to src/or/dirauth/shared_random.h diff --git a/src/or/shared_random_state.c b/src/or/dirauth/shared_random_state.c similarity index 99% rename from src/or/shared_random_state.c rename to src/or/dirauth/shared_random_state.c index 53782af59a..11d7a06378 100644 --- a/src/or/shared_random_state.c +++ b/src/or/dirauth/shared_random_state.c @@ -14,11 +14,12 @@ #include "shared_random.h" #include "config.h" #include "confparse.h" -#include "dirvote.h" #include "networkstatus.h" #include "router.h" #include "shared_random_state.h" +#include "dirauth/dirvote.h" + /* Default filename of the shared random state on disk. */ static const char default_fname[] = "sr-state"; diff --git a/src/or/shared_random_state.h b/src/or/dirauth/shared_random_state.h similarity index 100% rename from src/or/shared_random_state.h rename to src/or/dirauth/shared_random_state.h diff --git a/src/or/directory.c b/src/or/directory.c index c419b61d02..8a343ac02c 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -20,7 +20,6 @@ #include "compat.h" #include "directory.h" #include "dirserv.h" -#include "dirvote.h" #include "entrynodes.h" #include "geoip.h" #include "hs_cache.h" @@ -41,7 +40,7 @@ #include "routerlist.h" #include "routerparse.h" #include "routerset.h" -#include "shared_random.h" +#include "dirauth/shared_random.h" #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) #if !defined(OpenBSD) @@ -49,6 +48,8 @@ #endif #endif +#include "dirauth/dirvote.h" + /** * \file directory.c * \brief Code to send and fetch information from directory authorities and diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 68727f0718..c20e2966c3 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -18,7 +18,6 @@ #include "control.h" #include "directory.h" #include "dirserv.h" -#include "dirvote.h" #include "hibernate.h" #include "keypin.h" #include "main.h" @@ -34,6 +33,8 @@ #include "routerset.h" #include "torcert.h" +#include "dirauth/dirvote.h" + /** * \file dirserv.c * \brief Directory server core implementation. Manages directory diff --git a/src/or/hs_common.c b/src/or/hs_common.c index 24eb7a104a..fc7bc5729b 100644 --- a/src/or/hs_common.c +++ b/src/or/hs_common.c @@ -28,8 +28,8 @@ #include "rendservice.h" #include "routerset.h" #include "router.h" -#include "shared_random.h" -#include "shared_random_state.h" +#include "dirauth/shared_random.h" +#include "dirauth/shared_random_state.h" /* Trunnel */ #include "ed25519_cert.h" diff --git a/src/or/hs_service.c b/src/or/hs_service.c index f6c7e3cd81..ebb58f7f68 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -24,7 +24,7 @@ #include "router.h" #include "routerkeys.h" #include "routerlist.h" -#include "shared_random_state.h" +#include "dirauth/shared_random_state.h" #include "statefile.h" #include "hs_circuit.h" diff --git a/src/or/include.am b/src/or/include.am index 56d41e47dd..9265ecf483 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -41,10 +41,8 @@ LIBTOR_A_SOURCES = \ src/or/consdiffmgr.c \ src/or/control.c \ src/or/cpuworker.c \ - src/or/dircollate.c \ src/or/directory.c \ src/or/dirserv.c \ - src/or/dirvote.c \ src/or/dns.c \ src/or/dnsserv.c \ src/or/dos.c \ @@ -76,8 +74,6 @@ LIBTOR_A_SOURCES = \ src/or/onion.c \ src/or/onion_fast.c \ src/or/onion_tap.c \ - src/or/shared_random.c \ - src/or/shared_random_state.c \ src/or/transports.c \ src/or/parsecommon.c \ src/or/periodic.c \ @@ -121,7 +117,11 @@ LIBTOR_A_SOURCES = \ # The Directory Authority module. if BUILD_MODULE_DIRAUTH -#LIBTOR_A_SOURCES += +LIBTOR_A_SOURCES += \ + src/or/dirauth/dircollate.c \ + src/or/dirauth/dirvote.c \ + src/or/dirauth/shared_random.c \ + src/or/dirauth/shared_random_state.c endif src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES) @@ -195,10 +195,8 @@ ORHEADERS = \ src/or/consdiffmgr.h \ src/or/control.h \ src/or/cpuworker.h \ - src/or/dircollate.h \ src/or/directory.h \ src/or/dirserv.h \ - src/or/dirvote.h \ src/or/dns.h \ src/or/dns_structs.h \ src/or/dnsserv.h \ @@ -235,8 +233,6 @@ ORHEADERS = \ src/or/onion_ntor.h \ src/or/onion_tap.h \ src/or/or.h \ - src/or/shared_random.h \ - src/or/shared_random_state.h \ src/or/transports.h \ src/or/parsecommon.h \ src/or/periodic.h \ @@ -273,7 +269,11 @@ ORHEADERS = \ # properly compiled the entry points stub. # The Directory Authority module headers. -#ORHEADERS += +ORHEADERS += \ + src/or/dirauth/dircollate.h \ + src/or/dirauth/dirvote.h \ + src/or/dirauth/shared_random.h \ + src/or/dirauth/shared_random_state.h # This may someday want to be an installed file? noinst_HEADERS += src/or/tor_api.h diff --git a/src/or/main.c b/src/or/main.c index c1103edb3a..b7b7b71624 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -72,7 +72,6 @@ #include "crypto_s2k.h" #include "directory.h" #include "dirserv.h" -#include "dirvote.h" #include "dns.h" #include "dnsserv.h" #include "dos.h" @@ -103,7 +102,7 @@ #include "routerlist.h" #include "routerparse.h" #include "scheduler.h" -#include "shared_random.h" +#include "dirauth/shared_random.h" #include "statefile.h" #include "status.h" #include "tor_api.h" @@ -118,6 +117,8 @@ #include +#include "dirauth/dirvote.h" + #ifdef HAVE_SYSTEMD # if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) /* Systemd's use of gcc's __INCLUDE_LEVEL__ extension macro appears to confuse diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index b0db0cecbc..f78d9d672b 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -50,7 +50,6 @@ #include "control.h" #include "directory.h" #include "dirserv.h" -#include "dirvote.h" #include "dos.h" #include "entrynodes.h" #include "hibernate.h" @@ -64,11 +63,13 @@ #include "routerlist.h" #include "routerparse.h" #include "scheduler.h" -#include "shared_random.h" +#include "dirauth/shared_random.h" #include "transports.h" #include "torcert.h" #include "channelpadding.h" +#include "dirauth/dirvote.h" + /** Most recently received and validated v3 "ns"-flavored consensus network * status. */ STATIC networkstatus_t *current_ns_consensus = NULL; diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 1bfbd9f670..7eb9ec7990 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -101,7 +101,6 @@ #include "control.h" #include "directory.h" #include "dirserv.h" -#include "dirvote.h" #include "entrynodes.h" #include "fp_pair.h" #include "geoip.h" @@ -122,6 +121,8 @@ #include "sandbox.h" #include "torcert.h" +#include "dirauth/dirvote.h" + // #define DEBUG_ROUTERLIST /****************************************************************************/ diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 1834cfad24..84db239155 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -59,7 +59,6 @@ #include "config.h" #include "circuitstats.h" #include "dirserv.h" -#include "dirvote.h" #include "parsecommon.h" #include "policies.h" #include "protover.h" @@ -75,11 +74,13 @@ #include "entrynodes.h" #include "torcert.h" #include "sandbox.h" -#include "shared_random.h" +#include "dirauth/shared_random.h" #undef log #include +#include "dirauth/dirvote.h" + /****************************************************************************/ /** List of tokens recognized in router descriptors */ diff --git a/src/test/test_config.c b/src/test/test_config.c index 7983106a2f..461aa646d6 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -24,7 +24,7 @@ #include "control.h" #include "cpuworker.h" #include "dirserv.h" -#include "dirvote.h" +#include "dirauth/dirvote.h" #include "dns.h" #include "entrynodes.h" #include "transports.h" diff --git a/src/test/test_dir.c b/src/test/test_dir.c index df5ae2d594..74153c671a 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -25,7 +25,7 @@ #include "crypto_ed25519.h" #include "directory.h" #include "dirserv.h" -#include "dirvote.h" +#include "dirauth/dirvote.h" #include "entrynodes.h" #include "hibernate.h" #include "memarea.h" @@ -35,7 +35,7 @@ #include "routerlist.h" #include "routerparse.h" #include "routerset.h" -#include "shared_random_state.h" +#include "dirauth/shared_random_state.h" #include "test.h" #include "test_dir_common.h" #include "torcert.h" diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c index fdf43533a8..c3e3662fde 100644 --- a/src/test/test_dir_common.c +++ b/src/test/test_dir_common.c @@ -9,7 +9,7 @@ #include "test.h" #include "container.h" #include "or.h" -#include "dirvote.h" +#include "dirauth/dirvote.h" #include "nodelist.h" #include "routerlist.h" #include "test_dir_common.h" diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index 71faf70af2..1bff249df5 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -30,7 +30,7 @@ #include "proto_http.h" #include "geoip.h" #include "dirserv.h" -#include "dirvote.h" +#include "dirauth/dirvote.h" #include "log_test_helpers.h" #ifdef _WIN32 diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c index 17ba11ca7d..43a2c5e80c 100644 --- a/src/test/test_hs_common.c +++ b/src/test/test_hs_common.c @@ -23,12 +23,12 @@ #include "config.h" #include "networkstatus.h" #include "directory.h" -#include "dirvote.h" +#include "dirauth/dirvote.h" #include "nodelist.h" #include "routerlist.h" #include "statefile.h" #include "circuitlist.h" -#include "shared_random.h" +#include "dirauth/shared_random.h" #include "util.h" /** Test the validation of HS v3 addresses */ diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index 481521520c..fc8e016b52 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -34,7 +34,7 @@ #include "circuitlist.h" #include "circuituse.h" #include "crypto.h" -#include "dirvote.h" +#include "dirauth/dirvote.h" #include "networkstatus.h" #include "nodelist.h" #include "relay.h" @@ -51,7 +51,7 @@ #include "main.h" #include "rendservice.h" #include "statefile.h" -#include "shared_random_state.h" +#include "dirauth/shared_random_state.h" /* Trunnel */ #include "hs/cell_establish_intro.h" diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 94b4d5e51f..4b168f49ed 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -6,7 +6,7 @@ #include "config.h" #define DIRVOTE_PRIVATE -#include "dirvote.h" +#include "dirauth/dirvote.h" #include "microdesc.h" #include "networkstatus.h" #include "routerlist.h" diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index c19d66ef9d..71b487f35b 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -19,7 +19,7 @@ #include "container.h" #include "control.h" #include "directory.h" -#include "dirvote.h" +#include "dirauth/dirvote.h" #include "entrynodes.h" #include "hibernate.h" #include "microdesc.h" @@ -30,7 +30,7 @@ #include "routerlist.h" #include "routerset.h" #include "routerparse.h" -#include "shared_random.h" +#include "dirauth/shared_random.h" #include "statefile.h" #include "test.h" #include "test_dir_common.h" diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 4fe9ee45f0..30d0d44cac 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -9,9 +9,9 @@ #include "or.h" #include "test.h" #include "config.h" -#include "dirvote.h" -#include "shared_random.h" -#include "shared_random_state.h" +#include "dirauth/dirvote.h" +#include "dirauth/shared_random.h" +#include "dirauth/shared_random_state.h" #include "routerkeys.h" #include "routerlist.h" #include "router.h" From bdcf3a383932cc48a360c9a75b93b44a6968171e Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 24 Apr 2018 11:34:31 -0400 Subject: [PATCH 07/20] sr: Extract shared SR functions Move most of the shared random functions that are needed outside of the dirauth module. At this commit, because dirvote.c hasn't been refactor, it doesn't compile because some SR functions need a dirvote function. Furthermore, 5 functions haven't been touched yet because they are dirauth only but are in used in other C files than the dirauth module ones. No code behavior change. Only moving code around. Signed-off-by: David Goulet --- src/or/control.c | 2 +- src/or/dirauth/shared_random.c | 163 +---------------- src/or/dirauth/shared_random.h | 8 - src/or/dirauth/shared_random_state.c | 80 +-------- src/or/dirauth/shared_random_state.h | 5 - src/or/hs_common.c | 2 +- src/or/hs_service.c | 2 +- src/or/include.am | 2 + src/or/routerparse.c | 1 + src/or/shared_random_common.c | 258 +++++++++++++++++++++++++++ src/or/shared_random_common.h | 47 +++++ 11 files changed, 313 insertions(+), 257 deletions(-) create mode 100644 src/or/shared_random_common.c create mode 100644 src/or/shared_random_common.h diff --git a/src/or/control.c b/src/or/control.c index 3e643c2d76..aab854ecdd 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -76,7 +76,7 @@ #include "router.h" #include "routerlist.h" #include "routerparse.h" -#include "dirauth/shared_random.h" +#include "shared_random_common.h" #ifndef _WIN32 #include diff --git a/src/or/dirauth/shared_random.c b/src/or/dirauth/shared_random.c index e9644adf9e..5dee77dce9 100644 --- a/src/or/dirauth/shared_random.c +++ b/src/or/dirauth/shared_random.c @@ -96,6 +96,7 @@ #include "router.h" #include "routerlist.h" #include "shared_random_state.h" +#include "shared_random_common.h" #include "util.h" #include "dirauth/dirvote.h" @@ -499,20 +500,6 @@ get_vote_line_from_commit(const sr_commit_t *commit, sr_phase_t phase) return vote_line; } -/* Convert a given srv object to a string for the control port. This doesn't - * fail and the srv object MUST be valid. */ -static char * -srv_to_control_string(const sr_srv_t *srv) -{ - char *srv_str; - char srv_hash_encoded[SR_SRV_VALUE_BASE64_LEN + 1]; - tor_assert(srv); - - sr_srv_encode(srv_hash_encoded, sizeof(srv_hash_encoded), srv); - tor_asprintf(&srv_str, "%s", srv_hash_encoded); - return srv_str; -} - /* Return a heap allocated string that contains the given srv string * representation formatted for a networkstatus document using the * key as the start of the line. This doesn't return NULL. */ @@ -875,27 +862,6 @@ get_majority_srv_from_votes(const smartlist_t *votes, int current) return the_srv; } -/* Encode the given shared random value and put it in dst. Destination - * buffer must be at least SR_SRV_VALUE_BASE64_LEN plus the NULL byte. */ -void -sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv) -{ - int ret; - /* Extra byte for the NULL terminated char. */ - char buf[SR_SRV_VALUE_BASE64_LEN + 1]; - - tor_assert(dst); - tor_assert(srv); - tor_assert(dst_len >= sizeof(buf)); - - ret = base64_encode(buf, sizeof(buf), (const char *) srv->value, - sizeof(srv->value), 0); - /* Always expect the full length without the NULL byte. */ - tor_assert(ret == (sizeof(buf) - 1)); - tor_assert(ret <= (int) dst_len); - strlcpy(dst, buf, dst_len); -} - /* Free a commit object. */ void sr_commit_free_(sr_commit_t *commit) @@ -1037,55 +1003,6 @@ sr_compute_srv(void) tor_free(reveals); } -/* Parse a list of arguments from a SRV value either from a vote, consensus - * or from our disk state and return a newly allocated srv object. NULL is - * returned on error. - * - * The arguments' order: - * num_reveals, value - */ -sr_srv_t * -sr_parse_srv(const smartlist_t *args) -{ - char *value; - int ok, ret; - uint64_t num_reveals; - sr_srv_t *srv = NULL; - - tor_assert(args); - - if (smartlist_len(args) < 2) { - goto end; - } - - /* First argument is the number of reveal values */ - num_reveals = tor_parse_uint64(smartlist_get(args, 0), - 10, 0, UINT64_MAX, &ok, NULL); - if (!ok) { - goto end; - } - /* Second and last argument is the shared random value it self. */ - value = smartlist_get(args, 1); - if (strlen(value) != SR_SRV_VALUE_BASE64_LEN) { - goto end; - } - - srv = tor_malloc_zero(sizeof(*srv)); - srv->num_reveals = num_reveals; - /* We subtract one byte from the srclen because the function ignores the - * '=' character in the given buffer. This is broken but it's a documented - * behavior of the implementation. */ - ret = base64_decode((char *) srv->value, sizeof(srv->value), value, - SR_SRV_VALUE_BASE64_LEN - 1); - if (ret != sizeof(srv->value)) { - tor_free(srv); - srv = NULL; - goto end; - } - end: - return srv; -} - /* Parse a commit from a vote or from our disk state and return a newly * allocated commit object. NULL is returned on error. * @@ -1353,84 +1270,6 @@ sr_save_and_cleanup(void) sr_cleanup(); } -/* Return the current SRV string representation for the control port. Return a - * newly allocated string on success containing the value else "" if not found - * or if we don't have a valid consensus yet. */ -char * -sr_get_current_for_control(void) -{ - char *srv_str; - const networkstatus_t *c = networkstatus_get_latest_consensus(); - if (c && c->sr_info.current_srv) { - srv_str = srv_to_control_string(c->sr_info.current_srv); - } else { - srv_str = tor_strdup(""); - } - return srv_str; -} - -/* Return the previous SRV string representation for the control port. Return - * a newly allocated string on success containing the value else "" if not - * found or if we don't have a valid consensus yet. */ -char * -sr_get_previous_for_control(void) -{ - char *srv_str; - const networkstatus_t *c = networkstatus_get_latest_consensus(); - if (c && c->sr_info.previous_srv) { - srv_str = srv_to_control_string(c->sr_info.previous_srv); - } else { - srv_str = tor_strdup(""); - } - return srv_str; -} - -/* Return current shared random value from the latest consensus. Caller can - * NOT keep a reference to the returned pointer. Return NULL if none. */ -const sr_srv_t * -sr_get_current(const networkstatus_t *ns) -{ - const networkstatus_t *consensus; - - /* Use provided ns else get a live one */ - if (ns) { - consensus = ns; - } else { - consensus = networkstatus_get_live_consensus(approx_time()); - } - /* Ideally we would never be asked for an SRV without a live consensus. Make - * sure this assumption is correct. */ - tor_assert_nonfatal(consensus); - - if (consensus) { - return consensus->sr_info.current_srv; - } - return NULL; -} - -/* Return previous shared random value from the latest consensus. Caller can - * NOT keep a reference to the returned pointer. Return NULL if none. */ -const sr_srv_t * -sr_get_previous(const networkstatus_t *ns) -{ - const networkstatus_t *consensus; - - /* Use provided ns else get a live one */ - if (ns) { - consensus = ns; - } else { - consensus = networkstatus_get_live_consensus(approx_time()); - } - /* Ideally we would never be asked for an SRV without a live consensus. Make - * sure this assumption is correct. */ - tor_assert_nonfatal(consensus); - - if (consensus) { - return consensus->sr_info.previous_srv; - } - return NULL; -} - #ifdef TOR_UNIT_TESTS /* Set the global value of number of SRV agreements so the test can play diff --git a/src/or/dirauth/shared_random.h b/src/or/dirauth/shared_random.h index 675a8d8b06..d1b2ac2e25 100644 --- a/src/or/dirauth/shared_random.h +++ b/src/or/dirauth/shared_random.h @@ -109,13 +109,11 @@ void sr_act_post_consensus(const networkstatus_t *consensus); void sr_handle_received_commits(smartlist_t *commits, crypto_pk_t *voter_key); sr_commit_t *sr_parse_commit(const smartlist_t *args); -sr_srv_t *sr_parse_srv(const smartlist_t *args); char *sr_get_string_for_vote(void); char *sr_get_string_for_consensus(const smartlist_t *votes, int32_t num_srv_agreements); void sr_commit_free_(sr_commit_t *commit); #define sr_commit_free(sr) FREE_AND_NULL(sr_commit_t, sr_commit_free_, (sr)) -void sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv); /* Private methods (only used by shared_random_state.c): */ static inline @@ -128,12 +126,6 @@ void sr_compute_srv(void); sr_commit_t *sr_generate_our_commit(time_t timestamp, const authority_cert_t *my_rsa_cert); -char *sr_get_current_for_control(void); -char *sr_get_previous_for_control(void); - -const sr_srv_t *sr_get_current(const networkstatus_t *ns); -const sr_srv_t *sr_get_previous(const networkstatus_t *ns); - #ifdef SHARED_RANDOM_PRIVATE /* Encode */ diff --git a/src/or/dirauth/shared_random_state.c b/src/or/dirauth/shared_random_state.c index 11d7a06378..846c3c7aa2 100644 --- a/src/or/dirauth/shared_random_state.c +++ b/src/or/dirauth/shared_random_state.c @@ -17,6 +17,7 @@ #include "networkstatus.h" #include "router.h" #include "shared_random_state.h" +#include "shared_random_common.h" #include "dirauth/dirvote.h" @@ -54,10 +55,6 @@ DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t); VAR(#member, conftype, member, initvalue) /* Our persistent state magic number. */ #define SR_DISK_STATE_MAGIC 0x98AB1254 -/* Each protocol phase has 12 rounds */ -#define SHARED_RANDOM_N_ROUNDS 12 -/* Number of phase we have in a protocol. */ -#define SHARED_RANDOM_N_PHASES 2 static int disk_state_validate_cb(void *old_state, void *state, void *default_state, @@ -116,81 +113,6 @@ get_phase_str(sr_phase_t phase) return the_string; } - -/* Return the voting interval of the tor vote subsystem. */ -static int -get_voting_interval(void) -{ - int interval; - networkstatus_t *consensus = networkstatus_get_live_consensus(time(NULL)); - - if (consensus) { - interval = (int)(consensus->fresh_until - consensus->valid_after); - } else { - /* Same for both a testing and real network. We voluntarily ignore the - * InitialVotingInterval since it complexifies things and it doesn't - * affect the SR protocol. */ - interval = get_options()->V3AuthVotingInterval; - } - tor_assert(interval > 0); - return interval; -} - -/* Given the time now, return the start time of the current round of - * the SR protocol. For example, if it's 23:47:08, the current round thus - * started at 23:47:00 for a voting interval of 10 seconds. */ -STATIC time_t -get_start_time_of_current_round(void) -{ - const or_options_t *options = get_options(); - int voting_interval = get_voting_interval(); - /* First, get the start time of the next round */ - time_t next_start = dirvote_get_next_valid_after_time(); - /* Now roll back next_start by a voting interval to find the start time of - the current round. */ - time_t curr_start = dirvote_get_start_of_next_interval( - next_start - voting_interval - 1, - voting_interval, - options->TestingV3AuthVotingStartOffset); - return curr_start; -} - -/** Return the start time of the current SR protocol run. For example, if the - * time is 23/06/2017 23:47:08 and a full SR protocol run is 24 hours, this - * function should return 23/06/2017 00:00:00. */ -time_t -sr_state_get_start_time_of_current_protocol_run(time_t now) -{ - int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES; - int voting_interval = get_voting_interval(); - /* Find the time the current round started. */ - time_t beginning_of_current_round = get_start_time_of_current_round(); - - /* Get current SR protocol round */ - int current_round = (now / voting_interval) % total_rounds; - - /* Get start time by subtracting the time elapsed from the beginning of the - protocol run */ - time_t time_elapsed_since_start_of_run = current_round * voting_interval; - return beginning_of_current_round - time_elapsed_since_start_of_run; -} - -/** Return the time (in seconds) it takes to complete a full SR protocol phase - * (e.g. the commit phase). */ -unsigned int -sr_state_get_phase_duration(void) -{ - return SHARED_RANDOM_N_ROUNDS * get_voting_interval(); -} - -/** Return the time (in seconds) it takes to complete a full SR protocol run */ -unsigned int -sr_state_get_protocol_run_duration(void) -{ - int total_protocol_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES; - return total_protocol_rounds * get_voting_interval(); -} - /* Return the time we should expire the state file created at now. * We expire the state file in the beginning of the next protocol run. */ STATIC time_t diff --git a/src/or/dirauth/shared_random_state.h b/src/or/dirauth/shared_random_state.h index fdbbf4919a..60a326f86c 100644 --- a/src/or/dirauth/shared_random_state.h +++ b/src/or/dirauth/shared_random_state.h @@ -121,16 +121,11 @@ int sr_state_is_initialized(void); void sr_state_save(void); void sr_state_free_all(void); -time_t sr_state_get_start_time_of_current_protocol_run(time_t now); -unsigned int sr_state_get_phase_duration(void); -unsigned int sr_state_get_protocol_run_duration(void); - #ifdef SHARED_RANDOM_STATE_PRIVATE STATIC int disk_state_load_from_disk_impl(const char *fname); STATIC sr_phase_t get_sr_protocol_phase(time_t valid_after); -STATIC time_t get_start_time_of_current_round(void); STATIC time_t get_state_valid_until_time(time_t now); STATIC const char *get_phase_str(sr_phase_t phase); diff --git a/src/or/hs_common.c b/src/or/hs_common.c index fc7bc5729b..8cc7d08911 100644 --- a/src/or/hs_common.c +++ b/src/or/hs_common.c @@ -28,7 +28,7 @@ #include "rendservice.h" #include "routerset.h" #include "router.h" -#include "dirauth/shared_random.h" +#include "shared_random_common.h" #include "dirauth/shared_random_state.h" /* Trunnel */ diff --git a/src/or/hs_service.c b/src/or/hs_service.c index ebb58f7f68..4ac0df2add 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -24,7 +24,7 @@ #include "router.h" #include "routerkeys.h" #include "routerlist.h" -#include "dirauth/shared_random_state.h" +#include "shared_random_common.h" #include "statefile.h" #include "hs_circuit.h" diff --git a/src/or/include.am b/src/or/include.am index 9265ecf483..e90b1fb2ab 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -103,6 +103,7 @@ LIBTOR_A_SOURCES = \ src/or/scheduler.c \ src/or/scheduler_kist.c \ src/or/scheduler_vanilla.c \ + src/or/shared_random_common.c \ src/or/statefile.c \ src/or/status.c \ src/or/torcert.c \ @@ -260,6 +261,7 @@ ORHEADERS = \ src/or/routerset.h \ src/or/routerparse.h \ src/or/scheduler.h \ + src/or/shared_random_common.h \ src/or/statefile.h \ src/or/status.h \ src/or/torcert.h \ diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 84db239155..2d64a82b6f 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -74,6 +74,7 @@ #include "entrynodes.h" #include "torcert.h" #include "sandbox.h" +#include "shared_random_common.h" #include "dirauth/shared_random.h" #undef log diff --git a/src/or/shared_random_common.c b/src/or/shared_random_common.c new file mode 100644 index 0000000000..c782e709ff --- /dev/null +++ b/src/or/shared_random_common.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file shared_random_common.c + * \brief This file contains functions that are from the shared random + * subsystem but used by many part of tor. The full feature is built + * as part of the dirauth module. + **/ + +#define SHARED_RANDOM_COMMON_PRIVATE +#include "shared_random_common.h" + +#include "config.h" +#include "networkstatus.h" +#include "util.h" +#include "util_format.h" + +/* Convert a given srv object to a string for the control port. This doesn't + * fail and the srv object MUST be valid. */ +static char * +srv_to_control_string(const sr_srv_t *srv) +{ + char *srv_str; + char srv_hash_encoded[SR_SRV_VALUE_BASE64_LEN + 1]; + tor_assert(srv); + + sr_srv_encode(srv_hash_encoded, sizeof(srv_hash_encoded), srv); + tor_asprintf(&srv_str, "%s", srv_hash_encoded); + return srv_str; +} + +/* Return the voting interval of the tor vote subsystem. */ +int +get_voting_interval(void) +{ + int interval; + networkstatus_t *consensus = networkstatus_get_live_consensus(time(NULL)); + + if (consensus) { + interval = (int)(consensus->fresh_until - consensus->valid_after); + } else { + /* Same for both a testing and real network. We voluntarily ignore the + * InitialVotingInterval since it complexifies things and it doesn't + * affect the SR protocol. */ + interval = get_options()->V3AuthVotingInterval; + } + tor_assert(interval > 0); + return interval; +} + +/* Given the time now, return the start time of the current round of + * the SR protocol. For example, if it's 23:47:08, the current round thus + * started at 23:47:00 for a voting interval of 10 seconds. */ +time_t +get_start_time_of_current_round(void) +{ + const or_options_t *options = get_options(); + int voting_interval = get_voting_interval(); + /* First, get the start time of the next round */ + time_t next_start = dirvote_get_next_valid_after_time(); + /* Now roll back next_start by a voting interval to find the start time of + the current round. */ + time_t curr_start = dirvote_get_start_of_next_interval( + next_start - voting_interval - 1, + voting_interval, + options->TestingV3AuthVotingStartOffset); + return curr_start; +} + +/* + * Public API + */ + +/* Encode the given shared random value and put it in dst. Destination + * buffer must be at least SR_SRV_VALUE_BASE64_LEN plus the NULL byte. */ +void +sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv) +{ + int ret; + /* Extra byte for the NULL terminated char. */ + char buf[SR_SRV_VALUE_BASE64_LEN + 1]; + + tor_assert(dst); + tor_assert(srv); + tor_assert(dst_len >= sizeof(buf)); + + ret = base64_encode(buf, sizeof(buf), (const char *) srv->value, + sizeof(srv->value), 0); + /* Always expect the full length without the NULL byte. */ + tor_assert(ret == (sizeof(buf) - 1)); + tor_assert(ret <= (int) dst_len); + strlcpy(dst, buf, dst_len); +} + +/* Return the current SRV string representation for the control port. Return a + * newly allocated string on success containing the value else "" if not found + * or if we don't have a valid consensus yet. */ +char * +sr_get_current_for_control(void) +{ + char *srv_str; + const networkstatus_t *c = networkstatus_get_latest_consensus(); + if (c && c->sr_info.current_srv) { + srv_str = srv_to_control_string(c->sr_info.current_srv); + } else { + srv_str = tor_strdup(""); + } + return srv_str; +} + +/* Return the previous SRV string representation for the control port. Return + * a newly allocated string on success containing the value else "" if not + * found or if we don't have a valid consensus yet. */ +char * +sr_get_previous_for_control(void) +{ + char *srv_str; + const networkstatus_t *c = networkstatus_get_latest_consensus(); + if (c && c->sr_info.previous_srv) { + srv_str = srv_to_control_string(c->sr_info.previous_srv); + } else { + srv_str = tor_strdup(""); + } + return srv_str; +} + +/* Return current shared random value from the latest consensus. Caller can + * NOT keep a reference to the returned pointer. Return NULL if none. */ +const sr_srv_t * +sr_get_current(const networkstatus_t *ns) +{ + const networkstatus_t *consensus; + + /* Use provided ns else get a live one */ + if (ns) { + consensus = ns; + } else { + consensus = networkstatus_get_live_consensus(approx_time()); + } + /* Ideally we would never be asked for an SRV without a live consensus. Make + * sure this assumption is correct. */ + tor_assert_nonfatal(consensus); + + if (consensus) { + return consensus->sr_info.current_srv; + } + return NULL; +} + +/* Return previous shared random value from the latest consensus. Caller can + * NOT keep a reference to the returned pointer. Return NULL if none. */ +const sr_srv_t * +sr_get_previous(const networkstatus_t *ns) +{ + const networkstatus_t *consensus; + + /* Use provided ns else get a live one */ + if (ns) { + consensus = ns; + } else { + consensus = networkstatus_get_live_consensus(approx_time()); + } + /* Ideally we would never be asked for an SRV without a live consensus. Make + * sure this assumption is correct. */ + tor_assert_nonfatal(consensus); + + if (consensus) { + return consensus->sr_info.previous_srv; + } + return NULL; +} + +/* Parse a list of arguments from a SRV value either from a vote, consensus + * or from our disk state and return a newly allocated srv object. NULL is + * returned on error. + * + * The arguments' order: + * num_reveals, value + */ +sr_srv_t * +sr_parse_srv(const smartlist_t *args) +{ + char *value; + int ok, ret; + uint64_t num_reveals; + sr_srv_t *srv = NULL; + + tor_assert(args); + + if (smartlist_len(args) < 2) { + goto end; + } + + /* First argument is the number of reveal values */ + num_reveals = tor_parse_uint64(smartlist_get(args, 0), + 10, 0, UINT64_MAX, &ok, NULL); + if (!ok) { + goto end; + } + /* Second and last argument is the shared random value it self. */ + value = smartlist_get(args, 1); + if (strlen(value) != SR_SRV_VALUE_BASE64_LEN) { + goto end; + } + + srv = tor_malloc_zero(sizeof(*srv)); + srv->num_reveals = num_reveals; + /* We subtract one byte from the srclen because the function ignores the + * '=' character in the given buffer. This is broken but it's a documented + * behavior of the implementation. */ + ret = base64_decode((char *) srv->value, sizeof(srv->value), value, + SR_SRV_VALUE_BASE64_LEN - 1); + if (ret != sizeof(srv->value)) { + tor_free(srv); + srv = NULL; + goto end; + } + end: + return srv; +} + +/** Return the start time of the current SR protocol run. For example, if the + * time is 23/06/2017 23:47:08 and a full SR protocol run is 24 hours, this + * function should return 23/06/2017 00:00:00. */ +time_t +sr_state_get_start_time_of_current_protocol_run(time_t now) +{ + int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES; + int voting_interval = get_voting_interval(); + /* Find the time the current round started. */ + time_t beginning_of_current_round = get_start_time_of_current_round(); + + /* Get current SR protocol round */ + int current_round = (now / voting_interval) % total_rounds; + + /* Get start time by subtracting the time elapsed from the beginning of the + protocol run */ + time_t time_elapsed_since_start_of_run = current_round * voting_interval; + return beginning_of_current_round - time_elapsed_since_start_of_run; +} + +/** Return the time (in seconds) it takes to complete a full SR protocol phase + * (e.g. the commit phase). */ +unsigned int +sr_state_get_phase_duration(void) +{ + return SHARED_RANDOM_N_ROUNDS * get_voting_interval(); +} + +/** Return the time (in seconds) it takes to complete a full SR protocol run */ +unsigned int +sr_state_get_protocol_run_duration(void) +{ + int total_protocol_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES; + return total_protocol_rounds * get_voting_interval(); +} + diff --git a/src/or/shared_random_common.h b/src/or/shared_random_common.h new file mode 100644 index 0000000000..35e08ddf32 --- /dev/null +++ b/src/or/shared_random_common.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file shared_random_common.h + * \brief Header file for shared_random_common.c. + **/ + +#ifndef TOR_SHARED_RANDOM_COMMON_H +#define TOR_SHARED_RANDOM_COMMON_H + +/* Dirauth module. */ +#include "dirauth/shared_random.h" + +/* Helper functions. */ +void sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv); +int get_voting_interval(void); + +/* Control port functions. */ +char *sr_get_current_for_control(void); +char *sr_get_previous_for_control(void); + +/* SRV functions. */ +const sr_srv_t *sr_get_current(const networkstatus_t *ns); +const sr_srv_t *sr_get_previous(const networkstatus_t *ns); +sr_srv_t *sr_parse_srv(const smartlist_t *args); + +/* + * Shared Random State API + */ + +/* Each protocol phase has 12 rounds */ +#define SHARED_RANDOM_N_ROUNDS 12 +/* Number of phase we have in a protocol. */ +#define SHARED_RANDOM_N_PHASES 2 + +time_t sr_state_get_start_time_of_current_protocol_run(time_t now); +unsigned int sr_state_get_phase_duration(void); +unsigned int sr_state_get_protocol_run_duration(void); +time_t get_start_time_of_current_round(void); + +#ifdef TOR_UNIT_TESTS + +#endif /* TOR_UNIT_TESTS */ + +#endif /* TOR_SHARED_RANDOM_COMMON_H */ + From 79a1112a495f76542d13eab4992ff4fd50f7f830 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 24 Apr 2018 15:28:47 -0400 Subject: [PATCH 08/20] sr: Static inline functions if no dirauth module Add static inline dirauth public functions used outside of the dirauth module so they can be seen by the tor code but simply do nothing. Signed-off-by: David Goulet --- src/or/dirauth/shared_random.h | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/or/dirauth/shared_random.h b/src/or/dirauth/shared_random.h index d1b2ac2e25..1778ce8f09 100644 --- a/src/or/dirauth/shared_random.h +++ b/src/or/dirauth/shared_random.h @@ -101,11 +101,40 @@ typedef struct sr_commit_t { /* API */ -/* Public methods: */ +/* Public methods used _outside_ of the module. + * + * We need to nullify them if the module is disabled. */ +#ifdef HAVE_MODULE_DIRAUTH int sr_init(int save_to_disk); void sr_save_and_cleanup(void); void sr_act_post_consensus(const networkstatus_t *consensus); + +#else /* HAVE_MODULE_DIRAUTH */ + +static inline int +sr_init(int save_to_disk) +{ + (void) save_to_disk; + /* Always return success. */ + return 0; +} + +static inline void +sr_save_and_cleanup(void) +{ +} + +static inline void +sr_act_post_consensus(const networkstatus_t *consensus) +{ + (void) consensus; +} + +#endif /* HAVE_MODULE_DIRAUTH */ + +/* Public methods used only by dirauth code. */ + void sr_handle_received_commits(smartlist_t *commits, crypto_pk_t *voter_key); sr_commit_t *sr_parse_commit(const smartlist_t *args); From 26817d9d2231d2580361ae9082db17250b454628 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 09:06:29 -0400 Subject: [PATCH 09/20] dirvote: Extract shared functions to common file No code behavior change. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.c | 237 +--------------------------------- src/or/dirauth/dirvote.h | 33 +++-- src/or/dirserv.c | 1 + src/or/dirvote_common.c | 219 +++++++++++++++++++++++++++++++ src/or/dirvote_common.h | 69 ++++++++++ src/or/include.am | 2 + src/or/routerparse.c | 1 + src/or/shared_random_common.c | 1 + src/test/test_dir_common.c | 1 + src/test/test_shared_random.c | 1 + 10 files changed, 316 insertions(+), 249 deletions(-) create mode 100644 src/or/dirvote_common.c create mode 100644 src/or/dirvote_common.h diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index 67ab1d4ffb..dc35c892e0 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -10,6 +10,7 @@ #include "directory.h" #include "dirserv.h" #include "dirvote.h" +#include "dirvote_common.h" #include "microdesc.h" #include "networkstatus.h" #include "policies.h" @@ -72,40 +73,6 @@ typedef struct pending_consensus_t { networkstatus_t *consensus; } pending_consensus_t; -/** Scheduling information for a voting interval. */ -typedef struct { - /** When do we generate and distribute our vote for this interval? */ - time_t voting_starts; - /** When do we send an HTTP request for any votes that we haven't - * been posted yet?*/ - time_t fetch_missing_votes; - /** When do we give up on getting more votes and generate a consensus? */ - time_t voting_ends; - /** When do we send an HTTP request for any signatures we're expecting to - * see on the consensus? */ - time_t fetch_missing_signatures; - /** When do we publish the consensus? */ - time_t interval_starts; - - /* True iff we have generated and distributed our vote. */ - int have_voted; - /* True iff we've requested missing votes. */ - int have_fetched_missing_votes; - /* True iff we have built a consensus and sent the signatures around. */ - int have_built_consensus; - /* True iff we've fetched missing signatures. */ - int have_fetched_missing_signatures; - /* True iff we have published our consensus. */ - int have_published_consensus; - - /* True iff this voting schedule was set on demand meaning not through the - * normal vote operation of a dirauth or when a consensus is set. This only - * applies to a directory authority that needs to recalculate the voting - * timings only for the first vote even though this object was initilized - * prior to voting. */ - int created_on_demand; -} voting_schedule_t; - /* DOCDOC dirvote_add_signatures_to_all_pending_consensuses */ static int dirvote_add_signatures_to_all_pending_consensuses( const char *detached_signatures_body, @@ -444,20 +411,6 @@ get_voter(const networkstatus_t *vote) return smartlist_get(vote->voters, 0); } -/** Return the signature made by voter using the algorithm - * alg, or NULL if none is found. */ -document_signature_t * -voter_get_sig_by_algorithm(const networkstatus_voter_info_t *voter, - digest_algorithm_t alg) -{ - if (!voter->sigs) - return NULL; - SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig, - if (sig->alg == alg) - return sig); - return NULL; -} - /** Temporary structure used in constructing a list of dir-source entries * for a consensus. One of these is generated for every vote, and one more * for every legacy key in each vote. */ @@ -2769,194 +2722,6 @@ ns_detached_signatures_free_(ns_detached_signatures_t *s) tor_free(s); } -/* ===== - * Certificate functions - * ===== */ - -/** Allocate and return a new authority_cert_t with the same contents as - * cert. */ -authority_cert_t * -authority_cert_dup(authority_cert_t *cert) -{ - authority_cert_t *out = tor_malloc(sizeof(authority_cert_t)); - tor_assert(cert); - - memcpy(out, cert, sizeof(authority_cert_t)); - /* Now copy pointed-to things. */ - out->cache_info.signed_descriptor_body = - tor_strndup(cert->cache_info.signed_descriptor_body, - cert->cache_info.signed_descriptor_len); - out->cache_info.saved_location = SAVED_NOWHERE; - out->identity_key = crypto_pk_dup_key(cert->identity_key); - out->signing_key = crypto_pk_dup_key(cert->signing_key); - - return out; -} - -/* ===== - * Vote scheduling - * ===== */ - -/** Set *timing_out to the intervals at which we would like to vote. - * Note that these aren't the intervals we'll use to vote; they're the ones - * that we'll vote to use. */ -void -dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out) -{ - const or_options_t *options = get_options(); - - tor_assert(timing_out); - - timing_out->vote_interval = options->V3AuthVotingInterval; - timing_out->n_intervals_valid = options->V3AuthNIntervalsValid; - timing_out->vote_delay = options->V3AuthVoteDelay; - timing_out->dist_delay = options->V3AuthDistDelay; -} - -/** Return the start of the next interval of size interval (in - * seconds) after now, plus offset. Midnight always - * starts a fresh interval, and if the last interval of a day would be - * truncated to less than half its size, it is rolled into the - * previous interval. */ -time_t -dirvote_get_start_of_next_interval(time_t now, int interval, int offset) -{ - struct tm tm; - time_t midnight_today=0; - time_t midnight_tomorrow; - time_t next; - - tor_gmtime_r(&now, &tm); - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - - if (tor_timegm(&tm, &midnight_today) < 0) { - log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight."); - } - midnight_tomorrow = midnight_today + (24*60*60); - - next = midnight_today + ((now-midnight_today)/interval + 1)*interval; - - /* Intervals never cross midnight. */ - if (next > midnight_tomorrow) - next = midnight_tomorrow; - - /* If the interval would only last half as long as it's supposed to, then - * skip over to the next day. */ - if (next + interval/2 > midnight_tomorrow) - next = midnight_tomorrow; - - next += offset; - if (next - interval > now) - next -= interval; - - return next; -} - -/* Populate and return a new voting_schedule_t that can be used to schedule - * voting. The object is allocated on the heap and it's the responsibility of - * the caller to free it. Can't fail. */ -static voting_schedule_t * -get_voting_schedule(const or_options_t *options, time_t now, int severity) -{ - int interval, vote_delay, dist_delay; - time_t start; - time_t end; - networkstatus_t *consensus; - voting_schedule_t *new_voting_schedule; - - new_voting_schedule = tor_malloc_zero(sizeof(voting_schedule_t)); - - consensus = networkstatus_get_live_consensus(now); - - if (consensus) { - interval = (int)( consensus->fresh_until - consensus->valid_after ); - vote_delay = consensus->vote_seconds; - dist_delay = consensus->dist_seconds; - } else { - interval = options->TestingV3AuthInitialVotingInterval; - vote_delay = options->TestingV3AuthInitialVoteDelay; - dist_delay = options->TestingV3AuthInitialDistDelay; - } - - tor_assert(interval > 0); - - if (vote_delay + dist_delay > interval/2) - vote_delay = dist_delay = interval / 4; - - start = new_voting_schedule->interval_starts = - dirvote_get_start_of_next_interval(now,interval, - options->TestingV3AuthVotingStartOffset); - end = dirvote_get_start_of_next_interval(start+1, interval, - options->TestingV3AuthVotingStartOffset); - - tor_assert(end > start); - - new_voting_schedule->fetch_missing_signatures = start - (dist_delay/2); - new_voting_schedule->voting_ends = start - dist_delay; - new_voting_schedule->fetch_missing_votes = - start - dist_delay - (vote_delay/2); - new_voting_schedule->voting_starts = start - dist_delay - vote_delay; - - { - char tbuf[ISO_TIME_LEN+1]; - format_iso_time(tbuf, new_voting_schedule->interval_starts); - tor_log(severity, LD_DIR,"Choosing expected valid-after time as %s: " - "consensus_set=%d, interval=%d", - tbuf, consensus?1:0, interval); - } - - return new_voting_schedule; -} - -#define voting_schedule_free(s) \ - FREE_AND_NULL(voting_schedule_t, voting_schedule_free_, (s)) - -/** Frees a voting_schedule_t. This should be used instead of the generic - * tor_free. */ -static void -voting_schedule_free_(voting_schedule_t *voting_schedule_to_free) -{ - if (!voting_schedule_to_free) - return; - tor_free(voting_schedule_to_free); -} - -static voting_schedule_t voting_schedule; - -/* Using the time now, return the next voting valid-after time. */ -time_t -dirvote_get_next_valid_after_time(void) -{ - /* This is a safe guard in order to make sure that the voting schedule - * static object is at least initialized. Using this function with a zeroed - * voting schedule can lead to bugs. */ - if (tor_mem_is_zero((const char *) &voting_schedule, - sizeof(voting_schedule))) { - dirvote_recalculate_timing(get_options(), time(NULL)); - voting_schedule.created_on_demand = 1; - } - return voting_schedule.interval_starts; -} - -/** Set voting_schedule to hold the timing for the next vote we should be - * doing. All type of tor do that because HS subsystem needs the timing as - * well to function properly. */ -void -dirvote_recalculate_timing(const or_options_t *options, time_t now) -{ - voting_schedule_t *new_voting_schedule; - - /* get the new voting schedule */ - new_voting_schedule = get_voting_schedule(options, now, LOG_INFO); - tor_assert(new_voting_schedule); - - /* Fill in the global static struct now */ - memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule)); - voting_schedule_free(new_voting_schedule); -} - /** Entry point: Take whatever voting actions are pending as of now. */ void dirvote_act(const or_options_t *options, time_t now) diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index 4f1f35d856..6f4c55243f 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -91,17 +91,36 @@ /* * Public API. Used outside of the dirauth subsystem. + * + * We need to nullify them if the module is disabled. */ +#ifdef HAVE_MODULE_DIRAUTH +void dirvote_act(const or_options_t *options, time_t now); void dirvote_free_all(void); +#else /* HAVE_MODULE_DIRAUTH */ + +static inline void +dirvote_act(const or_options_t *options, time_t now) +{ + (void) options; + (void) now; +} + +static inline void +dirvote_free_all(void) +{ +} + +#endif /* HAVE_MODULE_DIRAUTH */ + /* Vote manipulation */ void ns_detached_signatures_free_(ns_detached_signatures_t *s); #define ns_detached_signatures_free(s) \ FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s)) void dirvote_recalculate_timing(const or_options_t *options, time_t now); -void dirvote_act(const or_options_t *options, time_t now); /* Invoked on timers and by outside triggers. */ struct pending_vote_t * dirvote_add_vote(const char *vote_body, const char **msg_out, @@ -114,23 +133,11 @@ MOCK_DECL(const char*, dirvote_get_pending_consensus, (consensus_flavor_t flav)); MOCK_DECL(const char*, dirvote_get_pending_detached_signatures, (void)); const cached_dir_t *dirvote_get_vote(const char *fp, int flags); -document_signature_t *voter_get_sig_by_algorithm( - const networkstatus_voter_info_t *voter, - digest_algorithm_t alg); /* * API used _only_ by the dirauth subsystem. */ -/* Cert manipulation */ -authority_cert_t *authority_cert_dup(authority_cert_t *cert); - -void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); -time_t dirvote_get_start_of_next_interval(time_t now, - int interval, - int offset); -time_t dirvote_get_next_valid_after_time(void); - void set_routerstatus_from_routerinfo(routerstatus_t *rs, node_t *node, routerinfo_t *ri, time_t now, diff --git a/src/or/dirserv.c b/src/or/dirserv.c index c20e2966c3..58294f6cf8 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -18,6 +18,7 @@ #include "control.h" #include "directory.h" #include "dirserv.h" +#include "dirvote_common.h" #include "hibernate.h" #include "keypin.h" #include "main.h" diff --git a/src/or/dirvote_common.c b/src/or/dirvote_common.c new file mode 100644 index 0000000000..caa9138f05 --- /dev/null +++ b/src/or/dirvote_common.c @@ -0,0 +1,219 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dirvote_common.c + * \brief This file contains functions that are from the directory authority + * subsystem related to voting specifically but used by many part of + * tor. The full feature is built as part of the dirauth module. + **/ + +#define DIRVOTE_COMMON_PRIVATE +#include "dirvote_common.h" + +#include "or.h" +#include "config.h" +#include "networkstatus.h" + +/* ===== + * Vote scheduling + * ===== */ + +/** Set *timing_out to the intervals at which we would like to vote. + * Note that these aren't the intervals we'll use to vote; they're the ones + * that we'll vote to use. */ +void +dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out) +{ + const or_options_t *options = get_options(); + + tor_assert(timing_out); + + timing_out->vote_interval = options->V3AuthVotingInterval; + timing_out->n_intervals_valid = options->V3AuthNIntervalsValid; + timing_out->vote_delay = options->V3AuthVoteDelay; + timing_out->dist_delay = options->V3AuthDistDelay; +} + +/** Return the start of the next interval of size interval (in + * seconds) after now, plus offset. Midnight always + * starts a fresh interval, and if the last interval of a day would be + * truncated to less than half its size, it is rolled into the + * previous interval. */ +time_t +dirvote_get_start_of_next_interval(time_t now, int interval, int offset) +{ + struct tm tm; + time_t midnight_today=0; + time_t midnight_tomorrow; + time_t next; + + tor_gmtime_r(&now, &tm); + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + + if (tor_timegm(&tm, &midnight_today) < 0) { + log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight."); + } + midnight_tomorrow = midnight_today + (24*60*60); + + next = midnight_today + ((now-midnight_today)/interval + 1)*interval; + + /* Intervals never cross midnight. */ + if (next > midnight_tomorrow) + next = midnight_tomorrow; + + /* If the interval would only last half as long as it's supposed to, then + * skip over to the next day. */ + if (next + interval/2 > midnight_tomorrow) + next = midnight_tomorrow; + + next += offset; + if (next - interval > now) + next -= interval; + + return next; +} + +/* Populate and return a new voting_schedule_t that can be used to schedule + * voting. The object is allocated on the heap and it's the responsibility of + * the caller to free it. Can't fail. */ +static voting_schedule_t * +get_voting_schedule(const or_options_t *options, time_t now, int severity) +{ + int interval, vote_delay, dist_delay; + time_t start; + time_t end; + networkstatus_t *consensus; + voting_schedule_t *new_voting_schedule; + + new_voting_schedule = tor_malloc_zero(sizeof(voting_schedule_t)); + + consensus = networkstatus_get_live_consensus(now); + + if (consensus) { + interval = (int)( consensus->fresh_until - consensus->valid_after ); + vote_delay = consensus->vote_seconds; + dist_delay = consensus->dist_seconds; + } else { + interval = options->TestingV3AuthInitialVotingInterval; + vote_delay = options->TestingV3AuthInitialVoteDelay; + dist_delay = options->TestingV3AuthInitialDistDelay; + } + + tor_assert(interval > 0); + + if (vote_delay + dist_delay > interval/2) + vote_delay = dist_delay = interval / 4; + + start = new_voting_schedule->interval_starts = + dirvote_get_start_of_next_interval(now,interval, + options->TestingV3AuthVotingStartOffset); + end = dirvote_get_start_of_next_interval(start+1, interval, + options->TestingV3AuthVotingStartOffset); + + tor_assert(end > start); + + new_voting_schedule->fetch_missing_signatures = start - (dist_delay/2); + new_voting_schedule->voting_ends = start - dist_delay; + new_voting_schedule->fetch_missing_votes = + start - dist_delay - (vote_delay/2); + new_voting_schedule->voting_starts = start - dist_delay - vote_delay; + + { + char tbuf[ISO_TIME_LEN+1]; + format_iso_time(tbuf, new_voting_schedule->interval_starts); + tor_log(severity, LD_DIR,"Choosing expected valid-after time as %s: " + "consensus_set=%d, interval=%d", + tbuf, consensus?1:0, interval); + } + + return new_voting_schedule; +} + +#define voting_schedule_free(s) \ + FREE_AND_NULL(voting_schedule_t, voting_schedule_free_, (s)) + +/** Frees a voting_schedule_t. This should be used instead of the generic + * tor_free. */ +static void +voting_schedule_free_(voting_schedule_t *voting_schedule_to_free) +{ + if (!voting_schedule_to_free) + return; + tor_free(voting_schedule_to_free); +} + +voting_schedule_t voting_schedule; + +/* Using the time now, return the next voting valid-after time. */ +time_t +dirvote_get_next_valid_after_time(void) +{ + /* This is a safe guard in order to make sure that the voting schedule + * static object is at least initialized. Using this function with a zeroed + * voting schedule can lead to bugs. */ + if (tor_mem_is_zero((const char *) &voting_schedule, + sizeof(voting_schedule))) { + dirvote_recalculate_timing(get_options(), time(NULL)); + voting_schedule.created_on_demand = 1; + } + return voting_schedule.interval_starts; +} + +/** Set voting_schedule to hold the timing for the next vote we should be + * doing. All type of tor do that because HS subsystem needs the timing as + * well to function properly. */ +void +dirvote_recalculate_timing(const or_options_t *options, time_t now) +{ + voting_schedule_t *new_voting_schedule; + + /* get the new voting schedule */ + new_voting_schedule = get_voting_schedule(options, now, LOG_INFO); + tor_assert(new_voting_schedule); + + /* Fill in the global static struct now */ + memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule)); + voting_schedule_free(new_voting_schedule); +} + +/** Return the signature made by voter using the algorithm + * alg, or NULL if none is found. */ +document_signature_t * +voter_get_sig_by_algorithm(const networkstatus_voter_info_t *voter, + digest_algorithm_t alg) +{ + if (!voter->sigs) + return NULL; + SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig, + if (sig->alg == alg) + return sig); + return NULL; +} + +/* ===== + * Certificate functions + * ===== */ + +/** Allocate and return a new authority_cert_t with the same contents as + * cert. */ +authority_cert_t * +authority_cert_dup(authority_cert_t *cert) +{ + authority_cert_t *out = tor_malloc(sizeof(authority_cert_t)); + tor_assert(cert); + + memcpy(out, cert, sizeof(authority_cert_t)); + /* Now copy pointed-to things. */ + out->cache_info.signed_descriptor_body = + tor_strndup(cert->cache_info.signed_descriptor_body, + cert->cache_info.signed_descriptor_len); + out->cache_info.saved_location = SAVED_NOWHERE; + out->identity_key = crypto_pk_dup_key(cert->identity_key); + out->signing_key = crypto_pk_dup_key(cert->signing_key); + + return out; +} + diff --git a/src/or/dirvote_common.h b/src/or/dirvote_common.h new file mode 100644 index 0000000000..91d32aaa84 --- /dev/null +++ b/src/or/dirvote_common.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dirvote_common.h + * \brief Header file for dirvote_common.c. + **/ + +#ifndef TOR_DIRVOTE_COMMON_H +#define TOR_DIRVOTE_COMMON_H + +#include "or.h" + +/* Dirauth module. */ +#include "dirauth/dirvote.h" + +/** Scheduling information for a voting interval. */ +typedef struct { + /** When do we generate and distribute our vote for this interval? */ + time_t voting_starts; + /** When do we send an HTTP request for any votes that we haven't + * been posted yet?*/ + time_t fetch_missing_votes; + /** When do we give up on getting more votes and generate a consensus? */ + time_t voting_ends; + /** When do we send an HTTP request for any signatures we're expecting to + * see on the consensus? */ + time_t fetch_missing_signatures; + /** When do we publish the consensus? */ + time_t interval_starts; + + /* True iff we have generated and distributed our vote. */ + int have_voted; + /* True iff we've requested missing votes. */ + int have_fetched_missing_votes; + /* True iff we have built a consensus and sent the signatures around. */ + int have_built_consensus; + /* True iff we've fetched missing signatures. */ + int have_fetched_missing_signatures; + /* True iff we have published our consensus. */ + int have_published_consensus; + + /* True iff this voting schedule was set on demand meaning not through the + * normal vote operation of a dirauth or when a consensus is set. This only + * applies to a directory authority that needs to recalculate the voting + * timings only for the first vote even though this object was initilized + * prior to voting. */ + int created_on_demand; +} voting_schedule_t; + +/* Public API. */ + +extern voting_schedule_t voting_schedule; + +void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); +time_t dirvote_get_start_of_next_interval(time_t now, + int interval, + int offset); +time_t dirvote_get_next_valid_after_time(void); + +document_signature_t *voter_get_sig_by_algorithm( + const networkstatus_voter_info_t *voter, + digest_algorithm_t alg); + +/* Cert manipulation */ +authority_cert_t *authority_cert_dup(authority_cert_t *cert); + +#endif /* TOR_DIRVOTE_COMMON_H */ + diff --git a/src/or/include.am b/src/or/include.am index e90b1fb2ab..93f405d619 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -43,6 +43,7 @@ LIBTOR_A_SOURCES = \ src/or/cpuworker.c \ src/or/directory.c \ src/or/dirserv.c \ + src/or/dirvote_common.c \ src/or/dns.c \ src/or/dnsserv.c \ src/or/dos.c \ @@ -198,6 +199,7 @@ ORHEADERS = \ src/or/cpuworker.h \ src/or/directory.h \ src/or/dirserv.h \ + src/or/dirvote_common.h \ src/or/dns.h \ src/or/dns_structs.h \ src/or/dnsserv.h \ diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 2d64a82b6f..b27833c3ed 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -75,6 +75,7 @@ #include "torcert.h" #include "sandbox.h" #include "shared_random_common.h" +#include "dirvote_common.h" #include "dirauth/shared_random.h" #undef log diff --git a/src/or/shared_random_common.c b/src/or/shared_random_common.c index c782e709ff..7d897d9531 100644 --- a/src/or/shared_random_common.c +++ b/src/or/shared_random_common.c @@ -12,6 +12,7 @@ #include "shared_random_common.h" #include "config.h" +#include "dirvote_common.h" #include "networkstatus.h" #include "util.h" #include "util_format.h" diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c index c3e3662fde..02d3295ca6 100644 --- a/src/test/test_dir_common.c +++ b/src/test/test_dir_common.c @@ -10,6 +10,7 @@ #include "container.h" #include "or.h" #include "dirauth/dirvote.h" +#include "dirvote_common.h" #include "nodelist.h" #include "routerlist.h" #include "test_dir_common.h" diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 30d0d44cac..95a7ff28f4 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -16,6 +16,7 @@ #include "routerlist.h" #include "router.h" #include "routerparse.h" +#include "shared_random_common.h" #include "networkstatus.h" #include "log_test_helpers.h" From 43bee06dd090b5e221a0622389e18a21c0d1e153 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 10:00:17 -0400 Subject: [PATCH 10/20] dirvote: Rename voter_get_sig_by_algorithm() In order to follow the public namespace of dirvote. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.c | 2 +- src/or/dirvote_common.c | 4 ++-- src/or/dirvote_common.h | 2 +- src/or/routerparse.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index dc35c892e0..5af6d841f8 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -2490,7 +2490,7 @@ networkstatus_add_detached_signatures(networkstatus_t *target, continue; } - old_sig = voter_get_sig_by_algorithm(target_voter, sig->alg); + old_sig = dirvote_get_voter_sig_by_alg(target_voter, sig->alg); /* If the target already has a good signature from this voter, then skip * this one. */ diff --git a/src/or/dirvote_common.c b/src/or/dirvote_common.c index caa9138f05..b34f4fe20c 100644 --- a/src/or/dirvote_common.c +++ b/src/or/dirvote_common.c @@ -182,8 +182,8 @@ dirvote_recalculate_timing(const or_options_t *options, time_t now) /** Return the signature made by voter using the algorithm * alg, or NULL if none is found. */ document_signature_t * -voter_get_sig_by_algorithm(const networkstatus_voter_info_t *voter, - digest_algorithm_t alg) +dirvote_get_voter_sig_by_alg(const networkstatus_voter_info_t *voter, + digest_algorithm_t alg) { if (!voter->sigs) return NULL; diff --git a/src/or/dirvote_common.h b/src/or/dirvote_common.h index 91d32aaa84..16621244b8 100644 --- a/src/or/dirvote_common.h +++ b/src/or/dirvote_common.h @@ -58,7 +58,7 @@ time_t dirvote_get_start_of_next_interval(time_t now, int offset); time_t dirvote_get_next_valid_after_time(void); -document_signature_t *voter_get_sig_by_algorithm( +document_signature_t *dirvote_get_voter_sig_by_alg( const networkstatus_voter_info_t *voter, digest_algorithm_t alg); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index b27833c3ed..9769d5ab50 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -3972,7 +3972,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, } } - if (voter_get_sig_by_algorithm(v, sig->alg)) { + if (dirvote_get_voter_sig_by_alg(v, sig->alg)) { /* We already parsed a vote with this algorithm from this voter. Use the first one. */ log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus " From 35ff2a3b864d921d45aec50f551b59f24e31a512 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 10:05:30 -0400 Subject: [PATCH 11/20] dirvote: Rename authority_cert_dup() Renamed to follow the file namespace. Signed-off-by: David Goulet --- src/or/dirserv.c | 2 +- src/or/dirvote_common.c | 2 +- src/or/dirvote_common.h | 2 +- src/test/test_dir_common.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 58294f6cf8..1ade52e81e 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -3131,7 +3131,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, v3_out->voters = smartlist_new(); smartlist_add(v3_out->voters, voter); - v3_out->cert = authority_cert_dup(cert); + v3_out->cert = dirvote_authority_cert_dup(cert); v3_out->routerstatus_list = routerstatuses; /* Note: networkstatus_digest is unset; it won't get set until we actually * format the vote. */ diff --git a/src/or/dirvote_common.c b/src/or/dirvote_common.c index b34f4fe20c..9d2c867c83 100644 --- a/src/or/dirvote_common.c +++ b/src/or/dirvote_common.c @@ -200,7 +200,7 @@ dirvote_get_voter_sig_by_alg(const networkstatus_voter_info_t *voter, /** Allocate and return a new authority_cert_t with the same contents as * cert. */ authority_cert_t * -authority_cert_dup(authority_cert_t *cert) +dirvote_authority_cert_dup(authority_cert_t *cert) { authority_cert_t *out = tor_malloc(sizeof(authority_cert_t)); tor_assert(cert); diff --git a/src/or/dirvote_common.h b/src/or/dirvote_common.h index 16621244b8..07e6259377 100644 --- a/src/or/dirvote_common.h +++ b/src/or/dirvote_common.h @@ -63,7 +63,7 @@ document_signature_t *dirvote_get_voter_sig_by_alg( digest_algorithm_t alg); /* Cert manipulation */ -authority_cert_t *authority_cert_dup(authority_cert_t *cert); +authority_cert_t *dirvote_authority_cert_dup(authority_cert_t *cert); #endif /* TOR_DIRVOTE_COMMON_H */ diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c index 02d3295ca6..8c6d99ccec 100644 --- a/src/test/test_dir_common.c +++ b/src/test/test_dir_common.c @@ -307,7 +307,7 @@ dir_common_construct_vote_1(networkstatus_t **vote, authority_cert_t *cert, * Set up a vote; generate it; try to parse it. */ smartlist_add((*vote)->voters, voter); - (*vote)->cert = authority_cert_dup(cert); + (*vote)->cert = dirvote_authority_cert_dup(cert); smartlist_split_string((*vote)->net_params, "circuitwindow=101 foo=990", NULL, 0, 0); *n_vrs = 0; @@ -356,7 +356,7 @@ dir_common_construct_vote_2(networkstatus_t **vote, authority_cert_t *cert, * Set up a vote; generate it; try to parse it. */ smartlist_add((*vote)->voters, voter); - (*vote)->cert = authority_cert_dup(cert); + (*vote)->cert = dirvote_authority_cert_dup(cert); if (! (*vote)->net_params) (*vote)->net_params = smartlist_new(); smartlist_split_string((*vote)->net_params, @@ -407,7 +407,7 @@ dir_common_construct_vote_3(networkstatus_t **vote, authority_cert_t *cert, * Set up a vote; generate it; try to parse it. */ smartlist_add((*vote)->voters, voter); - (*vote)->cert = authority_cert_dup(cert); + (*vote)->cert = dirvote_authority_cert_dup(cert); smartlist_split_string((*vote)->net_params, "circuitwindow=80 foo=660", NULL, 0, 0); /* add routerstatuses */ From d7e4706f2293cb199d3246197b2d911188de0e45 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 10:09:50 -0400 Subject: [PATCH 12/20] ns: Move ns_detached_signatures_free() to networkstatus.c From dirvote.c to networkstatus.c where it makes more sense both in terms of namespace and subsystem responsability. This removes one less dependency on the dirauth module. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.c | 19 ------------------- src/or/dirauth/dirvote.h | 5 ----- src/or/networkstatus.c | 19 +++++++++++++++++++ src/or/networkstatus.h | 3 +++ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index 5af6d841f8..b28bcf5ce5 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -2703,25 +2703,6 @@ get_detached_signatures_from_pending_consensuses(pending_consensus_t *pending, return signatures; } -/** Release all storage held in s. */ -void -ns_detached_signatures_free_(ns_detached_signatures_t *s) -{ - if (!s) - return; - if (s->signatures) { - STRMAP_FOREACH(s->signatures, flavor, smartlist_t *, sigs) { - SMARTLIST_FOREACH(sigs, document_signature_t *, sig, - document_signature_free(sig)); - smartlist_free(sigs); - } STRMAP_FOREACH_END; - strmap_free(s->signatures, NULL); - strmap_free(s->digests, tor_free_); - } - - tor_free(s); -} - /** Entry point: Take whatever voting actions are pending as of now. */ void dirvote_act(const or_options_t *options, time_t now) diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index 6f4c55243f..fcc7cecf26 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -115,11 +115,6 @@ dirvote_free_all(void) #endif /* HAVE_MODULE_DIRAUTH */ -/* Vote manipulation */ -void ns_detached_signatures_free_(ns_detached_signatures_t *s); -#define ns_detached_signatures_free(s) \ - FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s)) - void dirvote_recalculate_timing(const or_options_t *options, time_t now); /* Invoked on timers and by outside triggers. */ struct pending_vote_t * dirvote_add_vote(const char *vote_body, diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index f78d9d672b..fa8d0bcf13 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -2642,6 +2642,25 @@ networkstatus_check_required_protocols(const networkstatus_t *ns, return 0; } +/** Release all storage held in s. */ +void +ns_detached_signatures_free_(ns_detached_signatures_t *s) +{ + if (!s) + return; + if (s->signatures) { + STRMAP_FOREACH(s->signatures, flavor, smartlist_t *, sigs) { + SMARTLIST_FOREACH(sigs, document_signature_t *, sig, + document_signature_free(sig)); + smartlist_free(sigs); + } STRMAP_FOREACH_END; + strmap_free(s->signatures, NULL); + strmap_free(s->digests, tor_free_); + } + + tor_free(s); +} + /** Free all storage held locally in this module. */ void networkstatus_free_all(void) diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index 04cf277d2f..bd78292050 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -24,6 +24,9 @@ void routerstatus_free_(routerstatus_t *rs); void networkstatus_vote_free_(networkstatus_t *ns); #define networkstatus_vote_free(ns) \ FREE_AND_NULL(networkstatus_t, networkstatus_vote_free_, (ns)) +void ns_detached_signatures_free_(ns_detached_signatures_t *s); +#define ns_detached_signatures_free(s) \ + FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s)) networkstatus_voter_info_t *networkstatus_get_voter_by_id( networkstatus_t *vote, const char *identity); From 2963e65c30d1c1463e71385439246e0df1e363c5 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 10:42:56 -0400 Subject: [PATCH 13/20] dirvote: Move SR commit parsing into dirauth module When parsing a vote in routerparse.c, only dirauth extract the commits from the vote so move all this code into dirvote.c so we can make it specific to the dirauth module. If the dirauth module is disabled, the commit parsing does nothing. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.c | 71 ++++++++++++++++++++++++++++++++++++++++ src/or/dirauth/dirvote.h | 9 +++++ src/or/routerparse.c | 62 +---------------------------------- 3 files changed, 81 insertions(+), 61 deletions(-) diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index b28bcf5ce5..3ec4d67416 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -13,6 +13,7 @@ #include "dirvote_common.h" #include "microdesc.h" #include "networkstatus.h" +#include "parsecommon.h" #include "policies.h" #include "protover.h" #include "rephist.h" @@ -3828,3 +3829,73 @@ dirvote_format_all_microdesc_vote_lines(const routerinfo_t *ri, time_t now, return result; } +/** Parse and extract all SR commits from tokens and place them in + * ns. */ +static void +extract_shared_random_commits(networkstatus_t *ns, smartlist_t *tokens) +{ + smartlist_t *chunks = NULL; + + tor_assert(ns); + tor_assert(tokens); + /* Commits are only present in a vote. */ + tor_assert(ns->type == NS_TYPE_VOTE); + + ns->sr_info.commits = smartlist_new(); + + smartlist_t *commits = find_all_by_keyword(tokens, K_COMMIT); + /* It's normal that a vote might contain no commits even if it participates + * in the SR protocol. Don't treat it as an error. */ + if (commits == NULL) { + goto end; + } + + /* Parse the commit. We do NO validation of number of arguments or ordering + * for forward compatibility, it's the parse commit job to inform us if it's + * supported or not. */ + chunks = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(commits, directory_token_t *, tok) { + /* Extract all arguments and put them in the chunks list. */ + for (int i = 0; i < tok->n_args; i++) { + smartlist_add(chunks, tok->args[i]); + } + sr_commit_t *commit = sr_parse_commit(chunks); + smartlist_clear(chunks); + if (commit == NULL) { + /* Get voter identity so we can warn that this dirauth vote contains + * commit we can't parse. */ + networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0); + tor_assert(voter); + log_warn(LD_DIR, "SR: Unable to parse commit %s from vote of voter %s.", + escaped(tok->object_body), + hex_str(voter->identity_digest, + sizeof(voter->identity_digest))); + /* Commitment couldn't be parsed. Continue onto the next commit because + * this one could be unsupported for instance. */ + continue; + } + /* Add newly created commit object to the vote. */ + smartlist_add(ns->sr_info.commits, commit); + } SMARTLIST_FOREACH_END(tok); + + end: + smartlist_free(chunks); + smartlist_free(commits); +} + +/* Using the given directory tokens in tokens, parse the shared random commits + * and put them in the given vote document ns. + * + * This also sets the SR participation flag if present in the vote. */ +void +dirvote_parse_sr_commits(networkstatus_t *ns, smartlist_t *tokens) +{ + /* Does this authority participates in the SR protocol? */ + directory_token_t *tok = find_opt_by_keyword(tokens, K_SR_FLAG); + if (tok) { + ns->sr_info.participate = 1; + /* Get the SR commitments and reveals from the vote. */ + extract_shared_random_commits(ns, tokens); + } +} + diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index fcc7cecf26..4514c6daf0 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -99,6 +99,8 @@ void dirvote_act(const or_options_t *options, time_t now); void dirvote_free_all(void); +void dirvote_parse_sr_commits(networkstatus_t *ns, smartlist_t *tokens); + #else /* HAVE_MODULE_DIRAUTH */ static inline void @@ -113,6 +115,13 @@ dirvote_free_all(void) { } +static inline void +dirvote_parse_sr_commits(networkstatus_t *ns, smartlist_t *tokens) +{ + (void) ns; + (void) tokens; +} + #endif /* HAVE_MODULE_DIRAUTH */ void dirvote_recalculate_timing(const or_options_t *options, time_t now); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 9769d5ab50..3a55c00cc1 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -3285,60 +3285,6 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) return valid; } -/** Parse and extract all SR commits from tokens and place them in - * ns. */ -static void -extract_shared_random_commits(networkstatus_t *ns, smartlist_t *tokens) -{ - smartlist_t *chunks = NULL; - - tor_assert(ns); - tor_assert(tokens); - /* Commits are only present in a vote. */ - tor_assert(ns->type == NS_TYPE_VOTE); - - ns->sr_info.commits = smartlist_new(); - - smartlist_t *commits = find_all_by_keyword(tokens, K_COMMIT); - /* It's normal that a vote might contain no commits even if it participates - * in the SR protocol. Don't treat it as an error. */ - if (commits == NULL) { - goto end; - } - - /* Parse the commit. We do NO validation of number of arguments or ordering - * for forward compatibility, it's the parse commit job to inform us if it's - * supported or not. */ - chunks = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(commits, directory_token_t *, tok) { - /* Extract all arguments and put them in the chunks list. */ - for (int i = 0; i < tok->n_args; i++) { - smartlist_add(chunks, tok->args[i]); - } - sr_commit_t *commit = sr_parse_commit(chunks); - smartlist_clear(chunks); - if (commit == NULL) { - /* Get voter identity so we can warn that this dirauth vote contains - * commit we can't parse. */ - networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0); - tor_assert(voter); - log_warn(LD_DIR, "SR: Unable to parse commit %s from vote of voter %s.", - escaped(tok->object_body), - hex_str(voter->identity_digest, - sizeof(voter->identity_digest))); - /* Commitment couldn't be parsed. Continue onto the next commit because - * this one could be unsupported for instance. */ - continue; - } - /* Add newly created commit object to the vote. */ - smartlist_add(ns->sr_info.commits, commit); - } SMARTLIST_FOREACH_END(tok); - - end: - smartlist_free(chunks); - smartlist_free(commits); -} - /** Check if a shared random value of type srv_type is in * tokens. If there is, parse it and set it to srv_out. Return * -1 on failure, 0 on success. The resulting srv is allocated on the heap and @@ -3776,13 +3722,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, /* If this is a vote document, check if information about the shared randomness protocol is included, and extract it. */ if (ns->type == NS_TYPE_VOTE) { - /* Does this authority participates in the SR protocol? */ - tok = find_opt_by_keyword(tokens, K_SR_FLAG); - if (tok) { - ns->sr_info.participate = 1; - /* Get the SR commitments and reveals from the vote. */ - extract_shared_random_commits(ns, tokens); - } + dirvote_parse_sr_commits(ns, tokens); } /* For both a vote and consensus, extract the shared random values. */ if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS) { From 6ee6533fd89018036f11c5ee62897f8a2b6c39c0 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 10:49:32 -0400 Subject: [PATCH 14/20] dirvote: Free vote commits in the dirauth module In order to make sr_commit_free() only used by the dirauth module, this commits moves the commits free from a vote object into the dirvote.c file which is now only for the module. The function does nothing if the module is disabled. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.c | 13 +++++++++++++ src/or/dirauth/dirvote.h | 7 +++++++ src/or/networkstatus.c | 4 +--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index 3ec4d67416..53a896eb4d 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -3899,3 +3899,16 @@ dirvote_parse_sr_commits(networkstatus_t *ns, smartlist_t *tokens) } } +/* For the given vote, free the shared random commits if any. */ +void +dirvote_clear_commits(networkstatus_t *ns) +{ + tor_assert(ns->type == NS_TYPE_VOTE); + + if (ns->sr_info.commits) { + SMARTLIST_FOREACH(ns->sr_info.commits, sr_commit_t *, c, + sr_commit_free(c)); + smartlist_free(ns->sr_info.commits); + } +} + diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index 4514c6daf0..9682c60364 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -100,6 +100,7 @@ void dirvote_act(const or_options_t *options, time_t now); void dirvote_free_all(void); void dirvote_parse_sr_commits(networkstatus_t *ns, smartlist_t *tokens); +void dirvote_clear_commits(networkstatus_t *ns); #else /* HAVE_MODULE_DIRAUTH */ @@ -122,6 +123,12 @@ dirvote_parse_sr_commits(networkstatus_t *ns, smartlist_t *tokens) (void) tokens; } +static inline void +dirvote_clear_commits(networkstatus_t *ns) +{ + (void) ns; +} + #endif /* HAVE_MODULE_DIRAUTH */ void dirvote_recalculate_timing(const or_options_t *options, time_t now); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index fa8d0bcf13..5ca320d284 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -366,9 +366,7 @@ networkstatus_vote_free_(networkstatus_t *ns) digestmap_free(ns->desc_digest_map, NULL); if (ns->sr_info.commits) { - SMARTLIST_FOREACH(ns->sr_info.commits, sr_commit_t *, c, - sr_commit_free(c)); - smartlist_free(ns->sr_info.commits); + dirvote_clear_commits(ns); } tor_free(ns->sr_info.previous_srv); tor_free(ns->sr_info.current_srv); From fdc01cb40e1c982c273f7e9685c586ee1ef89e30 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 11:04:47 -0400 Subject: [PATCH 15/20] dirvote: Move the handling of GET /tor/status-vote to dirauth module In order to further isolate the dirauth code into its module, this moves the handling of the directory request GET /tor/status-vote/* into the module. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.c | 54 ++++++++++++++++++++++++++++++++++++++++ src/or/dirauth/dirvote.h | 11 ++++++++ src/or/directory.c | 48 ++--------------------------------- 3 files changed, 67 insertions(+), 46 deletions(-) diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index 53a896eb4d..dd00806238 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -3912,3 +3912,57 @@ dirvote_clear_commits(networkstatus_t *ns) } } +/* The given url is the /tor/status-gove GET directory request. Populates the + * items list with strings that we can compress on the fly and dir_items with + * cached_dir_t objects that have a precompressed deflated version. */ +void +dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items, + smartlist_t *dir_items) +{ + int current; + + url += strlen("/tor/status-vote/"); + current = !strcmpstart(url, "current/"); + url = strchr(url, '/'); + tor_assert(url); + ++url; + if (!strcmp(url, "consensus")) { + const char *item; + tor_assert(!current); /* we handle current consensus specially above, + * since it wants to be spooled. */ + if ((item = dirvote_get_pending_consensus(FLAV_NS))) + smartlist_add(items, (char*)item); + } else if (!current && !strcmp(url, "consensus-signatures")) { + /* XXXX the spec says that we should implement + * current/consensus-signatures too. It doesn't seem to be needed, + * though. */ + const char *item; + if ((item=dirvote_get_pending_detached_signatures())) + smartlist_add(items, (char*)item); + } else if (!strcmp(url, "authority")) { + const cached_dir_t *d; + int flags = DGV_BY_ID | + (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING); + if ((d=dirvote_get_vote(NULL, flags))) + smartlist_add(dir_items, (cached_dir_t*)d); + } else { + const cached_dir_t *d; + smartlist_t *fps = smartlist_new(); + int flags; + if (!strcmpstart(url, "d/")) { + url += 2; + flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS; + } else { + flags = DGV_BY_ID | + (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING); + } + dir_split_resource_into_fingerprints(url, fps, NULL, + DSR_HEX|DSR_SORT_UNIQ); + SMARTLIST_FOREACH(fps, char *, fp, { + if ((d = dirvote_get_vote(fp, flags))) + smartlist_add(dir_items, (cached_dir_t*)d); + tor_free(fp); + }); + smartlist_free(fps); + } +} diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index 9682c60364..69d628766f 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -101,6 +101,8 @@ void dirvote_free_all(void); void dirvote_parse_sr_commits(networkstatus_t *ns, smartlist_t *tokens); void dirvote_clear_commits(networkstatus_t *ns); +void dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items, + smartlist_t *dir_items); #else /* HAVE_MODULE_DIRAUTH */ @@ -129,6 +131,15 @@ dirvote_clear_commits(networkstatus_t *ns) (void) ns; } +static inline void +dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items, + smartlist_t *dir_items) +{ + (void) url; + (void) items; + (void) dir_items; +} + #endif /* HAVE_MODULE_DIRAUTH */ void dirvote_recalculate_timing(const or_options_t *options, time_t now); diff --git a/src/or/directory.c b/src/or/directory.c index 8a343ac02c..ea38f005e4 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -4438,59 +4438,15 @@ handle_get_status_vote(dir_connection_t *conn, const get_handler_args_t *args) { const char *url = args->url; { - int current; ssize_t body_len = 0; ssize_t estimated_len = 0; + int lifetime = 60; /* XXXX?? should actually use vote intervals. */ /* This smartlist holds strings that we can compress on the fly. */ smartlist_t *items = smartlist_new(); /* This smartlist holds cached_dir_t objects that have a precompressed * deflated version. */ smartlist_t *dir_items = smartlist_new(); - int lifetime = 60; /* XXXX?? should actually use vote intervals. */ - url += strlen("/tor/status-vote/"); - current = !strcmpstart(url, "current/"); - url = strchr(url, '/'); - tor_assert(url); - ++url; - if (!strcmp(url, "consensus")) { - const char *item; - tor_assert(!current); /* we handle current consensus specially above, - * since it wants to be spooled. */ - if ((item = dirvote_get_pending_consensus(FLAV_NS))) - smartlist_add(items, (char*)item); - } else if (!current && !strcmp(url, "consensus-signatures")) { - /* XXXX the spec says that we should implement - * current/consensus-signatures too. It doesn't seem to be needed, - * though. */ - const char *item; - if ((item=dirvote_get_pending_detached_signatures())) - smartlist_add(items, (char*)item); - } else if (!strcmp(url, "authority")) { - const cached_dir_t *d; - int flags = DGV_BY_ID | - (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING); - if ((d=dirvote_get_vote(NULL, flags))) - smartlist_add(dir_items, (cached_dir_t*)d); - } else { - const cached_dir_t *d; - smartlist_t *fps = smartlist_new(); - int flags; - if (!strcmpstart(url, "d/")) { - url += 2; - flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS; - } else { - flags = DGV_BY_ID | - (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING); - } - dir_split_resource_into_fingerprints(url, fps, NULL, - DSR_HEX|DSR_SORT_UNIQ); - SMARTLIST_FOREACH(fps, char *, fp, { - if ((d = dirvote_get_vote(fp, flags))) - smartlist_add(dir_items, (cached_dir_t*)d); - tor_free(fp); - }); - smartlist_free(fps); - } + dirvote_dirreq_get_status_vote(url, items, dir_items); if (!smartlist_len(dir_items) && !smartlist_len(items)) { write_short_http_response(conn, 404, "Not found"); goto vote_done; From 0f3b765b3c8ba6f4f105440861e87ecaf4ea4323 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 11:12:56 -0400 Subject: [PATCH 16/20] dirvote: Handling adding vote and signature if module is disabled Both functions are used for directory request but they can only be used if the running tor instance is a directory authority. For this reason, make those symbols visible but hard assert() if they are called when the module is disabled. This would mean we failed to safeguard the entry point into the module. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.h | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index 69d628766f..59cfd6b999 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -104,6 +104,14 @@ void dirvote_clear_commits(networkstatus_t *ns); void dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items, smartlist_t *dir_items); +/* Storing signatures and votes functions */ +struct pending_vote_t * dirvote_add_vote(const char *vote_body, + const char **msg_out, + int *status_out); +int dirvote_add_signatures(const char *detached_signatures_body, + const char *source, + const char **msg_out); + #else /* HAVE_MODULE_DIRAUTH */ static inline void @@ -140,16 +148,32 @@ dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items, (void) dir_items; } +static inline struct pending_vote_t * +dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) +{ + (void) vote_body; + (void) msg_out; + (void) status_out; + /* If the dirauth module is disabled, this should NEVER be called else we + * failed to safeguard the dirauth module. */ + tor_assert_nonfatal_unreached(); +} + +static inline int +dirvote_add_signatures(const char *detached_signatures_body, const char *source, + const char **msg_out) +{ + (void) detached_signatures_body; + (void) source; + (void) msg_out; + /* If the dirauth module is disabled, this should NEVER be called else we + * failed to safeguard the dirauth module. */ + tor_assert_nonfatal_unreached(); +} + #endif /* HAVE_MODULE_DIRAUTH */ void dirvote_recalculate_timing(const or_options_t *options, time_t now); -/* Invoked on timers and by outside triggers. */ -struct pending_vote_t * dirvote_add_vote(const char *vote_body, - const char **msg_out, - int *status_out); -int dirvote_add_signatures(const char *detached_signatures_body, - const char *source, - const char **msg_out); /* Item access */ MOCK_DECL(const char*, dirvote_get_pending_consensus, (consensus_flavor_t flav)); From a2ff4975f372870c841a8c4eeeeb93d834663650 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 25 Apr 2018 11:20:59 -0400 Subject: [PATCH 17/20] dirvote: Move the vote creation code into dirvote.c This code is only for dirauth so this commit moves it into the module in dirvote.c. No code behavior change. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.c | 514 ++++++++++++++++++++++++ src/or/dirauth/shared_random.c | 1 + src/or/dirauth/shared_random_state.c | 1 + src/or/dirserv.c | 571 ++------------------------- src/or/dirserv.h | 15 +- 5 files changed, 553 insertions(+), 549 deletions(-) diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index dd00806238..683cfdfcac 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -13,6 +13,7 @@ #include "dirvote_common.h" #include "microdesc.h" #include "networkstatus.h" +#include "nodelist.h" #include "parsecommon.h" #include "policies.h" #include "protover.h" @@ -3966,3 +3967,516 @@ dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items, smartlist_free(fps); } } + +/** Get the best estimate of a router's bandwidth for dirauth purposes, + * preferring measured to advertised values if available. */ +static uint32_t +dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri) +{ + uint32_t bw_kb = 0; + /* + * Yeah, measured bandwidths in measured_bw_line_t are (implicitly + * signed) longs and the ones router_get_advertised_bandwidth() returns + * are uint32_t. + */ + long mbw_kb = 0; + + if (ri) { + /* + * * First try to see if we have a measured bandwidth; don't bother with + * as_of_out here, on the theory that a stale measured bandwidth is still + * better to trust than an advertised one. + */ + if (dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest, + &mbw_kb, NULL)) { + /* Got one! */ + bw_kb = (uint32_t)mbw_kb; + } else { + /* If not, fall back to advertised */ + bw_kb = router_get_advertised_bandwidth(ri) / 1000; + } + } + + return bw_kb; +} + +/** Helper for sorting: compares two routerinfos first by address, and then by + * descending order of "usefulness". (An authority is more useful than a + * non-authority; a running router is more useful than a non-running router; + * and a router with more bandwidth is more useful than one with less.) + **/ +static int +compare_routerinfo_by_ip_and_bw_(const void **a, const void **b) +{ + routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b; + int first_is_auth, second_is_auth; + uint32_t bw_kb_first, bw_kb_second; + const node_t *node_first, *node_second; + int first_is_running, second_is_running; + + /* we return -1 if first should appear before second... that is, + * if first is a better router. */ + if (first->addr < second->addr) + return -1; + else if (first->addr > second->addr) + return 1; + + /* Potentially, this next bit could cause k n lg n memeq calls. But in + * reality, we will almost never get here, since addresses will usually be + * different. */ + + first_is_auth = + router_digest_is_trusted_dir(first->cache_info.identity_digest); + second_is_auth = + router_digest_is_trusted_dir(second->cache_info.identity_digest); + + if (first_is_auth && !second_is_auth) + return -1; + else if (!first_is_auth && second_is_auth) + return 1; + + node_first = node_get_by_id(first->cache_info.identity_digest); + node_second = node_get_by_id(second->cache_info.identity_digest); + first_is_running = node_first && node_first->is_running; + second_is_running = node_second && node_second->is_running; + + if (first_is_running && !second_is_running) + return -1; + else if (!first_is_running && second_is_running) + return 1; + + bw_kb_first = dirserv_get_bandwidth_for_router_kb(first); + bw_kb_second = dirserv_get_bandwidth_for_router_kb(second); + + if (bw_kb_first > bw_kb_second) + return -1; + else if (bw_kb_first < bw_kb_second) + return 1; + + /* They're equal! Compare by identity digest, so there's a + * deterministic order and we avoid flapping. */ + return fast_memcmp(first->cache_info.identity_digest, + second->cache_info.identity_digest, + DIGEST_LEN); +} + +/** Given a list of routerinfo_t in routers, return a new digestmap_t + * whose keys are the identity digests of those routers that we're going to + * exclude for Sybil-like appearance. */ +static digestmap_t * +get_possible_sybil_list(const smartlist_t *routers) +{ + const or_options_t *options = get_options(); + digestmap_t *omit_as_sybil; + smartlist_t *routers_by_ip = smartlist_new(); + uint32_t last_addr; + int addr_count; + /* Allow at most this number of Tor servers on a single IP address, ... */ + int max_with_same_addr = options->AuthDirMaxServersPerAddr; + if (max_with_same_addr <= 0) + max_with_same_addr = INT_MAX; + + smartlist_add_all(routers_by_ip, routers); + smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_); + omit_as_sybil = digestmap_new(); + + last_addr = 0; + addr_count = 0; + SMARTLIST_FOREACH_BEGIN(routers_by_ip, routerinfo_t *, ri) { + if (last_addr != ri->addr) { + last_addr = ri->addr; + addr_count = 1; + } else if (++addr_count > max_with_same_addr) { + digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri); + } + } SMARTLIST_FOREACH_END(ri); + + smartlist_free(routers_by_ip); + return omit_as_sybil; +} + +/** Given a platform string as in a routerinfo_t (possibly null), return a + * newly allocated version string for a networkstatus document, or NULL if the + * platform doesn't give a Tor version. */ +static char * +version_from_platform(const char *platform) +{ + if (platform && !strcmpstart(platform, "Tor ")) { + const char *eos = find_whitespace(platform+4); + if (eos && !strcmpstart(eos, " (r")) { + /* XXXX Unify this logic with the other version extraction + * logic in routerparse.c. */ + eos = find_whitespace(eos+1); + } + if (eos) { + return tor_strndup(platform, eos-platform); + } + } + return NULL; +} + +/** Given a (possibly empty) list of config_line_t, each line of which contains + * a list of comma-separated version numbers surrounded by optional space, + * allocate and return a new string containing the version numbers, in order, + * separated by commas. Used to generate Recommended(Client|Server)?Versions + */ +static char * +format_versions_list(config_line_t *ln) +{ + smartlist_t *versions; + char *result; + versions = smartlist_new(); + for ( ; ln; ln = ln->next) { + smartlist_split_string(versions, ln->value, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + } + sort_version_list(versions, 1); + result = smartlist_join_strings(versions,",",0,NULL); + SMARTLIST_FOREACH(versions,char *,s,tor_free(s)); + smartlist_free(versions); + return result; +} + +/** If there are entries in routers with exactly the same ed25519 keys, + * remove the older one. If they are exactly the same age, remove the one + * with the greater descriptor digest. May alter the order of the list. */ +static void +routers_make_ed_keys_unique(smartlist_t *routers) +{ + routerinfo_t *ri2; + digest256map_t *by_ed_key = digest256map_new(); + + SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { + ri->omit_from_vote = 0; + if (ri->cache_info.signing_key_cert == NULL) + continue; /* No ed key */ + const uint8_t *pk = ri->cache_info.signing_key_cert->signing_key.pubkey; + if ((ri2 = digest256map_get(by_ed_key, pk))) { + /* Duplicate; must omit one. Set the omit_from_vote flag in whichever + * one has the earlier published_on. */ + const time_t ri_pub = ri->cache_info.published_on; + const time_t ri2_pub = ri2->cache_info.published_on; + if (ri2_pub < ri_pub || + (ri2_pub == ri_pub && + fast_memcmp(ri->cache_info.signed_descriptor_digest, + ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) { + digest256map_set(by_ed_key, pk, ri); + ri2->omit_from_vote = 1; + } else { + ri->omit_from_vote = 1; + } + } else { + /* Add to map */ + digest256map_set(by_ed_key, pk, ri); + } + } SMARTLIST_FOREACH_END(ri); + + digest256map_free(by_ed_key, NULL); + + /* Now remove every router where the omit_from_vote flag got set. */ + SMARTLIST_FOREACH_BEGIN(routers, const routerinfo_t *, ri) { + if (ri->omit_from_vote) { + SMARTLIST_DEL_CURRENT(routers, ri); + } + } SMARTLIST_FOREACH_END(ri); +} + +/** Routerstatus rs is part of a group of routers that are on + * too narrow an IP-space. Clear out its flags since we don't want it be used + * because of its Sybil-like appearance. + * + * Leave its BadExit flag alone though, since if we think it's a bad exit, + * we want to vote that way in case all the other authorities are voting + * Running and Exit. + */ +static void +clear_status_flags_on_sybil(routerstatus_t *rs) +{ + rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = + rs->is_flagged_running = rs->is_named = rs->is_valid = + rs->is_hs_dir = rs->is_v2_dir = rs->is_possible_guard = 0; + /* FFFF we might want some mechanism to check later on if we + * missed zeroing any flags: it's easy to add a new flag but + * forget to add it to this clause. */ +} + +/** Return a new networkstatus_t* containing our current opinion. (For v3 + * authorities) */ +networkstatus_t * +dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, + authority_cert_t *cert) +{ + const or_options_t *options = get_options(); + networkstatus_t *v3_out = NULL; + uint32_t addr; + char *hostname = NULL, *client_versions = NULL, *server_versions = NULL; + const char *contact; + smartlist_t *routers, *routerstatuses; + char identity_digest[DIGEST_LEN]; + char signing_key_digest[DIGEST_LEN]; + int listbadexits = options->AuthDirListBadExits; + routerlist_t *rl = router_get_routerlist(); + time_t now = time(NULL); + time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; + networkstatus_voter_info_t *voter = NULL; + vote_timing_t timing; + digestmap_t *omit_as_sybil = NULL; + const int vote_on_reachability = running_long_enough_to_decide_unreachable(); + smartlist_t *microdescriptors = NULL; + + tor_assert(private_key); + tor_assert(cert); + + if (crypto_pk_get_digest(private_key, signing_key_digest)<0) { + log_err(LD_BUG, "Error computing signing key digest"); + return NULL; + } + if (crypto_pk_get_digest(cert->identity_key, identity_digest)<0) { + log_err(LD_BUG, "Error computing identity key digest"); + return NULL; + } + if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) { + log_warn(LD_NET, "Couldn't resolve my hostname"); + return NULL; + } + if (!hostname || !strchr(hostname, '.')) { + tor_free(hostname); + hostname = tor_dup_ip(addr); + } + + if (options->VersioningAuthoritativeDir) { + client_versions = format_versions_list(options->RecommendedClientVersions); + server_versions = format_versions_list(options->RecommendedServerVersions); + } + + contact = get_options()->ContactInfo; + if (!contact) + contact = "(none)"; + + /* + * Do this so dirserv_compute_performance_thresholds() and + * set_routerstatus_from_routerinfo() see up-to-date bandwidth info. + */ + if (options->V3BandwidthsFile) { + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL); + } else { + /* + * No bandwidths file; clear the measured bandwidth cache in case we had + * one last time around. + */ + if (dirserv_get_measured_bw_cache_size() > 0) { + dirserv_clear_measured_bw_cache(); + } + } + + /* precompute this part, since we need it to decide what "stable" + * means. */ + SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, { + dirserv_set_router_is_running(ri, now); + }); + + routers = smartlist_new(); + smartlist_add_all(routers, rl->routers); + routers_make_ed_keys_unique(routers); + /* After this point, don't use rl->routers; use 'routers' instead. */ + routers_sort_by_identity(routers); + omit_as_sybil = get_possible_sybil_list(routers); + + DIGESTMAP_FOREACH(omit_as_sybil, sybil_id, void *, ignore) { + (void) ignore; + rep_hist_make_router_pessimal(sybil_id, now); + } DIGESTMAP_FOREACH_END; + + /* Count how many have measured bandwidths so we know how to assign flags; + * this must come before dirserv_compute_performance_thresholds() */ + dirserv_count_measured_bws(routers); + + dirserv_compute_performance_thresholds(omit_as_sybil); + + routerstatuses = smartlist_new(); + microdescriptors = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { + if (ri->cache_info.published_on >= cutoff) { + routerstatus_t *rs; + vote_routerstatus_t *vrs; + node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); + if (!node) + continue; + + vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); + rs = &vrs->status; + set_routerstatus_from_routerinfo(rs, node, ri, now, + listbadexits); + + if (ri->cache_info.signing_key_cert) { + memcpy(vrs->ed25519_id, + ri->cache_info.signing_key_cert->signing_key.pubkey, + ED25519_PUBKEY_LEN); + } + + if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) + clear_status_flags_on_sybil(rs); + + if (!vote_on_reachability) + rs->is_flagged_running = 0; + + vrs->version = version_from_platform(ri->platform); + if (ri->protocol_list) { + vrs->protocols = tor_strdup(ri->protocol_list); + } else { + vrs->protocols = tor_strdup( + protover_compute_for_old_tor(vrs->version)); + } + vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now, + microdescriptors); + + smartlist_add(routerstatuses, vrs); + } + } SMARTLIST_FOREACH_END(ri); + + { + smartlist_t *added = + microdescs_add_list_to_cache(get_microdesc_cache(), + microdescriptors, SAVED_NOWHERE, 0); + smartlist_free(added); + smartlist_free(microdescriptors); + } + + smartlist_free(routers); + digestmap_free(omit_as_sybil, NULL); + + /* Apply guardfraction information to routerstatuses. */ + if (options->GuardfractionFile) { + dirserv_read_guardfraction_file(options->GuardfractionFile, + routerstatuses); + } + + /* This pass through applies the measured bw lines to the routerstatuses */ + if (options->V3BandwidthsFile) { + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, + routerstatuses); + } else { + /* + * No bandwidths file; clear the measured bandwidth cache in case we had + * one last time around. + */ + if (dirserv_get_measured_bw_cache_size() > 0) { + dirserv_clear_measured_bw_cache(); + } + } + + v3_out = tor_malloc_zero(sizeof(networkstatus_t)); + + v3_out->type = NS_TYPE_VOTE; + dirvote_get_preferred_voting_intervals(&timing); + v3_out->published = now; + { + char tbuf[ISO_TIME_LEN+1]; + networkstatus_t *current_consensus = + networkstatus_get_live_consensus(now); + long last_consensus_interval; /* only used to pick a valid_after */ + if (current_consensus) + last_consensus_interval = current_consensus->fresh_until - + current_consensus->valid_after; + else + last_consensus_interval = options->TestingV3AuthInitialVotingInterval; + v3_out->valid_after = + dirvote_get_start_of_next_interval(now, (int)last_consensus_interval, + options->TestingV3AuthVotingStartOffset); + format_iso_time(tbuf, v3_out->valid_after); + log_notice(LD_DIR,"Choosing valid-after time in vote as %s: " + "consensus_set=%d, last_interval=%d", + tbuf, current_consensus?1:0, (int)last_consensus_interval); + } + v3_out->fresh_until = v3_out->valid_after + timing.vote_interval; + v3_out->valid_until = v3_out->valid_after + + (timing.vote_interval * timing.n_intervals_valid); + v3_out->vote_seconds = timing.vote_delay; + v3_out->dist_seconds = timing.dist_delay; + tor_assert(v3_out->vote_seconds > 0); + tor_assert(v3_out->dist_seconds > 0); + tor_assert(timing.n_intervals_valid > 0); + + v3_out->client_versions = client_versions; + v3_out->server_versions = server_versions; + + /* These are hardwired, to avoid disaster. */ + v3_out->recommended_relay_protocols = + tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " + "Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"); + v3_out->recommended_client_protocols = + tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " + "Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"); + v3_out->required_client_protocols = + tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " + "Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"); + v3_out->required_relay_protocols = + tor_strdup("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " + "Link=3-4 LinkAuth=1 Microdesc=1 Relay=1-2"); + + /* We are not allowed to vote to require anything we don't have. */ + tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL)); + tor_assert(protover_all_supported(v3_out->required_client_protocols, NULL)); + + /* We should not recommend anything we don't have. */ + tor_assert_nonfatal(protover_all_supported( + v3_out->recommended_relay_protocols, NULL)); + tor_assert_nonfatal(protover_all_supported( + v3_out->recommended_client_protocols, NULL)); + + v3_out->package_lines = smartlist_new(); + { + config_line_t *cl; + for (cl = get_options()->RecommendedPackages; cl; cl = cl->next) { + if (validate_recommended_package_line(cl->value)) + smartlist_add_strdup(v3_out->package_lines, cl->value); + } + } + + v3_out->known_flags = smartlist_new(); + smartlist_split_string(v3_out->known_flags, + "Authority Exit Fast Guard Stable V2Dir Valid HSDir", + 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (vote_on_reachability) + smartlist_add_strdup(v3_out->known_flags, "Running"); + if (listbadexits) + smartlist_add_strdup(v3_out->known_flags, "BadExit"); + smartlist_sort_strings(v3_out->known_flags); + + if (options->ConsensusParams) { + v3_out->net_params = smartlist_new(); + smartlist_split_string(v3_out->net_params, + options->ConsensusParams, NULL, 0, 0); + smartlist_sort_strings(v3_out->net_params); + } + + voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); + voter->nickname = tor_strdup(options->Nickname); + memcpy(voter->identity_digest, identity_digest, DIGEST_LEN); + voter->sigs = smartlist_new(); + voter->address = hostname; + voter->addr = addr; + voter->dir_port = router_get_advertised_dir_port(options, 0); + voter->or_port = router_get_advertised_or_port(options); + voter->contact = tor_strdup(contact); + if (options->V3AuthUseLegacyKey) { + authority_cert_t *c = get_my_v3_legacy_cert(); + if (c) { + if (crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest)) { + log_warn(LD_BUG, "Unable to compute digest of legacy v3 identity key"); + memset(voter->legacy_id_digest, 0, DIGEST_LEN); + } + } + } + + v3_out->voters = smartlist_new(); + smartlist_add(v3_out->voters, voter); + v3_out->cert = dirvote_authority_cert_dup(cert); + v3_out->routerstatus_list = routerstatuses; + /* Note: networkstatus_digest is unset; it won't get set until we actually + * format the vote. */ + + return v3_out; +} + diff --git a/src/or/dirauth/shared_random.c b/src/or/dirauth/shared_random.c index 5dee77dce9..7e49204159 100644 --- a/src/or/dirauth/shared_random.c +++ b/src/or/dirauth/shared_random.c @@ -91,6 +91,7 @@ #include "shared_random.h" #include "config.h" #include "confparse.h" +#include "dirvote_common.h" #include "networkstatus.h" #include "routerkeys.h" #include "router.h" diff --git a/src/or/dirauth/shared_random_state.c b/src/or/dirauth/shared_random_state.c index 846c3c7aa2..ac8fb5c151 100644 --- a/src/or/dirauth/shared_random_state.c +++ b/src/or/dirauth/shared_random_state.c @@ -14,6 +14,7 @@ #include "shared_random.h" #include "config.h" #include "confparse.h" +#include "dirvote_common.h" #include "networkstatus.h" #include "router.h" #include "shared_random_state.h" diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 1ade52e81e..e7b55b152b 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -76,7 +76,6 @@ static int routers_with_measured_bw = 0; static void directory_remove_invalid(void); -static char *format_versions_list(config_line_t *ln); struct authdir_config_t; static uint32_t dirserv_get_status_impl(const char *fp, const char *nickname, @@ -89,7 +88,6 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp( int extrainfo); static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei, const char **msg); -static uint32_t dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri); static uint32_t dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri); static int spooled_resource_lookup_body(const spooled_resource_t *spooled, @@ -923,7 +921,7 @@ list_single_server_status(const routerinfo_t *desc, int is_live) } /* DOCDOC running_long_enough_to_decide_unreachable */ -static inline int +int running_long_enough_to_decide_unreachable(void) { return time_of_process_start @@ -1058,28 +1056,6 @@ list_server_status_v1(smartlist_t *routers, char **router_status_out, return 0; } -/** Given a (possibly empty) list of config_line_t, each line of which contains - * a list of comma-separated version numbers surrounded by optional space, - * allocate and return a new string containing the version numbers, in order, - * separated by commas. Used to generate Recommended(Client|Server)?Versions - */ -static char * -format_versions_list(config_line_t *ln) -{ - smartlist_t *versions; - char *result; - versions = smartlist_new(); - for ( ; ln; ln = ln->next) { - smartlist_split_string(versions, ln->value, ",", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - } - sort_version_list(versions, 1); - result = smartlist_join_strings(versions,",",0,NULL); - SMARTLIST_FOREACH(versions,char *,s,tor_free(s)); - smartlist_free(versions); - return result; -} - /** Return 1 if ri's descriptor is "active" -- running, valid, * not hibernating, having observed bw greater 0, and not too old. Else * return 0. @@ -1469,6 +1445,24 @@ router_counts_toward_thresholds(const node_t *node, time_t now, (have_mbw || !require_mbw); } +/** Look through the routerlist, and using the measured bandwidth cache count + * how many measured bandwidths we know. This is used to decide whether we + * ever trust advertised bandwidths for purposes of assigning flags. */ +void +dirserv_count_measured_bws(const smartlist_t *routers) +{ + /* Initialize this first */ + routers_with_measured_bw = 0; + + /* Iterate over the routerlist and count measured bandwidths */ + SMARTLIST_FOREACH_BEGIN(routers, const routerinfo_t *, ri) { + /* Check if we know a measured bandwidth for this one */ + if (dirserv_has_measured_bw(ri->cache_info.identity_digest)) { + ++routers_with_measured_bw; + } + } SMARTLIST_FOREACH_END(ri); +} + /** Look through the routerlist, the Mean Time Between Failure history, and * the Weighted Fractional Uptime history, and use them to set thresholds for * the Stable, Fast, and Guard flags. Update the fields stable_uptime, @@ -1476,7 +1470,7 @@ router_counts_toward_thresholds(const node_t *node, time_t now, * guard_bandwidth_including_exits, and guard_bandwidth_excluding_exits. * * Also, set the is_exit flag of each router appropriately. */ -static void +void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) { int n_active, n_active_nonexit, n_familiar; @@ -1707,7 +1701,7 @@ dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, } /** Clear and free the measured bandwidth cache */ -STATIC void +void dirserv_clear_measured_bw_cache(void) { if (mbw_cache) { @@ -1739,18 +1733,10 @@ dirserv_expire_measured_bw_cache(time_t now) } } -/** Get the current size of the measured bandwidth cache */ -STATIC int -dirserv_get_measured_bw_cache_size(void) -{ - if (mbw_cache) return digestmap_size(mbw_cache); - else return 0; -} - /** Query the cache by identity digest, return value indicates whether * we found it. The bw_out and as_of_out pointers receive the cached * bandwidth value and the time it was cached if not NULL. */ -STATIC int +int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out, time_t *as_of_out) { @@ -1771,61 +1757,18 @@ dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out, } /** Predicate wrapper for dirserv_query_measured_bw_cache() */ -STATIC int +int dirserv_has_measured_bw(const char *node_id) { return dirserv_query_measured_bw_cache_kb(node_id, NULL, NULL); } -/** Get the best estimate of a router's bandwidth for dirauth purposes, - * preferring measured to advertised values if available. */ - -static uint32_t -dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri) +/** Get the current size of the measured bandwidth cache */ +int +dirserv_get_measured_bw_cache_size(void) { - uint32_t bw_kb = 0; - /* - * Yeah, measured bandwidths in measured_bw_line_t are (implicitly - * signed) longs and the ones router_get_advertised_bandwidth() returns - * are uint32_t. - */ - long mbw_kb = 0; - - if (ri) { - /* - * * First try to see if we have a measured bandwidth; don't bother with - * as_of_out here, on the theory that a stale measured bandwidth is still - * better to trust than an advertised one. - */ - if (dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest, - &mbw_kb, NULL)) { - /* Got one! */ - bw_kb = (uint32_t)mbw_kb; - } else { - /* If not, fall back to advertised */ - bw_kb = router_get_advertised_bandwidth(ri) / 1000; - } - } - - return bw_kb; -} - -/** Look through the routerlist, and using the measured bandwidth cache count - * how many measured bandwidths we know. This is used to decide whether we - * ever trust advertised bandwidths for purposes of assigning flags. */ -static void -dirserv_count_measured_bws(const smartlist_t *routers) -{ - /* Initialize this first */ - routers_with_measured_bw = 0; - - /* Iterate over the routerlist and count measured bandwidths */ - SMARTLIST_FOREACH_BEGIN(routers, const routerinfo_t *, ri) { - /* Check if we know a measured bandwidth for this one */ - if (dirserv_has_measured_bw(ri->cache_info.identity_digest)) { - ++routers_with_measured_bw; - } - } SMARTLIST_FOREACH_END(ri); + if (mbw_cache) return digestmap_size(mbw_cache); + else return 0; } /** Return the bandwidth we believe for assigning flags; prefer measured @@ -1888,26 +1831,6 @@ dirserv_get_flag_thresholds_line(void) return result; } -/** Given a platform string as in a routerinfo_t (possibly null), return a - * newly allocated version string for a networkstatus document, or NULL if the - * platform doesn't give a Tor version. */ -static char * -version_from_platform(const char *platform) -{ - if (platform && !strcmpstart(platform, "Tor ")) { - const char *eos = find_whitespace(platform+4); - if (eos && !strcmpstart(eos, " (r")) { - /* XXXX Unify this logic with the other version extraction - * logic in routerparse.c. */ - eos = find_whitespace(eos+1); - } - if (eos) { - return tor_strndup(platform, eos-platform); - } - } - return NULL; -} - /** Helper: write the router-status information in rs into a newly * allocated character buffer. Use the same format as in network-status * documents. If version is non-NULL, add a "v" line for the platform. @@ -2096,145 +2019,6 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, return result; } -/** Helper for sorting: compares two routerinfos first by address, and then by - * descending order of "usefulness". (An authority is more useful than a - * non-authority; a running router is more useful than a non-running router; - * and a router with more bandwidth is more useful than one with less.) - **/ -static int -compare_routerinfo_by_ip_and_bw_(const void **a, const void **b) -{ - routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b; - int first_is_auth, second_is_auth; - uint32_t bw_kb_first, bw_kb_second; - const node_t *node_first, *node_second; - int first_is_running, second_is_running; - - /* we return -1 if first should appear before second... that is, - * if first is a better router. */ - if (first->addr < second->addr) - return -1; - else if (first->addr > second->addr) - return 1; - - /* Potentially, this next bit could cause k n lg n memeq calls. But in - * reality, we will almost never get here, since addresses will usually be - * different. */ - - first_is_auth = - router_digest_is_trusted_dir(first->cache_info.identity_digest); - second_is_auth = - router_digest_is_trusted_dir(second->cache_info.identity_digest); - - if (first_is_auth && !second_is_auth) - return -1; - else if (!first_is_auth && second_is_auth) - return 1; - - node_first = node_get_by_id(first->cache_info.identity_digest); - node_second = node_get_by_id(second->cache_info.identity_digest); - first_is_running = node_first && node_first->is_running; - second_is_running = node_second && node_second->is_running; - - if (first_is_running && !second_is_running) - return -1; - else if (!first_is_running && second_is_running) - return 1; - - bw_kb_first = dirserv_get_bandwidth_for_router_kb(first); - bw_kb_second = dirserv_get_bandwidth_for_router_kb(second); - - if (bw_kb_first > bw_kb_second) - return -1; - else if (bw_kb_first < bw_kb_second) - return 1; - - /* They're equal! Compare by identity digest, so there's a - * deterministic order and we avoid flapping. */ - return fast_memcmp(first->cache_info.identity_digest, - second->cache_info.identity_digest, - DIGEST_LEN); -} - -/** Given a list of routerinfo_t in routers, return a new digestmap_t - * whose keys are the identity digests of those routers that we're going to - * exclude for Sybil-like appearance. */ -static digestmap_t * -get_possible_sybil_list(const smartlist_t *routers) -{ - const or_options_t *options = get_options(); - digestmap_t *omit_as_sybil; - smartlist_t *routers_by_ip = smartlist_new(); - uint32_t last_addr; - int addr_count; - /* Allow at most this number of Tor servers on a single IP address, ... */ - int max_with_same_addr = options->AuthDirMaxServersPerAddr; - if (max_with_same_addr <= 0) - max_with_same_addr = INT_MAX; - - smartlist_add_all(routers_by_ip, routers); - smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_); - omit_as_sybil = digestmap_new(); - - last_addr = 0; - addr_count = 0; - SMARTLIST_FOREACH_BEGIN(routers_by_ip, routerinfo_t *, ri) { - if (last_addr != ri->addr) { - last_addr = ri->addr; - addr_count = 1; - } else if (++addr_count > max_with_same_addr) { - digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri); - } - } SMARTLIST_FOREACH_END(ri); - - smartlist_free(routers_by_ip); - return omit_as_sybil; -} - -/** If there are entries in routers with exactly the same ed25519 keys, - * remove the older one. If they are exactly the same age, remove the one - * with the greater descriptor digest. May alter the order of the list. */ -static void -routers_make_ed_keys_unique(smartlist_t *routers) -{ - routerinfo_t *ri2; - digest256map_t *by_ed_key = digest256map_new(); - - SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { - ri->omit_from_vote = 0; - if (ri->cache_info.signing_key_cert == NULL) - continue; /* No ed key */ - const uint8_t *pk = ri->cache_info.signing_key_cert->signing_key.pubkey; - if ((ri2 = digest256map_get(by_ed_key, pk))) { - /* Duplicate; must omit one. Set the omit_from_vote flag in whichever - * one has the earlier published_on. */ - const time_t ri_pub = ri->cache_info.published_on; - const time_t ri2_pub = ri2->cache_info.published_on; - if (ri2_pub < ri_pub || - (ri2_pub == ri_pub && - fast_memcmp(ri->cache_info.signed_descriptor_digest, - ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) { - digest256map_set(by_ed_key, pk, ri); - ri2->omit_from_vote = 1; - } else { - ri->omit_from_vote = 1; - } - } else { - /* Add to map */ - digest256map_set(by_ed_key, pk, ri); - } - } SMARTLIST_FOREACH_END(ri); - - digest256map_free(by_ed_key, NULL); - - /* Now remove every router where the omit_from_vote flag got set. */ - SMARTLIST_FOREACH_BEGIN(routers, const routerinfo_t *, ri) { - if (ri->omit_from_vote) { - SMARTLIST_DEL_CURRENT(routers, ri); - } - } SMARTLIST_FOREACH_END(ri); -} - /** Extract status information from ri and from other authority * functions and store it in rs. rs is zeroed out before it is * set. @@ -2347,25 +2131,6 @@ dirserv_set_routerstatus_testing(routerstatus_t *rs) } } -/** Routerstatus rs is part of a group of routers that are on - * too narrow an IP-space. Clear out its flags since we don't want it be used - * because of its Sybil-like appearance. - * - * Leave its BadExit flag alone though, since if we think it's a bad exit, - * we want to vote that way in case all the other authorities are voting - * Running and Exit. - */ -static void -clear_status_flags_on_sybil(routerstatus_t *rs) -{ - rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = - rs->is_flagged_running = rs->is_named = rs->is_valid = - rs->is_hs_dir = rs->is_v2_dir = rs->is_possible_guard = 0; - /* FFFF we might want some mechanism to check later on if we - * missed zeroing any flags: it's easy to add a new flag but - * forget to add it to this clause. */ -} - /** The guardfraction of the guard with identity fingerprint guard_id * is guardfraction_percentage. See if we have a vote routerstatus for * this guard in vote_routerstatuses, and if we do, register the @@ -2859,286 +2624,6 @@ dirserv_read_measured_bandwidths(const char *from_file, return 0; } -/** Return a new networkstatus_t* containing our current opinion. (For v3 - * authorities) */ -networkstatus_t * -dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, - authority_cert_t *cert) -{ - const or_options_t *options = get_options(); - networkstatus_t *v3_out = NULL; - uint32_t addr; - char *hostname = NULL, *client_versions = NULL, *server_versions = NULL; - const char *contact; - smartlist_t *routers, *routerstatuses; - char identity_digest[DIGEST_LEN]; - char signing_key_digest[DIGEST_LEN]; - int listbadexits = options->AuthDirListBadExits; - routerlist_t *rl = router_get_routerlist(); - time_t now = time(NULL); - time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; - networkstatus_voter_info_t *voter = NULL; - vote_timing_t timing; - digestmap_t *omit_as_sybil = NULL; - const int vote_on_reachability = running_long_enough_to_decide_unreachable(); - smartlist_t *microdescriptors = NULL; - - tor_assert(private_key); - tor_assert(cert); - - if (crypto_pk_get_digest(private_key, signing_key_digest)<0) { - log_err(LD_BUG, "Error computing signing key digest"); - return NULL; - } - if (crypto_pk_get_digest(cert->identity_key, identity_digest)<0) { - log_err(LD_BUG, "Error computing identity key digest"); - return NULL; - } - if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) { - log_warn(LD_NET, "Couldn't resolve my hostname"); - return NULL; - } - if (!hostname || !strchr(hostname, '.')) { - tor_free(hostname); - hostname = tor_dup_ip(addr); - } - - if (options->VersioningAuthoritativeDir) { - client_versions = format_versions_list(options->RecommendedClientVersions); - server_versions = format_versions_list(options->RecommendedServerVersions); - } - - contact = get_options()->ContactInfo; - if (!contact) - contact = "(none)"; - - /* - * Do this so dirserv_compute_performance_thresholds() and - * set_routerstatus_from_routerinfo() see up-to-date bandwidth info. - */ - if (options->V3BandwidthsFile) { - dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL); - } else { - /* - * No bandwidths file; clear the measured bandwidth cache in case we had - * one last time around. - */ - if (dirserv_get_measured_bw_cache_size() > 0) { - dirserv_clear_measured_bw_cache(); - } - } - - /* precompute this part, since we need it to decide what "stable" - * means. */ - SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, { - dirserv_set_router_is_running(ri, now); - }); - - routers = smartlist_new(); - smartlist_add_all(routers, rl->routers); - routers_make_ed_keys_unique(routers); - /* After this point, don't use rl->routers; use 'routers' instead. */ - routers_sort_by_identity(routers); - omit_as_sybil = get_possible_sybil_list(routers); - - DIGESTMAP_FOREACH(omit_as_sybil, sybil_id, void *, ignore) { - (void) ignore; - rep_hist_make_router_pessimal(sybil_id, now); - } DIGESTMAP_FOREACH_END; - - /* Count how many have measured bandwidths so we know how to assign flags; - * this must come before dirserv_compute_performance_thresholds() */ - dirserv_count_measured_bws(routers); - - dirserv_compute_performance_thresholds(omit_as_sybil); - - routerstatuses = smartlist_new(); - microdescriptors = smartlist_new(); - - SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { - if (ri->cache_info.published_on >= cutoff) { - routerstatus_t *rs; - vote_routerstatus_t *vrs; - node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); - if (!node) - continue; - - vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); - rs = &vrs->status; - set_routerstatus_from_routerinfo(rs, node, ri, now, - listbadexits); - - if (ri->cache_info.signing_key_cert) { - memcpy(vrs->ed25519_id, - ri->cache_info.signing_key_cert->signing_key.pubkey, - ED25519_PUBKEY_LEN); - } - - if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) - clear_status_flags_on_sybil(rs); - - if (!vote_on_reachability) - rs->is_flagged_running = 0; - - vrs->version = version_from_platform(ri->platform); - if (ri->protocol_list) { - vrs->protocols = tor_strdup(ri->protocol_list); - } else { - vrs->protocols = tor_strdup( - protover_compute_for_old_tor(vrs->version)); - } - vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now, - microdescriptors); - - smartlist_add(routerstatuses, vrs); - } - } SMARTLIST_FOREACH_END(ri); - - { - smartlist_t *added = - microdescs_add_list_to_cache(get_microdesc_cache(), - microdescriptors, SAVED_NOWHERE, 0); - smartlist_free(added); - smartlist_free(microdescriptors); - } - - smartlist_free(routers); - digestmap_free(omit_as_sybil, NULL); - - /* Apply guardfraction information to routerstatuses. */ - if (options->GuardfractionFile) { - dirserv_read_guardfraction_file(options->GuardfractionFile, - routerstatuses); - } - - /* This pass through applies the measured bw lines to the routerstatuses */ - if (options->V3BandwidthsFile) { - dirserv_read_measured_bandwidths(options->V3BandwidthsFile, - routerstatuses); - } else { - /* - * No bandwidths file; clear the measured bandwidth cache in case we had - * one last time around. - */ - if (dirserv_get_measured_bw_cache_size() > 0) { - dirserv_clear_measured_bw_cache(); - } - } - - v3_out = tor_malloc_zero(sizeof(networkstatus_t)); - - v3_out->type = NS_TYPE_VOTE; - dirvote_get_preferred_voting_intervals(&timing); - v3_out->published = now; - { - char tbuf[ISO_TIME_LEN+1]; - networkstatus_t *current_consensus = - networkstatus_get_live_consensus(now); - long last_consensus_interval; /* only used to pick a valid_after */ - if (current_consensus) - last_consensus_interval = current_consensus->fresh_until - - current_consensus->valid_after; - else - last_consensus_interval = options->TestingV3AuthInitialVotingInterval; - v3_out->valid_after = - dirvote_get_start_of_next_interval(now, (int)last_consensus_interval, - options->TestingV3AuthVotingStartOffset); - format_iso_time(tbuf, v3_out->valid_after); - log_notice(LD_DIR,"Choosing valid-after time in vote as %s: " - "consensus_set=%d, last_interval=%d", - tbuf, current_consensus?1:0, (int)last_consensus_interval); - } - v3_out->fresh_until = v3_out->valid_after + timing.vote_interval; - v3_out->valid_until = v3_out->valid_after + - (timing.vote_interval * timing.n_intervals_valid); - v3_out->vote_seconds = timing.vote_delay; - v3_out->dist_seconds = timing.dist_delay; - tor_assert(v3_out->vote_seconds > 0); - tor_assert(v3_out->dist_seconds > 0); - tor_assert(timing.n_intervals_valid > 0); - - v3_out->client_versions = client_versions; - v3_out->server_versions = server_versions; - - /* These are hardwired, to avoid disaster. */ - v3_out->recommended_relay_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"); - v3_out->recommended_client_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"); - v3_out->required_client_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 LinkAuth=1 Microdesc=1-2 Relay=2"); - v3_out->required_relay_protocols = - tor_strdup("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=3-4 LinkAuth=1 Microdesc=1 Relay=1-2"); - - /* We are not allowed to vote to require anything we don't have. */ - tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL)); - tor_assert(protover_all_supported(v3_out->required_client_protocols, NULL)); - - /* We should not recommend anything we don't have. */ - tor_assert_nonfatal(protover_all_supported( - v3_out->recommended_relay_protocols, NULL)); - tor_assert_nonfatal(protover_all_supported( - v3_out->recommended_client_protocols, NULL)); - - v3_out->package_lines = smartlist_new(); - { - config_line_t *cl; - for (cl = get_options()->RecommendedPackages; cl; cl = cl->next) { - if (validate_recommended_package_line(cl->value)) - smartlist_add_strdup(v3_out->package_lines, cl->value); - } - } - - v3_out->known_flags = smartlist_new(); - smartlist_split_string(v3_out->known_flags, - "Authority Exit Fast Guard Stable V2Dir Valid HSDir", - 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (vote_on_reachability) - smartlist_add_strdup(v3_out->known_flags, "Running"); - if (listbadexits) - smartlist_add_strdup(v3_out->known_flags, "BadExit"); - smartlist_sort_strings(v3_out->known_flags); - - if (options->ConsensusParams) { - v3_out->net_params = smartlist_new(); - smartlist_split_string(v3_out->net_params, - options->ConsensusParams, NULL, 0, 0); - smartlist_sort_strings(v3_out->net_params); - } - - voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); - voter->nickname = tor_strdup(options->Nickname); - memcpy(voter->identity_digest, identity_digest, DIGEST_LEN); - voter->sigs = smartlist_new(); - voter->address = hostname; - voter->addr = addr; - voter->dir_port = router_get_advertised_dir_port(options, 0); - voter->or_port = router_get_advertised_or_port(options); - voter->contact = tor_strdup(contact); - if (options->V3AuthUseLegacyKey) { - authority_cert_t *c = get_my_v3_legacy_cert(); - if (c) { - if (crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest)) { - log_warn(LD_BUG, "Unable to compute digest of legacy v3 identity key"); - memset(voter->legacy_id_digest, 0, DIGEST_LEN); - } - } - } - - v3_out->voters = smartlist_new(); - smartlist_add(v3_out->voters, voter); - v3_out->cert = dirvote_authority_cert_dup(cert); - v3_out->routerstatus_list = routerstatuses; - /* Note: networkstatus_digest is unset; it won't get set until we actually - * format the vote. */ - - return v3_out; -} - /** As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t * pointers, adds copies of digests to fps_out, and doesn't use the * /tor/server/ prefix. For a /d/ request, adds descriptor digests; for other diff --git a/src/or/dirserv.h b/src/or/dirserv.h index b9af68ff6e..f0b8913c5c 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -157,6 +157,15 @@ void cached_dir_decref(cached_dir_t *d); cached_dir_t *new_cached_dir(char *s, time_t published); int validate_recommended_package_line(const char *line); +int dirserv_query_measured_bw_cache_kb(const char *node_id, + long *bw_out, + time_t *as_of_out); +void dirserv_clear_measured_bw_cache(void); +int dirserv_has_measured_bw(const char *node_id); +int dirserv_get_measured_bw_cache_size(void); +void dirserv_count_measured_bws(const smartlist_t *routers); +int running_long_enough_to_decide_unreachable(void); +void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil); #ifdef DIRSERV_PRIVATE @@ -172,13 +181,7 @@ STATIC int measured_bw_line_apply(measured_bw_line_t *parsed_line, STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, time_t as_of); -STATIC void dirserv_clear_measured_bw_cache(void); STATIC void dirserv_expire_measured_bw_cache(time_t now); -STATIC int dirserv_get_measured_bw_cache_size(void); -STATIC int dirserv_query_measured_bw_cache_kb(const char *node_id, - long *bw_out, - time_t *as_of_out); -STATIC int dirserv_has_measured_bw(const char *node_id); STATIC int dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str, From 43bba89656cce89964f260d46f2550ab9af00c9e Mon Sep 17 00:00:00 2001 From: David Goulet Date: Fri, 27 Apr 2018 11:33:22 -0400 Subject: [PATCH 18/20] build: Always compile module support for tests The --disable-module-* configure option removes code from the final binary but we still build the unit tests with the disable module(s) so we can actually test that code path all the time and not forget about it. Signed-off-by: David Goulet --- Makefile.am | 6 +++--- configure.ac | 12 ++++++++++++ src/or/include.am | 11 +++++++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index cccad6c5ed..163b650bb0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -51,14 +51,14 @@ AM_ETAGSFLAGS=--regex='{c}/MOCK_IMPL([^,]+,\W*\([a-zA-Z0-9_]+\)\W*,/\1/s' if COVERAGE_ENABLED TEST_CFLAGS=-fno-inline -fprofile-arcs -ftest-coverage if DISABLE_ASSERTS_IN_UNIT_TESTS -TEST_CPPFLAGS=-DTOR_UNIT_TESTS -DTOR_COVERAGE -DDISABLE_ASSERTS_IN_UNIT_TESTS +TEST_CPPFLAGS=-DTOR_UNIT_TESTS -DTOR_COVERAGE -DDISABLE_ASSERTS_IN_UNIT_TESTS @TOR_MODULES_ALL_ENABLED@ else -TEST_CPPFLAGS=-DTOR_UNIT_TESTS -DTOR_COVERAGE +TEST_CPPFLAGS=-DTOR_UNIT_TESTS -DTOR_COVERAGE @TOR_MODULES_ALL_ENABLED@ endif TEST_NETWORK_FLAGS=--coverage --hs-multi-client 1 else TEST_CFLAGS= -TEST_CPPFLAGS=-DTOR_UNIT_TESTS +TEST_CPPFLAGS=-DTOR_UNIT_TESTS @TOR_MODULES_ALL_ENABLED@ TEST_NETWORK_FLAGS=--hs-multi-client 1 endif TEST_NETWORK_WARNING_FLAGS=--quiet --only-warnings diff --git a/configure.ac b/configure.ac index b423ea95e5..ae2c420557 100644 --- a/configure.ac +++ b/configure.ac @@ -234,6 +234,9 @@ dnl --- dnl Tor modules options. These options are namespaced with --disable-module-XXX dnl --- +dnl All our modules. +m4_define(MODULES, dirauth) + dnl Directory Authority module. AC_ARG_ENABLE([module-dirauth], AS_HELP_STRING([--disable-module-dirauth], @@ -243,6 +246,15 @@ AC_ARG_ENABLE([module-dirauth], [Compile with Directory Authority feature support])) AM_CONDITIONAL(BUILD_MODULE_DIRAUTH, [test "x$enable_module_dirauth" != "xno"]) +dnl Helper variables. +TOR_MODULES_ALL_ENABLED= +AC_DEFUN([ADD_MODULE], [ + MODULE=m4_toupper($1) + TOR_MODULES_ALL_ENABLED="${TOR_MODULES_ALL_ENABLED} -DHAVE_MODULE_${MODULE}=1" +]) +m4_foreach_w([module], MODULES, [ADD_MODULE([module])]) +AC_SUBST(TOR_MODULES_ALL_ENABLED) + dnl check for the correct "ar" when cross-compiling. dnl (AM_PROG_AR was new in automake 1.11.2, which we do not yet require, dnl so kludge up a replacement for the case where it isn't there yet.) diff --git a/src/or/include.am b/src/or/include.am index 93f405d619..bb505937ac 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -114,20 +114,23 @@ LIBTOR_A_SOURCES = \ # # Modules are conditionnally compiled in tor starting here. We add the C files -# only if the modules has been enabled at configure time. +# only if the modules has been enabled at configure time. We always add the +# source files of every module to libtor-testing.a so we can build the unit +# tests for everything. # # The Directory Authority module. -if BUILD_MODULE_DIRAUTH -LIBTOR_A_SOURCES += \ +MODULE_DIRAUTH_SOURCES = \ src/or/dirauth/dircollate.c \ src/or/dirauth/dirvote.c \ src/or/dirauth/shared_random.c \ src/or/dirauth/shared_random_state.c +if BUILD_MODULE_DIRAUTH +LIBTOR_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) endif src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES) -src_or_libtor_testing_a_SOURCES = $(LIBTOR_A_SOURCES) +src_or_libtor_testing_a_SOURCES = $(LIBTOR_A_SOURCES) $(MODULE_DIRAUTH_SOURCES) src_or_tor_SOURCES = src/or/tor_main.c AM_CPPFLAGS += -I$(srcdir)/src/or -Isrc/or From 15e8ce39379fde7b6cddb4b06b3d8e01fadd4867 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 1 May 2018 08:58:57 -0400 Subject: [PATCH 19/20] Move back dirvote_authority_cert_dup to dirvote.c Originally, it was made public outside of the dirauth module but it is no longer needed. In doing so, we put it back in dirvote.c and reverted its name to the original one: dirvote_authority_cert_dup() --> authority_cert_dup() Signed-off-by: David Goulet --- src/or/dirauth/dirvote.c | 26 +++++++++++++++++++++++++- src/or/dirauth/dirvote.h | 2 ++ src/or/dirvote_common.c | 24 ------------------------ src/or/dirvote_common.h | 3 --- src/test/test_dir_common.c | 6 +++--- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index 683cfdfcac..dc978f26e9 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -94,6 +94,30 @@ static void dirvote_clear_votes(int all_votes); static int dirvote_compute_consensuses(void); static int dirvote_publish_consensus(void); +/* ===== + * Certificate functions + * ===== */ + +/** Allocate and return a new authority_cert_t with the same contents as + * cert. */ +STATIC authority_cert_t * +authority_cert_dup(authority_cert_t *cert) +{ + authority_cert_t *out = tor_malloc(sizeof(authority_cert_t)); + tor_assert(cert); + + memcpy(out, cert, sizeof(authority_cert_t)); + /* Now copy pointed-to things. */ + out->cache_info.signed_descriptor_body = + tor_strndup(cert->cache_info.signed_descriptor_body, + cert->cache_info.signed_descriptor_len); + out->cache_info.saved_location = SAVED_NOWHERE; + out->identity_key = crypto_pk_dup_key(cert->identity_key); + out->signing_key = crypto_pk_dup_key(cert->signing_key); + + return out; +} + /* ===== * Voting * =====*/ @@ -4472,7 +4496,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, v3_out->voters = smartlist_new(); smartlist_add(v3_out->voters, voter); - v3_out->cert = dirvote_authority_cert_dup(cert); + v3_out->cert = authority_cert_dup(cert); v3_out->routerstatus_list = routerstatuses; /* Note: networkstatus_digest is unset; it won't get set until we actually * format the vote. */ diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index 59cfd6b999..2c3b1a1cf0 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -202,6 +202,8 @@ vote_microdesc_hash_t *dirvote_format_all_microdesc_vote_lines( */ #ifdef DIRVOTE_PRIVATE +/* Cert manipulation */ +STATIC authority_cert_t *authority_cert_dup(authority_cert_t *cert); STATIC int32_t dirvote_get_intermediate_param_value( const smartlist_t *param_list, const char *keyword, diff --git a/src/or/dirvote_common.c b/src/or/dirvote_common.c index 9d2c867c83..a28a441d64 100644 --- a/src/or/dirvote_common.c +++ b/src/or/dirvote_common.c @@ -193,27 +193,3 @@ dirvote_get_voter_sig_by_alg(const networkstatus_voter_info_t *voter, return NULL; } -/* ===== - * Certificate functions - * ===== */ - -/** Allocate and return a new authority_cert_t with the same contents as - * cert. */ -authority_cert_t * -dirvote_authority_cert_dup(authority_cert_t *cert) -{ - authority_cert_t *out = tor_malloc(sizeof(authority_cert_t)); - tor_assert(cert); - - memcpy(out, cert, sizeof(authority_cert_t)); - /* Now copy pointed-to things. */ - out->cache_info.signed_descriptor_body = - tor_strndup(cert->cache_info.signed_descriptor_body, - cert->cache_info.signed_descriptor_len); - out->cache_info.saved_location = SAVED_NOWHERE; - out->identity_key = crypto_pk_dup_key(cert->identity_key); - out->signing_key = crypto_pk_dup_key(cert->signing_key); - - return out; -} - diff --git a/src/or/dirvote_common.h b/src/or/dirvote_common.h index 07e6259377..857b8497ee 100644 --- a/src/or/dirvote_common.h +++ b/src/or/dirvote_common.h @@ -62,8 +62,5 @@ document_signature_t *dirvote_get_voter_sig_by_alg( const networkstatus_voter_info_t *voter, digest_algorithm_t alg); -/* Cert manipulation */ -authority_cert_t *dirvote_authority_cert_dup(authority_cert_t *cert); - #endif /* TOR_DIRVOTE_COMMON_H */ diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c index 8c6d99ccec..02d3295ca6 100644 --- a/src/test/test_dir_common.c +++ b/src/test/test_dir_common.c @@ -307,7 +307,7 @@ dir_common_construct_vote_1(networkstatus_t **vote, authority_cert_t *cert, * Set up a vote; generate it; try to parse it. */ smartlist_add((*vote)->voters, voter); - (*vote)->cert = dirvote_authority_cert_dup(cert); + (*vote)->cert = authority_cert_dup(cert); smartlist_split_string((*vote)->net_params, "circuitwindow=101 foo=990", NULL, 0, 0); *n_vrs = 0; @@ -356,7 +356,7 @@ dir_common_construct_vote_2(networkstatus_t **vote, authority_cert_t *cert, * Set up a vote; generate it; try to parse it. */ smartlist_add((*vote)->voters, voter); - (*vote)->cert = dirvote_authority_cert_dup(cert); + (*vote)->cert = authority_cert_dup(cert); if (! (*vote)->net_params) (*vote)->net_params = smartlist_new(); smartlist_split_string((*vote)->net_params, @@ -407,7 +407,7 @@ dir_common_construct_vote_3(networkstatus_t **vote, authority_cert_t *cert, * Set up a vote; generate it; try to parse it. */ smartlist_add((*vote)->voters, voter); - (*vote)->cert = dirvote_authority_cert_dup(cert); + (*vote)->cert = authority_cert_dup(cert); smartlist_split_string((*vote)->net_params, "circuitwindow=80 foo=660", NULL, 0, 0); /* add routerstatuses */ From d8509b450a1de815399a42b5df8c6b25789429c7 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 1 May 2018 10:15:28 -0400 Subject: [PATCH 20/20] vote: Return error when adding vote/signature if no dirauth module Commit 0f3b765b3c8ba6f4f105440861e87ecaf4ea4323 added tor_assert_nonfatal_unreached() to dirvote_add_vote() and dirvote_add_signatures() when the dirauth module is disabled. However, they need to return a value. Furthermore, the dirvote_add_vote() needs to set the msg_out and status_out so it can be sent back. Else, uninitialized values would be used. Signed-off-by: David Goulet --- src/or/dirauth/dirvote.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index 2c3b1a1cf0..f69e872c8e 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -152,11 +152,14 @@ static inline struct pending_vote_t * dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) { (void) vote_body; - (void) msg_out; - (void) status_out; /* If the dirauth module is disabled, this should NEVER be called else we * failed to safeguard the dirauth module. */ tor_assert_nonfatal_unreached(); + + /* We need to send out an error code. */ + *status_out = 400; + *msg_out = "No directory authority support"; + return NULL; } static inline int @@ -169,6 +172,7 @@ dirvote_add_signatures(const char *detached_signatures_body, const char *source, /* If the dirauth module is disabled, this should NEVER be called else we * failed to safeguard the dirauth module. */ tor_assert_nonfatal_unreached(); + return 0; } #endif /* HAVE_MODULE_DIRAUTH */