diff options
Diffstat (limited to 'src/or/dirserv.c')
-rw-r--r-- | src/or/dirserv.c | 249 |
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; } |