[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#856790: marked as done (unblock: tor/0.2.9.10-1)



Your message dated Sun, 05 Mar 2017 20:59:44 +0000
with message-id <E1ckdFo-0000sR-F1@respighi.debian.org>
and subject line unblock tor
has caused the Debian Bug report #856790,
regarding unblock: tor/0.2.9.10-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
856790: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=856790
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package tor

unblock tor/0.2.9.10-1

I would very much like to update tor in testing.  I have not yet
uploaded my proposed change to unstable.

This new version fixes the underlying bug of the DoS issue tracked
upstream as TROVE-2017-001.  Debian Bug #856786, upstream issue
https://bugs.torproject.org/21278

It also makes ipv6 exit relays actually exit.  Debian Bug #856788,
upstream https://bugs.torproject.org/21357

This upload also fixes a few other, minor issues as it is an upstream
bugfix release -- the 0.2.9.x branch does not see new features, it only
sees bug fixes for issues where the bug-severity/change-complexity seem
appropriate (and it's a conservative cutoff).

Please find attached the diff of my proposed upload.  Let me know if I can go
forward.

diffstat of attached file:
 ChangeLog               |   62 +++++
 configure.ac            |    7 
 debian/changelog        |   11 
 src/or/dirserv.c        |   16 +
 src/or/dirvote.c        |   30 +-
 src/or/policies.c       |  153 +++++++++----
 src/or/policies.h       |    5 
 src/or/routerlist.c     |    2 
 src/or/routerparse.c    |  126 +++++++----
 src/or/routerparse.h    |    3 
 src/test/test_policy.c  |  542 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/test/test_tortls.c  |   43 ++-
 src/tools/tor-resolve.c |    4 
 src/win32/orconfig.h    |    2 
 14 files changed, 874 insertions(+), 132 deletions(-)

additionally, I have cut the following from my diff (db update and a duplicate
of the changelog and more windows only stuff):
 contrib/win32build/tor-mingw.nsi.in |    2 
 ReleaseNotes                        |   62 
 src/config/geoip                    |10832 +++++++++++++++++++-----------------
 src/config/geoip6                   | 1651 ++++-

Cheers,
diff --git a/ChangeLog b/ChangeLog
index 512c245..203a213 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,65 @@
+Changes in version 0.2.9.10 - 2017-03-01
+  Tor 0.2.9.10 backports a security fix for users who build Tor with
+  the --enable-expensive-hardening option. It also includes fixes for
+  some major issues affecting directory authorities, LibreSSL
+  compatibility, and IPv6 correctness.
+
+  The Tor 0.2.9.x release series is now marked as a long-term-support
+  series.  We intend to backport security fixes to 0.2.9.x until at
+  least January of 2020.
+
+  o Major bugfixes (directory authority, 0.3.0.3-alpha):
+    - During voting, when marking a relay as a probable sybil, do not
+      clear its BadExit flag: sybils can still be bad in other ways
+      too. (We still clear the other flags.) Fixes bug 21108; bugfix
+      on 0.2.0.13-alpha.
+
+  o Major bugfixes (IPv6 Exits, backport from 0.3.0.3-alpha):
+    - Stop rejecting all IPv6 traffic on Exits whose exit policy rejects
+      any 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 rejected a relay's own IPv6 address by default. Fixes bug
+      21357; bugfix on commit 004f3f4e53 in 0.2.4.7-alpha.
+
+  o Major bugfixes (parsing, also in 0.3.0.4-rc):
+    - Fix an integer underflow bug when comparing malformed Tor
+      versions. This bug could crash Tor when built with
+      --enable-expensive-hardening, or on Tor 0.2.9.1-alpha through Tor
+      0.2.9.8, which were built with -ftrapv by default. In other cases
+      it was harmless. Part of TROVE-2017-001. Fixes bug 21278; bugfix
+      on 0.0.8pre1. Found by OSS-Fuzz.
+
+  o Minor features (directory authorities, also in 0.3.0.4-rc):
+    - Directory authorities now reject descriptors that claim to be
+      malformed versions of Tor. Helps prevent exploitation of
+      bug 21278.
+    - Reject version numbers with components that exceed INT32_MAX.
+      Otherwise 32-bit and 64-bit platforms would behave inconsistently.
+      Fixes bug 21450; bugfix on 0.0.8pre1.
+
+  o Minor features (geoip):
+    - Update geoip and geoip6 to the February 8 2017 Maxmind GeoLite2
+      Country database.
+
+  o Minor features (portability, compilation, backport from 0.3.0.3-alpha):
+    - Autoconf now checks to determine if OpenSSL structures are opaque,
+      instead of explicitly checking for OpenSSL version numbers. Part
+      of ticket 21359.
+    - Support building with recent LibreSSL code that uses opaque
+      structures. Closes ticket 21359.
+
+  o Minor bugfixes (code correctness, also in 0.3.0.4-rc):
+    - Repair a couple of (unreachable or harmless) cases of the risky
+      comparison-by-subtraction pattern that caused bug 21278.
+
+  o Minor bugfixes (tor-resolve, backport from 0.3.0.3-alpha):
+    - The tor-resolve command line tool now rejects hostnames over 255
+      characters in length. Previously, it would silently truncate them,
+      which could lead to bugs. Fixes bug 21280; bugfix on 0.0.9pre5.
+      Patch by "junglefowl".
+
+
 Changes in version 0.2.9.9 - 2017-01-23
   Tor 0.2.9.9 fixes a denial-of-service bug where an attacker could
   cause relays and clients to crash, even if they were not built with
diff --git a/ReleaseNotes b/ReleaseNotes
[cut]
diff --git a/configure.ac b/configure.ac
index 1506373..095f374 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ dnl Copyright (c) 2007-2015, The Tor Project, Inc.
 dnl See LICENSE for licensing information
 
 AC_PREREQ([2.63])
-AC_INIT([tor],[0.2.9.9])
+AC_INIT([tor],[0.2.9.10])
 AC_CONFIG_SRCDIR([src/or/main.c])
 AC_CONFIG_MACRO_DIR([m4])
 
@@ -677,6 +677,11 @@ AC_CHECK_FUNCS([ \
 dnl Check if OpenSSL has scrypt implementation.
 AC_CHECK_FUNCS([ EVP_PBE_scrypt ])
 
+dnl Check if OpenSSL structures are opaque
+AC_CHECK_MEMBERS([SSL.state], , ,
+[#include <openssl/ssl.h>
+])
+
 LIBS="$save_LIBS"
 LDFLAGS="$save_LDFLAGS"
 CPPFLAGS="$save_CPPFLAGS"
diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in
[cut]
diff --git a/debian/changelog b/debian/changelog
index 2d7c4b7..29cbbf0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,14 @@
+tor (0.2.9.10-1) unstable; urgency=medium
+
+  * New upstream version.
+    - Stop rejecting all IPv6 traffic on Exits whose exit policy rejects
+      any IPv6 addresses.
+    - Fix an integer underflow bug when comparing malformed Tor
+      versions. Underlying issue of TROVE-2017-001, mitigated in the
+      previous release.
+
+ -- Peter Palfrader <weasel@debian.org>  Sat, 04 Mar 2017 16:28:58 +0100
+
 tor (0.2.9.9-1) unstable; urgency=medium
 
   * New upstream version.
diff --git a/src/config/geoip b/src/config/geoip
[cut]
diff --git a/src/config/geoip6 b/src/config/geoip6
[cut]
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 34db063..fa3938b 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -365,6 +365,16 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
             strmap_size(fingerprint_list->fp_by_name),
             digestmap_size(fingerprint_list->status_by_digest));
 
+  if (platform) {
+    tor_version_t ver_tmp;
+    if (tor_version_parse_platform(platform, &ver_tmp, 1) < 0) {
+      if (msg) {
+        *msg = "Malformed platform string.";
+      }
+      return FP_REJECT;
+    }
+  }
+
   /* Versions before Tor 0.2.4.18-rc are too old to support, and are
    * missing some important security fixes too. Disable them. */
   if (platform && !tor_version_as_new_as(platform,"0.2.4.18-rc")) {
@@ -2233,13 +2243,17 @@ dirserv_set_routerstatus_testing(routerstatus_t *rs)
 /** Routerstatus <b>rs</b> is part of a group of routers that are on
  * too narrow an IP-space. Clear out its flags: we don't want people
  * using it.
+ *
+ * Leave its BadExit flag alone though, since if we think it's a bad exit,
+ * we want to vote that way in case all the other authorities are voting
+ * Running and Exit.
  */
 static void
 clear_status_flags_on_sybil(routerstatus_t *rs)
 {
   rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
     rs->is_flagged_running = rs->is_named = rs->is_valid =
-    rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit = 0;
+    rs->is_hs_dir = rs->is_v2_dir = rs->is_possible_guard = 0;
   /* FFFF we might want some mechanism to check later on if we
    * missed zeroing any flags: it's easy to add a new flag but
    * forget to add it to this clause. */
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 2c10e78..738ab35 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -421,16 +421,30 @@ compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
                        b->status.descriptor_digest,
                        DIGEST_LEN)))
     return r;
-  if ((r = (int)(b->status.published_on - a->status.published_on)))
-    return r;
+  /* If we actually reached this point, then the identities and
+   * the descriptor digests matched, so somebody is making SHA1 collisions.
+   */
+#define CMP_FIELD(utype, itype, field) do {                             \
+    utype aval = (utype) (itype) a->status.field;                       \
+    utype bval = (utype) (itype) b->status.field;                       \
+    utype u = bval - aval;                                              \
+    itype r2 = (itype) u;                                               \
+    if (r2 < 0) {                                                       \
+      return -1;                                                        \
+    } else if (r2 > 0) {                                                \
+      return 1;                                                         \
+    }                                                                   \
+  } while (0)
+
+  CMP_FIELD(uint64_t, int64_t, published_on);
+
   if ((r = strcmp(b->status.nickname, a->status.nickname)))
     return r;
-  if ((r = (((int)b->status.addr) - ((int)a->status.addr))))
-    return r;
-  if ((r = (((int)b->status.or_port) - ((int)a->status.or_port))))
-    return r;
-  if ((r = (((int)b->status.dir_port) - ((int)a->status.dir_port))))
-    return r;
+
+  CMP_FIELD(unsigned, int, addr);
+  CMP_FIELD(unsigned, int, or_port);
+  CMP_FIELD(unsigned, int, dir_port);
+
   return 0;
 }
 
