diff options
author | teor <teor2345@gmail.com> | 2016-12-16 22:34:42 +1100 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2017-01-13 16:49:33 -0500 |
commit | 0417dae5808ddf86aed3a9b9a6883fa8f0922d2e (patch) | |
tree | abe901ae769502b7600ffad7546a968afce9a13f /src/or/policies.c | |
parent | 5227ff4aadcb41f8758d426bf8ddfb4fb2d82cdf (diff) | |
download | tor-0417dae5808ddf86aed3a9b9a6883fa8f0922d2e.tar.gz tor-0417dae5808ddf86aed3a9b9a6883fa8f0922d2e.zip |
When IPv6 addresses have not been downloaded, use hard-coded address info
The microdesc consensus does not contain any IPv6 addresses.
When a client has a microdesc consensus but no microdescriptor, make it
use the hard-coded IPv6 address for the node (if available).
(Hard-coded addresses can come from authorities, fallback directories,
or configured bridges.)
If there is no hard-coded address, log a BUG message, and fail the
connection attempt. (All existing code checks for a hard-coded address
before choosing a node address.)
Fixes 20996, fix on b167e82 from 19608 in 0.2.8.5-alpha.
Diffstat (limited to 'src/or/policies.c')
-rw-r--r-- | src/or/policies.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/src/or/policies.c b/src/or/policies.c index dcee65301c..ac57e7209f 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -20,6 +20,7 @@ #include "or.h" #include "config.h" #include "dirserv.h" +#include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "policies.h" @@ -893,6 +894,33 @@ fascist_firewall_choose_address_ipv4h(uint32_t ipv4h_addr, pref_ipv6, ap); } +/* The microdescriptor consensus has no IPv6 addresses in rs: they are in + * the microdescriptors. This means we can't rely on the node's IPv6 address + * until its microdescriptor is available (when using microdescs). + * But for bridges, rewrite_node_address_for_bridge() updates node->ri with + * the configured address, so we can trust bridge addresses. + * (Bridges could gain an IPv6 address if their microdescriptor arrives, but + * this will never be their preferred address: that is in the config.) + * Returns true if the node needs a microdescriptor for its IPv6 address, and + * false if the addresses in the node are already up-to-date. + */ +static int +node_awaiting_ipv6(const or_options_t* options, const node_t *node) +{ + tor_assert(node); + + /* There's no point waiting for an IPv6 address if we'd never use it */ + if (!fascist_firewall_use_ipv6(options)) { + return 0; + } + + /* We are waiting if we_use_microdescriptors_for_circuits() and we have no + * md. Bridges have a ri based on their config. They would never use the + * address from their md, so there's no need to wait for it. */ + return (!node->md && we_use_microdescriptors_for_circuits(options) && + !node->ri); +} + /** Like fascist_firewall_choose_address_base(), but takes <b>rs</b>. * Consults the corresponding node, then falls back to rs if node is NULL. * This should only happen when there's no valid consensus, and rs doesn't @@ -909,15 +937,15 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs, tor_assert(ap); + const or_options_t *options = get_options(); const node_t *node = node_get_by_id(rs->identity_digest); - if (node) { + if (node && !node_awaiting_ipv6(options, node)) { return fascist_firewall_choose_address_node(node, fw_connection, pref_only, ap); } else { /* There's no node-specific IPv6 preference, so use the generic IPv6 * preference instead. */ - const or_options_t *options = get_options(); int pref_ipv6 = (fw_connection == FIREWALL_OR_CONNECTION ? fascist_firewall_prefer_ipv6_orport(options) : fascist_firewall_prefer_ipv6_dirport(options)); @@ -951,6 +979,18 @@ fascist_firewall_choose_address_node(const node_t *node, node_assert_ok(node); + /* Calling fascist_firewall_choose_address_node() when the node is missing + * IPv6 information breaks IPv6-only clients. + * If the node is a hard-coded fallback directory or authority, call + * fascist_firewall_choose_address_rs() on the fake (hard-coded) routerstatus + * for the node. + * If it is not hard-coded, check that the node has a microdescriptor, full + * descriptor (routerinfo), or is one of our configured bridges before + * calling this function. */ + if (BUG(node_awaiting_ipv6(get_options(), node))) { + return 0; + } + const int pref_ipv6_node = (fw_connection == FIREWALL_OR_CONNECTION ? node_ipv6_or_preferred(node) : node_ipv6_dir_preferred(node)); |