Commit 2d33d192 authored by teor (Tim Wilson-Brown)'s avatar teor (Tim Wilson-Brown)
Browse files

Add ClientUseIPv4 and ClientPreferIPv6DirPort torrc options

ClientUseIPv4 0 tells tor to avoid IPv4 client connections.
ClientPreferIPv6DirPort 1 tells tor to prefer IPv6 directory connections.

Refactor policy for IPv4/IPv6 preferences.

Fix a bug where node->ipv6_preferred could become stale if
ClientPreferIPv6ORPort was changed after the consensus was loaded.

Update documentation, existing code, add unit tests.
parent 4460feaf
o Minor feature (IPv6):
- Add ClientUseIPv4, which is set to 1 by default. If set to 0, tor
avoids using IPv4 for client OR and directory connections.
- Add ClientPreferIPv6DirPort, which is set to 0 by default. If set
to 1, tor prefers IPv6 directory addresses.
- Try harder to fulfil IP version restrictions ClientUseIPv4 0 and
ClientUseIPv6 0; and the preferences ClientPreferIPv6ORPort and
ClientPreferIPv6DirPort.
Closes ticket 17840; patch by "teor".
......@@ -367,6 +367,7 @@ GENERAL OPTIONS
authorities.
By default, the directory authorities are also FallbackDirs. Specifying a
FallbackDir replaces Tor's default hard-coded FallbackDirs (if any).
(See the **DirAuthority** entry for an explanation of each flag.)
[[UseDefaultFallbackDirs]] **UseDefaultFallbackDirs** **0**|**1**::
Use Tor's default hard-coded FallbackDirs (if any). (When a
......@@ -390,6 +391,10 @@ GENERAL OPTIONS
if an "ipv6=__address__:__orport__" flag is present, then the directory
authority is listening for IPv6 connections on the indicated IPv6 address
and OR Port. +
+
Tor will contact the authority at __address__:__port__ (the DirPort) to
download directory documents. If an IPv6 address is supplied, Tor will
also download directory documents at the IPv6 address on the DirPort. +
+
If no **DirAuthority** line is given, Tor will use the default directory
authorities. NOTE: this option is intended for setting up a private Tor
......@@ -1483,17 +1488,31 @@ The following options are useful only for clients (that is, if
If no defaults are available there, these options default to 20, .80,
.60, and 100, respectively.
[[ClientUseIPv4]] **ClientUseIPv4** **0**|**1**::
If this option is set to 0, Tor will avoid connecting to directory servers
and entry nodes over IPv4. Note that clients with an IPv4
address in a **Bridge**, proxy, or pluggable transport line will try
connecting over IPv4 even if **ClientUseIPv4** is set to 0. (Default: 1)
[[ClientUseIPv6]] **ClientUseIPv6** **0**|**1**::
If this option is set to 1, Tor might connect to entry nodes over
IPv6. Note that clients configured with an IPv6 address in a
**Bridge** line will try connecting over IPv6 even if
**ClientUseIPv6** is set to 0. (Default: 0)
If this option is set to 1, Tor might connect to directory servers or
entry nodes over IPv6. Note that clients configured with an IPv6 address
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**::
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)
[[ClientPreferIPv6ORPort]] **ClientPreferIPv6ORPort** **0**|**1**::
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. Other
things may influence the choice. This option breaks a tie to the
favor of IPv6. (Default: 0)
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)
[[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__::
Tor clients don't build circuits for user traffic until they know
......
......@@ -2161,14 +2161,12 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
* family. */
nodelist_add_node_and_family(excluded, node);
}
if (firewall_is_fascist_or()) {
/* Exclude all ORs that we can't reach through our firewall */
smartlist_t *nodes = nodelist_get_list();
SMARTLIST_FOREACH(nodes, const node_t *, node, {
if (!fascist_firewall_allows_node(node))
smartlist_add(excluded, (void*)node);
});
}
/* Exclude all ORs that we can't reach through our firewall */
smartlist_t *nodes = nodelist_get_list();
SMARTLIST_FOREACH(nodes, const node_t *, node, {
if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0))
smartlist_add(excluded, (void*)node);
});
/* and exclude current entry guards and their families,
* unless we're in a test network, and excluding guards
* would exclude all nodes (i.e. we're in an incredibly small tor network,
......
......@@ -191,9 +191,11 @@ static config_var_t option_vars_[] = {
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
V(ClientOnly, BOOL, "0"),
V(ClientPreferIPv6ORPort, BOOL, "0"),
V(ClientPreferIPv6DirPort, BOOL, "0"),
V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientTransportPlugin, LINELIST, NULL),
V(ClientUseIPv6, BOOL, "0"),
V(ClientUseIPv4, BOOL, "1"),
V(ConsensusParams, STRING, NULL),
V(ConnLimit, UINT, "1000"),
V(ConnDirectionStatistics, BOOL, "0"),
......@@ -3071,6 +3073,9 @@ 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;
for (i=0; i<3; i++) {
config_line_t **linep =
(i==0) ? &options->ReachableAddresses :
......@@ -3080,7 +3085,19 @@ options_validate(or_options_t *old_options, or_options_t *options,
continue;
/* We need to end with a reject *:*, not an implicit accept *:* */
for (;;) {
if (!strcmp((*linep)->value, "reject *:*")) /* already there */
/* 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) {
......@@ -3095,13 +3112,41 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
if ((options->ReachableAddresses ||
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 ||
options->ClientUseIPv4 == 0) &&
server_mode(options))
REJECT("Servers must be able to freely connect to the rest "
"of the Internet, so they must not set Reachable*Addresses "
"or FascistFirewall.");
"or FascistFirewall or FirewallPorts or ClientUseIPv4 0.");
/* We check if Reachable*Addresses blocks all addresses in
* parse_reachable_addresses(). */
if (options->ClientUseIPv4 == 0 && options->ClientUseIPv6 == 0)
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.");
if (options->ClientUseIPv6 == 0 && options->ClientPreferIPv6ORPort == 1)
log_warn(LD_CONFIG, "ClientPreferIPv6ORPort 1 is ignored unless "
"ClientUseIPv6 is also 1.");
if (options->ClientUseIPv6 == 0 && options->ClientPreferIPv6DirPort == 1)
log_warn(LD_CONFIG, "ClientPreferIPv6DirPort 1 is ignored unless "
"ClientUseIPv6 is also 1.");
if (options->UseBridges &&
server_mode(options))
......
......@@ -37,6 +37,7 @@
#include "ext_orport.h"
#include "geoip.h"
#include "main.h"
#include "nodelist.h"
#include "policies.h"
#include "reasons.h"
#include "relay.h"
......@@ -44,6 +45,7 @@
#include "rendcommon.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
#include "transports.h"
#include "routerparse.h"
#include "transports.h"
......
......@@ -313,7 +313,6 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) {
routerstatus_t *rs = &(ds->fake_status);
size_t upload_len = payload_len;
tor_addr_t ds_addr;
if ((type & ds->type) == 0)
continue;
......@@ -344,11 +343,12 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
log_info(LD_DIR, "Uploading an extrainfo too (length %d)",
(int) extrainfo_len);
}
tor_addr_from_ipv4h(&ds_addr, ds->addr);
if (purpose_needs_anonymity(dir_purpose, router_purpose)) {
indirection = DIRIND_ANONYMOUS;
} else if (!fascist_firewall_allows_address_dir(&ds_addr,ds->dir_port)) {
if (fascist_firewall_allows_address_or(&ds_addr,ds->or_port))
} else if (!fascist_firewall_allows_dir_server(ds,
FIREWALL_DIR_CONNECTION,
0)) {
if (fascist_firewall_allows_dir_server(ds, FIREWALL_OR_CONNECTION, 0))
indirection = DIRIND_ONEHOP;
else
indirection = DIRIND_ANONYMOUS;
......
......@@ -268,7 +268,7 @@ entry_is_live(const entry_guard_t *e, entry_is_live_flags_t flags,
*msg = "not fast/stable";
return NULL;
}
if (!fascist_firewall_allows_node(node)) {
if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0)) {
*msg = "unreachable by config";
return NULL;
}
......@@ -918,7 +918,8 @@ entry_guards_set_from_config(const or_options_t *options)
} else if (routerset_contains_node(options->ExcludeNodes, node)) {
SMARTLIST_DEL_CURRENT(entry_nodes, node);
continue;
} else if (!fascist_firewall_allows_node(node)) {
} else if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION,
0)) {
SMARTLIST_DEL_CURRENT(entry_nodes, node);
continue;
} else if (! node->is_possible_guard) {
......@@ -2178,7 +2179,8 @@ fetch_bridge_descriptors(const or_options_t *options, time_t now)
!options->UpdateBridgesFromAuthority, !num_bridge_auths);
if (ask_bridge_directly &&
!fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) {
!fascist_firewall_allows_address_addr(&bridge->addr, bridge->port,
FIREWALL_OR_CONNECTION, 0)) {
log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our "
"firewall policy. %s.",
fmt_addrport(&bridge->addr, bridge->port),
......
......@@ -214,6 +214,76 @@ 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,
......@@ -224,7 +294,6 @@ nodelist_set_consensus(networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v3(options);
int client = !server_mode(options);
init_nodelist();
if (ns->flavor == FLAV_MICRODESC)
......@@ -261,7 +330,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 (client && options->ClientPreferIPv6ORPort == 1 &&
if (nodelist_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;
......@@ -925,30 +994,60 @@ node_get_declared_family(const node_t *node)
return NULL;
}
/* Does this node have a valid IPv6 address? */
static 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);
return 0;
}
/** Return 1 if we prefer the IPv6 address and OR TCP port of
* <b>node</b>, else 0.
*
* We prefer the IPv6 address if the router has an IPv6 address and
* We prefer the IPv6 address if the router has an IPv6 address,
* and we can use IPv6 addresses, and:
* i) the node_t says that it prefers IPv6
* or
* ii) the router has no IPv4 address. */
* ii) the router has no IPv4 OR address.
* or
* iii) our preference is for IPv6 addresses.
* (This extra step is needed in case our preferences have changed since
* node->ipv6_preferred was set at the time the consensus was loaded.)
*/
int
node_ipv6_preferred(const node_t *node)
node_ipv6_or_preferred(const node_t *node)
{
const or_options_t *options = get_options();
tor_addr_port_t ipv4_addr;
node_assert_ok(node);
if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) {
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);
if (!options->ClientUseIPv6) {
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);
}
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; \
tor_addr_from_ipv4h(&(ap_out)->addr, (r)->addr); \
(ap_out)->port = (r)->port_field; \
return 0; \
} \
STMT_END
/** Copy the primary (IPv4) OR port (IP address and TCP port) for
* <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
* port was copied, else return non-zero.*/
......@@ -958,20 +1057,10 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
node_assert_ok(node);
tor_assert(ap_out);
if (node->ri) {
if (node->ri->addr == 0 || node->ri->or_port == 0)
return -1;
tor_addr_from_ipv4h(&ap_out->addr, node->ri->addr);
ap_out->port = node->ri->or_port;
return 0;
}
if (node->rs) {
if (node->rs->addr == 0 || node->rs->or_port == 0)
return -1;
tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
ap_out->port = node->rs->or_port;
return 0;
}
RETURN_IPV4_AP(node->ri, or_port, ap_out);
RETURN_IPV4_AP(node->rs, or_port, ap_out);
/* Microdescriptors only have an IPv6 address */
return -1;
}
......@@ -980,21 +1069,12 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
void
node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out)
{
const or_options_t *options = get_options();
tor_assert(ap_out);
/* Cheap implementation of config option ClientUseIPv6 -- simply
don't prefer IPv6 when ClientUseIPv6 is not set and we're not a
client running with bridges. See #4455 for more on this subject.
Note that this filter is too strict since we're hindering not
only clients! Erring on the safe side shouldn't be a problem
though. XXX move this check to where outgoing connections are
made? -LN */
if ((options->ClientUseIPv6 || options->UseBridges) &&
node_ipv6_preferred(node)) {
if (node_ipv6_or_preferred(node)) {
node_get_pref_ipv6_orport(node, ap_out);
} else {
/* the primary ORPort is always on IPv4 */
node_get_prim_orport(node, ap_out);
}
}
......@@ -1007,20 +1087,113 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
node_assert_ok(node);
tor_assert(ap_out);
/* We prefer the microdesc over a potential routerstatus here. They
are not being synchronised atm so there might be a chance that
they differ at some point, f.ex. when flipping
UseMicrodescriptors? -LN */
/* Prefer routerstatus over microdesc for consistency with the
* fascist_firewall_* functions. Also check if the address or port are valid,
* and try another alternative if they are not. */
if (node->ri) {
if (node->ri && node->ri->ipv6_orport
&& !tor_addr_is_null(&node->ri->ipv6_addr)) {
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
ap_out->port = node->ri->ipv6_orport;
} else if (node->md) {
} else if (node->rs && node->rs->ipv6_orport
&& !tor_addr_is_null(&node->rs->ipv6_addr)) {
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)) {
tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr);
ap_out->port = node->md->ipv6_orport;
} else if (node->rs) {
} else {
tor_addr_make_null(&ap_out->addr, AF_INET6);
ap_out->port = 0;
}
}
/** Return 1 if we prefer the IPv6 address and Dir TCP port of
* <b>node</b>, else 0.
*
* We prefer the IPv6 address if the router has an IPv6 address,
* and we can use IPv6 addresses, and:
* i) the node_t says that it prefers IPv6
* or
* ii) the router has no IPv4 Dir address.
* or
* iii) our preference is for IPv6 addresses.
* (This extra step is needed in case our preferences have changed since
* node->ipv6_preferred was set at the time the consensus was loaded.)
*/
int
node_ipv6_dir_preferred(const node_t *node)
{
const or_options_t *options = get_options();
tor_addr_port_t ipv4_addr;
node_assert_ok(node);
if (!options->ClientUseIPv6) {
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);
}
return 0;
}
/** Copy the primary (IPv4) Dir port (IP address and TCP port) for
* <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
* port was copied, else return non-zero.*/
int
node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out)
{
node_assert_ok(node);
tor_assert(ap_out);
RETURN_IPV4_AP(node->ri, dir_port, ap_out);
RETURN_IPV4_AP(node->rs, dir_port, ap_out);
/* Microdescriptors only have an IPv6 address */
return -1;
}
#undef RETURN_IPV4_AP
/** Copy the preferred Dir port (IP address and TCP port) for
* <b>node</b> into *<b>ap_out</b>. */
void
node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out)
{
tor_assert(ap_out);
if (node_ipv6_dir_preferred(node)) {
node_get_pref_ipv6_dirport(node, ap_out);
} else {
/* the primary DirPort is always on IPv4 */
node_get_prim_dirport(node, ap_out);
}
}
/** Copy the preferred IPv6 Dir port (IP address and TCP port) for
* <b>node</b> into *<b>ap_out</b>. */
void
node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
{
node_assert_ok(node);
tor_assert(ap_out);
/* Check if the address or port are valid, and try another alternative if
* they are not. Note that microdescriptors have no dir_port. */
/* Assume IPv4 and IPv6 dirports are the same */
if (node->ri && node->ri->dir_port
&& !tor_addr_is_null(&node->ri->ipv6_addr)) {
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)) {
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
ap_out->port = node->rs->ipv6_orport;
ap_out->port = node->rs->dir_port;
} else {
tor_addr_make_null(&ap_out->addr, AF_INET6);
ap_out->port = 0;
}
}
......
......@@ -21,6 +21,8 @@ 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);
......@@ -55,10 +57,17 @@ void node_get_address_string(const node_t *node, char *cp, size_t len);
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_ipv6_preferred(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);
int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
int node_ipv6_dir_preferred(const node_t *node);
int node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out);
int node_has_curve25519_onion_key(const node_t *node);
MOCK_DECL(smartlist_t *, nodelist_get_list, (void));
......
......@@ -2400,7 +2400,8 @@ typedef struct node_t {
/* Local info: derived. */
/** True if the IPv6 OR port is preferred over the IPv4 OR port. */
/** True if the IPv6 OR port is preferred over the IPv4 OR port.
* XX/teor - can this become out of date if the torrc changes? */
unsigned int ipv6_preferred:1;
/** According to the geoip db what country is this router in? */
......@@ -4061,12 +4062,20 @@ typedef struct {
* over randomly chosen exits. */
int ClientRejectInternalAddresses;
/** If true, clients may connect over IPv6. XXX we don't really