diff --git a/src/or/policies.c b/src/or/policies.c
index 227e168..28770bb 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -1198,48 +1198,48 @@ policies_parse_from_options(const or_options_t *options)
   return ret;
 }
 
-/** Compare two provided address policy items, and return -1, 0, or 1
+/** Compare two provided address policy items, and renturn -1, 0, or 1
  * if the first is less than, equal to, or greater than the second. */
 static int
-cmp_single_addr_policy(addr_policy_t *a, addr_policy_t *b)
+single_addr_policy_eq(const addr_policy_t *a, const addr_policy_t *b)
 {
   int r;
-  if ((r=((int)a->policy_type - (int)b->policy_type)))
-    return r;
-  if ((r=((int)a->is_private - (int)b->is_private)))
-    return r;
+#define CMP_FIELD(field) do {                   \
+    if (a->field != b->field) {                 \
+      return 0;                                 \
+    }                                           \
+  } while (0)
+  CMP_FIELD(policy_type);
+  CMP_FIELD(is_private);
   /* refcnt and is_canonical are irrelevant to equality,
    * they are hash table implementation details */
   if ((r=tor_addr_compare(&a->addr, &b->addr, CMP_EXACT)))
-    return r;
-  if ((r=((int)a->maskbits - (int)b->maskbits)))
-    return r;
-  if ((r=((int)a->prt_min - (int)b->prt_min)))
-    return r;
-  if ((r=((int)a->prt_max - (int)b->prt_max)))
-    return r;
-  return 0;
+    return 0;
+  CMP_FIELD(maskbits);
+  CMP_FIELD(prt_min);
+  CMP_FIELD(prt_max);
+#undef CMP_FIELD
+  return 1;
 }
 
-/** Like cmp_single_addr_policy() above, but looks at the
- * whole set of policies in each case. */
+/** As single_addr_policy_eq, but compare every element of two policies.
+ */
 int
-cmp_addr_policies(smartlist_t *a, smartlist_t *b)
+addr_policies_eq(const smartlist_t *a, const smartlist_t *b)
 {
-  int r, i;
+  int i;
   int len_a = a ? smartlist_len(a) : 0;
   int len_b = b ? smartlist_len(b) : 0;
 
-  for (i = 0; i < len_a && i < len_b; ++i) {
-    if ((r = cmp_single_addr_policy(smartlist_get(a, i), smartlist_get(b, i))))
-      return r;
-  }
-  if (i == len_a && i == len_b)
+  if (len_a != len_b)
     return 0;
-  if (i < len_a)
-    return -1;
-  else
-    return 1;
+
+  for (i = 0; i < len_a; ++i) {
+    if (! single_addr_policy_eq(smartlist_get(a, i), smartlist_get(b, i)))
+      return 0;
+  }
+
+  return 1;
 }
 
 /** Node in hashtable used to store address policy entries. */
@@ -1255,7 +1255,7 @@ static HT_HEAD(policy_map, policy_map_ent_t) policy_root = HT_INITIALIZER();
 static inline int
 policy_eq(policy_map_ent_t *a, policy_map_ent_t *b)
 {
-  return cmp_single_addr_policy(a->policy, b->policy) == 0;
+  return single_addr_policy_eq(a->policy, b->policy);
 }
 
 /** Return a hashcode for <b>ent</b> */
@@ -1306,7 +1306,7 @@ addr_policy_get_canonical_entry(addr_policy_t *e)
     HT_INSERT(policy_map, &policy_root, found);
   }
 
-  tor_assert(!cmp_single_addr_policy(found->policy, e));
+  tor_assert(single_addr_policy_eq(found->policy, e));
   ++found->policy->refcnt;
   return found->policy;
 }
@@ -2299,7 +2299,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.
  */
@@ -2332,35 +2351,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) {
-    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);
@@ -2380,7 +2446,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) {
 
@@ -2401,7 +2467,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);
@@ -2435,7 +2502,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);
 
@@ -2624,8 +2690,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)
 {
diff --git a/src/or/policies.h b/src/or/policies.h
index 20f58f2..f73f850 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -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,
@@ -73,7 +76,7 @@ void policy_expand_unspec(smartlist_t **policy);
 int policies_parse_from_options(const or_options_t *options);
 
 addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent);
-int cmp_addr_policies(smartlist_t *a, smartlist_t *b);
+int addr_policies_eq(const smartlist_t *a, const smartlist_t *b);
 MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
     (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
 addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr,
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index b876795..2365f28 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -5445,7 +5445,7 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
       (r1->contact_info && r2->contact_info &&
        strcasecmp(r1->contact_info, r2->contact_info)) ||
       r1->is_hibernating != r2->is_hibernating ||
-      cmp_addr_policies(r1->exit_policy, r2->exit_policy) ||
+      ! addr_policies_eq(r1->exit_policy, r2->exit_policy) ||
       (r1->supports_tunnelled_dir_requests !=
        r2->supports_tunnelled_dir_requests))
     return 0;
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index d7e4252..2ee0d27 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -5512,40 +5512,78 @@ microdescs_parse_from_string(const char *s, const char *eos,
   return result;
 }
 
-/** Parse the Tor version of the platform string <b>platform</b>,
- * and compare it to the version in <b>cutoff</b>. Return 1 if
- * the router is at least as new as the cutoff, else return 0.
+/** Extract a Tor version from a <b>platform</b> line from a router
+ * descriptor, and place the result in <b>router_version</b>.
+ *
+ * Return 1 on success, -1 on parsing failure, and 0 if the
+ * platform line does not indicate some version of Tor.
+ *
+ * If <b>strict</b> is non-zero, finding any weird version components
+ * (like negative numbers) counts as a parsing failure.
  */
 int
-tor_version_as_new_as(const char *platform, const char *cutoff)
+tor_version_parse_platform(const char *platform,
+                           tor_version_t *router_version,
+                           int strict)
 {
-  tor_version_t cutoff_version, router_version;
-  char *s, *s2, *start;
   char tmp[128];
+  char *s, *s2, *start;
 
-  tor_assert(platform);
-
-  if (tor_version_parse(cutoff, &cutoff_version)<0) {
-    log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff);
+  if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; say 0. */
     return 0;
-  }
-  if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; be safe and say yes */
-    return 1;
 
   start = (char *)eat_whitespace(platform+3);
-  if (!*start) return 0;
+  if (!*start) return -1;
   s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
   s2 = (char*)eat_whitespace(s);
   if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-"))
     s = (char*)find_whitespace(s2);
 
   if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
-    return 0;
+    return -1;
   strlcpy(tmp, start, s-start+1);
 
