aboutsummaryrefslogtreecommitdiff
path: root/src/feature/dirauth
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/dirauth')
-rw-r--r--src/feature/dirauth/authmode.h6
-rw-r--r--src/feature/dirauth/bridgeauth.c55
-rw-r--r--src/feature/dirauth/bridgeauth.h12
-rw-r--r--src/feature/dirauth/bwauth.c61
-rw-r--r--src/feature/dirauth/bwauth.h6
-rw-r--r--src/feature/dirauth/dirauth_periodic.c161
-rw-r--r--src/feature/dirauth/dirauth_periodic.h25
-rw-r--r--src/feature/dirauth/dirauth_sys.c40
-rw-r--r--src/feature/dirauth/dirauth_sys.h12
-rw-r--r--src/feature/dirauth/dirvote.c104
-rw-r--r--src/feature/dirauth/dirvote.h15
-rw-r--r--src/feature/dirauth/dsigs_parse.c2
-rw-r--r--src/feature/dirauth/dsigs_parse.h2
-rw-r--r--src/feature/dirauth/guardfraction.h2
-rw-r--r--src/feature/dirauth/keypin.h18
-rw-r--r--src/feature/dirauth/ns_detached_signatures_st.h2
-rw-r--r--src/feature/dirauth/process_descs.c71
-rw-r--r--src/feature/dirauth/process_descs.h86
-rw-r--r--src/feature/dirauth/reachability.h33
-rw-r--r--src/feature/dirauth/recommend_pkg.h14
-rw-r--r--src/feature/dirauth/shared_random.c12
-rw-r--r--src/feature/dirauth/shared_random.h6
-rw-r--r--src/feature/dirauth/shared_random_state.c64
-rw-r--r--src/feature/dirauth/vote_microdesc_hash_st.h2
-rw-r--r--src/feature/dirauth/voteflags.c108
-rw-r--r--src/feature/dirauth/voteflags.h20
26 files changed, 788 insertions, 151 deletions
diff --git a/src/feature/dirauth/authmode.h b/src/feature/dirauth/authmode.h
index 876a1f947b..48afc3cdb4 100644
--- a/src/feature/dirauth/authmode.h
+++ b/src/feature/dirauth/authmode.h
@@ -29,7 +29,7 @@ authdir_mode_v3(const or_options_t *options)
#define have_module_dirauth() (1)
-#else /* HAVE_MODULE_DIRAUTH */
+#else /* !(defined(HAVE_MODULE_DIRAUTH)) */
#define authdir_mode(options) (((void)(options)),0)
#define authdir_mode_handles_descs(options,purpose) \
@@ -41,6 +41,6 @@ authdir_mode_v3(const or_options_t *options)
#define have_module_dirauth() (0)
-#endif /* HAVE_MODULE_DIRAUTH */
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
-#endif /* TOR_MODE_H */
+#endif /* !defined(TOR_DIRAUTH_MODE_H) */
diff --git a/src/feature/dirauth/bridgeauth.c b/src/feature/dirauth/bridgeauth.c
new file mode 100644
index 0000000000..4aaefc7a6d
--- /dev/null
+++ b/src/feature/dirauth/bridgeauth.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "core/or/or.h"
+#include "feature/dirauth/bridgeauth.h"
+#include "feature/dirauth/voteflags.h"
+#include "feature/nodelist/networkstatus.h"
+#include "feature/relay/router.h"
+#include "app/config/config.h"
+
+#include "feature/nodelist/routerinfo_st.h"
+
+/** Write out router status entries for all our bridge descriptors. Here, we
+ * also mark routers as running. */
+void
+bridgeauth_dump_bridge_status_to_file(time_t now)
+{
+ char *status;
+ char *fname = NULL;
+ char *thresholds = NULL;
+ char *published_thresholds_and_status = NULL;
+ char published[ISO_TIME_LEN+1];
+ const routerinfo_t *me = router_get_my_routerinfo();
+ char fingerprint[FINGERPRINT_LEN+1];
+ char *fingerprint_line = NULL;
+
+ dirserv_set_bridges_running(now);
+ status = networkstatus_getinfo_by_purpose("bridge", now);
+
+ if (me && crypto_pk_get_fingerprint(me->identity_pkey,
+ fingerprint, 0) >= 0) {
+ tor_asprintf(&fingerprint_line, "fingerprint %s\n", fingerprint);
+ } else {
+ log_warn(LD_BUG, "Error computing fingerprint for bridge status.");
+ }
+ format_iso_time(published, now);
+ dirserv_compute_bridge_flag_thresholds();
+ thresholds = dirserv_get_flag_thresholds_line();
+ tor_asprintf(&published_thresholds_and_status,
+ "published %s\nflag-thresholds %s\n%s%s",
+ published, thresholds, fingerprint_line ? fingerprint_line : "",
+ status);
+ fname = get_datadir_fname("networkstatus-bridges");
+ if (write_str_to_file(fname,published_thresholds_and_status,0)<0) {
+ log_warn(LD_DIRSERV, "Unable to write networkstatus-bridges file.");
+ }
+ tor_free(thresholds);
+ tor_free(published_thresholds_and_status);
+ tor_free(fname);
+ tor_free(status);
+ tor_free(fingerprint_line);
+}
diff --git a/src/feature/dirauth/bridgeauth.h b/src/feature/dirauth/bridgeauth.h
new file mode 100644
index 0000000000..4905e9c3ee
--- /dev/null
+++ b/src/feature/dirauth/bridgeauth.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_DIRAUTH_BRIDGEAUTH_H
+#define TOR_DIRAUTH_BRIDGEAUTH_H
+
+void bridgeauth_dump_bridge_status_to_file(time_t now);
+
+#endif /* !defined(TOR_DIRAUTH_BRIDGEAUTH_H) */
diff --git a/src/feature/dirauth/bwauth.c b/src/feature/dirauth/bwauth.c
index 12f9399e9f..e60c8b86bd 100644
--- a/src/feature/dirauth/bwauth.c
+++ b/src/feature/dirauth/bwauth.c
@@ -20,6 +20,7 @@
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/vote_routerstatus_st.h"
+#include "lib/crypt_ops/crypto_format.h"
#include "lib/encoding/keyval.h"
/** Total number of routers with measured bandwidth; this is set by
@@ -198,14 +199,38 @@ dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri)
}
/**
- * Read the measured bandwidth list file, apply it to the list of
- * vote_routerstatus_t and store all the headers in <b>bw_file_headers</b>.
+ * Read the measured bandwidth list <b>from_file</b>:
+ * - store all the headers in <b>bw_file_headers</b>,
+ * - apply bandwidth lines to the list of vote_routerstatus_t in
+ * <b>routerstatuses</b>,
+ * - cache bandwidth lines for dirserv_get_bandwidth_for_router(),
+ * - expire old entries in the measured bandwidth cache, and
+ * - store the DIGEST_SHA256 of the contents of the file in <b>digest_out</b>.
+ *
* Returns -1 on error, 0 otherwise.
+ *
+ * If the file can't be read, or is empty:
+ * - <b>bw_file_headers</b> is empty,
+ * - <b>routerstatuses</b> is not modified,
+ * - the measured bandwidth cache is not modified, and
+ * - <b>digest_out</b> is the zero-byte digest.
+ *
+ * Otherwise, if there is an error later in the file:
+ * - <b>bw_file_headers</b> contains all the headers up to the error,
+ * - <b>routerstatuses</b> is updated with all the relay lines up to the error,
+ * - the measured bandwidth cache is updated with all the relay lines up to
+ * the error,
+ * - if the timestamp is valid and recent, old entries in the measured
+ * bandwidth cache are expired, and
+ * - <b>digest_out</b> is the digest up to the first read error (if any).
+ * The digest is taken over all the readable file contents, even if the
+ * file is outdated or unparseable.
*/
int
dirserv_read_measured_bandwidths(const char *from_file,
smartlist_t *routerstatuses,
- smartlist_t *bw_file_headers)
+ smartlist_t *bw_file_headers,
+ uint8_t *digest_out)
{
FILE *fp = tor_fopen_cloexec(from_file, "r");
int applied_lines = 0;
@@ -219,8 +244,7 @@ dirserv_read_measured_bandwidths(const char *from_file,
int rv = -1;
char *line = NULL;
size_t n = 0;
-
- /* Initialise line, so that we can't possibly run off the end. */
+ crypto_digest_t *digest = crypto_digest256_new(DIGEST_SHA256);
if (fp == NULL) {
log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s",
@@ -228,16 +252,18 @@ dirserv_read_measured_bandwidths(const char *from_file,
goto err;
}
- /* If fgets fails, line is either unmodified, or indeterminate. */
if (tor_getline(&line,&n,fp) <= 0) {
log_warn(LD_DIRSERV, "Empty bandwidth file");
goto err;
}
+ /* If the line could be gotten, add it to the digest */
+ crypto_digest_add_bytes(digest, (const char *) line, strlen(line));
if (!strlen(line) || line[strlen(line)-1] != '\n') {
log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s",
escaped(line));
- goto err;
+ /* Continue adding lines to the digest. */
+ goto continue_digest;
}
line[strlen(line)-1] = '\0';
@@ -245,14 +271,14 @@ dirserv_read_measured_bandwidths(const char *from_file,
if (!ok) {
log_warn(LD_DIRSERV, "Non-integer time in bandwidth file: %s",
escaped(line));
- goto err;
+ goto continue_digest;
}
- now = time(NULL);
+ now = approx_time();
if ((now - file_time) > MAX_MEASUREMENT_AGE) {
log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u",
(unsigned)(time(NULL) - file_time));
- goto err;
+ goto continue_digest;
}
/* If timestamp was correct and bw_file_headers is not NULL,
@@ -267,6 +293,7 @@ dirserv_read_measured_bandwidths(const char *from_file,
while (!feof(fp)) {
measured_bw_line_t parsed_line;
if (tor_getline(&line, &n, fp) >= 0) {
+ crypto_digest_add_bytes(digest, (const char *) line, strlen(line));
if (measured_bw_line_parse(&parsed_line, line,
line_is_after_headers) != -1) {
/* This condition will be true when the first complete valid bw line
@@ -305,6 +332,14 @@ dirserv_read_measured_bandwidths(const char *from_file,
"Applied %d measurements.", applied_lines);
rv = 0;
+ continue_digest:
+ /* Continue parsing lines to return the digest of the Bandwidth File. */
+ while (!feof(fp)) {
+ if (tor_getline(&line, &n, fp) >= 0) {
+ crypto_digest_add_bytes(digest, (const char *) line, strlen(line));
+ }
+ }
+
err:
if (line) {
// we need to raw_free this buffer because we got it from tor_getdelim()
@@ -312,6 +347,9 @@ dirserv_read_measured_bandwidths(const char *from_file,
}
if (fp)
fclose(fp);
+ if (digest_out)
+ crypto_digest_get_digest(digest, (char *) digest_out, DIGEST256_LEN);
+ crypto_digest_free(digest);
return rv;
}
@@ -327,6 +365,9 @@ dirserv_read_measured_bandwidths(const char *from_file,
* the header block yet. If we encounter an incomplete bw line, return -1 but
* don't warn since there could be additional header lines coming. If we
* encounter a proper bw line, return 0 (and we got past the headers).
+ *
+ * If the line contains "vote=0", stop parsing it, and return -1, so that the
+ * line is ignored during voting.
*/
STATIC int
measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line,
diff --git a/src/feature/dirauth/bwauth.h b/src/feature/dirauth/bwauth.h
index 4507728458..81c8affbd7 100644
--- a/src/feature/dirauth/bwauth.h
+++ b/src/feature/dirauth/bwauth.h
@@ -21,8 +21,8 @@
int dirserv_read_measured_bandwidths(const char *from_file,
smartlist_t *routerstatuses,
- smartlist_t *bw_file_headers);
-
+ smartlist_t *bw_file_headers,
+ uint8_t *digest_out);
int dirserv_query_measured_bw_cache_kb(const char *node_id,
long *bw_out,
time_t *as_of_out);
@@ -55,4 +55,4 @@ STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
STATIC void dirserv_expire_measured_bw_cache(time_t now);
#endif /* defined(BWAUTH_PRIVATE) */
-#endif
+#endif /* !defined(TOR_BWAUTH_H) */
diff --git a/src/feature/dirauth/dirauth_periodic.c b/src/feature/dirauth/dirauth_periodic.c
new file mode 100644
index 0000000000..02727d61b4
--- /dev/null
+++ b/src/feature/dirauth/dirauth_periodic.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "core/or/or.h"
+
+#include "app/config/or_options_st.h"
+#include "core/mainloop/netstatus.h"
+#include "feature/dirauth/reachability.h"
+#include "feature/stats/rephist.h"
+
+#include "feature/dirauth/bridgeauth.h"
+#include "feature/dirauth/dirvote.h"
+#include "feature/dirauth/dirauth_periodic.h"
+#include "feature/dirauth/authmode.h"
+
+#include "core/mainloop/periodic.h"
+
+#define DECLARE_EVENT(name, roles, flags) \
+ static periodic_event_item_t name ## _event = \
+ PERIODIC_EVENT(name, \
+ PERIODIC_EVENT_ROLE_##roles, \
+ flags)
+
+#define FL(name) (PERIODIC_EVENT_FLAG_##name)
+
+/**
+ * Periodic callback: if we're an authority, check on our authority
+ * certificate (the one that authenticates our authority signing key).
+ */
+static int
+check_authority_cert_callback(time_t now, const or_options_t *options)
+{
+ (void)now;
+ (void)options;
+ /* 1e. Periodically, if we're a v3 authority, we check whether our cert is
+ * close to expiring and warn the admin if it is. */
+ v3_authority_check_key_expiry();
+#define CHECK_V3_CERTIFICATE_INTERVAL (5*60)
+ return CHECK_V3_CERTIFICATE_INTERVAL;
+}
+
+DECLARE_EVENT(check_authority_cert, DIRAUTH, 0);
+
+/**
+ * Scheduled callback: Run directory-authority voting functionality.
+ *
+ * The schedule is a bit complicated here, so dirvote_act() manages the
+ * schedule itself.
+ **/
+static int
+dirvote_callback(time_t now, const or_options_t *options)
+{
+ if (!authdir_mode_v3(options)) {
+ tor_assert_nonfatal_unreached();
+ return 3600;
+ }
+
+ time_t next = dirvote_act(options, now);
+ if (BUG(next == TIME_MAX)) {
+ /* This shouldn't be returned unless we called dirvote_act() without
+ * being an authority. If it happens, maybe our configuration will
+ * fix itself in an hour or so? */
+ return 3600;
+ }
+ return safe_timer_diff(now, next);
+}
+
+DECLARE_EVENT(dirvote, DIRAUTH, FL(NEED_NET));
+
+/** Reschedule the directory-authority voting event. Run this whenever the
+ * schedule has changed. */
+void
+reschedule_dirvote(const or_options_t *options)
+{
+ if (authdir_mode_v3(options)) {
+ periodic_event_reschedule(&dirvote_event);
+ }
+}
+
+/**
+ * Periodic callback: if we're an authority, record our measured stability
+ * information from rephist in an mtbf file.
+ */
+static int
+save_stability_callback(time_t now, const or_options_t *options)
+{
+ if (authdir_mode_tests_reachability(options)) {
+ if (rep_hist_record_mtbf_data(now, 1)<0) {
+ log_warn(LD_GENERAL, "Couldn't store mtbf data.");
+ }
+ }
+#define SAVE_STABILITY_INTERVAL (30*60)
+ return SAVE_STABILITY_INTERVAL;
+}
+
+DECLARE_EVENT(save_stability, AUTHORITIES, 0);
+
+/**
+ * Periodic callback: if we're an authority, make sure we test
+ * the routers on the network for reachability.
+ */
+static int
+launch_reachability_tests_callback(time_t now, const or_options_t *options)
+{
+ if (authdir_mode_tests_reachability(options) &&
+ !net_is_disabled()) {
+ /* try to determine reachability of the other Tor relays */
+ dirserv_test_reachability(now);
+ }
+ return REACHABILITY_TEST_INTERVAL;
+}
+
+DECLARE_EVENT(launch_reachability_tests, AUTHORITIES, FL(NEED_NET));
+
+/**
+ * Periodic callback: if we're an authority, discount the stability
+ * information (and other rephist information) that's older.
+ */
+static int
+downrate_stability_callback(time_t now, const or_options_t *options)
+{
+ (void)options;
+ /* 1d. Periodically, we discount older stability information so that new
+ * stability info counts more, and save the stability information to disk as
+ * appropriate. */
+ time_t next = rep_hist_downrate_old_runs(now);
+ return safe_timer_diff(now, next);
+}
+
+DECLARE_EVENT(downrate_stability, AUTHORITIES, 0);
+
+/**
+ * Periodic callback: if we're the bridge authority, write a networkstatus
+ * file to disk.
+ */
+static int
+write_bridge_ns_callback(time_t now, const or_options_t *options)
+{
+ if (options->BridgeAuthoritativeDir) {
+ bridgeauth_dump_bridge_status_to_file(now);
+#define BRIDGE_STATUSFILE_INTERVAL (30*60)
+ return BRIDGE_STATUSFILE_INTERVAL;
+ }
+ return PERIODIC_EVENT_NO_UPDATE;
+}
+
+DECLARE_EVENT(write_bridge_ns, BRIDGEAUTH, 0);
+
+void
+dirauth_register_periodic_events(void)
+{
+ periodic_events_register(&downrate_stability_event);
+ periodic_events_register(&launch_reachability_tests_event);
+ periodic_events_register(&save_stability_event);
+ periodic_events_register(&check_authority_cert_event);
+ periodic_events_register(&dirvote_event);
+ periodic_events_register(&write_bridge_ns_event);
+}
diff --git a/src/feature/dirauth/dirauth_periodic.h b/src/feature/dirauth/dirauth_periodic.h
new file mode 100644
index 0000000000..1124fae952
--- /dev/null
+++ b/src/feature/dirauth/dirauth_periodic.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef DIRVOTE_PERIODIC_H
+#define DIRVOTE_PERIODIC_H
+
+#ifdef HAVE_MODULE_DIRAUTH
+
+void dirauth_register_periodic_events(void);
+void reschedule_dirvote(const or_options_t *options);
+
+#else /* !(defined(HAVE_MODULE_DIRAUTH)) */
+
+static inline void
+reschedule_dirvote(const or_options_t *options)
+{
+ (void)options;
+}
+
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
+
+#endif /* !defined(DIRVOTE_PERIODIC_H) */
diff --git a/src/feature/dirauth/dirauth_sys.c b/src/feature/dirauth/dirauth_sys.c
new file mode 100644
index 0000000000..e38d391300
--- /dev/null
+++ b/src/feature/dirauth/dirauth_sys.c
@@ -0,0 +1,40 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "core/or/or.h"
+
+#include "feature/dirauth/bwauth.h"
+#include "feature/dirauth/dirauth_sys.h"
+#include "feature/dirauth/dirvote.h"
+#include "feature/dirauth/dirauth_periodic.h"
+#include "feature/dirauth/keypin.h"
+#include "feature/dirauth/process_descs.h"
+
+#include "lib/subsys/subsys.h"
+
+static int
+subsys_dirauth_initialize(void)
+{
+ dirauth_register_periodic_events();
+ return 0;
+}
+
+static void
+subsys_dirauth_shutdown(void)
+{
+ dirserv_free_fingerprint_list();
+ dirvote_free_all();
+ dirserv_clear_measured_bw_cache();
+ keypin_close_journal();
+}
+
+const struct subsys_fns_t sys_dirauth = {
+ .name = "dirauth",
+ .supported = true,
+ .level = 70,
+ .initialize = subsys_dirauth_initialize,
+ .shutdown = subsys_dirauth_shutdown,
+};
diff --git a/src/feature/dirauth/dirauth_sys.h b/src/feature/dirauth/dirauth_sys.h
new file mode 100644
index 0000000000..4e9b6a2ab4
--- /dev/null
+++ b/src/feature/dirauth/dirauth_sys.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef DIRAUTH_SYS_H
+#define DIRAUTH_SYS_H
+
+extern const struct subsys_fns_t sys_dirauth;
+
+#endif /* !defined(DIRAUTH_SYS_H) */
diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index af8b3dc207..cdbdf5a216 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -28,6 +28,7 @@
#include "feature/nodelist/fmt_routerstatus.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/nodefamily.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/relay/router.h"
@@ -60,6 +61,9 @@
#include "lib/encoding/confline.h"
#include "lib/crypt_ops/crypto_format.h"
+/* Algorithm to use for the bandwidth file digest. */
+#define DIGEST_ALG_BW_FILE DIGEST_SHA256
+
/**
* \file dirvote.c
* \brief Functions to compute directory consensus, and schedule voting.
@@ -268,6 +272,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
char *flag_thresholds = dirserv_get_flag_thresholds_line();
char *params;
char *bw_headers_line = NULL;
+ char *bw_file_digest = NULL;
authority_cert_t *cert = v3_ns->cert;
char *methods =
make_consensus_method_list(MIN_SUPPORTED_CONSENSUS_METHOD,
@@ -307,6 +312,27 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
tor_free(bw_file_headers);
}
+ /* Create bandwidth-file-digest if applicable.
+ * v3_ns->b64_digest_bw_file will contain the digest when V3BandwidthsFile
+ * is configured and the bandwidth file could be read, even if it was not
+ * parseable.
+ */
+ if (!tor_digest256_is_zero((const char *)v3_ns->bw_file_digest256)) {
+ /* Encode the digest. */
+ char b64_digest_bw_file[BASE64_DIGEST256_LEN+1] = {0};
+ digest256_to_base64(b64_digest_bw_file,
+ (const char *)v3_ns->bw_file_digest256);
+ /* "bandwidth-file-digest" 1*(SP algorithm "=" digest) NL */
+ char *digest_algo_b64_digest_bw_file = NULL;
+ tor_asprintf(&digest_algo_b64_digest_bw_file, "%s=%s",
+ crypto_digest_algorithm_get_name(DIGEST_ALG_BW_FILE),
+ b64_digest_bw_file);
+ /* No need for tor_strdup(""), format_line_if_present does it. */
+ bw_file_digest = format_line_if_present(
+ "bandwidth-file-digest", digest_algo_b64_digest_bw_file);
+ tor_free(digest_algo_b64_digest_bw_file);
+ }
+
smartlist_add_asprintf(chunks,
"network-status-version 3\n"
"vote-status %s\n"
@@ -323,6 +349,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
"flag-thresholds %s\n"
"params %s\n"
"%s" /* bandwidth file headers */
+ "%s" /* bandwidth file digest */
"dir-source %s %s %s %s %d %d\n"
"contact %s\n"
"%s" /* shared randomness information */
@@ -339,6 +366,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
flag_thresholds,
params,
bw_headers_line ? bw_headers_line : "",
+ bw_file_digest ? bw_file_digest: "",
voter->nickname, fingerprint, voter->address,
fmt_addr32(addr), voter->dir_port, voter->or_port,
voter->contact,
@@ -351,6 +379,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
tor_free(methods);
tor_free(shared_random_vote_str);
tor_free(bw_headers_line);
+ tor_free(bw_file_digest);
if (!tor_digest_is_zero(voter->legacy_id_digest)) {
char fpbuf[HEX_DIGEST_LEN+1];
@@ -412,7 +441,8 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
{
networkstatus_t *v;
- if (!(v = networkstatus_parse_vote_from_string(status, NULL,
+ if (!(v = networkstatus_parse_vote_from_string(status, strlen(status),
+ NULL,
v3_ns->type))) {
log_err(LD_BUG,"Generated a networkstatus %s we couldn't parse: "
"<<%s>>",
@@ -2409,7 +2439,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
{
networkstatus_t *c;
- if (!(c = networkstatus_parse_vote_from_string(result, NULL,
+ if (!(c = networkstatus_parse_vote_from_string(result, strlen(result),
+ NULL,
NS_TYPE_CONSENSUS))) {
log_err(LD_BUG, "Generated a networkstatus consensus we couldn't "
"parse.");
@@ -2567,7 +2598,7 @@ networkstatus_add_detached_signatures(networkstatus_t *target,
return -1;
}
for (alg = DIGEST_SHA1; alg < N_COMMON_DIGEST_ALGORITHMS; ++alg) {
- if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) {
+ if (!fast_mem_is_zero(digests->d[alg], DIGEST256_LEN)) {
if (fast_memeq(target->digests.d[alg], digests->d[alg],
DIGEST256_LEN)) {
++n_matches;
@@ -2763,7 +2794,7 @@ networkstatus_get_detached_signatures(smartlist_t *consensuses)
char d[HEX_DIGEST256_LEN+1];
const char *alg_name =
crypto_digest_algorithm_get_name(alg);
- if (tor_mem_is_zero(ns->digests.d[alg], DIGEST256_LEN))
+ if (fast_mem_is_zero(ns->digests.d[alg], DIGEST256_LEN))
continue;
base16_encode(d, sizeof(d), ns->digests.d[alg], DIGEST256_LEN);
smartlist_add_asprintf(elements, "additional-digest %s %s %s\n",
@@ -3132,7 +3163,8 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
*msg_out = NULL;
again:
- vote = networkstatus_parse_vote_from_string(vote_body, &end_of_vote,
+ vote = networkstatus_parse_vote_from_string(vote_body, strlen(vote_body),
+ &end_of_vote,
NS_TYPE_VOTE);
if (!end_of_vote)
end_of_vote = vote_body + strlen(vote_body);
@@ -3390,7 +3422,9 @@ dirvote_compute_consensuses(void)
flavor_name);
continue;
}
- consensus = networkstatus_parse_vote_from_string(consensus_body, NULL,
+ consensus = networkstatus_parse_vote_from_string(consensus_body,
+ strlen(consensus_body),
+ NULL,
NS_TYPE_CONSENSUS);
if (!consensus) {
log_warn(LD_DIR, "Couldn't parse %s consensus we generated!",
@@ -3529,7 +3563,7 @@ dirvote_add_signatures_to_pending_consensus(
* just in case we break detached signature processing at some point. */
{
networkstatus_t *v = networkstatus_parse_vote_from_string(
- pc->body, NULL,
+ pc->body, strlen(pc->body), NULL,
NS_TYPE_CONSENSUS);
tor_assert(v);
networkstatus_vote_free(v);
@@ -3654,7 +3688,9 @@ dirvote_publish_consensus(void)
continue;
}
- if (networkstatus_set_current_consensus(pending->body, name, 0, NULL))
+ if (networkstatus_set_current_consensus(pending->body,
+ strlen(pending->body),
+ name, 0, NULL))
log_warn(LD_DIR, "Error publishing %s consensus", name);
else
log_notice(LD_DIR, "Published %s consensus", name);
@@ -3791,8 +3827,16 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
smartlist_add_asprintf(chunks, "a %s\n",
fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport));
- if (family)
- smartlist_add_asprintf(chunks, "family %s\n", family);
+ if (family) {
+ if (consensus_method < MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS) {
+ smartlist_add_asprintf(chunks, "family %s\n", family);
+ } else {
+ const uint8_t *id = (const uint8_t *)ri->cache_info.identity_digest;
+ char *canonical_family = nodefamily_canonicalize(family, id, 0);
+ smartlist_add_asprintf(chunks, "family %s\n", canonical_family);
+ tor_free(canonical_family);
+ }
+ }
if (summary && strcmp(summary, "reject 1-65535"))
smartlist_add_asprintf(chunks, "p %s\n", summary);
@@ -3869,8 +3913,7 @@ dirvote_format_microdesc_vote_line(char *out_buf, size_t out_buf_len,
",");
tor_assert(microdesc_consensus_methods);
- if (digest256_to_base64(d64, md->digest)<0)
- goto out;
+ digest256_to_base64(d64, md->digest);
if (tor_snprintf(out_buf, out_buf_len, "m %s sha256=%s\n",
microdesc_consensus_methods, d64)<0)
@@ -3890,7 +3933,10 @@ static const struct consensus_method_range_t {
int high;
} microdesc_consensus_methods[] = {
{MIN_SUPPORTED_CONSENSUS_METHOD, MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC - 1},
- {MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC, MAX_SUPPORTED_CONSENSUS_METHOD},
+ {MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC,
+ MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1},
+ {MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS,
+ MAX_SUPPORTED_CONSENSUS_METHOD},
{-1, -1}
};
@@ -4364,6 +4410,23 @@ clear_status_flags_on_sybil(routerstatus_t *rs)
* forget to add it to this clause. */
}
+/** Space-separated list of all the flags that we will always vote on. */
+const char DIRVOTE_UNIVERSAL_FLAGS[] =
+ "Authority "
+ "Exit "
+ "Fast "
+ "Guard "
+ "HSDir "
+ "Stable "
+ "StaleDesc "
+ "V2Dir "
+ "Valid";
+/** Space-separated list of all flags that we may or may not vote on,
+ * depending on our configuration. */
+const char DIRVOTE_OPTIONAL_FLAGS[] =
+ "BadExit "
+ "Running";
+
/** Return a new networkstatus_t* containing our current opinion. (For v3
* authorities) */
networkstatus_t *
@@ -4388,6 +4451,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
const int vote_on_reachability = running_long_enough_to_decide_unreachable();
smartlist_t *microdescriptors = NULL;
smartlist_t *bw_file_headers = NULL;
+ uint8_t bw_file_digest256[DIGEST256_LEN] = {0};
tor_assert(private_key);
tor_assert(cert);
@@ -4425,7 +4489,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
* set_routerstatus_from_routerinfo() see up-to-date bandwidth info.
*/
if (options->V3BandwidthsFile) {
- dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL);
+ dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL,
+ NULL);
} else {
/*
* No bandwidths file; clear the measured bandwidth cache in case we had
@@ -4479,8 +4544,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
rs = &vrs->status;
- set_routerstatus_from_routerinfo(rs, node, ri, now,
- listbadexits);
+ dirauth_set_routerstatus_from_routerinfo(rs, node, ri, now,
+ listbadexits);
if (ri->cache_info.signing_key_cert) {
memcpy(vrs->ed25519_id,
@@ -4530,7 +4595,9 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/* Only set bw_file_headers when V3BandwidthsFile is configured */
bw_file_headers = smartlist_new();
dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
- routerstatuses, bw_file_headers);
+ routerstatuses, bw_file_headers,
+ bw_file_digest256);
+
} else {
/*
* No bandwidths file; clear the measured bandwidth cache in case we had
@@ -4612,7 +4679,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
v3_out->known_flags = smartlist_new();
smartlist_split_string(v3_out->known_flags,
- "Authority Exit Fast Guard Stable V2Dir Valid HSDir",
+ DIRVOTE_UNIVERSAL_FLAGS,
0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (vote_on_reachability)
smartlist_add_strdup(v3_out->known_flags, "Running");
@@ -4627,6 +4694,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
smartlist_sort_strings(v3_out->net_params);
}
v3_out->bw_file_headers = bw_file_headers;
+ memcpy(v3_out->bw_file_digest256, bw_file_digest256, DIGEST256_LEN);
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
voter->nickname = tor_strdup(options->Nickname);
diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h
index 02d88d19d1..a0cfe0a34c 100644
--- a/src/feature/dirauth/dirvote.h
+++ b/src/feature/dirauth/dirvote.h
@@ -57,7 +57,7 @@
#define MIN_SUPPORTED_CONSENSUS_METHOD 25
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 28
+#define MAX_SUPPORTED_CONSENSUS_METHOD 29
/** Lowest consensus method where authorities vote on required/recommended
* protocols. */
@@ -79,6 +79,12 @@
* addresses. See #23828 and #20916. */
#define MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC 28
+/**
+ * Lowest consensus method where microdescriptor lines are put in canonical
+ * form for improved compressibility and ease of storage. See proposal 298.
+ **/
+#define MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS 29
+
/** Default bandwidth to clip unmeasured bandwidths to using method >=
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
* get confused with the above macros.) */
@@ -92,6 +98,9 @@
/** Maximum size of a line in a vote. */
#define MAX_BW_FILE_HEADERS_LINE_LEN 1024
+extern const char DIRVOTE_UNIVERSAL_FLAGS[];
+extern const char DIRVOTE_OPTIONAL_FLAGS[];
+
/*
* Public API. Used outside of the dirauth subsystem.
*
@@ -119,7 +128,7 @@ struct config_line_t;
char *format_recommended_version_list(const struct config_line_t *line,
int warn);
-#else /* HAVE_MODULE_DIRAUTH */
+#else /* !(defined(HAVE_MODULE_DIRAUTH)) */
static inline time_t
dirvote_act(const or_options_t *options, time_t now)
@@ -184,7 +193,7 @@ dirvote_add_signatures(const char *detached_signatures_body,
return 0;
}
-#endif /* HAVE_MODULE_DIRAUTH */
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
/* Item access */
MOCK_DECL(const char*, dirvote_get_pending_consensus,
diff --git a/src/feature/dirauth/dsigs_parse.c b/src/feature/dirauth/dsigs_parse.c
index d88176fee9..c5c8e18866 100644
--- a/src/feature/dirauth/dsigs_parse.c
+++ b/src/feature/dirauth/dsigs_parse.c
@@ -127,7 +127,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
}
digests = detached_get_digests(sigs, flavor);
tor_assert(digests);
- if (!tor_mem_is_zero(digests->d[alg], digest_length)) {
+ if (!fast_mem_is_zero(digests->d[alg], digest_length)) {
log_warn(LD_DIR, "Multiple digests for %s with %s on detached "
"signatures document", flavor, algname);
continue;
diff --git a/src/feature/dirauth/dsigs_parse.h b/src/feature/dirauth/dsigs_parse.h
index fec51ba488..0cc53072f8 100644
--- a/src/feature/dirauth/dsigs_parse.h
+++ b/src/feature/dirauth/dsigs_parse.h
@@ -19,4 +19,4 @@ 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))
-#endif
+#endif /* !defined(TOR_DSIGS_PARSE_H) */
diff --git a/src/feature/dirauth/guardfraction.h b/src/feature/dirauth/guardfraction.h
index 72404907a4..9f01ded838 100644
--- a/src/feature/dirauth/guardfraction.h
+++ b/src/feature/dirauth/guardfraction.h
@@ -21,4 +21,4 @@ dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str,
int dirserv_read_guardfraction_file(const char *fname,
smartlist_t *vote_routerstatuses);
-#endif
+#endif /* !defined(TOR_GUARDFRACTION_H) */
diff --git a/src/feature/dirauth/keypin.h b/src/feature/dirauth/keypin.h
index 722b6ca5fc..ab2362b3f8 100644
--- a/src/feature/dirauth/keypin.h
+++ b/src/feature/dirauth/keypin.h
@@ -11,10 +11,25 @@ int keypin_check_and_add(const uint8_t *rsa_id_digest,
const int replace_existing_entry);
int keypin_check(const uint8_t *rsa_id_digest,
const uint8_t *ed25519_id_key);
+int keypin_close_journal(void);
+#ifdef HAVE_MODULE_DIRAUTH
int keypin_open_journal(const char *fname);
-int keypin_close_journal(void);
int keypin_load_journal(const char *fname);
+#else
+static inline int
+keypin_open_journal(const char *fname)
+{
+ (void)fname;
+ return 0;
+}
+static inline int
+keypin_load_journal(const char *fname)
+{
+ (void)fname;
+ return 0;
+}
+#endif
void keypin_clear(void);
int keypin_check_lone_rsa(const uint8_t *rsa_id_digest);
@@ -44,4 +59,3 @@ MOCK_DECL(STATIC void, keypin_add_entry_to_map, (keypin_ent_t *ent));
#endif /* defined(KEYPIN_PRIVATE) */
#endif /* !defined(TOR_KEYPIN_H) */
-
diff --git a/src/feature/dirauth/ns_detached_signatures_st.h b/src/feature/dirauth/ns_detached_signatures_st.h
index 0f92be2f0d..61d20b7525 100644
--- a/src/feature/dirauth/ns_detached_signatures_st.h
+++ b/src/feature/dirauth/ns_detached_signatures_st.h
@@ -18,5 +18,5 @@ struct ns_detached_signatures_t {
* document_signature_t */
};
-#endif
+#endif /* !defined(NS_DETACHED_SIGNATURES_ST_H) */
diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c
index 21b8e239ec..760560a5d9 100644
--- a/src/feature/dirauth/process_descs.c
+++ b/src/feature/dirauth/process_descs.c
@@ -310,6 +310,47 @@ dirserv_would_reject_router(const routerstatus_t *rs)
return (res & FP_REJECT) != 0;
}
+/**
+ * Check whether the platform string in <b>platform</b> describes a platform
+ * that, as a directory authority, we want to reject. If it does, return
+ * true, and set *<b>msg</b> (if present) to a rejection message. Otherwise
+ * return false.
+ */
+static bool
+dirserv_rejects_tor_version(const char *platform,
+ const char **msg)
+{
+ if (!platform)
+ return false;
+
+ static const char please_upgrade_string[] =
+ "Tor version is insecure or unsupported. Please upgrade!";
+
+ /* Versions before Tor 0.2.9 are unsupported. Versions between 0.2.9.0 and
+ * 0.2.9.4 suffer from bug #20499, where relays don't keep their consensus
+ * up to date */
+ if (!tor_version_as_new_as(platform,"0.2.9.5-alpha")) {
+ if (msg)
+ *msg = please_upgrade_string;
+ return true;
+ }
+
+ /* Series between Tor 0.3.0 and 0.3.4 inclusive are unsupported, and some
+ * have bug #27841, which makes them broken as intro points. Reject them.
+ *
+ * Also reject unstable versions of 0.3.5, since (as of this writing)
+ * they are almost none of the network. */
+ if (tor_version_as_new_as(platform,"0.3.0.0-alpha-dev") &&
+ !tor_version_as_new_as(platform,"0.3.5.7")) {
+ if (msg) {
+ *msg = please_upgrade_string;
+ }
+ return true;
+ }
+
+ return false;
+}
+
/** Helper: As dirserv_router_get_status, but takes the router fingerprint
* (hex, no spaces), nickname, address (used for logging only), IP address, OR
* port and platform (logging only) as arguments.
@@ -342,22 +383,8 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
}
}
- /* Versions before Tor 0.2.4.18-rc are too old to support, and are
- * missing some important security fixes too. Disable them. */
- if (platform && !tor_version_as_new_as(platform,"0.2.4.18-rc")) {
- if (msg)
- *msg = "Tor version is insecure or unsupported. Please upgrade!";
- return FP_REJECT;
- }
-
- /* Tor 0.2.9.x where x<5 suffers from bug #20499, where relays don't
- * keep their consensus up to date so they make bad guards.
- * The simple fix is to just drop them from the network. */
- if (platform &&
- tor_version_as_new_as(platform,"0.2.9.0-alpha") &&
- !tor_version_as_new_as(platform,"0.2.9.5-alpha")) {
- if (msg)
- *msg = "Tor version contains bug 20499. Please upgrade!";
+ /* Check whether the version is obsolete, broken, insecure, etc... */
+ if (platform && dirserv_rejects_tor_version(platform, msg)) {
return FP_REJECT;
}
@@ -519,7 +546,8 @@ WRA_MORE_SEVERE(was_router_added_t a, was_router_added_t b)
/** As for dirserv_add_descriptor(), but accepts multiple documents, and
* returns the most severe error that occurred for any one of them. */
was_router_added_t
-dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
+dirserv_add_multiple_descriptors(const char *desc, size_t desclen,
+ uint8_t purpose,
const char *source,
const char **msg)
{
@@ -536,6 +564,11 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
r=ROUTER_ADDED_SUCCESSFULLY; /*Least severe return value. */
+ if (!string_is_utf8_no_bom(desc, desclen)) {
+ *msg = "descriptor(s) or extrainfo(s) not valid UTF-8 or had BOM.";
+ return ROUTER_AUTHDIR_REJECTS;
+ }
+
format_iso_time(time_buf, now);
if (tor_snprintf(annotation_buf, sizeof(annotation_buf),
"@uploaded-at %s\n"
@@ -552,7 +585,7 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
s = desc;
list = smartlist_new();
- if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
+ if (!router_parse_list_from_string(&s, s+desclen, list, SAVED_NOWHERE, 0, 0,
annotation_buf, NULL)) {
SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
msg_out = NULL;
@@ -568,7 +601,7 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
smartlist_clear(list);
s = desc;
- if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0,
+ if (!router_parse_list_from_string(&s, s+desclen, list, SAVED_NOWHERE, 1, 0,
NULL, NULL)) {
SMARTLIST_FOREACH(list, extrainfo_t *, ei, {
msg_out = NULL;
diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h
index ae2d6ad25d..a8a1dcca1e 100644
--- a/src/feature/dirauth/process_descs.h
+++ b/src/feature/dirauth/process_descs.h
@@ -12,27 +12,101 @@
#ifndef TOR_RECV_UPLOADS_H
#define TOR_RECV_UPLOADS_H
-int dirserv_load_fingerprint_file(void);
+// for was_router_added_t.
+#include "feature/nodelist/routerlist.h"
+
void dirserv_free_fingerprint_list(void);
-int dirserv_add_own_fingerprint(crypto_pk_t *pk);
+#ifdef HAVE_MODULE_DIRAUTH
+int dirserv_load_fingerprint_file(void);
enum was_router_added_t dirserv_add_multiple_descriptors(
- const char *desc, uint8_t purpose,
+ const char *desc, size_t desclen,
+ uint8_t purpose,
const char *source,
const char **msg);
enum was_router_added_t dirserv_add_descriptor(routerinfo_t *ri,
const char **msg,
const char *source);
+int dirserv_would_reject_router(const routerstatus_t *rs);
int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
int complain,
int *valid_out);
+int dirserv_add_own_fingerprint(crypto_pk_t *pk);
uint32_t dirserv_router_get_status(const routerinfo_t *router,
const char **msg,
int severity);
void dirserv_set_node_flags_from_authoritative_status(node_t *node,
uint32_t authstatus);
-
-int dirserv_would_reject_router(const routerstatus_t *rs);
-
+#else
+static inline int
+dirserv_load_fingerprint_file(void)
+{
+ return 0;
+}
+static inline enum was_router_added_t
+dirserv_add_multiple_descriptors(const char *desc, size_t desclen,
+ uint8_t purpose,
+ const char *source,
+ const char **msg)
+{
+ (void)desc;
+ (void)desclen;
+ (void)purpose;
+ (void)source;
+ (void)msg;
+ return (enum was_router_added_t)0;
+}
+static inline enum was_router_added_t
+dirserv_add_descriptor(routerinfo_t *ri,
+ const char **msg,
+ const char *source)
+{
+ (void)ri;
+ (void)msg;
+ (void)source;
+ return (enum was_router_added_t)0;
+}
+static inline int
+dirserv_would_reject_router(const routerstatus_t *rs)
+{
+ (void)rs;
+ return 0;
+}
+static inline int
+authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
+ int complain,
+ int *valid_out)
+{
+ (void)ri;
+ (void)msg;
+ (void)complain;
+ (void)valid_out;
+ return 0;
+}
+static inline int
+dirserv_add_own_fingerprint(crypto_pk_t *pk)
+{
+ (void)pk;
+ return 0;
+}
+static inline uint32_t
+dirserv_router_get_status(const routerinfo_t *router,
+ const char **msg,
+ int severity)
+{
+ (void)router;
+ (void)msg;
+ (void)severity;
+ return 0;
+}
+static inline void
+dirserv_set_node_flags_from_authoritative_status(node_t *node,
+ uint32_t authstatus)
+{
+ (void)node;
+ (void)authstatus;
+}
#endif
+
+#endif /* !defined(TOR_RECV_UPLOADS_H) */
diff --git a/src/feature/dirauth/reachability.h b/src/feature/dirauth/reachability.h
index 5a938673ff..8a83f0c493 100644
--- a/src/feature/dirauth/reachability.h
+++ b/src/feature/dirauth/reachability.h
@@ -24,13 +24,36 @@
#define REACHABILITY_TEST_CYCLE_PERIOD \
(REACHABILITY_TEST_INTERVAL*REACHABILITY_MODULO_PER_TEST)
+void dirserv_single_reachability_test(time_t now, routerinfo_t *router);
+void dirserv_test_reachability(time_t now);
+
+#ifdef HAVE_MODULE_DIRAUTH
+int dirserv_should_launch_reachability_test(const routerinfo_t *ri,
+ const routerinfo_t *ri_old);
void dirserv_orconn_tls_done(const tor_addr_t *addr,
uint16_t or_port,
const char *digest_rcvd,
const struct ed25519_public_key_t *ed_id_rcvd);
-int dirserv_should_launch_reachability_test(const routerinfo_t *ri,
- const routerinfo_t *ri_old);
-void dirserv_single_reachability_test(time_t now, routerinfo_t *router);
-void dirserv_test_reachability(time_t now);
-
+#else
+static inline int
+dirserv_should_launch_reachability_test(const routerinfo_t *ri,
+ const routerinfo_t *ri_old)
+{
+ (void)ri;
+ (void)ri_old;
+ return 0;
+}
+static inline void
+dirserv_orconn_tls_done(const tor_addr_t *addr,
+ uint16_t or_port,
+ const char *digest_rcvd,
+ const struct ed25519_public_key_t *ed_id_rcvd)
+{
+ (void)addr;
+ (void)or_port;
+ (void)digest_rcvd;
+ (void)ed_id_rcvd;
+}
#endif
+
+#endif /* !defined(TOR_REACHABILITY_H) */
diff --git a/src/feature/dirauth/recommend_pkg.h b/src/feature/dirauth/recommend_pkg.h
index 8200d78f72..af17e945e8 100644
--- a/src/feature/dirauth/recommend_pkg.h
+++ b/src/feature/dirauth/recommend_pkg.h
@@ -12,6 +12,18 @@
#ifndef TOR_RECOMMEND_PKG_H
#define TOR_RECOMMEND_PKG_H
+#ifdef HAVE_MODULE_DIRAUTH
int validate_recommended_package_line(const char *line);
-#endif
+#else
+
+static inline int
+validate_recommended_package_line(const char *line)
+{
+ (void) line;
+ return 0;
+}
+
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
+
+#endif /* !defined(TOR_RECOMMEND_PKG_H) */
diff --git a/src/feature/dirauth/shared_random.c b/src/feature/dirauth/shared_random.c
index 34b2283250..5ccf1a95e5 100644
--- a/src/feature/dirauth/shared_random.c
+++ b/src/feature/dirauth/shared_random.c
@@ -120,8 +120,8 @@ static const char sr_flag_ns_str[] = "shared-rand-participate";
static int32_t num_srv_agreements_from_vote;
/* Return a heap allocated copy of the SRV <b>orig</b>. */
-STATIC sr_srv_t *
-srv_dup(const sr_srv_t *orig)
+sr_srv_t *
+sr_srv_dup(const sr_srv_t *orig)
{
sr_srv_t *duplicate = NULL;
@@ -224,7 +224,7 @@ verify_commit_and_reveal(const sr_commit_t *commit)
STATIC int
commit_has_reveal_value(const sr_commit_t *commit)
{
- return !tor_mem_is_zero(commit->encoded_reveal,
+ return !fast_mem_is_zero(commit->encoded_reveal,
sizeof(commit->encoded_reveal));
}
@@ -486,7 +486,7 @@ get_vote_line_from_commit(const sr_commit_t *commit, sr_phase_t phase)
{
/* Send a reveal value for this commit if we have one. */
const char *reveal_str = commit->encoded_reveal;
- if (tor_mem_is_zero(commit->encoded_reveal,
+ if (fast_mem_is_zero(commit->encoded_reveal,
sizeof(commit->encoded_reveal))) {
reveal_str = "";
}
@@ -1253,8 +1253,8 @@ sr_act_post_consensus(const networkstatus_t *consensus)
* decided by the majority. */
sr_state_unset_fresh_srv();
/* Set the SR values from the given consensus. */
- sr_state_set_previous_srv(srv_dup(consensus->sr_info.previous_srv));
- sr_state_set_current_srv(srv_dup(consensus->sr_info.current_srv));
+ sr_state_set_previous_srv(sr_srv_dup(consensus->sr_info.previous_srv));
+ sr_state_set_current_srv(sr_srv_dup(consensus->sr_info.current_srv));
}
/* Prepare our state so that it's ready for the next voting period. */
diff --git a/src/feature/dirauth/shared_random.h b/src/feature/dirauth/shared_random.h
index 25d95ebbc7..1d8fa89b0f 100644
--- a/src/feature/dirauth/shared_random.h
+++ b/src/feature/dirauth/shared_random.h
@@ -110,7 +110,7 @@ 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 */
+#else /* !(defined(HAVE_MODULE_DIRAUTH)) */
static inline int
sr_init(int save_to_disk)
@@ -131,7 +131,7 @@ sr_act_post_consensus(const networkstatus_t *consensus)
(void) consensus;
}
-#endif /* HAVE_MODULE_DIRAUTH */
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
/* Public methods used only by dirauth code. */
@@ -154,6 +154,7 @@ const char *sr_commit_get_rsa_fpr(const sr_commit_t *commit)
void sr_compute_srv(void);
sr_commit_t *sr_generate_our_commit(time_t timestamp,
const authority_cert_t *my_rsa_cert);
+sr_srv_t *sr_srv_dup(const sr_srv_t *orig);
#ifdef SHARED_RANDOM_PRIVATE
@@ -172,7 +173,6 @@ STATIC sr_srv_t *get_majority_srv_from_votes(const smartlist_t *votes,
int current);
STATIC void save_commit_to_state(sr_commit_t *commit);
-STATIC sr_srv_t *srv_dup(const sr_srv_t *orig);
STATIC int commitments_are_the_same(const sr_commit_t *commit_one,
const sr_commit_t *commit_two);
STATIC int commit_is_authoritative(const sr_commit_t *commit,
diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c
index b3e4a4ef92..58c203e204 100644
--- a/src/feature/dirauth/shared_random_state.c
+++ b/src/feature/dirauth/shared_random_state.c
@@ -22,6 +22,7 @@
#include "feature/dirauth/shared_random_state.h"
#include "feature/dircommon/voting_schedule.h"
#include "lib/encoding/confline.h"
+#include "lib/version/torversion.h"
#include "app/config/or_state_st.h"
@@ -101,6 +102,8 @@ static const config_format_t state_format = {
&state_extra_var,
};
+static void state_query_del_(sr_state_object_t obj_type, void *data);
+
/* Return a string representation of a protocol phase. */
STATIC const char *
get_phase_str(sr_phase_t phase)
@@ -535,7 +538,7 @@ disk_state_put_commit_line(const sr_commit_t *commit, config_line_t *line)
tor_assert(commit);
tor_assert(line);
- if (!tor_mem_is_zero(commit->encoded_reveal,
+ if (!fast_mem_is_zero(commit->encoded_reveal,
sizeof(commit->encoded_reveal))) {
/* Add extra whitespace so we can format the line correctly. */
tor_asprintf(&reveal_str, " %s", commit->encoded_reveal);
@@ -833,6 +836,9 @@ state_query_get_commit(const char *rsa_fpr)
static void *
state_query_get_(sr_state_object_t obj_type, const void *data)
{
+ if (BUG(!sr_state))
+ return NULL;
+
void *obj = NULL;
switch (obj_type) {
@@ -861,23 +867,44 @@ state_query_get_(sr_state_object_t obj_type, const void *data)
}
/* Helper function: This handles the PUT state action using an
- * <b>obj_type</b> and <b>data</b> needed for the action. */
+ * <b>obj_type</b> and <b>data</b> needed for the action.
+ * PUT frees the previous data before replacing it, if needed. */
static void
state_query_put_(sr_state_object_t obj_type, void *data)
{
+ if (BUG(!sr_state))
+ return;
+
switch (obj_type) {
case SR_STATE_OBJ_COMMIT:
{
sr_commit_t *commit = data;
tor_assert(commit);
+ /* commit_add_to_state() frees the old commit, if there is one */
commit_add_to_state(commit, sr_state);
break;
}
case SR_STATE_OBJ_CURSRV:
- sr_state->current_srv = (sr_srv_t *) data;
+ /* Check if the new pointer is the same as the old one: if it is, it's
+ * probably a bug. The caller may have confused current and previous,
+ * or they may have forgotten to sr_srv_dup().
+ * Putting NULL multiple times is allowed. */
+ if (!BUG(data && sr_state->current_srv == (sr_srv_t *) data)) {
+ /* We own the old SRV, so we need to free it. */
+ state_query_del_(SR_STATE_OBJ_CURSRV, NULL);
+ sr_state->current_srv = (sr_srv_t *) data;
+ }
break;
case SR_STATE_OBJ_PREVSRV:
- sr_state->previous_srv = (sr_srv_t *) data;
+ /* Check if the new pointer is the same as the old one: if it is, it's
+ * probably a bug. The caller may have confused current and previous,
+ * or they may have forgotten to sr_srv_dup().
+ * Putting NULL multiple times is allowed. */
+ if (!BUG(data && sr_state->previous_srv == (sr_srv_t *) data)) {
+ /* We own the old SRV, so we need to free it. */
+ state_query_del_(SR_STATE_OBJ_PREVSRV, NULL);
+ sr_state->previous_srv = (sr_srv_t *) data;
+ }
break;
case SR_STATE_OBJ_VALID_AFTER:
sr_state->valid_after = *((time_t *) data);
@@ -897,6 +924,9 @@ state_query_put_(sr_state_object_t obj_type, void *data)
static void
state_query_del_all_(sr_state_object_t obj_type)
{
+ if (BUG(!sr_state))
+ return;
+
switch (obj_type) {
case SR_STATE_OBJ_COMMIT:
{
@@ -907,7 +937,7 @@ state_query_del_all_(sr_state_object_t obj_type)
} DIGESTMAP_FOREACH_END;
break;
}
- /* The following object are _NOT_ suppose to be removed. */
+ /* The following objects are _NOT_ supposed to be removed. */
case SR_STATE_OBJ_CURSRV:
case SR_STATE_OBJ_PREVSRV:
case SR_STATE_OBJ_PHASE:
@@ -925,6 +955,9 @@ state_query_del_(sr_state_object_t obj_type, void *data)
{
(void) data;
+ if (BUG(!sr_state))
+ return;
+
switch (obj_type) {
case SR_STATE_OBJ_PREVSRV:
tor_free(sr_state->previous_srv);
@@ -999,16 +1032,16 @@ state_del_previous_srv(void)
state_query(SR_STATE_ACTION_DEL, SR_STATE_OBJ_PREVSRV, NULL, NULL);
}
-/* Rotate SRV value by freeing the previous value, assigning the current
- * value to the previous one and nullifying the current one. */
+/* Rotate SRV value by setting the previous SRV to the current SRV, and
+ * clearing the current SRV. */
STATIC void
state_rotate_srv(void)
{
/* First delete previous SRV from the state. Object will be freed. */
state_del_previous_srv();
- /* Set previous SRV with the current one. */
- sr_state_set_previous_srv(sr_state_get_current_srv());
- /* Nullify the current srv. */
+ /* Set previous SRV to a copy of the current one. */
+ sr_state_set_previous_srv(sr_srv_dup(sr_state_get_current_srv()));
+ /* Free and NULL the current srv. */
sr_state_set_current_srv(NULL);
}
@@ -1024,12 +1057,15 @@ sr_state_set_valid_after(time_t valid_after)
sr_phase_t
sr_state_get_phase(void)
{
- void *ptr;
+ void *ptr=NULL;
state_query(SR_STATE_ACTION_GET, SR_STATE_OBJ_PHASE, NULL, &ptr);
+ tor_assert(ptr);
return *(sr_phase_t *) ptr;
}
-/* Return the previous SRV value from our state. Value CAN be NULL. */
+/* Return the previous SRV value from our state. Value CAN be NULL.
+ * The state object owns the SRV, so the calling code should not free the SRV.
+ * Use sr_srv_dup() if you want to keep a copy of the SRV. */
const sr_srv_t *
sr_state_get_previous_srv(void)
{
@@ -1048,7 +1084,9 @@ sr_state_set_previous_srv(const sr_srv_t *srv)
NULL);
}
-/* Return the current SRV value from our state. Value CAN be NULL. */
+/* Return the current SRV value from our state. Value CAN be NULL.
+ * The state object owns the SRV, so the calling code should not free the SRV.
+ * Use sr_srv_dup() if you want to keep a copy of the SRV. */
const sr_srv_t *
sr_state_get_current_srv(void)
{
diff --git a/src/feature/dirauth/vote_microdesc_hash_st.h b/src/feature/dirauth/vote_microdesc_hash_st.h
index 92acdf1157..7869f92b4f 100644
--- a/src/feature/dirauth/vote_microdesc_hash_st.h
+++ b/src/feature/dirauth/vote_microdesc_hash_st.h
@@ -18,5 +18,5 @@ struct vote_microdesc_hash_t {
char *microdesc_hash_line;
};
-#endif
+#endif /* !defined(VOTE_MICRODESC_HASH_ST_H) */
diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c
index 54c70b989a..f552af98c4 100644
--- a/src/feature/dirauth/voteflags.c
+++ b/src/feature/dirauth/voteflags.c
@@ -29,6 +29,7 @@
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
+#include "feature/nodelist/routerlist_st.h"
#include "feature/nodelist/vote_routerstatus_st.h"
#include "lib/container/order.h"
@@ -95,7 +96,7 @@ real_uptime(const routerinfo_t *router, time_t now)
*/
static int
dirserv_thinks_router_is_unreliable(time_t now,
- routerinfo_t *router,
+ const routerinfo_t *router,
int need_uptime, int need_capacity)
{
if (need_uptime) {
@@ -238,7 +239,7 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
uint32_t *uptimes, *bandwidths_kb, *bandwidths_excluding_exits_kb;
long *tks;
double *mtbfs, *wfus;
- smartlist_t *nodelist;
+ const smartlist_t *nodelist;
time_t now = time(NULL);
const or_options_t *options = get_options();
@@ -531,38 +532,45 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
node->is_running = answer;
}
-/** 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.
- *
- * We assume that ri-\>is_running has already been set, e.g. by
- * dirserv_set_router_is_running(ri, now);
+/* Check <b>node</b> and <b>ri</b> on whether or not we should publish a
+ * relay's IPv6 addresses. */
+static int
+should_publish_node_ipv6(const node_t *node, const routerinfo_t *ri,
+ time_t now)
+{
+ const or_options_t *options = get_options();
+
+ return options->AuthDirHasIPv6Connectivity == 1 &&
+ !tor_addr_is_null(&ri->ipv6_addr) &&
+ ((node->last_reachable6 >= now - REACHABLE_TIMEOUT) ||
+ router_is_me(ri));
+}
+
+/**
+ * Extract status information from <b>ri</b> and from other authority
+ * functions and store it in <b>rs</b>, as per
+ * <b>set_routerstatus_from_routerinfo</b>. Additionally, sets information
+ * in from the authority subsystem.
*/
void
-set_routerstatus_from_routerinfo(routerstatus_t *rs,
- node_t *node,
- routerinfo_t *ri,
- time_t now,
- int listbadexits)
+dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
+ node_t *node,
+ const routerinfo_t *ri,
+ time_t now,
+ int listbadexits)
{
const or_options_t *options = get_options();
uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri);
- memset(rs, 0, sizeof(routerstatus_t));
-
- rs->is_authority =
- router_digest_is_trusted_dir(ri->cache_info.identity_digest);
-
- /* Already set by compute_performance_thresholds. */
- rs->is_exit = node->is_exit;
- rs->is_stable = node->is_stable =
- !dirserv_thinks_router_is_unreliable(now, ri, 1, 0);
- rs->is_fast = node->is_fast =
- !dirserv_thinks_router_is_unreliable(now, ri, 0, 1);
- rs->is_flagged_running = node->is_running; /* computed above */
+ /* Set these flags so that set_routerstatus_from_routerinfo can copy them.
+ */
+ node->is_stable = !dirserv_thinks_router_is_unreliable(now, ri, 1, 0);
+ node->is_fast = !dirserv_thinks_router_is_unreliable(now, ri, 0, 1);
+ node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now);
- rs->is_valid = node->is_valid;
+ set_routerstatus_from_routerinfo(rs, node, ri);
+ /* Override rs->is_possible_guard. */
if (node->is_fast && node->is_stable &&
ri->supports_tunnelled_dir_requests &&
((options->AuthDirGuardBWGuarantee &&
@@ -578,29 +586,16 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->is_possible_guard = 0;
}
+ /* Override rs->is_bad_exit */
rs->is_bad_exit = listbadexits && node->is_bad_exit;
- rs->is_hs_dir = node->is_hs_dir =
- dirserv_thinks_router_is_hs_dir(ri, node, now);
-
- rs->is_named = rs->is_unnamed = 0;
-
- rs->published_on = ri->cache_info.published_on;
- memcpy(rs->identity_digest, node->identity, DIGEST_LEN);
- memcpy(rs->descriptor_digest, ri->cache_info.signed_descriptor_digest,
- DIGEST_LEN);
- rs->addr = ri->addr;
- strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname));
- rs->or_port = ri->or_port;
- rs->dir_port = ri->dir_port;
- rs->is_v2_dir = ri->supports_tunnelled_dir_requests;
- if (options->AuthDirHasIPv6Connectivity == 1 &&
- !tor_addr_is_null(&ri->ipv6_addr) &&
- node->last_reachable6 >= now - REACHABLE_TIMEOUT) {
- /* We're configured as having IPv6 connectivity. There's an IPv6
- OR port and it's reachable so copy it to the routerstatus. */
- tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr);
- rs->ipv6_orport = ri->ipv6_orport;
- } else {
+
+ /* Set rs->is_staledesc. */
+ rs->is_staledesc =
+ (ri->cache_info.published_on + DESC_IS_STALE_INTERVAL) < now;
+
+ if (! should_publish_node_ipv6(node, ri, now)) {
+ /* We're not configured as having IPv6 connectivity or the node isn't:
+ * zero its IPv6 information. */
tor_addr_make_null(&rs->ipv6_addr, AF_INET6);
rs->ipv6_orport = 0;
}
@@ -642,3 +637,20 @@ dirserv_set_routerstatus_testing(routerstatus_t *rs)
rs->is_hs_dir = 0;
}
}
+
+/** Use dirserv_set_router_is_running() to set bridges as running if they're
+ * reachable.
+ *
+ * This function is called from set_bridge_running_callback() when running as
+ * a bridge authority.
+ */
+void
+dirserv_set_bridges_running(time_t now)
+{
+ routerlist_t *rl = router_get_routerlist();
+
+ SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) {
+ if (ri->purpose == ROUTER_PURPOSE_BRIDGE)
+ dirserv_set_router_is_running(ri, now);
+ } SMARTLIST_FOREACH_END(ri);
+}
diff --git a/src/feature/dirauth/voteflags.h b/src/feature/dirauth/voteflags.h
index aa7b6ed082..c4f36e7817 100644
--- a/src/feature/dirauth/voteflags.h
+++ b/src/feature/dirauth/voteflags.h
@@ -12,20 +12,28 @@
#ifndef TOR_VOTEFLAGS_H
#define TOR_VOTEFLAGS_H
+#ifdef HAVE_MODULE_DIRAUTH
void dirserv_set_router_is_running(routerinfo_t *router, time_t now);
char *dirserv_get_flag_thresholds_line(void);
void dirserv_compute_bridge_flag_thresholds(void);
int running_long_enough_to_decide_unreachable(void);
-void set_routerstatus_from_routerinfo(routerstatus_t *rs,
- node_t *node,
- routerinfo_t *ri, time_t now,
- int listbadexits);
+void dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
+ node_t *node,
+ const routerinfo_t *ri,
+ time_t now,
+ int listbadexits);
void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil);
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
+
+void dirserv_set_bridges_running(time_t now);
#ifdef VOTEFLAGS_PRIVATE
+/** Any descriptor older than this age causes the authorities to set the
+ * StaleDesc flag. */
+#define DESC_IS_STALE_INTERVAL (18*60*60)
STATIC void dirserv_set_routerstatus_testing(routerstatus_t *rs);
-#endif
+#endif /* defined(VOTEFLAGS_PRIVATE) */
-#endif
+#endif /* !defined(TOR_VOTEFLAGS_H) */