diff options
-rw-r--r-- | changes/bug2510 | 8 | ||||
-rw-r--r-- | changes/bug2511 | 6 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 55 | ||||
-rw-r--r-- | src/or/or.h | 1 | ||||
-rw-r--r-- | src/or/routerlist.c | 17 |
5 files changed, 84 insertions, 3 deletions
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/src/or/circuitbuild.c b/src/or/circuitbuild.c index 7ad3b07500..e2b5f138d9 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4688,6 +4688,55 @@ 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 <b>node</b>, rewrite the routerinfo + * we received to use the address we meant to use. Now we handle + * multihomed bridges better. + */ +static void +rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) +{ + /* XXXX move this function. */ + /* XXXX overridden addresses should really live in the node_t, so that the + * routerinfo_t and the microdesc_t can be immutable. But we can only + * do that safely if + */ + tor_addr_t addr; + + if (node->ri) { + routerinfo_t *ri = node->ri; + tor_addr_from_ipv4h(&addr, ri->addr); + + if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == ri->or_port) { + /* they match, so no need to do anything */ + } else { + 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); + } + } + if (node->rs) { + routerstatus_t *rs = node->rs; + tor_addr_from_ipv4h(&addr, rs->addr); + + if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == rs->or_port) { + /* they match, so no need to do anything */ + } else { + rs->addr = tor_addr_to_ipv4h(&bridge->addr); + rs->or_port = bridge->port; + log_info(LD_DIR, + "Adjusted bridge '%s' to match configured address %s:%d.", + rs->nickname, fmt_addr(&bridge->addr), rs->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 @@ -4702,14 +4751,16 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) router_set_status(ri->cache_info.identity_digest, 1); if (bridge) { /* if we actually want to use this one */ - const node_t *node; + node_t *node; /* it's here; schedule its re-fetch for a long time from now. */ if (!from_cache) download_status_reset(&bridge->fetch_status); - node = node_get_by_id(ri->cache_info.identity_digest); + node = node_get_mutable_by_id(ri->cache_info.identity_digest); tor_assert(node); + rewrite_node_address_for_bridge(bridge, node); add_an_entry_guard(node, 1); + log_notice(LD_DIR, "new bridge descriptor '%s' (%s)", ri->nickname, from_cache ? "cached" : "fresh"); /* set entry->made_contact so if it goes down we don't drop it from diff --git a/src/or/or.h b/src/or/or.h index 323c472e47..553afbdb7b 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3687,6 +3687,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/routerlist.c b/src/or/routerlist.c index 66066f68d1..1205fd1234 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -3233,7 +3233,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(); @@ -3339,6 +3340,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 <= |