-  if (tor_version_parse(tmp, &router_version)<0) {
+  if (tor_version_parse(tmp, router_version)<0) {
     log_info(LD_DIR,"Router version '%s' unparseable.",tmp);
-    return 1; /* be safe and say yes */
+    return -1;
+  }
+
+  if (strict) {
+    if (router_version->major < 0 ||
+        router_version->minor < 0 ||
+        router_version->micro < 0 ||
+        router_version->patchlevel < 0 ||
+        router_version->svn_revision < 0) {
+      return -1;
+    }
+  }
+
+  return 1;
+}
+
+/** Parse the Tor version of the platform string <b>platform</b>,
+ * and compare it to the version in <b>cutoff</b>. Return 1 if
+ * the router is at least as new as the cutoff, else return 0.
+ */
+int
+tor_version_as_new_as(const char *platform, const char *cutoff)
+{
+  tor_version_t cutoff_version, router_version;
+  int r;
+  tor_assert(platform);
+
+  if (tor_version_parse(cutoff, &cutoff_version)<0) {
+    log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff);
+    return 0;
+  }
+
+  r = tor_version_parse_platform(platform, &router_version, 0);
+  if (r == 0) {
+    /* nonstandard Tor; be safe and say yes */
+    return 1;
+  } else if (r < 0) {
+    /* unparseable version; be safe and say yes. */
+    return 1;
   }
 
   /* Here's why we don't need to do any special handling for svn revisions:
@@ -5567,6 +5605,7 @@ tor_version_parse(const char *s, tor_version_t *out)
 {
   char *eos=NULL;
   const char *cp=NULL;
+  int ok = 1;
   /* Format is:
    *   "Tor " ? NUM dot NUM [ dot NUM [ ( pre | rc | dot ) NUM ] ] [ - tag ]
    */
@@ -5582,7 +5621,9 @@ tor_version_parse(const char *s, tor_version_t *out)
 
 #define NUMBER(m)                               \
   do {                                          \
-    out->m = (int)strtol(cp, &eos, 10);         \
+    out->m = (int)tor_parse_uint64(cp, 10, 0, INT32_MAX, &ok, &eos);    \
+    if (!ok)                                    \
+      return -1;                                \
     if (!eos || eos == cp)                      \
       return -1;                                \
     cp = eos;                                   \
@@ -5672,26 +5713,37 @@ tor_version_compare(tor_version_t *a, tor_version_t *b)
   int i;
   tor_assert(a);
   tor_assert(b);
-  if ((i = a->major - b->major))
-    return i;
-  else if ((i = a->minor - b->minor))
-    return i;
-  else if ((i = a->micro - b->micro))
-    return i;
-  else if ((i = a->status - b->status))
-    return i;
-  else if ((i = a->patchlevel - b->patchlevel))
-    return i;
-  else if ((i = strcmp(a->status_tag, b->status_tag)))
-    return i;
-  else if ((i = a->svn_revision - b->svn_revision))
-    return i;
-  else if ((i = a->git_tag_len - b->git_tag_len))
-    return i;
-  else if (a->git_tag_len)
-    return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
+
+  /* We take this approach to comparison to ensure the same (bogus!) behavior
+   * on all inputs as we would have seen before bug #21278 was fixed. The
+   * only important difference here is that this method doesn't cause
+   * a signed integer underflow.
+   */
+#define CMP(field) do {                               \
+    unsigned aval = (unsigned) a->field;              \
+    unsigned bval = (unsigned) b->field;              \
+    int result = (int) (aval - bval);                 \
+    if (result < 0)                                   \
+      return -1;                                      \
+    else if (result > 0)                              \
+      return 1;                                       \
+  } while (0)
+
+  CMP(major);
+  CMP(minor);
+  CMP(micro);
+  CMP(status);
+  CMP(patchlevel);
+  if ((i = strcmp(a->status_tag, b->status_tag)))
+     return i;
+  CMP(svn_revision);
+  CMP(git_tag_len);
+  if (a->git_tag_len)
+     return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
   else
-    return 0;
+     return 0;
+
+#undef CMP
 }
 
 /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
diff --git a/src/or/routerparse.h b/src/or/routerparse.h
index 9a3fadc..01a5de8 100644
--- a/src/or/routerparse.h
+++ b/src/or/routerparse.h
@@ -45,6 +45,9 @@ MOCK_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
          (const char *s, int assume_action, int *malformed_list));
 version_status_t tor_version_is_obsolete(const char *myversion,
                                          const char *versionlist);
+int tor_version_parse_platform(const char *platform,
+                               tor_version_t *version_out,
+                               int strict);
 int tor_version_as_new_as(const char *platform, const char *cutoff);
 int tor_version_parse(const char *s, tor_version_t *out);
 int tor_version_compare(tor_version_t *a, tor_version_t *b);
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 22f473f..1ffdc2c 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -32,12 +32,14 @@ test_short_policy_parse(const char *input,
   short_policy_free(short_policy);
 }
 
-/** Helper: Parse the exit policy string in <b>policy_str</b>, and make sure
- * that policies_summarize() produces the string <b>expected_summary</b> from
- * it. */
+/** Helper: Parse the exit policy string in <b>policy_str</b> with
+ * <b>options</b>, and make sure that policies_summarize() produces the string
+ * <b>expected_summary</b> from it when called with family. */
 static void
