Commit f1530d0e authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

Merge branch 'teor_bug21357-v2_029'

parents c3b63544 bed94a9e
Loading
Loading
Loading
Loading

changes/bug21357

0 → 100644
+7 −0
Original line number Diff line number Diff line
  o Major bugfixes (IPv6 Exits):
    - Stop rejecting all IPv6 traffic on Exits whose exit policy rejects IPv6
      addresses. Instead, only reject a port over IPv6 if the exit policy
      rejects that port on more than an IPv6 /16 of addresses. This bug was
      made worse by 17027 in 0.2.8.1-alpha, which rejects a relay's own IPv6
      address by default.
      Fixes bug 21357; bugfix on commit 004f3f4e53 in 0.2.4.7-alpha.
+80 −15
Original line number Diff line number Diff line
@@ -2353,7 +2353,26 @@ policy_summary_item_split(policy_summary_item_t* old, uint16_t new_starts)
 * my immortal soul, he can clean it up himself. */
#define AT(x) ((policy_summary_item_t*)smartlist_get(summary, x))

#define REJECT_CUTOFF_COUNT (1<<25)
#define IPV4_BITS                (32)
/* Every IPv4 address is counted as one rejection */
#define REJECT_CUTOFF_SCALE_IPV4 (0)
/* Ports are rejected in an IPv4 summary if they are rejected in more than two
 * IPv4 /8 address blocks */
#define REJECT_CUTOFF_COUNT_IPV4 (U64_LITERAL(1) << \
                                  (IPV4_BITS - REJECT_CUTOFF_SCALE_IPV4 - 7))

#define IPV6_BITS                (128)
/* IPv6 /64s are counted as one rejection, anything smaller is ignored */
#define REJECT_CUTOFF_SCALE_IPV6 (64)
/* Ports are rejected in an IPv6 summary if they are rejected in more than one
 * IPv6 /16 address block.
 * This is rougly equivalent to the IPv4 cutoff, as only five IPv6 /12s (and
 * some scattered smaller blocks) have been allocated to the RIRs.
 * Network providers are typically allocated one or more IPv6 /32s.
 */
#define REJECT_CUTOFF_COUNT_IPV6 (U64_LITERAL(1) << \
                                  (IPV6_BITS - REJECT_CUTOFF_SCALE_IPV6 - 16))

/** Split an exit policy summary so that prt_min and prt_max
 * fall at exactly the start and end of an item respectively.
 */
@@ -2386,35 +2405,82 @@ 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)
        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 */
  uint64_t count = (U64_LITERAL(1) << (32-maskbits));

  /* The length of a single address mask */
  int addrbits = (family == AF_INET) ? IPV4_BITS : IPV6_BITS;
  tor_assert_nonfatal_once(addrbits >= maskbits);

  /* We divide IPv6 address counts by (1 << scale) to keep them in a uint64_t
   */
  int scale = ((family == AF_INET) ?
               REJECT_CUTOFF_SCALE_IPV4 :
               REJECT_CUTOFF_SCALE_IPV6);

  tor_assert_nonfatal_once(addrbits >= scale);
  if (maskbits > (addrbits - scale)) {
    tor_assert_nonfatal_once(family == AF_INET6);
    /* The address range is so small, we'd need billions of them to reach the
     * rejection limit. So we ignore this range in the reject count. */
    return;
  }

  uint64_t count = 0;
  if (addrbits - scale - 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 - scale - maskbits));
  }
  tor_assert_nonfatal_once(count > 0);
  while (i < smartlist_len(summary) &&
         AT(i)->prt_max <= prt_max) {
    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);
@@ -2434,7 +2500,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) {

@@ -2455,7 +2521,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);
@@ -2489,7 +2556,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);

@@ -2678,8 +2744,7 @@ parse_short_policy(const char *summary)
  return result;
}

/** Write <b>policy</b> back out into a string. Used only for unit tests
 * currently. */
/** Write <b>policy</b> back out into a string. */
char *
write_short_policy(const short_policy_t *policy)
{
+3 −0
Original line number Diff line number Diff line
@@ -22,6 +22,9 @@
#define EXIT_POLICY_REJECT_PRIVATE           (1 << 1)
#define EXIT_POLICY_ADD_DEFAULT              (1 << 2)
#define EXIT_POLICY_REJECT_LOCAL_INTERFACES  (1 << 3)
#define EXIT_POLICY_OPTION_MAX             EXIT_POLICY_REJECT_LOCAL_INTERFACES
/* All options set: used for unit testing */
#define EXIT_POLICY_OPTION_ALL             ((EXIT_POLICY_OPTION_MAX << 1) - 1)

typedef enum firewall_connection_t {
  FIREWALL_OR_CONNECTION      = 0,