diff options
author | Nick Mathewson <nickm@torproject.org> | 2016-02-11 12:20:20 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2016-02-11 12:20:20 -0500 |
commit | ba2be81fc36ba6140247873799b747605fb07bd4 (patch) | |
tree | bf63ac0c702babc4f467af10f4ae85620b3fb8e4 /src/or/policies.c | |
parent | cae59b913f7daa154c6b1eb9083d1f582c8d2a1e (diff) | |
parent | c213f277cde00b258b159446f8d975026194c034 (diff) | |
download | tor-ba2be81fc36ba6140247873799b747605fb07bd4.tar.gz tor-ba2be81fc36ba6140247873799b747605fb07bd4.zip |
Merge remote-tracking branch 'teor/feature17840-v11-merged-v2'
Diffstat (limited to 'src/or/policies.c')
-rw-r--r-- | src/or/policies.c | 695 |
1 files changed, 666 insertions, 29 deletions
diff --git a/src/or/policies.c b/src/or/policies.c index 4706a9da72..faa39adfd6 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -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,76 @@ parse_reachable_addresses(void) "Error parsing ReachableDirAddresses entry; ignoring."); ret = -1; } + + /* 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 + && 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."); + } 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 might block any address:port - * combination. +/* Return true iff ClientUseIPv4 0 or ClientUseIPv6 0 might block any OR or Dir + * address:port combination. */ +static int +firewall_is_fascist_impl(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 (options->ClientUseIPv4 == 0 + || (!fascist_firewall_use_ipv6(options) + && options->UseBridges == 1)); +} + +/** Return true iff the firewall options, including ClientUseIPv4 0 and + * ClientUseIPv6 0, might block any OR address:port combination. + * Address preferences may still change which address is selected even if + * this function returns false. */ int firewall_is_fascist_or(void) { - return reachable_or_addr_policy != NULL; + return (reachable_or_addr_policy != NULL || firewall_is_fascist_impl()); +} + +/** Return true iff the firewall options, including ClientUseIPv4 0 and + * ClientUseIPv6 0, might block any Dir address:port combination. + * Address preferences may still change which address is selected even if + * this function returns false. + */ +int +firewall_is_fascist_dir(void) +{ + return (reachable_dir_addr_policy != NULL || firewall_is_fascist_impl()); } /** Return true iff <b>policy</b> (possibly NULL) will allow a @@ -317,49 +378,625 @@ 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 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 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. */ +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 (!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 && + (!fascist_firewall_use_ipv6(options) || (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>. */ +/** Is this client configured to use IPv6? + */ +int fascist_firewall_use_ipv6(const or_options_t *options) +{ + /* Clients use IPv6 if it's set, or they use bridges, or they don't use + * IPv4 */ + return (options->ClientUseIPv6 == 1 || options->UseBridges == 1 + || options->ClientUseIPv4 == 0); +} + +/** 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_allows_or(const routerinfo_t *ri) +fascist_firewall_prefer_ipv6_orport(const or_options_t *options) +{ + /* node->ipv6_preferred is set from fascist_firewall_prefer_ipv6_orport() + * each time the consensus is loaded. + * If our preferences change, we will only reset ipv6_preferred on the node + * when the next consensus is loaded. But the consensus is realoded when the + * configuration changes after a HUP. So as long as the result of this + * function only depends on Tor's options, everything should work ok. + */ + 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; + } + + return 0; +} + +/** Do we prefer to connect to IPv6 DirPorts? + */ +int +fascist_firewall_prefer_ipv6_dirport(const or_options_t *options) { - /* XXXX proposal 118 */ - tor_addr_t addr; - tor_addr_from_ipv4h(&addr, ri->addr); - return fascist_firewall_allows_address_or(&addr, ri->or_port); + 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; + } + + return 0; } -/** Return true iff we think our firewall will let us make an OR connection to - * <b>node</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_node(const node_t *node) +fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port, + firewall_connection_t fw_connection, + int pref_only) { - 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); + const or_options_t *options = get_options(); + + if (fw_connection == FIREWALL_OR_CONNECTION) { + return fascist_firewall_allows_address(addr, port, + reachable_or_addr_policy, + pref_only, + 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, + fascist_firewall_prefer_ipv6_dirport(options)); } else { + 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 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_ap(const tor_addr_port_t *ap, + firewall_connection_t fw_connection, + int pref_only) +{ + 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; } -/** Return true iff we think our firewall will let us make a directory - * connection to addr:port. */ +/** 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); +} + +/** 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_address_dir(const tor_addr_t *addr, uint16_t port) +fascist_firewall_allows_rs(const routerstatus_t *rs, + firewall_connection_t fw_connection, int pref_only) { - return addr_policy_permits_tor_addr(addr, port, - reachable_dir_addr_policy); + 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>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>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 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, |