mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-24 14:51:11 +01:00
Merge remote-tracking branch 'dgoulet/ticket25610_034_01-squashed'
This commit is contained in:
commit
d018bf199c
37 changed files with 1612 additions and 1313 deletions
|
@ -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
|
||||
|
|
25
configure.ac
25
configure.ac
|
@ -230,6 +230,31 @@ if test "x$enable_android" = "xyes"; then
|
|||
|
||||
fi
|
||||
|
||||
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],
|
||||
[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 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.)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "shared_random.h"
|
||||
#include "shared_random_common.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pwd.h>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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,74 +84,27 @@
|
|||
* 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.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/* 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))
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
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. */
|
||||
/* Storing signatures and votes functions */
|
||||
struct pending_vote_t * dirvote_add_vote(const char *vote_body,
|
||||
const char **msg_out,
|
||||
int *status_out);
|
||||
|
@ -161,15 +112,82 @@ int dirvote_add_signatures(const char *detached_signatures_body,
|
|||
const char *source,
|
||||
const char **msg_out);
|
||||
|
||||
#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)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
dirvote_parse_sr_commits(networkstatus_t *ns, smartlist_t *tokens)
|
||||
{
|
||||
(void) ns;
|
||||
(void) tokens;
|
||||
}
|
||||
|
||||
static inline void
|
||||
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;
|
||||
}
|
||||
|
||||
static inline struct pending_vote_t *
|
||||
dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
|
||||
{
|
||||
(void) vote_body;
|
||||
/* 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
|
||||
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();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_MODULE_DIRAUTH */
|
||||
|
||||
void dirvote_recalculate_timing(const or_options_t *options, time_t now);
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* API used _only_ by the dirauth subsystem.
|
||||
*/
|
||||
|
||||
void set_routerstatus_from_routerinfo(routerstatus_t *rs,
|
||||
node_t *node,
|
||||
routerinfo_t *ri, time_t now,
|
||||
|
@ -178,26 +196,18 @@ 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);
|
||||
|
||||
/*
|
||||
* Exposed functions for unit tests.
|
||||
*/
|
||||
#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,
|
||||
|
@ -212,6 +222,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) */
|
|
@ -91,14 +91,17 @@
|
|||
#include "shared_random.h"
|
||||
#include "config.h"
|
||||
#include "confparse.h"
|
||||
#include "dirvote.h"
|
||||
#include "dirvote_common.h"
|
||||
#include "networkstatus.h"
|
||||
#include "routerkeys.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "shared_random_state.h"
|
||||
#include "shared_random_common.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";
|
||||
|
@ -498,20 +501,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 <b>srv</b> string
|
||||
* representation formatted for a networkstatus document using the
|
||||
* <b>key</b> as the start of the line. This doesn't return NULL. */
|
||||
|
@ -874,27 +863,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)
|
||||
|
@ -1036,55 +1004,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.
|
||||
*
|
||||
|
@ -1352,84 +1271,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
|
|
@ -101,21 +101,48 @@ 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);
|
||||
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 +155,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 */
|
|
@ -14,10 +14,13 @@
|
|||
#include "shared_random.h"
|
||||
#include "config.h"
|
||||
#include "confparse.h"
|
||||
#include "dirvote.h"
|
||||
#include "dirvote_common.h"
|
||||
#include "networkstatus.h"
|
||||
#include "router.h"
|
||||
#include "shared_random_state.h"
|
||||
#include "shared_random_common.h"
|
||||
|
||||
#include "dirauth/dirvote.h"
|
||||
|
||||
/* Default filename of the shared random state on disk. */
|
||||
static const char default_fname[] = "sr-state";
|
||||
|
@ -53,10 +56,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,
|
||||
|
@ -115,81 +114,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 <b>now</b>, 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 <b>now</b>.
|
||||
* We expire the state file in the beginning of the next protocol run. */
|
||||
STATIC time_t
|
|
@ -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);
|
|
@ -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
|
||||
|
@ -4437,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;
|
||||
|
|
575
src/or/dirserv.c
575
src/or/dirserv.c
|
@ -18,7 +18,7 @@
|
|||
#include "control.h"
|
||||
#include "directory.h"
|
||||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
#include "dirvote_common.h"
|
||||
#include "hibernate.h"
|
||||
#include "keypin.h"
|
||||
#include "main.h"
|
||||
|
@ -34,6 +34,8 @@
|
|||
#include "routerset.h"
|
||||
#include "torcert.h"
|
||||
|
||||
#include "dirauth/dirvote.h"
|
||||
|
||||
/**
|
||||
* \file dirserv.c
|
||||
* \brief Directory server core implementation. Manages directory
|
||||
|
@ -74,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,
|
||||
|
@ -87,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,
|
||||
|
@ -921,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
|
||||
|
@ -1056,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 <b>ri</b>'s descriptor is "active" -- running, valid,
|
||||
* not hibernating, having observed bw greater 0, and not too old. Else
|
||||
* return 0.
|
||||
|
@ -1467,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,
|
||||
|
@ -1474,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;
|
||||
|
@ -1705,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) {
|
||||
|
@ -1737,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)
|
||||
{
|
||||
|
@ -1769,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
|
||||
|
@ -1886,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 <b>rs</b> into a newly
|
||||
* allocated character buffer. Use the same format as in network-status
|
||||
* documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
|
||||
|
@ -2094,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 <b>routers</b>, 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 <b>routers</b> 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 <b>ri</b> and from other authority
|
||||
* functions and store it in <b>rs</b>. <b>rs</b> is zeroed out before it is
|
||||
* set.
|
||||
|
@ -2345,25 +2131,6 @@ dirserv_set_routerstatus_testing(routerstatus_t *rs)
|
|||
}
|
||||
}
|
||||
|
||||
/** Routerstatus <b>rs</b> 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 <b>guard_id</b>
|
||||
* is <b>guardfraction_percentage</b>. See if we have a vote routerstatus for
|
||||
* this guard in <b>vote_routerstatuses</b>, and if we do, register the
|
||||
|
@ -2857,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 = 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
|
||||
|
|
|
@ -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,
|
||||
|
|
195
src/or/dirvote_common.c
Normal file
195
src/or/dirvote_common.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/* 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 *<b>timing_out</b> 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 <b>interval</b> (in
|
||||
* seconds) after <b>now</b>, plus <b>offset</b>. 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 <b>now</b>, 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 <b>voter</b> using the algorithm
|
||||
* <b>alg</b>, or NULL if none is found. */
|
||||
document_signature_t *
|
||||
dirvote_get_voter_sig_by_alg(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;
|
||||
}
|
||||
|
66
src/or/dirvote_common.h
Normal file
66
src/or/dirvote_common.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* 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 *dirvote_get_voter_sig_by_alg(
|
||||
const networkstatus_voter_info_t *voter,
|
||||
digest_algorithm_t alg);
|
||||
|
||||
#endif /* TOR_DIRVOTE_COMMON_H */
|
||||
|
|
@ -28,8 +28,8 @@
|
|||
#include "rendservice.h"
|
||||
#include "routerset.h"
|
||||
#include "router.h"
|
||||
#include "shared_random.h"
|
||||
#include "shared_random_state.h"
|
||||
#include "shared_random_common.h"
|
||||
#include "dirauth/shared_random_state.h"
|
||||
|
||||
/* Trunnel */
|
||||
#include "ed25519_cert.h"
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "router.h"
|
||||
#include "routerkeys.h"
|
||||
#include "routerlist.h"
|
||||
#include "shared_random_state.h"
|
||||
#include "shared_random_common.h"
|
||||
#include "statefile.h"
|
||||
|
||||
#include "hs_circuit.h"
|
||||
|
|
|
@ -41,10 +41,9 @@ 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/dirvote_common.c \
|
||||
src/or/dns.c \
|
||||
src/or/dnsserv.c \
|
||||
src/or/dos.c \
|
||||
|
@ -76,8 +75,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 \
|
||||
|
@ -107,6 +104,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 \
|
||||
|
@ -114,8 +112,25 @@ 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. 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.
|
||||
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
|
||||
|
@ -185,10 +200,9 @@ 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/dirvote_common.h \
|
||||
src/or/dns.h \
|
||||
src/or/dns_structs.h \
|
||||
src/or/dnsserv.h \
|
||||
|
@ -225,8 +239,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 \
|
||||
|
@ -254,11 +266,22 @@ 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 \
|
||||
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 += \
|
||||
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
|
||||
|
||||
|
|
|
@ -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 <event2/event.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
|
||||
|
|
|
@ -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;
|
||||
|
@ -365,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);
|
||||
|
@ -2641,6 +2640,25 @@ networkstatus_check_required_protocols(const networkstatus_t *ns,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Release all storage held in <b>s</b>. */
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
@ -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,15 @@
|
|||
#include "entrynodes.h"
|
||||
#include "torcert.h"
|
||||
#include "sandbox.h"
|
||||
#include "shared_random.h"
|
||||
#include "shared_random_common.h"
|
||||
#include "dirvote_common.h"
|
||||
#include "dirauth/shared_random.h"
|
||||
|
||||
#undef log
|
||||
#include <math.h>
|
||||
|
||||
#include "dirauth/dirvote.h"
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** List of tokens recognized in router descriptors */
|
||||
|
@ -3282,60 +3285,6 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method)
|
|||
return valid;
|
||||
}
|
||||
|
||||
/** Parse and extract all SR commits from <b>tokens</b> and place them in
|
||||
* <b>ns</b>. */
|
||||
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 <b>srv_type</b> is in
|
||||
* <b>tokens</b>. If there is, parse it and set it to <b>srv_out</b>. Return
|
||||
* -1 on failure, 0 on success. The resulting srv is allocated on the heap and
|
||||
|
@ -3773,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) {
|
||||
|
@ -3969,7 +3912,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 "
|
||||
|
|
259
src/or/shared_random_common.c
Normal file
259
src/or/shared_random_common.c
Normal file
|
@ -0,0 +1,259 @@
|
|||
/* 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 "dirvote_common.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 <b>now</b>, 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();
|
||||
}
|
||||
|
47
src/or/shared_random_common.h
Normal file
47
src/or/shared_random_common.h
Normal file
|
@ -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 */
|
||||
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#include "test.h"
|
||||
#include "container.h"
|
||||
#include "or.h"
|
||||
#include "dirvote.h"
|
||||
#include "dirauth/dirvote.h"
|
||||
#include "dirvote_common.h"
|
||||
#include "nodelist.h"
|
||||
#include "routerlist.h"
|
||||
#include "test_dir_common.h"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
#include "or.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "dirvote.h"
|
||||
#define DIRVOTE_PRIVATE
|
||||
#include "dirauth/dirvote.h"
|
||||
#include "microdesc.h"
|
||||
#include "networkstatus.h"
|
||||
#include "routerlist.h"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -9,13 +9,14 @@
|
|||
#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"
|
||||
#include "routerparse.h"
|
||||
#include "shared_random_common.h"
|
||||
#include "networkstatus.h"
|
||||
#include "log_test_helpers.h"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue