tor-commits
Threads by month
- ----- 2025 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
February 2016
- 18 participants
- 833 discussions

[tor/master] Log when IPv4/IPv6 restrictions or preferences weren't met
by nickm@torproject.org 11 Feb '16
by nickm@torproject.org 11 Feb '16
11 Feb '16
commit c3cc8e16e9655ffcaead811675c360b6764f2992
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Tue Dec 22 11:31:54 2015 +1100
Log when IPv4/IPv6 restrictions or preferences weren't met
---
src/or/connection.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/or/directory.c | 12 +++++++---
src/or/routerlist.c | 49 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 123 insertions(+), 3 deletions(-)
diff --git a/src/or/connection.c b/src/or/connection.c
index d59e07b..f252d2f 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -19,6 +19,7 @@
*/
#define TOR_CHANNEL_INTERNAL_
#define CONNECTION_PRIVATE
+#include "backtrace.h"
#include "channel.h"
#include "channeltls.h"
#include "circuitbuild.h"
@@ -1721,6 +1722,66 @@ connection_connect_sockaddr,(connection_t *conn,
return inprogress ? 0 : 1;
}
+/* Log a message if connection violates ClientUseIPv4 0 or ClientUseIPv6 0.
+ * Log a less severe message if we couldn't conform to ClientPreferIPv6ORPort
+ * or ClientPreferIPv6ORPort. */
+static void
+connection_connect_log_client_use_ip_version(const connection_t *conn)
+{
+ const or_options_t *options = get_options();
+
+ /* Only non-bridge clients care about ClientUseIPv4/6, bail out early on
+ * servers and bridge clients */
+ if (options->UseBridges || server_mode(options) || !conn
+ || conn->type == CONN_TYPE_EXIT) {
+ return;
+ }
+
+ /* We're only prepared to log OR and DIR connections here */
+ if (conn->type != CONN_TYPE_OR && conn->type != CONN_TYPE_DIR) {
+ return;
+ }
+
+ const int must_ipv4 = (options->ClientUseIPv6 == 0);
+ const int must_ipv6 = (options->ClientUseIPv4 == 0);
+ const int pref_ipv6 = (conn->type == CONN_TYPE_OR
+ ? nodelist_prefer_ipv6_orport(options)
+ : nodelist_prefer_ipv6_dirport(options));
+ tor_addr_t real_addr;
+ tor_addr_make_null(&real_addr, AF_UNSPEC);
+
+ /* OR conns keep the original address in real_addr, as addr gets overwritten
+ * with the descriptor address */
+ if (conn->type == CONN_TYPE_OR) {
+ const or_connection_t *or_conn = TO_OR_CONN((connection_t *)conn);
+ tor_addr_copy(&real_addr, &or_conn->real_addr);
+ } else if (conn->type == CONN_TYPE_DIR) {
+ tor_addr_copy(&real_addr, &conn->addr);
+ }
+
+ /* Check if we broke a mandatory address family restriction */
+ if ((must_ipv4 && tor_addr_family(&real_addr) == AF_INET6)
+ || (must_ipv6 && tor_addr_family(&real_addr) == AF_INET)) {
+ log_warn(LD_BUG, "%s connection to %s violated ClientUseIPv%s 0.",
+ conn->type == CONN_TYPE_OR ? "OR" : "Dir",
+ fmt_addr(&real_addr),
+ options->ClientUseIPv4 == 0 ? "4" : "6");
+ log_backtrace(LOG_WARN, LD_BUG, "Address came from");
+ }
+
+ /* Check if we couldn't satisfy an address family preference */
+ if ((!pref_ipv6 && tor_addr_family(&real_addr) == AF_INET6)
+ || (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) {
+ log_info(LD_NET, "Connection to %s doesn't satisfy ClientPreferIPv6%sPort "
+ "%d, with ClientUseIPv4 %d and ClientUseIPv6 %d.",
+ fmt_addr(&real_addr),
+ conn->type == CONN_TYPE_OR ? "OR" : "Dir",
+ conn->type == CONN_TYPE_OR ? options->ClientPreferIPv6ORPort
+ : options->ClientPreferIPv6DirPort,
+ options->ClientUseIPv4, options->ClientUseIPv4);
+ }
+}
+
/** Take conn, make a nonblocking socket; try to connect to
* addr:port (port arrives in *host order*). If fail, return -1 and if
* applicable put your best guess about errno into *<b>socket_error</b>.
@@ -1745,6 +1806,10 @@ connection_connect(connection_t *conn, const char *address,
const or_options_t *options = get_options();
int protocol_family;
+ /* Log if we didn't stick to ClientUseIPv4/6 or ClientPreferIPv6OR/DirPort
+ */
+ connection_connect_log_client_use_ip_version(conn);
+
if (tor_addr_family(addr) == AF_INET6)
protocol_family = PF_INET6;
else
diff --git a/src/or/directory.c b/src/or/directory.c
index 438b5d8..20ffcee 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -4,6 +4,7 @@
/* See LICENSE for licensing information */
#include "or.h"
+#include "backtrace.h"
#include "buffers.h"
#include "circuitbuild.h"
#include "config.h"
@@ -692,11 +693,13 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
/* We rejected both addresses. This isn't great. */
if (!have_or && !have_dir) {
- log_info(LD_DIR, "Rejected both the OR and Dir address when launching a "
- "directory connection to: IPv4 %s OR %d Dir %d IPv6 %s OR %d "
- "Dir %d", fmt_addr32(status->addr), status->or_port,
+ log_warn(LD_BUG, "Rejected all OR and Dir addresses from %s when "
+ "launching a directory connection to: IPv4 %s OR %d Dir %d "
+ "IPv6 %s OR %d Dir %d", routerstatus_describe(status),
+ fmt_addr32(status->addr), status->or_port,
status->dir_port, fmt_addr(&status->ipv6_addr),
status->ipv6_orport, status->dir_port);
+ log_backtrace(LOG_WARN, LD_BUG, "Addresses came from");
return;
}
@@ -1050,10 +1053,13 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
if (or_connection && (!or_addr_port->port
|| tor_addr_is_null(&or_addr_port->addr))) {
log_warn(LD_DIR, "Cannot make an OR connection without an OR port.");
+ log_backtrace(LOG_WARN, LD_BUG, "Address came from");
return;
} else if (!or_connection && (!dir_addr_port->port
|| tor_addr_is_null(&dir_addr_port->addr))) {
log_warn(LD_DIR, "Cannot make a Dir connection without a Dir port.");
+ log_backtrace(LOG_WARN, LD_BUG, "Address came from");
+
return;
}
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 4a3c1cd..2923da3 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -13,6 +13,7 @@
#define ROUTERLIST_PRIVATE
#include "or.h"
+#include "backtrace.h"
#include "crypto_ed25519.h"
#include "circuitstats.h"
#include "config.h"
@@ -1536,6 +1537,50 @@ router_is_already_dir_fetching_rs(const routerstatus_t *rs,
|| router_is_already_dir_fetching(&ipv6_dir_ap, serverdesc, microdesc));
}
+#ifndef LOG_FALSE_POSITIVES_DURING_BOOTSTRAP
+#define LOG_FALSE_POSITIVES_DURING_BOOTSTRAP 0
+#endif
+
+/* Log a message if rs is not found or not a preferred address */
+static void
+router_picked_poor_directory_log(const routerstatus_t *rs)
+{
+ const networkstatus_t *usable_consensus;
+ usable_consensus = networkstatus_get_reasonably_live_consensus(time(NULL),
+ usable_consensus_flavor());
+
+#if !LOG_FALSE_POSITIVES_DURING_BOOTSTRAP
+ /* Don't log early in the bootstrap process, it's normal to pick from a
+ * small pool of nodes. Of course, this won't help if we're trying to
+ * diagnose bootstrap issues. */
+ if (!smartlist_len(nodelist_get_list()) || !usable_consensus
+ || !router_have_minimum_dir_info()) {
+ return;
+ }
+#endif
+
+ /* We couldn't find a node, or the one we have doesn't fit our preferences.
+ * This might be a bug. */
+ if (!rs) {
+ log_warn(LD_BUG, "Firewall denied all OR and Dir addresses for all relays "
+ "when searching for a directory.");
+ log_backtrace(LOG_WARN, LD_BUG, "Node search initiated by");
+ } else if (!fascist_firewall_allows_rs(rs, FIREWALL_OR_CONNECTION, 1)
+ && !fascist_firewall_allows_rs(rs, FIREWALL_DIR_CONNECTION, 1)
+ ) {
+ log_warn(LD_BUG, "Selected a directory %s with non-preferred OR and Dir "
+ "addresses for launching a connection: "
+ "IPv4 %s OR %d Dir %d IPv6 %s OR %d Dir %d",
+ routerstatus_describe(rs),
+ fmt_addr32(rs->addr), rs->or_port,
+ rs->dir_port, fmt_addr(&rs->ipv6_addr),
+ rs->ipv6_orport, rs->dir_port);
+ log_backtrace(LOG_WARN, LD_BUG, "Node search initiated by");
+ }
+}
+
+#undef LOG_FALSE_POSITIVES_DURING_BOOTSTRAP
+
/** How long do we avoid using a directory server after it's given us a 503? */
#define DIR_503_TIMEOUT (60*60)
@@ -1711,6 +1756,8 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
if (n_busy_out)
*n_busy_out = n_busy;
+ router_picked_poor_directory_log(result ? result->rs : NULL);
+
return result ? result->rs : NULL;
}
@@ -1843,6 +1890,8 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
RETRY_WITHOUT_EXCLUDE(retry_search);
+ router_picked_poor_directory_log(result);
+
if (n_busy_out)
*n_busy_out = n_busy;
return result;
1
0

