aboutsummaryrefslogtreecommitdiff
path: root/src/or/dirserv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/dirserv.c')
-rw-r--r--src/or/dirserv.c249
1 files changed, 164 insertions, 85 deletions
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index f1c9c6232d..7ffd753524 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -7,6 +7,10 @@
#include "or.h"
#include "buffers.h"
#include "config.h"
+#include "confparse.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "command.h"
#include "connection.h"
#include "connection_or.h"
#include "control.h"
@@ -62,6 +66,19 @@ static cached_dir_t *the_directory = NULL;
/** For authoritative directories: the current (v1) network status. */
static cached_dir_t the_runningrouters;
+/** Array of start and end of consensus methods used for supported
+ microdescriptor formats. */
+static const struct consensus_method_range_t {
+ int low;
+ int high;
+} microdesc_consensus_methods[] = {
+ {MIN_METHOD_FOR_MICRODESC, MIN_METHOD_FOR_A_LINES - 1},
+ {MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1},
+ {MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1},
+ {MIN_METHOD_FOR_NTOR_KEY, MAX_SUPPORTED_CONSENSUS_METHOD},
+ {-1, -1}
+};
+
static void directory_remove_invalid(void);
static cached_dir_t *dirserv_regenerate_directory(void);
static char *format_versions_list(config_line_t *ln);
@@ -79,7 +96,8 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp(
const char *fp,
int extrainfo,
time_t publish_cutoff);
-static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg);
+static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
+ const char **msg);
/************** Measured Bandwidth parsing code ******/
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
@@ -388,18 +406,18 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
strmap_size(fingerprint_list->fp_by_name),
digestmap_size(fingerprint_list->status_by_digest));
- /* Versions before Tor 0.2.1.30 have known security issues that
+ /* Versions before Tor 0.2.2.35 have known security issues that
* make them unsuitable for the current network. */
- if (platform && !tor_version_as_new_as(platform,"0.2.1.30")) {
+ if (platform && !tor_version_as_new_as(platform,"0.2.2.35")) {
if (msg)
- *msg = "Tor version is insecure. Please upgrade!";
+ *msg = "Tor version is insecure or unsupported. Please upgrade!";
return FP_REJECT;
- } else if (platform && tor_version_as_new_as(platform,"0.2.2.1-alpha")) {
- /* Versions from 0.2.2.1-alpha...0.2.2.20-alpha have known security
+ } else if (platform && tor_version_as_new_as(platform,"0.2.3.0-alpha")) {
+ /* Versions from 0.2.3-alpha...0.2.3.9-alpha have known security
* issues that make them unusable for the current network */
- if (!tor_version_as_new_as(platform, "0.2.2.21-alpha")) {
+ if (!tor_version_as_new_as(platform, "0.2.3.10-alpha")) {
if (msg)
- *msg = "Tor version is insecure. Please upgrade!";
+ *msg = "Tor version is insecure or unsupported. Please upgrade!";
return FP_REJECT;
}
}
@@ -501,8 +519,8 @@ dirserv_free_fingerprint_list(void)
if (!fingerprint_list)
return;
- strmap_free(fingerprint_list->fp_by_name, _tor_free);
- digestmap_free(fingerprint_list->status_by_digest, _tor_free);
+ strmap_free(fingerprint_list->fp_by_name, tor_free_);
+ digestmap_free(fingerprint_list->status_by_digest, tor_free_);
tor_free(fingerprint_list);
}
@@ -717,7 +735,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
"MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.",
ri->nickname, source, (int)ri->cache_info.signed_descriptor_len,
MAX_DESCRIPTOR_UPLOAD_SIZE);
- *msg = "Router descriptor was too large";
+ *msg = "Router descriptor was too large.";
control_event_or_authdir_new_descriptor("REJECTED",
ri->cache_info.signed_descriptor_body,
ri->cache_info.signed_descriptor_len, *msg);
@@ -980,6 +998,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
unreachable.
*/
int answer;
+ const or_options_t *options = get_options();
node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest);
tor_assert(node);
@@ -988,17 +1007,27 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
answer = ! we_are_hibernating();
} else if (router->is_hibernating &&
(router->cache_info.published_on +
- HIBERNATION_PUBLICATION_SKEW) > router->last_reachable) {
+ HIBERNATION_PUBLICATION_SKEW) > node->last_reachable) {
/* A hibernating router is down unless we (somehow) had contact with it
* since it declared itself to be hibernating. */
answer = 0;
- } else if (get_options()->AssumeReachable) {
+ } else if (options->AssumeReachable) {
/* If AssumeReachable, everybody is up unless they say they are down! */
answer = 1;
} else {
- /* Otherwise, a router counts as up if we found it reachable in the last
- REACHABLE_TIMEOUT seconds. */
- answer = (now < router->last_reachable + REACHABLE_TIMEOUT);
+ /* Otherwise, a router counts as up if we found all announced OR
+ ports reachable in the last REACHABLE_TIMEOUT seconds.
+
+ XXX prop186 For now there's always one IPv4 and at most one
+ IPv6 OR port.
+
+ If we're not on IPv6, don't consider reachability of potential
+ IPv6 OR port since that'd kill all dual stack relays until a
+ majority of the dir auths have IPv6 connectivity. */
+ answer = (now < node->last_reachable + REACHABLE_TIMEOUT &&
+ (options->AuthDirHasIPv6Connectivity != 1 ||
+ tor_addr_is_null(&router->ipv6_addr) ||
+ now < node->last_reachable6 + REACHABLE_TIMEOUT));
}
if (!answer && running_long_enough_to_decide_unreachable()) {
@@ -1008,11 +1037,13 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
REACHABILITY_TEST_CYCLE_PERIOD seconds, then the router has probably
been down since at least that time after we last successfully reached
it.
+
+ XXX ipv6
*/
time_t when = now;
- if (router->last_reachable &&
- router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
- when = router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
+ if (node->last_reachable &&
+ node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
+ when = node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
rep_hist_note_router_unreachable(router->cache_info.identity_digest, when);
}
@@ -1117,6 +1148,8 @@ int
dirserv_dump_directory_to_string(char **dir_out,
crypto_pk_t *private_key)
{
+ /* XXXX 024 Get rid of this function if we can confirm that nobody's
+ * fetching these any longer */
char *cp;
char *identity_pkey; /* Identity key, DER64-encoded. */
char *recommended_versions;
@@ -1399,7 +1432,7 @@ clear_cached_dir(cached_dir_t *d)
/** Free all storage held by the cached_dir_t in <b>d</b>. */
static void
-_free_cached_dir(void *_d)
+free_cached_dir_(void *_d)
{
cached_dir_t *d;
if (!_d)
@@ -1417,21 +1450,12 @@ _free_cached_dir(void *_d)
* If <b>is_running_routers</b>, this is really a v1 running_routers
* document rather than a v1 directory.
*/
-void
-dirserv_set_cached_directory(const char *directory, time_t published,
- int is_running_routers)
+static void
+dirserv_set_cached_directory(const char *directory, time_t published)
{
- time_t now = time(NULL);
- if (is_running_routers) {
- if (published >= now - MAX_V1_RR_AGE)
- set_cached_dir(&cached_runningrouters, tor_strdup(directory), published);
- } else {
- if (published >= now - MAX_V1_DIRECTORY_AGE) {
- cached_dir_decref(cached_directory);
- cached_directory = new_cached_dir(tor_strdup(directory), published);
- }
- }
+ cached_dir_decref(cached_directory);
+ cached_directory = new_cached_dir(tor_strdup(directory), published);
}
/** If <b>networkstatus</b> is non-NULL, we've just received a v2
@@ -1448,7 +1472,6 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
time_t published)
{
cached_dir_t *d, *old_d;
- smartlist_t *trusted_dirs;
if (!cached_v2_networkstatus)
cached_v2_networkstatus = digestmap_new();
@@ -1471,9 +1494,9 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
}
/* Now purge old entries. */
- trusted_dirs = router_get_trusted_dir_servers();
+
if (digestmap_size(cached_v2_networkstatus) >
- smartlist_len(trusted_dirs) + MAX_UNTRUSTED_NETWORKSTATUSES) {
+ get_n_authorities(V2_DIRINFO) + MAX_UNTRUSTED_NETWORKSTATUSES) {
/* We need to remove the oldest untrusted networkstatus. */
const char *oldest = NULL;
time_t oldest_published = TIME_MAX;
@@ -1613,6 +1636,8 @@ dirserv_get_directory(void)
static cached_dir_t *
dirserv_regenerate_directory(void)
{
+ /* XXXX 024 Get rid of this function if we can confirm that nobody's
+ * fetching these any longer */
char *new_directory=NULL;
if (dirserv_dump_directory_to_string(&new_directory,
@@ -1632,7 +1657,7 @@ dirserv_regenerate_directory(void)
/* Save the directory to disk so we re-load it quickly on startup.
*/
- dirserv_set_cached_directory(the_directory->dir, time(NULL), 0);
+ dirserv_set_cached_directory(the_directory->dir, time(NULL));
return the_directory;
}
@@ -2040,7 +2065,7 @@ version_from_platform(const char *platform)
* non-NULL, add a "v" line for the platform. Return 0 on success, -1 on
* failure.
*
- * The format argument has three possible values:
+ * The format argument has one of the following values:
* NS_V2 - Output an entry suitable for a V2 NS opinion document
* NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
* NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
@@ -2079,15 +2104,32 @@ routerstatus_format_entry(char *buf, size_t buf_len,
log_warn(LD_BUG, "Not enough space in buffer.");
return -1;
}
+ cp = buf + strlen(buf);
/* TODO: Maybe we want to pass in what we need to build the rest of
* this here, instead of in the caller. Then we could use the
* networkstatus_type_t values, with an additional control port value
* added -MP */
- if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
+
+ /* V3 microdesc consensuses don't have "a" lines. */
+ if (format == NS_V3_CONSENSUS_MICRODESC)
+ return 0;
+
+ /* Possible "a" line. At most one for now. */
+ if (!tor_addr_is_null(&rs->ipv6_addr)) {
+ r = tor_snprintf(cp, buf_len - (cp-buf),
+ "a %s\n",
+ fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
+ if (r<0) {
+ log_warn(LD_BUG, "Not enough space in buffer.");
+ return -1;
+ }
+ cp += strlen(cp);
+ }
+
+ if (format == NS_V3_CONSENSUS)
return 0;
- cp = buf + strlen(buf);
/* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
r = tor_snprintf(cp, buf_len - (cp-buf),
"s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
@@ -2114,7 +2156,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
/* length of "opt v \n" */
#define V_LINE_OVERHEAD 7
if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
- if (tor_snprintf(cp, buf_len - (cp-buf), "opt v %s\n", version)<0) {
+ if (tor_snprintf(cp, buf_len - (cp-buf), "v %s\n", version)<0) {
log_warn(LD_BUG, "Unable to print router version.");
return -1;
}
@@ -2192,7 +2234,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
}
if (desc) {
- summary = policy_summarize(desc->exit_policy);
+ summary = policy_summarize(desc->exit_policy, AF_INET);
r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
if (r<0) {
log_warn(LD_BUG, "Not enough space in buffer.");
@@ -2213,7 +2255,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
* 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)
+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;
@@ -2228,7 +2270,7 @@ _compare_routerinfo_by_ip_and_bw(const void **a, const void **b)
else if (first->addr > second->addr)
return 1;
- /* Potentially, this next bit could cause k n lg n memcmp calls. But in
+ /* 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. */
@@ -2288,7 +2330,7 @@ get_possible_sybil_list(const smartlist_t *routers)
max_with_same_addr_on_authority = INT_MAX;
smartlist_add_all(routers_by_ip, routers);
- smartlist_sort(routers_by_ip, _compare_routerinfo_by_ip_and_bw);
+ smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_);
omit_as_sybil = digestmap_new();
last_addr = 0;
@@ -2393,8 +2435,6 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
int listbaddirs, int vote_on_hsdirs)
{
const or_options_t *options = get_options();
- int unstable_version =
- !tor_version_as_new_as(ri->platform,"0.1.1.16-rc-cvs");
uint32_t routerbw = router_get_advertised_bandwidth(ri);
memset(rs, 0, sizeof(routerstatus_t));
@@ -2406,8 +2446,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->is_exit = node->is_exit;
rs->is_stable = node->is_stable =
router_is_active(ri, node, now) &&
- !dirserv_thinks_router_is_unreliable(now, ri, 1, 0) &&
- !unstable_version;
+ !dirserv_thinks_router_is_unreliable(now, ri, 1, 0);
rs->is_fast = node->is_fast =
router_is_active(ri, node, now) &&
!dirserv_thinks_router_is_unreliable(now, ri, 0, 1);
@@ -2453,6 +2492,14 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname));
rs->or_port = ri->or_port;
rs->dir_port = ri->dir_port;
+ 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;
+ }
}
/** Routerstatus <b>rs</b> is part of a group of routers that are on
@@ -2715,6 +2762,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
microdescriptors = smartlist_new();
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
+ const struct consensus_method_range_t *cmr = NULL;
if (ri->cache_info.published_on >= cutoff) {
routerstatus_t *rs;
vote_routerstatus_t *vrs;
@@ -2736,17 +2784,22 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
rs->is_flagged_running = 0;
vrs->version = version_from_platform(ri->platform);
- md = dirvote_create_microdescriptor(ri);
- if (md) {
- char buf[128];
- vote_microdesc_hash_t *h;
- dirvote_format_microdesc_vote_line(buf, sizeof(buf), md);
- h = tor_malloc(sizeof(vote_microdesc_hash_t));
- h->microdesc_hash_line = tor_strdup(buf);
- h->next = NULL;
- vrs->microdesc = h;
- md->last_listed = now;
- smartlist_add(microdescriptors, md);
+ for (cmr = microdesc_consensus_methods;
+ cmr->low != -1 && cmr->high != -1;
+ cmr++) {
+ md = dirvote_create_microdescriptor(ri, cmr->low);
+ if (md) {
+ char buf[128];
+ vote_microdesc_hash_t *h;
+ dirvote_format_microdesc_vote_line(buf, sizeof(buf), md,
+ cmr->low, cmr->high);
+ h = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
+ h->microdesc_hash_line = tor_strdup(buf);
+ h->next = vrs->microdesc;
+ vrs->microdesc = h;
+ md->last_listed = now;
+ smartlist_add(microdescriptors, md);
+ }
}
smartlist_add(routerstatuses, vrs);
@@ -3074,7 +3127,7 @@ dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result,
}
} else {
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
if (ds->type & V2_DIRINFO)
smartlist_add(result, tor_memdup(ds->digest, DIGEST_LEN)));
}
@@ -3273,36 +3326,42 @@ dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
* Inform the reachability checker that we could get to this guy.
*/
void
-dirserv_orconn_tls_done(const char *address,
+dirserv_orconn_tls_done(const tor_addr_t *addr,
uint16_t or_port,
const char *digest_rcvd)
{
- routerinfo_t *ri;
+ node_t *node = NULL;
+ tor_addr_port_t orport;
+ routerinfo_t *ri = NULL;
time_t now = time(NULL);
- tor_assert(address);
+ tor_assert(addr);
tor_assert(digest_rcvd);
- ri = router_get_mutable_by_digest(digest_rcvd);
-
- if (ri == NULL)
+ node = node_get_mutable_by_id(digest_rcvd);
+ if (node == NULL || node->ri == NULL)
return;
+ ri = node->ri;
- if (!strcasecmp(address, ri->address) && or_port == ri->or_port) {
+ tor_addr_copy(&orport.addr, addr);
+ orport.port = or_port;
+ if (router_has_orport(ri, &orport)) {
/* Found the right router. */
if (!authdir_mode_bridge(get_options()) ||
ri->purpose == ROUTER_PURPOSE_BRIDGE) {
+ char addrstr[TOR_ADDR_BUF_LEN];
/* This is a bridge or we're not a bridge authorititative --
mark it as reachable. */
- tor_addr_t addr, *addrp=NULL;
log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.",
router_describe(ri),
- address, ri->or_port);
- if (tor_addr_parse(&addr, ri->address) != -1)
- addrp = &addr;
- else
- log_warn(LD_BUG, "Couldn't parse IP address \"%s\"", ri->address);
- rep_hist_note_router_reachable(digest_rcvd, addrp, or_port, now);
- ri->last_reachable = now;
+ tor_addr_to_str(addrstr, addr, sizeof(addrstr), 1),
+ ri->or_port);
+ if (tor_addr_family(addr) == AF_INET) {
+ rep_hist_note_router_reachable(digest_rcvd, addr, or_port, now);
+ node->last_reachable = now;
+ } else if (tor_addr_family(addr) == AF_INET6) {
+ /* No rephist for IPv6. */
+ node->last_reachable6 = now;
+ }
}
}
}
@@ -3325,7 +3384,7 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
/* It just came out of hibernation; launch a reachability test */
return 1;
}
- if (! routers_have_same_or_addr(ri, ri_old)) {
+ if (! routers_have_same_or_addrs(ri, ri_old)) {
/* Address or port changed; launch a reachability test */
return 1;
}
@@ -3338,15 +3397,35 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
void
dirserv_single_reachability_test(time_t now, routerinfo_t *router)
{
+ channel_t *chan = NULL;
+ node_t *node = NULL;
tor_addr_t router_addr;
+ (void) now;
+
+ tor_assert(router);
+ node = node_get_mutable_by_id(router->cache_info.identity_digest);
+ tor_assert(node);
+
+ /* IPv4. */
log_debug(LD_OR,"Testing reachability of %s at %s:%u.",
router->nickname, router->address, router->or_port);
- /* Remember when we started trying to determine reachability */
- if (!router->testing_since)
- router->testing_since = now;
tor_addr_from_ipv4h(&router_addr, router->addr);
- connection_or_connect(&router_addr, router->or_port,
- router->cache_info.identity_digest);
+ chan = channel_tls_connect(&router_addr, router->or_port,
+ router->cache_info.identity_digest);
+ if (chan) command_setup_channel(chan);
+
+ /* Possible IPv6. */
+ if (get_options()->AuthDirHasIPv6Connectivity == 1 &&
+ !tor_addr_is_null(&router->ipv6_addr)) {
+ char addrstr[TOR_ADDR_BUF_LEN];
+ log_debug(LD_OR, "Testing reachability of %s at %s:%u.",
+ router->nickname,
+ tor_addr_to_str(addrstr, &router->ipv6_addr, sizeof(addrstr), 1),
+ router->ipv6_orport);
+ chan = channel_tls_connect(&router->ipv6_addr, router->ipv6_orport,
+ router->cache_info.identity_digest);
+ if (chan) command_setup_channel(chan);
+ }
}
/** Auth dir server only: load balance such that we only
@@ -3767,7 +3846,7 @@ connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn)
int
connection_dirserv_flushed_some(dir_connection_t *conn)
{
- tor_assert(conn->_base.state == DIR_CONN_STATE_SERVER_WRITING);
+ tor_assert(conn->base_.state == DIR_CONN_STATE_SERVER_WRITING);
if (connection_get_outbuf_len(TO_CONN(conn)) >= DIRSERV_BUFFER_MIN)
return 0;
@@ -3802,9 +3881,9 @@ dirserv_free_all(void)
cached_dir_decref(cached_directory);
clear_cached_dir(&cached_runningrouters);
- digestmap_free(cached_v2_networkstatus, _free_cached_dir);
+ digestmap_free(cached_v2_networkstatus, free_cached_dir_);
cached_v2_networkstatus = NULL;
- strmap_free(cached_consensuses, _free_cached_dir);
+ strmap_free(cached_consensuses, free_cached_dir_);
cached_consensuses = NULL;
}