From 2d8f7a8391014a07fc7d45f169cf2f719d819d61 Mon Sep 17 00:00:00 2001 From: Robert Hogan Date: Thu, 30 Sep 2010 21:41:20 +0100 Subject: Issues with router_get_by_nickname() https://trac.torproject.org/projects/tor/ticket/1859 There are two problems in this bug: 1. When an OP makes a .exit request specifying itself as the exit, and the exit is not yet listed, Tor gets all the routerinfos needed for the circuit but discovers in circuit_is_acceptable() that its own routerinfo is not in the routerdigest list and cannot be used. Tor then gets locked in a cycle of repeating these two steps. When gathering the routerinfos for a circuit, specifically when the exit has been chosen by .exit notation, Tor needs to apply the same rules it uses later on when deciding if it can build a circuit with those routerinfos. 2. A different bug arises in the above situation when the Tor instance's routerinfo *is* listed in the routerlist, it shares its nickname with a number of other Tor nodes, and it does not have 'Named' rights to its nickname. So for example, if (i) there are five nodes named Bob in the network, (ii) I am running one of them but am flagged as 'Unnamed' because someone else claimed the 'Bob' nickname first, and (iii) I run my Tor as both client and exit the following can happen to me: - I go to www.evil.com - I click on a link www.evil.com.bob.exit - My request will exit through my own Tor node rather than the 'Named' node Bob or any of the others. - www.evil.com now knows I am actually browsing from the same computer that is running my 'Bob' node So to solve both issues we need to ensure: - When fulfilling a .exit request we only choose a routerinfo if it exists in the routerlist, even when that routerinfo is ours. - When getting a router by nickname we only return our own router information if it is not going to be used for building a circuit. We ensure this by removing the special treatment afforded our own router in router_get_by_nickname(). This means the function will only return the routerinfo of our own router if it is in the routerlist built from authority info and has a unique nickname or is bound to a non-unique nickname. There are some uses of router_get_by_nickname() where we are looking for the router by name because of a configuration directive, specifically local declaration of NodeFamilies and EntryNodes and other routers' declaration of MyFamily. In these cases it is not at first clear if we need to continue returning our own routerinfo even if our router is not listed and/or has a non-unique nickname with the Unnamed flag. The patch treats each of these cases as follows: Other Routers' Declaration of MyFamily This happens in routerlist_add_family(). If another router declares our router in its family and our router has the Unnamed flag or is not in the routerlist yet, should we take advantage of the fact that we know our own routerinfo to add us in anyway? This patch says 'no, treat our own router just like any other'. This is a safe choice because it ensures our client has the same view of the network as other clients. We also have no good way of knowing if our router is Named or not independently of the authorities, so we have to rely on them in this. Local declaration of NodeFamilies Again, we have no way of knowing if the declaration 'NodeFamilies Bob,Alice,Ringo' refers to our router Bob or the Named router Bob, so we have to defer to the authorities and treat our own router like any other. Local declaration of NodeFamilies Again, same as above. There's also no good reason we would want our client to choose it's own router as an entry guard if it does not meet the requirements expected of any other router on the network. In order to reduce the possibility of error, the patch also replaces two instances where we were using router_get_by_nickname() with calls to router_get_by_hexdigest() where the identity digest of the router is available. --- src/or/connection_edge.c | 2 +- src/or/rendclient.c | 2 +- src/or/routerlist.c | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 6a3a5ef0a..15b0610d5 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -600,7 +600,7 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info) !edge_conn->chosen_exit_retries) continue; r1 = router_get_by_nickname(edge_conn->chosen_exit_name, 0); - r2 = router_get_by_nickname(info->nickname, 0); + r2 = router_get_by_hexdigest(info->identity_digest); if (!r1 || !r2 || r1 != r2) continue; tor_assert(edge_conn->socks_request); diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 68abb886a..6ff7f1896 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -755,7 +755,7 @@ rend_client_get_random_intro(const rend_data_t *rend_query) intro = smartlist_get(entry->parsed->intro_nodes, i); /* Do we need to look up the router or is the extend info complete? */ if (!intro->extend_info->onion_key) { - router = router_get_by_nickname(intro->extend_info->nickname, 0); + router = router_get_by_hexdigest(intro->extend_info->identity_digest); if (!router) { log_info(LD_REND, "Unknown router with nickname '%s'; trying another.", intro->extend_info->nickname); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 5fb4fe13c..915745532 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -2244,9 +2244,6 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed) return router_get_by_hexdigest(nickname); if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) return NULL; - if (server_mode(get_options()) && - !strcasecmp(nickname, get_options()->Nickname)) - return router_get_my_routerinfo(); maybedigest = (strlen(nickname) >= HEX_DIGEST_LEN) && (base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0); -- cgit v1.2.3 From 0acd5e6208bfeec2fbbef3941bbe4cd694cd61f8 Mon Sep 17 00:00:00 2001 From: Robert Hogan Date: Sun, 17 Oct 2010 12:27:57 +0100 Subject: Issues with router_get_by_nickname() https://trac.torproject.org/projects/tor/ticket/1859 Use router_get_by_digest() instead of router_get_by_hexdigest() in circuit_discard_optional_exit_enclaves() and rend_client_get_random_intro(), per Nick's comments. Using router_get_by_digest() in rend_client_get_random_intro() will break hidden services published by Tor versions pre 0.1.2.18 and 0.2.07-alpha as they only publish by nickname. This is acceptable however as these versions only publish to authority tor26 and don't work for versions in the 0.2.2.x series anyway. --- src/or/connection_edge.c | 2 +- src/or/rendclient.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 15b0610d5..ab2c9087a 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -600,7 +600,7 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info) !edge_conn->chosen_exit_retries) continue; r1 = router_get_by_nickname(edge_conn->chosen_exit_name, 0); - r2 = router_get_by_hexdigest(info->identity_digest); + r2 = router_get_by_digest(info->identity_digest); if (!r1 || !r2 || r1 != r2) continue; tor_assert(edge_conn->socks_request); diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 6ff7f1896..cc1c2733a 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -755,7 +755,7 @@ rend_client_get_random_intro(const rend_data_t *rend_query) intro = smartlist_get(entry->parsed->intro_nodes, i); /* Do we need to look up the router or is the extend info complete? */ if (!intro->extend_info->onion_key) { - router = router_get_by_hexdigest(intro->extend_info->identity_digest); + router = router_get_by_digest(intro->extend_info->identity_digest); if (!router) { log_info(LD_REND, "Unknown router with nickname '%s'; trying another.", intro->extend_info->nickname); -- cgit v1.2.3 From 69a496ba9810f5065f55af558932e84152ce50bc Mon Sep 17 00:00:00 2001 From: Robert Hogan Date: Sun, 17 Oct 2010 15:12:25 +0100 Subject: Issues with router_get_by_nickname() (3) Add changes file --- changes/bug1859 | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 changes/bug1859 diff --git a/changes/bug1859 b/changes/bug1859 new file mode 100644 index 000000000..5b139f357 --- /dev/null +++ b/changes/bug1859 @@ -0,0 +1,9 @@ + o Minor bugfixes: + - Bring the logic that gathers routerinfos and assesses the + acceptability of circuits into line. This prevents a Tor OP from getting + locked in a cycle of choosing its local OR as an exit for a path (due to + a .exit request) and then rejecting the circuit because its OR is not + listed yet. Also prevent Tor clients from using an OR running in the same + instance as an exit (due to a .exit request) if the OR does not meet the + same requirements expected of an OR running elsewhere. + Fixes bug 1859; bugfix on 0.2.0-alpha. -- cgit v1.2.3 From 5f3010667d9473d5c246ff77d6dc3d0ad4c4f30a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 21 Oct 2010 11:08:15 -0400 Subject: Fix a remaining bug in Robert's bug1859 fix. When intro->extend_info is created for an introduction point, it only starts out with a nickname, not necessarily an identity digest. Thus, doing router_get_by_digest isn't necessarily safe. --- src/or/rendclient.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/or/rendclient.c b/src/or/rendclient.c index cc1c2733a..3e1083f69 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -755,7 +755,10 @@ rend_client_get_random_intro(const rend_data_t *rend_query) intro = smartlist_get(entry->parsed->intro_nodes, i); /* Do we need to look up the router or is the extend info complete? */ if (!intro->extend_info->onion_key) { - router = router_get_by_digest(intro->extend_info->identity_digest); + if (tor_digest_is_zero(intro->extend_info->identity_digest)) + router = router_get_by_hexdigest(intro->extend_info->nickname); + else + router = router_get_by_digest(intro->extend_info->identity_digest); if (!router) { log_info(LD_REND, "Unknown router with nickname '%s'; trying another.", intro->extend_info->nickname); -- cgit v1.2.3