|
@@ -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));
|