mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
Add ClientUseIPv4 and ClientPreferIPv6DirPort torrc options
ClientUseIPv4 0 tells tor to avoid IPv4 client connections. ClientPreferIPv6DirPort 1 tells tor to prefer IPv6 directory connections. Refactor policy for IPv4/IPv6 preferences. Fix a bug where node->ipv6_preferred could become stale if ClientPreferIPv6ORPort was changed after the consensus was loaded. Update documentation, existing code, add unit tests.
This commit is contained in:
parent
4460feaf28
commit
2d33d192fc
9
changes/feature17840
Normal file
9
changes/feature17840
Normal file
@ -0,0 +1,9 @@
|
||||
o Minor feature (IPv6):
|
||||
- Add ClientUseIPv4, which is set to 1 by default. If set to 0, tor
|
||||
avoids using IPv4 for client OR and directory connections.
|
||||
- Add ClientPreferIPv6DirPort, which is set to 0 by default. If set
|
||||
to 1, tor prefers IPv6 directory addresses.
|
||||
- Try harder to fulfil IP version restrictions ClientUseIPv4 0 and
|
||||
ClientUseIPv6 0; and the preferences ClientPreferIPv6ORPort and
|
||||
ClientPreferIPv6DirPort.
|
||||
Closes ticket 17840; patch by "teor".
|
@ -367,6 +367,7 @@ GENERAL OPTIONS
|
||||
authorities.
|
||||
By default, the directory authorities are also FallbackDirs. Specifying a
|
||||
FallbackDir replaces Tor's default hard-coded FallbackDirs (if any).
|
||||
(See the **DirAuthority** entry for an explanation of each flag.)
|
||||
|
||||
[[UseDefaultFallbackDirs]] **UseDefaultFallbackDirs** **0**|**1**::
|
||||
Use Tor's default hard-coded FallbackDirs (if any). (When a
|
||||
@ -390,6 +391,10 @@ GENERAL OPTIONS
|
||||
if an "ipv6=__address__:__orport__" flag is present, then the directory
|
||||
authority is listening for IPv6 connections on the indicated IPv6 address
|
||||
and OR Port. +
|
||||
+
|
||||
Tor will contact the authority at __address__:__port__ (the DirPort) to
|
||||
download directory documents. If an IPv6 address is supplied, Tor will
|
||||
also download directory documents at the IPv6 address on the DirPort. +
|
||||
+
|
||||
If no **DirAuthority** line is given, Tor will use the default directory
|
||||
authorities. NOTE: this option is intended for setting up a private Tor
|
||||
@ -1483,17 +1488,31 @@ The following options are useful only for clients (that is, if
|
||||
If no defaults are available there, these options default to 20, .80,
|
||||
.60, and 100, respectively.
|
||||
|
||||
[[ClientUseIPv4]] **ClientUseIPv4** **0**|**1**::
|
||||
If this option is set to 0, Tor will avoid connecting to directory servers
|
||||
and entry nodes over IPv4. Note that clients with an IPv4
|
||||
address in a **Bridge**, proxy, or pluggable transport line will try
|
||||
connecting over IPv4 even if **ClientUseIPv4** is set to 0. (Default: 1)
|
||||
|
||||
[[ClientUseIPv6]] **ClientUseIPv6** **0**|**1**::
|
||||
If this option is set to 1, Tor might connect to entry nodes over
|
||||
IPv6. Note that clients configured with an IPv6 address in a
|
||||
**Bridge** line will try connecting over IPv6 even if
|
||||
**ClientUseIPv6** is set to 0. (Default: 0)
|
||||
If this option is set to 1, Tor might connect to directory servers or
|
||||
entry nodes over IPv6. Note that clients configured with an IPv6 address
|
||||
in a **Bridge**, proxy, or pluggable transport line will try connecting
|
||||
over IPv6 even if **ClientUseIPv6** is set to 0. (Default: 0)
|
||||
|
||||
[[ClientPreferIPv6DirPort]] **ClientPreferIPv6DirPort** **0**|**1**::
|
||||
If this option is set to 1, Tor prefers a directory port with an IPv6
|
||||
address over one with IPv4, for direct connections, if a given directory
|
||||
server has both. (Tor also prefers an IPv6 DirPort if IPv4Client is set to
|
||||
0.) Other things may influence the choice. This option breaks a tie to the
|
||||
favor of IPv6. (Default: 0)
|
||||
|
||||
[[ClientPreferIPv6ORPort]] **ClientPreferIPv6ORPort** **0**|**1**::
|
||||
If this option is set to 1, Tor prefers an OR port with an IPv6
|
||||
address over one with IPv4 if a given entry node has both. Other
|
||||
things may influence the choice. This option breaks a tie to the
|
||||
favor of IPv6. (Default: 0)
|
||||
address over one with IPv4 if a given entry node has both. (Tor also
|
||||
prefers an IPv6 ORPort if IPv4Client is set to 0.) Other things may
|
||||
influence the choice. This option breaks a tie to the favor of IPv6.
|
||||
(Default: 0)
|
||||
|
||||
[[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__::
|
||||
Tor clients don't build circuits for user traffic until they know
|
||||
|
@ -2161,14 +2161,12 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
|
||||
* family. */
|
||||
nodelist_add_node_and_family(excluded, node);
|
||||
}
|
||||
if (firewall_is_fascist_or()) {
|
||||
/* Exclude all ORs that we can't reach through our firewall */
|
||||
smartlist_t *nodes = nodelist_get_list();
|
||||
SMARTLIST_FOREACH(nodes, const node_t *, node, {
|
||||
if (!fascist_firewall_allows_node(node))
|
||||
smartlist_add(excluded, (void*)node);
|
||||
});
|
||||
}
|
||||
/* Exclude all ORs that we can't reach through our firewall */
|
||||
smartlist_t *nodes = nodelist_get_list();
|
||||
SMARTLIST_FOREACH(nodes, const node_t *, node, {
|
||||
if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0))
|
||||
smartlist_add(excluded, (void*)node);
|
||||
});
|
||||
/* and exclude current entry guards and their families,
|
||||
* unless we're in a test network, and excluding guards
|
||||
* would exclude all nodes (i.e. we're in an incredibly small tor network,
|
||||
|
@ -191,9 +191,11 @@ static config_var_t option_vars_[] = {
|
||||
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
|
||||
V(ClientOnly, BOOL, "0"),
|
||||
V(ClientPreferIPv6ORPort, BOOL, "0"),
|
||||
V(ClientPreferIPv6DirPort, BOOL, "0"),
|
||||
V(ClientRejectInternalAddresses, BOOL, "1"),
|
||||
V(ClientTransportPlugin, LINELIST, NULL),
|
||||
V(ClientUseIPv6, BOOL, "0"),
|
||||
V(ClientUseIPv4, BOOL, "1"),
|
||||
V(ConsensusParams, STRING, NULL),
|
||||
V(ConnLimit, UINT, "1000"),
|
||||
V(ConnDirectionStatistics, BOOL, "0"),
|
||||
@ -3071,6 +3073,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate Reachable*Addresses with reject *, but check if it has an
|
||||
* IPv6 entry on the way through */
|
||||
int reachable_knows_ipv6 = 0;
|
||||
for (i=0; i<3; i++) {
|
||||
config_line_t **linep =
|
||||
(i==0) ? &options->ReachableAddresses :
|
||||
@ -3080,7 +3085,19 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
continue;
|
||||
/* We need to end with a reject *:*, not an implicit accept *:* */
|
||||
for (;;) {
|
||||
if (!strcmp((*linep)->value, "reject *:*")) /* already there */
|
||||
/* Check if the policy has an IPv6 entry, or uses IPv4-specific
|
||||
* policies (and therefore we assume it's aware of IPv6). */
|
||||
if (!strcmpstart((*linep)->value, "accept6") ||
|
||||
!strcmpstart((*linep)->value, "reject6") ||
|
||||
!strstr((*linep)->value, "*6") ||
|
||||
strchr((*linep)->value, '[') ||
|
||||
!strcmpstart((*linep)->value, "accept4") ||
|
||||
!strcmpstart((*linep)->value, "reject4") ||
|
||||
!strstr((*linep)->value, "*4"))
|
||||
reachable_knows_ipv6 = 1;
|
||||
/* already has a reject all */
|
||||
if (!strcmp((*linep)->value, "reject *:*") ||
|
||||
!strcmp((*linep)->value, "reject *"))
|
||||
break;
|
||||
linep = &((*linep)->next);
|
||||
if (!*linep) {
|
||||
@ -3095,13 +3112,41 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
}
|
||||
}
|
||||
|
||||
if ((options->ReachableAddresses ||
|
||||
if (options->ClientUseIPv6 &&
|
||||
(options->ReachableAddresses ||
|
||||
options->ReachableORAddresses ||
|
||||
options->ReachableDirAddresses) &&
|
||||
!reachable_knows_ipv6)
|
||||
log_warn(LD_CONFIG, "You have set ClientUseIPv6 1 and at least one of "
|
||||
"ReachableAddresses, ReachableORAddresses, or "
|
||||
"ReachableDirAddresses, but without any IPv6-specific rules. "
|
||||
"Tor won't connect to any IPv6 addresses, unless a rule accepts "
|
||||
"them. (Use 'accept6 *:*' or 'reject6 *:*' as the last rule to "
|
||||
"disable this warning.)");
|
||||
|
||||
if ((options->ReachableAddresses ||
|
||||
options->ReachableORAddresses ||
|
||||
options->ReachableDirAddresses ||
|
||||
options->ClientUseIPv4 == 0) &&
|
||||
server_mode(options))
|
||||
REJECT("Servers must be able to freely connect to the rest "
|
||||
"of the Internet, so they must not set Reachable*Addresses "
|
||||
"or FascistFirewall.");
|
||||
"or FascistFirewall or FirewallPorts or ClientUseIPv4 0.");
|
||||
|
||||
/* We check if Reachable*Addresses blocks all addresses in
|
||||
* parse_reachable_addresses(). */
|
||||
if (options->ClientUseIPv4 == 0 && options->ClientUseIPv6 == 0)
|
||||
REJECT("Tor cannot connect to the Internet if ClientUseIPv4 is 0 and "
|
||||
"ClientUseIPv6 is 0. Please set at least one of these options "
|
||||
"to 1.");
|
||||
|
||||
if (options->ClientUseIPv6 == 0 && options->ClientPreferIPv6ORPort == 1)
|
||||
log_warn(LD_CONFIG, "ClientPreferIPv6ORPort 1 is ignored unless "
|
||||
"ClientUseIPv6 is also 1.");
|
||||
|
||||
if (options->ClientUseIPv6 == 0 && options->ClientPreferIPv6DirPort == 1)
|
||||
log_warn(LD_CONFIG, "ClientPreferIPv6DirPort 1 is ignored unless "
|
||||
"ClientUseIPv6 is also 1.");
|
||||
|
||||
if (options->UseBridges &&
|
||||
server_mode(options))
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "ext_orport.h"
|
||||
#include "geoip.h"
|
||||
#include "main.h"
|
||||
#include "nodelist.h"
|
||||
#include "policies.h"
|
||||
#include "reasons.h"
|
||||
#include "relay.h"
|
||||
@ -44,6 +45,7 @@
|
||||
#include "rendcommon.h"
|
||||
#include "rephist.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "transports.h"
|
||||
#include "routerparse.h"
|
||||
#include "transports.h"
|
||||
|
@ -313,7 +313,6 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
|
||||
SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) {
|
||||
routerstatus_t *rs = &(ds->fake_status);
|
||||
size_t upload_len = payload_len;
|
||||
tor_addr_t ds_addr;
|
||||
|
||||
if ((type & ds->type) == 0)
|
||||
continue;
|
||||
@ -344,11 +343,12 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
|
||||
log_info(LD_DIR, "Uploading an extrainfo too (length %d)",
|
||||
(int) extrainfo_len);
|
||||
}
|
||||
tor_addr_from_ipv4h(&ds_addr, ds->addr);
|
||||
if (purpose_needs_anonymity(dir_purpose, router_purpose)) {
|
||||
indirection = DIRIND_ANONYMOUS;
|
||||
} else if (!fascist_firewall_allows_address_dir(&ds_addr,ds->dir_port)) {
|
||||
if (fascist_firewall_allows_address_or(&ds_addr,ds->or_port))
|
||||
} else if (!fascist_firewall_allows_dir_server(ds,
|
||||
FIREWALL_DIR_CONNECTION,
|
||||
0)) {
|
||||
if (fascist_firewall_allows_dir_server(ds, FIREWALL_OR_CONNECTION, 0))
|
||||
indirection = DIRIND_ONEHOP;
|
||||
else
|
||||
indirection = DIRIND_ANONYMOUS;
|
||||
|
@ -268,7 +268,7 @@ entry_is_live(const entry_guard_t *e, entry_is_live_flags_t flags,
|
||||
*msg = "not fast/stable";
|
||||
return NULL;
|
||||
}
|
||||
if (!fascist_firewall_allows_node(node)) {
|
||||
if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0)) {
|
||||
*msg = "unreachable by config";
|
||||
return NULL;
|
||||
}
|
||||
@ -918,7 +918,8 @@ entry_guards_set_from_config(const or_options_t *options)
|
||||
} else if (routerset_contains_node(options->ExcludeNodes, node)) {
|
||||
SMARTLIST_DEL_CURRENT(entry_nodes, node);
|
||||
continue;
|
||||
} else if (!fascist_firewall_allows_node(node)) {
|
||||
} else if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION,
|
||||
0)) {
|
||||
SMARTLIST_DEL_CURRENT(entry_nodes, node);
|
||||
continue;
|
||||
} else if (! node->is_possible_guard) {
|
||||
@ -2178,7 +2179,8 @@ fetch_bridge_descriptors(const or_options_t *options, time_t now)
|
||||
!options->UpdateBridgesFromAuthority, !num_bridge_auths);
|
||||
|
||||
if (ask_bridge_directly &&
|
||||
!fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) {
|
||||
!fascist_firewall_allows_address_addr(&bridge->addr, bridge->port,
|
||||
FIREWALL_OR_CONNECTION, 0)) {
|
||||
log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our "
|
||||
"firewall policy. %s.",
|
||||
fmt_addrport(&bridge->addr, bridge->port),
|
||||
|
@ -214,6 +214,76 @@ nodelist_add_microdesc(microdesc_t *md)
|
||||
return node;
|
||||
}
|
||||
|
||||
/** Do we prefer to connect to IPv6, ignoring ClientPreferIPv6ORPort and
|
||||
* ClientPreferIPv6DirPort?
|
||||
* If we're unsure, return -1, otherwise, return 1 for IPv6 and 0 for IPv4.
|
||||
*/
|
||||
static int
|
||||
nodelist_prefer_ipv6(const or_options_t *options)
|
||||
{
|
||||
/*
|
||||
Cheap implementation of config options ClientUseIPv4 & ClientUseIPv6 --
|
||||
If we're a server, use IPv4.
|
||||
If we're a client running with bridges, use IPv6.
|
||||
Otherwise, use IPv6 if we can and it's preferred, or if IPv4 is disabled.
|
||||
See #4455 and #17840 for more on this subject.
|
||||
*/
|
||||
|
||||
/* Servers prefer IPv4 */
|
||||
if (server_mode(options)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bridge clients prefer IPv6 */
|
||||
if (options->UseBridges) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!options->ClientUseIPv4) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Do we prefer to connect to IPv6 ORPorts?
|
||||
*/
|
||||
int
|
||||
nodelist_prefer_ipv6_orport(const or_options_t *options)
|
||||
{
|
||||
int pref_ipv6 = nodelist_prefer_ipv6(options);
|
||||
|
||||
if (pref_ipv6 >= 0) {
|
||||
return pref_ipv6;
|
||||
}
|
||||
|
||||
/* We prefer IPv6 ORPorts if the option is set */
|
||||
if (options->ClientUseIPv6 && options->ClientPreferIPv6ORPort) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Do we prefer to connect to IPv6 DirPorts?
|
||||
*/
|
||||
int
|
||||
nodelist_prefer_ipv6_dirport(const or_options_t *options)
|
||||
{
|
||||
int pref_ipv6 = nodelist_prefer_ipv6(options);
|
||||
|
||||
if (pref_ipv6 >= 0) {
|
||||
return pref_ipv6;
|
||||
}
|
||||
|
||||
/* We prefer IPv6 DirPorts if the option is set */
|
||||
if (options->ClientUseIPv6 && options->ClientPreferIPv6DirPort) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Tell the nodelist that the current usable consensus is <b>ns</b>.
|
||||
* This makes the nodelist change all of the routerstatus entries for
|
||||
* the nodes, drop nodes that no longer have enough info to get used,
|
||||
@ -224,7 +294,6 @@ nodelist_set_consensus(networkstatus_t *ns)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
int authdir = authdir_mode_v3(options);
|
||||
int client = !server_mode(options);
|
||||
|
||||
init_nodelist();
|
||||
if (ns->flavor == FLAV_MICRODESC)
|
||||
@ -261,7 +330,7 @@ nodelist_set_consensus(networkstatus_t *ns)
|
||||
node->is_bad_exit = rs->is_bad_exit;
|
||||
node->is_hs_dir = rs->is_hs_dir;
|
||||
node->ipv6_preferred = 0;
|
||||
if (client && options->ClientPreferIPv6ORPort == 1 &&
|
||||
if (nodelist_prefer_ipv6_orport(options) &&
|
||||
(tor_addr_is_null(&rs->ipv6_addr) == 0 ||
|
||||
(node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
|
||||
node->ipv6_preferred = 1;
|
||||
@ -925,30 +994,60 @@ node_get_declared_family(const node_t *node)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Does this node have a valid IPv6 address? */
|
||||
static int
|
||||
node_has_ipv6_addr(const node_t *node)
|
||||
{
|
||||
if (node->ri)
|
||||
return !tor_addr_is_null(&node->ri->ipv6_addr);
|
||||
if (node->md)
|
||||
return !tor_addr_is_null(&node->md->ipv6_addr);
|
||||
if (node->rs)
|
||||
return !tor_addr_is_null(&node->rs->ipv6_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return 1 if we prefer the IPv6 address and OR TCP port of
|
||||
* <b>node</b>, else 0.
|
||||
*
|
||||
* We prefer the IPv6 address if the router has an IPv6 address and
|
||||
* We prefer the IPv6 address if the router has an IPv6 address,
|
||||
* and we can use IPv6 addresses, and:
|
||||
* i) the node_t says that it prefers IPv6
|
||||
* or
|
||||
* ii) the router has no IPv4 address. */
|
||||
* ii) the router has no IPv4 OR address.
|
||||
* or
|
||||
* iii) our preference is for IPv6 addresses.
|
||||
* (This extra step is needed in case our preferences have changed since
|
||||
* node->ipv6_preferred was set at the time the consensus was loaded.)
|
||||
*/
|
||||
int
|
||||
node_ipv6_preferred(const node_t *node)
|
||||
node_ipv6_or_preferred(const node_t *node)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
tor_addr_port_t ipv4_addr;
|
||||
node_assert_ok(node);
|
||||
|
||||
if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) {
|
||||
if (node->ri)
|
||||
return !tor_addr_is_null(&node->ri->ipv6_addr);
|
||||
if (node->md)
|
||||
return !tor_addr_is_null(&node->md->ipv6_addr);
|
||||
if (node->rs)
|
||||
return !tor_addr_is_null(&node->rs->ipv6_addr);
|
||||
if (!options->ClientUseIPv6) {
|
||||
return 0;
|
||||
} else if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)
|
||||
|| nodelist_prefer_ipv6_orport(get_options())) {
|
||||
return node_has_ipv6_addr(node);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define RETURN_IPV4_AP(r, port_field, ap_out) \
|
||||
STMT_BEGIN \
|
||||
if (r) { \
|
||||
if ((r)->addr == 0 || (r)->port_field == 0) \
|
||||
return -1; \
|
||||
tor_addr_from_ipv4h(&(ap_out)->addr, (r)->addr); \
|
||||
(ap_out)->port = (r)->port_field; \
|
||||
return 0; \
|
||||
} \
|
||||
STMT_END
|
||||
|
||||
/** Copy the primary (IPv4) OR port (IP address and TCP port) for
|
||||
* <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
|
||||
* port was copied, else return non-zero.*/
|
||||
@ -958,20 +1057,10 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
|
||||
node_assert_ok(node);
|
||||
tor_assert(ap_out);
|
||||
|
||||
if (node->ri) {
|
||||
if (node->ri->addr == 0 || node->ri->or_port == 0)
|
||||
return -1;
|
||||
tor_addr_from_ipv4h(&ap_out->addr, node->ri->addr);
|
||||
ap_out->port = node->ri->or_port;
|
||||
return 0;
|
||||
}
|
||||
if (node->rs) {
|
||||
if (node->rs->addr == 0 || node->rs->or_port == 0)
|
||||
return -1;
|
||||
tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
|
||||
ap_out->port = node->rs->or_port;
|
||||
return 0;
|
||||
}
|
||||
RETURN_IPV4_AP(node->ri, or_port, ap_out);
|
||||
RETURN_IPV4_AP(node->rs, or_port, ap_out);
|
||||
/* Microdescriptors only have an IPv6 address */
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -980,21 +1069,12 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
|
||||
void
|
||||
node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
tor_assert(ap_out);
|
||||
|
||||
/* Cheap implementation of config option ClientUseIPv6 -- simply
|
||||
don't prefer IPv6 when ClientUseIPv6 is not set and we're not a
|
||||
client running with bridges. See #4455 for more on this subject.
|
||||
|
||||
Note that this filter is too strict since we're hindering not
|
||||
only clients! Erring on the safe side shouldn't be a problem
|
||||
though. XXX move this check to where outgoing connections are
|
||||
made? -LN */
|
||||
if ((options->ClientUseIPv6 || options->UseBridges) &&
|
||||
node_ipv6_preferred(node)) {
|
||||
if (node_ipv6_or_preferred(node)) {
|
||||
node_get_pref_ipv6_orport(node, ap_out);
|
||||
} else {
|
||||
/* the primary ORPort is always on IPv4 */
|
||||
node_get_prim_orport(node, ap_out);
|
||||
}
|
||||
}
|
||||
@ -1007,20 +1087,113 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
|
||||
node_assert_ok(node);
|
||||
tor_assert(ap_out);
|
||||
|
||||
/* We prefer the microdesc over a potential routerstatus here. They
|
||||
are not being synchronised atm so there might be a chance that
|
||||
they differ at some point, f.ex. when flipping
|
||||
UseMicrodescriptors? -LN */
|
||||
/* Prefer routerstatus over microdesc for consistency with the
|
||||
* fascist_firewall_* functions. Also check if the address or port are valid,
|
||||
* and try another alternative if they are not. */
|
||||
|
||||
if (node->ri) {
|
||||
if (node->ri && node->ri->ipv6_orport
|
||||
&& !tor_addr_is_null(&node->ri->ipv6_addr)) {
|
||||
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
|
||||
ap_out->port = node->ri->ipv6_orport;
|
||||
} else if (node->md) {
|
||||
tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr);
|
||||
ap_out->port = node->md->ipv6_orport;
|
||||
} else if (node->rs) {
|
||||
} else if (node->rs && node->rs->ipv6_orport
|
||||
&& !tor_addr_is_null(&node->rs->ipv6_addr)) {
|
||||
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
|
||||
ap_out->port = node->rs->ipv6_orport;
|
||||
} else if (node->md && node->md->ipv6_orport
|
||||
&& !tor_addr_is_null(&node->md->ipv6_addr)) {
|
||||
tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr);
|
||||
ap_out->port = node->md->ipv6_orport;
|
||||
} else {
|
||||
tor_addr_make_null(&ap_out->addr, AF_INET6);
|
||||
ap_out->port = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return 1 if we prefer the IPv6 address and Dir TCP port of
|
||||
* <b>node</b>, else 0.
|
||||
*
|
||||
* We prefer the IPv6 address if the router has an IPv6 address,
|
||||
* and we can use IPv6 addresses, and:
|
||||
* i) the node_t says that it prefers IPv6
|
||||
* or
|
||||
* ii) the router has no IPv4 Dir address.
|
||||
* or
|
||||
* iii) our preference is for IPv6 addresses.
|
||||
* (This extra step is needed in case our preferences have changed since
|
||||
* node->ipv6_preferred was set at the time the consensus was loaded.)
|
||||
*/
|
||||
int
|
||||
node_ipv6_dir_preferred(const node_t *node)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
tor_addr_port_t ipv4_addr;
|
||||
node_assert_ok(node);
|
||||
|
||||
if (!options->ClientUseIPv6) {
|
||||
return 0;
|
||||
} else if (node->ipv6_preferred || node_get_prim_dirport(node, &ipv4_addr)
|
||||
|| nodelist_prefer_ipv6_dirport(get_options())) {
|
||||
return node_has_ipv6_addr(node);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Copy the primary (IPv4) Dir port (IP address and TCP port) for
|
||||
* <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
|
||||
* port was copied, else return non-zero.*/
|
||||
int
|
||||
node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out)
|
||||
{
|
||||
node_assert_ok(node);
|
||||
tor_assert(ap_out);
|
||||
|
||||
RETURN_IPV4_AP(node->ri, dir_port, ap_out);
|
||||
RETURN_IPV4_AP(node->rs, dir_port, ap_out);
|
||||
/* Microdescriptors only have an IPv6 address */
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#undef RETURN_IPV4_AP
|
||||
|
||||
/** Copy the preferred Dir port (IP address and TCP port) for
|
||||
* <b>node</b> into *<b>ap_out</b>. */
|
||||
void
|
||||
node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out)
|
||||
{
|
||||
tor_assert(ap_out);
|
||||
|
||||
if (node_ipv6_dir_preferred(node)) {
|
||||
node_get_pref_ipv6_dirport(node, ap_out);
|
||||
} else {
|
||||
/* the primary DirPort is always on IPv4 */
|
||||
node_get_prim_dirport(node, ap_out);
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy the preferred IPv6 Dir port (IP address and TCP port) for
|
||||
* <b>node</b> into *<b>ap_out</b>. */
|
||||
void
|
||||
node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
|
||||
{
|
||||
node_assert_ok(node);
|
||||
tor_assert(ap_out);
|
||||
|
||||
/* Check if the address or port are valid, and try another alternative if
|
||||
* they are not. Note that microdescriptors have no dir_port. */
|
||||
|
||||
/* Assume IPv4 and IPv6 dirports are the same */
|
||||
if (node->ri && node->ri->dir_port
|
||||
&& !tor_addr_is_null(&node->ri->ipv6_addr)) {
|
||||
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
|
||||
ap_out->port = node->ri->dir_port;
|
||||
} else if (node->rs && node->rs->dir_port
|
||||
&& !tor_addr_is_null(&node->rs->ipv6_addr)) {
|
||||
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
|
||||
ap_out->port = node->rs->dir_port;
|
||||
} else {
|
||||
tor_addr_make_null(&ap_out->addr, AF_INET6);
|
||||
ap_out->port = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ MOCK_DECL(const node_t *, node_get_by_id, (const char *identity_digest));
|
||||
const node_t *node_get_by_hex_id(const char *identity_digest);
|
||||
node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
|
||||
node_t *nodelist_add_microdesc(microdesc_t *md);
|
||||
int nodelist_prefer_ipv6_orport(const or_options_t *options);
|
||||
int nodelist_prefer_ipv6_dirport(const or_options_t *options);
|
||||
void nodelist_set_consensus(networkstatus_t *ns);
|
||||
|
||||
void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md);
|
||||
@ -55,10 +57,17 @@ void node_get_address_string(const node_t *node, char *cp, size_t len);
|
||||
long node_get_declared_uptime(const node_t *node);
|
||||
time_t node_get_published_on(const node_t *node);
|
||||
const smartlist_t *node_get_declared_family(const node_t *node);
|
||||
int node_ipv6_preferred(const node_t *node);
|
||||
|
||||
/* Deprecated - use node_ipv6_or_preferred or node_ipv6_dir_preferred */
|
||||
#define node_ipv6_preferred(node) node_ipv6_or_preferred(node)
|
||||
int node_ipv6_or_preferred(const node_t *node);
|
||||
int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out);
|
||||
void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
|
||||
void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
|
||||
int node_ipv6_dir_preferred(const node_t *node);
|
||||
int node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out);
|
||||
void node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out);
|
||||
void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out);
|
||||
int node_has_curve25519_onion_key(const node_t *node);
|
||||
|
||||
MOCK_DECL(smartlist_t *, nodelist_get_list, (void));
|
||||
|
21
src/or/or.h
21
src/or/or.h
@ -2400,7 +2400,8 @@ typedef struct node_t {
|
||||
|
||||
/* Local info: derived. */
|
||||
|
||||
/** True if the IPv6 OR port is preferred over the IPv4 OR port. */
|
||||
/** True if the IPv6 OR port is preferred over the IPv4 OR port.
|
||||
* XX/teor - can this become out of date if the torrc changes? */
|
||||
unsigned int ipv6_preferred:1;
|
||||
|
||||
/** According to the geoip db what country is this router in? */
|
||||
@ -4061,12 +4062,20 @@ typedef struct {
|
||||
* over randomly chosen exits. */
|
||||
int ClientRejectInternalAddresses;
|
||||
|
||||
/** If true, clients may connect over IPv6. XXX we don't really
|
||||
enforce this -- clients _may_ set up outgoing IPv6 connections
|
||||
even when this option is not set. */
|
||||
/** If true, clients may connect over IPv4. If false, they will avoid
|
||||
* 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. */
|
||||
int ClientUseIPv6;
|
||||
/** If true, prefer an IPv6 OR port over an IPv4 one. */
|
||||
/** If true, prefer an IPv6 OR port over an IPv4 one for entry node
|
||||
* connections. Use nodelist_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
|
||||
* accessing this value directly. */
|
||||
int ClientPreferIPv6DirPort;
|
||||
|
||||
/** The length of time that we think a consensus should be fresh. */
|
||||
int V3AuthVotingInterval;
|
||||
@ -5125,6 +5134,8 @@ typedef struct dir_server_t {
|
||||
char *description;
|
||||
char *nickname;
|
||||
char *address; /**< Hostname. */
|
||||
/* XX/teor - why do we duplicate the address and port fields here and in
|
||||
* fake_status? Surely we could just use fake_status (#17867). */
|
||||
tor_addr_t ipv6_addr; /**< IPv6 address if present; AF_UNSPEC if not */
|
||||
uint32_t addr; /**< IPv4 address. */
|
||||
uint16_t dir_port; /**< Directory port. */
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "dirserv.h"
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
#include "policies.h"
|
||||
#include "router.h"
|
||||
@ -270,16 +271,21 @@ parse_reachable_addresses(void)
|
||||
"Error parsing ReachableDirAddresses entry; ignoring.");
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Return true iff the firewall options might block any address:port
|
||||
* combination.
|
||||
*/
|
||||
int
|
||||
firewall_is_fascist_or(void)
|
||||
{
|
||||
return reachable_or_addr_policy != NULL;
|
||||
/* XX/teor - we ignore ReachableAddresses for bridge clients and relays */
|
||||
if (!options->UseBridges || server_mode(options)) {
|
||||
if ((reachable_or_addr_policy
|
||||
&& policy_is_reject_star(reachable_or_addr_policy, AF_UNSPEC))
|
||||
|| (reachable_dir_addr_policy
|
||||
&& policy_is_reject_star(reachable_dir_addr_policy, AF_UNSPEC))) {
|
||||
log_warn(LD_CONFIG, "Tor cannot connect to the Internet if "
|
||||
"ReachableAddresses, ReachableORAddresses, or "
|
||||
"ReachableDirAddresses reject all addresses. Please accept "
|
||||
"some addresses in these options.");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Return true iff <b>policy</b> (possibly NULL) will allow a
|
||||
@ -317,49 +323,708 @@ addr_policy_permits_address(uint32_t addr, uint16_t port,
|
||||
return addr_policy_permits_tor_addr(&a, port, policy);
|
||||
}
|
||||
|
||||
/** Return true iff we think our firewall will let us make an OR connection to
|
||||
* addr:port. */
|
||||
int
|
||||
fascist_firewall_allows_address_or(const tor_addr_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.
|
||||
* 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 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. */
|
||||
STATIC int
|
||||
fascist_firewall_allows_address(const tor_addr_t *addr,
|
||||
uint16_t port,
|
||||
smartlist_t *firewall_policy,
|
||||
int pref_only, int pref_ipv6)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
if (!addr || tor_addr_is_null(addr) || !port) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!options->UseBridges && !server_mode(options)) {
|
||||
if (tor_addr_family(addr) == AF_INET &&
|
||||
(!options->ClientUseIPv4 || (pref_only && pref_ipv6)))
|
||||
return 0;
|
||||
|
||||
if (tor_addr_family(addr) == AF_INET6 &&
|
||||
(!options->ClientUseIPv6 || (pref_only && !pref_ipv6)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return addr_policy_permits_tor_addr(addr, port,
|
||||
reachable_or_addr_policy);
|
||||
firewall_policy);
|
||||
}
|
||||
|
||||
/** Return true iff we think our firewall will let us make an OR connection to
|
||||
* <b>ri</b>. */
|
||||
/** Return true iff we think our firewall will let us make a connection to
|
||||
* addr:port. Uses ReachableORAddresses or ReachableDirAddresses based on
|
||||
* fw_connection.
|
||||
* If pref_only, return false if addr is not in the client's preferred address
|
||||
* family.
|
||||
*/
|
||||
int
|
||||
fascist_firewall_allows_or(const routerinfo_t *ri)
|
||||
fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
/* XXXX proposal 118 */
|
||||
tor_addr_t addr;
|
||||
tor_addr_from_ipv4h(&addr, ri->addr);
|
||||
return fascist_firewall_allows_address_or(&addr, ri->or_port);
|
||||
}
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
/** Return true iff we think our firewall will let us make an OR connection to
|
||||
* <b>node</b>. */
|
||||
int
|
||||
fascist_firewall_allows_node(const node_t *node)
|
||||
{
|
||||
if (node->ri) {
|
||||
return fascist_firewall_allows_or(node->ri);
|
||||
} else if (node->rs) {
|
||||
tor_addr_t addr;
|
||||
tor_addr_from_ipv4h(&addr, node->rs->addr);
|
||||
return fascist_firewall_allows_address_or(&addr, node->rs->or_port);
|
||||
if (fw_connection == FIREWALL_OR_CONNECTION) {
|
||||
return fascist_firewall_allows_address(addr, port,
|
||||
reachable_or_addr_policy,
|
||||
pref_only,
|
||||
nodelist_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));
|
||||
} else {
|
||||
return 1;
|
||||
log_warn(LD_BUG, "Bad firewall_connection_t value %d.",
|
||||
fw_connection);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true iff we think our firewall will let us make a directory
|
||||
* connection to addr:port. */
|
||||
/** Return true iff we think our firewall will let us make a connection to
|
||||
* addr:port (ap). Uses ReachableORAddresses or ReachableDirAddresses based on
|
||||
* fw_connection.
|
||||
* If pref_only, return false if addr is not in the client's preferred address
|
||||
* family.
|
||||
*/
|
||||
int
|
||||
fascist_firewall_allows_address_dir(const tor_addr_t *addr, uint16_t port)
|
||||
fascist_firewall_allows_address_ap(const tor_addr_port_t *ap,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
return addr_policy_permits_tor_addr(addr, port,
|
||||
reachable_dir_addr_policy);
|
||||
tor_assert(ap);
|
||||
return fascist_firewall_allows_address_addr(&ap->addr, ap->port,
|
||||
fw_connection, pref_only);
|
||||
}
|
||||
|
||||
/* Return true iff we think our firewall will let us make a connection to
|
||||
* ipv4h_or_addr:ipv4_or_port. ipv4h_or_addr is interpreted in host order.
|
||||
* Uses ReachableORAddresses or ReachableDirAddresses based on
|
||||
* fw_connection.
|
||||
* If pref_only, return false if addr is not in the client's preferred address
|
||||
* family. */
|
||||
int
|
||||
fascist_firewall_allows_address_ipv4h(uint32_t ipv4h_or_addr,
|
||||
uint16_t ipv4_or_port,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
tor_addr_t ipv4_or_addr;
|
||||
tor_addr_from_ipv4h(&ipv4_or_addr, ipv4h_or_addr);
|
||||
return fascist_firewall_allows_address_addr(&ipv4_or_addr, ipv4_or_port,
|
||||
fw_connection, pref_only);
|
||||
}
|
||||
|
||||
/** Return true iff we think our firewall will let us make a connection to
|
||||
* ipv4h_addr/ipv6_addr. Uses ipv4_orport/ipv6_orport/ReachableORAddresses or
|
||||
* ipv4_dirport/ipv6_dirport/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. */
|
||||
static int
|
||||
fascist_firewall_allows_base(uint32_t ipv4h_addr, uint16_t ipv4_orport,
|
||||
uint16_t ipv4_dirport,
|
||||
const tor_addr_t *ipv6_addr, uint16_t ipv6_orport,
|
||||
uint16_t ipv6_dirport,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
if (fascist_firewall_allows_address_ipv4h(ipv4h_addr,
|
||||
(fw_connection == FIREWALL_OR_CONNECTION
|
||||
? ipv4_orport
|
||||
: ipv4_dirport),
|
||||
fw_connection,
|
||||
pref_only)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fascist_firewall_allows_address_addr(ipv6_addr,
|
||||
(fw_connection == FIREWALL_OR_CONNECTION
|
||||
? ipv6_orport
|
||||
: ipv6_dirport),
|
||||
fw_connection,
|
||||
pref_only)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Like fascist_firewall_allows_ri, but doesn't consult the node. */
|
||||
static int
|
||||
fascist_firewall_allows_ri_impl(const routerinfo_t *ri,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
if (!ri) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assume IPv4 and IPv6 DirPorts are the same */
|
||||
return fascist_firewall_allows_base(ri->addr, ri->or_port, ri->dir_port,
|
||||
&ri->ipv6_addr, ri->ipv6_orport,
|
||||
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,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
if (!rs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assume IPv4 and IPv6 DirPorts are the same */
|
||||
return fascist_firewall_allows_base(rs->addr, rs->or_port, rs->dir_port,
|
||||
&rs->ipv6_addr, rs->ipv6_orport,
|
||||
rs->dir_port, fw_connection, pref_only);
|
||||
}
|
||||
|
||||
/** Return true iff we think our firewall will let us make a connection to
|
||||
* <b>rs</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 rs are not permitted. */
|
||||
int
|
||||
fascist_firewall_allows_rs(const routerstatus_t *rs,
|
||||
firewall_connection_t fw_connection, int pref_only)
|
||||
{
|
||||
if (!rs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assume IPv4 and IPv6 DirPorts are the same */
|
||||
if (fascist_firewall_allows_rs_impl(rs, fw_connection, pref_only)) {
|
||||
return 1;
|
||||
} else {
|
||||
const node_t *node = node_get_by_id(rs->identity_digest);
|
||||
return fascist_firewall_allows_node(node, fw_connection, pref_only);
|
||||
}
|
||||
}
|
||||
|
||||
/** Like fascist_firewall_allows_md, but doesn't consult the node. */
|
||||
static int
|
||||
fascist_firewall_allows_md_impl(const microdesc_t *md,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
if (!md) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Can't check dirport, it doesn't have one */
|
||||
if (fw_connection == FIREWALL_DIR_CONNECTION) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Also can't check IPv4, doesn't have that either */
|
||||
return fascist_firewall_allows_address_addr(&md->ipv6_addr, md->ipv6_orport,
|
||||
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,
|
||||
* - if not, 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. */
|
||||
int
|
||||
fascist_firewall_allows_node(const node_t *node,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
if (!node) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
node_assert_ok(node);
|
||||
|
||||
/* Sometimes, the rs is missing the IPv6 address info, and we need to go
|
||||
* all the way to the md */
|
||||
if (node->ri && fascist_firewall_allows_ri_impl(node->ri, fw_connection,
|
||||
pref_only)) {
|
||||
return 1;
|
||||
} else if (node->rs && fascist_firewall_allows_rs_impl(node->rs,
|
||||
fw_connection,
|
||||
pref_only)) {
|
||||
return 1;
|
||||
} else if (node->md && fascist_firewall_allows_md_impl(node->md,
|
||||
fw_connection,
|
||||
pref_only)) {
|
||||
return 1;
|
||||
} else {
|
||||
/* If we know nothing, assume it's unreachable, we'll never get an address
|
||||
* to connect to. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true iff we think our firewall will let us make a connection to
|
||||
* <b>ds</b> on either its IPv4 or IPv6 address. Uses ReachableORAddresses or
|
||||
* ReachableDirAddresses based on <b>fw_connection</b> (some directory
|
||||
* connections are tunneled over ORPorts).
|
||||
* If pref_only, return false if addr is not in the client's preferred address
|
||||
* family. */
|
||||
int
|
||||
fascist_firewall_allows_dir_server(const dir_server_t *ds,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
if (!ds) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A dir_server_t always has a fake_status. As long as it has the same
|
||||
* addresses/ports in both fake_status and dir_server_t, this works fine.
|
||||
* (See #17867.)
|
||||
* This function relies on fascist_firewall_allows_rs looking up the node on
|
||||
* failure, because it will get the latest info for the relay. */
|
||||
return fascist_firewall_allows_rs(&ds->fake_status, fw_connection,
|
||||
pref_only);
|
||||
}
|
||||
|
||||
/** If a and b are both valid and allowed by fw_connection,
|
||||
* choose one based on want_a and return it.
|
||||
* Otherwise, return whichever is allowed.
|
||||
* Otherwise, return NULL.
|
||||
* If pref_only, only return an address if it's in the client's preferred
|
||||
* address family. */
|
||||
static const tor_addr_port_t *
|
||||
fascist_firewall_choose_address_impl(const tor_addr_port_t *a,
|
||||
const tor_addr_port_t *b,
|
||||
int want_a,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
const tor_addr_port_t *use_a = NULL;
|
||||
const tor_addr_port_t *use_b = NULL;
|
||||
|
||||
if (fascist_firewall_allows_address_ap(a, fw_connection, pref_only)) {
|
||||
use_a = a;
|
||||
}
|
||||
|
||||
if (fascist_firewall_allows_address_ap(b, fw_connection, pref_only)) {
|
||||
use_b = b;
|
||||
}
|
||||
|
||||
/* If both are allowed */
|
||||
if (use_a && use_b) {
|
||||
/* Choose a if we want it */
|
||||
return (want_a ? use_a : use_b);
|
||||
} else {
|
||||
/* Choose a if we have it */
|
||||
return (use_a ? use_a : use_b);
|
||||
}
|
||||
}
|
||||
|
||||
/** If a and b are both valid and preferred by fw_connection,
|
||||
* choose one based on want_a and return it.
|
||||
* Otherwise, return whichever is preferred.
|
||||
* If neither are preferred, and pref_only is false:
|
||||
* - If a and b are both allowed by fw_connection,
|
||||
* choose one based on want_a and return it.
|
||||
* - Otherwise, return whichever is preferred.
|
||||
* Otherwise, return NULL. */
|
||||
const tor_addr_port_t *
|
||||
fascist_firewall_choose_address(const tor_addr_port_t *a,
|
||||
const tor_addr_port_t *b,
|
||||
int want_a,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only)
|
||||
{
|
||||
const tor_addr_port_t *pref = fascist_firewall_choose_address_impl(
|
||||
a, b, want_a,
|
||||
fw_connection,
|
||||
1);
|
||||
if (pref_only || pref) {
|
||||
/* If there is a preferred address, use it. If we can only use preferred
|
||||
* addresses, and neither address is preferred, pref will be NULL, and we
|
||||
* want to return NULL, so return it. */
|
||||
return pref;
|
||||
} else {
|
||||
/* If there's no preferred address, and we can return addresses that are
|
||||
* not preferred, use an address that's allowed */
|
||||
return fascist_firewall_choose_address_impl(a, b, want_a, fw_connection,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy an address and port into <b>ap</b> that we think our firewall will
|
||||
* let us connect to. Uses ipv4_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. */
|
||||
static int
|
||||
fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr,
|
||||
uint16_t ipv4_orport,
|
||||
uint16_t ipv4_dirport,
|
||||
const tor_addr_t *ipv6_addr,
|
||||
uint16_t ipv6_orport,
|
||||
uint16_t ipv6_dirport,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only,
|
||||
tor_addr_port_t* ap)
|
||||
{
|
||||
const tor_addr_port_t *result = NULL;
|
||||
/* This argument is ignored as long as the address pair is IPv4/IPv6,
|
||||
* because we always have a preference in a client.
|
||||
* For bridge clients, this selects the preferred address, which was
|
||||
* previously IPv6 (if a bridge has both), so we keep that behaviour. */
|
||||
const int bridge_client_prefer_ipv4 = 0;
|
||||
|
||||
tor_assert(ipv6_addr);
|
||||
tor_assert(ap);
|
||||
|
||||
tor_addr_port_t ipv4_ap;
|
||||
tor_addr_copy(&ipv4_ap.addr, ipv4_addr);
|
||||
ipv4_ap.port = (fw_connection == FIREWALL_OR_CONNECTION
|
||||
? ipv4_orport
|
||||
: ipv4_dirport);
|
||||
|
||||
tor_addr_port_t ipv6_ap;
|
||||
tor_addr_copy(&ipv6_ap.addr, ipv6_addr);
|
||||
ipv6_ap.port = (fw_connection == FIREWALL_OR_CONNECTION
|
||||
? ipv6_orport
|
||||
: ipv6_dirport);
|
||||
|
||||
result = fascist_firewall_choose_address(&ipv4_ap, &ipv6_ap,
|
||||
bridge_client_prefer_ipv4,
|
||||
fw_connection, pref_only);
|
||||
|
||||
if (result) {
|
||||
tor_addr_copy(&ap->addr, &result->addr);
|
||||
ap->port = result->port;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Like fascist_firewall_choose_address_base, but takes a host-order IPv4
|
||||
* address as the first parameter. */
|
||||
static int
|
||||
fascist_firewall_choose_address_ipv4h(uint32_t ipv4h_addr,
|
||||
uint16_t ipv4_orport,
|
||||
uint16_t ipv4_dirport,
|
||||
const tor_addr_t *ipv6_addr,
|
||||
uint16_t ipv6_orport,
|
||||
uint16_t ipv6_dirport,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only,
|
||||
tor_addr_port_t* ap)
|
||||
{
|
||||
tor_addr_t ipv4_addr;
|
||||
tor_addr_from_ipv4h(&ipv4_addr, ipv4h_addr);
|
||||
return fascist_firewall_choose_address_base(&ipv4_addr, ipv4_orport,
|
||||
ipv4_dirport, ipv6_addr,
|
||||
ipv6_orport, ipv6_dirport,
|
||||
fw_connection, pref_only, ap);
|
||||
}
|
||||
|
||||
#define IPV6_OR_LOOKUP(r, identity_digest, ipv6_or_ap) \
|
||||
STMT_BEGIN \
|
||||
if (!(r)->ipv6_orport || tor_addr_is_null(&(r)->ipv6_addr)) { \
|
||||
const node_t *node = node_get_by_id((identity_digest)); \
|
||||
if (node) { \
|
||||
node_get_pref_ipv6_orport(node, &(ipv6_or_ap)); \
|
||||
} else { \
|
||||
tor_addr_make_null(&(ipv6_or_ap).addr, AF_INET6); \
|
||||
(ipv6_or_ap).port = 0; \
|
||||
} \
|
||||
} else { \
|
||||
tor_addr_copy(&(ipv6_or_ap).addr, &(r)->ipv6_addr); \
|
||||
(ipv6_or_ap).port = (r)->ipv6_orport; \
|
||||
} \
|
||||
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
|
||||
* 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 rs are not valid. */
|
||||
int
|
||||
fascist_firewall_choose_address_rs(const routerstatus_t *rs,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only, tor_addr_port_t* ap)
|
||||
{
|
||||
if (!rs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tor_assert(ap);
|
||||
|
||||
/* Don't do the lookup if the IPv6 address/port in rs is OK.
|
||||
* If it's OK, assume the dir_port is also OK. */
|
||||
tor_addr_port_t ipv6_or_ap;
|
||||
IPV6_OR_LOOKUP(rs, rs->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(rs->addr,
|
||||
rs->or_port,
|
||||
rs->dir_port,
|
||||
&ipv6_or_ap.addr,
|
||||
ipv6_or_ap.port,
|
||||
rs->dir_port,
|
||||
fw_connection,
|
||||
pref_only,
|
||||
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
|
||||
* 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. */
|
||||
int
|
||||
fascist_firewall_choose_address_node(const node_t *node,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only, tor_addr_port_t *ap)
|
||||
{
|
||||
if (!node) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
node_assert_ok(node);
|
||||
|
||||
tor_addr_port_t ipv4_or_ap;
|
||||
node_get_prim_orport(node, &ipv4_or_ap);
|
||||
tor_addr_port_t ipv4_dir_ap;
|
||||
node_get_prim_dirport(node, &ipv4_dir_ap);
|
||||
|
||||
tor_addr_port_t ipv6_or_ap;
|
||||
node_get_pref_ipv6_orport(node, &ipv6_or_ap);
|
||||
tor_addr_port_t ipv6_dir_ap;
|
||||
node_get_pref_ipv6_dirport(node, &ipv6_dir_ap);
|
||||
|
||||
/* Assume the IPv6 OR and Dir addresses are the same. */
|
||||
return fascist_firewall_choose_address_base(&ipv4_or_ap.addr,
|
||||
ipv4_or_ap.port,
|
||||
ipv4_dir_ap.port,
|
||||
&ipv6_or_ap.addr,
|
||||
ipv6_or_ap.port,
|
||||
ipv6_dir_ap.port,
|
||||
fw_connection,
|
||||
pref_only,
|
||||
ap);
|
||||
}
|
||||
|
||||
/** Copy an address and port from <b>ds</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. */
|
||||
int
|
||||
fascist_firewall_choose_address_dir_server(const dir_server_t *ds,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only, tor_addr_port_t *ap)
|
||||
{
|
||||
if (!ds) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A dir_server_t always has a fake_status. As long as it has the same
|
||||
* addresses/ports in both fake_status and dir_server_t, this works fine.
|
||||
* (See #17867.)
|
||||
* This function relies on fascist_firewall_choose_address_rs looking up the
|
||||
* addresses from the node if it can, because that will get the latest info
|
||||
* for the relay. */
|
||||
return fascist_firewall_choose_address_rs(&ds->fake_status, fw_connection,
|
||||
pref_only, ap);
|
||||
}
|
||||
|
||||
/** Return 1 if <b>addr</b> is permitted to connect to our dir port,
|
||||
|
@ -22,13 +22,61 @@
|
||||
#define EXIT_POLICY_REJECT_PRIVATE (1 << 1)
|
||||
#define EXIT_POLICY_ADD_DEFAULT (1 << 2)
|
||||
|
||||
typedef enum firewall_connection_t {
|
||||
FIREWALL_OR_CONNECTION = 0,
|
||||
FIREWALL_DIR_CONNECTION = 1
|
||||
} firewall_connection_t;
|
||||
|
||||
typedef int exit_policy_parser_cfg_t;
|
||||
|
||||
int firewall_is_fascist_or(void);
|
||||
int fascist_firewall_allows_address_or(const tor_addr_t *addr, uint16_t port);
|
||||
int fascist_firewall_allows_or(const routerinfo_t *ri);
|
||||
int fascist_firewall_allows_node(const node_t *node);
|
||||
int fascist_firewall_allows_address_dir(const tor_addr_t *addr, uint16_t port);
|
||||
int fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only);
|
||||
int fascist_firewall_allows_address_ap(const tor_addr_port_t *ap,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only);
|
||||
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);
|
||||
int fascist_firewall_allows_dir_server(const dir_server_t *ds,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only);
|
||||
|
||||
const tor_addr_port_t * fascist_firewall_choose_address(
|
||||
const tor_addr_port_t *a,
|
||||
const tor_addr_port_t *b,
|
||||
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);
|
||||
int fascist_firewall_choose_address_dir_server(const dir_server_t *ds,
|
||||
firewall_connection_t fw_connection,
|
||||
int pref_only, tor_addr_port_t* ap);
|
||||
|
||||
int dir_policy_permits_address(const tor_addr_t *addr);
|
||||
int socks_policy_permits_address(const tor_addr_t *addr);
|
||||
int authdir_policy_permits_address(uint32_t addr, uint16_t port);
|
||||
@ -94,6 +142,10 @@ addr_policy_result_t compare_tor_addr_to_short_policy(
|
||||
|
||||
#ifdef POLICIES_PRIVATE
|
||||
STATIC void append_exit_policy_string(smartlist_t **policy, const char *more);
|
||||
STATIC int fascist_firewall_allows_address(const tor_addr_t *addr,
|
||||
uint16_t port,
|
||||
smartlist_t *firewall_policy,
|
||||
int pref_only, int pref_ipv6);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -624,6 +624,100 @@ test_entry_is_live(void *arg)
|
||||
; /* XXX */
|
||||
}
|
||||
|
||||
static or_options_t mocked_options;
|
||||
|
||||
static const or_options_t *
|
||||
mock_get_options(void)
|
||||
{
|
||||
return &mocked_options;
|
||||
}
|
||||
|
||||
#define TEST_IPV4_ADDR "123.45.67.89"
|
||||
#define TEST_IPV6_ADDR "[1234:5678:90ab:cdef::]"
|
||||
|
||||
static void
|
||||
test_node_preferred_orport(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
tor_addr_t ipv4_addr;
|
||||
const uint16_t ipv4_port = 4444;
|
||||
tor_addr_t ipv6_addr;
|
||||
const uint16_t ipv6_port = 6666;
|
||||
routerinfo_t node_ri;
|
||||
node_t node;
|
||||
tor_addr_port_t ap;
|
||||
|
||||
/* 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. */
|
||||
MOCK(get_options, mock_get_options);
|
||||
|
||||
/* Setup IP addresses */
|
||||
tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR);
|
||||
tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR);
|
||||
|
||||
/* Setup node_ri */
|
||||
memset(&node_ri, 0, sizeof(node_ri));
|
||||
node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
|
||||
node_ri.or_port = ipv4_port;
|
||||
tor_addr_copy(&node_ri.ipv6_addr, &ipv6_addr);
|
||||
node_ri.ipv6_orport = ipv6_port;
|
||||
|
||||
/* Setup node */
|
||||
memset(&node, 0, sizeof(node));
|
||||
node.ri = &node_ri;
|
||||
|
||||
/* Check the preferred address is IPv4 if we're only using IPv4, regardless
|
||||
* of whether we prefer it or not */
|
||||
mocked_options.ClientUseIPv4 = 1;
|
||||
mocked_options.ClientUseIPv6 = 0;
|
||||
node.ipv6_preferred = 0;
|
||||
node_get_pref_orport(&node, &ap);
|
||||
tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
|
||||
tt_assert(ap.port == ipv4_port);
|
||||
|
||||
node.ipv6_preferred = 1;
|
||||
node_get_pref_orport(&node, &ap);
|
||||
tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
|
||||
tt_assert(ap.port == ipv4_port);
|
||||
|
||||
/* Check the preferred address is IPv4 if we're using IPv4 and IPv6, but
|
||||
* don't prefer the IPv6 address */
|
||||
mocked_options.ClientUseIPv4 = 1;
|
||||
mocked_options.ClientUseIPv6 = 1;
|
||||
node.ipv6_preferred = 0;
|
||||
node_get_pref_orport(&node, &ap);
|
||||
tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
|
||||
tt_assert(ap.port == ipv4_port);
|
||||
|
||||
/* Check the preferred address is IPv6 if we prefer it and
|
||||
* ClientUseIPv6 is 1, regardless of ClientUseIPv4 */
|
||||
mocked_options.ClientUseIPv4 = 1;
|
||||
mocked_options.ClientUseIPv6 = 1;
|
||||
node.ipv6_preferred = 1;
|
||||
node_get_pref_orport(&node, &ap);
|
||||
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
|
||||
tt_assert(ap.port == ipv6_port);
|
||||
|
||||
mocked_options.ClientUseIPv4 = 0;
|
||||
node_get_pref_orport(&node, &ap);
|
||||
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
|
||||
tt_assert(ap.port == ipv6_port);
|
||||
|
||||
/* Check the preferred address is IPv6 if we don't prefer it, but
|
||||
* ClientUseIPv4 is 0 */
|
||||
mocked_options.ClientUseIPv4 = 0;
|
||||
mocked_options.ClientUseIPv6 = 1;
|
||||
node.ipv6_preferred = 0;
|
||||
node_get_pref_orport(&node, &ap);
|
||||
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
|
||||
tt_assert(ap.port == ipv6_port);
|
||||
|
||||
done:
|
||||
UNMOCK(get_options);
|
||||
}
|
||||
|
||||
static const struct testcase_setup_t fake_network = {
|
||||
fake_network_setup, fake_network_cleanup
|
||||
};
|
||||
@ -654,6 +748,9 @@ struct testcase_t entrynodes_tests[] = {
|
||||
{ "entry_is_live",
|
||||
test_entry_is_live,
|
||||
TT_FORK, &fake_network, NULL },
|
||||
{ "node_preferred_orport",
|
||||
test_node_preferred_orport,
|
||||
0, NULL, NULL },
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
@ -1127,6 +1127,449 @@ test_policies_getinfo_helper_policies(void *arg)
|
||||
#undef TEST_IPV4_ADDR
|
||||
#undef TEST_IPV6_ADDR
|
||||
|
||||
#define TEST_IPV4_ADDR_STR "1.2.3.4"
|
||||
#define TEST_IPV6_ADDR_STR "[1002::4567]"
|
||||
#define REJECT_IPv4_FINAL_STR "reject 0.0.0.0/0:*"
|
||||
#define REJECT_IPv6_FINAL_STR "reject [::]/0:*"
|
||||
|
||||
#define OTHER_IPV4_ADDR_STR "6.7.8.9"
|
||||
#define OTHER_IPV6_ADDR_STR "[afff::]"
|
||||
|
||||
/** Run unit tests for fascist_firewall_allows_address */
|
||||
static void
|
||||
test_policies_fascist_firewall_allows_address(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
tor_addr_t ipv4_addr, ipv6_addr, r_ipv4_addr, r_ipv6_addr;
|
||||
tor_addr_t n_ipv4_addr, n_ipv6_addr;
|
||||
const uint16_t port = 1234;
|
||||
smartlist_t *policy = NULL;
|
||||
smartlist_t *e_policy = NULL;
|
||||
addr_policy_t *item = NULL;
|
||||
int malformed_list = 0;
|
||||
|
||||
/* Setup the options and the items in the policies */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
MOCK(get_options, mock_get_options);
|
||||
|
||||
policy = smartlist_new();
|
||||
item = router_parse_addr_policy_item_from_string("accept "
|
||||
TEST_IPV4_ADDR_STR ":*",
|
||||
ADDR_POLICY_ACCEPT,
|
||||
&malformed_list);
|
||||
tt_assert(item);
|
||||
tt_assert(!malformed_list);
|
||||
smartlist_add(policy, item);
|
||||
item = router_parse_addr_policy_item_from_string("accept "
|
||||
TEST_IPV6_ADDR_STR,
|
||||
ADDR_POLICY_ACCEPT,
|
||||
&malformed_list);
|
||||
tt_assert(item);
|
||||
tt_assert(!malformed_list);
|
||||
smartlist_add(policy, item);
|
||||
/* Normally, policy_expand_unspec would do this for us */
|
||||
item = router_parse_addr_policy_item_from_string(REJECT_IPv4_FINAL_STR,
|
||||
ADDR_POLICY_ACCEPT,
|
||||
&malformed_list);
|
||||
tt_assert(item);
|
||||
tt_assert(!malformed_list);
|
||||
smartlist_add(policy, item);
|
||||
item = router_parse_addr_policy_item_from_string(REJECT_IPv6_FINAL_STR,
|
||||
ADDR_POLICY_ACCEPT,
|
||||
&malformed_list);
|
||||
tt_assert(item);
|
||||
tt_assert(!malformed_list);
|
||||
smartlist_add(policy, item);
|
||||
item = NULL;
|
||||
|
||||
e_policy = smartlist_new();
|
||||
|
||||
/*
|
||||
char *polstr = policy_dump_to_string(policy, 1, 1);
|
||||
printf("%s\n", polstr);
|
||||
tor_free(polstr);
|
||||
*/
|
||||
|
||||
/* Parse the addresses */
|
||||
tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR_STR);
|
||||
tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR_STR);
|
||||
tor_addr_parse(&r_ipv4_addr, OTHER_IPV4_ADDR_STR);
|
||||
tor_addr_parse(&r_ipv6_addr, OTHER_IPV6_ADDR_STR);
|
||||
tor_addr_make_null(&n_ipv4_addr, AF_INET);
|
||||
tor_addr_make_null(&n_ipv6_addr, AF_INET6);
|
||||
|
||||
/* Test the function's address matching with IPv4 and IPv6 on */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 1;
|
||||
mock_options.ClientUseIPv6 = 1;
|
||||
mock_options.UseBridges = 0;
|
||||
|
||||
tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
|
||||
== 1);
|
||||
tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
|
||||
== 1);
|
||||
tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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.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);
|
||||
|
||||
/* Test the function's address matching with IPv4 on */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 1;
|
||||
mock_options.ClientUseIPv6 = 0;
|
||||
mock_options.UseBridges = 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)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
|
||||
/* Test the function's address matching with IPv6 on */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 0;
|
||||
mock_options.ClientUseIPv6 = 1;
|
||||
mock_options.UseBridges = 0;
|
||||
|
||||
tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
|
||||
== 1);
|
||||
tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
|
||||
/* Test the function's address matching with everything off */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 0;
|
||||
mock_options.ClientUseIPv6 = 0;
|
||||
mock_options.UseBridges = 0;
|
||||
|
||||
tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
|
||||
/* Test the function's address matching for unusual inputs */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 1;
|
||||
mock_options.ClientUseIPv6 = 1;
|
||||
mock_options.UseBridges = 1;
|
||||
|
||||
/* NULL and tor_addr_is_null addresses are rejected */
|
||||
tt_assert(fascist_firewall_allows_address(NULL, port, policy, 0, 0) == 0);
|
||||
tt_assert(fascist_firewall_allows_address(&n_ipv4_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&n_ipv6_addr, port, policy, 0, 0)
|
||||
== 0);
|
||||
|
||||
/* zero ports are rejected */
|
||||
tt_assert(fascist_firewall_allows_address(&ipv4_addr, 0, policy, 0, 0)
|
||||
== 0);
|
||||
tt_assert(fascist_firewall_allows_address(&ipv6_addr, 0, policy, 0, 0)
|
||||
== 0);
|
||||
|
||||
/* NULL and empty policies accept everything */
|
||||
tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, NULL, 0, 0)
|
||||
== 1);
|
||||
tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, NULL, 0, 0)
|
||||
== 1);
|
||||
tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, e_policy, 0, 0)
|
||||
== 1);
|
||||
tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, e_policy, 0, 0)
|
||||
== 1);
|
||||
|
||||
done:
|
||||
addr_policy_free(item);
|
||||
addr_policy_list_free(policy);
|
||||
addr_policy_list_free(e_policy);
|
||||
UNMOCK(get_options);
|
||||
}
|
||||
|
||||
#undef REJECT_IPv4_FINAL_STR
|
||||
#undef REJECT_IPv6_FINAL_STR
|
||||
#undef OTHER_IPV4_ADDR_STR
|
||||
#undef OTHER_IPV6_ADDR_STR
|
||||
|
||||
#define TEST_IPV4_OR_PORT 1234
|
||||
#define TEST_IPV4_DIR_PORT 2345
|
||||
#define TEST_IPV6_OR_PORT 61234
|
||||
#define TEST_IPV6_DIR_PORT 62345
|
||||
|
||||
/** Run unit tests for fascist_firewall_choose_address */
|
||||
static void
|
||||
test_policies_fascist_firewall_choose_address(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
tor_addr_port_t ipv4_or_ap, ipv4_dir_ap, ipv6_or_ap, ipv6_dir_ap;
|
||||
tor_addr_port_t n_ipv4_ap, n_ipv6_ap;
|
||||
|
||||
/* Setup the options */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
MOCK(get_options, mock_get_options);
|
||||
|
||||
/* Parse the addresses */
|
||||
tor_addr_parse(&ipv4_or_ap.addr, TEST_IPV4_ADDR_STR);
|
||||
ipv4_or_ap.port = TEST_IPV4_OR_PORT;
|
||||
tor_addr_parse(&ipv4_dir_ap.addr, TEST_IPV4_ADDR_STR);
|
||||
ipv4_dir_ap.port = TEST_IPV4_DIR_PORT;
|
||||
|
||||
tor_addr_parse(&ipv6_or_ap.addr, TEST_IPV6_ADDR_STR);
|
||||
ipv6_or_ap.port = TEST_IPV6_OR_PORT;
|
||||
tor_addr_parse(&ipv6_dir_ap.addr, TEST_IPV6_ADDR_STR);
|
||||
ipv6_dir_ap.port = TEST_IPV6_DIR_PORT;
|
||||
|
||||
tor_addr_make_null(&n_ipv4_ap.addr, AF_INET);
|
||||
n_ipv4_ap.port = 0;
|
||||
tor_addr_make_null(&n_ipv6_ap.addr, AF_INET6);
|
||||
n_ipv6_ap.port = 0;
|
||||
|
||||
/* Choose an address with IPv4 and IPv6 on */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 1;
|
||||
mock_options.ClientUseIPv6 = 1;
|
||||
mock_options.UseBridges = 0;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Preferring IPv4 OR / IPv6 Dir */
|
||||
mock_options.ClientPreferIPv6ORPort = 0;
|
||||
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)
|
||||
== &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 OR / IPv4 Dir */
|
||||
mock_options.ClientPreferIPv6ORPort = 1;
|
||||
mock_options.ClientPreferIPv6DirPort = 0;
|
||||
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)
|
||||
== &ipv4_dir_ap);
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
|
||||
FIREWALL_DIR_CONNECTION, 1)
|
||||
== &ipv4_dir_ap);
|
||||
|
||||
/* Choose an address with UseBridges on */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.UseBridges = 1;
|
||||
|
||||
for (mock_options.ClientUseIPv4 = 0; mock_options.ClientUseIPv4 <= 1;
|
||||
mock_options.ClientUseIPv4++) {
|
||||
for (mock_options.ClientUseIPv6 = 0; mock_options.ClientUseIPv6 <= 1;
|
||||
mock_options.ClientUseIPv6++) {
|
||||
for (mock_options.ClientPreferIPv6ORPort = 0;
|
||||
mock_options.ClientPreferIPv6ORPort <= 1;
|
||||
mock_options.ClientPreferIPv6ORPort++) {
|
||||
for (mock_options.ClientPreferIPv6DirPort = 0;
|
||||
mock_options.ClientPreferIPv6DirPort <= 1;
|
||||
mock_options.ClientPreferIPv6DirPort++) {
|
||||
/* This (ab)uses the actual enum values */
|
||||
tt_assert(FIREWALL_OR_CONNECTION < FIREWALL_DIR_CONNECTION);
|
||||
for (firewall_connection_t fw_connection = FIREWALL_OR_CONNECTION;
|
||||
fw_connection <= FIREWALL_DIR_CONNECTION; fw_connection++) {
|
||||
for (int pref_only = 0; pref_only <= 1; pref_only++) {
|
||||
|
||||
/* Ignoring all other settings, want_a should choose the address
|
||||
* for bridge clients */
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_or_ap,
|
||||
&ipv6_or_ap, 1,
|
||||
fw_connection,
|
||||
pref_only)
|
||||
== &ipv4_or_ap);
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_or_ap,
|
||||
&ipv6_or_ap, 0,
|
||||
fw_connection,
|
||||
pref_only)
|
||||
== &ipv6_or_ap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Choose an address with IPv4 on */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 1;
|
||||
mock_options.ClientUseIPv6 = 0;
|
||||
mock_options.UseBridges = 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);
|
||||
|
||||
/* Choose an address with IPv6 on */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 0;
|
||||
mock_options.ClientUseIPv6 = 1;
|
||||
mock_options.UseBridges = 0;
|
||||
|
||||
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 everything off */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 0;
|
||||
mock_options.ClientUseIPv6 = 0;
|
||||
mock_options.UseBridges = 0;
|
||||
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
|
||||
FIREWALL_OR_CONNECTION, 0)
|
||||
== NULL);
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
|
||||
FIREWALL_OR_CONNECTION, 1)
|
||||
== NULL);
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
|
||||
FIREWALL_DIR_CONNECTION, 0)
|
||||
== NULL);
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
|
||||
FIREWALL_DIR_CONNECTION, 1)
|
||||
== NULL);
|
||||
|
||||
/* Choose from unusual inputs */
|
||||
memset(&mock_options, 0, sizeof(or_options_t));
|
||||
mock_options.ClientUseIPv4 = 1;
|
||||
mock_options.ClientUseIPv6 = 1;
|
||||
mock_options.UseBridges = 1;
|
||||
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &n_ipv6_ap, 0,
|
||||
FIREWALL_OR_CONNECTION, 0)
|
||||
== &ipv4_or_ap);
|
||||
tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_or_ap, 0,
|
||||
FIREWALL_OR_CONNECTION, 0)
|
||||
== &ipv6_or_ap);
|
||||
tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
|
||||
FIREWALL_OR_CONNECTION, 0)
|
||||
== NULL);
|
||||
|
||||
tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &n_ipv6_ap, 0,
|
||||
FIREWALL_DIR_CONNECTION, 0)
|
||||
== &ipv4_dir_ap);
|
||||
tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_dir_ap, 0,
|
||||
FIREWALL_DIR_CONNECTION, 0)
|
||||
== &ipv6_dir_ap);
|
||||
tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
|
||||
FIREWALL_DIR_CONNECTION, 0)
|
||||
== NULL);
|
||||
|
||||
done:
|
||||
UNMOCK(get_options);
|
||||
}
|
||||
|
||||
#undef TEST_IPV4_ADDR_STR
|
||||
#undef TEST_IPV6_ADDR_STR
|
||||
#undef TEST_IPV4_OR_PORT
|
||||
#undef TEST_IPV4_DIR_PORT
|
||||
#undef TEST_IPV6_OR_PORT
|
||||
#undef TEST_IPV6_DIR_PORT
|
||||
|
||||
struct testcase_t policy_tests[] = {
|
||||
{ "router_dump_exit_policy_to_string", test_dump_exit_policy_to_string, 0,
|
||||
NULL, NULL },
|
||||
@ -1137,6 +1580,10 @@ struct testcase_t policy_tests[] = {
|
||||
{ "reject_interface_address", test_policies_reject_interface_address, 0,
|
||||
NULL, NULL },
|
||||
{ "reject_port_address", test_policies_reject_port_address, 0, NULL, NULL },
|
||||
{ "fascist_firewall_allows_address",
|
||||
test_policies_fascist_firewall_allows_address, 0, NULL, NULL },
|
||||
{ "fascist_firewall_choose_address",
|
||||
test_policies_fascist_firewall_choose_address, 0, NULL, NULL },
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user