summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2011-03-14 17:21:36 -0400
committerRoger Dingledine <arma@torproject.org>2011-03-14 17:21:36 -0400
commit626912a81a9d494d496de38c4fd46e058d9039f2 (patch)
tree09a4d999abfb35b7430b191c504f634be6aa91f9
parentaf04bd489b79acd4614119f26944fac2835fe641 (diff)
parentb97d9abd0940037b249a1ee56724dbfed904263b (diff)
downloadtor-626912a81a9d494d496de38c4fd46e058d9039f2.tar.gz
tor-626912a81a9d494d496de38c4fd46e058d9039f2.zip
Merge branch 'maint-0.2.2' into release-0.2.2
-rw-r--r--changes/bug11729
-rw-r--r--changes/bug25108
-rw-r--r--changes/bug25116
-rw-r--r--changes/bug27165
-rw-r--r--changes/hsdir_assignment8
-rw-r--r--src/or/circuitbuild.c25
-rw-r--r--src/or/dirserv.c41
-rw-r--r--src/or/dirserv.h12
-rw-r--r--src/or/dirvote.c2
-rw-r--r--src/or/main.c7
-rw-r--r--src/or/or.h1
-rw-r--r--src/or/rephist.c14
-rw-r--r--src/or/rephist.h1
-rw-r--r--src/or/router.c20
-rw-r--r--src/or/routerlist.c17
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 <=