diff options
author | Nick Mathewson <nickm@torproject.org> | 2012-10-24 15:03:29 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2012-11-14 23:16:21 -0500 |
commit | a96c0affcb4cda1a2e0d83d123993d10efc6e396 (patch) | |
tree | 179be96049286cae1b9b1aa4b633f60da2c29023 /src/or/policies.c | |
parent | 2eb7eafc9d789cb5063dd36021412434b656bf75 (diff) | |
download | tor-a96c0affcb4cda1a2e0d83d123993d10efc6e396.tar.gz tor-a96c0affcb4cda1a2e0d83d123993d10efc6e396.zip |
Better policy support for IPv6
Now, "accept *:80" means "accept all addresses on port 80", and not
just IPv4. For just v4, say "accept *4:80"; for just v6 say "accept
*6:80".
We can parse these policies from torrc just fine, and we should be
successfully keeping them out of descriptors for now.
We also now include appropriate IPv6 addresses in "reject private:*"
Diffstat (limited to 'src/or/policies.c')
-rw-r--r-- | src/or/policies.c | 135 |
1 files changed, 110 insertions, 25 deletions
diff --git a/src/or/policies.c b/src/or/policies.c index 442377b1c5..8367446ff2 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -59,8 +59,10 @@ typedef struct policy_summary_item_t { static const char *private_nets[] = { "0.0.0.0/8", "169.254.0.0/16", "127.0.0.0/8", "192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12", - // "fc00::/7", "fe80::/10", "fec0::/10", "::/127", - NULL }; + "[::]/8", + "[fc00::]/7", "[fe80::]/10", "[fec0::]/10", "[ff00::]/8", "[::]/127", + NULL +}; /** Replace all "private" entries in *<b>policy</b> with their expanded * equivalents. */ @@ -101,6 +103,49 @@ policy_expand_private(smartlist_t **policy) *policy = tmp; } +/** Expand each of the AF_UNSPEC elements in *<b>policy</b> (which indicate + * protocol-neutral wildcards) into a pair of wildcard elements: one IPv4- + * specific and one IPv6-specific. */ +void +policy_expand_unspec(smartlist_t **policy) +{ + smartlist_t *tmp; + if (!*policy) + return; + + tmp = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(*policy, addr_policy_t *, p) { + sa_family_t family = tor_addr_family(&p->addr); + if (family == AF_INET6 || family == AF_INET || p->is_private) { + smartlist_add(tmp, p); + } else if (family == AF_UNSPEC) { + addr_policy_t newpolicy_ipv4; + addr_policy_t newpolicy_ipv6; + memcpy(&newpolicy_ipv4, p, sizeof(addr_policy_t)); + memcpy(&newpolicy_ipv6, p, sizeof(addr_policy_t)); + newpolicy_ipv4.is_canonical = 0; + newpolicy_ipv6.is_canonical = 0; + if (p->maskbits != 0) { + log_warn(LD_BUG, "AF_UNSPEC policy with maskbits==%d", p->maskbits); + newpolicy_ipv4.maskbits = 0; + newpolicy_ipv6.maskbits = 0; + } + tor_addr_from_ipv4h(&newpolicy_ipv4.addr, 0); + tor_addr_from_ipv6_bytes(&newpolicy_ipv6.addr, + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv4)); + smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv6)); + addr_policy_free(p); + } else { + log_warn(LD_BUG, "Funny-looking address policy with family %d", family); + smartlist_add(tmp, p); + } + } SMARTLIST_FOREACH_END(p); + + smartlist_free(*policy); + *policy = tmp; +} + /** * Given a linked list of config lines containing "allow" and "deny" * tokens, parse them and append the result to <b>dest</b>. Return -1 @@ -145,6 +190,7 @@ parse_addr_policy(config_line_t *cfg, smartlist_t **dest, addr_policy_list_free(result); } else { policy_expand_private(&result); + policy_expand_unspec(&result); if (*dest) { smartlist_add_all(*dest, result); @@ -735,6 +781,10 @@ compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port, static int addr_policy_covers(addr_policy_t *a, addr_policy_t *b) { + if (tor_addr_family(&a->addr) != tor_addr_family(&b->addr)) { + /* You can't cover a different family. */ + return 0; + } /* We can ignore accept/reject, since "accept *:80, reject *:80" reduces * to "accept *:80". */ if (a->maskbits > b->maskbits) { @@ -790,20 +840,32 @@ append_exit_policy_string(smartlist_t **policy, const char *more) static void exit_policy_remove_redundancies(smartlist_t *dest) { - addr_policy_t *ap, *tmp, *victim; + addr_policy_t *ap, *tmp; int i, j; - /* Step one: find a *:* entry and cut off everything after it. */ - for (i = 0; i < smartlist_len(dest); ++i) { - ap = smartlist_get(dest, i); - if (ap->maskbits == 0 && ap->prt_min <= 1 && ap->prt_max >= 65535) { - /* This is a catch-all line -- later lines are unreachable. */ - while (i+1 < smartlist_len(dest)) { - victim = smartlist_get(dest, i+1); - smartlist_del(dest, i+1); - addr_policy_free(victim); + /* Step one: kill every ipv4 thing after *4:*, every IPv6 thing after *6:* + */ + { + int kill_v4=0, kill_v6=0; + for (i = 0; i < smartlist_len(dest); ++i) { + sa_family_t family; + ap = smartlist_get(dest, i); + family = tor_addr_family(&ap->addr); + if ((family == AF_INET && kill_v4) || + (family == AF_INET6 && kill_v6)) { + smartlist_del_keeporder(dest, i--); + addr_policy_free(ap); + continue; + } + + if (ap->maskbits == 0 && ap->prt_min <= 1 && ap->prt_max >= 65535) { + /* This is a catch-all line -- later lines are unreachable. */ + if (family == AF_INET) { + kill_v4 = 1; + } else if (family == AF_INET6) { + kill_v6 = 1; + } } - break; } } @@ -869,6 +931,10 @@ exit_policy_remove_redundancies(smartlist_t *dest) * policy afterwards. If <b>rejectprivate</b> is true, prepend * "reject private:*" to the policy. Return -1 if we can't parse cfg, * else return 0. + * + * This function is used to parse the exit policy from our torrc. For + * the functions used to parse the exit policy from a router descriptor, + * see router_add_exit_policy. */ int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, @@ -885,10 +951,12 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, } if (parse_addr_policy(cfg, dest, -1)) return -1; - if (add_default_policy) + if (add_default_policy) { append_exit_policy_string(dest, DEFAULT_EXIT_POLICY); - else - append_exit_policy_string(dest, "reject *:*"); + } else { + append_exit_policy_string(dest, "reject *4:*"); + append_exit_policy_string(dest, "reject *6:*"); + } exit_policy_remove_redundancies(*dest); return 0; @@ -899,7 +967,8 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, void policies_exit_policy_append_reject_star(smartlist_t **dest) { - append_exit_policy_string(dest, "reject *:*"); + append_exit_policy_string(dest, "reject *4:*"); + append_exit_policy_string(dest, "reject *6:*"); } /** Replace the exit policy of <b>node</b> with reject *:* */ @@ -1001,17 +1070,26 @@ policy_write_item(char *buf, size_t buflen, addr_policy_t *policy, const char *addrpart; int result; const int is_accept = policy->policy_type == ADDR_POLICY_ACCEPT; - const int is_ip6 = tor_addr_family(&policy->addr) == AF_INET6; + const sa_family_t family = tor_addr_family(&policy->addr); + const int is_ip6 = (family == AF_INET6); tor_addr_to_str(addrbuf, &policy->addr, sizeof(addrbuf), 1); /* write accept/reject 1.2.3.4 */ - if (policy->is_private) + if (policy->is_private) { addrpart = "private"; - else if (policy->maskbits == 0) - addrpart = "*"; - else + } else if (policy->maskbits == 0) { + if (format_for_desc) + addrpart = "*"; + else if (family == AF_INET6) + addrpart = "*6"; + else if (family == AF_INET) + addrpart = "*4"; + else + addrpart = "*"; + } else { addrpart = addrbuf; + } result = tor_snprintf(buf, buflen, "%s%s %s", is_accept ? "accept" : "reject", @@ -1220,7 +1298,7 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p) * is an exception to the shorter-representation-wins rule). */ char * -policy_summarize(smartlist_t *policy) +policy_summarize(smartlist_t *policy, sa_family_t family) { smartlist_t *summary = policy_summary_create(); smartlist_t *accepts, *rejects; @@ -1232,9 +1310,16 @@ policy_summarize(smartlist_t *policy) tor_assert(policy); /* Create the summary list */ - SMARTLIST_FOREACH(policy, addr_policy_t *, p, { + SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) { + sa_family_t f = tor_addr_family(&p->addr); + if (f != AF_INET && f != AF_INET6) { + log_warn(LD_BUG, "Weird family when summarizing address policy"); + } + if (f != family) + continue; + /* XXXX-ipv6 More family work is needed */ policy_summary_add_item(summary, p); - }); + } SMARTLIST_FOREACH_END(p); /* Now create two lists of strings, one for accepted and one * for rejected ports. We take care to merge ranges so that |