Commit 3b8216f2 authored by teor (Tim Wilson-Brown)'s avatar teor (Tim Wilson-Brown)
Browse files

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.
parent 4528f893
......@@ -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
......
......@@ -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))
......
......@@ -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);
}
}
......
......@@ -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
......
......@@ -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 {
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
}