11 Feb '16
commit 16486662038de53c482cd6f50a30505f2bf20453
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Sun Jan 3 18:20:37 2016 +1100
Choose bridge addresses by IPv4/IPv6 preferences
---
src/or/directory.c | 176 ++++++++++++++++++++++++++++++++--------------------
src/or/directory.h | 4 +-
src/or/entrynodes.c | 13 +++-
src/or/router.c | 5 +-
4 files changed, 123 insertions(+), 75 deletions(-)
diff --git a/src/or/directory.c b/src/or/directory.c
index 20ffcee..665ba27 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -497,11 +497,14 @@ MOCK_IMPL(void, directory_get_from_dirserver, (
const node_t *node = choose_random_dirguard(type);
if (node && node->ri) {
/* every bridge has a routerinfo. */
- tor_addr_t addr;
routerinfo_t *ri = node->ri;
- node_get_addr(node, &addr);
- directory_initiate_command(&addr,
- ri->or_port, 0/*no dirport*/,
+ /* 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 */
+ fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0,
+ &or_ap);
+ directory_initiate_command(&or_ap.addr, or_ap.port,
+ NULL, 0, /*no dirport*/
ri->cache_info.identity_digest,
dir_purpose,
router_purpose,
@@ -610,6 +613,80 @@ dirind_is_anon(dir_indirection_t ind)
return ind == DIRIND_ANON_DIRPORT || ind == DIRIND_ANONYMOUS;
}
+/* Choose reachable OR and Dir addresses and ports from status, copying them
+ * into use_or_ap and use_dir_ap. If indirection is anonymous, then we're
+ * connecting via another relay, so choose the primary IPv4 address and ports.
+ *
+ * status should have at least one reachable address, if we can't choose a
+ * reachable address, warn and return -1. Otherwise, return 0.
+ */
+static int
+directory_choose_address_routerstatus(const routerstatus_t *status,
+ dir_indirection_t indirection,
+ tor_addr_port_t *use_or_ap,
+ tor_addr_port_t *use_dir_ap)
+{
+ tor_assert(status != NULL);
+ tor_assert(use_or_ap != NULL);
+ tor_assert(use_dir_ap != NULL);
+
+ const int anonymized_connection = dirind_is_anon(indirection);
+ int have_or = 0, have_dir = 0;
+
+ /* We expect status to have at least one reachable address if we're
+ * connecting to it directly.
+ *
+ * Therefore, we can simply use the other address if the one we want isn't
+ * allowed by the firewall.
+ *
+ * (When Tor uploads and downloads a hidden service descriptor, it uses
+ * DIRIND_ANONYMOUS, except for Tor2Web, which uses DIRIND_ONEHOP.
+ * So this code will only modify the address for Tor2Web's HS descriptor
+ * fetches. Even Single Onion Servers (NYI) use DIRIND_ANONYMOUS, to avoid
+ * HSDirs denying service by rejecting descriptors.)
+ */
+
+ /* Initialise the OR / Dir addresses */
+ tor_addr_make_null(&use_or_ap->addr, AF_UNSPEC);
+ use_or_ap->port = 0;
+ tor_addr_make_null(&use_dir_ap->addr, AF_UNSPEC);
+ use_dir_ap->port = 0;
+
+ if (anonymized_connection) {
+ /* Use the primary (IPv4) OR address if we're making an indirect
+ * connection. */
+ tor_addr_from_ipv4h(&use_or_ap->addr, status->addr);
+ use_or_ap->port = status->or_port;
+ have_or = 1;
+ } else {
+ /* We use an IPv6 address if we have one and we prefer it.
+ * Use the preferred address and port if they are reachable, otherwise,
+ * use the alternate address and port (if any).
+ */
+ have_or = fascist_firewall_choose_address_rs(status,
+ FIREWALL_OR_CONNECTION, 0,
+ use_or_ap);
+ }
+
+ have_dir = fascist_firewall_choose_address_rs(status,
+ FIREWALL_DIR_CONNECTION, 0,
+ use_dir_ap);
+
+ /* We rejected both addresses. This isn't great. */
+ if (!have_or && !have_dir) {
+ log_warn(LD_BUG, "Rejected all OR and Dir addresses from %s when "
+ "launching a directory connection to: IPv4 %s OR %d Dir %d "
+ "IPv6 %s OR %d Dir %d", routerstatus_describe(status),
+ fmt_addr32(status->addr), status->or_port,
+ status->dir_port, fmt_addr(&status->ipv6_addr),
+ status->ipv6_orport, status->dir_port);
+ log_backtrace(LOG_WARN, LD_BUG, "Addresses came from");
+ return -1;
+ }
+
+ return 0;
+}
+
/** Same as directory_initiate_command_routerstatus(), but accepts
* rendezvous data to fetch a hidden service descriptor. */
void
@@ -627,7 +704,8 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
const node_t *node;
tor_addr_port_t use_or_ap, use_dir_ap;
const int anonymized_connection = dirind_is_anon(indirection);
- int have_or = 0, have_dir = 0;
+
+ tor_assert(status != NULL);
node = node_get_by_id(status->identity_digest);
@@ -654,57 +732,16 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
* selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if
* possible. (If UseBridges is set, clients ignore all these settings.)
*
- * Now we use a similar process to select an address for the relay,
- * but simply use the other address if the one we want isn't allowed by
- * the firewall.
- *
- * (When Tor uploads and downloads a hidden service descriptor, it uses
- * DIRIND_ANONYMOUS, except for Tor2Web, which uses DIRIND_ONEHOP.
- * So this code will only modify the address for Tor2Web's HS descriptor
- * fetches. Even Single Onion Servers (NYI) use DIRIND_ANONYMOUS, to avoid
- * HSDirs denying service by rejecting descriptors.)
+ * Now choose an address that we can use to connect to the directory server.
*/
-
- /* Initialise the OR / Dir addresses */
- tor_addr_make_null(&use_or_ap.addr, AF_UNSPEC);
- use_or_ap.port = 0;
- tor_addr_make_null(&use_dir_ap.addr, AF_UNSPEC);
- use_dir_ap.port = 0;
-
- if (anonymized_connection) {
- /* Use the primary (IPv4) OR address if we're making an indirect
- * connection. */
- tor_addr_from_ipv4h(&use_or_ap.addr, status->addr);
- use_or_ap.port = status->or_port;
- have_or = 1;
- } else {
- /* We use an IPv6 address if we have one and we prefer it.
- * Use the preferred address and port if they are reachable, otherwise,
- * use the alternate address and port (if any).
- */
- have_or = fascist_firewall_choose_address_rs(status,
- FIREWALL_OR_CONNECTION, 0,
- &use_or_ap);
- }
-
- have_dir = fascist_firewall_choose_address_rs(status,
- FIREWALL_DIR_CONNECTION, 0,
- &use_dir_ap);
-
- /* We rejected both addresses. This isn't great. */
- if (!have_or && !have_dir) {
- log_warn(LD_BUG, "Rejected all OR and Dir addresses from %s when "
- "launching a directory connection to: IPv4 %s OR %d Dir %d "
- "IPv6 %s OR %d Dir %d", routerstatus_describe(status),
- fmt_addr32(status->addr), status->or_port,
- status->dir_port, fmt_addr(&status->ipv6_addr),
- status->ipv6_orport, status->dir_port);
- log_backtrace(LOG_WARN, LD_BUG, "Addresses came from");
+ if (directory_choose_address_routerstatus(status, indirection, &use_or_ap,
+ &use_dir_ap) < 0) {
return;
}
- /* XX/teor - we don't retry the alternate OR/Dir address if this one fails.
- * (See #6772.) Instead, we'll retry another directory on failure. */
+ /* We don't retry the alternate OR/Dir address for the same directory if
+ * the address we choose fails (#6772).
+ * Instead, we'll retry another directory on failure. */
directory_initiate_command_rend(&use_or_ap, &use_dir_ap,
status->identity_digest,
@@ -941,41 +978,42 @@ directory_command_should_use_begindir(const or_options_t *options,
}
/** Helper for directory_initiate_command_rend: send the
- * command to a server whose address is <b>_addr</b>, whose OR port is
- * <b>or_port</b>, whose directory port is <b>dir_port</b>, whose identity key
- * digest is <b>digest</b>, with purposes <b>dir_purpose</b> and
+ * command to a server whose OR address/port is <b>or_addr</b>/<b>or_port</b>,
+ * whose directory address/port is <b>dir_addr</b>/<b>dir_port</b>, whose
+ * identity key digest is <b>digest</b>, with purposes <b>dir_purpose</b> and
* <b>router_purpose</b>, making an (in)direct connection as specified in
* <b>indirection</b>, with command <b>resource</b>, <b>payload</b> of
* <b>payload_len</b>, and asking for a result only <b>if_modified_since</b>.
*/
void
-directory_initiate_command(const tor_addr_t *_addr,
- uint16_t or_port, uint16_t dir_port,
+directory_initiate_command(const tor_addr_t *or_addr, uint16_t or_port,
+ const tor_addr_t *dir_addr, uint16_t dir_port,
const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
dir_indirection_t indirection, const char *resource,
const char *payload, size_t payload_len,
time_t if_modified_since)
{
- /* Assume _addr applies to both the ORPort and the DirPort, but use the
- * null tor_addr if ORPort or DirPort are 0. */
tor_addr_port_t or_ap, dir_ap;
- if (or_port) {
- tor_addr_copy(&or_ap.addr, _addr);
+ /* Use the null tor_addr and 0 port if the address or port isn't valid. */
+ if (tor_addr_port_is_valid(or_addr, or_port, 0)) {
+ tor_addr_copy(&or_ap.addr, or_addr);
+ or_ap.port = or_port;
} else {
- /* the family doesn't matter here, so make it the same as _addr */
- tor_addr_make_null(&or_ap.addr, tor_addr_family(_addr));
+ /* the family doesn't matter here, so make it IPv4 */
+ tor_addr_make_null(&or_ap.addr, AF_INET);
+ or_port = 0;
}
- or_ap.port = or_port;
- if (dir_port) {
- tor_addr_copy(&dir_ap.addr, _addr);
+ if (tor_addr_port_is_valid(dir_addr, dir_port, 0)) {
+ tor_addr_copy(&dir_ap.addr, dir_addr);
+ dir_ap.port = dir_port;
} else {
- /* the family doesn't matter here, so make it the same as _addr */
- tor_addr_make_null(&dir_ap.addr, tor_addr_family(_addr));
+ /* the family doesn't matter here, so make it IPv4 */
+ tor_addr_make_null(&dir_ap.addr, AF_INET);
+ dir_port = 0;
}
- dir_ap.port = dir_port;
directory_initiate_command_rend(&or_ap, &dir_ap,
digest, dir_purpose,
diff --git a/src/or/directory.h b/src/or/directory.h
index 2644e57..61c29ba 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -66,8 +66,8 @@ int connection_dir_process_inbuf(dir_connection_t *conn);
int connection_dir_finished_flushing(dir_connection_t *conn);
int connection_dir_finished_connecting(dir_connection_t *conn);
void connection_dir_about_to_close(dir_connection_t *dir_conn);
-void directory_initiate_command(const tor_addr_t *addr,
- uint16_t or_port, uint16_t dir_port,
+void directory_initiate_command(const tor_addr_t *or_addr, uint16_t or_port,
+ const tor_addr_t *dir_addr, uint16_t dir_port,
const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
dir_indirection_t indirection,
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index e358e92..583b7ef 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -2117,8 +2117,17 @@ launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
return;
}
- directory_initiate_command(&bridge->addr,
- bridge->port, 0/*no dirport*/,
+ /* Until we get a descriptor for the bridge, we only know one address for
+ * it. If we */
+ if (!fascist_firewall_allows_address_addr(&bridge->addr, bridge->port,
+ FIREWALL_OR_CONNECTION, 0)) {
+ log_notice(LD_CONFIG, "Tried to fetch a descriptor directly from a bridge, "
+ "but that bridge is not reachable through our firewall.");
+ return;
+ }
+
+ directory_initiate_command(&bridge->addr, bridge->port,
+ NULL, 0, /*no dirport*/
bridge->identity,
DIR_PURPOSE_FETCH_SERVERDESC,
ROUTER_PURPOSE_BRIDGE,
diff --git a/src/or/router.c b/src/or/router.c
index ba32d77..d413199 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1244,14 +1244,15 @@ consider_testing_reachability(int test_or, int test_dir)
extend_info_free(ei);
}
+ /* XXX IPv6 self testing */
tor_addr_from_ipv4h(&addr, me->addr);
if (test_dir && !check_whether_dirport_reachable() &&
!connection_get_by_type_addr_port_purpose(
CONN_TYPE_DIR, &addr, me->dir_port,
DIR_PURPOSE_FETCH_SERVERDESC)) {
/* ask myself, via tor, for my server descriptor. */
- directory_initiate_command(&addr,
- me->or_port, me->dir_port,
+ directory_initiate_command(&addr, me->or_port,
+ &addr, me->dir_port,
me->cache_info.identity_digest,
DIR_PURPOSE_FETCH_SERVERDESC,
ROUTER_PURPOSE_GENERAL,
1
0

[tor/master] Make entry_guard_set_status consistent with entry_is_live
by nickm@torproject.org 11 Feb '16
by nickm@torproject.org 11 Feb '16
11 Feb '16
commit 4528f893163ad7ab27915451caf23b3a722413ce
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Sun Jan 3 23:16:06 2016 +1100
Make entry_guard_set_status consistent with entry_is_live
Check fascist_firewall_allows_node in entry_guard_set_status and
return the same message as entry_is_live.
---
src/or/entrynodes.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 583b7ef..1ce44d1 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -87,7 +87,7 @@ get_entry_guards(void)
/** Check whether the entry guard <b>e</b> is usable, given the directory
* authorities' opinion about the router (stored in <b>ri</b>) and the user's
- * configuration (in <b>options</b>). Set <b>e</b>->bad_since
+ * configuration (in <b>options</b>). Set <b>e</b>->bad_since
* accordingly. Return true iff the entry guard's status changes.
*
* If it's not usable, set *<b>reason</b> to a static string explaining why.
@@ -117,6 +117,9 @@ entry_guard_set_status(entry_guard_t *e, const node_t *node,
*reason = "not recommended as a guard";
else if (routerset_contains_node(options->ExcludeNodes, node))
*reason = "excluded";
+ /* We only care about OR connection connectivity for entry guards. */
+ else if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0))
+ *reason = "unreachable by config";
else if (e->path_bias_disabled)
*reason = "path-biased";
1
0
commit e991d642ec14d41df9da70442d99861bdb5bfb5b
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Thu Jan 21 12:58:59 2016 +1100
Add firewall_is_fascist_dir()
Refactor common parts of firewall_is_fascist_or().
---
src/or/policies.c | 32 +++++++++++++++++++++++++-------
src/or/policies.h | 1 +
2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/src/or/policies.c b/src/or/policies.c
index ecc89da..506edec 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -307,18 +307,36 @@ parse_reachable_addresses(void)
return ret;
}
-/** Return true iff the firewall options, including ClientUseIPv4 0 and
- * ClientUseIPv6 0, might block any address:port combination.
- */
-int
-firewall_is_fascist_or(void)
+/* Return true iff ClientUseIPv4 0 or ClientUseIPv6 0 might block any OR or Dir
+ * address:port combination. */
+static int
+firewall_is_fascist_impl(void)
{
const or_options_t *options = get_options();
/* Assume every non-bridge relay has an IPv4 address.
* Clients which use bridges may only know the IPv6 address of their
* bridge. */
- return (reachable_or_addr_policy != NULL || options->ClientUseIPv4 == 0
- || (options->ClientUseIPv6 == 0 && options->UseBridges == 1));
+ return (options->ClientUseIPv4 == 0
+ || (!fascist_firewall_use_ipv6(options)
+ && options->UseBridges == 1));
+}
+
+/** Return true iff the firewall options, including ClientUseIPv4 0 and
+ * ClientUseIPv6 0, might block any OR address:port combination.
+ */
+int
+firewall_is_fascist_or(void)
+{
+ return (reachable_or_addr_policy != NULL || firewall_is_fascist_impl());
+}
+
+/** Return true iff the firewall options, including ClientUseIPv4 0 and
+ * ClientUseIPv6 0, might block any Dir address:port combination.
+ */
+int
+firewall_is_fascist_dir(void)
+{
+ return (reachable_dir_addr_policy != NULL || firewall_is_fascist_impl());
}
/** Return true iff <b>policy</b> (possibly NULL) will allow a
diff --git a/src/or/policies.h b/src/or/policies.h
index ac4f7ea..65f10e2 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -30,6 +30,7 @@ typedef enum firewall_connection_t {
typedef int exit_policy_parser_cfg_t;
int firewall_is_fascist_or(void);
+int firewall_is_fascist_dir(void);
int fascist_firewall_use_ipv6(const or_options_t *options);
int fascist_firewall_prefer_ipv6_orport(const or_options_t *options);
int fascist_firewall_prefer_ipv6_dirport(const or_options_t *options);
1
0

[tor/master] Consistently format addresses in node_get_address_string
by nickm@torproject.org 11 Feb '16
by nickm@torproject.org 11 Feb '16
11 Feb '16
commit 4db5a35e669a03db33d04632349ec95022de53cf
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Wed Jan 20 13:17:08 2016 +1100
Consistently format addresses in node_get_address_string
Also, don't write to a buffer with length zero.
---
src/or/nodelist.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index c8f93bf..28d8741 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -863,13 +863,13 @@ node_get_prim_addr_ipv4h(const node_t *node)
void
node_get_address_string(const node_t *node, char *buf, size_t len)
{
- if (node->ri) {
- strlcpy(buf, fmt_addr32(node->ri->addr), len);
- } else if (node->rs) {
+ uint32_t ipv4_addr = node_get_prim_addr_ipv4h(node);
+
+ if (tor_addr_is_valid_ipv4h(ipv4_addr, 0)) {
tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, node->rs->addr);
+ tor_addr_from_ipv4h(&addr, ipv4_addr);
tor_addr_to_str(buf, &addr, len, 0);
- } else {
+ } else if (len > 0) {
buf[0] = '\0';
}
}
1
0
commit 3a00215c35b01909a2db24132ab800298d61b647
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Thu Jan 21 12:57:28 2016 +1100
Minor whitespace-only fix
---
src/or/connection.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/or/connection.c b/src/or/connection.c
index 0420f26..63bfb2e 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1732,8 +1732,7 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
/* Only clients care about ClientUseIPv4/6, bail out early on servers, and
* on connections we don't care about */
- if (server_mode(options) || !conn
- || conn->type == CONN_TYPE_EXIT) {
+ if (server_mode(options) || !conn || conn->type == CONN_TYPE_EXIT) {
return;
}
1
0

[tor/master] Use fascist firewall and ClientUseIPv4 for bridge clients
by nickm@torproject.org 11 Feb '16
by nickm@torproject.org 11 Feb '16
11 Feb '16
commit 3b8216f2155f224bf66497c71de4cecb55cd83e6
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Mon Jan 4 00:35:22 2016 +1100
Use fascist firewall and ClientUseIPv4 for bridge clients
Bridge clients ignore ClientUseIPv6, acting as if it is always 1.
This preserves existing behaviour.
Make ClientPreferIPv6OR/DirPort auto by default:
* Bridge clients prefer IPv6 by default.
* Other clients prefer IPv4 by default.
This preserves existing behaviour.
---
doc/tor.1.txt | 16 +--
src/or/config.c | 49 ++------
src/or/connection.c | 20 +--
src/or/directory.c | 12 +-
src/or/nodelist.c | 156 +++++++++---------------
src/or/nodelist.h | 5 +-
src/or/or.h | 10 +-
src/or/policies.c | 296 +++++++++++++++++++--------------------------
src/or/policies.h | 17 +--
src/or/routerlist.c | 8 +-
src/test/test_entrynodes.c | 45 ++++++-
src/test/test_policy.c | 154 +++++++++++++++++------
12 files changed, 403 insertions(+), 385 deletions(-)
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 26abef1..f201a61 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1500,19 +1500,21 @@ The following options are useful only for clients (that is, if
in a **Bridge**, proxy, or pluggable transport line will try connecting
over IPv6 even if **ClientUseIPv6** is set to 0. (Default: 0)
-[[ClientPreferIPv6DirPort]] **ClientPreferIPv6DirPort** **0**|**1**::
+[[ClientPreferIPv6DirPort]] **ClientPreferIPv6DirPort** **0**|**1**|**auto**::
If this option is set to 1, Tor prefers a directory port with an IPv6
address over one with IPv4, for direct connections, if a given directory
server has both. (Tor also prefers an IPv6 DirPort if IPv4Client is set to
- 0.) Other things may influence the choice. This option breaks a tie to the
- favor of IPv6. (Default: 0)
+ 0.) If this option is set to auto, Tor bridge clients prefer IPv6, and
+ other clients prefer IPv4. Other things may influence the choice. This
+ option breaks a tie to the favor of IPv6. (Default: auto)
-[[ClientPreferIPv6ORPort]] **ClientPreferIPv6ORPort** **0**|**1**::
+[[ClientPreferIPv6ORPort]] **ClientPreferIPv6ORPort** **0**|**1**|**auto**::
If this option is set to 1, Tor prefers an OR port with an IPv6
address over one with IPv4 if a given entry node has both. (Tor also
- prefers an IPv6 ORPort if IPv4Client is set to 0.) Other things may
- influence the choice. This option breaks a tie to the favor of IPv6.
- (Default: 0)
+ prefers an IPv6 ORPort if IPv4Client is set to 0.) If this option is set
+ to auto, Tor bridge clients prefer IPv6, and other clients prefer IPv4.
+ Other things may influence the choice. This option breaks a tie to the
+ favor of IPv6. (Default: auto)
[[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__::
Tor clients don't build circuits for user traffic until they know
diff --git a/src/or/config.c b/src/or/config.c
index d676c6e..caa01d1 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -190,8 +190,8 @@ static config_var_t option_vars_[] = {
V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
V(ClientOnly, BOOL, "0"),
- V(ClientPreferIPv6ORPort, BOOL, "0"),
- V(ClientPreferIPv6DirPort, BOOL, "0"),
+ V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"),
+ V(ClientPreferIPv6DirPort, AUTOBOOL, "auto"),
V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientTransportPlugin, LINELIST, NULL),
V(ClientUseIPv6, BOOL, "0"),
@@ -3073,9 +3073,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
- /* Terminate Reachable*Addresses with reject *, but check if it has an
- * IPv6 entry on the way through */
- int reachable_knows_ipv6 = 0;
+ /* Terminate Reachable*Addresses with reject *
+ */
for (i=0; i<3; i++) {
config_line_t **linep =
(i==0) ? &options->ReachableAddresses :
@@ -3085,20 +3084,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
continue;
/* We need to end with a reject *:*, not an implicit accept *:* */
for (;;) {
- /* Check if the policy has an IPv6 entry, or uses IPv4-specific
- * policies (and therefore we assume it's aware of IPv6). */
- if (!strcmpstart((*linep)->value, "accept6") ||
- !strcmpstart((*linep)->value, "reject6") ||
- !strstr((*linep)->value, "*6") ||
- strchr((*linep)->value, '[') ||
- !strcmpstart((*linep)->value, "accept4") ||
- !strcmpstart((*linep)->value, "reject4") ||
- !strstr((*linep)->value, "*4"))
- reachable_knows_ipv6 = 1;
- /* already has a reject all */
- if (!strcmp((*linep)->value, "reject *:*") ||
- !strcmp((*linep)->value, "reject *"))
- break;
linep = &((*linep)->next);
if (!*linep) {
*linep = tor_malloc_zero(sizeof(config_line_t));
@@ -3112,18 +3097,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
- if (options->ClientUseIPv6 &&
- (options->ReachableAddresses ||
- options->ReachableORAddresses ||
- options->ReachableDirAddresses) &&
- !reachable_knows_ipv6)
- log_warn(LD_CONFIG, "You have set ClientUseIPv6 1 and at least one of "
- "ReachableAddresses, ReachableORAddresses, or "
- "ReachableDirAddresses, but without any IPv6-specific rules. "
- "Tor won't connect to any IPv6 addresses, unless a rule accepts "
- "them. (Use 'accept6 *:*' or 'reject6 *:*' as the last rule to "
- "disable this warning.)");
-
if ((options->ReachableAddresses ||
options->ReachableORAddresses ||
options->ReachableDirAddresses ||
@@ -3135,18 +3108,20 @@ options_validate(or_options_t *old_options, or_options_t *options,
/* We check if Reachable*Addresses blocks all addresses in
* parse_reachable_addresses(). */
- if (options->ClientUseIPv4 == 0 && options->ClientUseIPv6 == 0)
+ if (options->ClientUseIPv4 == 0 && !fascist_firewall_use_ipv6(options))
REJECT("Tor cannot connect to the Internet if ClientUseIPv4 is 0 and "
"ClientUseIPv6 is 0. Please set at least one of these options "
- "to 1.");
+ "to 1, or configure bridges.");
- if (options->ClientUseIPv6 == 0 && options->ClientPreferIPv6ORPort == 1)
+ if (!fascist_firewall_use_ipv6(options)
+ && options->ClientPreferIPv6ORPort == 1)
log_warn(LD_CONFIG, "ClientPreferIPv6ORPort 1 is ignored unless "
- "ClientUseIPv6 is also 1.");
+ "ClientUseIPv6 is also 1, or bridges are configured.");
- if (options->ClientUseIPv6 == 0 && options->ClientPreferIPv6DirPort == 1)
+ if (!fascist_firewall_use_ipv6(options)
+ && options->ClientPreferIPv6DirPort == 1)
log_warn(LD_CONFIG, "ClientPreferIPv6DirPort 1 is ignored unless "
- "ClientUseIPv6 is also 1.");
+ "ClientUseIPv6 is also 1, or bridges are configured.");
if (options->UseBridges &&
server_mode(options))
diff --git a/src/or/connection.c b/src/or/connection.c
index f252d2f..0420f26 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1722,7 +1722,7 @@ connection_connect_sockaddr,(connection_t *conn,
return inprogress ? 0 : 1;
}
-/* Log a message if connection violates ClientUseIPv4 0 or ClientUseIPv6 0.
+/* Log a message if connection attempt is made when IPv4 or IPv6 is disabled.
* Log a less severe message if we couldn't conform to ClientPreferIPv6ORPort
* or ClientPreferIPv6ORPort. */
static void
@@ -1730,9 +1730,9 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
{
const or_options_t *options = get_options();
- /* Only non-bridge clients care about ClientUseIPv4/6, bail out early on
- * servers and bridge clients */
- if (options->UseBridges || server_mode(options) || !conn
+ /* Only clients care about ClientUseIPv4/6, bail out early on servers, and
+ * on connections we don't care about */
+ if (server_mode(options) || !conn
|| conn->type == CONN_TYPE_EXIT) {
return;
}
@@ -1742,11 +1742,11 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
return;
}
- const int must_ipv4 = (options->ClientUseIPv6 == 0);
+ const int must_ipv4 = !fascist_firewall_use_ipv6(options);
const int must_ipv6 = (options->ClientUseIPv4 == 0);
const int pref_ipv6 = (conn->type == CONN_TYPE_OR
- ? nodelist_prefer_ipv6_orport(options)
- : nodelist_prefer_ipv6_dirport(options));
+ ? fascist_firewall_prefer_ipv6_orport(options)
+ : fascist_firewall_prefer_ipv6_dirport(options));
tor_addr_t real_addr;
tor_addr_make_null(&real_addr, AF_UNSPEC);
@@ -1773,12 +1773,14 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
if ((!pref_ipv6 && tor_addr_family(&real_addr) == AF_INET6)
|| (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) {
log_info(LD_NET, "Connection to %s doesn't satisfy ClientPreferIPv6%sPort "
- "%d, with ClientUseIPv4 %d and ClientUseIPv6 %d.",
+ "%d, with ClientUseIPv4 %d, and fascist_firewall_use_ipv6 %d "
+ "(ClientUseIPv6 %d and UseBridges %d).",
fmt_addr(&real_addr),
conn->type == CONN_TYPE_OR ? "OR" : "Dir",
conn->type == CONN_TYPE_OR ? options->ClientPreferIPv6ORPort
: options->ClientPreferIPv6DirPort,
- options->ClientUseIPv4, options->ClientUseIPv4);
+ options->ClientUseIPv4, fascist_firewall_use_ipv6(options),
+ options->ClientUseIPv6, options->UseBridges);
}
}
diff --git a/src/or/directory.c b/src/or/directory.c
index 665ba27..b3a2f36 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -730,7 +730,8 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
* directory server, we have selected a server that has at least one address
* allowed by ClientUseIPv4/6 and Reachable{"",OR,Dir}Addresses. This
* selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if
- * possible. (If UseBridges is set, clients ignore all these settings.)
+ * possible. (If UseBridges is set, clients always use IPv6, and prefer it
+ * by default.)
*
* Now choose an address that we can use to connect to the directory server.
*/
@@ -1070,6 +1071,15 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
log_debug(LD_DIR, "anonymized %d, use_begindir %d.",
anonymized_connection, use_begindir);
+ if (!dir_port && !use_begindir) {
+ char ipaddr[TOR_ADDR_BUF_LEN];
+ tor_addr_to_str(ipaddr, &addr, TOR_ADDR_BUF_LEN, 0);
+ log_warn(LD_BUG, "Cannot use directory server without dirport or "
+ "begindir! Address: %s, DirPort: %d, Connection Port: %d",
+ escaped_safe_str_client(ipaddr), dir_port, port);
+ return;
+ }
+
log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose));
#ifndef NON_ANONYMOUS_MODE_ENABLED
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 7ca1146..c8f93bf 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -214,76 +214,6 @@ nodelist_add_microdesc(microdesc_t *md)
return node;
}
-/** Do we prefer to connect to IPv6, ignoring ClientPreferIPv6ORPort and
- * ClientPreferIPv6DirPort?
- * If we're unsure, return -1, otherwise, return 1 for IPv6 and 0 for IPv4.
- */
-static int
-nodelist_prefer_ipv6(const or_options_t *options)
-{
- /*
- Cheap implementation of config options ClientUseIPv4 & ClientUseIPv6 --
- If we're a server, use IPv4.
- If we're a client running with bridges, use IPv6.
- Otherwise, use IPv6 if we can and it's preferred, or if IPv4 is disabled.
- See #4455 and #17840 for more on this subject.
- */
-
- /* Servers prefer IPv4 */
- if (server_mode(options)) {
- return 0;
- }
-
- /* Bridge clients prefer IPv6 */
- if (options->UseBridges) {
- return 1;
- }
-
- if (!options->ClientUseIPv4) {
- return 1;
- }
-
- return -1;
-}
-
-/** Do we prefer to connect to IPv6 ORPorts?
- */
-int
-nodelist_prefer_ipv6_orport(const or_options_t *options)
-{
- int pref_ipv6 = nodelist_prefer_ipv6(options);
-
- if (pref_ipv6 >= 0) {
- return pref_ipv6;
- }
-
- /* We prefer IPv6 ORPorts if the option is set */
- if (options->ClientUseIPv6 && options->ClientPreferIPv6ORPort) {
- return 1;
- }
-
- return 0;
-}
-
-/** Do we prefer to connect to IPv6 DirPorts?
- */
-int
-nodelist_prefer_ipv6_dirport(const or_options_t *options)
-{
- int pref_ipv6 = nodelist_prefer_ipv6(options);
-
- if (pref_ipv6 >= 0) {
- return pref_ipv6;
- }
-
- /* We prefer IPv6 DirPorts if the option is set */
- if (options->ClientUseIPv6 && options->ClientPreferIPv6DirPort) {
- return 1;
- }
-
- return 0;
-}
-
/** Tell the nodelist that the current usable consensus is <b>ns</b>.
* This makes the nodelist change all of the routerstatus entries for
* the nodes, drop nodes that no longer have enough info to get used,
@@ -330,7 +260,7 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_bad_exit = rs->is_bad_exit;
node->is_hs_dir = rs->is_hs_dir;
node->ipv6_preferred = 0;
- if (nodelist_prefer_ipv6_orport(options) &&
+ if (fascist_firewall_prefer_ipv6_orport(options) &&
(tor_addr_is_null(&rs->ipv6_addr) == 0 ||
(node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
node->ipv6_preferred = 1;
@@ -916,9 +846,13 @@ node_get_addr(const node_t *node, tor_addr_t *addr_out)
uint32_t
node_get_prim_addr_ipv4h(const node_t *node)
{
- if (node->ri) {
+ /* Don't check the ORPort or DirPort, as this function isn't port-specific,
+ * and the node might have a valid IPv4 address, yet have a zero
+ * ORPort or DirPort.
+ */
+ if (node->ri && tor_addr_is_valid_ipv4h(node->ri->addr, 0)) {
return node->ri->addr;
- } else if (node->rs) {
+ } else if (node->rs && tor_addr_is_valid_ipv4h(node->rs->addr, 0)) {
return node->rs->addr;
}
return 0;
@@ -994,20 +928,44 @@ node_get_declared_family(const node_t *node)
return NULL;
}
-/* Does this node have a valid IPv6 address? */
-static int
+/* Does this node have a valid IPv6 address?
+ * Prefer node_has_ipv6_orport() or node_has_ipv6_dirport() for
+ * checking specific ports. */
+int
node_has_ipv6_addr(const node_t *node)
{
- if (node->ri)
- return !tor_addr_is_null(&node->ri->ipv6_addr);
- if (node->md)
- return !tor_addr_is_null(&node->md->ipv6_addr);
- if (node->rs)
- return !tor_addr_is_null(&node->rs->ipv6_addr);
+ /* Don't check the ORPort or DirPort, as this function isn't port-specific,
+ * and the node might have a valid IPv6 address, yet have a zero
+ * ORPort or DirPort.
+ */
+ if (node->ri && tor_addr_is_valid(&node->ri->ipv6_addr, 0))
+ return 1;
+ if (node->rs && tor_addr_is_valid(&node->rs->ipv6_addr, 0))
+ return 1;
+ if (node->md && tor_addr_is_valid(&node->md->ipv6_addr, 0))
+ return 1;
return 0;
}
+/* Does this node have a valid IPv6 ORPort? */
+int
+node_has_ipv6_orport(const node_t *node)
+{
+ tor_addr_port_t ipv6_orport;
+ node_get_pref_ipv6_orport(node, &ipv6_orport);
+ return tor_addr_port_is_valid_ap(&ipv6_orport, 0);
+}
+
+/* Does this node have a valid IPv6 DirPort? */
+int
+node_has_ipv6_dirport(const node_t *node)
+{
+ tor_addr_port_t ipv6_dirport;
+ node_get_pref_ipv6_dirport(node, &ipv6_dirport);
+ return tor_addr_port_is_valid_ap(&ipv6_dirport, 0);
+}
+
/** Return 1 if we prefer the IPv6 address and OR TCP port of
* <b>node</b>, else 0.
*
@@ -1028,20 +986,18 @@ node_ipv6_or_preferred(const node_t *node)
tor_addr_port_t ipv4_addr;
node_assert_ok(node);
- if (!options->ClientUseIPv6) {
+ if (!fascist_firewall_use_ipv6(options)) {
return 0;
} else if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)
- || nodelist_prefer_ipv6_orport(get_options())) {
- return node_has_ipv6_addr(node);
+ || fascist_firewall_prefer_ipv6_orport(get_options())) {
+ return node_has_ipv6_orport(node);
}
return 0;
}
#define RETURN_IPV4_AP(r, port_field, ap_out) \
STMT_BEGIN \
- if (r) { \
- if ((r)->addr == 0 || (r)->port_field == 0) \
- return -1; \
+ if (r && tor_addr_port_is_valid_ipv4h((r)->addr, (r)->port_field, 0)) { \
tor_addr_from_ipv4h(&(ap_out)->addr, (r)->addr); \
(ap_out)->port = (r)->port_field; \
return 0; \
@@ -1091,16 +1047,16 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
* fascist_firewall_* functions. Also check if the address or port are valid,
* and try another alternative if they are not. */
- if (node->ri && node->ri->ipv6_orport
- && !tor_addr_is_null(&node->ri->ipv6_addr)) {
+ if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
+ node->ri->ipv6_orport, 0)) {
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
ap_out->port = node->ri->ipv6_orport;
- } else if (node->rs && node->rs->ipv6_orport
- && !tor_addr_is_null(&node->rs->ipv6_addr)) {
+ } else if (node->rs && tor_addr_port_is_valid(&node->rs->ipv6_addr,
+ node->rs->ipv6_orport, 0)) {
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
ap_out->port = node->rs->ipv6_orport;
- } else if (node->md && node->md->ipv6_orport
- && !tor_addr_is_null(&node->md->ipv6_addr)) {
+ } else if (node->md && tor_addr_port_is_valid(&node->md->ipv6_addr,
+ node->md->ipv6_orport, 0)) {
tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr);
ap_out->port = node->md->ipv6_orport;
} else {
@@ -1129,11 +1085,11 @@ node_ipv6_dir_preferred(const node_t *node)
tor_addr_port_t ipv4_addr;
node_assert_ok(node);
- if (!options->ClientUseIPv6) {
+ if (!fascist_firewall_use_ipv6(options)) {
return 0;
} else if (node->ipv6_preferred || node_get_prim_dirport(node, &ipv4_addr)
- || nodelist_prefer_ipv6_dirport(get_options())) {
- return node_has_ipv6_addr(node);
+ || fascist_firewall_prefer_ipv6_dirport(get_options())) {
+ return node_has_ipv6_dirport(node);
}
return 0;
}
@@ -1183,12 +1139,12 @@ node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
* they are not. Note that microdescriptors have no dir_port. */
/* Assume IPv4 and IPv6 dirports are the same */
- if (node->ri && node->ri->dir_port
- && !tor_addr_is_null(&node->ri->ipv6_addr)) {
+ if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
+ node->ri->dir_port, 0)) {
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
ap_out->port = node->ri->dir_port;
- } else if (node->rs && node->rs->dir_port
- && !tor_addr_is_null(&node->rs->ipv6_addr)) {
+ } else if (node->rs && tor_addr_port_is_valid(&node->rs->ipv6_addr,
+ node->rs->dir_port, 0)) {
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
ap_out->port = node->rs->dir_port;
} else {
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index fa1f22e..8271e75 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -21,8 +21,6 @@ MOCK_DECL(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_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
node_t *nodelist_add_microdesc(microdesc_t *md);
-int nodelist_prefer_ipv6_orport(const or_options_t *options);
-int nodelist_prefer_ipv6_dirport(const or_options_t *options);
void nodelist_set_consensus(networkstatus_t *ns);
void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md);
@@ -58,6 +56,9 @@ long node_get_declared_uptime(const node_t *node);
time_t node_get_published_on(const node_t *node);
const smartlist_t *node_get_declared_family(const node_t *node);
+int node_has_ipv6_addr(const node_t *node);
+int node_has_ipv6_orport(const node_t *node);
+int node_has_ipv6_dirport(const node_t *node);
/* Deprecated - use node_ipv6_or_preferred or node_ipv6_dir_preferred */
#define node_ipv6_preferred(node) node_ipv6_or_preferred(node)
int node_ipv6_or_preferred(const node_t *node);
diff --git a/src/or/or.h b/src/or/or.h
index 412789c..79b1c95 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -4066,14 +4066,18 @@ typedef struct {
* connecting over IPv4. We enforce this for OR and Dir connections. */
int ClientUseIPv4;
/** If true, clients may connect over IPv6. If false, they will avoid
- * connecting over IPv4. We enforce this for OR and Dir connections. */
+ * connecting over IPv4. We enforce this for OR and Dir connections.
+ * Use fascist_firewall_use_ipv6() instead of accessing this value
+ * directly. */
int ClientUseIPv6;
/** If true, prefer an IPv6 OR port over an IPv4 one for entry node
- * connections. Use nodelist_prefer_ipv6_orport() instead of accessing
+ * connections. If auto, bridge clients prefer IPv6, and other clients
+ * prefer IPv4. Use fascist_firewall_prefer_ipv6_orport() instead of accessing
* this value directly. */
int ClientPreferIPv6ORPort;
/** If true, prefer an IPv6 directory port over an IPv4 one for direct
- * directory connections. Use nodelist_prefer_ipv6_dirport() instead of
+ * directory connections. If auto, bridge clients prefer IPv6, and other
+ * clients prefer IPv4. Use fascist_firewall_prefer_ipv6_dirport() instead of
* accessing this value directly. */
int ClientPreferIPv6DirPort;
diff --git a/src/or/policies.c b/src/or/policies.c
index 2a97df7..ecc89da 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -272,8 +272,8 @@ parse_reachable_addresses(void)
ret = -1;
}
- /* XX/teor - we ignore ReachableAddresses for bridge clients and relays */
- if (!options->UseBridges || server_mode(options)) {
+ /* We ignore ReachableAddresses for relays */
+ if (!server_mode(options)) {
if ((reachable_or_addr_policy
&& policy_is_reject_star(reachable_or_addr_policy, AF_UNSPEC))
|| (reachable_dir_addr_policy
@@ -282,12 +282,45 @@ parse_reachable_addresses(void)
"ReachableAddresses, ReachableORAddresses, or "
"ReachableDirAddresses reject all addresses. Please accept "
"some addresses in these options.");
+ } else if (options->ClientUseIPv4 == 1
+ && ((reachable_or_addr_policy
+ && policy_is_reject_star(reachable_or_addr_policy, AF_INET))
+ || (reachable_dir_addr_policy
+ && policy_is_reject_star(reachable_dir_addr_policy, AF_INET)))) {
+ log_warn(LD_CONFIG, "You have set ClientUseIPv4 1, but "
+ "ReachableAddresses, ReachableORAddresses, or "
+ "ReachableDirAddresses reject all IPv4 addresses. "
+ "Tor will not connect using IPv4.");
+ } else if (fascist_firewall_use_ipv6(options)
+ && ((reachable_or_addr_policy
+ && policy_is_reject_star(reachable_or_addr_policy, AF_INET6))
+ || (reachable_dir_addr_policy
+ && policy_is_reject_star(reachable_dir_addr_policy, AF_INET6)))) {
+ log_warn(LD_CONFIG, "You have configured tor to use IPv6 "
+ "(ClientUseIPv6 1 or UseBridges 1), but "
+ "ReachableAddresses, ReachableORAddresses, or "
+ "ReachableDirAddresses reject all IPv6 addresses. "
+ "Tor will not connect using IPv6.");
}
}
return ret;
}
+/** Return true iff the firewall options, including ClientUseIPv4 0 and
+ * ClientUseIPv6 0, might block any address:port combination.
+ */
+int
+firewall_is_fascist_or(void)
+{
+ const or_options_t *options = get_options();
+ /* Assume every non-bridge relay has an IPv4 address.
+ * Clients which use bridges may only know the IPv6 address of their
+ * bridge. */
+ return (reachable_or_addr_policy != NULL || options->ClientUseIPv4 == 0
+ || (options->ClientUseIPv6 == 0 && options->UseBridges == 1));
+}
+
/** Return true iff <b>policy</b> (possibly NULL) will allow a
* connection to <b>addr</b>:<b>port</b>.
*/
@@ -326,14 +359,14 @@ addr_policy_permits_address(uint32_t addr, uint16_t port,
/** Return true iff we think our firewall will let us make a connection to
* addr:port.
*
- * If UseBridges is set, or we are configured as a server, ignore the
- * following address family preferences.
+ * If we are configured as a server, ignore any address family preference and
+ * just use IPv4.
* Otherwise:
* - return false for all IPv4 addresses:
* - if ClientUseIPv4 is 0, or
* if pref_only and pref_ipv6 are both true;
* - return false for all IPv6 addresses:
- * - if ClientUseIPv6 is 0, or
+ * - if fascist_firewall_use_ipv6() is 0, or
* - if pref_only is true and pref_ipv6 is false.
*
* Return false if addr is NULL or tor_addr_is_null(), or if port is 0. */
@@ -349,13 +382,14 @@ fascist_firewall_allows_address(const tor_addr_t *addr,
return 0;
}
- if (!options->UseBridges && !server_mode(options)) {
+ if (!server_mode(options)) {
if (tor_addr_family(addr) == AF_INET &&
(!options->ClientUseIPv4 || (pref_only && pref_ipv6)))
return 0;
+ /* Bridges can always use IPv6 */
if (tor_addr_family(addr) == AF_INET6 &&
- (!options->ClientUseIPv6 || (pref_only && !pref_ipv6)))
+ (!fascist_firewall_use_ipv6(options) || (pref_only && !pref_ipv6)))
return 0;
}
@@ -363,6 +397,87 @@ fascist_firewall_allows_address(const tor_addr_t *addr,
firewall_policy);
}
+/** Is this client configured to use IPv6?
+ * Clients use IPv6 if ClientUseIPv6 is 1, or UseBridges is 1.
+ */
+int fascist_firewall_use_ipv6(const or_options_t *options)
+{
+ return (options->ClientUseIPv6 == 1 || options->UseBridges == 1);
+}
+
+/** Do we prefer to connect to IPv6, ignoring ClientPreferIPv6ORPort and
+ * ClientPreferIPv6DirPort?
+ * If we're unsure, return -1, otherwise, return 1 for IPv6 and 0 for IPv4.
+ */
+static int
+fascist_firewall_prefer_ipv6_impl(const or_options_t *options)
+{
+ /*
+ Cheap implementation of config options ClientUseIPv4 & ClientUseIPv6 --
+ If we're a server or IPv6 is disabled, use IPv4.
+ If IPv4 is disabled, use IPv6.
+ */
+
+ if (server_mode(options) || !fascist_firewall_use_ipv6(options)) {
+ return 0;
+ }
+
+ if (!options->ClientUseIPv4) {
+ return 1;
+ }
+
+ return -1;
+}
+
+/** Do we prefer to connect to IPv6 ORPorts?
+ */
+int
+fascist_firewall_prefer_ipv6_orport(const or_options_t *options)
+{
+ int pref_ipv6 = fascist_firewall_prefer_ipv6_impl(options);
+
+ if (pref_ipv6 >= 0) {
+ return pref_ipv6;
+ }
+
+ /* We can use both IPv4 and IPv6 - which do we prefer? */
+ if (options->ClientPreferIPv6ORPort == 1) {
+ return 1;
+ }
+
+ /* For bridge clients, ClientPreferIPv6ORPort auto means "prefer IPv6". */
+ if (options->UseBridges && options->ClientPreferIPv6ORPort != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Do we prefer to connect to IPv6 DirPorts?
+ */
+int
+fascist_firewall_prefer_ipv6_dirport(const or_options_t *options)
+{
+ int pref_ipv6 = fascist_firewall_prefer_ipv6_impl(options);
+
+ if (pref_ipv6 >= 0) {
+ return pref_ipv6;
+ }
+
+ /* We can use both IPv4 and IPv6 - which do we prefer? */
+ if (options->ClientPreferIPv6DirPort == 1) {
+ return 1;
+ }
+
+ /* For bridge clients, ClientPreferIPv6ORPort auto means "prefer IPv6".
+ * XX/teor - do bridge clients ever use a DirPort? */
+ if (options->UseBridges && options->ClientPreferIPv6DirPort != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
/** Return true iff we think our firewall will let us make a connection to
* addr:port. Uses ReachableORAddresses or ReachableDirAddresses based on
* fw_connection.
@@ -380,12 +495,12 @@ fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port,
return fascist_firewall_allows_address(addr, port,
reachable_or_addr_policy,
pref_only,
- nodelist_prefer_ipv6_orport(options));
+ fascist_firewall_prefer_ipv6_orport(options));
} else if (fw_connection == FIREWALL_DIR_CONNECTION) {
return fascist_firewall_allows_address(addr, port,
reachable_dir_addr_policy,
pref_only,
- nodelist_prefer_ipv6_dirport(options));
+ fascist_firewall_prefer_ipv6_dirport(options));
} else {
log_warn(LD_BUG, "Bad firewall_connection_t value %d.",
fw_connection);
@@ -478,30 +593,6 @@ fascist_firewall_allows_ri_impl(const routerinfo_t *ri,
ri->dir_port, fw_connection, pref_only);
}
-/** Return true iff we think our firewall will let us make a connection to
- * <b>ri</b> on either its IPv4 or IPv6 address. Uses
- * or_port/ipv6_orport/ReachableORAddresses or dir_port/ReachableDirAddresses
- * based on IPv4/IPv6 and <b>fw_connection</b>.
- * If pref_only, return false if addr is not in the client's preferred address
- * family.
- * Consults the corresponding node if the addresses in ri are not permitted. */
-int
-fascist_firewall_allows_ri(const routerinfo_t *ri,
- firewall_connection_t fw_connection, int pref_only)
-{
- if (!ri) {
- return 0;
- }
-
- /* Assume IPv4 and IPv6 DirPorts are the same */
- if (fascist_firewall_allows_ri_impl(ri, fw_connection, pref_only)) {
- return 1;
- } else {
- const node_t *node = node_get_by_id(ri->cache_info.identity_digest);
- return fascist_firewall_allows_node(node, fw_connection, pref_only);
- }
-}
-
/** Like fascist_firewall_allows_rs, but doesn't consult the node. */
static int
fascist_firewall_allows_rs_impl(const routerstatus_t *rs,
@@ -563,40 +654,6 @@ fascist_firewall_allows_md_impl(const microdesc_t *md,
}
/** Return true iff we think our firewall will let us make a connection to
- * <b>md</b> on its IPv6 address. (The IPv4 address is in the routerstatus and
- * the routerinfo.) Uses ipv6_orport/ReachableORAddresses or
- * dir_port/ReachableDirAddresses based on <b>fw_connection</b>.
- * If pref_only, return false if addr is not in the client's preferred address
- * family.
- * Consults the corresponding node if the address in md is not permitted. */
-int
-fascist_firewall_allows_md(const microdesc_t *md,
- firewall_connection_t fw_connection,
- int pref_only)
-{
- if (!md) {
- return 0;
- }
-
- if (fascist_firewall_allows_md_impl(md, fw_connection, pref_only)) {
- return 1;
- } else {
- networkstatus_t *ns;
- ns = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
- if (!ns) {
- return 0;
- }
- const routerstatus_t *rs;
- rs = router_get_consensus_status_by_descriptor_digest(ns, md->digest);
- if (!rs) {
- return 0;
- }
- const node_t *node = node_get_by_id(rs->identity_digest);
- return fascist_firewall_allows_node(node, fw_connection, pref_only);
- }
-}
-
-/** Return true iff we think our firewall will let us make a connection to
* <b>node</b>:
* - if <b>preferred</b> is true, on its preferred address,
* - if not, on either its IPv4 or IPv6 address.
@@ -816,44 +873,6 @@ fascist_firewall_choose_address_ipv4h(uint32_t ipv4h_addr,
} \
STMT_END
-/** Copy an address and port from <b>ri</b> into <b>ap</b> that we think our
- * firewall will let us connect to. Uses ipv4h_addr/ipv6_addr and
- * ipv4_orport/ipv6_orport/ReachableORAddresses or
- * ipv4_dirport/ipv6_dirport/ReachableDirAddresses based on IPv4/IPv6 and
- * <b>fw_connection</b>.
- * If pref_only, only choose preferred addresses. In either case, choose
- * a preferred address before an address that's not preferred.
- * If neither address is chosen, return 0, else return 1.
- * Consults the corresponding node if the addresses in ri are not valid. */
-int
-fascist_firewall_choose_address_ri(const routerinfo_t *ri,
- firewall_connection_t fw_connection,
- int pref_only, tor_addr_port_t* ap)
-{
- if (!ri) {
- return 0;
- }
-
- tor_assert(ap);
-
- /* Don't do the lookup if the IPv6 address/port in ri is OK.
- * If it's OK, assume the dir_port is also OK. */
- tor_addr_port_t ipv6_or_ap;
- IPV6_OR_LOOKUP(ri, ri->cache_info.identity_digest, ipv6_or_ap);
-
- /* Assume IPv4 and IPv6 DirPorts are the same.
- * Assume the IPv6 OR and Dir addresses are the same. */
- return fascist_firewall_choose_address_ipv4h(ri->addr,
- ri->or_port,
- ri->dir_port,
- &ipv6_or_ap.addr,
- ipv6_or_ap.port,
- ri->dir_port,
- fw_connection,
- pref_only,
- ap);
-}
-
/** Copy an address and port from <b>rs</b> into <b>ap</b> that we think our
* firewall will let us connect to. Uses ipv4h_addr/ipv6_addr and
* ipv4_orport/ipv6_orport/ReachableORAddresses or
@@ -892,73 +911,6 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs,
ap);
}
-/* Copy the IPv6 address and ORPort from <b>md</b> into <b>ap</b> if we think
- * our firewall will let us connect to it. Uses ReachableORAddresses.
- * If pref_only, only copy if it's a preferred address.
- * If <b>fw_connection</b> is FIREWALL_DIR_CONNECTION, don't copy the address.
- * If the address isn't copied, return 0, else return 1. */
-static int
-fascist_firewall_choose_address_md_impl(const microdesc_t *md,
- firewall_connection_t fw_connection,
- int pref_only, tor_addr_port_t* ap)
-{
- if (!md) {
- return 0;
- }
-
- /* Can't check dirport, it doesn't have one */
- if (fw_connection == FIREWALL_DIR_CONNECTION) {
- return 0;
- }
-
- tor_assert(ap);
-
- if (fascist_firewall_allows_md(md, fw_connection, pref_only)) {
- tor_addr_copy(&ap->addr, &md->ipv6_addr);
- ap->port = md->ipv6_orport;
- return 1;
- } else {
- return 0;
- }
-}
-
-/** Lookup the node for md, and call fascist_firewall_choose_address_node on
- * it. If any step in this process fails, fall back to calling
- * fascist_firewall_choose_address_md_impl. */
-int
-fascist_firewall_choose_address_md(const microdesc_t *md,
- firewall_connection_t fw_connection,
- int pref_only, tor_addr_port_t* ap)
-{
- if (!md) {
- return 0;
- }
-
- tor_assert(ap);
-
- /* If we can't get the node, */
- networkstatus_t *ns;
- ns = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
- if (!ns) {
- return fascist_firewall_choose_address_md_impl(md, fw_connection,
- pref_only, ap);
- }
- const routerstatus_t *rs;
- rs = router_get_consensus_status_by_descriptor_digest(ns, md->digest);
- if (!rs) {
- return fascist_firewall_choose_address_md_impl(md, fw_connection,
- pref_only, ap);
- }
- const node_t *node = node_get_by_id(rs->identity_digest);
- if (node) {
- return fascist_firewall_choose_address_node(node, fw_connection,
- pref_only, ap);
- } else {
- return fascist_firewall_choose_address_md_impl(md, fw_connection,
- pref_only, ap);
- }
-}
-
/** Copy an address and port from <b>node</b> into <b>ap</b> that we think our
* firewall will let us connect to. Uses ipv4h_addr/ipv6_addr and
* ipv4_orport/ipv6_orport/ReachableORAddresses or
diff --git a/src/or/policies.h b/src/or/policies.h
index 7309bcf..ac4f7ea 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -29,6 +29,11 @@ typedef enum firewall_connection_t {
typedef int exit_policy_parser_cfg_t;
+int firewall_is_fascist_or(void);
+int fascist_firewall_use_ipv6(const or_options_t *options);
+int fascist_firewall_prefer_ipv6_orport(const or_options_t *options);
+int fascist_firewall_prefer_ipv6_dirport(const or_options_t *options);
+
int fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port,
firewall_connection_t fw_connection,
int pref_only);
@@ -39,15 +44,9 @@ int fascist_firewall_allows_address_ipv4h(uint32_t ipv4h_or_addr,
uint16_t ipv4_or_port,
firewall_connection_t fw_connection,
int pref_only);
-int fascist_firewall_allows_ri(const routerinfo_t *ri,
- firewall_connection_t fw_connection,
- int pref_only);
int fascist_firewall_allows_rs(const routerstatus_t *rs,
firewall_connection_t fw_connection,
int pref_only);
-int fascist_firewall_allows_md(const microdesc_t *md,
- firewall_connection_t fw_connection,
- int pref_only);
int fascist_firewall_allows_node(const node_t *node,
firewall_connection_t fw_connection,
int pref_only);
@@ -61,15 +60,9 @@ const tor_addr_port_t * fascist_firewall_choose_address(
int want_a,
firewall_connection_t fw_connection,
int pref_only);
-int fascist_firewall_choose_address_ri(const routerinfo_t *ri,
- firewall_connection_t fw_connection,
- int pref_only, tor_addr_port_t* ap);
int fascist_firewall_choose_address_rs(const routerstatus_t *rs,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap);
-int fascist_firewall_choose_address_md(const microdesc_t *md,
- firewall_connection_t fw_connection,
- int pref_only, tor_addr_port_t* ap);
int fascist_firewall_choose_address_node(const node_t *node,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 2923da3..247818d 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1594,8 +1594,8 @@ router_picked_poor_directory_log(const routerstatus_t *rs)
#define RETRY_ALTERNATE_IP_VERSION(retry_label) \
STMT_BEGIN \
if (result == NULL && try_ip_pref && options->ClientUseIPv4 \
- && options->ClientUseIPv6 && !server_mode(options) && n_not_preferred \
- && !n_busy) { \
+ && fascist_firewall_use_ipv6(options) && !server_mode(options) \
+ && n_not_preferred && !n_busy) { \
n_excluded = 0; \
n_busy = 0; \
try_ip_pref = 0; \
@@ -1976,7 +1976,7 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
continue;
if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
continue;
- /* Choose a node with a preferred OR address */
+ /* Choose a node with an OR address that matches the firewall rules */
if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, pref_addr))
continue;
@@ -2443,7 +2443,7 @@ node_sl_choose_by_bandwidth(const smartlist_t *sl,
* If <b>CRN_PREF_ADDR</b> is set in flags, we only consider nodes that
* have an address that is preferred by the ClientPreferIPv6ORPort setting
* (regardless of this flag, we exclude nodes that aren't allowed by the
- * firewall, including ClientUseIPv4 0 and ClientUseIPv6 0).
+ * firewall, including ClientUseIPv4 0 and fascist_firewall_use_ipv6() == 0).
*/
const node_t *
router_choose_random_node(smartlist_t *excludedsmartlist,
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index e4947e0..a0208b9 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -107,6 +107,11 @@ test_choose_random_entry_no_guards(void *arg)
chosen_entry = choose_random_entry(NULL);
tt_assert(chosen_entry);
+ /* And with the preference on auto */
+ mocked_options.ClientPreferIPv6ORPort = -1;
+ chosen_entry = choose_random_entry(NULL);
+ tt_assert(chosen_entry);
+
/* Check that we don't get a guard if it doesn't pass mandatory address
* settings */
memset(&mocked_options, 0, sizeof(mocked_options));
@@ -128,6 +133,21 @@ test_choose_random_entry_no_guards(void *arg)
chosen_entry = choose_random_entry(NULL);
tt_assert(chosen_entry);
+ /* Check that we get a guard if it passes preferred address settings when
+ * they're auto */
+ memset(&mocked_options, 0, sizeof(mocked_options));
+ mocked_options.ClientUseIPv4 = 1;
+ mocked_options.ClientPreferIPv6ORPort = -1;
+
+ chosen_entry = choose_random_entry(NULL);
+ tt_assert(chosen_entry);
+
+ /* And with IPv6 active */
+ mocked_options.ClientUseIPv6 = 1;
+
+ chosen_entry = choose_random_entry(NULL);
+ tt_assert(chosen_entry);
+
done:
memset(&mocked_options, 0, sizeof(mocked_options));
UNMOCK(get_options);
@@ -166,6 +186,11 @@ test_choose_random_entry_one_possible_guard(void *arg)
chosen_entry = choose_random_entry(NULL);
tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+ /* And with the preference on auto */
+ mocked_options.ClientPreferIPv6ORPort = -1;
+ chosen_entry = choose_random_entry(NULL);
+ tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+
/* Check that we don't get a guard if it doesn't pass mandatory address
* settings */
memset(&mocked_options, 0, sizeof(mocked_options));
@@ -190,6 +215,21 @@ test_choose_random_entry_one_possible_guard(void *arg)
* time, so we can't be sure we get the guard */
tt_assert(chosen_entry);
+ /* Check that we get the guard if it passes preferred address settings when
+ * they're auto */
+ memset(&mocked_options, 0, sizeof(mocked_options));
+ mocked_options.ClientUseIPv4 = 1;
+ mocked_options.ClientPreferIPv6ORPort = -1;
+
+ chosen_entry = choose_random_entry(NULL);
+ tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+
+ /* and with IPv6 active */
+ mocked_options.ClientUseIPv6 = 1;
+
+ chosen_entry = choose_random_entry(NULL);
+ tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+
done:
memset(&mocked_options, 0, sizeof(mocked_options));
UNMOCK(get_options);
@@ -722,8 +762,9 @@ test_node_preferred_orport(void *arg)
/* Setup options */
memset(&mocked_options, 0, sizeof(mocked_options));
- /* We don't test ClientPreferIPv6ORPort here, because it's only used in
- * nodelist_set_consensus to setup each node_t. */
+ /* We don't test ClientPreferIPv6ORPort here, because it's used in
+ * nodelist_set_consensus to setup node.ipv6_preferred, which we set
+ * directly. */
MOCK(get_options, mock_get_options);
/* Setup IP addresses */
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 077d1b2..1daa38e 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -1235,8 +1235,8 @@ test_policies_fascist_firewall_allows_address(void *arg)
/* Test the function's address matching with UseBridges on */
memset(&mock_options, 0, sizeof(or_options_t));
- mock_options.ClientUseIPv4 = 0;
- mock_options.ClientUseIPv6 = 0;
+ mock_options.ClientUseIPv4 = 1;
+ mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 1;
tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
@@ -1248,6 +1248,38 @@ test_policies_fascist_firewall_allows_address(void *arg)
tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
== 0);
+ /* Preferring IPv4 */
+ tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0)
+ == 1);
+ tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0)
+ == 0);
+ tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0)
+ == 0);
+ tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0)
+ == 0);
+
+ /* Preferring IPv6 */
+ tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1)
+ == 0);
+ tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1)
+ == 1);
+ tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1)
+ == 0);
+ tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1)
+ == 0);
+
+ /* bridge clients always use IPv6, regardless of ClientUseIPv6 */
+ mock_options.ClientUseIPv4 = 1;
+ mock_options.ClientUseIPv6 = 0;
+ tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
+ == 1);
+ tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
+ == 1);
+ tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
+ == 0);
+ tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
+ == 0);
+
/* Test the function's address matching with IPv4 on */
memset(&mock_options, 0, sizeof(or_options_t));
mock_options.ClientUseIPv4 = 1;
@@ -1389,6 +1421,22 @@ test_policies_fascist_firewall_choose_address(void *arg)
FIREWALL_DIR_CONNECTION, 1)
== &ipv4_dir_ap);
+ /* Auto (Preferring IPv4) */
+ mock_options.ClientPreferIPv6ORPort = -1;
+ mock_options.ClientPreferIPv6DirPort = -1;
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 0)
+ == &ipv4_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 1)
+ == &ipv4_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0)
+ == &ipv4_dir_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 1)
+ == &ipv4_dir_ap);
+
/* Preferring IPv6 */
mock_options.ClientPreferIPv6ORPort = 1;
mock_options.ClientPreferIPv6DirPort = 1;
@@ -1440,41 +1488,75 @@ test_policies_fascist_firewall_choose_address(void *arg)
/* Choose an address with UseBridges on */
memset(&mock_options, 0, sizeof(or_options_t));
mock_options.UseBridges = 1;
+ mock_options.ClientUseIPv4 = 1;
+ mock_options.ClientUseIPv6 = 1;
- for (mock_options.ClientUseIPv4 = 0; mock_options.ClientUseIPv4 <= 1;
- mock_options.ClientUseIPv4++) {
- for (mock_options.ClientUseIPv6 = 0; mock_options.ClientUseIPv6 <= 1;
- mock_options.ClientUseIPv6++) {
- for (mock_options.ClientPreferIPv6ORPort = 0;
- mock_options.ClientPreferIPv6ORPort <= 1;
- mock_options.ClientPreferIPv6ORPort++) {
- for (mock_options.ClientPreferIPv6DirPort = 0;
- mock_options.ClientPreferIPv6DirPort <= 1;
- mock_options.ClientPreferIPv6DirPort++) {
- /* This (ab)uses the actual enum values */
- tt_assert(FIREWALL_OR_CONNECTION < FIREWALL_DIR_CONNECTION);
- for (firewall_connection_t fw_connection = FIREWALL_OR_CONNECTION;
- fw_connection <= FIREWALL_DIR_CONNECTION; fw_connection++) {
- for (int pref_only = 0; pref_only <= 1; pref_only++) {
-
- /* Ignoring all other settings, want_a should choose the address
- * for bridge clients */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap,
- &ipv6_or_ap, 1,
- fw_connection,
- pref_only)
- == &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap,
- &ipv6_or_ap, 0,
- fw_connection,
- pref_only)
- == &ipv6_or_ap);
- }
- }
- }
- }
- }
- }
+ /* Preferring IPv4 */
+ mock_options.ClientPreferIPv6ORPort = 0;
+ mock_options.ClientPreferIPv6DirPort = 0;
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 0)
+ == &ipv4_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 1)
+ == &ipv4_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0)
+ == &ipv4_dir_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 1)
+ == &ipv4_dir_ap);
+
+ /* Auto (Preferring IPv6 for bridge clients) */
+ mock_options.ClientPreferIPv6ORPort = -1;
+ mock_options.ClientPreferIPv6DirPort = -1;
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 0)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 1)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0)
+ == &ipv6_dir_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 1)
+ == &ipv6_dir_ap);
+
+ /* Preferring IPv6 */
+ mock_options.ClientPreferIPv6ORPort = 1;
+ mock_options.ClientPreferIPv6DirPort = 1;
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 0)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 1)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0)
+ == &ipv6_dir_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 1)
+ == &ipv6_dir_ap);
+
+
+ /* In the default configuration (Auto / IPv6 off), bridge clients should
+ * still use and prefer IPv6 regardless of ClientUseIPv6. */
+ mock_options.ClientUseIPv6 = 0;
+ mock_options.ClientPreferIPv6ORPort = -1;
+ mock_options.ClientPreferIPv6DirPort = -1;
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 0)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 1)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0)
+ == &ipv6_dir_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 1)
+ == &ipv6_dir_ap);
/* Choose an address with IPv4 on */
memset(&mock_options, 0, sizeof(or_options_t));
1
0