-test_policy_summary_helper(const char *policy_str,
-                           const char *expected_summary)
+test_policy_summary_helper_family_flags(const char *policy_str,
+                                        const char *expected_summary,
+                                        sa_family_t family,
+                                        exit_policy_parser_cfg_t options)
 {
   config_line_t line;
   smartlist_t *policy = smartlist_new();
@@ -45,17 +47,17 @@ test_policy_summary_helper(const char *policy_str,
   char *summary_after = NULL;
   int r;
   short_policy_t *short_policy = NULL;
+  int success = 0;
 
   line.key = (char*)"foo";
   line.value = (char *)policy_str;
   line.next = NULL;
 
   r = policies_parse_exit_policy(&line, &policy,
-                                 EXIT_POLICY_IPV6_ENABLED |
-                                 EXIT_POLICY_ADD_DEFAULT, NULL);
+                                 options, NULL);
   tt_int_op(r,OP_EQ, 0);
 
-  summary = policy_summarize(policy, AF_INET);
+  summary = policy_summarize(policy, family);
 
   tt_assert(summary != NULL);
   tt_str_op(summary,OP_EQ, expected_summary);
@@ -65,7 +67,12 @@ test_policy_summary_helper(const char *policy_str,
   summary_after = write_short_policy(short_policy);
   tt_str_op(summary,OP_EQ, summary_after);
 
+  success = 1;
  done:
+  /* If we don't print the flags on failure, it's very hard to diagnose bugs */
+  if (!success)
+    TT_DECLARE("CTXT", ("\n     IPv%d\n     Options: %x\n     Policy: %s",
+                        family == AF_INET ? 4 : 6, options, policy_str));
   tor_free(summary_after);
   tor_free(summary);
   if (policy)
@@ -73,6 +80,50 @@ test_policy_summary_helper(const char *policy_str,
   short_policy_free(short_policy);
 }
 
+/** Like test_policy_summary_helper_family_flags, but tries all the different
+ * flag combinations */
+static void
+test_policy_summary_helper_family(const char *policy_str,
+                                  const char *expected_summary,
+                                  sa_family_t family)
+{
+  for (exit_policy_parser_cfg_t opt = 0;
+       opt <= EXIT_POLICY_OPTION_ALL;
+       opt++) {
+    if (family == AF_INET6 && !(opt & EXIT_POLICY_IPV6_ENABLED))
+      /* Skip the test: IPv6 addresses need IPv6 enabled */
+      continue;
+
+    if (opt & EXIT_POLICY_REJECT_LOCAL_INTERFACES)
+      /* Skip the test: local interfaces are machine-specific */
+      continue;
+
+    test_policy_summary_helper_family_flags(policy_str, expected_summary,
+                                            family, opt);
+  }
+}
+
+/** Like test_policy_summary_helper_family, but uses expected_summary for
+ * both IPv4 and IPv6. */
+static void
+test_policy_summary_helper(const char *policy_str,
+                           const char *expected_summary)
+{
+  test_policy_summary_helper_family(policy_str, expected_summary, AF_INET);
+  test_policy_summary_helper_family(policy_str, expected_summary, AF_INET6);
+}
+
+/** Like test_policy_summary_helper_family, but uses expected_summary4 for
+ * IPv4 and expected_summary6 for IPv6. */
+static void
+test_policy_summary_helper6(const char *policy_str,
+                            const char *expected_summary4,
+                            const char *expected_summary6)
+{
+  test_policy_summary_helper_family(policy_str, expected_summary4, AF_INET);
+  test_policy_summary_helper_family(policy_str, expected_summary6, AF_INET6);
+}
+
 /** Run unit tests for generating summary lines of exit policies */
 static void
 test_policies_general(void *arg)
@@ -253,10 +304,10 @@ test_policies_general(void *arg)
   tt_assert(!exit_policy_is_general_exit(policy10));
   tt_assert(!exit_policy_is_general_exit(policy11));
 
-  tt_assert(cmp_addr_policies(policy, policy2));
-  tt_assert(cmp_addr_policies(policy, NULL));
-  tt_assert(!cmp_addr_policies(policy2, policy2));
-  tt_assert(!cmp_addr_policies(NULL, NULL));
+  tt_assert(!addr_policies_eq(policy, policy2));
+  tt_assert(!addr_policies_eq(policy, NULL));
+  tt_assert(addr_policies_eq(policy2, policy2));
+  tt_assert(addr_policies_eq(NULL, NULL));
 
   tt_assert(!policy_is_reject_star(policy2, AF_INET, 1));
   tt_assert(policy_is_reject_star(policy, AF_INET, 1));
@@ -394,13 +445,14 @@ test_policies_general(void *arg)
                              "reject 14.0.0.0/9:80,"
                              "reject 15.0.0.0:81,"
                              "accept *:*", "accept 1-65535");
-  test_policy_summary_helper("reject 11.0.0.0/9:80,"
-                             "reject 12.0.0.0/9:80,"
-                             "reject 13.0.0.0/9:80,"
-                             "reject 14.0.0.0/9:80,"
-                             "reject 15.0.0.0:80,"
-                             "accept *:*",
-                             "reject 80");
+  test_policy_summary_helper6("reject 11.0.0.0/9:80,"
+                              "reject 12.0.0.0/9:80,"
+                              "reject 13.0.0.0/9:80,"
+                              "reject 14.0.0.0/9:80,"
+                              "reject 15.0.0.0:80,"
+                              "accept *:*",
+                              "reject 80",
+                              "accept 1-65535");
   /* no exits */
   test_policy_summary_helper("accept 11.0.0.0/9:80,"
                              "reject *:*",
@@ -431,6 +483,458 @@ test_policies_general(void *arg)
                              "reject *:7,"
                              "accept *:*",
                              "reject 1,3,5,7");
+  /* long policies */
+  /* standard long policy on many exits */
+  test_policy_summary_helper("accept *:20-23,"
+                             "accept *:43,"
+                             "accept *:53,"
+                             "accept *:79-81,"
+                             "accept *:88,"
+                             "accept *:110,"
+                             "accept *:143,"
+                             "accept *:194,"
+                             "accept *:220,"
+                             "accept *:389,"
+                             "accept *:443,"
+                             "accept *:464,"
+                             "accept *:531,"
+                             "accept *:543-544,"
+                             "accept *:554,"
+                             "accept *:563,"
+                             "accept *:636,"
+                             "accept *:706,"
+                             "accept *:749,"
+                             "accept *:873,"
+                             "accept *:902-904,"
+                             "accept *:981,"
+                             "accept *:989-995,"
+                             "accept *:1194,"
+                             "accept *:1220,"
+                             "accept *:1293,"
+                             "accept *:1500,"
+                             "accept *:1533,"
+                             "accept *:1677,"
+                             "accept *:1723,"
+                             "accept *:1755,"
+                             "accept *:1863,"
+                             "accept *:2082,"
+                             "accept *:2083,"
+                             "accept *:2086-2087,"
+                             "accept *:2095-2096,"
+                             "accept *:2102-2104,"
+                             "accept *:3128,"
+                             "accept *:3389,"
+                             "accept *:3690,"
+                             "accept *:4321,"
+                             "accept *:4643,"
+                             "accept *:5050,"
+                             "accept *:5190,"
+                             "accept *:5222-5223,"
+                             "accept *:5228,"
+                             "accept *:5900,"
+                             "accept *:6660-6669,"
+                             "accept *:6679,"
+                             "accept *:6697,"
+                             "accept *:8000,"
+                             "accept *:8008,"
+                             "accept *:8074,"
+                             "accept *:8080,"
+                             "accept *:8087-8088,"
+                             "accept *:8332-8333,"
+                             "accept *:8443,"
+                             "accept *:8888,"
+                             "accept *:9418,"
+                             "accept *:9999,"
+                             "accept *:10000,"
+                             "accept *:11371,"
+                             "accept *:12350,"
+                             "accept *:19294,"
+                             "accept *:19638,"
+                             "accept *:23456,"
+                             "accept *:33033,"
+                             "accept *:64738,"
+                             "reject *:*",
+                             "accept 20-23,43,53,79-81,88,110,143,194,220,389,"
+                             "443,464,531,543-544,554,563,636,706,749,873,"
+                             "902-904,981,989-995,1194,1220,1293,1500,1533,"
+                             "1677,1723,1755,1863,2082-2083,2086-2087,"
+                             "2095-2096,2102-2104,3128,3389,3690,4321,4643,"
+                             "5050,5190,5222-5223,5228,5900,6660-6669,6679,"
+                             "6697,8000,8008,8074,8080,8087-8088,8332-8333,"
+                             "8443,8888,9418,9999-10000,11371,12350,19294,"
+                             "19638,23456,33033,64738");
+  /* short policy with configured addresses */
+  test_policy_summary_helper("reject 149.56.1.1:*,"
+                             "reject [2607:5300:1:1::1:0]:*,"
+                             "accept *:80,"
+                             "accept *:443,"
+                             "reject *:*",
+                             "accept 80,443");
+  /* short policy with configured and local interface addresses */
+  test_policy_summary_helper("reject 149.56.1.0:*,"
+                             "reject 149.56.1.1:*,"
+                             "reject 149.56.1.2:*,"
+                             "reject 149.56.1.3:*,"
+                             "reject 149.56.1.4:*,"
+                             "reject 149.56.1.5:*,"
+                             "reject 149.56.1.6:*,"
+                             "reject 149.56.1.7:*,"
+                             "reject [2607:5300:1:1::1:0]:*,"
+                             "reject [2607:5300:1:1::1:1]:*,"
+                             "reject [2607:5300:1:1::1:2]:*,"
+                             "reject [2607:5300:1:1::1:3]:*,"
+                             "reject [2607:5300:1:1::2:0]:*,"
+                             "reject [2607:5300:1:1::2:1]:*,"
+                             "reject [2607:5300:1:1::2:2]:*,"
+                             "reject [2607:5300:1:1::2:3]:*,"
+                             "accept *:80,"
+                             "accept *:443,"
+                             "reject *:*",
+                             "accept 80,443");
+  /* short policy with configured netblocks */
+  test_policy_summary_helper("reject 149.56.0.0/16,"
+                             "reject6 2607:5300::/32,"
+                             "reject6 2608:5300::/64,"
+                             "reject6 2609:5300::/96,"
+                             "accept *:80,"
+                             "accept *:443,"
+                             "reject *:*",
+                             "accept 80,443");
+  /* short policy with large netblocks that do not count as a rejection */
+  test_policy_summary_helper("reject 148.0.0.0/7,"
+                             "reject6 2600::/16,"
+                             "accept *:80,"
+                             "accept *:443,"
+                             "reject *:*",
+                             "accept 80,443");
+  /* short policy with large netblocks that count as a rejection */
+  test_policy_summary_helper("reject 148.0.0.0/6,"
+                             "reject6 2600::/15,"
+                             "accept *:80,"
+                             "accept *:443,"
+                             "reject *:*",
+                             "reject 1-65535");
+  /* short policy with huge netblocks that count as a rejection */
+  test_policy_summary_helper("reject 128.0.0.0/1,"
+                             "reject6 8000::/1,"
+                             "accept *:80,"
+                             "accept *:443,"
+                             "reject *:*",
+                             "reject 1-65535");
+  /* short policy which blocks everything using netblocks */
+  test_policy_summary_helper("reject 0.0.0.0/0,"
+                             "reject6 ::/0,"
+                             "accept *:80,"
+                             "accept *:443,"
+                             "reject *:*",
+                             "reject 1-65535");
+  /* short policy which has repeated redundant netblocks */
+  test_policy_summary_helper("reject 0.0.0.0/0,"
+                             "reject 0.0.0.0/0,"
+                             "reject 0.0.0.0/0,"
+                             "reject 0.0.0.0/0,"
+                             "reject 0.0.0.0/0,"
+                             "reject6 ::/0,"
+                             "reject6 ::/0,"
+                             "reject6 ::/0,"
+                             "reject6 ::/0,"
+                             "reject6 ::/0,"
+                             "accept *:80,"
+                             "accept *:443,"
+                             "reject *:*",
+                             "reject 1-65535");
+
+  /* longest possible policy
+   * (1-2,4-5,... is longer, but gets reduced to 3,6,... )
+   * Going all the way to 65535 is incredibly slow, so we just go slightly
+   * more than the expected length */
+  test_policy_summary_helper("accept *:1,"
+                             "accept *:3,"
+                             "accept *:5,"
+                             "accept *:7,"
+                             "accept *:9,"
+                             "accept *:11,"
+                             "accept *:13,"
+                             "accept *:15,"
+                             "accept *:17,"
+                             "accept *:19,"
+                             "accept *:21,"
+                             "accept *:23,"
+                             "accept *:25,"
+                             "accept *:27,"
+                             "accept *:29,"
+                             "accept *:31,"
+                             "accept *:33,"
+                             "accept *:35,"
+                             "accept *:37,"
+                             "accept *:39,"
+                             "accept *:41,"
+                             "accept *:43,"
+                             "accept *:45,"
+                             "accept *:47,"
+                             "accept *:49,"
+                             "accept *:51,"
+                             "accept *:53,"
+                             "accept *:55,"
+                             "accept *:57,"
+                             "accept *:59,"
+                             "accept *:61,"
+                             "accept *:63,"
+                             "accept *:65,"
+                             "accept *:67,"
+                             "accept *:69,"
+                             "accept *:71,"
+                             "accept *:73,"
+                             "accept *:75,"
+                             "accept *:77,"
+                             "accept *:79,"
+                             "accept *:81,"
+                             "accept *:83,"
+                             "accept *:85,"
+                             "accept *:87,"
+                             "accept *:89,"
+                             "accept *:91,"
+                             "accept *:93,"
+                             "accept *:95,"
+                             "accept *:97,"
+                             "accept *:99,"
+                             "accept *:101,"
+                             "accept *:103,"
+                             "accept *:105,"
+                             "accept *:107,"
+                             "accept *:109,"
+                             "accept *:111,"
+                             "accept *:113,"
+                             "accept *:115,"
+                             "accept *:117,"
+                             "accept *:119,"
+                             "accept *:121,"
+                             "accept *:123,"
+                             "accept *:125,"
+                             "accept *:127,"
+                             "accept *:129,"
+                             "accept *:131,"
+                             "accept *:133,"
+                             "accept *:135,"
+                             "accept *:137,"
+                             "accept *:139,"
+                             "accept *:141,"
+                             "accept *:143,"
+                             "accept *:145,"
+                             "accept *:147,"
+                             "accept *:149,"
+                             "accept *:151,"
+                             "accept *:153,"
+                             "accept *:155,"
+                             "accept *:157,"
+                             "accept *:159,"
+                             "accept *:161,"
+                             "accept *:163,"
+                             "accept *:165,"
+                             "accept *:167,"
+                             "accept *:169,"
+                             "accept *:171,"
+                             "accept *:173,"
+                             "accept *:175,"
+                             "accept *:177,"
+                             "accept *:179,"
+                             "accept *:181,"
+                             "accept *:183,"
+                             "accept *:185,"
+                             "accept *:187,"
+                             "accept *:189,"
+                             "accept *:191,"
+                             "accept *:193,"
+                             "accept *:195,"
+                             "accept *:197,"
+                             "accept *:199,"
+                             "accept *:201,"
+                             "accept *:203,"
+                             "accept *:205,"
+                             "accept *:207,"
+                             "accept *:209,"
+                             "accept *:211,"
+                             "accept *:213,"
+                             "accept *:215,"
+                             "accept *:217,"
+                             "accept *:219,"
+                             "accept *:221,"
+                             "accept *:223,"
+                             "accept *:225,"
+                             "accept *:227,"
+                             "accept *:229,"
+                             "accept *:231,"
+                             "accept *:233,"
+                             "accept *:235,"
+                             "accept *:237,"
+                             "accept *:239,"
+                             "accept *:241,"
+                             "accept *:243,"
+                             "accept *:245,"
+                             "accept *:247,"
+                             "accept *:249,"
+                             "accept *:251,"
+                             "accept *:253,"
+                             "accept *:255,"
+                             "accept *:257,"
+                             "accept *:259,"
+                             "accept *:261,"
+                             "accept *:263,"
+                             "accept *:265,"
+                             "accept *:267,"
+                             "accept *:269,"
+                             "accept *:271,"
+                             "accept *:273,"
+                             "accept *:275,"
+                             "accept *:277,"
+                             "accept *:279,"
+                             "accept *:281,"
+                             "accept *:283,"
+                             "accept *:285,"
+                             "accept *:287,"
+                             "accept *:289,"
+                             "accept *:291,"
+                             "accept *:293,"
+                             "accept *:295,"
+                             "accept *:297,"
+                             "accept *:299,"
+                             "accept *:301,"
+                             "accept *:303,"
+                             "accept *:305,"
+                             "accept *:307,"
+                             "accept *:309,"
+                             "accept *:311,"
+                             "accept *:313,"
+                             "accept *:315,"
+                             "accept *:317,"
+                             "accept *:319,"
+                             "accept *:321,"
+                             "accept *:323,"
+                             "accept *:325,"
+                             "accept *:327,"
+                             "accept *:329,"
+                             "accept *:331,"
+                             "accept *:333,"
+                             "accept *:335,"
+                             "accept *:337,"
+                             "accept *:339,"
+                             "accept *:341,"
+                             "accept *:343,"
+                             "accept *:345,"
+                             "accept *:347,"
+                             "accept *:349,"
+                             "accept *:351,"
+                             "accept *:353,"
+                             "accept *:355,"
+                             "accept *:357,"
+                             "accept *:359,"
+                             "accept *:361,"
+                             "accept *:363,"
+                             "accept *:365,"
+                             "accept *:367,"
+                             "accept *:369,"
+                             "accept *:371,"
+                             "accept *:373,"
+                             "accept *:375,"
+                             "accept *:377,"
+                             "accept *:379,"
+                             "accept *:381,"
+                             "accept *:383,"
+                             "accept *:385,"
+                             "accept *:387,"
+                             "accept *:389,"
+                             "accept *:391,"
+                             "accept *:393,"
+                             "accept *:395,"
+                             "accept *:397,"
+                             "accept *:399,"
+                             "accept *:401,"
+                             "accept *:403,"
+                             "accept *:405,"
+                             "accept *:407,"
+                             "accept *:409,"
+                             "accept *:411,"
+                             "accept *:413,"
+                             "accept *:415,"
+                             "accept *:417,"
+                             "accept *:419,"
+                             "accept *:421,"
+                             "accept *:423,"
+                             "accept *:425,"
+                             "accept *:427,"
+                             "accept *:429,"
+                             "accept *:431,"
+                             "accept *:433,"
+                             "accept *:435,"
+                             "accept *:437,"
+                             "accept *:439,"
+                             "accept *:441,"
+                             "accept *:443,"
+                             "accept *:445,"
+                             "accept *:447,"
+                             "accept *:449,"
+                             "accept *:451,"
+                             "accept *:453,"
+                             "accept *:455,"
+                             "accept *:457,"
+                             "accept *:459,"
+                             "accept *:461,"
+                             "accept *:463,"
+                             "accept *:465,"
+                             "accept *:467,"
+                             "accept *:469,"
+                             "accept *:471,"
+                             "accept *:473,"
+                             "accept *:475,"
+                             "accept *:477,"
+                             "accept *:479,"
+                             "accept *:481,"
+                             "accept *:483,"
+                             "accept *:485,"
+                             "accept *:487,"
+                             "accept *:489,"
+                             "accept *:491,"
+                             "accept *:493,"
+                             "accept *:495,"
+                             "accept *:497,"
+                             "accept *:499,"
+                             "accept *:501,"
+                             "accept *:503,"
+                             "accept *:505,"
+                             "accept *:507,"
+                             "accept *:509,"
+                             "accept *:511,"
+                             "accept *:513,"
+                             "accept *:515,"
+                             "accept *:517,"
+                             "accept *:519,"
+                             "accept *:521,"
+                             "accept *:523,"
+                             "accept *:525,"
+                             "accept *:527,"
+                             "accept *:529,"
+                             "reject *:*",
+                             "accept 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,"
+                             "31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,"
+                             "63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,"
+                             "95,97,99,101,103,105,107,109,111,113,115,117,"
+                             "119,121,123,125,127,129,131,133,135,137,139,141,"
+                             "143,145,147,149,151,153,155,157,159,161,163,165,"
+                             "167,169,171,173,175,177,179,181,183,185,187,189,"
+                             "191,193,195,197,199,201,203,205,207,209,211,213,"
+                             "215,217,219,221,223,225,227,229,231,233,235,237,"
+                             "239,241,243,245,247,249,251,253,255,257,259,261,"
+                             "263,265,267,269,271,273,275,277,279,281,283,285,"
+                             "287,289,291,293,295,297,299,301,303,305,307,309,"
+                             "311,313,315,317,319,321,323,325,327,329,331,333,"
+                             "335,337,339,341,343,345,347,349,351,353,355,357,"
+                             "359,361,363,365,367,369,371,373,375,377,379,381,"
+                             "383,385,387,389,391,393,395,397,399,401,403,405,"
+                             "407,409,411,413,415,417,419,421,423,425,427,429,"
+                             "431,433,435,437,439,441,443,445,447,449,451,453,"
+                             "455,457,459,461,463,465,467,469,471,473,475,477,"
+                             "479,481,483,485,487,489,491,493,495,497,499,501,"
+                             "503,505,507,509,511,513,515,517,519,521,523");
 
   /* Short policies with unrecognized formats should get accepted. */
   test_short_policy_parse("accept fred,2,3-5", "accept 2,3-5");
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index 1cba617..47455cf 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -38,9 +38,11 @@ ENABLE_GCC_WARNING(redundant-decls)
 #include "log_test_helpers.h"
 #define NS_MODULE tortls
 
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) \
-    && !defined(LIBRESSL_VERSION_NUMBER)
+#ifndef HAVE_SSL_STATE
 #define OPENSSL_OPAQUE
