diff options
author | teor <teor2345@gmail.com> | 2017-02-01 15:28:46 +1100 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2017-02-01 09:39:06 -0500 |
commit | 4667a40ca944134866b95b10407a7e471206aa00 (patch) | |
tree | 368311ed8f0124133addb88cef599929c7b69a2b /src | |
parent | 82850d0da6c29fe50e2622f0cde0142ca9530ae4 (diff) | |
download | tor-4667a40ca944134866b95b10407a7e471206aa00.tar.gz tor-4667a40ca944134866b95b10407a7e471206aa00.zip |
Fix IPv6 support in policy_summary_reject and policy_summary_accept
This interim fix results in too many IPv6 rejections.
No behaviour change for IPv4 counts, except for overflow fixes that
would require 4 billion redundant 0.0.0.0/0 policy entries to trigger.
Part of 21357
Diffstat (limited to 'src')
-rw-r--r-- | src/or/policies.c | 60 |
1 files changed, 47 insertions, 13 deletions
diff --git a/src/or/policies.c b/src/or/policies.c index 71062eb741..cac475db47 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -2304,6 +2304,12 @@ policy_summary_item_split(policy_summary_item_t* old, uint16_t new_starts) * IPv4 /8 address blocks */ #define REJECT_CUTOFF_COUNT_IPV4 (U64_LITERAL(1) << \ (IPV4_BITS - 7)) + +#define IPV6_BITS (128) +/* Ports are rejected in an IPv6 summary if they are rejected in at least one + * IPv6 /64. */ +#define REJECT_CUTOFF_COUNT_IPV6 (UINT64_MAX) + /** Split an exit policy summary so that prt_min and prt_max * fall at exactly the start and end of an item respectively. */ @@ -2336,40 +2342,68 @@ policy_summary_split(smartlist_t *summary, return start_at_index; } -/** Mark port ranges as accepted if they are below the reject_count */ +/** Mark port ranges as accepted if they are below the reject_count for family + */ static void policy_summary_accept(smartlist_t *summary, - uint16_t prt_min, uint16_t prt_max) + uint16_t prt_min, uint16_t prt_max, + sa_family_t family) { + tor_assert_nonfatal_once(family == AF_INET || family == AF_INET6); + uint64_t family_reject_count = ((family == AF_INET) ? + REJECT_CUTOFF_COUNT_IPV4 : + REJECT_CUTOFF_COUNT_IPV6); + int i = policy_summary_split(summary, prt_min, prt_max); while (i < smartlist_len(summary) && AT(i)->prt_max <= prt_max) { if (!AT(i)->accepted && - AT(i)->reject_count <= REJECT_CUTOFF_COUNT_IPV4) + AT(i)->reject_count <= family_reject_count) AT(i)->accepted = 1; i++; } tor_assert(i < smartlist_len(summary) || prt_max==65535); } -/** Count the number of addresses in a network with prefixlen maskbits - * against the given portrange. */ +/** Count the number of addresses in a network in family with prefixlen + * maskbits against the given portrange. */ static void policy_summary_reject(smartlist_t *summary, maskbits_t maskbits, - uint16_t prt_min, uint16_t prt_max) + uint16_t prt_min, uint16_t prt_max, + sa_family_t family) { + tor_assert_nonfatal_once(family == AF_INET || family == AF_INET6); + int i = policy_summary_split(summary, prt_min, prt_max); - /* XXX: ipv4 specific */ + /* The length of a single address mask */ - int addrbits = IPV4_BITS; + int addrbits = (family == AF_INET) ? IPV4_BITS : IPV6_BITS; tor_assert_nonfatal_once(addrbits >= maskbits); - uint64_t count = (U64_LITERAL(1) << (addrbits-maskbits)); + uint64_t count = 0; + if (addrbits - maskbits >= 64) { + tor_assert_nonfatal_once(family == AF_INET6); + /* The address range is so large, it's an automatic rejection for all ports + * in the range. */ + count = UINT64_MAX; + } else { + count = (U64_LITERAL(1) << (addrbits - maskbits)); + } tor_assert_nonfatal_once(count > 0); while (i < smartlist_len(summary) && AT(i)->prt_max <= prt_max) { - AT(i)->reject_count += count; + if (AT(i)->reject_count <= UINT64_MAX - count) { + AT(i)->reject_count += count; + } else { + /* IPv4 would require a 4-billion address redundant policy to get here, + * but IPv6 just needs to have ::/0 */ + if (family == AF_INET) { + tor_assert_nonfatal_unreached_once(); + } + /* If we do get here, use saturating arithmetic */ + AT(i)->reject_count = UINT64_MAX; + } i++; } tor_assert(i < smartlist_len(summary) || prt_max==65535); @@ -2389,7 +2423,7 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p) { if (p->policy_type == ADDR_POLICY_ACCEPT) { if (p->maskbits == 0) { - policy_summary_accept(summary, p->prt_min, p->prt_max); + policy_summary_accept(summary, p->prt_min, p->prt_max, p->addr.family); } } else if (p->policy_type == ADDR_POLICY_REJECT) { @@ -2410,7 +2444,8 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p) } if (!is_private) { - policy_summary_reject(summary, p->maskbits, p->prt_min, p->prt_max); + policy_summary_reject(summary, p->maskbits, p->prt_min, p->prt_max, + p->addr.family); } } else tor_assert(0); @@ -2444,7 +2479,6 @@ policy_summarize(smartlist_t *policy, sa_family_t family) } if (f != family) continue; - /* XXXX-ipv6 More family work is needed */ policy_summary_add_item(summary, p); } SMARTLIST_FOREACH_END(p); |