aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2017-12-12 09:27:03 -0500
committerNick Mathewson <nickm@torproject.org>2017-12-12 09:27:03 -0500
commite622f208a316cf3388003c1cdd1961eaaa8c370d (patch)
treecc874db33a4fb8ce7b57f53c2bbb17e94a2eed7c
parent9c604e2bbb10f7637316f2e0e226eb4669b7f4ac (diff)
parent94ad47e332940aee3e1a04beeebac03b3803e085 (diff)
downloadtor-e622f208a316cf3388003c1cdd1961eaaa8c370d.tar.gz
tor-e622f208a316cf3388003c1cdd1961eaaa8c370d.zip
Merge remote-tracking branch 'teor/bug23827-v2'
-rw-r--r--changes/bug238278
-rw-r--r--src/or/networkstatus.c26
-rw-r--r--src/or/networkstatus.h1
-rw-r--r--src/or/policies.c31
-rw-r--r--src/test/test_dir.c101
5 files changed, 160 insertions, 7 deletions
diff --git a/changes/bug23827 b/changes/bug23827
new file mode 100644
index 0000000000..75279abb85
--- /dev/null
+++ b/changes/bug23827
@@ -0,0 +1,8 @@
+ o Minor feature (IPv6):
+ - When a consensus has IPv6 ORPorts, make IPv6-only clients use them,
+ rather than waiting to download microdescriptors.
+ Implements 23827.
+ - Make IPv6-only clients wait for microdescs for relays, even if we were
+ previously using descriptors (or were using them as a bridge) and have
+ a cached descriptor for them.
+ Implements 23827.
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 2843d06262..61cca1b9b6 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1507,6 +1507,32 @@ networkstatus_consensus_is_already_downloading(const char *resource)
return answer;
}
+/* Does the current, reasonably live consensus have IPv6 addresses?
+ * Returns 1 if there is a reasonably live consensus and its consensus method
+ * includes IPv6 addresses in the consensus.
+ * Otherwise, if there is no consensus, or the method does not include IPv6
+ * addresses, returns 0. */
+int
+networkstatus_consensus_has_ipv6(const or_options_t* options)
+{
+ const networkstatus_t *cons = networkstatus_get_reasonably_live_consensus(
+ approx_time(),
+ usable_consensus_flavor());
+
+ /* If we have no consensus, we have no IPv6 in it */
+ if (!cons) {
+ return 0;
+ }
+
+ /* Different flavours of consensus gained IPv6 at different times */
+ if (we_use_microdescriptors_for_circuits(options)) {
+ return
+ cons->consensus_method >= MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
+ } else {
+ return cons->consensus_method >= MIN_METHOD_FOR_A_LINES;
+ }
+}
+
/** Given two router status entries for the same router identity, return 1 if
* if the contents have changed between them. Otherwise, return 0. */
static int
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index 791e32adc4..1851a55e82 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -93,6 +93,7 @@ int networkstatus_consensus_can_use_multiple_directories(
MOCK_DECL(int, networkstatus_consensus_can_use_extra_fallbacks,(
const or_options_t *options));
int networkstatus_consensus_is_already_downloading(const char *resource);
+int networkstatus_consensus_has_ipv6(const or_options_t* options);
#define NSSET_FROM_CACHE 1
#define NSSET_WAS_WAITING_FOR_CERTS 2
diff --git a/src/or/policies.c b/src/or/policies.c
index fc033c5593..a5bde2fe7a 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -18,6 +18,7 @@
#define POLICIES_PRIVATE
#include "or.h"
+#include "bridges.h"
#include "config.h"
#include "dirserv.h"
#include "microdesc.h"
@@ -893,9 +894,10 @@ 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).
+/* Some microdescriptor consensus methods have no IPv6 addresses in rs: they
+ * are in the microdescriptors. For these consensus methods, 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
@@ -913,11 +915,26 @@ node_awaiting_ipv6(const or_options_t* options, const node_t *node)
return 0;
}
+ /* If the node has an IPv6 address, we're not waiting */
+ if (node_has_ipv6_addr(node)) {
+ return 0;
+ }
+
+ /* If the current consensus method and flavour has IPv6 addresses, we're not
+ * waiting */
+ if (networkstatus_consensus_has_ipv6(options)) {
+ return 0;
+ }
+
+ /* Bridge clients never use the address from a bridge's md, so there's no
+ * need to wait for it. */
+ if (node_is_a_configured_bridge(node)) {
+ 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);
+ * md. */
+ return (!node->md && we_use_microdescriptors_for_circuits(options));
}
/** Like fascist_firewall_choose_address_base(), but takes <b>rs</b>.
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index ee7aea5b84..c85f7f0652 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -6174,6 +6174,106 @@ test_dir_platform_str(void *arg)
;
}
+static networkstatus_t *mock_networkstatus;
+
+static networkstatus_t *
+mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
+{
+ (void)f;
+ return mock_networkstatus;
+}
+
+static void
+test_dir_networkstatus_consensus_has_ipv6(void *arg)
+{
+ (void)arg;
+
+ int has_ipv6 = 0;
+
+ /* Init options and networkstatus */
+ or_options_t our_options;
+ mock_options = &our_options;
+ reset_options(mock_options, &mock_get_options_calls);
+ MOCK(get_options, mock_get_options);
+
+ networkstatus_t our_networkstatus;
+ mock_networkstatus = &our_networkstatus;
+ memset(mock_networkstatus, 0, sizeof(*mock_networkstatus));
+ MOCK(networkstatus_get_latest_consensus_by_flavor,
+ mock_networkstatus_get_latest_consensus_by_flavor);
+
+ /* A live consensus */
+ mock_networkstatus->valid_after = time(NULL) - 3600;
+ mock_networkstatus->valid_until = time(NULL) + 3600;
+
+ /* Test the bounds for A lines in the NS consensus */
+ mock_options->UseMicrodescriptors = 0;
+
+ mock_networkstatus->consensus_method = MIN_METHOD_FOR_A_LINES;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(has_ipv6);
+
+ mock_networkstatus->consensus_method = MIN_METHOD_FOR_A_LINES + 1;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(has_ipv6);
+
+ mock_networkstatus->consensus_method = MIN_METHOD_FOR_A_LINES + 20;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(has_ipv6);
+
+ mock_networkstatus->consensus_method = MIN_METHOD_FOR_A_LINES - 1;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(!has_ipv6);
+
+ /* Test the bounds for A lines in the microdesc consensus */
+ mock_options->UseMicrodescriptors = 1;
+
+ mock_networkstatus->consensus_method =
+ MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(has_ipv6);
+
+ mock_networkstatus->consensus_method =
+ MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS + 1;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(has_ipv6);
+
+ mock_networkstatus->consensus_method =
+ MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS + 20;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(has_ipv6);
+
+ mock_networkstatus->consensus_method =
+ MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS - 1;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(!has_ipv6);
+
+ /* Test the edge cases */
+ mock_options->UseMicrodescriptors = 1;
+ mock_networkstatus->consensus_method =
+ MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
+
+ /* Reasonably live */
+ mock_networkstatus->valid_until = time(NULL) - 60;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(has_ipv6);
+
+ /* Not reasonably live */
+ mock_networkstatus->valid_after = time(NULL) - 24*60*60 - 3600;
+ mock_networkstatus->valid_until = time(NULL) - 24*60*60 - 60;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(!has_ipv6);
+
+ /* NULL consensus */
+ mock_networkstatus = NULL;
+ has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
+ tt_assert(!has_ipv6);
+
+ done:
+ UNMOCK(get_options);
+ UNMOCK(networkstatus_get_latest_consensus_by_flavor);
+}
+
#define DIR_LEGACY(name) \
{ #name, test_dir_ ## name , TT_FORK, NULL, NULL }
@@ -6241,6 +6341,7 @@ struct testcase_t dir_tests[] = {
DIR(assumed_flags, 0),
DIR(networkstatus_compute_bw_weights_v10, 0),
DIR(platform_str, 0),
+ DIR(networkstatus_consensus_has_ipv6, 0),
END_OF_TESTCASES
};