+#endif
+
+#if defined(OPENSSL_OPAQUE) && !defined(LIBRESSL_VERSION_NUMBER)
 #define SSL_STATE_STR "before SSL initialization"
 #else
 #define SSL_STATE_STR "before/accept initialization"
@@ -723,6 +725,26 @@ test_tortls_get_my_certs(void *ignored)
   (void)1;
 }
 
+#ifndef HAVE_SSL_GET_CLIENT_CIPHERS
+static SSL_CIPHER *
+get_cipher_by_name(const char *name)
+{
+  int i;
+  const SSL_METHOD *method = SSLv23_method();
+  int num = method->num_ciphers();
+
+  for (i = 0; i < num; ++i) {
+    const SSL_CIPHER *cipher = method->get_cipher(i);
+    const char *ciphername = SSL_CIPHER_get_name(cipher);
+    if (!strcmp(ciphername, name)) {
+      return (SSL_CIPHER *)cipher;
+    }
+  }
+
+  return NULL;
+}
+#endif
+
 #ifndef OPENSSL_OPAQUE
 static void
 test_tortls_get_ciphersuite_name(void *ignored)
@@ -742,23 +764,6 @@ test_tortls_get_ciphersuite_name(void *ignored)
 }
 
 static SSL_CIPHER *
-get_cipher_by_name(const char *name)
-{
-  int i;
-  const SSL_METHOD *method = SSLv23_method();
-  int num = method->num_ciphers();
-  for (i = 0; i < num; ++i) {
-    const SSL_CIPHER *cipher = method->get_cipher(i);
-    const char *ciphername = SSL_CIPHER_get_name(cipher);
-    if (!strcmp(ciphername, name)) {
-      return (SSL_CIPHER *)cipher;
-    }
-  }
-
-  return NULL;
-}
-
-static SSL_CIPHER *
 get_cipher_by_id(uint16_t id)
 {
   int i;
diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c
index 29f85c4..6ac866d 100644
--- a/src/tools/tor-resolve.c
+++ b/src/tools/tor-resolve.c
@@ -80,6 +80,10 @@ build_socks_resolve_request(char **out,
     }
     ipv6 = reverse && tor_addr_family(&addr) == AF_INET6;
     addrlen = reverse ? (ipv6 ? 16 : 4) : 1 + strlen(hostname);
+    if (addrlen > UINT8_MAX) {
+      log_err(LD_GENERAL, "Hostname is too long!");
+      return -1;
+    }
     len = 6 + addrlen;
     *out = tor_malloc(len);
     (*out)[0] = 5; /* SOCKS version 5 */
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index 17e1e54..540cfab 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -218,7 +218,7 @@
 #define USING_TWOS_COMPLEMENT
 
 /* Version number of package */
-#define VERSION "0.2.9.9"
+#define VERSION "0.2.9.10"
 
 
 

--- End Message ---
--- Begin Message ---
Unblocked tor.

--- End Message ---

Reply to: