diff options
author | teor (Tim Wilson-Brown) <teor2345@gmail.com> | 2016-01-04 00:35:22 +1100 |
---|---|---|
committer | teor (Tim Wilson-Brown) <teor2345@gmail.com> | 2016-01-29 07:16:04 +1100 |
commit | 3b8216f2155f224bf66497c71de4cecb55cd83e6 (patch) | |
tree | d20a3e81663bfafb73020acd78343640f12ce54a /src/or | |
parent | 4528f893163ad7ab27915451caf23b3a722413ce (diff) | |
download | tor-3b8216f2155f224bf66497c71de4cecb55cd83e6.tar.gz tor-3b8216f2155f224bf66497c71de4cecb55cd83e6.zip |
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.
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/config.c | 49 | ||||
-rw-r--r-- | src/or/connection.c | 20 | ||||
-rw-r--r-- | src/or/directory.c | 12 | ||||
-rw-r--r-- | src/or/nodelist.c | 156 | ||||
-rw-r--r-- | src/or/nodelist.h | 5 | ||||
-rw-r--r-- | src/or/or.h | 10 | ||||
-rw-r--r-- | src/or/policies.c | 296 | ||||
-rw-r--r-- | src/or/policies.h | 17 | ||||
-rw-r--r-- | src/or/routerlist.c | 8 |
9 files changed, 233 insertions, 340 deletions
diff --git a/src/or/config.c b/src/or/config.c index d676c6e29d..caa01d1d93 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 f252d2faa1..0420f2656b 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 665ba27767..b3a2f36f20 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 7ca1146e86..c8f93bf30c 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 fa1f22e630..8271e7532a 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 412789cafe..79b1c95ff0 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 2a97df7cac..ecc89da1c2 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 7309bcf667..ac4f7ea492 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 2923da311f..247818d8e6 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, |