[tor-commits] [tor/master] When IPv6 addresses have not been downloaded, use hard-coded address info

nickm at torproject.org nickm at torproject.org
Fri Jan 13 21:55:12 UTC 2017


commit 0417dae5808ddf86aed3a9b9a6883fa8f0922d2e
Author: teor <teor2345 at gmail.com>
Date:   Fri Dec 16 22:34:42 2016 +1100

    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.
---
 src/or/nodelist.c   | 21 ++++++++++++++++-----
 src/or/policies.c   | 44 ++++++++++++++++++++++++++++++++++++++++++--
 src/or/routerlist.c |  2 +-
 3 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 3f2e111..b29f217 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -1126,6 +1126,9 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
   node_assert_ok(node);
   tor_assert(ap_out);
 
+  /* Check ri first, because rewrite_node_address_for_bridge() updates
+   * node->ri with the configured bridge address. */
+
   RETURN_IPV4_AP(node->ri, or_port, ap_out);
   RETURN_IPV4_AP(node->rs, or_port, ap_out);
   /* Microdescriptors only have an IPv6 address */
@@ -1156,9 +1159,11 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
   node_assert_ok(node);
   tor_assert(ap_out);
 
-  /* Prefer routerstatus over microdesc for consistency with the
-   * fascist_firewall_* functions. Also check if the address or port are valid,
-   * and try another alternative if they are not. */
+  /* Check ri first, because rewrite_node_address_for_bridge() updates
+   * node->ri with the configured bridge address.
+   * Prefer rs over md for consistency with the fascist_firewall_* functions.
+   * Check if the address or port are valid, and try another alternative
+   * if they are not. */
 
   if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
                                          node->ri->ipv6_orport, 0)) {
@@ -1218,6 +1223,9 @@ node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out)
   node_assert_ok(node);
   tor_assert(ap_out);
 
+  /* Check ri first, because rewrite_node_address_for_bridge() updates
+   * node->ri with the configured bridge address. */
+
   RETURN_IPV4_AP(node->ri, dir_port, ap_out);
   RETURN_IPV4_AP(node->rs, dir_port, ap_out);
   /* Microdescriptors only have an IPv6 address */
@@ -1250,8 +1258,11 @@ node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
   node_assert_ok(node);
   tor_assert(ap_out);
 
-  /* Check if the address or port are valid, and try another alternative if
-   * they are not. Note that microdescriptors have no dir_port. */
+  /* Check ri first, because rewrite_node_address_for_bridge() updates
+   * node->ri with the configured bridge address.
+   * Prefer rs over md for consistency with the fascist_firewall_* functions.
+   * Check if the address or port are valid, and try another alternative
+   * if they are not. */
 
   /* Assume IPv4 and IPv6 dirports are the same */
   if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
diff --git a/src/or/policies.c b/src/or/policies.c
index dcee653..ac57e72 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));
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 6bac57d..0434195 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -948,7 +948,7 @@ authority_certs_fetch_resource_impl(const char *resource,
 
   /* If we've just downloaded a consensus from a bridge, re-use that
    * bridge */
-  if (options->UseBridges && node && !get_via_tor) {
+  if (options->UseBridges && node && node->ri && !get_via_tor) {
     /* clients always make OR connections to bridges */
     tor_addr_port_t or_ap;
     /* we are willing to use a non-preferred address if we need to */





More information about the tor-commits mailing list