From 631ec5c4fe4d5535d91e8e1e3597fbaa687b8790 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 27 Mar 2012 15:00:34 +0200 Subject: [PATCH 01/12] Move last_reachable and testing_since from routerinfo_t to node_t. --- changes/bug5529 | 3 +++ src/or/dirserv.c | 31 +++++++++++++++---------- src/or/nodelist.c | 55 ++++++++++++++++++++++++++++++++++++++++----- src/or/nodelist.h | 3 ++- src/or/or.h | 17 +++++++------- src/or/routerlist.c | 10 ++------- 6 files changed, 84 insertions(+), 35 deletions(-) create mode 100644 changes/bug5529 diff --git a/changes/bug5529 b/changes/bug5529 new file mode 100644 index 0000000000..3f56e82047 --- /dev/null +++ b/changes/bug5529 @@ -0,0 +1,3 @@ + o Code refactoring: + - Move last_reachable and testing_since from routerinfo_t to + node_t. Implements enhancement 5529. diff --git a/src/or/dirserv.c b/src/or/dirserv.c index e21f5113f2..8f65b7fce4 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -988,7 +988,7 @@ 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; @@ -998,7 +998,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now) } 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); + answer = (now < node->last_reachable + REACHABLE_TIMEOUT); } if (!answer && running_long_enough_to_decide_unreachable()) { @@ -1010,9 +1010,9 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now) 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; + 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); } @@ -3277,15 +3277,17 @@ dirserv_orconn_tls_done(const char *address, uint16_t or_port, const char *digest_rcvd) { - routerinfo_t *ri; + node_t *node = NULL; + routerinfo_t *ri = NULL; time_t now = time(NULL); tor_assert(address); 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) return; + ri = node->ri; + tor_assert(ri); if (!strcasecmp(address, ri->address) && or_port == ri->or_port) { /* Found the right router. */ @@ -3302,7 +3304,7 @@ dirserv_orconn_tls_done(const char *address, 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; + node->last_reachable = now; } } } @@ -3338,12 +3340,17 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri, void dirserv_single_reachability_test(time_t now, routerinfo_t *router) { + node_t *node = NULL; tor_addr_t router_addr; + + tor_assert(router); + node = node_get_mutable_by_id(router->cache_info.identity_digest); + tor_assert(node); 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; + if (!node->testing_since) + node->testing_since = now; tor_addr_from_ipv4h(&router_addr, router->addr); connection_or_connect(&router_addr, router->or_port, router->cache_info.identity_digest); diff --git a/src/or/nodelist.c b/src/or/nodelist.c index d17850888d..1e07c82e35 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -115,13 +115,58 @@ node_get_or_create(const char *identity_digest) return node; } -/** Add ri to the nodelist. */ +/** Replace old router with new in nodelist. If + * old and new in fact are the same relays (having the + * same identity_digest) the node_t of old is used for + * new. Otherwise the node_t of old is dropped and + * new gets a new one (which might be a recycled node_t in + * case we already have one matching its identity). + */ node_t * -nodelist_add_routerinfo(routerinfo_t *ri) +nodelist_replace_routerinfo(routerinfo_t *old, routerinfo_t *new) { - node_t *node; - init_nodelist(); - node = node_get_or_create(ri->cache_info.identity_digest); + node_t *node = NULL; + tor_assert(old); + tor_assert(new); + + if (tor_memeq(old->cache_info.identity_digest, + new->cache_info.identity_digest, DIGEST_LEN)) { + /* NEW == OLD, reuse node_t. */ + node = node_get_mutable_by_id(old->cache_info.identity_digest); + if (node) { + tor_assert(node->ri == old); + /* XXXX prop186 we may have more than one address. */ + if (!routers_have_same_or_addr(old, new)) { + /* These mustn't carry over when the address and orport + change. */ + node->last_reachable = 0; + node->testing_since = 0; + } + } + } else { + /* NEW != OLD, get a new node_t. */ + nodelist_remove_routerinfo(old); + } + node = nodelist_add_routerinfo(node, new); + + return node; +} + + +/** Add ri to the nodelist. If node_in is not NULL, use + that node rather than creating a new. */ +node_t * +nodelist_add_routerinfo(node_t *node_in, routerinfo_t *ri) +{ + node_t *node = NULL; + + if (node_in) { + node = node_in; + } else { + tor_assert(ri); + init_nodelist(); + node = node_get_or_create(ri->cache_info.identity_digest); + } node->ri = ri; if (node->country == -1) diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 1e9da88d4e..b110fe52f7 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -15,7 +15,8 @@ node_t *node_get_mutable_by_id(const char *identity_digest); const node_t *node_get_by_id(const char *identity_digest); const node_t *node_get_by_hex_id(const char *identity_digest); -node_t *nodelist_add_routerinfo(routerinfo_t *ri); +node_t *nodelist_replace_routerinfo(routerinfo_t *old, routerinfo_t *new); +node_t *nodelist_add_routerinfo(node_t *node, routerinfo_t *ri); node_t *nodelist_add_microdesc(microdesc_t *md); void nodelist_set_consensus(networkstatus_t *ns); diff --git a/src/or/or.h b/src/or/or.h index 3a53e5ed86..a330f770e8 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1793,15 +1793,6 @@ typedef struct { * things; see notes on ROUTER_PURPOSE_* macros above. */ uint8_t purpose; - - /* The below items are used only by authdirservers for - * reachability testing. */ - - /** When was the last time we could reach this OR? */ - time_t last_reachable; - /** When did we start testing reachability for this OR? */ - time_t testing_since; - } routerinfo_t; /** Information needed to keep and cache a signed extra-info document. */ @@ -2037,6 +2028,14 @@ typedef struct node_t { /** According to the geoip db what country is this router in? */ country_t country; + + /* The below items are used only by authdirservers for + * reachability testing. */ + + /** When was the last time we could reach this OR? */ + time_t last_reachable; /* IPv4 */ + /** When did we start testing reachability for this OR? */ + time_t testing_since; /* IPv4 */ } node_t; /** How many times will we try to download a router's descriptor before giving diff --git a/src/or/routerlist.c b/src/or/routerlist.c index de1a66ce16..f984d93e8e 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -2875,7 +2875,7 @@ routerlist_insert(routerlist_t *rl, routerinfo_t *ri) &ri->cache_info); smartlist_add(rl->routers, ri); ri->cache_info.routerlist_index = smartlist_len(rl->routers) - 1; - nodelist_add_routerinfo(ri); + nodelist_add_routerinfo(NULL, ri); router_dir_info_changed(); #ifdef DEBUG_ROUTERLIST routerlist_assert_ok(rl); @@ -3104,8 +3104,7 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old, tor_assert(0 <= idx && idx < smartlist_len(rl->routers)); tor_assert(smartlist_get(rl->routers, idx) == ri_old); - nodelist_remove_routerinfo(ri_old); - nodelist_add_routerinfo(ri_new); + nodelist_replace_routerinfo(ri_old, ri_new); router_dir_info_changed(); if (idx >= 0) { @@ -3442,11 +3441,6 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, /* Same key, and either new, or listed in the consensus. */ log_debug(LD_DIR, "Replacing entry for router %s", router_describe(router)); - if (routers_have_same_or_addr(router, old_router)) { - /* these carry over when the address and orport are unchanged. */ - router->last_reachable = old_router->last_reachable; - router->testing_since = old_router->testing_since; - } routerlist_replace(routerlist, old_router, router); if (!from_cache) { signed_desc_append_to_journal(&router->cache_info, From c1ff07440e67f1ae690acbfceddb6174fdb092df Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 8 May 2012 14:53:59 +0200 Subject: [PATCH 02/12] Don't assume that a node has routerinfo. We can end up in dirserv_orconn_tls_done() with a node missing routerinfo in at least two cases -- command_process_certs_cell() and connection_or_check_valid_tls_handshake() -- and probably more. --- src/or/dirserv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 8f65b7fce4..3518d9ea57 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -3284,10 +3284,9 @@ dirserv_orconn_tls_done(const char *address, tor_assert(digest_rcvd); node = node_get_mutable_by_id(digest_rcvd); - if (node == NULL) + if (node == NULL || node->ri == NULL) return; ri = node->ri; - tor_assert(ri); if (!strcasecmp(address, ri->address) && or_port == ri->or_port) { /* Found the right router. */ From 4cce8ab742999900a4c5f1f3f8faf13d217014e0 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 May 2012 17:58:01 +0200 Subject: [PATCH 03/12] Add last_reachable and testing_since for IPv6 OR port. --- src/or/connection_or.c | 2 +- src/or/dirserv.c | 42 +++++++++++++++++++++++++++++++----------- src/or/dirserv.h | 2 +- src/or/nodelist.c | 4 ++-- src/or/or.h | 14 +++++++++----- src/or/router.c | 20 ++++++++++++++++++++ src/or/router.h | 2 ++ src/or/routerlist.c | 4 +++- 8 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/or/connection_or.c b/src/or/connection_or.c index d016387935..55ea32e57b 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -1540,7 +1540,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn, return -1; } if (authdir_mode_tests_reachability(options)) { - dirserv_orconn_tls_done(conn->_base.address, conn->_base.port, + dirserv_orconn_tls_done(&conn->_base.addr, conn->_base.port, (const char*)peer_id); } diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 3518d9ea57..ad3c45da7b 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -3273,14 +3273,15 @@ 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) { 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); node = node_get_mutable_by_id(digest_rcvd); @@ -3288,22 +3289,26 @@ dirserv_orconn_tls_done(const char *address, 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); - node->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; + } } } } @@ -3345,6 +3350,8 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router) 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 */ @@ -3353,6 +3360,19 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router) tor_addr_from_ipv4h(&router_addr, router->addr); connection_or_connect(&router_addr, router->or_port, router->cache_info.identity_digest); + + /* Possible IPv6. */ + if (!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); + if (!node->testing_since6) + node->testing_since6 = now; + connection_or_connect(&router->ipv6_addr, router->ipv6_orport, + router->cache_info.identity_digest); + } } /** Auth dir server only: load balance such that we only diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 22269b2009..8508c938a8 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -107,7 +107,7 @@ int dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key, int is_extrainfo); int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key, const char **msg); -void dirserv_orconn_tls_done(const char *address, +void dirserv_orconn_tls_done(const tor_addr_t *addr, uint16_t or_port, const char *digest_rcvd); int dirserv_should_launch_reachability_test(const routerinfo_t *ri, diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 1e07c82e35..cb94173985 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -139,8 +139,8 @@ nodelist_replace_routerinfo(routerinfo_t *old, routerinfo_t *new) if (!routers_have_same_or_addr(old, new)) { /* These mustn't carry over when the address and orport change. */ - node->last_reachable = 0; - node->testing_since = 0; + node->last_reachable = node->last_reachable6 = 0; + node->testing_since = node->testing_since6 = 0; } } } else { diff --git a/src/or/or.h b/src/or/or.h index a330f770e8..0684b9d6fe 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1997,13 +1997,13 @@ typedef struct node_t { routerstatus_t *rs; /* local info: copied from routerstatus, then possibly frobbed based - * on experience. Authorities set this stuff directly. */ + * on experience. Authorities set this stuff directly. Note that + * these reflect knowledge of the primary (IPv4) OR port only. */ unsigned int is_running:1; /**< As far as we know, is this OR currently * running? */ unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR? - * (For Authdir: Have we validated this OR?) - */ + * (For Authdir: Have we validated this OR?) */ unsigned int is_fast:1; /** Do we think this is a fast OR? */ unsigned int is_stable:1; /** Do we think this is a stable OR? */ unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */ @@ -2027,15 +2027,19 @@ typedef struct node_t { /* Local info: derived. */ /** According to the geoip db what country is this router in? */ + /* XXXprop186 what is this suppose to mean with multiple OR ports? */ country_t country; /* The below items are used only by authdirservers for * reachability testing. */ /** When was the last time we could reach this OR? */ - time_t last_reachable; /* IPv4 */ + time_t last_reachable; /* IPv4. */ + time_t last_reachable6; /* IPv6. */ + /** When did we start testing reachability for this OR? */ - time_t testing_since; /* IPv4 */ + time_t testing_since; /* IPv4. */ + time_t testing_since6; /* IPv6. */ } node_t; /** How many times will we try to download a router's descriptor before giving diff --git a/src/or/router.c b/src/or/router.c index df44a76d8a..20767d8a3f 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -2230,6 +2230,26 @@ router_get_pref_ipv6_orport(const routerinfo_t *router, ap_out->port = router->ipv6_orport; } +/** Return 1 if any of router's addresses are addr. + * Otherwise return 0. */ +int +router_has_addr(const routerinfo_t *router, const tor_addr_t *addr) +{ + return + tor_addr_eq_ipv4h(addr, router->addr) || + tor_addr_eq(&router->ipv6_addr, addr); +} + +int +router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport) +{ + return + (tor_addr_eq_ipv4h(&orport->addr, router->addr) && + orport->port == router->or_port) || + (tor_addr_eq(&orport->addr, &router->ipv6_addr) && + orport->port == router->ipv6_orport); +} + /** Load the contents of filename, find the last line starting with * end_line, ensure that its timestamp is not more than 25 hours in * the past or more than 1 hour in the future with respect to now, diff --git a/src/or/router.h b/src/or/router.h index 69805d6f2d..81df183953 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -93,6 +93,8 @@ void router_get_pref_orport(const routerinfo_t *router, void router_get_pref_ipv6_orport(const routerinfo_t *router, tor_addr_port_t *addr_port_out); int router_ipv6_preferred(const routerinfo_t *router); +int router_has_addr(const routerinfo_t *router, const tor_addr_t *addr); +int router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport); int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo, crypto_pk_t *ident_key); int is_legal_nickname(const char *s); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index f984d93e8e..cc47299fce 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1345,7 +1345,9 @@ mark_all_trusteddirservers_up(void) int routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2) { - return r1->addr == r2->addr && r1->or_port == r2->or_port; + return r1->addr == r2->addr && r1->or_port == r2->or_port && + tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) && + r1->ipv6_orport == r2->ipv6_orport; } /** Reset all internal variables used to count failed downloads of network From dda177b19e614c866d67a02aab1c0a83ca22760d Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 May 2012 19:29:46 +0200 Subject: [PATCH 04/12] Add "a" line to status document. --- src/or/dirserv.c | 17 +++++++++++++++++ src/or/or.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/src/or/dirserv.c b/src/or/dirserv.c index ad3c45da7b..2af4e688c7 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2088,6 +2088,21 @@ routerstatus_format_entry(char *buf, size_t buf_len, return 0; cp = buf + strlen(buf); + + /* Possible "a" line, not included in consensus for now. */ + if (!tor_addr_is_null(&rs->ipv6_addr)) { + char buf[TOR_ADDR_BUF_LEN]; + r = tor_snprintf(cp, buf_len - (cp-buf), + "a %s:%d\n", + tor_addr_to_str(buf, &rs->ipv6_addr, sizeof(buf), 1), + (int)rs->ipv6_orport); + if (r<0) { + log_warn(LD_BUG, "Not enough space in buffer."); + return -1; + } + cp += strlen(cp); + } + /* 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", @@ -2453,6 +2468,8 @@ 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; + tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); + rs->ipv6_orport = ri->ipv6_orport; } /** Routerstatus rs is part of a group of routers that are on diff --git a/src/or/or.h b/src/or/or.h index 0684b9d6fe..a8ef4d97c8 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1824,6 +1824,8 @@ typedef struct routerstatus_t { uint32_t addr; /**< IPv4 address for this router. */ uint16_t or_port; /**< OR port for this router. */ uint16_t dir_port; /**< Directory port for this router. */ + tor_addr_t ipv6_addr; /**< IPv6 address for this router. */ + uint16_t ipv6_orport; /** Date: Thu, 10 May 2012 17:08:22 +0200 Subject: [PATCH 05/12] Don't put unreachable IPv6 OR port in routerstatus. To have only reachable ports in "a" lines. --- src/or/dirserv.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 2af4e688c7..abbc123f91 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2468,8 +2468,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; - tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); - rs->ipv6_orport = ri->ipv6_orport; + if (!tor_addr_is_null(&ri->ipv6_addr) && + node->last_reachable6 >= now - REACHABLE_TIMEOUT) { + /* There's an IPv6 OR port and it's reachable so copy it to the + routerstatus. FIXME: If we're not on IPv6, copy it regardless + of reachability. */ + tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); + rs->ipv6_orport = ri->ipv6_orport; + } } /** Routerstatus rs is part of a group of routers that are on From 7c80a4502ce3f0b6d95bf2cee134a89765894b74 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 10 May 2012 18:48:30 +0200 Subject: [PATCH 06/12] Include IPv6 OR ports in status documents only if we're a bridge authority. --- src/or/dirserv.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/or/dirserv.c b/src/or/dirserv.c index abbc123f91..2d9387ee19 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2468,11 +2468,13 @@ 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 (!tor_addr_is_null(&ri->ipv6_addr) && + if (authdir_mode_bridge(options) && + !tor_addr_is_null(&ri->ipv6_addr) && node->last_reachable6 >= now - REACHABLE_TIMEOUT) { - /* There's an IPv6 OR port and it's reachable so copy it to the - routerstatus. FIXME: If we're not on IPv6, copy it regardless - of reachability. */ + /* We're a bridge authority (we're not ready for IPv6 relays in + the consensus quite yet). There's an IPv6 OR port and it's + reachable so copy it to the routerstatus. FIXME: If we're not + on IPv6, copy it regardless of reachability. */ tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); rs->ipv6_orport = ri->ipv6_orport; } From cdef2b181a0a7690736132542fbc5307d5c38955 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 11 May 2012 10:22:45 +0200 Subject: [PATCH 07/12] Rename routers_have_same_or_addr() to reflect the fact that it now checks both OR ports. --- src/or/dirserv.c | 2 +- src/or/nodelist.c | 3 +-- src/or/routerlist.c | 2 +- src/or/routerlist.h | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 2d9387ee19..4d6f93d180 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -3356,7 +3356,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; } diff --git a/src/or/nodelist.c b/src/or/nodelist.c index cb94173985..bbbb9ebc3a 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -135,8 +135,7 @@ nodelist_replace_routerinfo(routerinfo_t *old, routerinfo_t *new) node = node_get_mutable_by_id(old->cache_info.identity_digest); if (node) { tor_assert(node->ri == old); - /* XXXX prop186 we may have more than one address. */ - if (!routers_have_same_or_addr(old, new)) { + if (!routers_have_same_or_addrs(old, new)) { /* These mustn't carry over when the address and orport change. */ node->last_reachable = node->last_reachable6 = 0; diff --git a/src/or/routerlist.c b/src/or/routerlist.c index cc47299fce..a349a4d0d8 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1343,7 +1343,7 @@ mark_all_trusteddirservers_up(void) /** Return true iff r1 and r2 have the same address and OR port. */ int -routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2) +routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2) { return r1->addr == r2->addr && r1->or_port == r2->or_port && tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) && diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 8dcc6eb026..e84b0405d4 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -36,7 +36,7 @@ const routerstatus_t *router_pick_trusteddirserver(dirinfo_type_t type, int router_get_my_share_of_directory_requests(double *v2_share_out, double *v3_share_out); void router_reset_status_download_failures(void); -int routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2); +int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2); int router_nickname_is_in_list(const routerinfo_t *router, const char *list); const routerinfo_t *routerlist_find_my_routerinfo(void); const node_t *router_find_exact_exit_enclave(const char *address, From 044da1bf0f3bf6299c33d837839ec80ca1966723 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Mon, 28 May 2012 14:41:04 +0200 Subject: [PATCH 08/12] Add configure option AuthDirHasIPv6Connectivity. Implements enhancement 5974. --- changes/bug5974 | 4 ++++ doc/tor.1.txt | 8 ++++++++ src/or/config.c | 1 + src/or/dirserv.c | 7 ++++--- src/or/or.h | 1 + 5 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 changes/bug5974 diff --git a/changes/bug5974 b/changes/bug5974 new file mode 100644 index 0000000000..c016be13b5 --- /dev/null +++ b/changes/bug5974 @@ -0,0 +1,4 @@ + o Minor features: + + - Add new configure option AuthDirHasIPv6Connectivity. Implements + feature #5974. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 78c34874c5..3cf257cb15 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1728,6 +1728,14 @@ DIRECTORY AUTHORITY SERVER OPTIONS votes on whether to accept relays as hidden service directories. (Default: 1) +**AuthDirHasIPv6Connectivity** **0**|**1**|**auto**:: + + Authoritative directories only. When set to 0, OR ports with an + IPv6 address are being accepted without reachability testing. + When set to 1, IPv6 OR ports are being tested just like IPv4 OR + ports. When set to auto, Tor tries to find out if the authority + relay has IPv6 connectivity or not. (Default: auto) + HIDDEN SERVICE OPTIONS ---------------------- diff --git a/src/or/config.c b/src/or/config.c index bfa8c7fad8..87c9cc4bb7 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -201,6 +201,7 @@ static config_var_t _option_vars[] = { V(AuthDirListBadExits, BOOL, "0"), V(AuthDirMaxServersPerAddr, UINT, "2"), V(AuthDirMaxServersPerAuthAddr,UINT, "5"), + V(AuthDirHasIPv6Connectivity, AUTOBOOL, "auto"), VAR("AuthoritativeDirectory", BOOL, AuthoritativeDir, "0"), V(AutomapHostsOnResolve, BOOL, "0"), V(AutomapHostsSuffixes, CSV, ".onion,.exit"), diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 4d6f93d180..6f16469540 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2470,11 +2470,12 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, rs->dir_port = ri->dir_port; if (authdir_mode_bridge(options) && !tor_addr_is_null(&ri->ipv6_addr) && - node->last_reachable6 >= now - REACHABLE_TIMEOUT) { + (options->AuthDirHasIPv6Connectivity == 0 || + node->last_reachable6 >= now - REACHABLE_TIMEOUT)) { /* We're a bridge authority (we're not ready for IPv6 relays in the consensus quite yet). There's an IPv6 OR port and it's - reachable so copy it to the routerstatus. FIXME: If we're not - on IPv6, copy it regardless of reachability. */ + reachable (or we know that we're not on IPv6) so copy it to the + routerstatus. */ tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); rs->ipv6_orport = ri->ipv6_orport; } diff --git a/src/or/or.h b/src/or/or.h index a8ef4d97c8..9474c00fae 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3273,6 +3273,7 @@ typedef struct { int AuthDirMaxServersPerAuthAddr; /**< Do not permit more than this * number of servers per IP address shared * with an authority. */ + int AuthDirHasIPv6Connectivity; /**< Autoboolean: are we on IPv6? */ /** If non-zero, always vote the Fast flag for any relay advertising * this amount of capacity or more. */ From 0fe6dde4b24fde9a63326e6cf9fd71e2247621c7 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 29 May 2012 09:08:46 +0200 Subject: [PATCH 09/12] Add changes file for #5534. --- changes/bug5534 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug5534 diff --git a/changes/bug5534 b/changes/bug5534 new file mode 100644 index 0000000000..1518317497 --- /dev/null +++ b/changes/bug5534 @@ -0,0 +1,4 @@ + o Major features (IPv6): + Add support for bridge authorities to accept IPv6 bridge addresses + and include them in network status documents. Implements + enhancement 5534. From dee4f068ee8be3d424aaa300168564f4abd18a36 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 31 May 2012 18:34:12 +0200 Subject: [PATCH 10/12] Don't shadow 'buf'. --- src/or/dirserv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 6f16469540..7020d5b2a3 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2091,10 +2091,10 @@ routerstatus_format_entry(char *buf, size_t buf_len, /* Possible "a" line, not included in consensus for now. */ if (!tor_addr_is_null(&rs->ipv6_addr)) { - char buf[TOR_ADDR_BUF_LEN]; + const char *addr_str = fmt_and_decorate_addr(&rs->ipv6_addr); r = tor_snprintf(cp, buf_len - (cp-buf), "a %s:%d\n", - tor_addr_to_str(buf, &rs->ipv6_addr, sizeof(buf), 1), + addr_str, (int)rs->ipv6_orport); if (r<0) { log_warn(LD_BUG, "Not enough space in buffer."); From 6208106c18c696756fe2be8f941992e31aa66a8d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 17 Jul 2012 20:00:19 -0400 Subject: [PATCH 11/12] Try to re-approximate the older semantics of nodelist_add_routerinfo --- src/or/nodelist.c | 73 ++++++++++++++++++--------------------------- src/or/nodelist.h | 3 +- src/or/routerlist.c | 8 +++-- 3 files changed, 36 insertions(+), 48 deletions(-) diff --git a/src/or/nodelist.c b/src/or/nodelist.c index bbbb9ebc3a..6ce8dcf2c7 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -115,63 +115,48 @@ node_get_or_create(const char *identity_digest) return node; } -/** Replace old router with new in nodelist. If - * old and new in fact are the same relays (having the - * same identity_digest) the node_t of old is used for - * new. Otherwise the node_t of old is dropped and - * new gets a new one (which might be a recycled node_t in - * case we already have one matching its identity). - */ -node_t * -nodelist_replace_routerinfo(routerinfo_t *old, routerinfo_t *new) +/** Called when a node's address changes. */ +static void +node_addrs_changed(node_t *node) { - node_t *node = NULL; - tor_assert(old); - tor_assert(new); - - if (tor_memeq(old->cache_info.identity_digest, - new->cache_info.identity_digest, DIGEST_LEN)) { - /* NEW == OLD, reuse node_t. */ - node = node_get_mutable_by_id(old->cache_info.identity_digest); - if (node) { - tor_assert(node->ri == old); - if (!routers_have_same_or_addrs(old, new)) { - /* These mustn't carry over when the address and orport - change. */ - node->last_reachable = node->last_reachable6 = 0; - node->testing_since = node->testing_since6 = 0; - } - } - } else { - /* NEW != OLD, get a new node_t. */ - nodelist_remove_routerinfo(old); - } - node = nodelist_add_routerinfo(node, new); - - return node; + node->last_reachable = node->last_reachable6 = 0; + node->testing_since = node->testing_since6 = 0; + node->country = -1; } - -/** Add ri to the nodelist. If node_in is not NULL, use - that node rather than creating a new. */ +/** Add ri to an appropriate node in the nodelist. If we replace an + * old routerinfo, and ri_old_out is not NULL, set *ri_old_out + * to the previous routerinfo. + */ node_t * -nodelist_add_routerinfo(node_t *node_in, routerinfo_t *ri) +nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out) { - node_t *node = NULL; + node_t *node; + const char *id_digest; + int had_router = 0; + tor_assert(ri); - if (node_in) { - node = node_in; + init_nodelist(); + id_digest = ri->cache_info.identity_digest; + node = node_get_or_create(id_digest); + + if (node->ri) { + if (!routers_have_same_or_addrs(node->ri, ri)) { + node_addrs_changed(node); + } + had_router = 1; + if (ri_old_out) + *ri_old_out = node->ri; } else { - tor_assert(ri); - init_nodelist(); - node = node_get_or_create(ri->cache_info.identity_digest); + if (ri_old_out) + *ri_old_out = NULL; } node->ri = ri; if (node->country == -1) node_set_country(node); - if (authdir_mode(get_options())) { + if (authdir_mode(get_options()) && !had_router) { const char *discard=NULL; uint32_t status = dirserv_router_get_status(ri, &discard); dirserv_set_node_flags_from_authoritative_status(node, status); diff --git a/src/or/nodelist.h b/src/or/nodelist.h index b110fe52f7..6c1d541483 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -15,8 +15,7 @@ node_t *node_get_mutable_by_id(const char *identity_digest); const node_t *node_get_by_id(const char *identity_digest); const node_t *node_get_by_hex_id(const char *identity_digest); -node_t *nodelist_replace_routerinfo(routerinfo_t *old, routerinfo_t *new); -node_t *nodelist_add_routerinfo(node_t *node, routerinfo_t *ri); +node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out); node_t *nodelist_add_microdesc(microdesc_t *md); void nodelist_set_consensus(networkstatus_t *ns); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index a349a4d0d8..c96a7268b8 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -2877,7 +2877,7 @@ routerlist_insert(routerlist_t *rl, routerinfo_t *ri) &ri->cache_info); smartlist_add(rl->routers, ri); ri->cache_info.routerlist_index = smartlist_len(rl->routers) - 1; - nodelist_add_routerinfo(NULL, ri); + nodelist_set_routerinfo(ri, NULL); router_dir_info_changed(); #ifdef DEBUG_ROUTERLIST routerlist_assert_ok(rl); @@ -3106,7 +3106,11 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old, tor_assert(0 <= idx && idx < smartlist_len(rl->routers)); tor_assert(smartlist_get(rl->routers, idx) == ri_old); - nodelist_replace_routerinfo(ri_old, ri_new); + { + routerinfo_t *ri_old_tmp=NULL; + nodelist_set_routerinfo(ri_new, &ri_old_tmp); + tor_assert(ri_old == ri_old_tmp); + } router_dir_info_changed(); if (idx >= 0) { From fff842a47c7aca7cc8d49ac0e487fa3c6a536c96 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 19 Jul 2012 23:23:22 +0200 Subject: [PATCH 12/12] Add config option AuthDirPublishIPv6. Test for config option AuthDirPublishIPv6 == 1 rather than for running as a bridge authority when deciding whether to care or not about IPv6 OR ports in descriptors. Implements enhancement #6406. --- changes/enh6406 | 4 ++++ doc/tor.1.txt | 6 ++++++ src/or/config.c | 1 + src/or/dirserv.c | 9 ++++----- src/or/or.h | 1 + 5 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 changes/enh6406 diff --git a/changes/enh6406 b/changes/enh6406 new file mode 100644 index 0000000000..08349b2e32 --- /dev/null +++ b/changes/enh6406 @@ -0,0 +1,4 @@ + o Minor features: + + - Add new configure option AuthDirPublishIPv6. Implements + enhancement #6406. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 3cf257cb15..364bfdc2f4 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1736,6 +1736,12 @@ DIRECTORY AUTHORITY SERVER OPTIONS ports. When set to auto, Tor tries to find out if the authority relay has IPv6 connectivity or not. (Default: auto) +**AuthDirPublishIPv6** **0**|**1**:: + + Authoritative directories only. When set to 0, Tor will not + include IPv6 OR ports in votes. When set to 1, Tor will vote for + IPv6 OR ports. (Default: 0). + HIDDEN SERVICE OPTIONS ---------------------- diff --git a/src/or/config.c b/src/or/config.c index 87c9cc4bb7..1a378c2271 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -202,6 +202,7 @@ static config_var_t _option_vars[] = { V(AuthDirMaxServersPerAddr, UINT, "2"), V(AuthDirMaxServersPerAuthAddr,UINT, "5"), V(AuthDirHasIPv6Connectivity, AUTOBOOL, "auto"), + V(AuthDirPublishIPv6, BOOL, "0"), VAR("AuthoritativeDirectory", BOOL, AuthoritativeDir, "0"), V(AutomapHostsOnResolve, BOOL, "0"), V(AutomapHostsSuffixes, CSV, ".onion,.exit"), diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 7020d5b2a3..d12ed8a811 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2468,14 +2468,13 @@ 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 (authdir_mode_bridge(options) && + if (options->AuthDirPublishIPv6 == 1 && !tor_addr_is_null(&ri->ipv6_addr) && (options->AuthDirHasIPv6Connectivity == 0 || node->last_reachable6 >= now - REACHABLE_TIMEOUT)) { - /* We're a bridge authority (we're not ready for IPv6 relays in - the consensus quite yet). There's an IPv6 OR port and it's - reachable (or we know that we're not on IPv6) so copy it to the - routerstatus. */ + /* We're configured for publishing IPv6 OR ports. There's an IPv6 + OR port and it's reachable (or we know that we're not on IPv6) + so copy it to the routerstatus. */ tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); rs->ipv6_orport = ri->ipv6_orport; } diff --git a/src/or/or.h b/src/or/or.h index 9474c00fae..b6cffd4bea 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3274,6 +3274,7 @@ typedef struct { * number of servers per IP address shared * with an authority. */ int AuthDirHasIPv6Connectivity; /**< Autoboolean: are we on IPv6? */ + int AuthDirPublishIPv6; /**< Boolean: should we list IPv6 OR ports? */ /** If non-zero, always vote the Fast flag for any relay advertising * this amount of capacity or more. */