diff options
author | Roger Dingledine <arma@torproject.org> | 2011-03-14 17:21:36 -0400 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2011-03-14 17:21:36 -0400 |
commit | 626912a81a9d494d496de38c4fd46e058d9039f2 (patch) | |
tree | 09a4d999abfb35b7430b191c504f634be6aa91f9 | |
parent | af04bd489b79acd4614119f26944fac2835fe641 (diff) | |
parent | b97d9abd0940037b249a1ee56724dbfed904263b (diff) | |
download | tor-626912a81a9d494d496de38c4fd46e058d9039f2.tar.gz tor-626912a81a9d494d496de38c4fd46e058d9039f2.zip |
Merge branch 'maint-0.2.2' into release-0.2.2
-rw-r--r-- | changes/bug1172 | 9 | ||||
-rw-r--r-- | changes/bug2510 | 8 | ||||
-rw-r--r-- | changes/bug2511 | 6 | ||||
-rw-r--r-- | changes/bug2716 | 5 | ||||
-rw-r--r-- | changes/hsdir_assignment | 8 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 25 | ||||
-rw-r--r-- | src/or/dirserv.c | 41 | ||||
-rw-r--r-- | src/or/dirserv.h | 12 | ||||
-rw-r--r-- | src/or/dirvote.c | 2 | ||||
-rw-r--r-- | src/or/main.c | 7 | ||||
-rw-r--r-- | src/or/or.h | 1 | ||||
-rw-r--r-- | src/or/rephist.c | 14 | ||||
-rw-r--r-- | src/or/rephist.h | 1 | ||||
-rw-r--r-- | src/or/router.c | 20 | ||||
-rw-r--r-- | src/or/routerlist.c | 17 |
15 files changed, 150 insertions, 26 deletions
diff --git a/changes/bug1172 b/changes/bug1172 new file mode 100644 index 0000000000..3abd7437f5 --- /dev/null +++ b/changes/bug1172 @@ -0,0 +1,9 @@ + o Minor bugfixes: + - When we restart our relay, we might get a successful connection + from the outside before we've started our reachability tests, + triggering a warning: "ORPort found reachable, but I have no + routerinfo yet. Failing to inform controller of success." This + bug was harmless unless Tor is running under a controller + like Vidalia, in which case the controller would never get a + REACHABILITY_SUCCEEDED status event. Bugfix on 0.1.2.6-alpha; + fixes bug 1172. diff --git a/changes/bug2510 b/changes/bug2510 new file mode 100644 index 0000000000..2c3f613556 --- /dev/null +++ b/changes/bug2510 @@ -0,0 +1,8 @@ + o Major bugfixes: + - Fix a bug where bridge users who configure the non-canonical + address of a bridge automatically switch to its canonical + address. If a bridge listens at more than one address, it should be + able to advertise those addresses independently and any non-blocked + addresses should continue to work. Bugfix on Tor 0.2.0.x. Fixes + bug 2510. + diff --git a/changes/bug2511 b/changes/bug2511 new file mode 100644 index 0000000000..a27696a5ff --- /dev/null +++ b/changes/bug2511 @@ -0,0 +1,6 @@ + o Major bugfixes: + - If you configured Tor to use bridge A, and then quit and + configured Tor to use bridge B instead, it would happily continue + to use bridge A if it's still reachable. While this behavior is + a feature if your goal is connectivity, in some scenarios it's a + dangerous bug. Bugfix on Tor 0.2.0.1-alpha; fixes bug 2511. diff --git a/changes/bug2716 b/changes/bug2716 new file mode 100644 index 0000000000..4663ed3184 --- /dev/null +++ b/changes/bug2716 @@ -0,0 +1,5 @@ + o Minor features: + - When a relay has failed several reachability tests, be more accurate + at recording when it became unreachable, so we can in turn provide + more accuracy at assigning Stable, Guard, HSDir, etc flags. Bugfix + on 0.2.0.6-alpha. Resolves bug 2716. diff --git a/changes/hsdir_assignment b/changes/hsdir_assignment new file mode 100644 index 0000000000..5c04b9b9bb --- /dev/null +++ b/changes/hsdir_assignment @@ -0,0 +1,8 @@ + o Security fixes: + - Directory authorities now use data collected from rephist when + choosing whether to assign the HSDir flag to relays, instead of + trusting the uptime value the relay reports in its descriptor. + This helps prevent an attack where a small set of nodes with + frequently-changing identity keys can blackhole a hidden service. + (Only authorities need upgrade; others will be fine once they do.) + Bugfix on 0.2.0.10-alpha; fixes bug 2709. diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 6be27d29e7..a54f232f51 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4671,6 +4671,29 @@ fetch_bridge_descriptors(or_options_t *options, time_t now) SMARTLIST_FOREACH_END(bridge); } +/** If our <b>bridge</b> is configured to be a different address than + * the bridge gives in its routerinfo <b>ri</b>, rewrite the routerinfo + * we received to use the address we meant to use. Now we handle + * multihomed bridges better. + */ +static void +rewrite_routerinfo_address_for_bridge(bridge_info_t *bridge, routerinfo_t *ri) +{ + tor_addr_t addr; + tor_addr_from_ipv4h(&addr, ri->addr); + + if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == ri->or_port) + return; /* they match, so no need to do anything */ + + ri->addr = tor_addr_to_ipv4h(&bridge->addr); + tor_free(ri->address); + ri->address = tor_dup_ip(ri->addr); + ri->or_port = bridge->port; + log_info(LD_DIR, "Adjusted bridge '%s' to match configured address %s:%d.", + ri->nickname, ri->address, ri->or_port); +} + /** We just learned a descriptor for a bridge. See if that * digest is in our entry guard list, and add it if not. */ void @@ -4689,6 +4712,8 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) if (!from_cache) download_status_reset(&bridge->fetch_status); + rewrite_routerinfo_address_for_bridge(bridge, ri); + add_an_entry_guard(ri, 1); log_notice(LD_DIR, "new bridge descriptor '%s' (%s)", ri->nickname, from_cache ? "cached" : "fresh"); diff --git a/src/or/dirserv.c b/src/or/dirserv.c index aeeab45383..18abd1865f 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -43,6 +43,8 @@ extern time_t time_of_process_start; /* from main.c */ +extern long stats_n_seconds_working; /* from main.c */ + /** Do we need to regenerate the v1 directory when someone asks for it? */ static time_t the_directory_is_dirty = 1; /** Do we need to regenerate the v1 runningrouters document when somebody @@ -969,8 +971,18 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now) } if (!answer && running_long_enough_to_decide_unreachable()) { - /* not considered reachable. tell rephist. */ - rep_hist_note_router_unreachable(router->cache_info.identity_digest, now); + /* Not considered reachable. tell rephist about that. + + Because we launch a reachability test for each router every + REACHABILITY_TEST_CYCLE_PERIOD seconds, then the router has probably + been down since at least that time after we last successfully reached + it. + */ + time_t when = now; + if (router->last_reachable && + router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now) + when = router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD; + rep_hist_note_router_unreachable(router->cache_info.identity_digest, when); } router->is_running = answer; @@ -1775,7 +1787,22 @@ dirserv_thinks_router_is_unreliable(time_t now, static int dirserv_thinks_router_is_hs_dir(routerinfo_t *router, time_t now) { - long uptime = real_uptime(router, now); + + long uptime; + + /* If we haven't been running for at least + * get_options()->MinUptimeHidServDirectoryV2 seconds, we can't + * have accurate data telling us a relay has been up for at least + * that long. We also want to allow a bit of slack: Reachability + * tests aren't instant. If we haven't been running long enough, + * trust the relay. */ + + if (stats_n_seconds_working > + get_options()->MinUptimeHidServDirectoryV2 * 1.1) + uptime = MIN(rep_hist_get_uptime(router->cache_info.identity_digest, now), + real_uptime(router, now)); + else + uptime = real_uptime(router, now); /* XXX We shouldn't need to check dir_port, but we do because of * bug 1693. In the future, once relays set wants_to_be_hs_dir @@ -3187,8 +3214,8 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router) * try a few connections per call. * * The load balancing is such that if we get called once every ten - * seconds, we will cycle through all the tests in 1280 seconds (a - * bit over 20 minutes). + * seconds, we will cycle through all the tests in + * REACHABILITY_TEST_CYCLE_PERIOD seconds (a bit over 20 minutes). */ void dirserv_test_reachability(time_t now) @@ -3214,11 +3241,11 @@ dirserv_test_reachability(time_t now) continue; /* bridge authorities only test reachability on bridges */ // if (router->cache_info.published_on > cutoff) // continue; - if ((((uint8_t)id_digest[0]) % 128) == ctr) { + if ((((uint8_t)id_digest[0]) % REACHABILITY_MODULO_PER_TEST) == ctr) { dirserv_single_reachability_test(now, router); } } SMARTLIST_FOREACH_END(router); - ctr = (ctr + 1) % 128; /* increment ctr */ + ctr = (ctr + 1) % REACHABILITY_MODULO_PER_TEST; /* increment ctr */ } /** Given a fingerprint <b>fp</b> which is either set if we're looking for a diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 56ad7a6a56..569abfca2e 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -12,6 +12,18 @@ #ifndef _TOR_DIRSERV_H #define _TOR_DIRSERV_H +/** What fraction (1 over this number) of the relay ID space do we + * (as a directory authority) launch connections to at each reachability + * test? */ +#define REACHABILITY_MODULO_PER_TEST 128 + +/** How often (in seconds) do we launch reachability tests? */ +#define REACHABILITY_TEST_INTERVAL 10 + +/** How many seconds apart are the reachability tests for a given relay? */ +#define REACHABILITY_TEST_CYCLE_PERIOD \ + (REACHABILITY_TEST_INTERVAL*REACHABILITY_MODULO_PER_TEST) + /** Maximum length of an exit policy summary. */ #define MAX_EXITPOLICY_SUMMARY_LEN 1000 diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 529b45c7d5..9273dbc90d 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -3080,7 +3080,7 @@ dirvote_compute_consensuses(void) n_votes = smartlist_len(pending_vote_list); if (n_votes <= n_voters/2) { log_warn(LD_DIR, "We don't have enough votes to generate a consensus: " - "%d of %d", n_votes, n_voters/2); + "%d of %d", n_votes, n_voters/2+1); goto err; } tor_assert(pending_vote_list); diff --git a/src/or/main.c b/src/or/main.c index 979a2bec5c..214a4fad5d 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -872,6 +872,7 @@ run_scheduled_events(time_t now) static time_t time_to_check_for_expired_networkstatus = 0; static time_t time_to_write_stats_files = 0; static time_t time_to_write_bridge_stats = 0; + static time_t time_to_launch_reachability_tests = 0; static int should_init_bridge_stats = 1; static time_t time_to_retry_dns_init = 0; or_options_t *options = get_options(); @@ -962,8 +963,10 @@ run_scheduled_events(time_t now) if (accounting_is_enabled(options)) accounting_run_housekeeping(now); - if (now % 10 == 0 && (authdir_mode_tests_reachability(options)) && - !we_are_hibernating()) { + if (time_to_launch_reachability_tests < now && + (authdir_mode_tests_reachability(options)) && + !we_are_hibernating()) { + time_to_launch_reachability_tests = now + REACHABILITY_TEST_INTERVAL; /* try to determine reachability of the other Tor relays */ dirserv_test_reachability(now); } diff --git a/src/or/or.h b/src/or/or.h index 3ce142556e..910bf8d8af 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3513,6 +3513,7 @@ typedef enum was_router_added_t { ROUTER_NOT_IN_CONSENSUS = -3, ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS = -4, ROUTER_AUTHDIR_REJECTS = -5, + ROUTER_WAS_NOT_WANTED = -6 } was_router_added_t; /********************************* routerparse.c ************************/ diff --git a/src/or/rephist.c b/src/or/rephist.c index 53214d61ef..e4afe62b67 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -528,6 +528,20 @@ get_weighted_fractional_uptime(or_history_t *hist, time_t when) return ((double) up) / total; } +/** Return how long the router whose identity digest is <b>id</b> has + * been reachable. Return 0 if the router is unknown or currently deemed + * unreachable. */ +long +rep_hist_get_uptime(const char *id, time_t when) +{ + or_history_t *hist = get_or_history(id); + if (!hist) + return 0; + if (!hist->start_of_run || when < hist->start_of_run) + return 0; + return when - hist->start_of_run; +} + /** Return an estimated MTBF for the router whose identity digest is * <b>id</b>. Return 0 if the router is unknown. */ double diff --git a/src/or/rephist.h b/src/or/rephist.h index 5f6b9f9b45..b06a39ed59 100644 --- a/src/or/rephist.h +++ b/src/or/rephist.h @@ -40,6 +40,7 @@ int rep_hist_record_mtbf_data(time_t now, int missing_means_down); int rep_hist_load_mtbf_data(time_t now); time_t rep_hist_downrate_old_runs(time_t now); +long rep_hist_get_uptime(const char *id, time_t when); double rep_hist_get_stability(const char *id, time_t when); double rep_hist_get_weighted_fractional_uptime(const char *id, time_t when); long rep_hist_get_weighted_time_known(const char *id, time_t when); diff --git a/src/or/router.c b/src/or/router.c index 4c5eb7a392..c15b9b236e 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -881,19 +881,14 @@ consider_testing_reachability(int test_or, int test_dir) void router_orport_found_reachable(void) { - if (!can_reach_or_port) { - routerinfo_t *me = router_get_my_routerinfo(); + routerinfo_t *me = router_get_my_routerinfo(); + if (!can_reach_or_port && me) { log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from " "the outside. Excellent.%s", get_options()->_PublishServerDescriptor != NO_AUTHORITY ? " Publishing server descriptor." : ""); can_reach_or_port = 1; mark_my_descriptor_dirty(); - if (!me) { /* should never happen */ - log_warn(LD_BUG, "ORPort found reachable, but I have no routerinfo " - "yet. Failing to inform controller of success."); - return; - } control_event_server_status(LOG_NOTICE, "REACHABILITY_SUCCEEDED ORADDRESS=%s:%d", me->address, me->or_port); @@ -904,18 +899,13 @@ router_orport_found_reachable(void) void router_dirport_found_reachable(void) { - if (!can_reach_dir_port) { - routerinfo_t *me = router_get_my_routerinfo(); + routerinfo_t *me = router_get_my_routerinfo(); + if (!can_reach_dir_port && me) { log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable " "from the outside. Excellent."); can_reach_dir_port = 1; - if (!me || decide_to_advertise_dirport(get_options(), me->dir_port)) + if (decide_to_advertise_dirport(get_options(), me->dir_port)) mark_my_descriptor_dirty(); - if (!me) { /* should never happen */ - log_warn(LD_BUG, "DirPort found reachable, but I have no routerinfo " - "yet. Failing to inform controller of success."); - return; - } control_event_server_status(LOG_NOTICE, "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d", me->address, me->dir_port); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 6d6386292f..4421d5cf81 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -3209,7 +3209,8 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, int from_cache, int from_fetch) { const char *id_digest; - int authdir = authdir_mode_handles_descs(get_options(), router->purpose); + or_options_t *options = get_options(); + int authdir = authdir_mode_handles_descs(options, router->purpose); int authdir_believes_valid = 0; routerinfo_t *old_router; networkstatus_t *consensus = networkstatus_get_latest_consensus(); @@ -3314,6 +3315,20 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, return ROUTER_NOT_IN_CONSENSUS; } + /* If we're reading a bridge descriptor from our cache, and we don't + * recognize it as one of our currently configured bridges, drop the + * descriptor. Otherwise we could end up using it as one of our entry + * guards even if it isn't in our Bridge config lines. */ + if (router->purpose == ROUTER_PURPOSE_BRIDGE && from_cache && + !authdir_mode_bridge(options) && + !routerinfo_is_a_configured_bridge(router)) { + log_info(LD_DIR, "Dropping bridge descriptor for '%s' because we have " + "no bridge configured at that address.", router->nickname); + *msg = "Router descriptor was not a configured bridge."; + routerinfo_free(router); + return ROUTER_WAS_NOT_WANTED; + } + /* If we have a router with the same identity key, choose the newer one. */ if (old_router) { if (!in_consensus && (router->cache_info.published_on <= |