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.
This commit is contained in:
teor (Tim Wilson-Brown) 2016-01-04 00:35:22 +11:00
parent 4528f89316
commit 3b8216f215
12 changed files with 402 additions and 384 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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 {

View file

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

View file

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

View file

@ -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,
@ -562,40 +653,6 @@ fascist_firewall_allows_md_impl(const microdesc_t *md,
fw_connection, pref_only);
}
/** 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,
@ -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

View file

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

View file

@ -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,

View file

@ -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 */

View file

@ -1235,10 +1235,42 @@ 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)
== 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);
/* 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)
@ -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++) {
/* 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);
/* 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);
}
}
}
}
}
}
/* 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));