[tor/master] Optimise reachability checks when iterating through relay lists
by nickm@torproject.org 11 Feb '16
by nickm@torproject.org 11 Feb '16
11 Feb '16
commit 772577b547aa5e6b13b89f465acf656cd08f2917
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Thu Jan 21 13:30:57 2016 +1100
Optimise reachability checks when iterating through relay lists
Skip address checks on servers.
Skip allowed-only address checks on non-bridge clients with IPv4.
---
src/or/policies.c | 4 ++++
src/or/routerlist.c | 55 +++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/src/or/policies.c b/src/or/policies.c
index 506edec..0dc4f96 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -323,6 +323,8 @@ firewall_is_fascist_impl(void)
/** Return true iff the firewall options, including ClientUseIPv4 0 and
* ClientUseIPv6 0, might block any OR address:port combination.
+ * Address preferences may still change which address is selected even if
+ * this function returns false.
*/
int
firewall_is_fascist_or(void)
@@ -332,6 +334,8 @@ firewall_is_fascist_or(void)
/** Return true iff the firewall options, including ClientUseIPv4 0 and
* ClientUseIPv6 0, might block any Dir address:port combination.
+ * Address preferences may still change which address is selected even if
+ * this function returns false.
*/
int
firewall_is_fascist_dir(void)
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 247818d..9b8885e 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1623,6 +1623,30 @@ router_picked_poor_directory_log(const routerstatus_t *rs)
} \
STMT_END
+/* When iterating through the routerlist, can OR address/port preference
+ * and reachability checks be skipped?
+ */
+static int
+router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
+{
+ /* Servers always have and prefer IPv4.
+ * And if clients are checking against the firewall for reachability only,
+ * but there's no firewall, don't bother checking */
+ return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_or());
+}
+
+/* When iterating through the routerlist, can Dir address/port preference
+ * and reachability checks be skipped?
+ */
+static int
+router_skip_dir_reachability(const or_options_t *options, int try_ip_pref)
+{
+ /* Servers always have and prefer IPv4.
+ * And if clients are checking against the firewall for reachability only,
+ * but there's no firewall, don't bother checking */
+ return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_dir());
+}
+
/** Pick a random running valid directory server/mirror from our
* routerlist. Arguments are as for router_pick_directory_server(), except:
*
@@ -1661,6 +1685,9 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
+ const int skip_or = router_skip_or_reachability(options, try_ip_pref);
+ const int skip_dir = router_skip_dir_reachability(options, try_ip_pref);
+
/* Find all the running dirservers we know about. */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
int is_trusted, is_trusted_extrainfo;
@@ -1704,18 +1731,20 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
- /* We use an IPv6 address if we have one and we prefer it.
+ /* Clients use IPv6 addresses if the server has one and the client
+ * prefers IPv6.
* Add the router if its preferred address and port are reachable.
* If we don't get any routers, we'll try again with the non-preferred
* address for each router (if any). (To ensure correct load-balancing
* we try routers that only have one address both times.)
*/
- if (!fascistfirewall ||
+ if (!fascistfirewall || skip_or ||
fascist_firewall_allows_rs(status, FIREWALL_OR_CONNECTION,
try_ip_pref))
smartlist_add(is_trusted ? trusted_tunnel :
is_overloaded ? overloaded_tunnel : tunnel, (void*)node);
- else if (fascist_firewall_allows_rs(status, FIREWALL_DIR_CONNECTION,
+ else if (skip_dir ||
+ fascist_firewall_allows_rs(status, FIREWALL_DIR_CONNECTION,
try_ip_pref))
smartlist_add(is_trusted ? trusted_direct :
is_overloaded ? overloaded_direct : direct, (void*)node);
@@ -1820,6 +1849,9 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
+ const int skip_or = router_skip_or_reachability(options, try_ip_pref);
+ const int skip_dir = router_skip_dir_reachability(options, try_ip_pref);
+
SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d)
{
int is_overloaded =
@@ -1845,17 +1877,19 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
continue;
}
- /* We use an IPv6 address if we have one and we prefer it.
+ /* Clients use IPv6 addresses if the server has one and the client
+ * prefers IPv6.
* Add the router if its preferred address and port are reachable.
* If we don't get any routers, we'll try again with the non-preferred
* address for each router (if any). (To ensure correct load-balancing
* we try routers that only have one address both times.)
*/
- if (!fascistfirewall ||
+ if (!fascistfirewall || skip_or ||
fascist_firewall_allows_dir_server(d, FIREWALL_OR_CONNECTION,
try_ip_pref))
smartlist_add(is_overloaded ? overloaded_tunnel : tunnel, (void*)d);
- else if (fascist_firewall_allows_dir_server(d, FIREWALL_DIR_CONNECTION,
+ else if (skip_dir ||
+ fascist_firewall_allows_dir_server(d, FIREWALL_DIR_CONNECTION,
try_ip_pref))
smartlist_add(is_overloaded ? overloaded_direct : direct, (void*)d);
else if (!tor_addr_is_null(&d->ipv6_addr))
@@ -1965,7 +1999,10 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
int need_uptime, int need_capacity,
int need_guard, int need_desc,
int pref_addr)
-{ /* XXXX MOVE */
+{
+ const int check_reach = !router_skip_or_reachability(get_options(),
+ pref_addr);
+ /* XXXX MOVE */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
if (!node->is_running ||
(!node->is_valid && !allow_invalid))
@@ -1977,7 +2014,9 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
continue;
/* Choose a node with an OR address that matches the firewall rules */
- if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, pref_addr))
+ if (check_reach && !fascist_firewall_allows_node(node,
+ FIREWALL_OR_CONNECTION,
+ pref_addr))
continue;
smartlist_add(sl, (void *)node);
1
0

[tor/master] Return NULL from extend_info_from_node if the node has no allowed address
by nickm@torproject.org 11 Feb '16
by nickm@torproject.org 11 Feb '16
11 Feb '16
commit 1401117ff2bc5fc90df51d19c3c0d7abc439c34e
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Fri Jan 22 17:43:24 2016 +1100
Return NULL from extend_info_from_node if the node has no allowed address
Modify callers to correctly handle these new NULL returns:
* fix assert in onion_extend_cpath
* warn and discard circuit in circuit_get_open_circ_or_launch
* warn, discard circuit, and tell controller in handle_control_extendcircuit
---
src/or/circuitbuild.c | 35 +++++++++++++++++++++++------------
src/or/circuituse.c | 7 ++++++-
src/or/control.c | 18 ++++++++++++++++--
3 files changed, 45 insertions(+), 15 deletions(-)
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index dcb9de3..daf0b2a 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -2241,9 +2241,11 @@ onion_extend_cpath(origin_circuit_t *circ)
if (r) {
/* If we're a client, use the preferred address rather than the
primary address, for potentially connecting to an IPv6 OR
- port. */
- info = extend_info_from_node(r, server_mode(get_options()) == 0);
- tor_assert(info);
+ port. Servers always want the primary (IPv4) address. */
+ int client = (server_mode(get_options()) == 0);
+ info = extend_info_from_node(r, client);
+ /* Clients can fail to find an allowed address */
+ tor_assert(info || client);
}
} else {
const node_t *r =
@@ -2318,34 +2320,43 @@ extend_info_new(const char *nickname, const char *digest,
* <b>for_direct_connect</b> is true, in which case the preferred
* address is used instead. May return NULL if there is not enough
* info about <b>node</b> to extend to it--for example, if there is no
- * routerinfo_t or microdesc_t.
+ * routerinfo_t or microdesc_t, or if for_direct_connect is true and none of
+ * the node's addresses are allowed by tor's firewall and IP version config.
**/
extend_info_t *
extend_info_from_node(const node_t *node, int for_direct_connect)
{
tor_addr_port_t ap;
+ int valid_addr = 0;
if (node->ri == NULL && (node->rs == NULL || node->md == NULL))
return NULL;
- /* Choose a preferred address first, but fall back to an allowed address*/
+ /* Choose a preferred address first, but fall back to an allowed address.
+ * choose_address returns 1 on success, but get_prim_orport returns 0. */
if (for_direct_connect)
- fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, &ap);
+ valid_addr = fascist_firewall_choose_address_node(node,
+ FIREWALL_OR_CONNECTION,
+ 0, &ap);
else
- node_get_prim_orport(node, &ap);
+ valid_addr = !node_get_prim_orport(node, &ap);
- log_debug(LD_CIRC, "using %s for %s",
- fmt_addrport(&ap.addr, ap.port),
- node->ri ? node->ri->nickname : node->rs->nickname);
+ if (valid_addr)
+ log_debug(LD_CIRC, "using %s for %s",
+ fmt_addrport(&ap.addr, ap.port),
+ node->ri ? node->ri->nickname : node->rs->nickname);
+ else
+ log_warn(LD_CIRC, "Could not choose valid address for %s",
+ node->ri ? node->ri->nickname : node->rs->nickname);
- if (node->ri)
+ if (valid_addr && node->ri)
return extend_info_new(node->ri->nickname,
node->identity,
node->ri->onion_pkey,
node->ri->onion_curve25519_pkey,
&ap.addr,
ap.port);
- else if (node->rs && node->md)
+ else if (valid_addr && node->rs && node->md)
return extend_info_new(node->rs->nickname,
node->identity,
node->md->onion_pkey,
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index e742a56..4831f2b 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -2006,8 +2006,13 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if (r && node_has_descriptor(r)) {
/* We might want to connect to an IPv6 bridge for loading
descriptors so we use the preferred address rather than
- the primary. */
+ the primary. */
extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0);
+ if (!extend_info) {
+ log_warn(LD_CIRC,"Could not make a one-hop connection to %s. "
+ "Discarding this circuit.", conn->chosen_exit_name);
+ return -1;
+ }
} else {
log_debug(LD_DIR, "considering %d, %s",
want_onehop, conn->chosen_exit_name);
diff --git a/src/or/control.c b/src/or/control.c
index 66182fe..2c0209e 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -2864,12 +2864,26 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
}
/* now circ refers to something that is ready to be extended */
+ int first_node = zero_circ;
SMARTLIST_FOREACH(nodes, const node_t *, node,
{
- extend_info_t *info = extend_info_from_node(node, 0);
- tor_assert(info); /* True, since node_has_descriptor(node) == true */
+ extend_info_t *info = extend_info_from_node(node, first_node);
+ if (first_node && !info) {
+ log_warn(LD_CONTROL,
+ "controller tried to connect to a node that doesn't have any "
+ "addresses that are allowed by the firewall configuration; "
+ "circuit marked for closing.");
+ circuit_mark_for_close(TO_CIRCUIT(circ), -END_CIRC_REASON_CONNECTFAILED);
+ connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn);
+ goto done;
+ } else {
+ /* True, since node_has_descriptor(node) == true and we are extending
+ * to the node's primary address */
+ tor_assert(info);
+ }
circuit_append_new_exit(circ, info);
extend_info_free(info);
+ first_node = 0;
});
/* now that we've populated the cpath, start extending */
1
0

11 Feb '16
commit 77a9de0d48e61e6762e65f6099c9a424544eb0ad
Author: teor (Tim Wilson-Brown) <teor2345(a)gmail.com>
Date: Fri Jan 22 15:10:18 2016 +1100
Automatically use IPv6 when ClientUseIPv4 is 0
Consequential changes to log messages:
* it's no longer possible to disable both IPv4 and IPv6,
* refactor common string out of remaining log messages
---
src/or/config.c | 16 ++++++++--------
src/or/policies.c | 6 ++++--
src/test/test_entrynodes.c | 11 +++++++----
src/test/test_policy.c | 16 +++++++++-------
4 files changed, 28 insertions(+), 21 deletions(-)
diff --git a/src/or/config.c b/src/or/config.c
index caa01d1..b9d9fb2 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -3108,20 +3108,20 @@ options_validate(or_options_t *old_options, or_options_t *options,
/* We check if Reachable*Addresses blocks all addresses in
* parse_reachable_addresses(). */
- if (options->ClientUseIPv4 == 0 && !fascist_firewall_use_ipv6(options))
- REJECT("Tor cannot connect to the Internet if ClientUseIPv4 is 0 and "
- "ClientUseIPv6 is 0. Please set at least one of these options "
- "to 1, or configure bridges.");
+
+#define WARN_PLEASE_USE_IPV6_LOG_MSG \
+ "ClientPreferIPv6%sPort 1 is ignored unless tor is using IPv6. " \
+ "Please set ClientUseIPv6 1, ClientUseIPv4 0, or configure bridges."
if (!fascist_firewall_use_ipv6(options)
&& options->ClientPreferIPv6ORPort == 1)
- log_warn(LD_CONFIG, "ClientPreferIPv6ORPort 1 is ignored unless "
- "ClientUseIPv6 is also 1, or bridges are configured.");
+ log_warn(LD_CONFIG, WARN_PLEASE_USE_IPV6_LOG_MSG, "OR");
if (!fascist_firewall_use_ipv6(options)
&& options->ClientPreferIPv6DirPort == 1)
- log_warn(LD_CONFIG, "ClientPreferIPv6DirPort 1 is ignored unless "
- "ClientUseIPv6 is also 1, or bridges are configured.");
+ log_warn(LD_CONFIG, WARN_PLEASE_USE_IPV6_LOG_MSG, "Dir");
+
+#undef WARN_PLEASE_USE_IPV6_LOG_MSG
if (options->UseBridges &&
server_mode(options))
diff --git a/src/or/policies.c b/src/or/policies.c
index 0dc4f96..734558d 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -420,11 +420,13 @@ fascist_firewall_allows_address(const tor_addr_t *addr,
}
/** Is this client configured to use IPv6?
- * Clients use IPv6 if ClientUseIPv6 is 1, or UseBridges is 1.
*/
int fascist_firewall_use_ipv6(const or_options_t *options)
{
- return (options->ClientUseIPv6 == 1 || options->UseBridges == 1);
+ /* Clients use IPv6 if it's set, or they use bridges, or they don't use
+ * IPv4 */
+ return (options->ClientUseIPv6 == 1 || options->UseBridges == 1
+ || options->ClientUseIPv4 == 0);
}
/** Do we prefer to connect to IPv6, ignoring ClientPreferIPv6ORPort and
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index a0208b9..14baa8c 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -215,20 +215,23 @@ test_choose_random_entry_one_possible_guard(void *arg)
* time, so we can't be sure we get the guard */
tt_assert(chosen_entry);
- /* Check that we get the guard if it passes preferred address settings when
- * they're auto */
+ /* Check that we get a node if it is allowed but not preferred when settings
+ * are auto */
memset(&mocked_options, 0, sizeof(mocked_options));
mocked_options.ClientUseIPv4 = 1;
mocked_options.ClientPreferIPv6ORPort = -1;
chosen_entry = choose_random_entry(NULL);
- tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+
+ /* We disable the guard check and the preferred address check at the same
+ * time, so we can't be sure we get the guard */
+ tt_assert(chosen_entry);
/* and with IPv6 active */
mocked_options.ClientUseIPv6 = 1;
chosen_entry = choose_random_entry(NULL);
- tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+ tt_assert(chosen_entry);
done:
memset(&mocked_options, 0, sizeof(mocked_options));
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 1daa38e..2e87f13 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -1310,7 +1310,8 @@ test_policies_fascist_firewall_allows_address(void *arg)
tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
== 0);
- /* Test the function's address matching with everything off */
+ /* Test the function's address matching with ClientUseIPv4 0.
+ * This means "use IPv6" regardless of the other settings. */
memset(&mock_options, 0, sizeof(or_options_t));
mock_options.ClientUseIPv4 = 0;
mock_options.ClientUseIPv6 = 0;
@@ -1319,7 +1320,7 @@ test_policies_fascist_firewall_allows_address(void *arg)
tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
== 0);
tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
- == 0);
+ == 1);
tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
== 0);
tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
@@ -1596,7 +1597,8 @@ test_policies_fascist_firewall_choose_address(void *arg)
FIREWALL_DIR_CONNECTION, 1)
== &ipv6_dir_ap);
- /* Choose an address with everything off */
+ /* Choose an address with ClientUseIPv4 0.
+ * This means "use IPv6" regardless of the other settings. */
memset(&mock_options, 0, sizeof(or_options_t));
mock_options.ClientUseIPv4 = 0;
mock_options.ClientUseIPv6 = 0;
@@ -1604,16 +1606,16 @@ test_policies_fascist_firewall_choose_address(void *arg)
tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 0)
- == NULL);
+ == &ipv6_or_ap);
tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 1)
- == NULL);
+ == &ipv6_or_ap);
tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
FIREWALL_DIR_CONNECTION, 0)
- == NULL);
+ == &ipv6_dir_ap);
tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
FIREWALL_DIR_CONNECTION, 1)
- == NULL);
+ == &ipv6_dir_ap);
/* Choose from unusual inputs */
memset(&mock_options, 0, sizeof(or_options_t));
1
0