diff options
Diffstat (limited to 'src/or/policies.c')
-rw-r--r-- | src/or/policies.c | 307 |
1 files changed, 192 insertions, 115 deletions
diff --git a/src/or/policies.c b/src/or/policies.c index 0e7b3bda2e..f4cde43ae4 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -63,17 +63,14 @@ static const char *private_nets[] = { }; static int policies_parse_exit_policy_internal( - config_line_t *cfg, - smartlist_t **dest, - int ipv6_exit, - int rejectprivate, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address, - int reject_interface_addresses, - int reject_configured_port_addresses, - int add_default_policy); + config_line_t *cfg, + smartlist_t **dest, + int ipv6_exit, + int rejectprivate, + const smartlist_t *configured_addresses, + int reject_interface_addresses, + int reject_configured_port_addresses, + int add_default_policy); /** Replace all "private" entries in *<b>policy</b> with their expanded * equivalents. */ @@ -868,7 +865,7 @@ addr_policy_intersects(addr_policy_t *a, addr_policy_t *b) /** Add the exit policy described by <b>more</b> to <b>policy</b>. */ -static void +STATIC void append_exit_policy_string(smartlist_t **policy, const char *more) { config_line_t tmp; @@ -885,6 +882,9 @@ append_exit_policy_string(smartlist_t **policy, const char *more) void addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr) { + tor_assert(dest); + tor_assert(addr); + addr_policy_t p, *add; memset(&p, 0, sizeof(p)); p.policy_type = ADDR_POLICY_REJECT; @@ -902,17 +902,68 @@ addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr) } +/* Is addr public for the purposes of rejection? */ +static int +tor_addr_is_public_for_reject(const tor_addr_t *addr) +{ + return !tor_addr_is_null(addr) && !tor_addr_is_internal(addr, 0); +} + +/* Add "reject <b>addr</b>:*" to <b>dest</b>, creating the list as needed. + * Filter the address, only adding an IPv4 reject rule if ipv4_rules + * is true, and similarly for ipv6_rules. Check each address returns true for + * tor_addr_is_public_for_reject before adding it. + */ +static void +addr_policy_append_reject_addr_filter(smartlist_t **dest, + const tor_addr_t *addr, + int ipv4_rules, + int ipv6_rules) +{ + tor_assert(dest); + tor_assert(addr); + + /* Only reject IP addresses which are public */ + if (tor_addr_is_public_for_reject(addr)) { + + /* Reject IPv4 addresses and IPv6 addresses based on the filters */ + int is_ipv4 = tor_addr_is_v4(addr); + if ((is_ipv4 && ipv4_rules) || (!is_ipv4 && ipv6_rules)) { + addr_policy_append_reject_addr(dest, addr); + } + } +} + /** Add "reject addr:*" to <b>dest</b>, for each addr in addrs, creating the * list as needed. */ void addr_policy_append_reject_addr_list(smartlist_t **dest, const smartlist_t *addrs) { + tor_assert(dest); + tor_assert(addrs); + SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, addr) { addr_policy_append_reject_addr(dest, addr); } SMARTLIST_FOREACH_END(addr); } +/** Add "reject addr:*" to <b>dest</b>, for each addr in addrs, creating the + * list as needed. Filter using */ +static void +addr_policy_append_reject_addr_list_filter(smartlist_t **dest, + const smartlist_t *addrs, + int ipv4_rules, + int ipv6_rules) +{ + tor_assert(dest); + tor_assert(addrs); + + SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, addr) { + addr_policy_append_reject_addr_filter(dest, addr, ipv4_rules, ipv6_rules); + } SMARTLIST_FOREACH_END(addr); +} + /** Detect and excise "dead code" from the policy *<b>dest</b>. */ static void exit_policy_remove_redundancies(smartlist_t *dest) @@ -997,21 +1048,12 @@ exit_policy_remove_redundancies(smartlist_t *dest) } } -/* Is addr public for the purposes of rejection? */ -static int -tor_addr_is_public_for_reject(const tor_addr_t *addr) -{ - return !tor_addr_is_null(addr) && !tor_addr_is_internal(addr, 0); -} - /** Reject private helper for policies_parse_exit_policy_internal: rejects * publicly routable addresses on this exit relay. * * Add reject entries to the linked list *dest: - * - if local_address is non-zero, treat it as a host-order IPv4 address, - * and add an entry that rejects it as a destination. - * - if ipv6_local_address, ipv4_outbound_address, or ipv6_outbound_address - * are non-NULL, add entries that reject them as destinations. + * - if configured_addresses is non-NULL, add entries that reject each + * tor_addr_t* in the list as a destination. * - if reject_interface_addresses is true, add entries that reject each * public IPv4 and IPv6 address of each interface on this machine. * - if reject_configured_port_addresses is true, add entries that reject @@ -1027,60 +1069,16 @@ void policies_parse_exit_policy_reject_private( smartlist_t **dest, int ipv6_exit, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address, + const smartlist_t *configured_addresses, int reject_interface_addresses, int reject_configured_port_addresses) { tor_assert(dest); - /* Reject our local IPv4 address */ - if (local_address) { - tor_addr_t v4_local; - tor_addr_from_ipv4h(&v4_local, local_address); - if (tor_addr_is_public_for_reject(&v4_local)) { - addr_policy_append_reject_addr(dest, &v4_local); - log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject %s:*' for our " - "published IPv4 address", fmt_addr32(local_address)); - } - } - - /* Reject the outbound IPv4 connection address */ - if (ipv4_outbound_address - && tor_addr_is_public_for_reject(ipv4_outbound_address)) { - addr_policy_append_reject_addr(dest, ipv4_outbound_address); - log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject %s:*' for " - "our outbound IPv4 connection address", - fmt_addr(ipv4_outbound_address)); - } - - /* If we're not an IPv6 exit, all IPv6 addresses have already been rejected - * by policies_parse_exit_policy_internal */ - if (ipv6_exit) { - - /* Reject our local IPv6 address */ - if (ipv6_local_address != NULL - && tor_addr_is_public_for_reject(ipv6_local_address)) { - if (tor_addr_is_v4(ipv6_local_address)) { - log_warn(LD_CONFIG, "IPv4 address '%s' provided as our IPv6 local " - "address", fmt_addr(ipv6_local_address)); - } else { - addr_policy_append_reject_addr(dest, ipv6_local_address); - log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject [%s]:*' for " - "our published IPv6 address", fmt_addr(ipv6_local_address)); - } - } - - /* Reject the outbound IPv6 connection address */ - if (ipv6_outbound_address - && tor_addr_is_public_for_reject(ipv6_outbound_address)) { - addr_policy_append_reject_addr(dest, ipv6_outbound_address); - log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject [%s]:*' for " - "our outbound IPv6 connection address", - fmt_addr(ipv6_outbound_address)); - } + /* Reject configured addresses, if they are from public netblocks. */ + if (configured_addresses) { + addr_policy_append_reject_addr_list_filter(dest, configured_addresses, + 1, ipv6_exit); } /* Reject configured port addresses, if they are from public netblocks. */ @@ -1089,14 +1087,9 @@ policies_parse_exit_policy_reject_private( SMARTLIST_FOREACH_BEGIN(port_addrs, port_cfg_t *, port) { - /* Only reject IP addresses which are public */ - if (!port->is_unix_addr && tor_addr_is_public_for_reject(&port->addr)) { - - /* Reject IPv4 addresses. If we are an IPv6 exit, also reject IPv6 - * addresses */ - if (tor_addr_is_v4(&port->addr) || ipv6_exit) { - addr_policy_append_reject_addr(dest, &port->addr); - } + /* Only reject port IP addresses, not port unix sockets */ + if (!port->is_unix_addr) { + addr_policy_append_reject_addr_filter(dest, &port->addr, 1, ipv6_exit); } } SMARTLIST_FOREACH_END(port); } @@ -1107,13 +1100,14 @@ policies_parse_exit_policy_reject_private( /* Reject public IPv4 addresses on any interface */ public_addresses = get_interface_address6_list(LOG_INFO, AF_INET, 0); - addr_policy_append_reject_addr_list(dest, public_addresses); + addr_policy_append_reject_addr_list_filter(dest, public_addresses, 1, 0); free_interface_address6_list(public_addresses); + /* Don't look for IPv6 addresses if we're configured as IPv4-only */ if (ipv6_exit) { /* Reject public IPv6 addresses on any interface */ public_addresses = get_interface_address6_list(LOG_INFO, AF_INET6, 0); - addr_policy_append_reject_addr_list(dest, public_addresses); + addr_policy_append_reject_addr_list_filter(dest, public_addresses, 0, 1); free_interface_address6_list(public_addresses); } } @@ -1149,13 +1143,11 @@ policies_parse_exit_policy_reject_private( * see router_add_exit_policy. */ static int -policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, +policies_parse_exit_policy_internal(config_line_t *cfg, + smartlist_t **dest, int ipv6_exit, int rejectprivate, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address, + const smartlist_t *configured_addresses, int reject_interface_addresses, int reject_configured_port_addresses, int add_default_policy) @@ -1168,10 +1160,8 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, append_exit_policy_string(dest, "reject private:*"); /* Reject IPv4 and IPv6 publicly routable addresses on this exit relay */ policies_parse_exit_policy_reject_private( - dest, ipv6_exit, local_address, - ipv6_local_address, - ipv4_outbound_address, - ipv6_outbound_address, + dest, ipv6_exit, + configured_addresses, reject_interface_addresses, reject_configured_port_addresses); } @@ -1256,12 +1246,8 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, * If <b>EXIT_POLICY_REJECT_PRIVATE</b> bit is set in <b>options</b>: * - prepend an entry that rejects all destinations in all netblocks * reserved for private use. - * - if local_address is non-zero, treat it as a host-order IPv4 address, - * and prepend an entry that rejects it as a destination. - * - if ipv6_local_address is non-NULL, prepend an entry that rejects it as - * a destination. - * - if reject_interface_addresses is true, prepend entries that reject each - * public IPv4 and IPv6 address of each interface on this machine. + * - prepend entries that reject publicly routable addresses on this exit + * relay by calling policies_parse_exit_policy_internal * * If <b>EXIT_POLICY_ADD_DEFAULT</b> bit is set in <b>options</b>, append * default exit policy entries to <b>result</b> smartlist. @@ -1269,10 +1255,7 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, exit_policy_parser_cfg_t options, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address) + const smartlist_t *configured_addresses) { int ipv6_enabled = (options & EXIT_POLICY_IPV6_ENABLED) ? 1 : 0; int reject_private = (options & EXIT_POLICY_REJECT_PRIVATE) ? 1 : 0; @@ -1280,15 +1263,51 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, return policies_parse_exit_policy_internal(cfg,dest,ipv6_enabled, reject_private, - local_address, - ipv6_local_address, - ipv4_outbound_address, - ipv6_outbound_address, + configured_addresses, reject_private, reject_private, add_default); } +/** Helper function that adds addr to a smartlist as long as it is non-NULL + * and not tor_addr_is_null(). */ +static void +policies_add_addr_to_smartlist(smartlist_t *addr_list, const tor_addr_t *addr) +{ + if (addr && !tor_addr_is_null(addr)) { + smartlist_add(addr_list, (void *)addr); + } +} + +/** Helper function that adds ipv4h_addr to a smartlist as a tor_addr_t *, + * by converting it to a tor_addr_t and passing it to + * policies_add_addr_to_smartlist. */ +static void +policies_add_ipv4h_to_smartlist(smartlist_t *addr_list, uint32_t ipv4h_addr) +{ + if (ipv4h_addr) { + tor_addr_t ipv4_tor_addr; + tor_addr_from_ipv4h(&ipv4_tor_addr, ipv4h_addr); + policies_add_addr_to_smartlist(addr_list, (void *)&ipv4_tor_addr); + } +} + +/** Helper function that adds or_options->OutboundBindAddressIPv[4|6]_ to a + * smartlist as a tor_addr_t *, as long as or_options is non-NULL, + * by passing them to policies_add_addr_to_smartlist. */ +static void +policies_add_outbound_addresses_to_smartlist(smartlist_t *addr_list, + const or_options_t *or_options) +{ + if (or_options) { + policies_add_addr_to_smartlist(addr_list, + &or_options->OutboundBindAddressIPv4_); + policies_add_addr_to_smartlist(addr_list, + &or_options->OutboundBindAddressIPv6_); + } +} + + /** Parse <b>ExitPolicy</b> member of <b>or_options</b> into <b>result</b> * smartlist. * If <b>or_options->IPv6Exit</b> is false, prepend an entry that @@ -1298,11 +1317,13 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, * - prepend an entry that rejects all destinations in all netblocks reserved * for private use. * - if local_address is non-zero, treat it as a host-order IPv4 address, and - * prepend an entry that rejects it as a destination. - * - if ipv6_local_address is non-NULL, prepend an entry that rejects it as a - * destination. - * - if reject_interface_addresses is true, prepend entries that reject each - * public IPv4 and IPv6 address of each interface on this machine. + * add it to the list of configured addresses. + * - if ipv6_local_address is non-NULL, and not the null tor_addr_t, add it + * to the list of configured addresses. + * - if or_options->OutboundBindAddressIPv4_ is not the null tor_addr_t, add + * it to the list of configured addresses. + * - if or_options->OutboundBindAddressIPv6_ is not the null tor_addr_t, add + * it to the list of configured addresses. * * If <b>or_options->BridgeRelay</b> is false, append entries of default * Tor exit policy into <b>result</b> smartlist. @@ -1317,13 +1338,17 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options, smartlist_t **result) { exit_policy_parser_cfg_t parser_cfg = 0; + smartlist_t *configured_addresses = smartlist_new(); + int rv = 0; + /* Short-circuit for non-exit relays */ if (or_options->ExitRelay == 0) { append_exit_policy_string(result, "reject *4:*"); append_exit_policy_string(result, "reject *6:*"); return 0; } + /* Configure the parser */ if (or_options->IPv6Exit) { parser_cfg |= EXIT_POLICY_IPV6_ENABLED; } @@ -1336,11 +1361,20 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options, parser_cfg |= EXIT_POLICY_ADD_DEFAULT; } - return policies_parse_exit_policy(or_options->ExitPolicy,result, - parser_cfg,local_address, - ipv6_local_address, - &or_options->OutboundBindAddressIPv4_, - &or_options->OutboundBindAddressIPv6_); + /* Add the configured addresses to the tor_addr_t* list */ + policies_add_ipv4h_to_smartlist(configured_addresses, local_address); + policies_add_addr_to_smartlist(configured_addresses, ipv6_local_address); + policies_add_outbound_addresses_to_smartlist(configured_addresses, + or_options); + + rv = policies_parse_exit_policy(or_options->ExitPolicy, result, parser_cfg, + configured_addresses); + + /* We don't need to free the pointers in this list, they are either constant + * or locally scoped. */ + smartlist_free(configured_addresses); + + return rv; } /** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating @@ -2085,6 +2119,49 @@ getinfo_helper_policies(control_connection_t *conn, (void) errmsg; if (!strcmp(question, "exit-policy/default")) { *answer = tor_strdup(DEFAULT_EXIT_POLICY); + } else if (!strcmp(question, "exit-policy/reject-private/default")) { + smartlist_t *private_policy_strings; + const char **priv = private_nets; + + private_policy_strings = smartlist_new(); + + while (*priv != NULL) { + /* IPv6 addresses are in "[]" and contain ":", + * IPv4 addresses are not in "[]" and contain "." */ + smartlist_add_asprintf(private_policy_strings, "reject %s:*", *priv); + priv++; + } + + *answer = smartlist_join_strings(private_policy_strings, + ",", 0, NULL); + + SMARTLIST_FOREACH(private_policy_strings, char *, str, tor_free(str)); + smartlist_free(private_policy_strings); + } else if (!strcmp(question, "exit-policy/reject-private/relay")) { + const or_options_t *options = get_options(); + const routerinfo_t *me = router_get_my_routerinfo(); + smartlist_t *private_policy_list = smartlist_new(); + smartlist_t *configured_addresses = smartlist_new(); + + if (!me) { + *errmsg = "router_get_my_routerinfo returned NULL"; + return -1; + } + + /* Add the configured addresses to the tor_addr_t* list */ + policies_add_ipv4h_to_smartlist(configured_addresses, me->addr); + policies_add_addr_to_smartlist(configured_addresses, &me->ipv6_addr); + policies_add_outbound_addresses_to_smartlist(configured_addresses, + options); + + policies_parse_exit_policy_reject_private( + &private_policy_list, + options->IPv6Exit, + configured_addresses, + 1, 1); + *answer = policy_dump_to_string(private_policy_list, 1, 1); + + addr_policy_list_free(private_policy_list); } else if (!strcmpstart(question, "exit-policy/")) { const routerinfo_t *me = router_get_my_routerinfo(); |