aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/common/Makefile.am67
-rw-r--r--src/common/address.c138
-rw-r--r--src/common/address.h21
-rw-r--r--src/common/aes.c38
-rw-r--r--src/common/aes.h4
-rw-r--r--src/common/compat.c7
-rw-r--r--src/common/compat.h23
-rw-r--r--src/common/compat_libevent.c2
-rw-r--r--src/common/compat_libevent.h4
-rw-r--r--src/common/container.c141
-rw-r--r--src/common/container.h4
-rw-r--r--src/common/crypto.c236
-rw-r--r--src/common/crypto.h16
-rw-r--r--src/common/di_ops.c2
-rw-r--r--src/common/include.am71
-rw-r--r--src/common/log.c84
-rw-r--r--src/common/memarea.c4
-rw-r--r--src/common/memarea.h4
-rw-r--r--src/common/mempool.c14
-rw-r--r--src/common/mempool.h4
-rw-r--r--src/common/procmon.c37
-rw-r--r--src/common/sha256.c331
-rw-r--r--src/common/torgzip.h4
-rw-r--r--src/common/torint.h4
-rw-r--r--src/common/torlog.h64
-rw-r--r--src/common/tortls.c64
-rw-r--r--src/common/tortls.h10
-rw-r--r--src/common/util.c655
-rw-r--r--src/common/util.h65
-rw-r--r--src/config/Makefile.am16
-rw-r--r--src/config/README.geoip90
-rwxr-xr-xsrc/config/deanonymind.py194
-rw-r--r--src/config/geoip-manual114
-rw-r--r--src/config/geoip611638
-rw-r--r--src/config/include.am16
-rw-r--r--src/config/torrc.sample.in4
-rw-r--r--src/ext/OpenBSD_malloc_Linux.c (renamed from src/common/OpenBSD_malloc_Linux.c)0
-rw-r--r--src/ext/README39
-rw-r--r--src/ext/eventdns.c (renamed from src/or/eventdns.c)2
-rw-r--r--src/ext/eventdns.h (renamed from src/or/eventdns.h)4
-rw-r--r--src/ext/ht.h (renamed from src/common/ht.h)4
-rw-r--r--src/ext/include.am17
-rw-r--r--src/ext/strlcat.c (renamed from src/common/strlcat.c)0
-rw-r--r--src/ext/strlcpy.c (renamed from src/common/strlcpy.c)0
-rw-r--r--src/ext/tinytest.c (renamed from src/test/tinytest.c)0
-rw-r--r--src/ext/tinytest.h (renamed from src/test/tinytest.h)0
-rw-r--r--src/ext/tinytest_demo.c (renamed from src/test/tinytest_demo.c)0
-rw-r--r--src/ext/tinytest_macros.h (renamed from src/test/tinytest_macros.h)0
-rw-r--r--src/ext/tor_queue.h573
-rw-r--r--src/ext/tor_queue.txt883
-rw-r--r--src/include.am7
-rw-r--r--src/or/Makefile.am158
-rw-r--r--src/or/Makefile.nmake14
-rw-r--r--src/or/addressmap.c974
-rw-r--r--src/or/addressmap.h44
-rw-r--r--src/or/buffers.c5
-rw-r--r--src/or/buffers.h4
-rw-r--r--src/or/channel.c4094
-rw-r--r--src/or/channel.h478
-rw-r--r--src/or/channeltls.c1932
-rw-r--r--src/or/channeltls.h57
-rw-r--r--src/or/circuitbuild.c4108
-rw-r--r--src/or/circuitbuild.h132
-rw-r--r--src/or/circuitlist.c575
-rw-r--r--src/or/circuitlist.h38
-rw-r--r--src/or/circuitmux.c1745
-rw-r--r--src/or/circuitmux.h136
-rw-r--r--src/or/circuitmux_ewma.c684
-rw-r--r--src/or/circuitmux_ewma.h29
-rw-r--r--src/or/circuitstats.c1569
-rw-r--r--src/or/circuitstats.h65
-rw-r--r--src/or/circuituse.c226
-rw-r--r--src/or/circuituse.h4
-rw-r--r--src/or/command.c1064
-rw-r--r--src/or/command.h12
-rw-r--r--src/or/config.c2686
-rw-r--r--src/or/config.h18
-rw-r--r--src/or/confparse.c1226
-rw-r--r--src/or/confparse.h132
-rw-r--r--src/or/connection.c378
-rw-r--r--src/or/connection.h62
-rw-r--r--src/or/connection_edge.c1494
-rw-r--r--src/or/connection_edge.h77
-rw-r--r--src/or/connection_or.c757
-rw-r--r--src/or/connection_or.h18
-rw-r--r--src/or/control.c149
-rw-r--r--src/or/control.h4
-rw-r--r--src/or/cpuworker.c39
-rw-r--r--src/or/cpuworker.h4
-rw-r--r--src/or/directory.c447
-rw-r--r--src/or/directory.h27
-rw-r--r--src/or/dirserv.c246
-rw-r--r--src/or/dirserv.h8
-rw-r--r--src/or/dirvote.c175
-rw-r--r--src/or/dirvote.h41
-rw-r--r--src/or/dns.c1005
-rw-r--r--src/or/dns.h5
-rw-r--r--src/or/dnsserv.c14
-rw-r--r--src/or/dnsserv.h4
-rw-r--r--src/or/entrynodes.c1948
-rw-r--r--src/or/entrynodes.h102
-rw-r--r--src/or/eventdns_tor.h5
-rw-r--r--src/or/geoip.c507
-rw-r--r--src/or/geoip.h18
-rw-r--r--src/or/hibernate.c15
-rw-r--r--src/or/hibernate.h4
-rw-r--r--src/or/include.am180
-rw-r--r--src/or/main.c89
-rw-r--r--src/or/main.h4
-rw-r--r--src/or/microdesc.c26
-rw-r--r--src/or/microdesc.h4
-rw-r--r--src/or/networkstatus.c111
-rw-r--r--src/or/networkstatus.h6
-rw-r--r--src/or/nodelist.c700
-rw-r--r--src/or/nodelist.h37
-rw-r--r--src/or/ntmain.h4
-rw-r--r--src/or/onion.c2
-rw-r--r--src/or/onion.h4
-rw-r--r--src/or/or.h610
-rw-r--r--src/or/policies.c196
-rw-r--r--src/or/policies.h10
-rw-r--r--src/or/reasons.c24
-rw-r--r--src/or/reasons.h4
-rw-r--r--src/or/relay.c923
-rw-r--r--src/or/relay.h29
-rw-r--r--src/or/rendclient.c86
-rw-r--r--src/or/rendclient.h4
-rw-r--r--src/or/rendcommon.c10
-rw-r--r--src/or/rendcommon.h4
-rw-r--r--src/or/rendmid.c8
-rw-r--r--src/or/rendmid.h4
-rw-r--r--src/or/rendservice.c1813
-rw-r--r--src/or/rendservice.h79
-rw-r--r--src/or/rephist.c24
-rw-r--r--src/or/rephist.h4
-rw-r--r--src/or/replaycache.c215
-rw-r--r--src/or/replaycache.h66
-rw-r--r--src/or/router.c228
-rw-r--r--src/or/router.h11
-rw-r--r--src/or/routerlist.c1805
-rw-r--r--src/or/routerlist.h97
-rw-r--r--src/or/routerparse.c423
-rw-r--r--src/or/routerparse.h6
-rw-r--r--src/or/routerset.c427
-rw-r--r--src/or/routerset.h48
-rw-r--r--src/or/statefile.c615
-rw-r--r--src/or/statefile.h22
-rw-r--r--src/or/status.c2
-rw-r--r--src/or/status.h4
-rw-r--r--src/or/transports.c513
-rw-r--r--src/or/transports.h51
-rw-r--r--src/test/Makefile.am49
-rw-r--r--src/test/bench.c4
-rw-r--r--src/test/include.am53
-rw-r--r--src/test/test.c144
-rw-r--r--src/test/test.h8
-rw-r--r--src/test/test_addr.c187
-rw-r--r--src/test/test_cell_formats.c386
-rw-r--r--src/test/test_config.c2
-rw-r--r--src/test/test_containers.c42
-rw-r--r--src/test/test_crypto.c11
-rw-r--r--src/test/test_dir.c155
-rw-r--r--src/test/test_introduce.c528
-rw-r--r--src/test/test_replay.c184
-rw-r--r--src/test/test_util.c283
-rw-r--r--src/tools/Makefile.am22
-rw-r--r--src/tools/include.am22
-rw-r--r--src/tools/tor-checkkey.c2
-rw-r--r--src/tools/tor-fw-helper/Makefile.am38
-rw-r--r--src/tools/tor-fw-helper/include.am36
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-natpmp.c58
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-natpmp.h8
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-upnp.c44
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-upnp.h7
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper.c367
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper.h24
-rw-r--r--src/tools/tor-gencert.c6
-rw-r--r--src/tools/tor-resolve.c44
-rw-r--r--src/win32/Makefile.am3
-rw-r--r--src/win32/include.am3
-rw-r--r--src/win32/orconfig.h8
182 files changed, 42702 insertions, 15044 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index fa2dd560a6..0000000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-
-# leave in dependency order, since common must be built first
-SUBDIRS = common or test tools win32 config
-DIST_SUBDIRS = common or test tools win32 config
-
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
deleted file mode 100644
index 5e7684259a..0000000000
--- a/src/common/Makefile.am
+++ /dev/null
@@ -1,67 +0,0 @@
-
-noinst_LIBRARIES = libor.a libor-crypto.a libor-event.a
-
-EXTRA_DIST = common_sha1.i sha256.c Makefile.nmake
-
-#CFLAGS = -Wall -Wpointer-arith -O2
-
-if USE_OPENBSD_MALLOC
-libor_extra_source=OpenBSD_malloc_Linux.c
-else
-libor_extra_source=
-endif
-
-libor_a_SOURCES = \
- address.c \
- compat.c \
- container.c \
- di_ops.c \
- log.c \
- memarea.c \
- mempool.c \
- procmon.c \
- util.c \
- util_codedigest.c \
- $(libor_extra_source)
-
-libor_crypto_a_SOURCES = \
- aes.c \
- crypto.c \
- torgzip.c \
- tortls.c
-
-libor_event_a_SOURCES = compat_libevent.c
-
-noinst_HEADERS = \
- address.h \
- aes.h \
- ciphers.inc \
- compat.h \
- compat_libevent.h \
- container.h \
- crypto.h \
- di_ops.h \
- ht.h \
- memarea.h \
- mempool.h \
- procmon.h \
- strlcat.c \
- strlcpy.c \
- torgzip.h \
- torint.h \
- torlog.h \
- tortls.h \
- util.h
-
-common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)
- if test "@SHA1SUM@" != none; then \
- (cd "$(srcdir)" && "@SHA1SUM@" $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > common_sha1.i; \
- elif test "@OPENSSL@" != none; then \
- (cd "$(srcdir)" && "@OPENSSL@" sha1 $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > common_sha1.i; \
- else \
- rm common_sha1.i; \
- touch common_sha1.i; \
- fi
-
-util_codedigest.o: common_sha1.i
-crypto.o: sha256.c
diff --git a/src/common/address.c b/src/common/address.c
index e88869f1d8..3b844f7993 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -181,6 +181,16 @@ tor_addr_make_unspec(tor_addr_t *a)
a->family = AF_UNSPEC;
}
+/** Set address <a>a</b> to the null address in address family <b>family</b>.
+ * The null address for AF_INET is 0.0.0.0. The null address for AF_INET6 is
+ * [::]. AF_UNSPEC is all null. */
+void
+tor_addr_make_null(tor_addr_t *a, sa_family_t family)
+{
+ memset(a, 0, sizeof(*a));
+ a->family = family;
+}
+
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
* *<b>addr</b> to the proper IP address and family. The <b>family</b>
* argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a
@@ -305,7 +315,8 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
* also treated as internal for now.)
*/
int
-tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
+tor_addr_is_internal_(const tor_addr_t *addr, int for_listening,
+ const char *filename, int lineno)
{
uint32_t iph4 = 0;
uint32_t iph6[4];
@@ -355,8 +366,8 @@ tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
/* unknown address family... assume it's not safe for external use */
/* rather than tor_assert(0) */
- log_warn(LD_BUG, "tor_addr_is_internal() called with a non-IP address of "
- "type %d", (int)v_family);
+ log_warn(LD_BUG, "tor_addr_is_internal() called from %s:%d with a "
+ "non-IP address of type %d", filename, lineno, (int)v_family);
tor_fragile_assert();
return 1;
}
@@ -558,9 +569,22 @@ tor_addr_to_PTR_name(char *out, size_t outlen,
*
* Return an address family on success, or -1 if an invalid address string is
* provided.
+ *
+ * If 'flags & TAPMP_EXTENDED_STAR' is false, then the wildcard address '*'
+ * yield an IPv4 wildcard.
+ *
+ * If 'flags & TAPMP_EXTENDED_STAR' is true, then the wildcard address '*'
+ * yields an AF_UNSPEC wildcard address, and the following change is made
+ * in the grammar above:
+ * Address ::= IPv4Address / "[" IPv6Address "]" / "*" / "*4" / "*6"
+ * with the new "*4" and "*6" productions creating a wildcard to match
+ * IPv4 or IPv6 addresses.
+ *
*/
int
-tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
+tor_addr_parse_mask_ports(const char *s,
+ unsigned flags,
+ tor_addr_t *addr_out,
maskbits_t *maskbits_out,
uint16_t *port_min_out, uint16_t *port_max_out)
{
@@ -617,9 +641,23 @@ tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
memset(addr_out, 0, sizeof(tor_addr_t));
if (!strcmp(address, "*")) {
- family = AF_INET; /* AF_UNSPEC ???? XXXX_IP6 */
+ if (flags & TAPMP_EXTENDED_STAR) {
+ family = AF_UNSPEC;
+ tor_addr_make_unspec(addr_out);
+ } else {
+ family = AF_INET;
+ tor_addr_from_ipv4h(addr_out, 0);
+ }
+ any_flag = 1;
+ } else if (!strcmp(address, "*4") && (flags & TAPMP_EXTENDED_STAR)) {
+ family = AF_INET;
tor_addr_from_ipv4h(addr_out, 0);
any_flag = 1;
+ } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) {
+ static char nil_bytes[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ family = AF_INET6;
+ tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
+ any_flag = 1;
} else if (tor_inet_pton(AF_INET6, address, &in6_tmp) > 0) {
family = AF_INET6;
tor_addr_from_in6(addr_out, &in6_tmp);
@@ -1006,6 +1044,19 @@ fmt_addr_impl(const tor_addr_t *addr, int decorate)
return "???";
}
+/** Return a string representing the pair <b>addr</b> and <b>port</b>.
+ * This calls fmt_and_decorate_addr internally, so IPv6 addresses will
+ * have brackets, and the caveats of fmt_addr_impl apply.
+ */
+const char *
+fmt_addrport(const tor_addr_t *addr, uint16_t port)
+{
+ /* Add space for a colon and up to 5 digits. */
+ static char buf[TOR_ADDR_BUF_LEN + 6];
+ tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port);
+ return buf;
+}
+
/** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4
* addresses. Also not thread-safe, also clobbers its return buffer on
* repeated calls. */
@@ -1379,7 +1430,46 @@ is_internal_IP(uint32_t ip, int for_listening)
return tor_addr_is_internal(&myaddr, for_listening);
}
-/** Given an address of the form "host:port", try to divide it into its host
+/** Given an address of the form "ip:port", try to divide it into its
+ * ip and port portions, setting *<b>address_out</b> to a newly
+ * allocated string holding the address portion and *<b>port_out</b>
+ * to the port.
+ *
+ * Don't do DNS lookups and don't allow domain names in the <ip> field.
+ * Don't accept <b>addrport</b> of the form "<ip>" or "<ip>:0".
+ *
+ * Return 0 on success, -1 on failure. */
+int
+tor_addr_port_parse(int severity, const char *addrport,
+ tor_addr_t *address_out, uint16_t *port_out)
+{
+ int retval = -1;
+ int r;
+ char *addr_tmp = NULL;
+
+ tor_assert(addrport);
+ tor_assert(address_out);
+ tor_assert(port_out);
+
+ r = tor_addr_port_split(severity, addrport, &addr_tmp, port_out);
+ if (r < 0)
+ goto done;
+
+ if (!*port_out)
+ goto done;
+
+ /* make sure that address_out is an IP address */
+ if (tor_addr_parse(address_out, addr_tmp) < 0)
+ goto done;
+
+ retval = 0;
+
+ done:
+ tor_free(addr_tmp);
+ return retval;
+}
+
+/** Given an address of the form "host[:port]", try to divide it into its host
* ane port portions, setting *<b>address_out</b> to a newly allocated string
* holding the address portion and *<b>port_out</b> to the port (or 0 if no
* port is given). Return 0 on success, -1 on failure. */
@@ -1408,17 +1498,17 @@ addr_port_lookup(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out)
{
const char *colon;
- char *_address = NULL;
- int _port;
+ char *address_ = NULL;
+ int port_;
int ok = 1;
tor_assert(addrport);
colon = strrchr(addrport, ':');
if (colon) {
- _address = tor_strndup(addrport, colon-addrport);
- _port = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
- if (!_port) {
+ address_ = tor_strndup(addrport, colon-addrport);
+ port_ = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
+ if (!port_) {
log_fn(severity, LD_GENERAL, "Port %s out of range", escaped(colon+1));
ok = 0;
}
@@ -1431,28 +1521,28 @@ addr_port_lookup(int severity, const char *addrport, char **address,
ok = 0;
}
} else {
- _address = tor_strdup(addrport);
- _port = 0;
+ address_ = tor_strdup(addrport);
+ port_ = 0;
}
if (addr) {
/* There's an addr pointer, so we need to resolve the hostname. */
- if (tor_lookup_hostname(_address,addr)) {
- log_fn(severity, LD_NET, "Couldn't look up %s", escaped(_address));
+ if (tor_lookup_hostname(address_,addr)) {
+ log_fn(severity, LD_NET, "Couldn't look up %s", escaped(address_));
ok = 0;
*addr = 0;
}
}
if (address && ok) {
- *address = _address;
+ *address = address_;
} else {
if (address)
*address = NULL;
- tor_free(_address);
+ tor_free(address_);
}
if (port_out)
- *port_out = ok ? ((uint16_t) _port) : 0;
+ *port_out = ok ? ((uint16_t) port_) : 0;
return ok ? 0 : -1;
}
@@ -1697,3 +1787,15 @@ tor_addr_hostname_is_local(const char *name)
!strcasecmpend(name, ".local");
}
+/** Return a newly allocated tor_addr_port_t with <b>addr</b> and
+ <b>port</b> filled in. */
+tor_addr_port_t *
+tor_addr_port_new(const tor_addr_t *addr, uint16_t port)
+{
+ tor_addr_port_t *ap = tor_malloc_zero(sizeof(tor_addr_port_t));
+ if (addr)
+ tor_addr_copy(&ap->addr, addr);
+ ap->port = port;
+ return ap;
+}
+
diff --git a/src/common/address.h b/src/common/address.h
index c6c126862a..0e2bbdcf88 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -8,8 +8,8 @@
* \brief Headers for address.h
**/
-#ifndef _TOR_ADDRESS_H
-#define _TOR_ADDRESS_H
+#ifndef TOR_ADDRESS_H
+#define TOR_ADDRESS_H
#include "orconfig.h"
#include "torint.h"
@@ -40,7 +40,7 @@ typedef struct tor_addr_port_t
uint16_t port;
} tor_addr_port_t;
-#define TOR_ADDR_NULL {AF_UNSPEC, {0}};
+#define TOR_ADDR_NULL {AF_UNSPEC, {0}}
static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a);
static INLINE uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
@@ -55,6 +55,7 @@ socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port,
int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out);
void tor_addr_make_unspec(tor_addr_t *a);
+void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
char *tor_sockaddr_to_str(const struct sockaddr *sa);
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
@@ -145,6 +146,7 @@ char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC;
* addresses. */
#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1)
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
+const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
const char * fmt_addr32(uint32_t addr);
int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr);
@@ -167,7 +169,10 @@ int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
unsigned int tor_addr_hash(const tor_addr_t *addr);
int tor_addr_is_v4(const tor_addr_t *addr);
-int tor_addr_is_internal(const tor_addr_t *ip, int for_listening);
+int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
+ const char *filename, int lineno);
+#define tor_addr_is_internal(addr, for_listening) \
+ tor_addr_is_internal_((addr), (for_listening), SHORT_FILE__, __LINE__)
/** Longest length that can be required for a reverse lookup name. */
/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */
@@ -179,7 +184,8 @@ int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out,
uint16_t *port_out);
-int tor_addr_parse_mask_ports(const char *s,
+#define TAPMP_EXTENDED_STAR 1
+int tor_addr_parse_mask_ports(const char *s, unsigned flags,
tor_addr_t *addr_out, maskbits_t *mask_out,
uint16_t *port_min_out, uint16_t *port_max_out);
const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len,
@@ -202,6 +208,9 @@ int tor_addr_is_loopback(const tor_addr_t *addr);
int tor_addr_port_split(int severity, const char *addrport,
char **address_out, uint16_t *port_out);
+int tor_addr_port_parse(int severity, const char *addrport,
+ tor_addr_t *address_out, uint16_t *port_out);
+
int tor_addr_hostname_is_local(const char *name);
/* IPv4 helpers */
@@ -221,5 +230,7 @@ int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
int get_interface_address(int severity, uint32_t *addr);
+tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
+
#endif
diff --git a/src/common/aes.c b/src/common/aes.c
index 295a90749a..2d64b85944 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -134,8 +134,8 @@ int
evaluate_evp_for_aes(int force_val)
{
(void) force_val;
- log_notice(LD_CRYPTO, "This version of OpenSSL has a known-good EVP "
- "counter-mode implementation. Using it.");
+ log_info(LD_CRYPTO, "This version of OpenSSL has a known-good EVP "
+ "counter-mode implementation. Using it.");
return 0;
}
int
@@ -212,11 +212,11 @@ evaluate_evp_for_aes(int force_val)
e = ENGINE_get_cipher_engine(NID_aes_128_ecb);
if (e) {
- log_notice(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
+ log_info(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
ENGINE_get_name(e));
should_use_EVP = 1;
} else {
- log_notice(LD_CRYPTO, "No AES engine found; using AES_* functions.");
+ log_info(LD_CRYPTO, "No AES engine found; using AES_* functions.");
should_use_EVP = 0;
}
#endif
@@ -263,12 +263,12 @@ evaluate_ctr_for_aes(void)
"not using it.");
} else {
/* Counter mode is okay */
- log_notice(LD_CRYPTO, "This OpenSSL has a good implementation of counter "
+ log_info(LD_CRYPTO, "This OpenSSL has a good implementation of counter "
"mode; using it.");
should_use_openssl_CTR = 1;
}
#else
- log_notice(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
+ log_info(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
"counter mode; not using it.");
#endif
return 0;
@@ -285,7 +285,7 @@ evaluate_ctr_for_aes(void)
* value of the current counter.
*/
static INLINE void
-_aes_fill_buf(aes_cnt_cipher_t *cipher)
+aes_fill_buf_(aes_cnt_cipher_t *cipher)
{
/* We don't currently use OpenSSL's counter mode implementation because:
* 1) some versions have known bugs
@@ -340,7 +340,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
EVP_EncryptInit(&cipher->key.evp, c, (const unsigned char*)key, NULL);
cipher->using_evp = 1;
} else {
- AES_set_encrypt_key((const unsigned char *)key, key_bits, &cipher->key.aes);
+ AES_set_encrypt_key((const unsigned char *)key, key_bits,&cipher->key.aes);
cipher->using_evp = 0;
}
@@ -360,7 +360,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
memset(cipher->buf, 0, sizeof(cipher->buf));
else
#endif
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
/** Release storage held by <b>cipher</b>
@@ -387,9 +387,10 @@ aes_cipher_free(aes_cnt_cipher_t *cipher)
#ifdef CAN_USE_OPENSSL_CTR
/* Helper function to use EVP with openssl's counter-mode wrapper. */
-static void evp_block128_fn(const uint8_t in[16],
- uint8_t out[16],
- const void *key)
+static void
+evp_block128_fn(const uint8_t in[16],
+ uint8_t out[16],
+ const void *key)
{
EVP_CIPHER_CTX *ctx = (void*)key;
int inl=16, outl=16;
@@ -429,8 +430,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
&cipher->pos);
}
return;
- }
- else
+ } else
#endif
{
int c = cipher->pos;
@@ -453,7 +453,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
UPDATE_CTR_BUF(cipher, 1);
}
UPDATE_CTR_BUF(cipher, 0);
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
}
}
@@ -469,8 +469,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
if (should_use_openssl_CTR) {
aes_crypt(cipher, data, len, data);
return;
- }
- else
+ } else
#endif
{
int c = cipher->pos;
@@ -493,7 +492,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
UPDATE_CTR_BUF(cipher, 1);
}
UPDATE_CTR_BUF(cipher, 0);
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
}
}
@@ -515,7 +514,8 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
#ifdef CAN_USE_OPENSSL_CTR
if (!should_use_openssl_CTR)
#endif
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
#endif
+
diff --git a/src/common/aes.h b/src/common/aes.h
index bde567f87f..fadeacc7ad 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -5,8 +5,8 @@
/* Implements a minimal interface to counter-mode AES. */
-#ifndef _TOR_AES_H
-#define _TOR_AES_H
+#ifndef TOR_AES_H
+#define TOR_AES_H
/**
* \file aes.h
diff --git a/src/common/compat.c b/src/common/compat.c
index 59e3898deb..d0e516c2ce 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -18,7 +18,7 @@
/* XXXX024 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf,
* and get this (and other important stuff!) automatically. Once we do that,
* make sure to also change the extern char **environ detection in
- * configure.in, because whether that is declared or not depends on whether
+ * configure.ac, because whether that is declared or not depends on whether
* we have _GNU_SOURCE defined! Maybe that means that once we take this out,
* we can also take out the configure check. */
#define _GNU_SOURCE
@@ -425,11 +425,10 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
else
*strp = strp_tmp;
return r;
-#elif defined(_MSC_VER)
+#elif defined(HAVE__VSCPRINTF)
/* On Windows, _vsnprintf won't tell us the length of the string if it
* overflows, so we need to use _vcsprintf to tell how much to allocate */
int len, r;
- char *res;
len = _vscprintf(fmt, args);
if (len < 0) {
*strp = NULL;
@@ -1256,7 +1255,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
/** Number of extra file descriptors to keep in reserve beyond those that we
* tell Tor it's allowed to use. */
-#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond _ConnLimit */
+#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */
/** Learn the maximum allowed number of file descriptors, and tell the system
* we want to use up to that number. (Some systems have a low soft limit, and
diff --git a/src/common/compat.h b/src/common/compat.h
index 42648bb04b..9c544fa309 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -3,8 +3,8 @@
* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_COMPAT_H
-#define _TOR_COMPAT_H
+#ifndef TOR_COMPAT_H
+#define TOR_COMPAT_H
#include "orconfig.h"
#include "torint.h"
@@ -239,6 +239,19 @@ size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2));
#define I64_FORMAT "%lld"
#endif
+#if (SIZEOF_INTPTR_T == SIZEOF_INT)
+#define INTPTR_T_FORMAT "%d"
+#define INTPTR_PRINTF_ARG(x) ((int)(x))
+#elif (SIZEOF_INTPTR_T == SIZEOF_LONG)
+#define INTPTR_T_FORMAT "%ld"
+#define INTPTR_PRINTF_ARG(x) ((long)(x))
+#elif (SIZEOF_INTPTR_T == 8)
+#define INTPTR_T_FORMAT I64_FORMAT
+#define INTPTR_PRINTF_ARG(x) I64_PRINTF_ARG(x)
+#else
+#error Unknown: SIZEOF_INTPTR_T
+#endif
+
/** Represents an mmaped file. Allocated via tor_mmap_file; freed with
* tor_munmap_file. */
typedef struct tor_mmap_t {
@@ -308,10 +321,10 @@ char *tor_strtok_r_impl(char *str, const char *sep, char **lasts);
#endif
#ifdef _WIN32
-#define _SHORT_FILE_ (tor_fix_source_file(__FILE__))
+#define SHORT_FILE__ (tor_fix_source_file(__FILE__))
const char *tor_fix_source_file(const char *fname);
#else
-#define _SHORT_FILE_ (__FILE__)
+#define SHORT_FILE__ (__FILE__)
#define tor_fix_source_file(s) (s)
#endif
@@ -403,11 +416,13 @@ typedef int socklen_t;
* any inadvertant checks for the socket being <= 0 or > 0 will probably
* still work. */
#define tor_socket_t intptr_t
+#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT
#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET)
#define TOR_INVALID_SOCKET INVALID_SOCKET
#else
/** Type used for a network socket. */
#define tor_socket_t int
+#define TOR_SOCKET_T_FORMAT "%d"
/** Macro: true iff 's' is a possible value for a valid initialized socket. */
#define SOCKET_OK(s) ((s) >= 0)
/** Error/uninitialized value for a tor_socket_t. */
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 6655ca87d3..0d06c49c9f 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -266,7 +266,7 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
/* Making this a NOTICE for now so we can link bugs to a libevent versions
* or methods better. */
- log(LOG_NOTICE, LD_GENERAL,
+ log(LOG_INFO, LD_GENERAL,
"Initialized libevent version %s using method %s. Good.",
event_get_version(), tor_libevent_get_method());
#else
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 56285ef80d..68da472cfc 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -1,8 +1,8 @@
/* Copyright (c) 2009-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_COMPAT_LIBEVENT_H
-#define _TOR_COMPAT_LIBEVENT_H
+#ifndef TOR_COMPAT_LIBEVENT_H
+#define TOR_COMPAT_LIBEVENT_H
#include "orconfig.h"
diff --git a/src/common/container.c b/src/common/container.c
index ede98eca5a..d4a2f89c90 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -571,59 +571,116 @@ smartlist_bsearch_idx(const smartlist_t *sl, const void *key,
int (*compare)(const void *key, const void **member),
int *found_out)
{
- const int len = smartlist_len(sl);
- int hi, lo, cmp, mid;
+ int hi, lo, cmp, mid, len, diff;
+ tor_assert(sl);
+ tor_assert(compare);
+ tor_assert(found_out);
+
+ len = smartlist_len(sl);
+
+ /* Check for the trivial case of a zero-length list */
if (len == 0) {
*found_out = 0;
+ /* We already know smartlist_len(sl) is 0 in this case */
return 0;
- } else if (len == 1) {
- cmp = compare(key, (const void **) &sl->list[0]);
- if (cmp == 0) {
- *found_out = 1;
- return 0;
- } else if (cmp < 0) {
- *found_out = 0;
- return 0;
- } else {
- *found_out = 0;
- return 1;
- }
}
- hi = smartlist_len(sl) - 1;
+ /* Okay, we have a real search to do */
+ tor_assert(len > 0);
lo = 0;
+ hi = len - 1;
+
+ /*
+ * These invariants are always true:
+ *
+ * For all i such that 0 <= i < lo, sl[i] < key
+ * For all i such that hi < i <= len, sl[i] > key
+ */
while (lo <= hi) {
- mid = (lo + hi) / 2;
+ diff = hi - lo;
+ /*
+ * We want mid = (lo + hi) / 2, but that could lead to overflow, so
+ * instead diff = hi - lo (non-negative because of loop condition), and
+ * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2).
+ */
+ mid = lo + (diff / 2);
cmp = compare(key, (const void**) &(sl->list[mid]));
- if (cmp>0) { /* key > sl[mid] */
- lo = mid+1;
- } else if (cmp<0) { /* key < sl[mid] */
- hi = mid-1;
- } else { /* key == sl[mid] */
+ if (cmp == 0) {
+ /* sl[mid] == key; we found it */
*found_out = 1;
return mid;
- }
- }
- /* lo > hi. */
- {
- tor_assert(lo >= 0);
- if (lo < smartlist_len(sl)) {
- cmp = compare(key, (const void**) &(sl->list[lo]));
+ } else if (cmp > 0) {
+ /*
+ * key > sl[mid] and an index i such that sl[i] == key must
+ * have i > mid if it exists.
+ */
+
+ /*
+ * Since lo <= mid <= hi, hi can only decrease on each iteration (by
+ * being set to mid - 1) and hi is initially len - 1, mid < len should
+ * always hold, and this is not symmetric with the left end of list
+ * mid > 0 test below. A key greater than the right end of the list
+ * should eventually lead to lo == hi == mid == len - 1, and then
+ * we set lo to len below and fall out to the same exit we hit for
+ * a key in the middle of the list but not matching. Thus, we just
+ * assert for consistency here rather than handle a mid == len case.
+ */
+ tor_assert(mid < len);
+ /* Move lo to the element immediately after sl[mid] */
+ lo = mid + 1;
+ } else {
+ /* This should always be true in this case */
tor_assert(cmp < 0);
- } else if (smartlist_len(sl)) {
- cmp = compare(key, (const void**) &(sl->list[smartlist_len(sl)-1]));
- tor_assert(cmp > 0);
+
+ /*
+ * key < sl[mid] and an index i such that sl[i] == key must
+ * have i < mid if it exists.
+ */
+
+ if (mid > 0) {
+ /* Normal case, move hi to the element immediately before sl[mid] */
+ hi = mid - 1;
+ } else {
+ /* These should always be true in this case */
+ tor_assert(mid == lo);
+ tor_assert(mid == 0);
+ /*
+ * We were at the beginning of the list and concluded that every
+ * element e compares e > key.
+ */
+ *found_out = 0;
+ return 0;
+ }
}
}
+
+ /*
+ * lo > hi; we have no element matching key but we have elements falling
+ * on both sides of it. The lo index points to the first element > key.
+ */
+ tor_assert(lo == hi + 1); /* All other cases should have been handled */
+ tor_assert(lo >= 0);
+ tor_assert(lo <= len);
+ tor_assert(hi >= 0);
+ tor_assert(hi <= len);
+
+ if (lo < len) {
+ cmp = compare(key, (const void **) &(sl->list[lo]));
+ tor_assert(cmp < 0);
+ } else {
+ cmp = compare(key, (const void **) &(sl->list[len-1]));
+ tor_assert(cmp > 0);
+ }
+
*found_out = 0;
return lo;
}
/** Helper: compare two const char **s. */
static int
-_compare_string_ptrs(const void **_a, const void **_b)
+compare_string_ptrs_(const void **_a, const void **_b)
{
return strcmp((const char*)*_a, (const char*)*_b);
}
@@ -633,14 +690,14 @@ _compare_string_ptrs(const void **_a, const void **_b)
void
smartlist_sort_strings(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_string_ptrs);
+ smartlist_sort(sl, compare_string_ptrs_);
}
/** Return the most frequent string in the sorted list <b>sl</b> */
char *
smartlist_get_most_frequent_string(smartlist_t *sl)
{
- return smartlist_get_most_frequent(sl, _compare_string_ptrs);
+ return smartlist_get_most_frequent(sl, compare_string_ptrs_);
}
/** Remove duplicate strings from a sorted list, and free them with tor_free().
@@ -648,7 +705,7 @@ smartlist_get_most_frequent_string(smartlist_t *sl)
void
smartlist_uniq_strings(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_string_ptrs, _tor_free);
+ smartlist_uniq(sl, compare_string_ptrs_, tor_free_);
}
/* Heap-based priority queue implementation for O(lg N) insert and remove.
@@ -849,7 +906,7 @@ smartlist_pqueue_assert_ok(smartlist_t *sl,
/** Helper: compare two DIGEST_LEN digests. */
static int
-_compare_digests(const void **_a, const void **_b)
+compare_digests_(const void **_a, const void **_b)
{
return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN);
}
@@ -858,7 +915,7 @@ _compare_digests(const void **_a, const void **_b)
void
smartlist_sort_digests(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_digests);
+ smartlist_sort(sl, compare_digests_);
}
/** Remove duplicate digests from a sorted list, and free them with tor_free().
@@ -866,12 +923,12 @@ smartlist_sort_digests(smartlist_t *sl)
void
smartlist_uniq_digests(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_digests, _tor_free);
+ smartlist_uniq(sl, compare_digests_, tor_free_);
}
/** Helper: compare two DIGEST256_LEN digests. */
static int
-_compare_digests256(const void **_a, const void **_b)
+compare_digests256_(const void **_a, const void **_b)
{
return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN);
}
@@ -880,7 +937,7 @@ _compare_digests256(const void **_a, const void **_b)
void
smartlist_sort_digests256(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_digests256);
+ smartlist_sort(sl, compare_digests256_);
}
/** Return the most frequent member of the sorted list of DIGEST256_LEN
@@ -888,7 +945,7 @@ smartlist_sort_digests256(smartlist_t *sl)
char *
smartlist_get_most_frequent_digest256(smartlist_t *sl)
{
- return smartlist_get_most_frequent(sl, _compare_digests256);
+ return smartlist_get_most_frequent(sl, compare_digests256_);
}
/** Remove duplicate 256-bit digests from a sorted list, and free them with
@@ -897,7 +954,7 @@ smartlist_get_most_frequent_digest256(smartlist_t *sl)
void
smartlist_uniq_digests256(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_digests256, _tor_free);
+ smartlist_uniq(sl, compare_digests256_, tor_free_);
}
/** Helper: Declare an entry type and a map type to implement a mapping using
diff --git a/src/common/container.h b/src/common/container.h
index dab3b83f37..0b3a3d1412 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -3,8 +3,8 @@
* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_CONTAINER_H
-#define _TOR_CONTAINER_H
+#ifndef TOR_CONTAINER_H
+#define TOR_CONTAINER_H
#include "util.h"
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 30990ecc8f..39f5a4a642 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -57,8 +57,8 @@
#include "container.h"
#include "compat.h"
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
-#error "We require OpenSSL >= 0.9.7"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
+#error "We require OpenSSL >= 0.9.8"
#endif
#ifdef ANDROID
@@ -69,31 +69,6 @@
/** Longest recognized */
#define MAX_DNS_LABEL_SIZE 63
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8) && \
- !defined(RUNNING_DOXYGEN)
-/** @{ */
-/** On OpenSSL versions before 0.9.8, there is no working SHA256
- * implementation, so we use Tom St Denis's nice speedy one, slightly adapted
- * to our needs. These macros make it usable by us. */
-#define SHA256_CTX sha256_state
-#define SHA256_Init sha256_init
-#define SHA256_Update sha256_process
-#define LTC_ARGCHK(x) tor_assert(x)
-/** @} */
-#include "sha256.c"
-#define SHA256_Final(a,b) sha256_done(b,a)
-
-static unsigned char *
-SHA256(const unsigned char *m, size_t len, unsigned char *d)
-{
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, m, len);
- SHA256_Final(d, &ctx);
- return d;
-}
-#endif
-
/** Macro: is k a valid RSA public or private key? */
#define PUBLIC_KEY_OK(k) ((k) && (k)->key && (k)->key->n)
/** Macro: is k a valid RSA private key? */
@@ -101,9 +76,9 @@ SHA256(const unsigned char *m, size_t len, unsigned char *d)
#ifdef TOR_IS_MULTITHREADED
/** A number of preallocated mutexes for use by OpenSSL. */
-static tor_mutex_t **_openssl_mutexes = NULL;
+static tor_mutex_t **openssl_mutexes_ = NULL;
/** How many mutexes have we allocated for use by OpenSSL? */
-static int _n_openssl_mutexes = 0;
+static int n_openssl_mutexes_ = 0;
#endif
/** A public key, or a public/private key-pair. */
@@ -158,7 +133,7 @@ crypto_get_rsa_padding(int padding)
}
/** Boolean: has OpenSSL's crypto been initialized? */
-static int _crypto_global_initialized = 0;
+static int crypto_global_initialized_ = 0;
/** Log all pending crypto errors at level <b>severity</b>. Use
* <b>doing</b> to describe our current activities.
@@ -221,16 +196,60 @@ try_load_engine(const char *path, const char *engine)
}
#endif
+static char *crypto_openssl_version_str = NULL;
+/* Return a human-readable version of the run-time openssl version number. */
+const char *
+crypto_openssl_get_version_str(void)
+{
+ if (crypto_openssl_version_str == NULL) {
+ const char *raw_version = SSLeay_version(SSLEAY_VERSION);
+ const char *end_of_version = NULL;
+ /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's
+ trim that down. */
+ if (!strcmpstart(raw_version, "OpenSSL ")) {
+ raw_version += strlen("OpenSSL ");
+ end_of_version = strchr(raw_version, ' ');
+ }
+
+ if (end_of_version)
+ crypto_openssl_version_str = tor_strndup(raw_version,
+ end_of_version-raw_version);
+ else
+ crypto_openssl_version_str = tor_strdup(raw_version);
+ }
+ return crypto_openssl_version_str;
+}
+
/** Initialize the crypto library. Return 0 on success, -1 on failure.
*/
int
crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
{
- if (!_crypto_global_initialized) {
+ if (!crypto_global_initialized_) {
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
- _crypto_global_initialized = 1;
+ crypto_global_initialized_ = 1;
setup_openssl_threading();
+
+ if (SSLeay() == OPENSSL_VERSION_NUMBER &&
+ !strcmp(SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT)) {
+ log_info(LD_CRYPTO, "OpenSSL version matches version from headers "
+ "(%lx: %s).", SSLeay(), SSLeay_version(SSLEAY_VERSION));
+ } else {
+ log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the "
+ "version we're running with. If you get weird crashes, that "
+ "might be why. (Compiled with %lx: %s; running with %lx: %s).",
+ (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT,
+ SSLeay(), SSLeay_version(SSLEAY_VERSION));
+ }
+
+ if (SSLeay() < OPENSSL_V_SERIES(1,0,0)) {
+ log_notice(LD_CRYPTO,
+ "Your OpenSSL version seems to be %s. We recommend 1.0.0 "
+ "or later.",
+ crypto_openssl_get_version_str());
+ }
+
if (useAccel > 0) {
#ifdef DISABLE_ENGINES
(void)accelName;
@@ -294,7 +313,7 @@ crypto_thread_cleanup(void)
/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
crypto_pk_t *
-_crypto_new_pk_from_rsa(RSA *rsa)
+crypto_new_pk_from_rsa_(RSA *rsa)
{
crypto_pk_t *env;
tor_assert(rsa);
@@ -307,7 +326,7 @@ _crypto_new_pk_from_rsa(RSA *rsa)
/** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a
* crypto_pk_t. */
RSA *
-_crypto_pk_get_rsa(crypto_pk_t *env)
+crypto_pk_get_rsa_(crypto_pk_t *env)
{
return env->key;
}
@@ -315,7 +334,7 @@ _crypto_pk_get_rsa(crypto_pk_t *env)
/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
* private is set, include the private-key portion of the key. */
EVP_PKEY *
-_crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
+crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private)
{
RSA *key = NULL;
EVP_PKEY *pkey = NULL;
@@ -343,7 +362,7 @@ _crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
/** Used by tortls.c: Get the DH* from a crypto_dh_t.
*/
DH *
-_crypto_dh_get_dh(crypto_dh_t *dh)
+crypto_dh_get_dh_(crypto_dh_t *dh)
{
return dh->dh;
}
@@ -358,7 +377,7 @@ crypto_pk_new(void)
rsa = RSA_new();
tor_assert(rsa);
- return _crypto_new_pk_from_rsa(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
}
/** Release a reference to an asymmetric key; when all the references
@@ -441,11 +460,7 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
if (env->key)
RSA_free(env->key);
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
- /* In OpenSSL 0.9.7, RSA_generate_key is all we have. */
- env->key = RSA_generate_key(bits, 65537, NULL, NULL);
-#else
- /* In OpenSSL 0.9.8, RSA_generate_key is deprecated. */
+
{
BIGNUM *e = BN_new();
RSA *r = NULL;
@@ -466,8 +481,8 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
BN_free(e);
if (r)
RSA_free(r);
- }
-#endif
+ }
+
if (!env->key) {
crypto_log_errors(LOG_WARN, "generating RSA key");
return -1;
@@ -711,19 +726,23 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env)
return BN_is_word(env->key->e, 65537);
}
-/** Compare the public-key components of a and b. Return -1 if a\<b, 0
- * if a==b, and 1 if a\>b.
+/** Compare the public-key components of a and b. Return less than 0
+ * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is
+ * considered to be less than all non-NULL keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
*/
int
crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
{
int result;
+ char a_is_non_null = (a != NULL) && (a->key != NULL);
+ char b_is_non_null = (b != NULL) && (b->key != NULL);
+ char an_argument_is_null = !a_is_non_null | !b_is_non_null;
- if (!a || !b)
- return -1;
-
- if (!a->key || !b->key)
- return -1;
+ result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null));
+ if (an_argument_is_null)
+ return result;
tor_assert(PUBLIC_KEY_OK(a));
tor_assert(PUBLIC_KEY_OK(b));
@@ -733,6 +752,18 @@ crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
return BN_cmp((a->key)->e, (b->key)->e);
}
+/** Compare the public-key components of a and b. Return non-zero iff
+ * a==b. A NULL key is considered to be distinct from all non-NULL
+ * keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
+ */
+int
+crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b)
+{
+ return (crypto_pk_cmp_keys(a, b) == 0);
+}
+
/** Return the size of the public key modulus in <b>env</b>, in bytes. */
size_t
crypto_pk_keysize(crypto_pk_t *env)
@@ -791,7 +822,7 @@ crypto_pk_copy_full(crypto_pk_t *env)
return NULL;
}
- return _crypto_new_pk_from_rsa(new_key);
+ return crypto_new_pk_from_rsa_(new_key);
}
/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key
@@ -1158,7 +1189,7 @@ crypto_pk_asn1_decode(const char *str, size_t len)
crypto_log_errors(LOG_WARN,"decoding public key");
return NULL;
}
- return _crypto_new_pk_from_rsa(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
}
/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
@@ -1623,63 +1654,11 @@ crypto_hmac_sha256(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len)
{
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,8)
/* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
tor_assert(key_len < INT_MAX);
tor_assert(msg_len < INT_MAX);
HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
(unsigned char*)hmac_out, NULL);
-#else
- /* OpenSSL doesn't have an EVP implementation for SHA256. We'll need
- to do HMAC on our own.
-
- HMAC isn't so hard: To compute HMAC(key, msg):
- 1. If len(key) > blocksize, key = H(key).
- 2. If len(key) < blocksize, right-pad key up to blocksize with 0 bytes.
- 3. let ipad = key xor 0x363636363636....36
- let opad = key xor 0x5c5c5c5c5c5c....5c
- The result is H(opad | H( ipad | msg ) )
- */
-#define BLOCKSIZE 64
-#define DIGESTSIZE 32
- uint8_t k[BLOCKSIZE];
- uint8_t pad[BLOCKSIZE];
- uint8_t d[DIGESTSIZE];
- int i;
- SHA256_CTX st;
-
- tor_assert(key_len < INT_MAX);
- tor_assert(msg_len < INT_MAX);
-
- if (key_len <= BLOCKSIZE) {
- memset(k, 0, sizeof(k));
- memcpy(k, key, key_len); /* not time invariant in key_len */
- } else {
- SHA256((const uint8_t *)key, key_len, k);
- memset(k+DIGESTSIZE, 0, sizeof(k)-DIGESTSIZE);
- }
- for (i = 0; i < BLOCKSIZE; ++i)
- pad[i] = k[i] ^ 0x36;
- SHA256_Init(&st);
- SHA256_Update(&st, pad, BLOCKSIZE);
- SHA256_Update(&st, (uint8_t*)msg, msg_len);
- SHA256_Final(d, &st);
-
- for (i = 0; i < BLOCKSIZE; ++i)
- pad[i] = k[i] ^ 0x5c;
- SHA256_Init(&st);
- SHA256_Update(&st, pad, BLOCKSIZE);
- SHA256_Update(&st, d, DIGESTSIZE);
- SHA256_Final((uint8_t*)hmac_out, &st);
-
- /* Now clear everything. */
- memwipe(k, 0, sizeof(k));
- memwipe(pad, 0, sizeof(pad));
- memwipe(d, 0, sizeof(d));
- memwipe(&st, 0, sizeof(st));
-#undef BLOCKSIZE
-#undef DIGESTSIZE
-#endif
}
/* DH */
@@ -2282,9 +2261,7 @@ crypto_dh_free(crypto_dh_t *dh)
* that fd without checking whether it fit in the fd_set. Thus, if the
* system has not just been started up, it is unsafe to call */
#define RAND_POLL_IS_SAFE \
- ((OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,7,'j') && \
- OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)) || \
- OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
+ (OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
/** Set the seed of the weak RNG to a random value. */
static void
@@ -2759,7 +2736,7 @@ digest256_from_base64(char *digest, const char *d64)
#endif
}
-/** Implements base32 encoding as in rfc3548. Limitation: Requires
+/** Implements base32 encoding as in RFC 4648. Limitation: Requires
* that srclen*8 is a multiple of 5.
*/
void
@@ -2784,7 +2761,7 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
dest[i] = '\0';
}
-/** Implements base32 decoding as in rfc3548. Limitation: Requires
+/** Implements base32 decoding as in RFC 4648. Limitation: Requires
* that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
*/
int
@@ -2939,19 +2916,19 @@ memwipe(void *mem, uint8_t byte, size_t sz)
#ifdef TOR_IS_MULTITHREADED
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
static void
-_openssl_locking_cb(int mode, int n, const char *file, int line)
+openssl_locking_cb_(int mode, int n, const char *file, int line)
{
(void)file;
(void)line;
- if (!_openssl_mutexes)
+ if (!openssl_mutexes_)
/* This is not a really good fix for the
* "release-freed-lock-from-separate-thread-on-shutdown" problem, but
* it can't hurt. */
return;
if (mode & CRYPTO_LOCK)
- tor_mutex_acquire(_openssl_mutexes[n]);
+ tor_mutex_acquire(openssl_mutexes_[n]);
else
- tor_mutex_release(_openssl_mutexes[n]);
+ tor_mutex_release(openssl_mutexes_[n]);
}
/** OpenSSL helper type: wraps a Tor mutex so that OpenSSL can use it
@@ -2963,7 +2940,7 @@ struct CRYPTO_dynlock_value {
/** OpenSSL callback function to allocate a lock: see CRYPTO_set_dynlock_*
* documentation in OpenSSL's docs for more info. */
static struct CRYPTO_dynlock_value *
-_openssl_dynlock_create_cb(const char *file, int line)
+openssl_dynlock_create_cb_(const char *file, int line)
{
struct CRYPTO_dynlock_value *v;
(void)file;
@@ -2976,7 +2953,7 @@ _openssl_dynlock_create_cb(const char *file, int line)
/** OpenSSL callback function to acquire or release a lock: see
* CRYPTO_set_dynlock_* documentation in OpenSSL's docs for more info. */
static void
-_openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v,
+openssl_dynlock_lock_cb_(int mode, struct CRYPTO_dynlock_value *v,
const char *file, int line)
{
(void)file;
@@ -2990,7 +2967,7 @@ _openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v,
/** OpenSSL callback function to free a lock: see CRYPTO_set_dynlock_*
* documentation in OpenSSL's docs for more info. */
static void
-_openssl_dynlock_destroy_cb(struct CRYPTO_dynlock_value *v,
+openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
const char *file, int line)
{
(void)file;
@@ -3007,15 +2984,15 @@ setup_openssl_threading(void)
{
int i;
int n = CRYPTO_num_locks();
- _n_openssl_mutexes = n;
- _openssl_mutexes = tor_malloc(n*sizeof(tor_mutex_t *));
+ n_openssl_mutexes_ = n;
+ openssl_mutexes_ = tor_malloc(n*sizeof(tor_mutex_t *));
for (i=0; i < n; ++i)
- _openssl_mutexes[i] = tor_mutex_new();
- CRYPTO_set_locking_callback(_openssl_locking_cb);
+ openssl_mutexes_[i] = tor_mutex_new();
+ CRYPTO_set_locking_callback(openssl_locking_cb_);
CRYPTO_set_id_callback(tor_get_thread_id);
- CRYPTO_set_dynlock_create_callback(_openssl_dynlock_create_cb);
- CRYPTO_set_dynlock_lock_callback(_openssl_dynlock_lock_cb);
- CRYPTO_set_dynlock_destroy_callback(_openssl_dynlock_destroy_cb);
+ CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_);
+ CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_);
+ CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_);
return 0;
}
#else
@@ -3049,18 +3026,19 @@ crypto_global_cleanup(void)
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
#ifdef TOR_IS_MULTITHREADED
- if (_n_openssl_mutexes) {
- int n = _n_openssl_mutexes;
- tor_mutex_t **ms = _openssl_mutexes;
+ if (n_openssl_mutexes_) {
+ int n = n_openssl_mutexes_;
+ tor_mutex_t **ms = openssl_mutexes_;
int i;
- _openssl_mutexes = NULL;
- _n_openssl_mutexes = 0;
+ openssl_mutexes_ = NULL;
+ n_openssl_mutexes_ = 0;
for (i=0;i<n;++i) {
tor_mutex_free(ms[i]);
}
tor_free(ms);
}
#endif
+ tor_free(crypto_openssl_version_str);
return 0;
}
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 7d56271785..4c5fa6ad97 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -10,8 +10,8 @@
* \brief Headers for crypto.c
**/
-#ifndef _TOR_CRYPTO_H
-#define _TOR_CRYPTO_H
+#ifndef TOR_CRYPTO_H
+#define TOR_CRYPTO_H
#include <stdio.h>
#include "torint.h"
@@ -51,7 +51,7 @@
/** Length of the output of our message digest. */
#define DIGEST_LEN 20
/** Length of the output of our second (improved) message digests. (For now
- * this is just sha256, but any it can be any other 256-byte digest). */
+ * this is just sha256, but it could be any other 256-bit digest.) */
#define DIGEST256_LEN 32
/** Length of our symmetric cipher's keys. */
#define CIPHER_KEY_LEN 16
@@ -111,6 +111,7 @@ typedef struct crypto_digest_t crypto_digest_t;
typedef struct crypto_dh_t crypto_dh_t;
/* global state */
+const char * crypto_openssl_get_version_str(void);
int crypto_global_init(int hardwareAccel,
const char *accelName,
const char *accelPath);
@@ -147,6 +148,7 @@ int crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
int crypto_pk_check_key(crypto_pk_t *env);
int crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b);
+int crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b);
size_t crypto_pk_keysize(crypto_pk_t *env);
int crypto_pk_num_bits(crypto_pk_t *env);
crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig);
@@ -280,11 +282,11 @@ void memwipe(void *mem, uint8_t byte, size_t sz);
struct rsa_st;
struct evp_pkey_st;
struct dh_st;
-struct rsa_st *_crypto_pk_get_rsa(crypto_pk_t *env);
-crypto_pk_t *_crypto_new_pk_from_rsa(struct rsa_st *rsa);
-struct evp_pkey_st *_crypto_pk_get_evp_pkey(crypto_pk_t *env,
+struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env);
+crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa);
+struct evp_pkey_st *crypto_pk_get_evp_pkey_(crypto_pk_t *env,
int private);
-struct dh_st *_crypto_dh_get_dh(crypto_dh_t *dh);
+struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh);
/* Prototypes for private functions only used by crypto.c and test.c*/
void add_spaces_to_fp(char *out, size_t outlen, const char *in);
#endif
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index 7683c59dee..418d6e3dca 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -123,7 +123,7 @@ tor_memeq(const void *a, const void *b, size_t sz)
*
* If any_difference != 0:
* 0 < any_difference < 256, so
- * 0 < any_difference - 1 < 255
+ * 0 <= any_difference - 1 < 255
* (any_difference - 1) >> 8 == 0
* 1 & ((any_difference - 1) >> 8) == 0
*/
diff --git a/src/common/include.am b/src/common/include.am
new file mode 100644
index 0000000000..0fdc72057f
--- /dev/null
+++ b/src/common/include.am
@@ -0,0 +1,71 @@
+
+noinst_LIBRARIES+= src/common/libor.a src/common/libor-crypto.a src/common/libor-event.a
+
+EXTRA_DIST+= \
+ src/common/common_sha1.i \
+ src/common/Makefile.nmake
+
+#CFLAGS = -Wall -Wpointer-arith -O2
+AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common
+
+if USE_OPENBSD_MALLOC
+libor_extra_source=src/ext/OpenBSD_malloc_Linux.c
+else
+libor_extra_source=
+endif
+
+src_common_libor_a_SOURCES = \
+ src/common/address.c \
+ src/common/compat.c \
+ src/common/container.c \
+ src/common/di_ops.c \
+ src/common/log.c \
+ src/common/memarea.c \
+ src/common/mempool.c \
+ src/common/procmon.c \
+ src/common/util.c \
+ src/common/util_codedigest.c \
+ $(libor_extra_source)
+
+src_common_libor_crypto_a_SOURCES = \
+ src/common/aes.c \
+ src/common/crypto.c \
+ src/common/torgzip.c \
+ src/common/tortls.c
+
+src_common_libor_event_a_SOURCES = src/common/compat_libevent.c
+
+COMMONHEADERS = \
+ src/common/address.h \
+ src/common/aes.h \
+ src/common/ciphers.inc \
+ src/common/compat.h \
+ src/common/compat_libevent.h \
+ src/common/container.h \
+ src/common/crypto.h \
+ src/common/di_ops.h \
+ src/common/memarea.h \
+ src/common/mempool.h \
+ src/common/procmon.h \
+ src/common/torgzip.h \
+ src/common/torint.h \
+ src/common/torlog.h \
+ src/common/tortls.h \
+ src/common/util.h
+
+noinst_HEADERS+= $(COMMONHEADERS)
+
+DISTCLEANFILES+= src/common/common_sha1.i
+
+src/common/common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(COMMONHEADERS)
+ $(AM_V_GEN)if test "@SHA1SUM@" != none; then \
+ (cd "$(srcdir)" && "@SHA1SUM@" $(src_common_libor_SOURCES) $(src_common_libor_crypto_a_SOURCES) $(COMMONHEADERS)) | "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > $@; \
+ elif test "@OPENSSL@" != none; then \
+ (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_common_libor_SOURCES) $(src_Common_libor_crypto_a_SOURCES) $(COMMONHEADERS)) | "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > $@; \
+ else \
+ rm $@; \
+ touch $@; \
+ fi
+
+src/common/util_codedigest.o: src/common/common_sha1.i
+
diff --git a/src/common/log.c b/src/common/log.c
index 5e2e6b5b50..5bf12cfe9c 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -131,7 +131,7 @@ static smartlist_t *pending_cb_messages = NULL;
/** What's the lowest log level anybody cares about? Checking this lets us
* bail out early from log_debug if we aren't debugging. */
-int _log_global_min_severity = LOG_NOTICE;
+int log_global_min_severity_ = LOG_NOTICE;
static void delete_log(logfile_t *victim);
static void close_log(logfile_t *victim);
@@ -177,7 +177,7 @@ set_log_time_granularity(int granularity_msec)
* <b>buf_len</b> character buffer in <b>buf</b>.
*/
static INLINE size_t
-_log_prefix(char *buf, size_t buf_len, int severity)
+log_prefix_(char *buf, size_t buf_len, int severity)
{
time_t t;
struct timeval now;
@@ -230,7 +230,7 @@ log_tor_version(logfile_t *lf, int reset)
/* We are resetting, but we aren't at the start of the file; no
* need to log again. */
return 0;
- n = _log_prefix(buf, sizeof(buf), LOG_NOTICE);
+ n = log_prefix_(buf, sizeof(buf), LOG_NOTICE);
if (appname) {
tor_snprintf(buf+n, sizeof(buf)-n,
"%s opening %slog file.\n", appname, is_new?"new ":"");
@@ -262,7 +262,7 @@ format_msg(char *buf, size_t buf_len,
buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
buf_end = buf+buf_len; /* point *after* the last char we can write to */
- n = _log_prefix(buf, buf_len, severity);
+ n = log_prefix_(buf, buf_len, severity);
end_of_prefix = buf+n;
if (log_domains_are_logged) {
@@ -423,7 +423,7 @@ void
tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
logv(severity, domain, NULL, format, ap);
@@ -436,11 +436,11 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
* variadic macros. All arguments are as for log_fn, except for
* <b>fn</b>, which is the name of the calling functions. */
void
-_log_fn(int severity, log_domain_mask_t domain, const char *fn,
+log_fn_(int severity, log_domain_mask_t domain, const char *fn,
const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
logv(severity, domain, fn, format, ap);
@@ -450,75 +450,75 @@ _log_fn(int severity, log_domain_mask_t domain, const char *fn,
/** @{ */
/** Variant implementation of log_fn, log_debug, log_info,... for C compilers
* without variadic macros. In this case, the calling function sets
- * _log_fn_function_name to the name of the function, then invokes the
- * appropriate _log_fn, _log_debug, etc. */
-const char *_log_fn_function_name=NULL;
+ * log_fn_function_name_ to the name of the function, then invokes the
+ * appropriate log_fn_, log_debug_, etc. */
+const char *log_fn_function_name_=NULL;
void
-_log_fn(int severity, log_domain_mask_t domain, const char *format, ...)
+log_fn_(int severity, log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
- logv(severity, domain, _log_fn_function_name, format, ap);
+ logv(severity, domain, log_fn_function_name_, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_debug(log_domain_mask_t domain, const char *format, ...)
+log_debug_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
/* For GCC we do this check in the macro. */
- if (PREDICT_LIKELY(LOG_DEBUG > _log_global_min_severity))
+ if (PREDICT_LIKELY(LOG_DEBUG > log_global_min_severity_))
return;
va_start(ap,format);
- logv(LOG_DEBUG, domain, _log_fn_function_name, format, ap);
+ logv(LOG_DEBUG, domain, log_fn_function_name_, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_info(log_domain_mask_t domain, const char *format, ...)
+log_info_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_INFO > _log_global_min_severity)
+ if (LOG_INFO > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_INFO, domain, _log_fn_function_name, format, ap);
+ logv(LOG_INFO, domain, log_fn_function_name_, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_notice(log_domain_mask_t domain, const char *format, ...)
+log_notice_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_NOTICE > _log_global_min_severity)
+ if (LOG_NOTICE > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_NOTICE, domain, _log_fn_function_name, format, ap);
+ logv(LOG_NOTICE, domain, log_fn_function_name_, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_warn(log_domain_mask_t domain, const char *format, ...)
+log_warn_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_WARN > _log_global_min_severity)
+ if (LOG_WARN > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_WARN, domain, _log_fn_function_name, format, ap);
+ logv(LOG_WARN, domain, log_fn_function_name_, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_err(log_domain_mask_t domain, const char *format, ...)
+log_err_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_ERR > _log_global_min_severity)
+ if (LOG_ERR > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_ERR, domain, _log_fn_function_name, format, ap);
+ logv(LOG_ERR, domain, log_fn_function_name_, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
/** @} */
#endif
@@ -638,7 +638,7 @@ add_stream_log_impl(const log_severity_list_t *severity,
lf->next = logfiles;
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
}
/** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
@@ -706,7 +706,7 @@ add_callback_log(const log_severity_list_t *severity, log_callback cb)
LOCK_LOGS();
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
return 0;
}
@@ -726,7 +726,7 @@ change_callback_log_severity(int loglevelMin, int loglevelMax,
memcpy(lf->severities, &severities, sizeof(severities));
}
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
@@ -792,7 +792,7 @@ close_temp_logs(void)
}
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
@@ -840,7 +840,7 @@ add_file_log(const log_severity_list_t *severity, const char *filename)
add_stream_log_impl(severity, filename, fd);
logfiles->needs_close = 1;
lf = logfiles;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
if (log_tor_version(lf, 0) < 0) {
delete_log(lf);
@@ -871,7 +871,7 @@ add_syslog_log(const log_severity_list_t *severity)
LOCK_LOGS();
lf->next = logfiles;
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
return 0;
}
@@ -907,7 +907,7 @@ log_level_to_string(int level)
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
- "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", NULL
+ "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
@@ -1106,7 +1106,7 @@ switch_logs_debug(void)
for (i = LOG_DEBUG; i >= LOG_ERR; --i)
lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u;
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
diff --git a/src/common/memarea.c b/src/common/memarea.c
index 07bd593cc9..ef8a8d76bc 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -77,7 +77,7 @@ typedef struct memarea_chunk_t {
* full. */
union {
char mem[1]; /**< Memory space in this chunk. */
- void *_void_for_alignment; /**< Dummy; used to make sure mem is aligned. */
+ void *void_for_alignment_; /**< Dummy; used to make sure mem is aligned. */
} u;
} memarea_chunk_t;
@@ -118,7 +118,7 @@ alloc_chunk(size_t sz, int freelist_ok)
size_t chunk_size = freelist_ok ? CHUNK_SIZE : sz;
memarea_chunk_t *res;
chunk_size += SENTINEL_LEN;
- res = tor_malloc_roundup(&chunk_size);
+ res = tor_malloc(chunk_size);
res->next_chunk = NULL;
res->mem_size = chunk_size - CHUNK_HEADER_SIZE - SENTINEL_LEN;
res->next_mem = res->u.mem;
diff --git a/src/common/memarea.h b/src/common/memarea.h
index b3c76d8d0c..26c3e6dfe3 100644
--- a/src/common/memarea.h
+++ b/src/common/memarea.h
@@ -2,8 +2,8 @@
/* See LICENSE for licensing information */
/* Tor dependencies */
-#ifndef _TOR_MEMAREA_H
-#define _TOR_MEMAREA_H
+#ifndef TOR_MEMAREA_H
+#define TOR_MEMAREA_H
typedef struct memarea_t memarea_t;
diff --git a/src/common/mempool.c b/src/common/mempool.c
index 637f081c88..78d4da6f76 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -71,7 +71,6 @@
#define ASSERT(x) tor_assert(x)
#undef ALLOC_CAN_RETURN_NULL
#define TOR
-//#define ALLOC_ROUNDUP(p) tor_malloc_roundup(p)
/* End Tor dependencies */
#else
/* If you're not building this as part of Tor, you'll want to define the
@@ -115,7 +114,7 @@ struct mp_allocated_t {
* (Not actual size.) */
char mem[1];
/** An extra element to the union to insure correct alignment. */
- ALIGNMENT_TYPE _dummy;
+ ALIGNMENT_TYPE dummy_;
} u;
};
@@ -166,25 +165,16 @@ static mp_chunk_t *
mp_chunk_new(mp_pool_t *pool)
{
size_t sz = pool->new_chunk_capacity * pool->item_alloc_size;
-#ifdef ALLOC_ROUNDUP
- size_t alloc_size = CHUNK_OVERHEAD + sz;
- mp_chunk_t *chunk = ALLOC_ROUNDUP(&alloc_size);
-#else
mp_chunk_t *chunk = ALLOC(CHUNK_OVERHEAD + sz);
-#endif
+
#ifdef MEMPOOL_STATS
++pool->total_chunks_allocated;
#endif
CHECK_ALLOC(chunk);
memset(chunk, 0, sizeof(mp_chunk_t)); /* Doesn't clear the whole thing. */
chunk->magic = MP_CHUNK_MAGIC;
-#ifdef ALLOC_ROUNDUP
- chunk->mem_size = alloc_size - CHUNK_OVERHEAD;
- chunk->capacity = chunk->mem_size / pool->item_alloc_size;
-#else
chunk->capacity = pool->new_chunk_capacity;
chunk->mem_size = sz;
-#endif
chunk->next_mem = chunk->mem;
chunk->pool = pool;
return chunk;
diff --git a/src/common/mempool.h b/src/common/mempool.h
index d0a7bc2f36..b01277df86 100644
--- a/src/common/mempool.h
+++ b/src/common/mempool.h
@@ -6,8 +6,8 @@
* \brief Headers for mempool.c
**/
-#ifndef _TOR_MEMPOOL_H
-#define _TOR_MEMPOOL_H
+#ifndef TOR_MEMPOOL_H
+#define TOR_MEMPOOL_H
/** A memory pool is a context in which a large number of fixed-sized
* objects can be allocated efficiently. See mempool.c for implementation
diff --git a/src/common/procmon.c b/src/common/procmon.c
index 36b1a48553..08fcfec49c 100644
--- a/src/common/procmon.c
+++ b/src/common/procmon.c
@@ -25,9 +25,21 @@
#ifdef _WIN32
#include <windows.h>
+#endif
-/* Windows does not define pid_t, but _getpid() returns an int. */
+#if (0 == SIZEOF_PID_T) && defined(_WIN32)
+/* Windows does not define pid_t sometimes, but _getpid() returns an int.
+ * Everybody else needs to have a pid_t. */
typedef int pid_t;
+#define PID_T_FORMAT "%d"
+#elif (SIZEOF_PID_T == SIZEOF_INT) || (SIZEOF_PID_T == SIZEOF_SHORT)
+#define PID_T_FORMAT "%d"
+#elif (SIZEOF_PID_T == SIZEOF_LONG)
+#define PID_T_FORMAT "%ld"
+#elif (SIZEOF_PID_T == SIZEOF_INT64_T)
+#define PID_T_FORMAT I64_FORMAT
+#else
+#error Unknown: SIZEOF_PID_T
#endif
/* Define to 1 if process-termination monitors on this OS and Libevent
@@ -204,15 +216,17 @@ tor_process_monitor_new(struct event_base *base,
if (procmon->hproc != NULL) {
procmon->poll_hproc = 1;
- log_info(procmon->log_domain, "Successfully opened handle to process %d; "
+ log_info(procmon->log_domain, "Successfully opened handle to process "
+ PID_T_FORMAT"; "
"monitoring it.",
- (int)(procmon->pid));
+ procmon->pid);
} else {
/* If we couldn't get a handle to the process, we'll try again the
* first time we poll. */
- log_info(procmon->log_domain, "Failed to open handle to process %d; will "
+ log_info(procmon->log_domain, "Failed to open handle to process "
+ PID_T_FORMAT"; will "
"try again later.",
- (int)(procmon->pid));
+ procmon->pid);
}
#endif
@@ -257,7 +271,8 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (!GetExitCodeProcess(procmon->hproc, &exit_code)) {
char *errmsg = format_win32_error(GetLastError());
log_warn(procmon->log_domain, "Error \"%s\" occurred while polling "
- "handle for monitored process %d; assuming it's dead.",
+ "handle for monitored process "PID_T_FORMAT"; assuming "
+ "it's dead.",
errmsg, procmon->pid);
tor_free(errmsg);
its_dead_jim = 1;
@@ -273,7 +288,7 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (procmon->hproc != NULL) {
log_info(procmon->log_domain, "Successfully opened handle to monitored "
- "process %d.",
+ "process "PID_T_FORMAT".",
procmon->pid);
its_dead_jim = 0;
procmon->poll_hproc = 1;
@@ -292,8 +307,8 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (!its_dead_jim)
log_info(procmon->log_domain, "Failed to open handle to monitored "
- "process %d, and error code %lu (%s) is not 'invalid "
- "parameter' -- assuming the process is still alive.",
+ "process "PID_T_FORMAT", and error code %lu (%s) is not "
+ "'invalid parameter' -- assuming the process is still alive.",
procmon->pid,
err_code, errmsg);
@@ -307,8 +322,8 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
#endif
log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
- procmon->log_domain, "Monitored process %d is %s.",
- (int)procmon->pid,
+ procmon->log_domain, "Monitored process "PID_T_FORMAT" is %s.",
+ procmon->pid,
its_dead_jim ? "dead" : "still alive");
if (its_dead_jim) {
diff --git a/src/common/sha256.c b/src/common/sha256.c
deleted file mode 100644
index 813c68d2a3..0000000000
--- a/src/common/sha256.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/* Copyright (c) 2009-2012, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-/* This SHA256 implementation is adapted from the public domain one in
- LibTomCrypt, version 1.6. Tor uses it on platforms where OpenSSL doesn't
- have a SHA256. */
-
-
-typedef struct sha256_state {
- uint64_t length;
- uint32_t state[8], curlen;
- unsigned char buf[64];
-} sha256_state;
-
-#define CRYPT_OK 0
-#define CRYPT_NOP -1
-#define CRYPT_INVALID_ARG -2
-
-#define LOAD32H(x,y) STMT_BEGIN x = ntohl(get_uint32((const char*)y)); STMT_END
-#define STORE32H(x,y) STMT_BEGIN set_uint32((char*)y, htonl(x)); STMT_END
-#define STORE64H(x,y) STMT_BEGIN \
- set_uint32((char*)y, htonl((uint32_t)((x)>>32))); \
- set_uint32(((char*)y)+4, htonl((uint32_t)((x)&0xffffffff))); \
- STMT_END
-#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#ifndef MIN
- #define MIN(x, y) ( ((x)<(y))?(x):(y) )
-#endif
-
-
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
- */
-
-/**
- @file sha256.c
- SHA256 by Tom St Denis
-*/
-
-
-#ifdef LTC_SMALL_CODE
-/* the K array */
-static const uint32_t K[64] = {
- 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
- 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
- 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
- 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
- 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
- 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
- 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
- 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
- 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
- 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
- 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
- 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
- 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
-};
-#endif
-
-/* Various logical functions */
-#define Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Maj(x,y,z) (((x | y) & z) | (x & y))
-#define S(x, n) RORc((x),(n))
-#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
-#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
-#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
-#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
-#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
-
-/* compress 512-bits */
-#ifdef LTC_CLEAN_STACK
-static int _sha256_compress(sha256_state * md, unsigned char *buf)
-#else
-static int sha256_compress(sha256_state * md, unsigned char *buf)
-#endif
-{
- uint32_t S[8], W[64], t0, t1;
-#ifdef LTC_SMALL_CODE
- uint32_t t;
-#endif
- int i;
-
- /* copy state into S */
- for (i = 0; i < 8; i++) {
- S[i] = md->state[i];
- }
-
- /* copy the state into 512-bits into W[0..15] */
- for (i = 0; i < 16; i++) {
- LOAD32H(W[i], buf + (4*i));
- }
-
- /* fill W[16..63] */
- for (i = 16; i < 64; i++) {
- W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
- }
-
- /* Compress */
-#ifdef LTC_SMALL_CODE
-#define RND(a,b,c,d,e,f,g,h,i) \
- t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
- t1 = Sigma0(a) + Maj(a, b, c); \
- d += t0; \
- h = t0 + t1;
-
- for (i = 0; i < 64; ++i) {
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i);
- t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
- S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
- }
-#else
-#define RND(a,b,c,d,e,f,g,h,i,ki) \
- t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
- t1 = Sigma0(a) + Maj(a, b, c); \
- d += t0; \
- h = t0 + t1;
-
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
-
-#undef RND
-
-#endif
-
- /* feedback */
- for (i = 0; i < 8; i++) {
- md->state[i] = md->state[i] + S[i];
- }
- return CRYPT_OK;
-}
-
-#ifdef LTC_CLEAN_STACK
-static int sha256_compress(sha256_state * md, unsigned char *buf)
-{
- int err;
- err = _sha256_compress(md, buf);
- burn_stack(sizeof(uint32_t) * 74);
- return err;
-}
-#endif
-
-/**
- Initialize the hash state
- @param md The hash state you wish to initialize
- @return CRYPT_OK if successful
-*/
-static int sha256_init(sha256_state * md)
-{
- LTC_ARGCHK(md != NULL);
-
- md->curlen = 0;
- md->length = 0;
- md->state[0] = 0x6A09E667UL;
- md->state[1] = 0xBB67AE85UL;
- md->state[2] = 0x3C6EF372UL;
- md->state[3] = 0xA54FF53AUL;
- md->state[4] = 0x510E527FUL;
- md->state[5] = 0x9B05688CUL;
- md->state[6] = 0x1F83D9ABUL;
- md->state[7] = 0x5BE0CD19UL;
- return CRYPT_OK;
-}
-
-/**
- Process a block of memory though the hash
- @param md The hash state
- @param in The data to hash
- @param inlen The length of the data (octets)
- @return CRYPT_OK if successful
-*/
-static int sha256_process (sha256_state * md, const unsigned char *in, unsigned long inlen)
-{
- unsigned long n;
- int err;
- LTC_ARGCHK(md != NULL);
- LTC_ARGCHK(in != NULL);
- if (md->curlen > sizeof(md->buf)) {
- return CRYPT_INVALID_ARG;
- }
- while (inlen > 0) {
- if (md->curlen == 0 && inlen >= 64) {
- if ((err = sha256_compress (md, (unsigned char *)in)) != CRYPT_OK) {
- return err;
- }
- md->length += 64 * 8;
- in += 64;
- inlen -= 64;
- } else {
- n = MIN(inlen, (64 - md->curlen));
- memcpy(md->buf + md->curlen, in, (size_t)n);
- md->curlen += n;
- in += n;
- inlen -= n;
- if (md->curlen == 64) {
- if ((err = sha256_compress (md, md->buf)) != CRYPT_OK) {
- return err;
- }
- md->length += 8*64;
- md->curlen = 0;
- }
- }
- }
- return CRYPT_OK;
-}
-
-/**
- Terminate the hash to get the digest
- @param md The hash state
- @param out [out] The destination of the hash (32 bytes)
- @return CRYPT_OK if successful
-*/
-static int sha256_done(sha256_state * md, unsigned char *out)
-{
- int i;
-
- LTC_ARGCHK(md != NULL);
- LTC_ARGCHK(out != NULL);
-
- if (md->curlen >= sizeof(md->buf)) {
- return CRYPT_INVALID_ARG;
- }
-
-
- /* increase the length of the message */
- md->length += md->curlen * 8;
-
- /* append the '1' bit */
- md->buf[md->curlen++] = (unsigned char)0x80;
-
- /* if the length is currently above 56 bytes we append zeros
- * then compress. Then we can fall back to padding zeros and length
- * encoding like normal.
- */
- if (md->curlen > 56) {
- while (md->curlen < 64) {
- md->buf[md->curlen++] = (unsigned char)0;
- }
- sha256_compress(md, md->buf);
- md->curlen = 0;
- }
-
- /* pad upto 56 bytes of zeroes */
- while (md->curlen < 56) {
- md->buf[md->curlen++] = (unsigned char)0;
- }
-
- /* store length */
- STORE64H(md->length, md->buf+56);
- sha256_compress(md, md->buf);
-
- /* copy output */
- for (i = 0; i < 8; i++) {
- STORE32H(md->state[i], out+(4*i));
- }
-#ifdef LTC_CLEAN_STACK
- zeromem(md, sizeof(sha256_state));
-#endif
- return CRYPT_OK;
-}
-
-/* $Source: /cvs/libtom/libtomcrypt/src/hashes/sha2/sha256.c,v $ */
-/* $Revision: 1.9 $ */
-/* $Date: 2006/11/01 09:28:17 $ */
diff --git a/src/common/torgzip.h b/src/common/torgzip.h
index d3ded81f9c..921b232b0f 100644
--- a/src/common/torgzip.h
+++ b/src/common/torgzip.h
@@ -8,8 +8,8 @@
* \brief Headers for torgzip.h
**/
-#ifndef _TOR_TORGZIP_H
-#define _TOR_TORGZIP_H
+#ifndef TOR_TORGZIP_H
+#define TOR_TORGZIP_H
/** Enumeration of what kind of compression to use. Only ZLIB_METHOD is
* guaranteed to be supported by the compress/uncompress functions here;
diff --git a/src/common/torint.h b/src/common/torint.h
index 8771802d70..0db9cc7e24 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -8,8 +8,8 @@
* \brief Header file to define uint32_t and friends
**/
-#ifndef _TOR_TORINT_H
-#define _TOR_TORINT_H
+#ifndef TOR_TORINT_H
+#define TOR_TORINT_H
#include "orconfig.h"
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 28890a44af..ab97f9c9a7 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -10,7 +10,7 @@
* \brief Headers for log.c
**/
-#ifndef _TOR_LOG_H
+#ifndef TOR_TORLOG_H
#include "compat.h"
@@ -94,8 +94,10 @@
#define LD_HANDSHAKE (1u<<19)
/** Heartbeat messages */
#define LD_HEARTBEAT (1u<<20)
+/** Abstract channel_t code */
+#define LD_CHANNEL (1u<<21)
/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 21
+#define N_LOGGING_DOMAINS 22
/** This log message is not safe to send to a callback-based logger
* immediately. Used as a flag, not a log domain. */
@@ -154,63 +156,63 @@ void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
#define log tor_log /* hack it so we don't conflict with log() as much */
#if defined(__GNUC__) || defined(RUNNING_DOXYGEN)
-extern int _log_global_min_severity;
+extern int log_global_min_severity_;
-void _log_fn(int severity, log_domain_mask_t domain,
+void log_fn_(int severity, log_domain_mask_t domain,
const char *funcname, const char *format, ...)
CHECK_PRINTF(4,5);
/** Log a message at level <b>severity</b>, using a pretty-printed version
* of the current function name. */
#define log_fn(severity, domain, args...) \
- _log_fn(severity, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(severity, domain, __PRETTY_FUNCTION__, args)
#define log_debug(domain, args...) \
STMT_BEGIN \
- if (PREDICT_UNLIKELY(_log_global_min_severity == LOG_DEBUG)) \
- _log_fn(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \
+ if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \
+ log_fn_(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \
STMT_END
#define log_info(domain, args...) \
- _log_fn(LOG_INFO, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_INFO, domain, __PRETTY_FUNCTION__, args)
#define log_notice(domain, args...) \
- _log_fn(LOG_NOTICE, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_NOTICE, domain, __PRETTY_FUNCTION__, args)
#define log_warn(domain, args...) \
- _log_fn(LOG_WARN, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_WARN, domain, __PRETTY_FUNCTION__, args)
#define log_err(domain, args...) \
- _log_fn(LOG_ERR, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_ERR, domain, __PRETTY_FUNCTION__, args)
#else /* ! defined(__GNUC__) */
-void _log_fn(int severity, log_domain_mask_t domain, const char *format, ...);
-void _log_debug(log_domain_mask_t domain, const char *format, ...);
-void _log_info(log_domain_mask_t domain, const char *format, ...);
-void _log_notice(log_domain_mask_t domain, const char *format, ...);
-void _log_warn(log_domain_mask_t domain, const char *format, ...);
-void _log_err(log_domain_mask_t domain, const char *format, ...);
+void log_fn_(int severity, log_domain_mask_t domain, const char *format, ...);
+void log_debug_(log_domain_mask_t domain, const char *format, ...);
+void log_info_(log_domain_mask_t domain, const char *format, ...);
+void log_notice_(log_domain_mask_t domain, const char *format, ...);
+void log_warn_(log_domain_mask_t domain, const char *format, ...);
+void log_err_(log_domain_mask_t domain, const char *format, ...);
#if defined(_MSC_VER) && _MSC_VER < 1300
/* MSVC 6 and earlier don't have __func__, or even __LINE__. */
-#define log_fn _log_fn
-#define log_debug _log_debug
-#define log_info _log_info
-#define log_notice _log_notice
-#define log_warn _log_warn
-#define log_err _log_err
+#define log_fn log_fn_
+#define log_debug log_debug_
+#define log_info log_info_
+#define log_notice log_notice_
+#define log_warn log_warn_
+#define log_err log_err_
#else
/* We don't have GCC's varargs macros, so use a global variable to pass the
* function name to log_fn */
-extern const char *_log_fn_function_name;
+extern const char *log_fn_function_name_;
/* We abuse the comma operator here, since we can't use the standard
* do {...} while (0) trick to wrap this macro, since the macro can't take
* arguments. */
-#define log_fn (_log_fn_function_name=__func__),_log_fn
-#define log_debug (_log_fn_function_name=__func__),_log_debug
-#define log_info (_log_fn_function_name=__func__),_log_info
-#define log_notice (_log_fn_function_name=__func__),_log_notice
-#define log_warn (_log_fn_function_name=__func__),_log_warn
-#define log_err (_log_fn_function_name=__func__),_log_err
+#define log_fn (log_fn_function_name_=__func__),log_fn_
+#define log_debug (log_fn_function_name_=__func__),log_debug_
+#define log_info (log_fn_function_name_=__func__),log_info_
+#define log_notice (log_fn_function_name_=__func__),log_notice_
+#define log_warn (log_fn_function_name_=__func__),log_warn_
+#define log_err (log_fn_function_name_=__func__),log_err_
#endif
#endif /* !GNUC */
-# define _TOR_LOG_H
+# define TOR_TORLOG_H
#endif
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 60aac64929..af3059a02d 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -58,8 +58,8 @@
#include "container.h"
#include <string.h>
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
-#error "We require OpenSSL >= 0.9.7"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
+#error "We require OpenSSL >= 0.9.8"
#endif
/* Enable the "v2" TLS handshake.
@@ -234,8 +234,8 @@ static tor_tls_context_t *client_tls_context = NULL;
static int tls_library_is_initialized = 0;
/* Module-internal error codes. */
-#define _TOR_TLS_SYSCALL (_MIN_TOR_TLS_ERROR_VAL - 2)
-#define _TOR_TLS_ZERORETURN (_MIN_TOR_TLS_ERROR_VAL - 1)
+#define TOR_TLS_SYSCALL_ (MIN_TOR_TLS_ERROR_VAL_ - 2)
+#define TOR_TLS_ZERORETURN_ (MIN_TOR_TLS_ERROR_VAL_ - 1)
/** Write a description of the current state of <b>tls</b> into the
* <b>sz</b>-byte buffer at <b>buf</b>. */
@@ -393,9 +393,9 @@ tor_tls_err_to_string(int err)
/** Given a TLS object and the result of an SSL_* call, use
* SSL_get_error to determine whether an error has occurred, and if so
* which one. Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}.
- * If extra&CATCH_SYSCALL is true, return _TOR_TLS_SYSCALL instead of
+ * If extra&CATCH_SYSCALL is true, return TOR_TLS_SYSCALL_ instead of
* reporting syscall errors. If extra&CATCH_ZERO is true, return
- * _TOR_TLS_ZERORETURN instead of reporting zero-return errors.
+ * TOR_TLS_ZERORETURN_ instead of reporting zero-return errors.
*
* If an error has occurred, log it at level <b>severity</b> and describe the
* current action as <b>doing</b>.
@@ -415,7 +415,7 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
return TOR_TLS_WANTWRITE;
case SSL_ERROR_SYSCALL:
if (extra&CATCH_SYSCALL)
- return _TOR_TLS_SYSCALL;
+ return TOR_TLS_SYSCALL_;
if (r == 0) {
log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
doing, SSL_state_string_long(tls->ssl));
@@ -432,7 +432,7 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
return tor_error;
case SSL_ERROR_ZERO_RETURN:
if (extra&CATCH_ZERO)
- return _TOR_TLS_ZERORETURN;
+ return TOR_TLS_ZERORETURN_;
log(severity, LD_NET, "TLS connection closed while %s in state %s",
doing, SSL_state_string_long(tls->ssl));
tls_log_errors(tls, severity, domain, doing);
@@ -478,7 +478,7 @@ tor_tls_init(void)
* a test of intelligence and determination.
*/
if (version > OPENSSL_V(0,9,8,'k') && version <= OPENSSL_V(0,9,8,'l')) {
- log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
+ log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
"some vendors have backported renegotiation code from "
"0.9.8m without updating the version number. "
"I will try SSL3_FLAGS and SSL_OP to enable renegotation.",
@@ -486,12 +486,12 @@ tor_tls_init(void)
use_unsafe_renegotiation_flag = 1;
use_unsafe_renegotiation_op = 1;
} else if (version > OPENSSL_V(0,9,8,'l')) {
- log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
+ log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
"I will try SSL_OP to enable renegotiation",
SSLeay_version(SSLEAY_VERSION));
use_unsafe_renegotiation_op = 1;
} else if (version <= OPENSSL_V(0,9,8,'k')) {
- log_notice(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
+ log_info(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
"0.9.8l, but some vendors have backported 0.9.8l's "
"renegotiation code to earlier versions, and some have "
"backported the code from 0.9.8m or 0.9.8n. I'll set both "
@@ -597,9 +597,9 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
tor_assert(cname);
tor_assert(rsa_sign);
tor_assert(cname_sign);
- if (!(sign_pkey = _crypto_pk_get_evp_pkey(rsa_sign,1)))
+ if (!(sign_pkey = crypto_pk_get_evp_pkey_(rsa_sign,1)))
goto error;
- if (!(pkey = _crypto_pk_get_evp_pkey(rsa,0)))
+ if (!(pkey = crypto_pk_get_evp_pkey_(rsa,0)))
goto error;
if (!(x509 = X509_new()))
goto error;
@@ -754,7 +754,7 @@ tor_cert_new(X509 *x509_cert)
if ((pkey = X509_get_pubkey(x509_cert)) &&
(rsa = EVP_PKEY_get1_RSA(pkey))) {
- crypto_pk_t *pk = _crypto_new_pk_from_rsa(rsa);
+ crypto_pk_t *pk = crypto_new_pk_from_rsa_(rsa);
crypto_pk_get_all_digests(pk, &cert->pkey_digests);
cert->pkey_digests_set = 1;
crypto_pk_free(pk);
@@ -778,13 +778,8 @@ tor_cert_decode(const uint8_t *certificate, size_t certificate_len)
if (certificate_len > INT_MAX)
return NULL;
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
- /* This ifdef suppresses a type warning. Take out this case once everybody
- * is using OpenSSL 0.9.8 or later. */
- x509 = d2i_X509(NULL, (unsigned char**)&cp, (int)certificate_len);
-#else
x509 = d2i_X509(NULL, &cp, (int)certificate_len);
-#endif
+
if (!x509)
return NULL; /* Couldn't decode */
if (cp - certificate != (int)certificate_len) {
@@ -901,7 +896,7 @@ tor_tls_cert_get_key(tor_cert_t *cert)
EVP_PKEY_free(pkey);
return NULL;
}
- result = _crypto_new_pk_from_rsa(rsa);
+ result = crypto_new_pk_from_rsa_(rsa);
EVP_PKEY_free(pkey);
return result;
}
@@ -1199,9 +1194,16 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
* using them can make our perfect forward secrecy a little worse, *and*
* create an opportunity to fingerprint us (since it's unusual to use them
* with TLS sessions turned off).
+ *
+ * In 0.2.4, clients advertise support for them though, to avoid a TLS
+ * distinguishability vector. This can give us worse PFS, though, if we
+ * get a server that doesn't set SSL_OP_NO_TICKET. With luck, there will
+ * be few such servers by the time 0.2.4 is more stable.
*/
#ifdef SSL_OP_NO_TICKET
- SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
+ if (! is_client) {
+ SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
+ }
#endif
if (
@@ -1257,7 +1259,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
if (!is_client) {
tor_assert(rsa);
- if (!(pkey = _crypto_pk_get_evp_pkey(rsa,1)))
+ if (!(pkey = crypto_pk_get_evp_pkey_(rsa,1)))
goto error;
if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
goto error;
@@ -1269,7 +1271,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
{
crypto_dh_t *dh = crypto_dh_new(DH_TYPE_TLS);
tor_assert(dh);
- SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_get_dh(dh));
+ SSL_CTX_set_tmp_dh(result->ctx, crypto_dh_get_dh_(dh));
crypto_dh_free(dh);
}
SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
@@ -1761,7 +1763,7 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
return r;
}
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
- if (err == _TOR_TLS_ZERORETURN || err == TOR_TLS_CLOSE) {
+ if (err == TOR_TLS_ZERORETURN_ || err == TOR_TLS_CLOSE) {
log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
tls->state = TOR_TLS_ST_CLOSED;
return TOR_TLS_CLOSE;
@@ -1974,7 +1976,7 @@ tor_tls_shutdown(tor_tls_t *tls)
} while (r>0);
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
LOG_INFO, LD_NET);
- if (err == _TOR_TLS_ZERORETURN) {
+ if (err == TOR_TLS_ZERORETURN_) {
tls->state = TOR_TLS_ST_GOTCLOSE;
/* fall through... */
} else {
@@ -1990,11 +1992,11 @@ tor_tls_shutdown(tor_tls_t *tls)
}
err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
LOG_INFO, LD_NET);
- if (err == _TOR_TLS_SYSCALL) {
+ if (err == TOR_TLS_SYSCALL_) {
/* The underlying TCP connection closed while we were shutting down. */
tls->state = TOR_TLS_ST_CLOSED;
return TOR_TLS_DONE;
- } else if (err == _TOR_TLS_ZERORETURN) {
+ } else if (err == TOR_TLS_ZERORETURN_) {
/* The TLS connection says that it sent a shutdown record, but
* isn't done shutting down yet. Make sure that this hasn't
* happened before, then go back to the start of the function
@@ -2075,7 +2077,7 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem)
BIO_get_mem_ptr(bio, &buf);
s2 = tor_strndup(buf->data, buf->length);
- strftime(mytime, 32, "%b %d %H:%M:%S %Y GMT", tor_gmtime_r(&now, &tm));
+ strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm));
log(severity, LD_GENERAL,
"(certificate lifetime runs from %s through %s. Your time is %s.)",
@@ -2164,7 +2166,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
rsa = EVP_PKEY_get1_RSA(id_pkey);
if (!rsa)
goto done;
- *identity_key = _crypto_new_pk_from_rsa(rsa);
+ *identity_key = crypto_new_pk_from_rsa_(rsa);
r = 0;
@@ -2294,7 +2296,7 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written)
/** Implement check_no_tls_errors: If there are any pending OpenSSL
* errors, log an error message. */
void
-_check_no_tls_errors(const char *fname, int line)
+check_no_tls_errors_(const char *fname, int line)
{
if (ERR_peek_error() == 0)
return;
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 491a5419df..7bc6c8e76b 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -3,8 +3,8 @@
* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_TORTLS_H
-#define _TOR_TORTLS_H
+#ifndef TOR_TORTLS_H
+#define TOR_TORTLS_H
/**
* \file tortls.h
@@ -21,7 +21,7 @@ typedef struct tor_tls_t tor_tls_t;
typedef struct tor_cert_t tor_cert_t;
/* Possible return values for most tor_tls_* functions. */
-#define _MIN_TOR_TLS_ERROR_VAL -9
+#define MIN_TOR_TLS_ERROR_VAL_ -9
#define TOR_TLS_ERROR_MISC -9
/* Rename to unexpected close or something. XXXX */
#define TOR_TLS_ERROR_IO -8
@@ -98,9 +98,9 @@ int tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out);
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
*/
-#define check_no_tls_errors() _check_no_tls_errors(__FILE__,__LINE__)
+#define check_no_tls_errors() check_no_tls_errors_(__FILE__,__LINE__)
-void _check_no_tls_errors(const char *fname, int line);
+void check_no_tls_errors_(const char *fname, int line);
void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
int severity, int domain, const char *doing);
diff --git a/src/common/util.c b/src/common/util.c
index 6fb597a3a5..61d09aa4a8 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -39,8 +39,8 @@
#endif
/* math.h needs this on Linux */
-#ifndef __USE_ISOC99
-#define __USE_ISOC99 1
+#ifndef _USE_ISOC99_
+#define _USE_ISOC99_ 1
#endif
#include <math.h>
#include <stdlib.h>
@@ -125,7 +125,7 @@
* ignored otherwise.
*/
void *
-_tor_malloc(size_t size DMALLOC_PARAMS)
+tor_malloc_(size_t size DMALLOC_PARAMS)
{
void *result;
@@ -159,7 +159,7 @@ _tor_malloc(size_t size DMALLOC_PARAMS)
* the process on error. (Same as calloc(size,1), but never returns NULL.)
*/
void *
-_tor_malloc_zero(size_t size DMALLOC_PARAMS)
+tor_malloc_zero_(size_t size DMALLOC_PARAMS)
{
/* You may ask yourself, "wouldn't it be smart to use calloc instead of
* malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
@@ -167,7 +167,7 @@ _tor_malloc_zero(size_t size DMALLOC_PARAMS)
* we're allocating something very big (it knows if it just got the memory
* from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero
* for big stuff, so we don't bother with calloc. */
- void *result = _tor_malloc(size DMALLOC_FN_ARGS);
+ void *result = tor_malloc_(size DMALLOC_FN_ARGS);
memset(result, 0, size);
return result;
}
@@ -184,7 +184,7 @@ _tor_malloc_zero(size_t size DMALLOC_PARAMS)
* smaller than size). Don't do that then.
*/
void *
-_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
+tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS)
{
/* You may ask yourself, "wouldn't it be smart to use calloc instead of
* malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
@@ -197,7 +197,7 @@ _tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
tor_assert(nmemb < max_nmemb);
- result = _tor_malloc_zero((nmemb * size) DMALLOC_FN_ARGS);
+ result = tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS);
return result;
}
@@ -206,7 +206,7 @@ _tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
* terminate. (Like realloc(ptr,size), but never returns NULL.)
*/
void *
-_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS)
+tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS)
{
void *result;
@@ -230,7 +230,7 @@ _tor_realloc(void *ptr, size_t size DMALLOC_PARAMS)
* NULL.)
*/
char *
-_tor_strdup(const char *s DMALLOC_PARAMS)
+tor_strdup_(const char *s DMALLOC_PARAMS)
{
char *dup;
tor_assert(s);
@@ -254,12 +254,12 @@ _tor_strdup(const char *s DMALLOC_PARAMS)
* NULL.)
*/
char *
-_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
+tor_strndup_(const char *s, size_t n DMALLOC_PARAMS)
{
char *dup;
tor_assert(s);
tor_assert(n < SIZE_T_CEILING);
- dup = _tor_malloc((n+1) DMALLOC_FN_ARGS);
+ dup = tor_malloc_((n+1) DMALLOC_FN_ARGS);
/* Performance note: Ordinarily we prefer strlcpy to strncpy. But
* this function gets called a whole lot, and platform strncpy is
* much faster than strlcpy when strlen(s) is much longer than n.
@@ -272,12 +272,12 @@ _tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
/** Allocate a chunk of <b>len</b> bytes, with the same contents as the
* <b>len</b> bytes starting at <b>mem</b>. */
void *
-_tor_memdup(const void *mem, size_t len DMALLOC_PARAMS)
+tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS)
{
char *dup;
tor_assert(len < SIZE_T_CEILING);
tor_assert(mem);
- dup = _tor_malloc(len DMALLOC_FN_ARGS);
+ dup = tor_malloc_(len DMALLOC_FN_ARGS);
memcpy(dup, mem, len);
return dup;
}
@@ -285,42 +285,11 @@ _tor_memdup(const void *mem, size_t len DMALLOC_PARAMS)
/** Helper for places that need to take a function pointer to the right
* spelling of "free()". */
void
-_tor_free(void *mem)
+tor_free_(void *mem)
{
tor_free(mem);
}
-#if defined(HAVE_MALLOC_GOOD_SIZE) && !defined(HAVE_MALLOC_GOOD_SIZE_PROTOTYPE)
-/* Some version of Mac OSX have malloc_good_size in their libc, but not
- * actually defined in malloc/malloc.h. We detect this and work around it by
- * prototyping.
- */
-extern size_t malloc_good_size(size_t size);
-#endif
-
-/** Allocate and return a chunk of memory of size at least *<b>size</b>, using
- * the same resources we would use to malloc *<b>sizep</b>. Set *<b>sizep</b>
- * to the number of usable bytes in the chunk of memory. */
-void *
-_tor_malloc_roundup(size_t *sizep DMALLOC_PARAMS)
-{
-#ifdef HAVE_MALLOC_GOOD_SIZE
- tor_assert(*sizep < SIZE_T_CEILING);
- *sizep = malloc_good_size(*sizep);
- return _tor_malloc(*sizep DMALLOC_FN_ARGS);
-#elif 0 && defined(HAVE_MALLOC_USABLE_SIZE) && !defined(USE_DMALLOC)
- /* Never use malloc_usable_size(); it makes valgrind really unhappy,
- * and doesn't win much in terms of usable space where it exists. */
- void *result;
- tor_assert(*sizep < SIZE_T_CEILING);
- result = _tor_malloc(*sizep DMALLOC_FN_ARGS);
- *sizep = malloc_usable_size(result);
- return result;
-#else
- return _tor_malloc(*sizep DMALLOC_FN_ARGS);
-#endif
-}
-
/** Call the platform malloc info function, and dump the results to the log at
* level <b>severity</b>. If no such function exists, do nothing. */
void
@@ -363,9 +332,9 @@ tor_mathlog(double d)
return log(d);
}
-/** Return the long integer closest to d. We define this wrapper here so
- * that not all users of math.h need to use the right incancations to get
- * the c99 functions. */
+/** Return the long integer closest to <b>d</b>. We define this wrapper
+ * here so that not all users of math.h need to use the right incantations
+ * to get the c99 functions. */
long
tor_lround(double d)
{
@@ -378,6 +347,21 @@ tor_lround(double d)
#endif
}
+/** Return the 64-bit integer closest to d. We define this wrapper here so
+ * that not all users of math.h need to use the right incantations to get the
+ * c99 functions. */
+int64_t
+tor_llround(double d)
+{
+#if defined(HAVE_LLROUND)
+ return (int64_t)llround(d);
+#elif defined(HAVE_RINT)
+ return (int64_t)rint(d);
+#else
+ return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5));
+#endif
+}
+
/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */
int
tor_log2(uint64_t u64)
@@ -410,12 +394,24 @@ tor_log2(uint64_t u64)
return r;
}
-/** Return the power of 2 closest to <b>u64</b>. */
+/** Return the power of 2 in range [1,UINT64_MAX] closest to <b>u64</b>. If
+ * there are two powers of 2 equally close, round down. */
uint64_t
round_to_power_of_2(uint64_t u64)
{
- int lg2 = tor_log2(u64);
- uint64_t low = U64_LITERAL(1) << lg2, high = U64_LITERAL(1) << (lg2+1);
+ int lg2;
+ uint64_t low;
+ uint64_t high;
+ if (u64 == 0)
+ return 1;
+
+ lg2 = tor_log2(u64);
+ low = U64_LITERAL(1) << lg2;
+
+ if (lg2 == 63)
+ return low;
+
+ high = U64_LITERAL(1) << (lg2+1);
if (high - u64 < u64 - low)
return high;
else
@@ -655,6 +651,16 @@ fast_memcmpstart(const void *mem, size_t memlen,
return fast_memcmp(mem, prefix, plen);
}
+/** Given a nul-terminated string s, set every character before the nul
+ * to zero. */
+void
+tor_strclear(char *s)
+{
+ while (*s) {
+ *s++ = '\0';
+ }
+}
+
/** Return a pointer to the first char of s that is not whitespace and
* not a comment, or to the terminating NUL if no such character exists.
*/
@@ -1013,7 +1019,7 @@ base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */
static INLINE int
-_hex_decode_digit(char c)
+hex_decode_digit_(char c)
{
switch (c) {
case '0': return 0;
@@ -1041,7 +1047,7 @@ _hex_decode_digit(char c)
int
hex_decode_digit(char c)
{
- return _hex_decode_digit(c);
+ return hex_decode_digit_(c);
}
/** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode it
@@ -1059,8 +1065,8 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
return -1;
end = src+srclen;
while (src<end) {
- v1 = _hex_decode_digit(*src);
- v2 = _hex_decode_digit(*(src+1));
+ v1 = hex_decode_digit_(*src);
+ v2 = hex_decode_digit_(*(src+1));
if (v1<0||v2<0)
return -1;
*(uint8_t*)dest = (v1<<4)|v2;
@@ -1160,15 +1166,15 @@ esc_for_log(const char *s)
const char *
escaped(const char *s)
{
- static char *_escaped_val = NULL;
- tor_free(_escaped_val);
+ static char *escaped_val_ = NULL;
+ tor_free(escaped_val_);
if (s)
- _escaped_val = esc_for_log(s);
+ escaped_val_ = esc_for_log(s);
else
- _escaped_val = NULL;
+ escaped_val_ = NULL;
- return _escaped_val;
+ return escaped_val_;
}
/** Rudimentary string wrapping code: given a un-wrapped <b>string</b> (no
@@ -1336,7 +1342,7 @@ n_leapdays(int y1, int y2)
static const int days_per_month[] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-/** Compute a time_t given a struct tm. The result is given in GMT, and
+/** Compute a time_t given a struct tm. The result is given in UTC, and
* does not account for leap seconds. Return 0 on success, -1 on failure.
*/
int
@@ -1377,10 +1383,11 @@ static const char *MONTH_NAMES[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-/** Set <b>buf</b> to the RFC1123 encoding of the GMT value of <b>t</b>.
+/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>.
* The buffer must be at least RFC1123_TIME_LEN+1 bytes long.
*
- * (RFC1123 format is Fri, 29 Sep 2006 15:54:20 GMT)
+ * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT"
+ * rather than "UTC".)
*/
void
format_rfc1123_time(char *buf, time_t t)
@@ -1398,8 +1405,11 @@ format_rfc1123_time(char *buf, time_t t)
memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
}
-/** Parse the RFC1123 encoding of some time (in GMT) from <b>buf</b>,
- * and store the result in *<b>t</b>.
+/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from
+ * <b>buf</b>, and store the result in *<b>t</b>.
+ *
+ * Note that we only accept the subset generated by format_rfc1123_time above,
+ * not the full range of formats suggested by RFC 1123.
*
* Return 0 on success, -1 on failure.
*/
@@ -1827,6 +1837,10 @@ file_status(const char *fname)
return FN_DIR;
else if (st.st_mode & S_IFREG)
return FN_FILE;
+#ifndef _WIN32
+ else if (st.st_mode & S_IFIFO)
+ return FN_FILE;
+#endif
else
return FN_ERROR;
}
@@ -2257,6 +2271,46 @@ write_bytes_to_new_file(const char *fname, const char *str, size_t len,
(bin?O_BINARY:O_TEXT));
}
+/**
+ * Read the contents of the open file <b>fd</b> presuming it is a FIFO
+ * (or similar) file descriptor for which the size of the file isn't
+ * known ahead of time. Return NULL on failure, and a NUL-terminated
+ * string on success. On success, set <b>sz_out</b> to the number of
+ * bytes read.
+ */
+char *
+read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out)
+{
+ ssize_t r;
+ size_t pos = 0;
+ char *string = NULL;
+ size_t string_max = 0;
+
+ if (max_bytes_to_read+1 >= SIZE_T_CEILING)
+ return NULL;
+
+ do {
+ /* XXXX This "add 1K" approach is a little goofy; if we care about
+ * performance here, we should be doubling. But in practice we shouldn't
+ * be using this function on big files anyway. */
+ string_max = pos + 1024;
+ if (string_max > max_bytes_to_read)
+ string_max = max_bytes_to_read + 1;
+ string = tor_realloc(string, string_max);
+ r = read(fd, string + pos, string_max - pos - 1);
+ if (r < 0) {
+ tor_free(string);
+ return NULL;
+ }
+
+ pos += r;
+ } while (r > 0 && pos < max_bytes_to_read);
+
+ *sz_out = pos;
+ string[pos] = '\0';
+ return string;
+}
+
/** Read the contents of <b>filename</b> into a newly allocated
* string; return the string on success or NULL on failure.
*
@@ -2305,6 +2359,22 @@ read_file_to_str(const char *filename, int flags, struct stat *stat_out)
return NULL;
}
+#ifndef _WIN32
+/** When we detect that we're reading from a FIFO, don't read more than
+ * this many bytes. It's insane overkill for most uses. */
+#define FIFO_READ_MAX (1024*1024)
+ if (S_ISFIFO(statbuf.st_mode)) {
+ size_t sz = 0;
+ string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz);
+ if (string && stat_out) {
+ statbuf.st_size = sz;
+ memcpy(stat_out, &statbuf, sizeof(struct stat));
+ }
+ close(fd);
+ return string;
+ }
+#endif
+
if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING)
return NULL;
@@ -2683,9 +2753,9 @@ digit_to_num(char d)
* success, store the result in <b>out</b>, advance bufp to the next
* character, and return 0. On failure, return -1. */
static int
-scan_unsigned(const char **bufp, unsigned *out, int width, int base)
+scan_unsigned(const char **bufp, unsigned long *out, int width, int base)
{
- unsigned result = 0;
+ unsigned long result = 0;
int scanned_so_far = 0;
const int hex = base==16;
tor_assert(base == 10 || base == 16);
@@ -2697,8 +2767,8 @@ scan_unsigned(const char **bufp, unsigned *out, int width, int base)
while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
&& scanned_so_far < width) {
int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
- unsigned new_result = result * base + digit;
- if (new_result > UINT32_MAX || new_result < result)
+ unsigned long new_result = result * base + digit;
+ if (new_result < result)
return -1; /* over/underflow. */
result = new_result;
++scanned_so_far;
@@ -2711,6 +2781,89 @@ scan_unsigned(const char **bufp, unsigned *out, int width, int base)
return 0;
}
+/** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b>
+ * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On
+ * success, store the result in <b>out</b>, advance bufp to the next
+ * character, and return 0. On failure, return -1. */
+static int
+scan_signed(const char **bufp, long *out, int width)
+{
+ int neg = 0;
+ unsigned long result = 0;
+
+ if (!bufp || !*bufp || !out)
+ return -1;
+ if (width<0)
+ width=MAX_SCANF_WIDTH;
+
+ if (**bufp == '-') {
+ neg = 1;
+ ++*bufp;
+ --width;
+ }
+
+ if (scan_unsigned(bufp, &result, width, 10) < 0)
+ return -1;
+
+ if (neg) {
+ if (result > ((unsigned long)LONG_MAX) + 1)
+ return -1; /* Underflow */
+ *out = -(long)result;
+ } else {
+ if (result > LONG_MAX)
+ return -1; /* Overflow */
+ *out = (long)result;
+ }
+
+ return 0;
+}
+
+/** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to
+ * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less
+ * than 0.) On success, store the result in <b>out</b>, advance bufp to the
+ * next character, and return 0. On failure, return -1. */
+static int
+scan_double(const char **bufp, double *out, int width)
+{
+ int neg = 0;
+ double result = 0;
+ int scanned_so_far = 0;
+
+ if (!bufp || !*bufp || !out)
+ return -1;
+ if (width<0)
+ width=MAX_SCANF_WIDTH;
+
+ if (**bufp == '-') {
+ neg = 1;
+ ++*bufp;
+ }
+
+ while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
+ const int digit = digit_to_num(*(*bufp)++);
+ result = result * 10 + digit;
+ ++scanned_so_far;
+ }
+ if (**bufp == '.') {
+ double fracval = 0, denominator = 1;
+ ++*bufp;
+ ++scanned_so_far;
+ while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
+ const int digit = digit_to_num(*(*bufp)++);
+ fracval = fracval * 10 + digit;
+ denominator *= 10;
+ ++scanned_so_far;
+ }
+ result += fracval / denominator;
+ }
+
+ if (!scanned_so_far) /* No actual digits scanned */
+ return -1;
+
+ *out = neg ? -result : result;
+ return 0;
+}
+
/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to
* <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b>
* to the next non-space character or the EOS. */
@@ -2747,6 +2900,7 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
}
} else {
int width = -1;
+ int longmod = 0;
++pattern;
if (TOR_ISDIGIT(*pattern)) {
width = digit_to_num(*pattern++);
@@ -2759,17 +2913,57 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
if (!width) /* No zero-width things. */
return -1;
}
+ if (*pattern == 'l') {
+ longmod = 1;
+ ++pattern;
+ }
if (*pattern == 'u' || *pattern == 'x') {
- unsigned *u = va_arg(ap, unsigned *);
+ unsigned long u;
const int base = (*pattern == 'u') ? 10 : 16;
if (!*buf)
return n_matched;
- if (scan_unsigned(&buf, u, width, base)<0)
+ if (scan_unsigned(&buf, &u, width, base)<0)
+ return n_matched;
+ if (longmod) {
+ unsigned long *out = va_arg(ap, unsigned long *);
+ *out = u;
+ } else {
+ unsigned *out = va_arg(ap, unsigned *);
+ if (u > UINT_MAX)
+ return n_matched;
+ *out = (unsigned) u;
+ }
+ ++pattern;
+ ++n_matched;
+ } else if (*pattern == 'f') {
+ double *d = va_arg(ap, double *);
+ if (!longmod)
+ return -1; /* float not supported */
+ if (!*buf)
+ return n_matched;
+ if (scan_double(&buf, d, width)<0)
return n_matched;
++pattern;
++n_matched;
+ } else if (*pattern == 'd') {
+ long lng=0;
+ if (scan_signed(&buf, &lng, width)<0)
+ return n_matched;
+ if (longmod) {
+ long *out = va_arg(ap, long *);
+ *out = lng;
+ } else {
+ int *out = va_arg(ap, int *);
+ if (lng < INT_MIN || lng > INT_MAX)
+ return n_matched;
+ *out = (int)lng;
+ }
+ ++pattern;
+ ++n_matched;
} else if (*pattern == 's') {
char *s = va_arg(ap, char *);
+ if (longmod)
+ return -1;
if (width < 0)
return -1;
if (scan_string(&buf, s, width)<0)
@@ -2778,6 +2972,8 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
++n_matched;
} else if (*pattern == 'c') {
char *ch = va_arg(ap, char *);
+ if (longmod)
+ return -1;
if (width != -1)
return -1;
if (!*buf)
@@ -2788,6 +2984,8 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
} else if (*pattern == '%') {
if (*buf != '%')
return n_matched;
+ if (longmod)
+ return -1;
++buf;
++pattern;
} else {
@@ -2801,9 +2999,14 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b>
* and store the results in the corresponding argument fields. Differs from
- * sscanf in that it: Only handles %u, %x, %c and %Ns. Does not handle
- * arbitrarily long widths. %u and %x do not consume any space. Is
- * locale-independent. Returns -1 on malformed patterns.
+ * sscanf in that:
+ * <ul><li>It only handles %u, %lu, %x, %lx, %<NUM>s, %d, %ld, %lf, and %c.
+ * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1)
+ * <li>It does not handle arbitrarily long widths.
+ * <li>Numbers do not consume any space characters.
+ * <li>It is locale-independent.
+ * <li>%u and %x do not consume any space.
+ * <li>It returns -1 on malformed patterns.</ul>
*
* (As with other locale-independent functions, we need this to parse data that
* is in ASCII without worrying that the C library's locale-handling will make
@@ -3784,10 +3987,17 @@ tor_process_handle_destroy(process_handle_t *process_handle,
if (also_terminate_process) {
if (tor_terminate_process(process_handle) < 0) {
- log_notice(LD_GENERAL, "Failed to terminate process with PID '%d'",
- tor_process_get_pid(process_handle));
+ const char *errstr =
+#ifdef _WIN32
+ format_win32_error(GetLastError());
+#else
+ strerror(errno);
+#endif
+ log_notice(LD_GENERAL, "Failed to terminate process with "
+ "PID '%d' ('%s').", tor_process_get_pid(process_handle),
+ errstr);
} else {
- log_info(LD_GENERAL, "Terminated process with PID '%d'",
+ log_info(LD_GENERAL, "Terminated process with PID '%d'.",
tor_process_get_pid(process_handle));
}
}
@@ -4255,7 +4465,70 @@ tor_split_lines(smartlist_t *sl, char *buf, int len)
return smartlist_len(sl);
}
+/** Return a string corresponding to <b>stream_status</b>. */
+const char *
+stream_status_to_string(enum stream_status stream_status)
+{
+ switch (stream_status) {
+ case IO_STREAM_OKAY:
+ return "okay";
+ case IO_STREAM_EAGAIN:
+ return "temporarily unavailable";
+ case IO_STREAM_TERM:
+ return "terminated";
+ case IO_STREAM_CLOSED:
+ return "closed";
+ default:
+ tor_fragile_assert();
+ return "unknown";
+ }
+}
+
#ifdef _WIN32
+
+/** Return a smartlist containing lines outputted from
+ * <b>handle</b>. Return NULL on error, and set
+ * <b>stream_status_out</b> appropriately. */
+smartlist_t *
+tor_get_lines_from_handle(HANDLE *handle,
+ enum stream_status *stream_status_out)
+{
+ int pos;
+ char stdout_buf[600] = {0};
+ smartlist_t *lines = NULL;
+
+ tor_assert(stream_status_out);
+
+ *stream_status_out = IO_STREAM_TERM;
+
+ pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL);
+ if (pos < 0) {
+ *stream_status_out = IO_STREAM_TERM;
+ return NULL;
+ }
+ if (pos == 0) {
+ *stream_status_out = IO_STREAM_EAGAIN;
+ return NULL;
+ }
+
+ /* End with a null even if there isn't a \r\n at the end */
+ /* TODO: What if this is a partial line? */
+ stdout_buf[pos] = '\0';
+
+ /* Split up the buffer */
+ lines = smartlist_new();
+ tor_split_lines(lines, stdout_buf, pos);
+
+ /* Currently 'lines' is populated with strings residing on the
+ stack. Replace them with their exact copies on the heap: */
+ SMARTLIST_FOREACH(lines, char *, line,
+ SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line)));
+
+ *stream_status_out = IO_STREAM_OKAY;
+
+ return lines;
+}
+
/** Read from stream, and send lines to log at the specified log level.
* Returns -1 if there is a error reading, and 0 otherwise.
* If the generated stream is flushed more often than on new lines, or
@@ -4303,6 +4576,33 @@ log_from_handle(HANDLE *pipe, int severity)
#else
+/** Return a smartlist containing lines outputted from
+ * <b>handle</b>. Return NULL on error, and set
+ * <b>stream_status_out</b> appropriately. */
+smartlist_t *
+tor_get_lines_from_handle(FILE *handle, enum stream_status *stream_status_out)
+{
+ enum stream_status stream_status;
+ char stdout_buf[400];
+ smartlist_t *lines = NULL;
+
+ while (1) {
+ memset(stdout_buf, 0, sizeof(stdout_buf));
+
+ stream_status = get_string_from_pipe(handle,
+ stdout_buf, sizeof(stdout_buf) - 1);
+ if (stream_status != IO_STREAM_OKAY)
+ goto done;
+
+ if (!lines) lines = smartlist_new();
+ smartlist_add(lines, tor_strdup(stdout_buf));
+ }
+
+ done:
+ *stream_status_out = stream_status;
+ return lines;
+}
+
/** Read from stream, and send lines to log at the specified log level.
* Returns 1 if stream is closed normally, -1 if there is a error reading, and
* 0 otherwise. Handles lines from tor-fw-helper and
@@ -4421,9 +4721,130 @@ get_string_from_pipe(FILE *stream, char *buf_out, size_t count)
return IO_STREAM_TERM;
}
-/* DOCDOC tor_check_port_forwarding */
+/** Parse a <b>line</b> from tor-fw-helper and issue an appropriate
+ * log message to our user. */
+static void
+handle_fw_helper_line(const char *line)
+{
+ smartlist_t *tokens = smartlist_new();
+ char *message = NULL;
+ char *message_for_log = NULL;
+ const char *external_port = NULL;
+ const char *internal_port = NULL;
+ const char *result = NULL;
+ int port = 0;
+ int success = 0;
+
+ smartlist_split_string(tokens, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(tokens) < 5)
+ goto err;
+
+ if (strcmp(smartlist_get(tokens, 0), "tor-fw-helper") ||
+ strcmp(smartlist_get(tokens, 1), "tcp-forward"))
+ goto err;
+
+ external_port = smartlist_get(tokens, 2);
+ internal_port = smartlist_get(tokens, 3);
+ result = smartlist_get(tokens, 4);
+
+ if (smartlist_len(tokens) > 5) {
+ /* If there are more than 5 tokens, they are part of [<message>].
+ Let's use a second smartlist to form the whole message;
+ strncat loops suck. */
+ int i;
+ int message_words_n = smartlist_len(tokens) - 5;
+ smartlist_t *message_sl = smartlist_new();
+ for (i = 0; i < message_words_n; i++)
+ smartlist_add(message_sl, smartlist_get(tokens, 5+i));
+
+ tor_assert(smartlist_len(message_sl) > 0);
+ message = smartlist_join_strings(message_sl, " ", 0, NULL);
+
+ /* wrap the message in log-friendly wrapping */
+ tor_asprintf(&message_for_log, " ('%s')", message);
+
+ smartlist_free(message_sl);
+ }
+
+ port = atoi(external_port);
+ if (port < 1 || port > 65535)
+ goto err;
+
+ port = atoi(internal_port);
+ if (port < 1 || port > 65535)
+ goto err;
+
+ if (!strcmp(result, "SUCCESS"))
+ success = 1;
+ else if (!strcmp(result, "FAIL"))
+ success = 0;
+ else
+ goto err;
+
+ if (!success) {
+ log_warn(LD_GENERAL, "Tor was unable to forward TCP port '%s' to '%s'%s. "
+ "Please make sure that your router supports port "
+ "forwarding protocols (like NAT-PMP). Note that if '%s' is "
+ "your ORPort, your relay will be unable to receive inbound "
+ "traffic.", external_port, internal_port,
+ message_for_log ? message_for_log : "",
+ internal_port);
+ } else {
+ log_info(LD_GENERAL,
+ "Tor successfully forwarded TCP port '%s' to '%s'%s.",
+ external_port, internal_port,
+ message_for_log ? message_for_log : "");
+ }
+
+ goto done;
+
+ err:
+ log_warn(LD_GENERAL, "tor-fw-helper sent us a string we could not "
+ "parse (%s).", line);
+
+ done:
+ SMARTLIST_FOREACH(tokens, char *, cp, tor_free(cp));
+ smartlist_free(tokens);
+ tor_free(message);
+ tor_free(message_for_log);
+}
+
+/** Read what tor-fw-helper has to say in its stdout and handle it
+ * appropriately */
+static int
+handle_fw_helper_output(process_handle_t *process_handle)
+{
+ smartlist_t *fw_helper_output = NULL;
+ enum stream_status stream_status = 0;
+
+ fw_helper_output =
+ tor_get_lines_from_handle(tor_process_get_stdout_pipe(process_handle),
+ &stream_status);
+ if (!fw_helper_output) { /* didn't get any output from tor-fw-helper */
+ /* if EAGAIN we should retry in the future */
+ return (stream_status == IO_STREAM_EAGAIN) ? 0 : -1;
+ }
+
+ /* Handle the lines we got: */
+ SMARTLIST_FOREACH_BEGIN(fw_helper_output, char *, line) {
+ handle_fw_helper_line(line);
+ tor_free(line);
+ } SMARTLIST_FOREACH_END(line);
+
+ smartlist_free(fw_helper_output);
+
+ return 0;
+}
+
+/** Spawn tor-fw-helper and ask it to forward the ports in
+ * <b>ports_to_forward</b>. <b>ports_to_forward</b> contains strings
+ * of the form "<external port>:<internal port>", which is the format
+ * that tor-fw-helper expects. */
void
-tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
+tor_check_port_forwarding(const char *filename,
+ smartlist_t *ports_to_forward,
time_t now)
{
/* When fw-helper succeeds, how long do we wait until running it again */
@@ -4437,32 +4858,51 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
static process_handle_t *child_handle=NULL;
static time_t time_to_run_helper = 0;
- int stdout_status, stderr_status, retval;
- const char *argv[10];
- char s_dirport[6], s_orport[6];
+ int stderr_status, retval;
+ int stdout_status = 0;
tor_assert(filename);
- /* Set up command line for tor-fw-helper */
- snprintf(s_dirport, sizeof s_dirport, "%d", dir_port);
- snprintf(s_orport, sizeof s_orport, "%d", or_port);
-
- /* TODO: Allow different internal and external ports */
- argv[0] = filename;
- argv[1] = "--internal-or-port";
- argv[2] = s_orport;
- argv[3] = "--external-or-port";
- argv[4] = s_orport;
- argv[5] = "--internal-dir-port";
- argv[6] = s_dirport;
- argv[7] = "--external-dir-port";
- argv[8] = s_dirport;
- argv[9] = NULL;
-
/* Start the child, if it is not already running */
if ((!child_handle || child_handle->status != PROCESS_STATUS_RUNNING) &&
time_to_run_helper < now) {
- int status;
+ /*tor-fw-helper cli looks like this: tor_fw_helper -p :5555 -p 4555:1111 */
+ const char **argv; /* cli arguments */
+ int args_n, status;
+ int argv_index = 0; /* index inside 'argv' */
+
+ tor_assert(smartlist_len(ports_to_forward) > 0);
+
+ /* check for overflow during 'argv' allocation:
+ (len(ports_to_forward)*2 + 2)*sizeof(char*) > SIZE_MAX ==
+ len(ports_to_forward) > (((SIZE_MAX/sizeof(char*)) - 2)/2) */
+ if ((size_t) smartlist_len(ports_to_forward) >
+ (((SIZE_MAX/sizeof(char*)) - 2)/2)) {
+ log_warn(LD_GENERAL,
+ "Overflow during argv allocation. This shouldn't happen.");
+ return;
+ }
+ /* check for overflow during 'argv_index' increase:
+ ((len(ports_to_forward)*2 + 2) > INT_MAX) ==
+ len(ports_to_forward) > (INT_MAX - 2)/2 */
+ if (smartlist_len(ports_to_forward) > (INT_MAX - 2)/2) {
+ log_warn(LD_GENERAL,
+ "Overflow during argv_index increase. This shouldn't happen.");
+ return;
+ }
+
+ /* Calculate number of cli arguments: one for the filename, two
+ for each smartlist element (one for "-p" and one for the
+ ports), and one for the final NULL. */
+ args_n = 1 + 2*smartlist_len(ports_to_forward) + 1;
+ argv = tor_malloc_zero(sizeof(char*)*args_n);
+
+ argv[argv_index++] = filename;
+ SMARTLIST_FOREACH_BEGIN(ports_to_forward, const char *, port) {
+ argv[argv_index++] = "-p";
+ argv[argv_index++] = port;
+ } SMARTLIST_FOREACH_END(port);
+ argv[argv_index] = NULL;
/* Assume tor-fw-helper will succeed, start it later*/
time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_SUCCESS;
@@ -4479,6 +4919,8 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
status = tor_spawn_background(filename, argv, NULL, &child_handle);
#endif
+ tor_free(argv);
+
if (PROCESS_STATUS_ERROR == status) {
log_warn(LD_GENERAL, "Failed to start port forwarding helper %s",
filename);
@@ -4496,16 +4938,17 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
/* Read from stdout/stderr and log result */
retval = 0;
#ifdef _WIN32
- stdout_status = log_from_handle(child_handle->stdout_pipe, LOG_INFO);
- stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_WARN);
- /* If we got this far (on Windows), the process started */
- retval = 0;
+ stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO);
#else
- stdout_status = log_from_pipe(child_handle->stdout_handle,
- LOG_INFO, filename, &retval);
stderr_status = log_from_pipe(child_handle->stderr_handle,
- LOG_WARN, filename, &retval);
+ LOG_INFO, filename, &retval);
#endif
+ if (handle_fw_helper_output(child_handle) < 0) {
+ log_warn(LD_GENERAL, "Failed to handle fw helper output.");
+ stdout_status = -1;
+ retval = -1;
+ }
+
if (retval) {
/* There was a problem in the child process */
time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
diff --git a/src/common/util.h b/src/common/util.h
index 8977d273c5..fabfdb19fd 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -8,8 +8,8 @@
* \brief Headers for util.c
**/
-#ifndef _TOR_UTIL_H
-#define _TOR_UTIL_H
+#ifndef TOR_UTIL_H
+#define TOR_UTIL_H
#include "orconfig.h"
#include "torint.h"
@@ -49,9 +49,9 @@
#define tor_assert(expr) STMT_BEGIN \
if (PREDICT_UNLIKELY(!(expr))) { \
log_err(LD_BUG, "%s:%d: %s: Assertion %s failed; aborting.", \
- _SHORT_FILE_, __LINE__, __func__, #expr); \
+ SHORT_FILE__, __LINE__, __func__, #expr); \
fprintf(stderr,"%s:%d %s: Assertion %s failed; aborting.\n", \
- _SHORT_FILE_, __LINE__, __func__, #expr); \
+ SHORT_FILE__, __LINE__, __func__, #expr); \
abort(); \
} STMT_END
@@ -62,7 +62,7 @@
* to calls. */
#ifdef USE_DMALLOC
#define DMALLOC_PARAMS , const char *file, const int line
-#define DMALLOC_ARGS , _SHORT_FILE_, __LINE__
+#define DMALLOC_ARGS , SHORT_FILE__, __LINE__
#else
#define DMALLOC_PARAMS
#define DMALLOC_ARGS
@@ -74,23 +74,22 @@
#define tor_fragile_assert()
/* Memory management */
-void *_tor_malloc(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_malloc_zero(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_malloc_roundup(size_t *size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS);
-char *_tor_strdup(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
-char *_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
+void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS);
+char *tor_strdup_(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
+char *tor_strndup_(const char *s, size_t n DMALLOC_PARAMS)
ATTR_MALLOC ATTR_NONNULL((1));
-void *_tor_memdup(const void *mem, size_t len DMALLOC_PARAMS)
+void *tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS)
ATTR_MALLOC ATTR_NONNULL((1));
-void _tor_free(void *mem);
+void tor_free_(void *mem);
#ifdef USE_DMALLOC
extern int dmalloc_free(const char *file, const int line, void *pnt,
const int func_id);
#define tor_free(p) STMT_BEGIN \
if (PREDICT_LIKELY((p)!=NULL)) { \
- dmalloc_free(_SHORT_FILE_, __LINE__, (p), 0); \
+ dmalloc_free(SHORT_FILE__, __LINE__, (p), 0); \
(p)=NULL; \
} \
STMT_END
@@ -100,7 +99,7 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
* and it sets the pointer value to NULL after freeing it.
*
* This is a macro. If you need a function pointer to release memory from
- * tor_malloc(), use _tor_free().
+ * tor_malloc(), use tor_free_().
*/
#define tor_free(p) STMT_BEGIN \
if (PREDICT_LIKELY((p)!=NULL)) { \
@@ -110,14 +109,14 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
STMT_END
#endif
-#define tor_malloc(size) _tor_malloc(size DMALLOC_ARGS)
-#define tor_malloc_zero(size) _tor_malloc_zero(size DMALLOC_ARGS)
-#define tor_calloc(nmemb,size) _tor_calloc(nmemb, size DMALLOC_ARGS)
+#define tor_malloc(size) tor_malloc_(size DMALLOC_ARGS)
+#define tor_malloc_zero(size) tor_malloc_zero_(size DMALLOC_ARGS)
+#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size DMALLOC_ARGS)
#define tor_malloc_roundup(szp) _tor_malloc_roundup(szp DMALLOC_ARGS)
-#define tor_realloc(ptr, size) _tor_realloc(ptr, size DMALLOC_ARGS)
-#define tor_strdup(s) _tor_strdup(s DMALLOC_ARGS)
-#define tor_strndup(s, n) _tor_strndup(s, n DMALLOC_ARGS)
-#define tor_memdup(s, n) _tor_memdup(s, n DMALLOC_ARGS)
+#define tor_realloc(ptr, size) tor_realloc_(ptr, size DMALLOC_ARGS)
+#define tor_strdup(s) tor_strdup_(s DMALLOC_ARGS)
+#define tor_strndup(s, n) tor_strndup_(s, n DMALLOC_ARGS)
+#define tor_memdup(s, n) tor_memdup_(s, n DMALLOC_ARGS)
void tor_log_mallinfo(int severity);
@@ -161,6 +160,7 @@ void tor_log_mallinfo(int severity);
/* Math functions */
double tor_mathlog(double d) ATTR_CONST;
long tor_lround(double d) ATTR_CONST;
+int64_t tor_llround(double d) ATTR_CONST;
int tor_log2(uint64_t u64) ATTR_CONST;
uint64_t round_to_power_of_2(uint64_t u64);
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
@@ -188,6 +188,7 @@ int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix);
+void tor_strclear(char *s);
void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2));
long tor_parse_long(const char *s, int base, long min,
@@ -306,6 +307,8 @@ enum stream_status {
IO_STREAM_CLOSED
};
+const char *stream_status_to_string(enum stream_status stream_status);
+
enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
/** Return values from file_status(); see that function's documentation
@@ -360,6 +363,9 @@ struct stat;
#endif
char *read_file_to_str(const char *filename, int flags, struct stat *stat_out)
ATTR_MALLOC;
+char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read,
+ size_t *sz_out)
+ ATTR_MALLOC;
const char *parse_config_line_from_str(const char *line,
char **key_out, char **value_out);
char *expand_filename(const char *filename);
@@ -373,7 +379,8 @@ void write_pidfile(char *filename);
/* Port forwarding */
void tor_check_port_forwarding(const char *filename,
- int dir_port, int or_port, time_t now);
+ struct smartlist_t *ports_to_forward,
+ time_t now);
typedef struct process_handle_t process_handle_t;
typedef struct process_environment_t process_environment_t;
@@ -464,6 +471,16 @@ HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle);
FILE *tor_process_get_stdout_pipe(process_handle_t *process_handle);
#endif
+#ifdef _WIN32
+struct smartlist_t *
+tor_get_lines_from_handle(HANDLE *handle,
+ enum stream_status *stream_status);
+#else
+struct smartlist_t *
+tor_get_lines_from_handle(FILE *handle,
+ enum stream_status *stream_status);
+#endif
+
int tor_terminate_process(process_handle_t *process_handle);
void tor_process_handle_destroy(process_handle_t *process_handle,
int also_terminate_process);
diff --git a/src/config/Makefile.am b/src/config/Makefile.am
deleted file mode 100644
index 90dd218b40..0000000000
--- a/src/config/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-confdir = $(sysconfdir)/tor
-
-tordatadir = $(datadir)/tor
-
-EXTRA_DIST = geoip
-# fallback-consensus
-
-conf_DATA = torrc.sample
-
-tordata_DATA = geoip
-# fallback_consensus
-
-# If we don't have it, fake it.
-fallback-consensus:
- touch fallback-consensus
-
diff --git a/src/config/README.geoip b/src/config/README.geoip
new file mode 100644
index 0000000000..8520501405
--- /dev/null
+++ b/src/config/README.geoip
@@ -0,0 +1,90 @@
+README.geoip -- information on the IP-to-country-code file shipped with tor
+===========================================================================
+
+The IP-to-country-code file in src/config/geoip is based on MaxMind's
+GeoLite Country database with the following modifications:
+
+ - Those "A1" ("Anonymous Proxy") entries lying inbetween two entries with
+ the same country code are automatically changed to that country code.
+ These changes can be overriden by specifying a different country code
+ in src/config/geoip-manual.
+
+ - Other "A1" entries are replaced with country codes specified in
+ src/config/geoip-manual, or are left as is if there is no corresponding
+ entry in that file. Even non-"A1" entries can be modified by adding a
+ replacement entry to src/config/geoip-manual. Handle with care.
+
+
+1. Updating the geoip file from a MaxMind database file
+-------------------------------------------------------
+
+Download the most recent MaxMind GeoLite Country database:
+http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip
+
+Run `python deanonymind.py` in the local directory. Review the output to
+learn about applied automatic/manual changes and watch out for any
+warnings.
+
+Possibly edit geoip-manual to make more/fewer/different manual changes and
+re-run `python deanonymind.py`.
+
+When done, prepend the new geoip file with a comment like this:
+
+ # Last updated based on $DATE Maxmind GeoLite Country
+ # See README.geoip for details on the conversion.
+
+
+2. Verifying automatic and manual changes using diff
+----------------------------------------------------
+
+To unzip the original MaxMind file and look at the automatic changes, run:
+
+ unzip GeoIPCountryCSV.zip
+ diff -U1 GeoIPCountryWhois.csv AutomaticGeoIPCountryWhois.csv
+
+To look at subsequent manual changes, run:
+
+ diff -U1 AutomaticGeoIPCountryWhois.csv ManualGeoIPCountryWhois.csv
+
+To manually generate the geoip file and compare it to the automatically
+created one, run:
+
+ cut -d, -f3-5 < ManualGeoIPCountryWhois.csv | sed 's/"//g' > mygeoip
+ diff -U1 geoip mygeoip
+
+
+3. Verifying automatic and manual changes using blockfinder
+-----------------------------------------------------------
+
+Blockfinder is a powerful tool to handle multiple IP-to-country data
+sources. Blockfinder has a function to specify a country code and compare
+conflicting country code assignments in different data sources.
+
+We can use blockfinder to compare A1 entries in the original MaxMind file
+with the same or overlapping blocks in the file generated above and in the
+RIR delegation files:
+
+ git clone https://github.com/ioerror/blockfinder
+ cd blockfinder/
+ python blockfinder -i
+ python blockfinder -r ../GeoIPCountryWhois.csv
+ python blockfinder -r ../ManualGeoIPCountryWhois.csv
+ python blockfinder -p A1 > A1-comparison.txt
+
+The output marks conflicts between assignments using either '*' in case of
+two different opinions or '#' for three or more different opinions about
+the country code for a given block.
+
+The '*' conflicts are most likely harmless, because there will always be
+at least two opinions with the original MaxMind file saying A1 and the
+other two sources saying something more meaningful.
+
+However, watch out for '#' conflicts. In these cases, the original
+MaxMind file ("A1"), the updated MaxMind file (hopefully the correct
+country code), and the RIR delegation files (some other country code) all
+disagree.
+
+There are perfectly valid cases where the updated MaxMind file and the RIR
+delegation files don't agree. But each of those cases must be verified
+manually.
+
diff --git a/src/config/deanonymind.py b/src/config/deanonymind.py
new file mode 100755
index 0000000000..c86dadca99
--- /dev/null
+++ b/src/config/deanonymind.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python
+import optparse
+import os
+import sys
+import zipfile
+
+"""
+Take a MaxMind GeoLite Country database as input and replace A1 entries
+with the country code and name of the preceding entry iff the preceding
+(subsequent) entry ends (starts) directly before (after) the A1 entry and
+both preceding and subsequent entries contain the same country code.
+
+Then apply manual changes, either replacing A1 entries that could not be
+replaced automatically or overriding previously made automatic changes.
+"""
+
+def main():
+ options = parse_options()
+ assignments = read_file(options.in_maxmind)
+ assignments = apply_automatic_changes(assignments)
+ write_file(options.out_automatic, assignments)
+ manual_assignments = read_file(options.in_manual, must_exist=False)
+ assignments = apply_manual_changes(assignments, manual_assignments)
+ write_file(options.out_manual, assignments)
+ write_file(options.out_geoip, assignments, long_format=False)
+
+def parse_options():
+ parser = optparse.OptionParser()
+ parser.add_option('-i', action='store', dest='in_maxmind',
+ default='GeoIPCountryCSV.zip', metavar='FILE',
+ help='use the specified MaxMind GeoLite Country .zip or .csv '
+ 'file as input [default: %default]')
+ parser.add_option('-g', action='store', dest='in_manual',
+ default='geoip-manual', metavar='FILE',
+ help='use the specified .csv file for manual changes or to '
+ 'override automatic changes [default: %default]')
+ parser.add_option('-a', action='store', dest='out_automatic',
+ default="AutomaticGeoIPCountryWhois.csv", metavar='FILE',
+ help='write full input file plus automatic changes to the '
+ 'specified .csv file [default: %default]')
+ parser.add_option('-m', action='store', dest='out_manual',
+ default='ManualGeoIPCountryWhois.csv', metavar='FILE',
+ help='write full input file plus automatic and manual '
+ 'changes to the specified .csv file [default: %default]')
+ parser.add_option('-o', action='store', dest='out_geoip',
+ default='geoip', metavar='FILE',
+ help='write full input file plus automatic and manual '
+ 'changes to the specified .csv file that can be shipped '
+ 'with tor [default: %default]')
+ (options, args) = parser.parse_args()
+ return options
+
+def read_file(path, must_exist=True):
+ if not os.path.exists(path):
+ if must_exist:
+ print 'File %s does not exist. Exiting.' % (path, )
+ sys.exit(1)
+ else:
+ return
+ if path.endswith('.zip'):
+ zip_file = zipfile.ZipFile(path)
+ csv_content = zip_file.read('GeoIPCountryWhois.csv')
+ zip_file.close()
+ else:
+ csv_file = open(path)
+ csv_content = csv_file.read()
+ csv_file.close()
+ assignments = []
+ for line in csv_content.split('\n'):
+ stripped_line = line.strip()
+ if len(stripped_line) > 0 and not stripped_line.startswith('#'):
+ assignments.append(stripped_line)
+ return assignments
+
+def apply_automatic_changes(assignments):
+ print '\nApplying automatic changes...'
+ result_lines = []
+ prev_line = None
+ a1_lines = []
+ for line in assignments:
+ if '"A1"' in line:
+ a1_lines.append(line)
+ else:
+ if len(a1_lines) > 0:
+ new_a1_lines = process_a1_lines(prev_line, a1_lines, line)
+ for new_a1_line in new_a1_lines:
+ result_lines.append(new_a1_line)
+ a1_lines = []
+ result_lines.append(line)
+ prev_line = line
+ if len(a1_lines) > 0:
+ new_a1_lines = process_a1_lines(prev_line, a1_lines, None)
+ for new_a1_line in new_a1_lines:
+ result_lines.append(new_a1_line)
+ return result_lines
+
+def process_a1_lines(prev_line, a1_lines, next_line):
+ if not prev_line or not next_line:
+ return a1_lines # Can't merge first or last line in file.
+ if len(a1_lines) > 1:
+ return a1_lines # Can't merge more than 1 line at once.
+ a1_line = a1_lines[0].strip()
+ prev_entry = parse_line(prev_line)
+ a1_entry = parse_line(a1_line)
+ next_entry = parse_line(next_line)
+ touches_prev_entry = int(prev_entry['end_num']) + 1 == \
+ int(a1_entry['start_num'])
+ touches_next_entry = int(a1_entry['end_num']) + 1 == \
+ int(next_entry['start_num'])
+ same_country_code = prev_entry['country_code'] == \
+ next_entry['country_code']
+ if touches_prev_entry and touches_next_entry and same_country_code:
+ new_line = format_line_with_other_country(a1_entry, prev_entry)
+ print '-%s\n+%s' % (a1_line, new_line, )
+ return [new_line]
+ else:
+ return a1_lines
+
+def parse_line(line):
+ if not line:
+ return None
+ keys = ['start_str', 'end_str', 'start_num', 'end_num',
+ 'country_code', 'country_name']
+ stripped_line = line.replace('"', '').strip()
+ parts = stripped_line.split(',')
+ entry = dict((k, v) for k, v in zip(keys, parts))
+ return entry
+
+def format_line_with_other_country(original_entry, other_entry):
+ return '"%s","%s","%s","%s","%s","%s"' % (original_entry['start_str'],
+ original_entry['end_str'], original_entry['start_num'],
+ original_entry['end_num'], other_entry['country_code'],
+ other_entry['country_name'], )
+
+def apply_manual_changes(assignments, manual_assignments):
+ if not manual_assignments:
+ return assignments
+ print '\nApplying manual changes...'
+ manual_dict = {}
+ for line in manual_assignments:
+ start_num = parse_line(line)['start_num']
+ if start_num in manual_dict:
+ print ('Warning: duplicate start number in manual '
+ 'assignments:\n %s\n %s\nDiscarding first entry.' %
+ (manual_dict[start_num], line, ))
+ manual_dict[start_num] = line
+ result = []
+ for line in assignments:
+ entry = parse_line(line)
+ start_num = entry['start_num']
+ if start_num in manual_dict:
+ manual_line = manual_dict[start_num]
+ manual_entry = parse_line(manual_line)
+ if entry['start_str'] == manual_entry['start_str'] and \
+ entry['end_str'] == manual_entry['end_str'] and \
+ entry['end_num'] == manual_entry['end_num']:
+ if len(manual_entry['country_code']) != 2:
+ print '-%s' % (line, ) # only remove, don't replace
+ else:
+ new_line = format_line_with_other_country(entry,
+ manual_entry)
+ print '-%s\n+%s' % (line, new_line, )
+ result.append(new_line)
+ del manual_dict[start_num]
+ else:
+ print ('Warning: only partial match between '
+ 'original/automatically replaced assignment and '
+ 'manual assignment:\n %s\n %s\nNot applying '
+ 'manual change.' % (line, manual_line, ))
+ result.append(line)
+ else:
+ result.append(line)
+ if len(manual_dict) > 0:
+ print ('Warning: could not apply all manual assignments: %s' %
+ ('\n '.join(manual_dict.values())), )
+ return result
+
+def write_file(path, assignments, long_format=True):
+ if long_format:
+ output_lines = assignments
+ else:
+ output_lines = []
+ for long_line in assignments:
+ entry = parse_line(long_line)
+ short_line = "%s,%s,%s" % (entry['start_num'],
+ entry['end_num'], entry['country_code'], )
+ output_lines.append(short_line)
+ out_file = open(path, 'w')
+ out_file.write('\n'.join(output_lines))
+ out_file.close()
+
+if __name__ == '__main__':
+ main()
+
diff --git a/src/config/geoip-manual b/src/config/geoip-manual
new file mode 100644
index 0000000000..3811c75bfb
--- /dev/null
+++ b/src/config/geoip-manual
@@ -0,0 +1,114 @@
+# This file contains manual overrides of A1 entries (and possibly others)
+# in MaxMind's GeoLite Country database. Use deanonymind.py in the same
+# directory to process this file when producing a new geoip file. See
+# README.geoip in the same directory for details.
+
+# Remove MaxMind entry 0.116.0.0-0.119.255.255 which MaxMind says is AT,
+# but which is part of reserved range 0.0.0.0/8. -KL 2012-06-13
+"0.116.0.0","0.119.255.255","7602176","7864319","",""
+
+# NL, because previous MaxMind entry 31.171.128.0-31.171.133.255 is NL,
+# and RIR delegation files say 31.171.128.0-31.171.135.255 is NL.
+# -KL 2012-11-27
+"31.171.134.0","31.171.135.255","531334656","531335167","NL","Netherlands"
+
+# EU, because next MaxMind entry 37.139.64.1-37.139.64.9 is EU, because
+# RIR delegation files say 37.139.64.0-37.139.71.255 is EU, and because it
+# just makes more sense for the next entry to start at .0 and not .1.
+# -KL 2012-11-27
+"37.139.64.0","37.139.64.0","629882880","629882880","EU","Europe"
+
+# CH, because previous MaxMind entry 46.19.141.0-46.19.142.255 is CH, and
+# RIR delegation files say 46.19.136.0-46.19.143.255 is CH.
+# -KL 2012-11-27
+"46.19.143.0","46.19.143.255","773033728","773033983","CH","Switzerland"
+
+# GB, because next MaxMind entry 46.166.129.0-46.166.134.255 is GB, and
+# RIR delegation files say 46.166.128.0-46.166.191.255 is GB.
+# -KL 2012-11-27
+"46.166.128.0","46.166.128.255","782663680","782663935","GB","United Kingdom"
+
+# US, though could as well be CA. Previous MaxMind entry
+# 64.237.32.52-64.237.34.127 is US, next MaxMind entry
+# 64.237.34.144-64.237.34.151 is CA, and RIR delegation files say the
+# entire block 64.237.32.0-64.237.63.255 is US. -KL 2012-11-27
+"64.237.34.128","64.237.34.143","1089282688","1089282703","US","United States"
+
+# US, though could as well be UY. Previous MaxMind entry
+# 67.15.170.0-67.15.182.255 is US, next MaxMind entry
+# 67.15.183.128-67.15.183.159 is UY, and RIR delegation files say the
+# entire block 67.15.0.0-67.15.255.255 is US. -KL 2012-11-27
+"67.15.183.0","67.15.183.127","1125103360","1125103487","US","United States"
+
+# US, because next MaxMind entry 67.43.145.0-67.43.155.255 is US, and RIR
+# delegation files say 67.43.144.0-67.43.159.255 is US.
+# -KL 2012-11-27
+"67.43.144.0","67.43.144.255","1126928384","1126928639","US","United States"
+
+# US, because previous MaxMind entry 70.159.21.51-70.232.244.255 is US,
+# because next MaxMind entry 70.232.245.58-70.232.245.59 is A2 ("Satellite
+# Provider") which is a country information about as useless as A1, and
+# because RIR delegation files say 70.224.0.0-70.239.255.255 is US.
+# -KL 2012-11-27
+"70.232.245.0","70.232.245.57","1189672192","1189672249","US","United States"
+
+# US, because next MaxMind entry 70.232.246.0-70.240.141.255 is US,
+# because previous MaxMind entry 70.232.245.58-70.232.245.59 is A2
+# ("Satellite Provider") which is a country information about as useless
+# as A1, and because RIR delegation files say 70.224.0.0-70.239.255.255 is
+# US. -KL 2012-11-27
+"70.232.245.60","70.232.245.255","1189672252","1189672447","US","United States"
+
+# GB, despite neither previous (GE) nor next (LV) MaxMind entry being GB,
+# but because RIR delegation files agree with both previous and next
+# MaxMind entry and say GB for 91.228.0.0-91.228.3.255. -KL 2012-11-27
+"91.228.0.0","91.228.3.255","1541668864","1541669887","GB","United Kingdom"
+
+# GB, because next MaxMind entry 91.232.125.0-91.232.125.255 is GB, and
+# RIR delegation files say 91.232.124.0-91.232.125.255 is GB.
+# -KL 2012-11-27
+"91.232.124.0","91.232.124.255","1541962752","1541963007","GB","United Kingdom"
+
+# GB, despite neither previous (RU) nor next (PL) MaxMind entry being GB,
+# but because RIR delegation files agree with both previous and next
+# MaxMind entry and say GB for 91.238.214.0-91.238.215.255.
+# -KL 2012-11-27
+"91.238.214.0","91.238.215.255","1542379008","1542379519","GB","United Kingdom"
+
+# US, because next MaxMind entry 173.0.16.0-173.0.65.255 is US, and RIR
+# delegation files say 173.0.0.0-173.0.15.255 is US. -KL 2012-11-27
+"173.0.0.0","173.0.15.255","2902458368","2902462463","US","United States"
+
+# US, because next MaxMind entry 176.67.84.0-176.67.84.79 is US, and RIR
+# delegation files say 176.67.80.0-176.67.87.255 is US. -KL 2012-11-27
+"176.67.80.0","176.67.83.255","2957201408","2957202431","US","United States"
+
+# US, because previous MaxMind entry 176.67.84.192-176.67.85.255 is US,
+# and RIR delegation files say 176.67.80.0-176.67.87.255 is US.
+# -KL 2012-11-27
+"176.67.86.0","176.67.87.255","2957202944","2957203455","US","United States"
+
+# EU, despite neither previous (RU) nor next (UA) MaxMind entry being EU,
+# but because RIR delegation files agree with both previous and next
+# MaxMind entry and say EU for 193.200.150.0-193.200.150.255.
+# -KL 2012-11-27
+"193.200.150.0","193.200.150.255","3251148288","3251148543","EU","Europe"
+
+# US, because previous MaxMind entry 199.96.68.0-199.96.87.127 is US, and
+# RIR delegation files say 199.96.80.0-199.96.87.255 is US.
+# -KL 2012-11-27
+"199.96.87.128","199.96.87.255","3344979840","3344979967","US","United States"
+
+# US, because previous MaxMind entry 209.58.176.144-209.59.31.255 is US,
+# and RIR delegation files say 209.59.32.0-209.59.63.255 is US.
+# -KL 2012-11-27
+"209.59.32.0","209.59.63.255","3510312960","3510321151","US","United States"
+
+# FR, because previous MaxMind entry 217.15.166.0-217.15.166.255 is FR,
+# and RIR delegation files contain a block 217.15.160.0-217.15.175.255
+# which, however, is EU, not FR. But merging with next MaxMind entry
+# 217.15.176.0-217.15.191.255 which is KZ and which fully matches what
+# the RIR delegation files say seems unlikely to be correct.
+# -KL 2012-11-27
+"217.15.167.0","217.15.175.255","3641681664","3641683967","FR","France"
+
diff --git a/src/config/geoip6 b/src/config/geoip6
new file mode 100644
index 0000000000..be70b29616
--- /dev/null
+++ b/src/config/geoip6
@@ -0,0 +1,11638 @@
+# Last updated based on October 16 2012 Maxmind GeoLite IPv6 Country
+# wget http://geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz
+# cut -d, -f1,2,5 < GeoIPv6.csv|sed 's/[ "]//g' > geoip6
+2001:200::,2001:200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:208::,2001:208:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:218::,2001:218:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:220::,2001:220:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:230::,2001:230:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:238::,2001:238:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:240::,2001:240:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:250::,2001:252:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:254::,2001:254:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:256::,2001:256:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:258::,2001:258:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:260::,2001:260:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:268::,2001:268:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:270::,2001:270:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:278::,2001:278:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:280::,2001:280:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:288::,2001:288:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:290::,2001:290:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:298::,2001:298:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2a0::,2001:2a0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2a8::,2001:2a8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2b0::,2001:2b0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:2b8::,2001:2b8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:2c0::,2001:2c0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2c8::,2001:2c8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2d8::,2001:2d8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:2e0::,2001:2e0:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:2e8::,2001:2e8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2f0::,2001:2f0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2f8::,2001:2f8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:300::,2001:300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:308::,2001:308:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:310::,2001:310:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:318::,2001:318:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:320::,2001:320:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:328::,2001:328:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:330::,2001:330:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:338::,2001:338:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:340::,2001:340:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:348::,2001:348:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:350::,2001:350:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:358::,2001:358:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:360::,2001:360:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:368::,2001:368:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:370::,2001:370:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:378::,2001:378:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:380::,2001:380:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:388::,2001:388:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:390::,2001:390:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:398::,2001:398:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3a0::,2001:3a0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3a8::,2001:3a8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:3b0::,2001:3b0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3b8::,2001:3b8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3c0::,2001:3c0:1fff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3c8::,2001:3c8:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:3d0::,2001:3d0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3d8::,2001:3d8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3e0::,2001:3e0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3e8::,2001:3e8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:400::,2001:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:408::,2001:408:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:410::,2001:410:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:418::,2001:418:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:420::,2001:420:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:428::,2001:428:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:430::,2001:430:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:438::,2001:438:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:440::,2001:440:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:448::,2001:448:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:450::,2001:450:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:458::,2001:458:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:460::,2001:460:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:468::,2001:468:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:470::,2001:470:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:478::,2001:478:ffff:ffff:ffff:ffff:ffff:ffff,KN
+2001:480::,2001:480:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:490::,2001:490:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4a0::,2001:4a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4b0::,2001:4b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4b8::,2001:4b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4c0::,2001:4c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4c8::,2001:4c8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4d0::,2001:4d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4d8::,2001:4d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4e0::,2001:4e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4e8::,2001:4e8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4f0::,2001:4f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4f8::,2001:4f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:500:1::,2001:500:4:ffff:ffff:ffff:ffff:ffff,US
+2001:500:6::,2001:500:f:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:10::,2001:500:10:ffff:ffff:ffff:ffff:ffff,PR
+2001:500:11::,2001:500:15:ffff:ffff:ffff:ffff:ffff,US
+2001:500:16::,2001:500:2c:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:2d::,2001:500:31:ffff:ffff:ffff:ffff:ffff,US
+2001:500:40::,2001:500:56:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:60::,2001:500:7d:ffff:ffff:ffff:ffff:ffff,US
+2001:500:80::,2001:500:83:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:84::,2001:500:89:ffff:ffff:ffff:ffff:ffff,US
+2001:500:8c::,2001:500:9a:ffff:ffff:ffff:ffff:ffff,US
+2001:500:9c::,2001:500:9f:ffff:ffff:ffff:ffff:ffff,US
+2001:500:a0::,2001:500:a6:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:c0::,2001:500:ef:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:f0::,2001:500:f0:ffff:ffff:ffff:ffff:ffff,US
+2001:500:f1::,2001:500:f1:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:100::,2001:500:109:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:3e5::,2001:500:3e5:ffff:ffff:ffff:ffff:ffff,US
+2001:500:30ff::,2001:500:30ff:ffff:ffff:ffff:ffff:ffff,US
+2001:500:3682::,2001:500:3682:ffff:ffff:ffff:ffff:ffff,US
+2001:500:4431::,2001:500:4431:ffff:ffff:ffff:ffff:ffff,US
+2001:500:7967::,2001:500:7967:ffff:ffff:ffff:ffff:ffff,US
+2001:500:856e::,2001:500:856e:ffff:ffff:ffff:ffff:ffff,US
+2001:500:d937::,2001:500:d937:ffff:ffff:ffff:ffff:ffff,US
+2001:500:ed30::,2001:500:ed30:ffff:ffff:ffff:ffff:ffff,US
+2001:501:8a29::,2001:501:8a29:ffff:ffff:ffff:ffff:ffff,US
+2001:501:973c::,2001:501:973c:ffff:ffff:ffff:ffff:ffff,US
+2001:501:b1f9::,2001:501:b1f9:ffff:ffff:ffff:ffff:ffff,US
+2001:502:8cc::,2001:502:8cc:ffff:ffff:ffff:ffff:ffff,US
+2001:502:100e::,2001:502:100e:ffff:ffff:ffff:ffff:ffff,US
+2001:502:1ca1::,2001:502:1ca1:ffff:ffff:ffff:ffff:ffff,US
+2001:502:2eda::,2001:502:2eda:ffff:ffff:ffff:ffff:ffff,US
+2001:502:4612::,2001:502:4612:ffff:ffff:ffff:ffff:ffff,US
+2001:502:63bd::,2001:502:63bd:ffff:ffff:ffff:ffff:ffff,US
+2001:502:7094::,2001:502:7094:ffff:ffff:ffff:ffff:ffff,US
+2001:502:7a71::,2001:502:7a71:ffff:ffff:ffff:ffff:ffff,US
+2001:502:8c25::,2001:502:8c25:ffff:ffff:ffff:ffff:ffff,US
+2001:502:ad09::,2001:502:ad09:ffff:ffff:ffff:ffff:ffff,US
+2001:502:be98::,2001:502:be98:ffff:ffff:ffff:ffff:ffff,US
+2001:502:cbe4::,2001:502:cbe4:ffff:ffff:ffff:ffff:ffff,US
+2001:502:cfb5::,2001:502:cfb5:ffff:ffff:ffff:ffff:ffff,US
+2001:502:d399::,2001:502:d399:ffff:ffff:ffff:ffff:ffff,US
+2001:502:f3ff::,2001:502:f3ff:ffff:ffff:ffff:ffff:ffff,US
+2001:503:c27::,2001:503:c27:ffff:ffff:ffff:ffff:ffff,US
+2001:503:d2d::,2001:503:d2d:ffff:ffff:ffff:ffff:ffff,US
+2001:503:231d::,2001:503:231d:ffff:ffff:ffff:ffff:ffff,US
+2001:503:3227::,2001:503:3227:ffff:ffff:ffff:ffff:ffff,US
+2001:503:39c1::,2001:503:39c1:ffff:ffff:ffff:ffff:ffff,US
+2001:503:4872::,2001:503:4872:ffff:ffff:ffff:ffff:ffff,US
+2001:503:5419::,2001:503:5419:ffff:ffff:ffff:ffff:ffff,US
+2001:503:5ae2::,2001:503:5ae2:ffff:ffff:ffff:ffff:ffff,US
+2001:503:6810::,2001:503:6810:ffff:ffff:ffff:ffff:ffff,US
+2001:503:7bbb::,2001:503:7bbb:ffff:ffff:ffff:ffff:ffff,US
+2001:503:7bbf::,2001:503:7bbf:ffff:ffff:ffff:ffff:ffff,US
+2001:503:8028::,2001:503:8028:ffff:ffff:ffff:ffff:ffff,US
+2001:503:83eb::,2001:503:83eb:ffff:ffff:ffff:ffff:ffff,US
+2001:503:91ef::,2001:503:91ef:ffff:ffff:ffff:ffff:ffff,US
+2001:503:a124::,2001:503:a124:ffff:ffff:ffff:ffff:ffff,US
+2001:503:a83e::,2001:503:a83e:ffff:ffff:ffff:ffff:ffff,US
+2001:503:ba3e::,2001:503:ba3e:ffff:ffff:ffff:ffff:ffff,US
+2001:503:bfb0::,2001:503:bfb0:ffff:ffff:ffff:ffff:ffff,US
+2001:503:c779::,2001:503:c779:ffff:ffff:ffff:ffff:ffff,US
+2001:503:cc2c::,2001:503:cc2c:ffff:ffff:ffff:ffff:ffff,US
+2001:503:d1ae::,2001:503:d1ae:ffff:ffff:ffff:ffff:ffff,US
+2001:503:d414::,2001:503:d414:ffff:ffff:ffff:ffff:ffff,US
+2001:503:e239::,2001:503:e239:ffff:ffff:ffff:ffff:ffff,US
+2001:503:e8ef::,2001:503:e8ef:ffff:ffff:ffff:ffff:ffff,US
+2001:503:eea3::,2001:503:eea3:ffff:ffff:ffff:ffff:ffff,US
+2001:503:f189::,2001:503:f189:ffff:ffff:ffff:ffff:ffff,US
+2001:503:f261::,2001:503:f261:ffff:ffff:ffff:ffff:ffff,US
+2001:503:f3da::,2001:503:f3da:ffff:ffff:ffff:ffff:ffff,US
+2001:503:ff39::,2001:503:ff39:ffff:ffff:ffff:ffff:ffff,US
+2001:504::,2001:504:14:ffff:ffff:ffff:ffff:ffff,US
+2001:504:15::,2001:504:15:ffff:ffff:ffff:ffff:ffff,CA
+2001:504:16::,2001:504:19:ffff:ffff:ffff:ffff:ffff,US
+2001:504:1a::,2001:504:1a:ffff:ffff:ffff:ffff:ffff,CA
+2001:504:1b::,2001:504:1c:ffff:ffff:ffff:ffff:ffff,US
+2001:504:1d::,2001:504:1d:ffff:ffff:ffff:ffff:ffff,PR
+2001:504:20::,2001:504:23:ffff:ffff:ffff:ffff:ffff,CA
+2001:504:24::,2001:504:24:ffff:ffff:ffff:ffff:ffff,US
+2001:504:25::,2001:504:26:ffff:ffff:ffff:ffff:ffff,CA
+2001:504:27::,2001:504:28:ffff:ffff:ffff:ffff:ffff,US
+2001:506::,2001:506:1:ffff:ffff:ffff:ffff:ffff,US
+2001:506:8::,2001:506:8:ffff:ffff:ffff:ffff:ffff,US
+2001:506:20::,2001:506:20:ffff:ffff:ffff:ffff:ffff,CA
+2001:506:28::,2001:506:28:ffff:ffff:ffff:ffff:ffff,US
+2001:506:100::,2001:506:100:ffff:ffff:ffff:ffff:ffff,US
+2001:506:1000::,2001:506:2fff:ffff:ffff:ffff:ffff:ffff,US
+2001:506:4000::,2001:506:5fff:ffff:ffff:ffff:ffff:ffff,US
+2001:508::,2001:508:ffff:ffff:ffff:ffff:ffff:ffff,BM
+2001:510::,2001:510:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:518::,2001:518:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:520::,2001:520:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:528::,2001:528:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:530::,2001:530:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:538::,2001:538:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:540::,2001:540:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:548::,2001:548:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:550::,2001:550:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:558::,2001:560:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:568::,2001:56f:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:570::,2001:570:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:578::,2001:57b:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:580::,2001:580:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:590::,2001:590:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:598::,2001:598:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:5a0::,2001:5a0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:5a8::,2001:5a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5b0::,2001:5b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5b8::,2001:5b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5c0::,2001:5c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:5c8::,2001:5c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5d0::,2001:5d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5d8::,2001:5d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5e0::,2001:5e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5e8::,2001:5e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5f0::,2001:5f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5f8::,2001:5f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:600::,2001:600:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:608::,2001:608:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:610::,2001:610:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:618::,2001:618:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:620::,2001:620:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:628::,2001:62f:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:630::,2001:630:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:638::,2001:638:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:640::,2001:640:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:648::,2001:648:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2001:650::,2001:650:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:658::,2001:658:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:660::,2001:667:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:668::,2001:66f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:670::,2001:670:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:678:1::,2001:678:1:ffff:ffff:ffff:ffff:ffff,CZ
+2001:678:2::,2001:678:2:ffff:ffff:ffff:ffff:ffff,DE
+2001:678:3::,2001:678:3:ffff:ffff:ffff:ffff:ffff,CH
+2001:678:4::,2001:678:5:ffff:ffff:ffff:ffff:ffff,GB
+2001:678:6::,2001:678:6:ffff:ffff:ffff:ffff:ffff,LT
+2001:678:7::,2001:678:7:ffff:ffff:ffff:ffff:ffff,GR
+2001:678:8::,2001:678:8:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:9::,2001:678:a:ffff:ffff:ffff:ffff:ffff,BE
+2001:678:b::,2001:678:b:ffff:ffff:ffff:ffff:ffff,LV
+2001:678:c::,2001:678:c:ffff:ffff:ffff:ffff:ffff,FR
+2001:678:d::,2001:678:d:ffff:ffff:ffff:ffff:ffff,AT
+2001:678:e::,2001:678:e:ffff:ffff:ffff:ffff:ffff,DE
+2001:678:f::,2001:678:11:ffff:ffff:ffff:ffff:ffff,CZ
+2001:678:12::,2001:678:12:ffff:ffff:ffff:ffff:ffff,IT
+2001:678:13::,2001:678:18:ffff:ffff:ffff:ffff:ffff,RU
+2001:678:19::,2001:678:19:ffff:ffff:ffff:ffff:ffff,LT
+2001:678:1a::,2001:678:1a:ffff:ffff:ffff:ffff:ffff,DK
+2001:678:1b::,2001:678:1b:ffff:ffff:ffff:ffff:ffff,LU
+2001:678:1c::,2001:678:1c:ffff:ffff:ffff:ffff:ffff,AT
+2001:678:20::,2001:678:20:ffff:ffff:ffff:ffff:ffff,AT
+2001:678:24::,2001:678:24:ffff:ffff:ffff:ffff:ffff,AT
+2001:678:28::,2001:678:28:ffff:ffff:ffff:ffff:ffff,SM
+2001:678:2c::,2001:678:2c:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:30::,2001:678:30:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:34::,2001:678:34:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:38::,2001:678:38:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:3c::,2001:678:3c:ffff:ffff:ffff:ffff:ffff,BG
+2001:678:40::,2001:678:40:ffff:ffff:ffff:ffff:ffff,ES
+2001:678:44::,2001:678:44:ffff:ffff:ffff:ffff:ffff,ES
+2001:678:48::,2001:678:48:ffff:ffff:ffff:ffff:ffff,ES
+2001:678:4c::,2001:678:4c:ffff:ffff:ffff:ffff:ffff,FR
+2001:678:50::,2001:678:50:ffff:ffff:ffff:ffff:ffff,TK
+2001:678:54::,2001:678:54:ffff:ffff:ffff:ffff:ffff,TK
+2001:678:58::,2001:678:58:ffff:ffff:ffff:ffff:ffff,TK
+2001:678:5c::,2001:678:5c:ffff:ffff:ffff:ffff:ffff,TK
+2001:678:60::,2001:678:60:ffff:ffff:ffff:ffff:ffff,LU
+2001:678:64::,2001:678:64:ffff:ffff:ffff:ffff:ffff,BE
+2001:678:68::,2001:678:68:ffff:ffff:ffff:ffff:ffff,BE
+2001:678:6c::,2001:678:6c:ffff:ffff:ffff:ffff:ffff,BE
+2001:678:70::,2001:678:70:ffff:ffff:ffff:ffff:ffff,SK
+2001:678:74::,2001:678:74:ffff:ffff:ffff:ffff:ffff,DK
+2001:678:78::,2001:678:78:ffff:ffff:ffff:ffff:ffff,DK
+2001:678:7c::,2001:678:7c:ffff:ffff:ffff:ffff:ffff,LV
+2001:678:80::,2001:678:80:ffff:ffff:ffff:ffff:ffff,LV
+2001:678:84::,2001:678:84:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c::,2001:67c:0:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:4::,2001:67c:4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:8::,2001:67c:8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:c::,2001:67c:c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:10::,2001:67c:10:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:14::,2001:67c:14:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:18::,2001:67c:18:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1c::,2001:67c:1c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:20::,2001:67c:20:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:24::,2001:67c:24:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2c::,2001:67c:2c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:30::,2001:67c:30:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:34::,2001:67c:34:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:38::,2001:67c:38:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:40::,2001:67c:40:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:44::,2001:67c:44:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:4c::,2001:67c:4c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:50::,2001:67c:50:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:54::,2001:67c:54:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:58::,2001:67c:58:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:5c::,2001:67c:5c:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:60::,2001:67c:60:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:64::,2001:67c:64:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:68::,2001:67c:68:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:6c::,2001:67c:6c:ffff:ffff:ffff:ffff:ffff,IS
+2001:67c:70::,2001:67c:70:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:74::,2001:67c:74:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:78::,2001:67c:78:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:84::,2001:67c:84:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:88::,2001:67c:88:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:8c::,2001:67c:8c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:90::,2001:67c:90:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:94::,2001:67c:94:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:98::,2001:67c:98:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:9c::,2001:67c:9c:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:a0::,2001:67c:a0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:a4::,2001:67c:a4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:a8::,2001:67c:a8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:ac::,2001:67c:ac:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:b0::,2001:67c:b0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:b4::,2001:67c:b4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:b8::,2001:67c:b8:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:bc::,2001:67c:bc:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:c0::,2001:67c:c0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:c4::,2001:67c:c4:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:c8::,2001:67c:c8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:cc::,2001:67c:cc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:d0::,2001:67c:d0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:d4::,2001:67c:d4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:d8::,2001:67c:d8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:dc::,2001:67c:dc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:e0::,2001:67c:e0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:e4::,2001:67c:e4:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:e8::,2001:67c:e8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:ec::,2001:67c:ec:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:f0::,2001:67c:f0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:f4::,2001:67c:f4:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:f8::,2001:67c:f8:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:fc::,2001:67c:fc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:100::,2001:67c:100:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:108::,2001:67c:108:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:10c::,2001:67c:10c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:110::,2001:67c:110:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:114::,2001:67c:114:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:118::,2001:67c:118:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:11c::,2001:67c:11c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:120::,2001:67c:120:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:124::,2001:67c:124:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:128::,2001:67c:128:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:12c::,2001:67c:12c:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:130::,2001:67c:130:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:134::,2001:67c:134:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:138::,2001:67c:138:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:13c::,2001:67c:13c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:140::,2001:67c:140:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:144::,2001:67c:144:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:148::,2001:67c:148:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:14c::,2001:67c:14d:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:150::,2001:67c:150:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:154::,2001:67c:154:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:158::,2001:67c:158:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:15c::,2001:67c:15c:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:160::,2001:67c:160:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:164::,2001:67c:164:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:168::,2001:67c:168:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:16c::,2001:67c:16c:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:170::,2001:67c:170:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:174::,2001:67c:174:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:178::,2001:67c:178:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:17c::,2001:67c:17c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:180::,2001:67c:180:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:184::,2001:67c:184:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:188::,2001:67c:188:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:18c::,2001:67c:18c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:190::,2001:67c:190:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:194::,2001:67c:194:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:19c::,2001:67c:19c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1a0::,2001:67c:1a0:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:1a4::,2001:67c:1a4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1a8::,2001:67c:1a8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1ac::,2001:67c:1ac:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1b0::,2001:67c:1b0:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:1b4::,2001:67c:1b4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:1b8::,2001:67c:1b8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1bc::,2001:67c:1bc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1c0::,2001:67c:1c0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1c4::,2001:67c:1c4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1c8::,2001:67c:1c8:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:1cc::,2001:67c:1cc:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:1d0::,2001:67c:1d0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1d4::,2001:67c:1d4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1d8::,2001:67c:1d8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1dc::,2001:67c:1dc:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1e0::,2001:67c:1e0:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:1e4::,2001:67c:1e4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1e8::,2001:67c:1e8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1ec::,2001:67c:1ec:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:1f0::,2001:67c:1f0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1f4::,2001:67c:1f4:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:1f8::,2001:67c:1f8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1fc::,2001:67c:1fc:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:200::,2001:67c:200:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:204::,2001:67c:204:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:208::,2001:67c:208:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:20c::,2001:67c:20c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:210::,2001:67c:210:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:214::,2001:67c:214:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:218::,2001:67c:218:ffff:ffff:ffff:ffff:ffff,LT
+2001:67c:21c::,2001:67c:21c:ffff:ffff:ffff:ffff:ffff,AM
+2001:67c:220::,2001:67c:220:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:224::,2001:67c:224:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:228::,2001:67c:228:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:22c::,2001:67c:22c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:230::,2001:67c:230:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:234::,2001:67c:234:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:238::,2001:67c:238:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:23c::,2001:67c:23c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:240::,2001:67c:240:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:244::,2001:67c:244:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:248::,2001:67c:248:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:24c::,2001:67c:24c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:250::,2001:67c:250:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:254::,2001:67c:254:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:258::,2001:67c:258:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:25c::,2001:67c:25c:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:260::,2001:67c:260:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:264::,2001:67c:264:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:268::,2001:67c:268:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:26c::,2001:67c:26c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:270::,2001:67c:270:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:274::,2001:67c:274:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:278::,2001:67c:278:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:27c::,2001:67c:27c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:280::,2001:67c:280:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:284::,2001:67c:284:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:288::,2001:67c:288:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:28c::,2001:67c:28c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:294::,2001:67c:294:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:298::,2001:67c:298:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:29c::,2001:67c:29c:ffff:ffff:ffff:ffff:ffff,IT
+2001:67c:2a0::,2001:67c:2a0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2a4::,2001:67c:2a4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a8::,2001:67c:2a8:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2ac::,2001:67c:2ac:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2b0::,2001:67c:2b0:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2b8::,2001:67c:2b8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2bc::,2001:67c:2bc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2c0::,2001:67c:2c0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2c4::,2001:67c:2c4:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2c8::,2001:67c:2c8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2cc::,2001:67c:2cc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2d0::,2001:67c:2d0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2d4::,2001:67c:2d4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2d8::,2001:67c:2d8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2dc::,2001:67c:2dc:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2e0::,2001:67c:2e0:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2e4::,2001:67c:2e4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2e8::,2001:67c:2e8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2ec::,2001:67c:2ec:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2f0::,2001:67c:2f0:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2f4::,2001:67c:2f4:ffff:ffff:ffff:ffff:ffff,LU
+2001:67c:2f8::,2001:67c:2f8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2fc::,2001:67c:2fc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:300::,2001:67c:300:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:304::,2001:67c:304:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:308::,2001:67c:308:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:30c::,2001:67c:30c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:310::,2001:67c:310:ffff:ffff:ffff:ffff:ffff,CY
+2001:67c:314::,2001:67c:314:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:318::,2001:67c:318:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:31c::,2001:67c:31c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:324::,2001:67c:324:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:328::,2001:67c:328:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:32c::,2001:67c:32c:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:330::,2001:67c:330:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:334::,2001:67c:334:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:338::,2001:67c:338:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:33c::,2001:67c:33c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:340::,2001:67c:340:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:344::,2001:67c:344:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:348::,2001:67c:348:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:34c::,2001:67c:34c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:350::,2001:67c:350:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:354::,2001:67c:354:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:358::,2001:67c:358:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:35c::,2001:67c:35c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:360::,2001:67c:360:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:364::,2001:67c:364:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:368::,2001:67c:368:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c:36c::,2001:67c:36c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:370::,2001:67c:370:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:374::,2001:67c:374:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:378::,2001:67c:378:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:37c::,2001:67c:37c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:380::,2001:67c:380:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:384::,2001:67c:384:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:388::,2001:67c:388:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:38c::,2001:67c:38c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:390::,2001:67c:390:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:394::,2001:67c:394:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:398::,2001:67c:398:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:39c::,2001:67c:39c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:3a0::,2001:67c:3a0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:3a4::,2001:67c:3a4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:3a8::,2001:67c:3a8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:3ac::,2001:67c:3ac:ffff:ffff:ffff:ffff:ffff,RS
+2001:67c:3b0::,2001:67c:3b0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:3b4::,2001:67c:3b4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:3b8::,2001:67c:3b8:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:3bc::,2001:67c:3bc:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:3c0::,2001:67c:3c0:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:3c4::,2001:67c:3c4:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:3c8::,2001:67c:3c8:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:3cc::,2001:67c:3cc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:3d0::,2001:67c:3d0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:3d4::,2001:67c:3d4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:3d8::,2001:67c:3d8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3dc::,2001:67c:3dc:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3e0::,2001:67c:3e0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3e4::,2001:67c:3e4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3e8::,2001:67c:3e9:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:3f0::,2001:67c:3f0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3f4::,2001:67c:3f4:ffff:ffff:ffff:ffff:ffff,HR
+2001:67c:3f8::,2001:67c:3f8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:3fc::,2001:67c:3fc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1000::,2001:67c:1001:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1008::,2001:67c:1009:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:1010::,2001:67c:1011:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1018::,2001:67c:1019:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1020::,2001:67c:1021:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1028::,2001:67c:1029:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1030::,2001:67c:1030:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1034::,2001:67c:1034:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:1038::,2001:67c:1038:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:103c::,2001:67c:103c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:1040::,2001:67c:1040:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:1044::,2001:67c:1044:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1048::,2001:67c:1048:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:104c::,2001:67c:104c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1050::,2001:67c:1050:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1054::,2001:67c:1054:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1058::,2001:67c:1058:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:105c::,2001:67c:105c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1060::,2001:67c:1060:ffff:ffff:ffff:ffff:ffff,LU
+2001:67c:1064::,2001:67c:1064:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1068::,2001:67c:1068:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:106c::,2001:67c:106c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1070::,2001:67c:1071:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:1078::,2001:67c:1078:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:107c::,2001:67c:107c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1080::,2001:67c:1080:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1084::,2001:67c:1084:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1088::,2001:67c:1089:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1090::,2001:67c:1090:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1094::,2001:67c:1094:ffff:ffff:ffff:ffff:ffff,IT
+2001:67c:1098::,2001:67c:1098:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:109c::,2001:67c:109c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10a0::,2001:67c:10a0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10a4::,2001:67c:10a4:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:10a8::,2001:67c:10a9:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:10b0::,2001:67c:10b0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:10b4::,2001:67c:10b4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:10b8::,2001:67c:10b8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:10bc::,2001:67c:10bc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:10c0::,2001:67c:10c0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10c4::,2001:67c:10c4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10c8::,2001:67c:10c8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10cc::,2001:67c:10cc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10d0::,2001:67c:10d0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10d4::,2001:67c:10d4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10d8::,2001:67c:10d8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10dc::,2001:67c:10dc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10e0::,2001:67c:10e0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:10e4::,2001:67c:10e4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10e8::,2001:67c:10e8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:10ec::,2001:67c:10ec:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:10f0::,2001:67c:10f0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:10f4::,2001:67c:10f4:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:10f8::,2001:67c:10f8:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:10fc::,2001:67c:10fc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1200::,2001:67c:1203:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1210::,2001:67c:1213:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:1220::,2001:67c:1223:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:1230::,2001:67c:1233:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1240::,2001:67c:1240:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:1244::,2001:67c:1244:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1248::,2001:67c:1248:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:124c::,2001:67c:124c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1250::,2001:67c:1250:ffff:ffff:ffff:ffff:ffff,LU
+2001:67c:1254::,2001:67c:1254:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1258::,2001:67c:1258:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:125c::,2001:67c:125c:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:1260::,2001:67c:1260:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:1264::,2001:67c:1264:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:1268::,2001:67c:1268:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:126c::,2001:67c:126c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1270::,2001:67c:1270:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1274::,2001:67c:1274:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1278::,2001:67c:1278:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:127c::,2001:67c:127c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1280::,2001:67c:1280:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1284::,2001:67c:1284:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1288::,2001:67c:1288:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:128c::,2001:67c:128c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1290::,2001:67c:1290:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1294::,2001:67c:1294:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1298::,2001:67c:1298:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:129c::,2001:67c:129c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:12a0::,2001:67c:12a0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:12a4::,2001:67c:12a4:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:12a8::,2001:67c:12a8:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:12ac::,2001:67c:12ac:ffff:ffff:ffff:ffff:ffff,LU
+2001:67c:12b0::,2001:67c:12b0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1400::,2001:67c:1407:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1420::,2001:67c:1427:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1440::,2001:67c:1447:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:1460::,2001:67c:1467:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1600::,2001:67c:160f:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1640::,2001:67c:164f:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:1a00::,2001:67c:1a3f:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1c00::,2001:67c:1cff:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2004::,2001:67c:2004:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2008::,2001:67c:2008:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:200c::,2001:67c:200c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2010::,2001:67c:2010:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2014::,2001:67c:2014:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2018::,2001:67c:2018:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:201c::,2001:67c:201c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2020::,2001:67c:2020:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2024::,2001:67c:2024:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2028::,2001:67c:2028:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:202c::,2001:67c:202c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2030::,2001:67c:2030:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2034::,2001:67c:2034:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2038::,2001:67c:2038:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:203c::,2001:67c:203c:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2040::,2001:67c:2040:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2044::,2001:67c:2044:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2048::,2001:67c:2048:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:204c::,2001:67c:204c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2050::,2001:67c:2050:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:205c::,2001:67c:205c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2060::,2001:67c:2060:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2064::,2001:67c:2064:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2068::,2001:67c:2068:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:206c::,2001:67c:206c:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2070::,2001:67c:2070:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2074::,2001:67c:2074:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2078::,2001:67c:2078:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:207c::,2001:67c:207c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2080::,2001:67c:2080:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2084::,2001:67c:2084:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2088::,2001:67c:2088:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:208c::,2001:67c:208c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2090::,2001:67c:2090:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2098::,2001:67c:2099:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:20a0::,2001:67c:20a1:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:20a8::,2001:67c:20a8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:20ac::,2001:67c:20ac:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:20b0::,2001:67c:20b0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:20b4::,2001:67c:20b4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:20b8::,2001:67c:20b9:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:20c0::,2001:67c:20c0:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:20c4::,2001:67c:20c4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:20c8::,2001:67c:20c8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:20cc::,2001:67c:20cc:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:20d0::,2001:67c:20d1:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:20d8::,2001:67c:20d8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:20dc::,2001:67c:20dc:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:20e0::,2001:67c:20e0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:20e4::,2001:67c:20e4:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:20e8::,2001:67c:20e8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:20ec::,2001:67c:20ec:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:20f0::,2001:67c:20f0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:20f4::,2001:67c:20f4:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:20f8::,2001:67c:20f8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:20fc::,2001:67c:20fc:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2100::,2001:67c:2100:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2104::,2001:67c:2104:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2108::,2001:67c:2108:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:210c::,2001:67c:210c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2110::,2001:67c:2110:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2114::,2001:67c:2114:ffff:ffff:ffff:ffff:ffff,IS
+2001:67c:2118::,2001:67c:2118:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:211c::,2001:67c:211c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2120::,2001:67c:2120:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2124::,2001:67c:2124:ffff:ffff:ffff:ffff:ffff,HU
+2001:67c:2128::,2001:67c:2128:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:212c::,2001:67c:212c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2130::,2001:67c:2130:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2134::,2001:67c:2134:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2138::,2001:67c:2138:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:213c::,2001:67c:213c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2140::,2001:67c:2140:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2144::,2001:67c:2144:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2148::,2001:67c:2148:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:214c::,2001:67c:214c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2150::,2001:67c:2150:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2154::,2001:67c:2154:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:2158::,2001:67c:2158:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:215c::,2001:67c:215c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2160::,2001:67c:2160:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2164::,2001:67c:2164:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:2168::,2001:67c:2168:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:216c::,2001:67c:216c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2170::,2001:67c:2170:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2174::,2001:67c:2174:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2178::,2001:67c:2178:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:217c::,2001:67c:217c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2180::,2001:67c:2180:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2188::,2001:67c:2188:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:218c::,2001:67c:218c:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2190::,2001:67c:2190:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2194::,2001:67c:2194:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2198::,2001:67c:2198:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c:219c::,2001:67c:219c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:21a0::,2001:67c:21a0:ffff:ffff:ffff:ffff:ffff,IT
+2001:67c:21a4::,2001:67c:21a4:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:21a8::,2001:67c:21a8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:21ac::,2001:67c:21ac:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:21b0::,2001:67c:21b0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:21b4::,2001:67c:21b4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:21b8::,2001:67c:21b8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:21bc::,2001:67c:21bc:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:21c0::,2001:67c:21c0:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:21c4::,2001:67c:21c4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:21c8::,2001:67c:21c8:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:21cc::,2001:67c:21cc:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:21d0::,2001:67c:21d0:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:21d8::,2001:67c:21d8:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:21dc::,2001:67c:21dc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:21e0::,2001:67c:21e0:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:21e4::,2001:67c:21e4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:21e8::,2001:67c:21e8:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:21ec::,2001:67c:21ec:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:21f0::,2001:67c:21f0:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:21f4::,2001:67c:21f4:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:21f8::,2001:67c:21f8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:21fc::,2001:67c:21fc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2200::,2001:67c:2200:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2204::,2001:67c:2204:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2208::,2001:67c:2208:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:220c::,2001:67c:220c:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:2210::,2001:67c:2210:ffff:ffff:ffff:ffff:ffff,RS
+2001:67c:2214::,2001:67c:2214:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2218::,2001:67c:2219:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2220::,2001:67c:2220:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2224::,2001:67c:2224:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2228::,2001:67c:2228:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:222c::,2001:67c:222c:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:2230::,2001:67c:2230:ffff:ffff:ffff:ffff:ffff,HR
+2001:67c:2234::,2001:67c:2234:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2238::,2001:67c:2238:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:223c::,2001:67c:223c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2240::,2001:67c:2240:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2244::,2001:67c:2244:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2248::,2001:67c:2248:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2250::,2001:67c:2250:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2254::,2001:67c:2254:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2258::,2001:67c:2258:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:225c::,2001:67c:225c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2260::,2001:67c:2260:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2264::,2001:67c:2264:ffff:ffff:ffff:ffff:ffff,KG
+2001:67c:2268::,2001:67c:2268:ffff:ffff:ffff:ffff:ffff,BY
+2001:67c:226c::,2001:67c:226c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2270::,2001:67c:2270:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2274::,2001:67c:2274:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2278::,2001:67c:2278:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:227c::,2001:67c:227c:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2280::,2001:67c:2280:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2284::,2001:67c:2284:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2288::,2001:67c:2288:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:228c::,2001:67c:228c:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2290::,2001:67c:2290:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2294::,2001:67c:2294:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:2298::,2001:67c:2298:ffff:ffff:ffff:ffff:ffff,US
+2001:67c:229c::,2001:67c:229c:ffff:ffff:ffff:ffff:ffff,GR
+2001:67c:22a0::,2001:67c:22a0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:22a4::,2001:67c:22a4:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:22a8::,2001:67c:22a8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:22ac::,2001:67c:22ac:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:22b0::,2001:67c:22b0:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:22b4::,2001:67c:22b4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:22b8::,2001:67c:22b8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:22bc::,2001:67c:22bc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:22c0::,2001:67c:22c0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:22c4::,2001:67c:22c4:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:22c8::,2001:67c:22c8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:22cc::,2001:67c:22cc:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:22d0::,2001:67c:22d0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:22d4::,2001:67c:22d4:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:22d8::,2001:67c:22d8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:22dc::,2001:67c:22dc:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:22e0::,2001:67c:22e0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:22e4::,2001:67c:22e4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:22e8::,2001:67c:22e8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:22ec::,2001:67c:22ec:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:22f0::,2001:67c:22f0:ffff:ffff:ffff:ffff:ffff,RS
+2001:67c:22f8::,2001:67c:22f8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:22fc::,2001:67c:22fc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2300::,2001:67c:2300:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2304::,2001:67c:2304:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2308::,2001:67c:2308:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:230c::,2001:67c:230c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2310::,2001:67c:2310:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2314::,2001:67c:2314:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2318::,2001:67c:2318:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:231c::,2001:67c:231c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2320::,2001:67c:2320:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2324::,2001:67c:2324:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2328::,2001:67c:2328:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:232c::,2001:67c:232c:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c:2330::,2001:67c:2330:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2334::,2001:67c:2334:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2338::,2001:67c:2338:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:233c::,2001:67c:233c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2340::,2001:67c:2340:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2344::,2001:67c:2344:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2348::,2001:67c:2348:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:234c::,2001:67c:234c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2350::,2001:67c:2350:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2354::,2001:67c:2354:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2358::,2001:67c:2358:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:235c::,2001:67c:235c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2360::,2001:67c:2360:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2364::,2001:67c:2364:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2368::,2001:67c:2368:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:236c::,2001:67c:236c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2370::,2001:67c:2370:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2374::,2001:67c:2374:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2378::,2001:67c:2378:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:237c::,2001:67c:237c:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2380::,2001:67c:2380:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2384::,2001:67c:2384:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2388::,2001:67c:2388:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:238c::,2001:67c:238c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2394::,2001:67c:2394:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2398::,2001:67c:2398:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:239c::,2001:67c:239c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:23a0::,2001:67c:23a0:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:23a4::,2001:67c:23a4:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:23a8::,2001:67c:23a8:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:23b0::,2001:67c:23b0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:23b4::,2001:67c:23b4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:23b8::,2001:67c:23b8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:23bc::,2001:67c:23bc:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:23c0::,2001:67c:23c0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:23c4::,2001:67c:23c4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:23c8::,2001:67c:23c8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:23cc::,2001:67c:23cc:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:23d0::,2001:67c:23d0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:23d4::,2001:67c:23d4:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:23d8::,2001:67c:23d9:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:23e4::,2001:67c:23e4:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:23e8::,2001:67c:23e8:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:23ec::,2001:67c:23ec:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:23f0::,2001:67c:23f0:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:23f4::,2001:67c:23f4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:23f8::,2001:67c:23f8:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:23fc::,2001:67c:23fc:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:2400::,2001:67c:2400:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2404::,2001:67c:2404:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2408::,2001:67c:2408:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:240c::,2001:67c:240c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2410::,2001:67c:2410:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:2414::,2001:67c:2414:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2418::,2001:67c:2418:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2420::,2001:67c:2420:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2424::,2001:67c:2424:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2428::,2001:67c:2428:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:242c::,2001:67c:242c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2430::,2001:67c:2433:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2440::,2001:67c:2440:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2444::,2001:67c:2444:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2448::,2001:67c:2448:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:244c::,2001:67c:244c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2450::,2001:67c:2450:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:2454::,2001:67c:2454:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2458::,2001:67c:2458:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:245c::,2001:67c:245c:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2460::,2001:67c:2460:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2464::,2001:67c:2464:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2468::,2001:67c:2468:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:246c::,2001:67c:246c:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2470::,2001:67c:2470:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2474::,2001:67c:2474:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2478::,2001:67c:2478:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:247c::,2001:67c:247c:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2480::,2001:67c:2480:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2484::,2001:67c:2484:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2488::,2001:67c:2488:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:248c::,2001:67c:248c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2490::,2001:67c:2490:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2494::,2001:67c:2494:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2498::,2001:67c:2498:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:249c::,2001:67c:249c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:24a0::,2001:67c:24a0:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:24a4::,2001:67c:24a4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:24a8::,2001:67c:24a8:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:24ac::,2001:67c:24ac:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:24b0::,2001:67c:24b0:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:24b4::,2001:67c:24b4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:24b8::,2001:67c:24b8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:24bc::,2001:67c:24bc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:24c0::,2001:67c:24c0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:24c4::,2001:67c:24c4:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:24c8::,2001:67c:24c8:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:24cc::,2001:67c:24cc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:24d0::,2001:67c:24d0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:24d4::,2001:67c:24d4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:24d8::,2001:67c:24d8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:24dc::,2001:67c:24dc:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:24e0::,2001:67c:24e0:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:24e4::,2001:67c:24e4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:24e8::,2001:67c:24e9:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:24f0::,2001:67c:24f0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:24f4::,2001:67c:24f4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:24f8::,2001:67c:24f8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:24fc::,2001:67c:24fc:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2500::,2001:67c:2507:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2520::,2001:67c:2520:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2524::,2001:67c:2524:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2528::,2001:67c:2528:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c:252c::,2001:67c:252c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2530::,2001:67c:2530:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2534::,2001:67c:2534:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2538::,2001:67c:2538:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:253c::,2001:67c:253c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2540::,2001:67c:2540:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2544::,2001:67c:2544:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2548::,2001:67c:2548:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:254c::,2001:67c:254c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2550::,2001:67c:2550:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2554::,2001:67c:2554:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2558::,2001:67c:2558:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:255c::,2001:67c:255c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2560::,2001:67c:2560:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2564::,2001:67c:2564:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:256c::,2001:67c:256c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2570::,2001:67c:2570:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:2574::,2001:67c:2574:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2578::,2001:67c:2578:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:257c::,2001:67c:257c:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2580::,2001:67c:2580:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2584::,2001:67c:2584:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2588::,2001:67c:2588:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:258c::,2001:67c:258c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2590::,2001:67c:2590:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2594::,2001:67c:2594:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2598::,2001:67c:2598:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:259c::,2001:67c:259c:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:25a0::,2001:67c:25a0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:25a4::,2001:67c:25a4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:25a8::,2001:67c:25a8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:25ac::,2001:67c:25ac:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:25b0::,2001:67c:25b0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:25b4::,2001:67c:25b4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:25b8::,2001:67c:25b8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:25bc::,2001:67c:25bc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:25c0::,2001:67c:25c0:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:25c4::,2001:67c:25c4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:25cc::,2001:67c:25cc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:25d0::,2001:67c:25d0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:25d4::,2001:67c:25d4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:25d8::,2001:67c:25d8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:25dc::,2001:67c:25dc:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:25e4::,2001:67c:25e4:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:25e8::,2001:67c:25e9:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:25f0::,2001:67c:25f0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:25f4::,2001:67c:25f4:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:25f8::,2001:67c:25f8:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:25fc::,2001:67c:25fc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2600::,2001:67c:2600:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2604::,2001:67c:2604:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:260c::,2001:67c:260c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2610::,2001:67c:2610:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2614::,2001:67c:2614:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2618::,2001:67c:2618:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:261c::,2001:67c:261c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2620::,2001:67c:2620:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2624::,2001:67c:2624:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:262c::,2001:67c:262c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2630::,2001:67c:2630:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2634::,2001:67c:2634:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2638::,2001:67c:2638:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:263c::,2001:67c:263c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2640::,2001:67c:2640:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2644::,2001:67c:2644:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2648::,2001:67c:2648:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:264c::,2001:67c:264c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2650::,2001:67c:2650:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2654::,2001:67c:2654:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2658::,2001:67c:2658:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:265c::,2001:67c:265c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2660::,2001:67c:2660:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2664::,2001:67c:2664:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2668::,2001:67c:2668:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:266c::,2001:67c:266c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2670::,2001:67c:2670:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:2674::,2001:67c:2674:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2678::,2001:67c:2678:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:267c::,2001:67c:267c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2680::,2001:67c:2680:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:2684::,2001:67c:2684:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2688::,2001:67c:2688:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:268c::,2001:67c:268c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2690::,2001:67c:2690:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:2694::,2001:67c:2694:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2698::,2001:67c:2698:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:269c::,2001:67c:269c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:26a0::,2001:67c:26a0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:26a4::,2001:67c:26a4:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:26a8::,2001:67c:26a8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:26ac::,2001:67c:26ac:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:26b0::,2001:67c:26b0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:26b4::,2001:67c:26b4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:26b8::,2001:67c:26b8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:26bc::,2001:67c:26bc:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:26c0::,2001:67c:26c3:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:26d0::,2001:67c:26d0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:26d4::,2001:67c:26d4:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:26d8::,2001:67c:26d8:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:26dc::,2001:67c:26dc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:26e0::,2001:67c:26e0:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:26e4::,2001:67c:26e4:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:26e8::,2001:67c:26e8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:26ec::,2001:67c:26ec:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:26f0::,2001:67c:26f0:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:26f4::,2001:67c:26f4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:26f8::,2001:67c:26f8:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:26fc::,2001:67c:26fc:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2700::,2001:67c:2700:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2704::,2001:67c:2704:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2708::,2001:67c:2708:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:270c::,2001:67c:270c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2710::,2001:67c:2710:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2714::,2001:67c:2714:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2718::,2001:67c:2718:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:271c::,2001:67c:271c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2720::,2001:67c:2720:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2724::,2001:67c:2724:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2728::,2001:67c:2728:ffff:ffff:ffff:ffff:ffff,IR
+2001:67c:272c::,2001:67c:272c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2730::,2001:67c:2730:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2734::,2001:67c:2734:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2738::,2001:67c:2738:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:273c::,2001:67c:273c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2740::,2001:67c:2740:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:2744::,2001:67c:2744:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2748::,2001:67c:2748:ffff:ffff:ffff:ffff:ffff,GR
+2001:67c:274c::,2001:67c:274c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2750::,2001:67c:2750:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2758::,2001:67c:2758:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:275c::,2001:67c:275c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2760::,2001:67c:2760:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2764::,2001:67c:2764:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2768::,2001:67c:2768:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:276c::,2001:67c:276c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2770::,2001:67c:2770:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2774::,2001:67c:2774:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2778::,2001:67c:2778:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:277c::,2001:67c:277c:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2780::,2001:67c:2780:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2784::,2001:67c:2784:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2788::,2001:67c:2788:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:278c::,2001:67c:278c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2790::,2001:67c:2790:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2794::,2001:67c:2794:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2798::,2001:67c:2798:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:279c::,2001:67c:279c:ffff:ffff:ffff:ffff:ffff,US
+2001:67c:27a0::,2001:67c:27a7:ffff:ffff:ffff:ffff:ffff,US
+2001:67c:27c0::,2001:67c:27c0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:27c4::,2001:67c:27c4:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:27c8::,2001:67c:27c8:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:27cc::,2001:67c:27cc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:27d0::,2001:67c:27d0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:27d4::,2001:67c:27d4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:27d8::,2001:67c:27d8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:27dc::,2001:67c:27dc:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:27e0::,2001:67c:27e0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:27e4::,2001:67c:27e4:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:27e8::,2001:67c:27e8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:27ec::,2001:67c:27ec:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:27f0::,2001:67c:27f0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:27f4::,2001:67c:27f4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:27f8::,2001:67c:27f8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:27fc::,2001:67c:27fc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2800::,2001:67c:2800:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2804::,2001:67c:2804:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2808::,2001:67c:2808:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:280c::,2001:67c:280c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2810::,2001:67c:2810:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2814::,2001:67c:2814:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2818::,2001:67c:2818:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:281c::,2001:67c:281c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2820::,2001:67c:2820:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2824::,2001:67c:2824:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2828::,2001:67c:2828:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:282c::,2001:67c:282c:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:2830::,2001:67c:2830:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2834::,2001:67c:2834:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2838::,2001:67c:2838:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:283c::,2001:67c:283c:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:2840::,2001:67c:2840:ffff:ffff:ffff:ffff:ffff,IL
+2001:67c:2844::,2001:67c:2844:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2848::,2001:67c:2848:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:284c::,2001:67c:284c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2850::,2001:67c:2850:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2854::,2001:67c:2854:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2858::,2001:67c:2858:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:285c::,2001:67c:285c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2860::,2001:67c:2860:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2864::,2001:67c:2864:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2868::,2001:67c:2868:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:286c::,2001:67c:286c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2870::,2001:67c:2870:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2874::,2001:67c:2874:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2878::,2001:67c:2878:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:287c::,2001:67c:287c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2880::,2001:67c:2880:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2884::,2001:67c:2884:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2888::,2001:67c:2889:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2890::,2001:67c:2890:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2894::,2001:67c:2894:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2898::,2001:67c:2898:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:289c::,2001:67c:289c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:28a0::,2001:67c:28a0:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:28a4::,2001:67c:28a4:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:28a8::,2001:67c:28a8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:28ac::,2001:67c:28ac:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:28b0::,2001:67c:28b0:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:28b4::,2001:67c:28b4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:28b8::,2001:67c:28b8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:28bc::,2001:67c:28bc:ffff:ffff:ffff:ffff:ffff,HU
+2001:67c:28c0::,2001:67c:28c0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:28c4::,2001:67c:28c4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:28c8::,2001:67c:28c8:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:28cc::,2001:67c:28cc:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:28d0::,2001:67c:28d0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:28d4::,2001:67c:28d4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:28d8::,2001:67c:28d8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:28e0::,2001:67c:28e0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:28e4::,2001:67c:28e4:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:28e8::,2001:67c:28e8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:28f0::,2001:67c:28f0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:28f4::,2001:67c:28f4:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:28f8::,2001:67c:28f8:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:28fc::,2001:67c:28fc:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2900::,2001:67c:291f:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2980::,2001:67c:2980:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2984::,2001:67c:2984:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2988::,2001:67c:2989:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:2994::,2001:67c:2994:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:2998::,2001:67c:2998:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:299c::,2001:67c:299c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:29a0::,2001:67c:29a0:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:29a4::,2001:67c:29a4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:29a8::,2001:67c:29a8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:29ac::,2001:67c:29ac:ffff:ffff:ffff:ffff:ffff,CY
+2001:67c:29b0::,2001:67c:29b1:ffff:ffff:ffff:ffff:ffff,CY
+2001:67c:29bc::,2001:67c:29bc:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:29c0::,2001:67c:29c1:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:29c8::,2001:67c:29c8:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:29cc::,2001:67c:29cc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:29d0::,2001:67c:29d0:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:29d4::,2001:67c:29d4:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:29d8::,2001:67c:29d8:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:29dc::,2001:67c:29dc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:29e0::,2001:67c:29e0:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:29e4::,2001:67c:29e4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:29e8::,2001:67c:29e8:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:29ec::,2001:67c:29ec:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:29f0::,2001:67c:29f0:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:29f4::,2001:67c:29f4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:29f8::,2001:67c:29f8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:29fc::,2001:67c:29fc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2a00::,2001:67c:2a00:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2a04::,2001:67c:2a04:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2a08::,2001:67c:2a08:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2a0c::,2001:67c:2a0c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a14::,2001:67c:2a14:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a18::,2001:67c:2a18:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2a1c::,2001:67c:2a1c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2a20::,2001:67c:2a20:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2a24::,2001:67c:2a24:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2a28::,2001:67c:2a28:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2a2c::,2001:67c:2a2c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2a30::,2001:67c:2a30:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a34::,2001:67c:2a34:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a38::,2001:67c:2a38:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2a3c::,2001:67c:2a3c:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:2a40::,2001:67c:2a40:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2a44::,2001:67c:2a44:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2a48::,2001:67c:2a48:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2a4c::,2001:67c:2a4c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2a50::,2001:67c:2a50:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2a54::,2001:67c:2a54:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a58::,2001:67c:2a58:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:2a5c::,2001:67c:2a5c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2a64::,2001:67c:2a64:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2a68::,2001:67c:2a68:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2a6c::,2001:67c:2a6c:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:2a70::,2001:67c:2a70:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2a74::,2001:67c:2a74:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2a78::,2001:67c:2a78:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2a7c::,2001:67c:2a7c:ffff:ffff:ffff:ffff:ffff,DE
+2001:680::,2001:680:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:688::,2001:688:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:690::,2001:690:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:698::,2001:698:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:6a0::,2001:6a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:6a8::,2001:6a8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:6b0::,2001:6b0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:6b8::,2001:6b8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:6c0::,2001:6c0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:6c8::,2001:6cf:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:6d0::,2001:6d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:6d8::,2001:6df:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:6e0::,2001:6e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:6e8::,2001:6ef:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:6f0::,2001:6f0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:6f8::,2001:6f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:700::,2001:700:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:708::,2001:708:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:710::,2001:710:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:718::,2001:718:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:720::,2001:720:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:728::,2001:728:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:730::,2001:737:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:738::,2001:738:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2001:740::,2001:740:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:748::,2001:748:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:750::,2001:750:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:758::,2001:758:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:760::,2001:760:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:768::,2001:768:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:770::,2001:770:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:778::,2001:778:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2001:780::,2001:787:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:788::,2001:788:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:790::,2001:790:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:798::,2001:798:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:7a0::,2001:7a0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:7a8::,2001:7a8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:7b0::,2001:7b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:7b8::,2001:7b8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:7c0::,2001:7c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:7c8::,2001:7c8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:7d0::,2001:7d0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:7d8::,2001:7d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:7e0::,2001:7e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:7e8::,2001:7e8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:7f0::,2001:7f0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8::,2001:7f8:0:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:1::,2001:7f8:1:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:2::,2001:7f8:2:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:3::,2001:7f8:5:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:6::,2001:7f8:6:ffff:ffff:ffff:ffff:ffff,BG
+2001:7f8:7::,2001:7f8:7:ffff:ffff:ffff:ffff:ffff,FI
+2001:7f8:8::,2001:7f8:8:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:9::,2001:7f8:9:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:a::,2001:7f8:a:ffff:ffff:ffff:ffff:ffff,PT
+2001:7f8:b::,2001:7f8:b:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:c::,2001:7f8:c:ffff:ffff:ffff:ffff:ffff,CH
+2001:7f8:d::,2001:7f8:d:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:e::,2001:7f8:e:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:f::,2001:7f8:f:ffff:ffff:ffff:ffff:ffff,ES
+2001:7f8:10::,2001:7f8:10:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:11::,2001:7f8:11:ffff:ffff:ffff:ffff:ffff,LU
+2001:7f8:12::,2001:7f8:12:ffff:ffff:ffff:ffff:ffff,NO
+2001:7f8:13::,2001:7f8:13:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:14::,2001:7f8:14:ffff:ffff:ffff:ffff:ffff,CZ
+2001:7f8:15::,2001:7f8:15:ffff:ffff:ffff:ffff:ffff,EE
+2001:7f8:16::,2001:7f8:16:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:17::,2001:7f8:17:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:18::,2001:7f8:18:ffff:ffff:ffff:ffff:ffff,IE
+2001:7f8:19::,2001:7f8:19:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:1a::,2001:7f8:1a:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8:1b::,2001:7f8:1b:ffff:ffff:ffff:ffff:ffff,BE
+2001:7f8:1c::,2001:7f8:1c:ffff:ffff:ffff:ffff:ffff,CH
+2001:7f8:1d::,2001:7f8:1d:ffff:ffff:ffff:ffff:ffff,FI
+2001:7f8:1e::,2001:7f8:1e:ffff:ffff:ffff:ffff:ffff,RS
+2001:7f8:1f::,2001:7f8:1f:ffff:ffff:ffff:ffff:ffff,DK
+2001:7f8:20::,2001:7f8:20:ffff:ffff:ffff:ffff:ffff,RU
+2001:7f8:21::,2001:7f8:21:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:22::,2001:7f8:22:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:23::,2001:7f8:23:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:24::,2001:7f8:24:ffff:ffff:ffff:ffff:ffff,CH
+2001:7f8:25::,2001:7f8:25:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:26::,2001:7f8:26:ffff:ffff:ffff:ffff:ffff,BE
+2001:7f8:27::,2001:7f8:27:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:28::,2001:7f8:28:ffff:ffff:ffff:ffff:ffff,HR
+2001:7f8:29::,2001:7f8:29:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:2a::,2001:7f8:2a:ffff:ffff:ffff:ffff:ffff,ES
+2001:7f8:2b::,2001:7f8:2c:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8:2d::,2001:7f8:2d:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:2e::,2001:7f8:2e:ffff:ffff:ffff:ffff:ffff,PT
+2001:7f8:2f::,2001:7f8:2f:ffff:ffff:ffff:ffff:ffff,SK
+2001:7f8:30::,2001:7f8:30:ffff:ffff:ffff:ffff:ffff,AT
+2001:7f8:31::,2001:7f8:31:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:33::,2001:7f8:33:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:34::,2001:7f8:34:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:35::,2001:7f8:35:ffff:ffff:ffff:ffff:ffff,HU
+2001:7f8:37::,2001:7f8:38:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:39::,2001:7f8:39:ffff:ffff:ffff:ffff:ffff,EE
+2001:7f8:3a::,2001:7f8:3a:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:3b::,2001:7f8:3b:ffff:ffff:ffff:ffff:ffff,IL
+2001:7f8:3c::,2001:7f8:3c:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8:3d::,2001:7f8:3d:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:3e::,2001:7f8:3e:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:3f::,2001:7f8:3f:ffff:ffff:ffff:ffff:ffff,SK
+2001:7f8:41::,2001:7f8:41:ffff:ffff:ffff:ffff:ffff,NO
+2001:7f8:42::,2001:7f8:42:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:43::,2001:7f8:43:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:44::,2001:7f8:44:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:45::,2001:7f8:45:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:46::,2001:7f8:46:ffff:ffff:ffff:ffff:ffff,SI
+2001:7f8:47::,2001:7f8:47:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:48::,2001:7f8:48:ffff:ffff:ffff:ffff:ffff,IS
+2001:7f8:49::,2001:7f8:49:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8:4a::,2001:7f8:4a:ffff:ffff:ffff:ffff:ffff,AT
+2001:7f8:4b::,2001:7f8:4b:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:4c::,2001:7f8:4c:ffff:ffff:ffff:ffff:ffff,LU
+2001:7f8:4d::,2001:7f8:4d:ffff:ffff:ffff:ffff:ffff,IE
+2001:7f8:4e::,2001:7f8:4e:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:4f::,2001:7f8:4f:ffff:ffff:ffff:ffff:ffff,BH
+2001:7f8:50::,2001:7f8:50:ffff:ffff:ffff:ffff:ffff,EE
+2001:7f8:51::,2001:7f8:51:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:52::,2001:7f8:52:ffff:ffff:ffff:ffff:ffff,LB
+2001:7f8:53::,2001:7f8:53:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:54::,2001:7f8:54:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:55::,2001:7f8:55:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:56::,2001:7f8:56:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:58::,2001:7f8:58:ffff:ffff:ffff:ffff:ffff,BG
+2001:7f8:59::,2001:7f8:59:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:5a::,2001:7f8:5a:ffff:ffff:ffff:ffff:ffff,BY
+2001:7f8:5b::,2001:7f8:5b:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:5c::,2001:7f8:5c:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:5d::,2001:7f8:5d:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:5e::,2001:7f8:5e:ffff:ffff:ffff:ffff:ffff,CZ
+2001:7f8:5f::,2001:7f8:5f:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:60::,2001:7f8:60:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:61::,2001:7f8:61:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:62::,2001:7f8:62:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:63::,2001:7f8:63:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:64::,2001:7f8:64:ffff:ffff:ffff:ffff:ffff,RO
+2001:7f8:66::,2001:7f8:66:ffff:ffff:ffff:ffff:ffff,AT
+2001:7f8:67::,2001:7f8:67:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:68::,2001:7f8:68:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:69::,2001:7f8:69:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:6a::,2001:7f8:6a:ffff:ffff:ffff:ffff:ffff,MD
+2001:7f8:6b::,2001:7f8:6b:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:6c::,2001:7f8:6c:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:6d::,2001:7f8:6d:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:6e::,2001:7f8:6e:ffff:ffff:ffff:ffff:ffff,GR
+2001:7f8:6f::,2001:7f8:6f:ffff:ffff:ffff:ffff:ffff,RU
+2001:7fa:0:1::,2001:7fa:0:1:ffff:ffff:ffff:ffff,HK
+2001:7fa:0:2::,2001:7fa:0:2:ffff:ffff:ffff:ffff,KR
+2001:7fa:0:3::,2001:7fa:0:3:ffff:ffff:ffff:ffff,JP
+2001:7fa:1::,2001:7fa:1:ffff:ffff:ffff:ffff:ffff,TW
+2001:7fa:2::,2001:7fa:2:ffff:ffff:ffff:ffff:ffff,ID
+2001:7fa:3::,2001:7fa:4:ffff:ffff:ffff:ffff:ffff,NZ
+2001:7fa:5::,2001:7fa:5:ffff:ffff:ffff:ffff:ffff,CN
+2001:7fa:6::,2001:7fa:6:ffff:ffff:ffff:ffff:ffff,VN
+2001:7fa:7::,2001:7fa:7:ffff:ffff:ffff:ffff:ffff,JP
+2001:7fa:8::,2001:7fa:8:ffff:ffff:ffff:ffff:ffff,KR
+2001:7fa:9::,2001:7fa:e:ffff:ffff:ffff:ffff:ffff,AU
+2001:7fa:f::,2001:7fa:f:ffff:ffff:ffff:ffff:ffff,ID
+2001:7fa:10::,2001:7fa:10:ffff:ffff:ffff:ffff:ffff,CN
+2001:7fa:11::,2001:7fa:11:ffff:ffff:ffff:ffff:ffff,AU
+2001:7fb::,2001:7fb:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:7fd::,2001:7fd:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:7fe::,2001:7fe:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:808::,2001:808:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:810::,2001:810:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:818::,2001:818:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:820::,2001:820:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:828::,2001:828:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:830::,2001:830:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:838::,2001:83f:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:840::,2001:840:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:848::,2001:848:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:850::,2001:850:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:858::,2001:858:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:860::,2001:860:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:868::,2001:86f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:870::,2001:870:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:878::,2001:878:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:880::,2001:880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:888::,2001:88b:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:890::,2001:890:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:898::,2001:89f:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:8a0::,2001:8a0:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:8a8::,2001:8a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:8b0::,2001:8b0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:8b8::,2001:8bf:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:8c0::,2001:8c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:8c8::,2001:8c8:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2001:8d0::,2001:8d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:8d8::,2001:8d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:8e0::,2001:8e0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:8e8::,2001:8e8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:8f0::,2001:8f0:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2001:8f8::,2001:8f8:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2001:900::,2001:900:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:908::,2001:908:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:910::,2001:910:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:918::,2001:918:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:920::,2001:920:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:928::,2001:928:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:930::,2001:930:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2001:938::,2001:938:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:940::,2001:940:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:948::,2001:948:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:950::,2001:950:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2001:958::,2001:958:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:960::,2001:960:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:968::,2001:968:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:978::,2001:978:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:980::,2001:983:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:988::,2001:988:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:990::,2001:990:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:998::,2001:998:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:9a0::,2001:9a0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:9a8::,2001:9a8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:9b0::,2001:9b0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:9b8::,2001:9b8:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:9c0::,2001:9c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:9c8::,2001:9c8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:9d0::,2001:9d0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:9d8::,2001:9d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:9e0::,2001:9e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:9e8::,2001:9e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:9f0::,2001:9f0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:a00::,2001:a00:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:a08::,2001:a08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:a10::,2001:a10:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:a18::,2001:a18:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:a20::,2001:a20:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:a30::,2001:a30:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:a38::,2001:a38:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:a40::,2001:a40:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:a48::,2001:a48:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:a50::,2001:a50:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:a58::,2001:a58:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:a60::,2001:a60:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:a68::,2001:a68:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:a70::,2001:a70:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:a78::,2001:a78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:a80::,2001:a80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:a88::,2001:a88:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:a90::,2001:a90:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:a98::,2001:a98:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2001:aa0::,2001:aa0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:aa8::,2001:aa8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:ab0::,2001:ab0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:ab8::,2001:ab8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:ac0::,2001:ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:ac8::,2001:ac8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:ad0::,2001:ad0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:ad8::,2001:ae0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:ae8::,2001:ae8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:af0::,2001:af0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:af8::,2001:af8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:b00::,2001:b00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:b08::,2001:b08:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:b10::,2001:b10:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:b18::,2001:b18:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:b20::,2001:b20:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:b28::,2001:b28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:b30::,2001:b30:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2001:b38::,2001:b38:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:b40::,2001:b40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:b48::,2001:b48:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:b50::,2001:b50:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:b58::,2001:b58:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:b60::,2001:b67:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:b68::,2001:b68:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2001:b70::,2001:b70:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:b80::,2001:b80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:b88::,2001:b88:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:b90::,2001:b90:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:b98::,2001:b98:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:ba0::,2001:ba0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:ba8::,2001:ba8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:bb0::,2001:bb0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:bb8::,2001:bb8:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:bc0::,2001:bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:bc8::,2001:bc8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:bd0::,2001:bd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:be0::,2001:be0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:be8::,2001:be8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:bf0::,2001:bf0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:bf8::,2001:bf8:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2001:c00::,2001:c00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:c08::,2001:c08:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:c10::,2001:c10:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:c18::,2001:c18:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:c20::,2001:c20:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:c28::,2001:c28:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c30::,2001:c30:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c38::,2001:c39:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:c40::,2001:c40:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c48::,2001:c48:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:c50::,2001:c50:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:c58::,2001:c58:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:c60::,2001:c60:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2001:c68::,2001:c68:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:c70::,2001:c70:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c78::,2001:c79:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:c80::,2001:c80:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c88::,2001:c88:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c90::,2001:c90:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c98::,2001:c98:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ca0::,2001:ca0:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:ca8::,2001:ca8:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:cb0::,2001:cb0:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:cb8::,2001:cb8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:cc0::,2001:cc0:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:cc8::,2001:cc9:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:cd0::,2001:cd0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:cd8::,2001:cd8:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:ce0::,2001:ce0:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:ce8::,2001:ce8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:cf0::,2001:cf0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:cf8::,2001:cf8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d00::,2001:d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d08::,2001:d08:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:d10::,2001:d10:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:d18::,2001:d18:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:d28::,2001:d28:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d30::,2001:d30:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d38::,2001:d38:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:d40::,2001:d40:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:d48::,2001:d48:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:d50::,2001:d50:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d58::,2001:d58:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:d68::,2001:d68:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:d70::,2001:d73:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d80::,2001:d80:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d88::,2001:d88:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d90::,2001:d90:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d98::,2001:d98:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:da0::,2001:da0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:da8::,2001:daa:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:db0::,2001:db0:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:dc0::,2001:dc0:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:dc1::,2001:dc1:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:dc2::,2001:dc4:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:dc5::,2001:dc5:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:dc6::,2001:dc6:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:dc7::,2001:dc7:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:dc8::,2001:dc8:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2001:dc9::,2001:dc9:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:dca::,2001:dca:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:dcc::,2001:dcc:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:dcd::,2001:dcd:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:dce::,2001:dce:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:dd8::,2001:dd8:0:ffff:ffff:ffff:ffff:ffff,FJ
+2001:dd8:1::,2001:dd8:1:ffff:ffff:ffff:ffff:ffff,CN
+2001:dd8:2::,2001:dd8:2:ffff:ffff:ffff:ffff:ffff,MY
+2001:dd8:3::,2001:dd8:3:ffff:ffff:ffff:ffff:ffff,NZ
+2001:dd8:4::,2001:dd8:4:ffff:ffff:ffff:ffff:ffff,SG
+2001:dd8:5::,2001:dd8:5:ffff:ffff:ffff:ffff:ffff,CN
+2001:dd8:6::,2001:dd8:6:ffff:ffff:ffff:ffff:ffff,AU
+2001:dd8:7::,2001:dd8:7:ffff:ffff:ffff:ffff:ffff,NP
+2001:dd8:8::,2001:dd8:f:ffff:ffff:ffff:ffff:ffff,AU
+2001:dd8:10::,2001:dd8:11:ffff:ffff:ffff:ffff:ffff,NP
+2001:dd8:12::,2001:dd8:12:ffff:ffff:ffff:ffff:ffff,AU
+2001:dd8:13::,2001:dd8:13:ffff:ffff:ffff:ffff:ffff,NZ
+2001:dd8:14::,2001:dd8:14:ffff:ffff:ffff:ffff:ffff,AU
+2001:dd8:15::,2001:dd8:15:ffff:ffff:ffff:ffff:ffff,HK
+2001:dd8:16::,2001:dd8:16:ffff:ffff:ffff:ffff:ffff,SG
+2001:dd8:17::,2001:dd8:17:ffff:ffff:ffff:ffff:ffff,KR
+2001:dd8:18::,2001:dd8:18:ffff:ffff:ffff:ffff:ffff,TW
+2001:dd8:19::,2001:dd8:19:ffff:ffff:ffff:ffff:ffff,IN
+2001:dd8:1a::,2001:dd8:1a:ffff:ffff:ffff:ffff:ffff,CN
+2001:dd8:1b::,2001:dd8:1b:ffff:ffff:ffff:ffff:ffff,IN
+2001:dd8:1c::,2001:dd8:1c:ffff:ffff:ffff:ffff:ffff,PK
+2001:dd8:1d::,2001:dd8:1d:ffff:ffff:ffff:ffff:ffff,BD
+2001:dd8:1e::,2001:dd8:1e:ffff:ffff:ffff:ffff:ffff,KH
+2001:dd8:1f::,2001:dd8:1f:ffff:ffff:ffff:ffff:ffff,ID
+2001:dd8:20::,2001:dd8:21:ffff:ffff:ffff:ffff:ffff,IN
+2001:dd8:22::,2001:dd8:22:ffff:ffff:ffff:ffff:ffff,JP
+2001:dd8:24::,2001:dd8:25:ffff:ffff:ffff:ffff:ffff,NP
+2001:de1::,2001:de1:3f:ffff:ffff:ffff:ffff:ffff,JP
+2001:de8::,2001:de8:0:ffff:ffff:ffff:ffff:ffff,TH
+2001:de8:1::,2001:de8:1:ffff:ffff:ffff:ffff:ffff,IN
+2001:de8:2::,2001:de8:2:ffff:ffff:ffff:ffff:ffff,ID
+2001:de8:3::,2001:de8:3:ffff:ffff:ffff:ffff:ffff,VN
+2001:de8:4::,2001:de8:7:ffff:ffff:ffff:ffff:ffff,SG
+2001:de8:8::,2001:de8:8:ffff:ffff:ffff:ffff:ffff,JP
+2001:de8:9::,2001:de8:9:ffff:ffff:ffff:ffff:ffff,AU
+2001:de8:a::,2001:de8:a:ffff:ffff:ffff:ffff:ffff,VN
+2001:de8:b::,2001:de8:b:ffff:ffff:ffff:ffff:ffff,BD
+2001:de8:c::,2001:de8:c:ffff:ffff:ffff:ffff:ffff,JP
+2001:de8:d::,2001:de8:d:ffff:ffff:ffff:ffff:ffff,SG
+2001:de8:e::,2001:de8:e:ffff:ffff:ffff:ffff:ffff,TH
+2001:de8:f::,2001:de8:10:ffff:ffff:ffff:ffff:ffff,MY
+2001:de8:11::,2001:de8:11:ffff:ffff:ffff:ffff:ffff,ID
+2001:de8:12::,2001:de8:12:ffff:ffff:ffff:ffff:ffff,SG
+2001:de8:13::,2001:de8:13:ffff:ffff:ffff:ffff:ffff,MY
+2001:de8:14::,2001:de8:14:ffff:ffff:ffff:ffff:ffff,AU
+2001:de8:15::,2001:de8:15:ffff:ffff:ffff:ffff:ffff,ID
+2001:de8:16::,2001:de8:16:ffff:ffff:ffff:ffff:ffff,PF
+2001:de8:17::,2001:de8:17:ffff:ffff:ffff:ffff:ffff,AU
+2001:de8:19::,2001:de8:19:ffff:ffff:ffff:ffff:ffff,NZ
+2001:de8:1a::,2001:de8:1a:ffff:ffff:ffff:ffff:ffff,ID
+2001:de8:1b::,2001:de8:1b:ffff:ffff:ffff:ffff:ffff,MY
+2001:de8:1c::,2001:de8:1d:ffff:ffff:ffff:ffff:ffff,KH
+2001:df0::,2001:df0:1:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2::,2001:df0:2:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:3::,2001:df0:4:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:7::,2001:df0:7:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:8::,2001:df0:8:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:9::,2001:df0:a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:c::,2001:df0:13:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:14::,2001:df0:14:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:15::,2001:df0:15:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:17::,2001:df0:17:ffff:ffff:ffff:ffff:ffff,LK
+2001:df0:18::,2001:df0:18:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:19::,2001:df0:1d:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:1e::,2001:df0:1e:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:1f::,2001:df0:1f:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:20::,2001:df0:3f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:40::,2001:df0:40:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:41::,2001:df0:41:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:42::,2001:df0:42:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:43::,2001:df0:43:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:44::,2001:df0:44:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:45::,2001:df0:46:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:48::,2001:df0:48:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:49::,2001:df0:49:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:4a::,2001:df0:4a:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:4b::,2001:df0:4d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:4f::,2001:df0:60:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:62::,2001:df0:62:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:63::,2001:df0:63:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:65::,2001:df0:65:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:66::,2001:df0:66:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:67::,2001:df0:67:ffff:ffff:ffff:ffff:ffff,FJ
+2001:df0:68::,2001:df0:68:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:69::,2001:df0:69:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:6a::,2001:df0:6a:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:6b::,2001:df0:6b:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:6c::,2001:df0:6c:ffff:ffff:ffff:ffff:ffff,WS
+2001:df0:6e::,2001:df0:6f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:70::,2001:df0:70:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:71::,2001:df0:71:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:73::,2001:df0:74:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:75::,2001:df0:75:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:76::,2001:df0:76:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:77::,2001:df0:77:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:78::,2001:df0:78:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:79::,2001:df0:79:ffff:ffff:ffff:ffff:ffff,MN
+2001:df0:7b::,2001:df0:7c:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:7d::,2001:df0:7d:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:7e::,2001:df0:81:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:82::,2001:df0:82:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:83::,2001:df0:83:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:84::,2001:df0:84:ffff:ffff:ffff:ffff:ffff,PK
+2001:df0:85::,2001:df0:85:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:86::,2001:df0:87:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:89::,2001:df0:89:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:8a::,2001:df0:8a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:8b::,2001:df0:8b:ffff:ffff:ffff:ffff:ffff,NP
+2001:df0:8c::,2001:df0:8c:ffff:ffff:ffff:ffff:ffff,NU
+2001:df0:8d::,2001:df0:8d:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:8e::,2001:df0:90:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:91::,2001:df0:91:ffff:ffff:ffff:ffff:ffff,FJ
+2001:df0:92::,2001:df0:92:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:93::,2001:df0:93:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:94::,2001:df0:94:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:95::,2001:df0:95:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:96::,2001:df0:96:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:97::,2001:df0:97:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:98::,2001:df0:9a:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:9b::,2001:df0:9b:ffff:ffff:ffff:ffff:ffff,FJ
+2001:df0:9c::,2001:df0:9c:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:9d::,2001:df0:9d:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:9e::,2001:df0:9e:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:9f::,2001:df0:9f:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:a0::,2001:df0:a1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:a2::,2001:df0:a2:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:a3::,2001:df0:a3:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:a4::,2001:df0:a4:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:a5::,2001:df0:a6:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:a7::,2001:df0:ac:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:ad::,2001:df0:ad:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:ae::,2001:df0:ae:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:af::,2001:df0:b0:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:b1::,2001:df0:b8:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:b9::,2001:df0:b9:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:ba::,2001:df0:bd:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:be::,2001:df0:be:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:bf::,2001:df0:bf:ffff:ffff:ffff:ffff:ffff,LA
+2001:df0:c0::,2001:df0:c0:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:c1::,2001:df0:c2:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:c4::,2001:df0:c4:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:c5::,2001:df0:c5:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:c6::,2001:df0:c6:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:c7::,2001:df0:c8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:c9::,2001:df0:cc:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:cd::,2001:df0:cd:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:ce::,2001:df0:ce:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:cf::,2001:df0:cf:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:d1::,2001:df0:d1:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:d2::,2001:df0:d2:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:d3::,2001:df0:d3:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:d4::,2001:df0:d6:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:d7::,2001:df0:d7:ffff:ffff:ffff:ffff:ffff,KR
+2001:df0:d8::,2001:df0:d8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:d9::,2001:df0:d9:ffff:ffff:ffff:ffff:ffff,TW
+2001:df0:da::,2001:df0:da:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:db::,2001:df0:db:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:dc::,2001:df0:dc:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:dd::,2001:df0:dd:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:de::,2001:df0:df:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:e0::,2001:df0:e1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:e2::,2001:df0:e2:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:e3::,2001:df0:e3:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:e4::,2001:df0:e5:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:e6::,2001:df0:e6:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:e7::,2001:df0:e8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:e9::,2001:df0:e9:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:ea::,2001:df0:ea:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:eb::,2001:df0:eb:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:ed::,2001:df0:ed:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:ee::,2001:df0:ee:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:ef::,2001:df0:f0:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:f1::,2001:df0:f1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:f2::,2001:df0:f2:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:f3::,2001:df0:f3:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:f4::,2001:df0:f4:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:f5::,2001:df0:f5:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:f6::,2001:df0:f6:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:f7::,2001:df0:f7:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:f8::,2001:df0:fa:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:fb::,2001:df0:fb:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:fc::,2001:df0:fc:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:fd::,2001:df0:fe:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:100::,2001:df0:1ff:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:200::,2001:df0:200:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:201::,2001:df0:201:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:202::,2001:df0:202:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:203::,2001:df0:203:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:204::,2001:df0:204:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:205::,2001:df0:205:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:206::,2001:df0:206:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:207::,2001:df0:207:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:208::,2001:df0:208:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:209::,2001:df0:209:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:20a::,2001:df0:20a:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:20b::,2001:df0:20b:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:20c::,2001:df0:20c:ffff:ffff:ffff:ffff:ffff,NF
+2001:df0:20d::,2001:df0:20d:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:20e::,2001:df0:20f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:210::,2001:df0:210:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:211::,2001:df0:211:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:212::,2001:df0:212:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:213::,2001:df0:213:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:214::,2001:df0:214:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:215::,2001:df0:215:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:216::,2001:df0:217:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:218::,2001:df0:219:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:21a::,2001:df0:21a:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:21b::,2001:df0:21b:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:21c::,2001:df0:21c:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:21d::,2001:df0:21d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:21e::,2001:df0:21e:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:21f::,2001:df0:220:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:221::,2001:df0:221:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:222::,2001:df0:222:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:224::,2001:df0:224:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:225::,2001:df0:225:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:226::,2001:df0:228:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:229::,2001:df0:229:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:22a::,2001:df0:22a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:22b::,2001:df0:22b:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:22c::,2001:df0:22d:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:22e::,2001:df0:22f:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:230::,2001:df0:230:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:231::,2001:df0:231:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:232::,2001:df0:232:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:233::,2001:df0:234:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:235::,2001:df0:235:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:237::,2001:df0:237:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:238::,2001:df0:238:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:239::,2001:df0:239:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:23a::,2001:df0:23a:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:23b::,2001:df0:23b:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:23c::,2001:df0:23d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:23e::,2001:df0:23e:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:23f::,2001:df0:23f:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:240::,2001:df0:241:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:242::,2001:df0:242:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:243::,2001:df0:243:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:245::,2001:df0:246:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:247::,2001:df0:247:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:248::,2001:df0:248:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:249::,2001:df0:24a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:24b::,2001:df0:24b:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:24c::,2001:df0:24c:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:24d::,2001:df0:24d:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:24e::,2001:df0:24e:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:24f::,2001:df0:24f:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:250::,2001:df0:250:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:251::,2001:df0:252:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:253::,2001:df0:253:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:254::,2001:df0:254:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:255::,2001:df0:255:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:256::,2001:df0:256:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:257::,2001:df0:257:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:258::,2001:df0:258:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:259::,2001:df0:259:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:25a::,2001:df0:25a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:25b::,2001:df0:25b:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:25c::,2001:df0:25d:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:25e::,2001:df0:25e:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:25f::,2001:df0:25f:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:260::,2001:df0:260:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:261::,2001:df0:261:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:262::,2001:df0:262:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:263::,2001:df0:263:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:264::,2001:df0:264:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:265::,2001:df0:265:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:266::,2001:df0:266:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:267::,2001:df0:267:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:268::,2001:df0:269:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:26a::,2001:df0:26b:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:26c::,2001:df0:26c:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:26d::,2001:df0:26f:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:270::,2001:df0:270:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:271::,2001:df0:271:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:272::,2001:df0:272:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:273::,2001:df0:273:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:274::,2001:df0:277:ffff:ffff:ffff:ffff:ffff,NP
+2001:df0:278::,2001:df0:278:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:279::,2001:df0:279:ffff:ffff:ffff:ffff:ffff,PK
+2001:df0:27a::,2001:df0:27a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:27b::,2001:df0:27b:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:27c::,2001:df0:27c:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:27d::,2001:df0:27d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:27e::,2001:df0:27e:ffff:ffff:ffff:ffff:ffff,CN
+2001:df0:27f::,2001:df0:27f:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:280::,2001:df0:28f:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:290::,2001:df0:290:ffff:ffff:ffff:ffff:ffff,KR
+2001:df0:291::,2001:df0:291:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:292::,2001:df0:292:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:293::,2001:df0:293:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:294::,2001:df0:294:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:295::,2001:df0:296:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:298::,2001:df0:298:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:299::,2001:df0:299:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:29a::,2001:df0:29a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:29b::,2001:df0:29b:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:29c::,2001:df0:29c:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:29d::,2001:df0:29d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:29f::,2001:df0:29f:ffff:ffff:ffff:ffff:ffff,BD
+2001:df0:2a0::,2001:df0:2a0:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:2a1::,2001:df0:2a1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2a2::,2001:df0:2a2:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:2a3::,2001:df0:2a3:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2a4::,2001:df0:2a4:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2a5::,2001:df0:2a5:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:2a6::,2001:df0:2a6:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2a7::,2001:df0:2a7:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2a8::,2001:df0:2a8:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:2a9::,2001:df0:2aa:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2ab::,2001:df0:2ab:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2ac::,2001:df0:2ac:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:2ad::,2001:df0:2ad:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2ae::,2001:df0:2ae:ffff:ffff:ffff:ffff:ffff,WS
+2001:df0:2af::,2001:df0:2af:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:2b0::,2001:df0:2b1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2b2::,2001:df0:2b2:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2b3::,2001:df0:2b3:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2b4::,2001:df0:2b4:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2b5::,2001:df0:2b5:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2b6::,2001:df0:2b6:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2b7::,2001:df0:2b7:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2b8::,2001:df0:2b8:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:2b9::,2001:df0:2b9:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2ba::,2001:df0:2ba:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:2bb::,2001:df0:2bb:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2bc::,2001:df0:2bc:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2bd::,2001:df0:2bd:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2be::,2001:df0:2be:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2bf::,2001:df0:2bf:ffff:ffff:ffff:ffff:ffff,GB
+2001:df0:2c0::,2001:df0:2c0:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:2c1::,2001:df0:2c1:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2c2::,2001:df0:2c2:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2c3::,2001:df0:2c3:ffff:ffff:ffff:ffff:ffff,BD
+2001:df0:2c4::,2001:df0:2c4:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2c5::,2001:df0:2c5:ffff:ffff:ffff:ffff:ffff,BD
+2001:df0:2c6::,2001:df0:2c8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2c9::,2001:df0:2c9:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2ca::,2001:df0:2ca:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2cb::,2001:df0:2cb:ffff:ffff:ffff:ffff:ffff,PK
+2001:df0:2cc::,2001:df0:2cc:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2cd::,2001:df0:2cd:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:2ce::,2001:df0:2e0:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2e1::,2001:df0:2e1:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2e2::,2001:df0:2e2:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2e3::,2001:df0:2e3:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2e4::,2001:df0:2e4:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2e5::,2001:df0:2e5:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2e6::,2001:df0:2e7:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2e8::,2001:df0:2e8:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:2e9::,2001:df0:2e9:ffff:ffff:ffff:ffff:ffff,CN
+2001:df0:2ea::,2001:df0:2ea:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2eb::,2001:df0:2eb:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2ec::,2001:df0:2ec:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2ed::,2001:df0:2ee:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2ef::,2001:df0:2ef:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:2f0::,2001:df0:2f3:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2f4::,2001:df0:2f4:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2f5::,2001:df0:2f5:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2f6::,2001:df0:2f6:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2f7::,2001:df0:2f7:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:2f8::,2001:df0:2f8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2f9::,2001:df0:2f9:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2fa::,2001:df0:2fa:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2fb::,2001:df0:2fb:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:2fc::,2001:df0:2fc:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2fd::,2001:df0:2fd:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2fe::,2001:df0:2ff:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:300::,2001:df0:30f:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:400::,2001:df0:400:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:401::,2001:df0:401:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:402::,2001:df0:403:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:404::,2001:df0:404:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:405::,2001:df0:405:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:406::,2001:df0:406:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:407::,2001:df0:407:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:408::,2001:df0:408:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:409::,2001:df0:409:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:40a::,2001:df0:40a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:40c::,2001:df0:40c:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:40d::,2001:df0:40d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:40e::,2001:df0:40f:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:410::,2001:df0:410:ffff:ffff:ffff:ffff:ffff,VU
+2001:df0:411::,2001:df0:411:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:412::,2001:df0:412:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:413::,2001:df0:413:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:415::,2001:df0:415:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:416::,2001:df0:416:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:500::,2001:df0:5ff:ffff:ffff:ffff:ffff:ffff,AU
+2001:df8::,2001:df9:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:dfa::,2001:dfa:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e00::,2001:e01:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:e08::,2001:e08:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:e10::,2001:e10:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:e18::,2001:e18:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:e20::,2001:e20:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:e28::,2001:e28:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:e30::,2001:e30:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:e38::,2001:e38:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e40::,2001:e47:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e48::,2001:e48:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:e50::,2001:e50:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e58::,2001:e58:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e60::,2001:e60:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:e68::,2001:e68:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:e70::,2001:e70:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:e78::,2001:e78:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:e80::,2001:e80:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:e88::,2001:e88:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:e90::,2001:e90:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e98::,2001:e98:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ea0::,2001:ea0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ea8::,2001:ea8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:eb0::,2001:eb0:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:eb8::,2001:eb8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ec0::,2001:ec0:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:ec8::,2001:ec8:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:ed0::,2001:ed0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ed8::,2001:ed8:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:ee0::,2001:ee0:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2001:ee8::,2001:ee8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ef0::,2001:ef0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ef8::,2001:ef8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:f00::,2001:f00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:f08::,2001:f08:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:f10::,2001:f10:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:f18::,2001:f18:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:f20::,2001:f20:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:f28::,2001:f28:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:f30::,2001:f30:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:f38::,2001:f38:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:f40::,2001:f40:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:f48::,2001:f48:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:f50::,2001:f50:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:f58::,2001:f58:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:f60::,2001:f6f:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:f80::,2001:f80:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:f88::,2001:f88:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:f90::,2001:f90:ffff:ffff:ffff:ffff:ffff:ffff,MO
+2001:f98::,2001:f98:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fa0::,2001:fa0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fa8::,2001:fa8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fb0::,2001:fb1:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:fb8::,2001:fb8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fc0::,2001:fc0:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:fc8::,2001:fc8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fd0::,2001:fd0:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:fd8::,2001:fd8:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:fe0::,2001:fe0:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:fe8::,2001:fe8:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2001:ff0::,2001:ff0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:ff8::,2001:ff8:ffff:ffff:ffff:ffff:ffff:ffff,MO
+2001:1200::,2001:1200:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1208::,2001:1208:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1210::,2001:1210:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1218::,2001:1218:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1220::,2001:1220:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1228::,2001:1228:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:122c::,2001:122c:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1230::,2001:1230:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1238::,2001:1238:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1240::,2001:1240:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1248::,2001:1248:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1250::,2001:1250:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1258::,2001:1258:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1260::,2001:1260:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1270::,2001:1270:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1278::,2001:1278:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1280::,2001:12ff:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2001:1300::,2001:1300:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2001:1308::,2001:1308:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2001:1310::,2001:1310:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2001:1318::,2001:1318:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2001:1320::,2001:1320:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2001:1328::,2001:1328:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2001:1330::,2001:1337:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2001:1338::,2001:1338:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2001:1340::,2001:1340:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2001:1348::,2001:1348:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2001:1350::,2001:1350:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2001:1358::,2001:1358:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2001:1360::,2001:1360:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2001:1368::,2001:1368:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2001:1370::,2001:1370:ffff:ffff:ffff:ffff:ffff:ffff,HT
+2001:1378::,2001:1378:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2001:1380::,2001:1380:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2001:1388::,2001:1388:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2001:1398::,2001:1398:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2001:13a0::,2001:13a0:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2001:13a8::,2001:13a8:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:13b0::,2001:13b7:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2001:13c7:6000::,2001:13c7:6000:ffff:ffff:ffff:ffff:ffff,CO
+2001:13c7:6001::,2001:13c7:6001:ffff:ffff:ffff:ffff:ffff,AR
+2001:13c7:6002::,2001:13c7:6002:ffff:ffff:ffff:ffff:ffff,CW
+2001:13c7:6003::,2001:13c7:6003:ffff:ffff:ffff:ffff:ffff,HT
+2001:13c7:6004::,2001:13c7:6005:ffff:ffff:ffff:ffff:ffff,CW
+2001:13c7:6006::,2001:13c7:6006:ffff:ffff:ffff:ffff:ffff,EC
+2001:13c7:6007::,2001:13c7:600e:ffff:ffff:ffff:ffff:ffff,AR
+2001:13c7:6010::,2001:13c7:601f:ffff:ffff:ffff:ffff:ffff,AR
+2001:13c7:6f00::,2001:13c7:6fff:ffff:ffff:ffff:ffff:ffff,EC
+2001:13c7:7000::,2001:13c7:7000:ffff:ffff:ffff:ffff:ffff,MX
+2001:13c7:7001::,2001:13c7:7003:ffff:ffff:ffff:ffff:ffff,UY
+2001:13c7:7004::,2001:13c7:7004:ffff:ffff:ffff:ffff:ffff,CR
+2001:13c7:7005::,2001:13c7:7009:ffff:ffff:ffff:ffff:ffff,UY
+2001:13c7:7010::,2001:13c7:7013:ffff:ffff:ffff:ffff:ffff,UY
+2001:13c7:7014::,2001:13c7:7014:ffff:ffff:ffff:ffff:ffff,MX
+2001:13c8::,2001:13c8:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2001:13d0::,2001:13d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2001:13d8::,2001:13d8:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2001:13e0::,2001:13e0:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2001:13e8::,2001:13e8:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2001:13f0::,2001:13f0:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2001:13f8::,2001:13f8:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2001:1400::,2001:1400:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1408::,2001:1408:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:1410::,2001:1410:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1418::,2001:1418:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1420::,2001:1420:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1428::,2001:1428:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:1430::,2001:1430:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:1438::,2001:1438:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1440::,2001:1440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1448::,2001:1448:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:1450::,2001:1450:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1458::,2001:1459:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1460::,2001:1460:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1468::,2001:1468:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1470::,2001:1477:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2001:1478::,2001:1478:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1488::,2001:1488:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1490::,2001:1490:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2001:1498::,2001:1498:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:14a0::,2001:14a0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:14a8::,2001:14a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:14b0::,2001:14b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14b8::,2001:14b8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:14c0::,2001:14c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14c8::,2001:14c8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:14d0::,2001:14d0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:14d8::,2001:14d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14e0::,2001:14e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14e8::,2001:14e8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:14f0::,2001:14f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14f8::,2001:14f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1500::,2001:1500:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:1508::,2001:1508:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1510::,2001:1510:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1520::,2001:1520:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1528::,2001:1528:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1530::,2001:1530:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:1538::,2001:1538:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1540::,2001:1540:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1548::,2001:1548:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2001:1558::,2001:1558:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1560::,2001:1560:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1568::,2001:1568:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1570::,2001:1570:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1578::,2001:1578:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1580::,2001:1580:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:1588::,2001:1588:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:1590::,2001:1590:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2001:1598::,2001:1598:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:15a0::,2001:15a0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:15a8::,2001:15a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:15b0::,2001:15b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:15b8::,2001:15b8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:15c0::,2001:15c0:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2001:15c8::,2001:15c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:15d0::,2001:15d0:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2001:15d8::,2001:15d8:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:15e0::,2001:15e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:15e8::,2001:15e8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:15f0::,2001:15f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:15f8::,2001:15f8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:1600::,2001:1600:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1608::,2001:1608:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1610::,2001:1610:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:1618::,2001:1618:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:1620::,2001:1620:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1628::,2001:1628:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1630::,2001:1630:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1638::,2001:1638:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1640::,2001:1640:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1650::,2001:1650:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1658::,2001:1658:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:1660::,2001:1660:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1668::,2001:1668:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1670::,2001:1670:ffff:ffff:ffff:ffff:ffff:ffff,OM
+2001:1678::,2001:1678:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1680::,2001:1687:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1688::,2001:1688:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2001:1690::,2001:1690:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1698::,2001:1698:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:16a0::,2001:16a7:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2001:16a8::,2001:16a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:16b0::,2001:16b0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:16b8::,2001:16b8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:16c0::,2001:16c0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:16c8::,2001:16c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:16d0::,2001:16d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:16d8::,2001:16d8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:16e0::,2001:16e7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:16e8::,2001:16e8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:16f0::,2001:16f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:16f8::,2001:16f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1700::,2001:171f:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1800::,2001:1800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1808::,2001:1808:ffff:ffff:ffff:ffff:ffff:ffff,GD
+2001:1810::,2001:1810:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1818::,2001:1818:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1820::,2001:1820:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1828::,2001:1828:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1830::,2001:1830:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1838::,2001:1838:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1840::,2001:1840:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1848::,2001:1848:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1850::,2001:1850:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1858::,2001:1858:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1860::,2001:1860:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1868::,2001:1868:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1878::,2001:1878:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1880::,2001:1880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1888::,2001:1888:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1890::,2001:1898:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18a0::,2001:18a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18a8::,2001:18a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18b0::,2001:18b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18b8::,2001:18b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18c0::,2001:18c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:18c8::,2001:18c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18d8::,2001:18d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18e0::,2001:18e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18e8::,2001:18e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18f0::,2001:18f0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:18f8::,2001:18f8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:1900::,2001:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1908::,2001:1908:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1910::,2001:1910:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1920::,2001:1920:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:1928::,2001:1928:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:1930::,2001:1930:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1938::,2001:1938:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1940::,2001:1940:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1948::,2001:1948:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1950::,2001:1950:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1958::,2001:1958:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1960::,2001:1960:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1968::,2001:1968:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1970::,2001:1970:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:1978::,2001:1978:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1980::,2001:1980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1988::,2001:1988:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1990::,2001:1990:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1998::,2001:1998:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19a0::,2001:19a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19a8::,2001:19a8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:19b0::,2001:19b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19b8::,2001:19b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19c0::,2001:19c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:19c8::,2001:19c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19d0::,2001:19d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19d8::,2001:19d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19e0::,2001:19e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19e8::,2001:19e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19f0::,2001:19f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19f8::,2001:19f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1a00::,2001:1a00:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:1a08::,2001:1a08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1a10::,2001:1a10:ffff:ffff:ffff:ffff:ffff:ffff,QA
+2001:1a18::,2001:1a18:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2001:1a20::,2001:1a20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1a28::,2001:1a28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a30::,2001:1a30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a38::,2001:1a38:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1a40::,2001:1a40:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2001:1a48::,2001:1a48:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1a50::,2001:1a50:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a58::,2001:1a58:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:1a60::,2001:1a60:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1a68::,2001:1a68:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:1a70::,2001:1a70:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2001:1a78::,2001:1a78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a80::,2001:1a80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a88::,2001:1a88:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1a90::,2001:1a90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1a98::,2001:1a98:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2001:1aa0::,2001:1aa0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2001:1aa8::,2001:1aa8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1ab0::,2001:1ab0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1ab8::,2001:1ab8:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2001:1ac0::,2001:1ac0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1ac8::,2001:1ac8:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2001:1ad0::,2001:1ad0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:1ad8::,2001:1ad8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:1ae0::,2001:1ae0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2001:1ae8::,2001:1aef:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1af0::,2001:1af0:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2001:1af8::,2001:1af8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1b00::,2001:1b00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:1b08::,2001:1b08:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b10::,2001:1b10:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b18::,2001:1b18:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b20::,2001:1b20:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b28::,2001:1b28:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:1b30::,2001:1b30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b38::,2001:1b38:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b40::,2001:1b40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1b48::,2001:1b48:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b50::,2001:1b50:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1b58::,2001:1b58:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b60::,2001:1b60:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b68::,2001:1b68:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2001:1b70::,2001:1b70:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1b78::,2001:1b78:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b80::,2001:1b80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:1b88::,2001:1b88:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1b90::,2001:1b90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1b98::,2001:1b98:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:1ba0::,2001:1ba0:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2001:1ba8::,2001:1ba8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1bb0::,2001:1bb0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:1bb8::,2001:1bb8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:1bc0::,2001:1bc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1bc8::,2001:1bc8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:1bd0::,2001:1bd0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1bd8::,2001:1bd8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:1be0::,2001:1be0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1be8::,2001:1be8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1bf0::,2001:1bf0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:1bf8::,2001:1bf8:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2001:1c00::,2001:1dff:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:2000::,2001:2fff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:4000::,2001:4000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4010::,2001:4010:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4018::,2001:4018:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4020::,2001:4020:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4028::,2001:4028:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4030::,2001:4030:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4038::,2001:4038:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4040::,2001:4040:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:4048::,2001:4048:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2001:4050::,2001:4050:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4058::,2001:4058:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:4060::,2001:4060:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4068::,2001:4068:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4070::,2001:4070:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4078::,2001:4078:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:4080::,2001:4080:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4088::,2001:4088:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4090::,2001:4090:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4098::,2001:4098:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2001:40a0::,2001:40a0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:40a8::,2001:40a8:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2001:40b0::,2001:40b0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:40b8::,2001:40b8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:40c0::,2001:40c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:40c8::,2001:40c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:40d0::,2001:40d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:40d8::,2001:40d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:40e0::,2001:40e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:40e8::,2001:40e8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:40f0::,2001:40f0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:40f8::,2001:40f8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4100::,2001:4100:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4108::,2001:4108:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4118::,2001:4118:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2001:4120::,2001:4120:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4128::,2001:4128:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4130::,2001:4130:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2001:4138::,2001:4138:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4140::,2001:4140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4150::,2001:4150:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4158::,2001:4158:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:4160::,2001:4160:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4168::,2001:4168:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4170::,2001:4170:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2001:4178::,2001:4178:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4180::,2001:4180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4188::,2001:4188:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:4190::,2001:4190:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4198::,2001:4198:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:41a0::,2001:41a0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:41a8::,2001:41a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:41b0::,2001:41b0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:41b8::,2001:41b8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:41c0::,2001:41c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:41d0::,2001:41d0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:41d8::,2001:41d8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:41e0::,2001:41e0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:41e8::,2001:41e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:41f0::,2001:41f0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:41f8::,2001:41f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4200::,2001:4200:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4208::,2001:4208:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4210::,2001:4210:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4218::,2001:4218:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4220::,2001:4220:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:4228::,2001:4228:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2001:4230::,2001:4230:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:4238::,2001:4238:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:4240::,2001:4240:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2001:4248::,2001:4248:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2001:4250::,2001:4250:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2001:4258::,2001:4258:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2001:4260::,2001:4260:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4268::,2001:4268:ffff:ffff:ffff:ffff:ffff:ffff,CM
+2001:4270::,2001:4270:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2001:4278::,2001:4278:ffff:ffff:ffff:ffff:ffff:ffff,SN
+2001:4288::,2001:4288:ffff:ffff:ffff:ffff:ffff:ffff,MA
+2001:4290::,2001:4290:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2001:4298::,2001:4298:ffff:ffff:ffff:ffff:ffff:ffff,DJ
+2001:42a0::,2001:42a0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:42a8::,2001:42a8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:42b0::,2001:42b0:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2001:42b8::,2001:42b8:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:42c0::,2001:42c0:ffff:ffff:ffff:ffff:ffff:ffff,ML
+2001:42c8::,2001:42c8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:42d0::,2001:42d0:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2001:42d8::,2001:42d8:ffff:ffff:ffff:ffff:ffff:ffff,CI
+2001:42e0::,2001:42e0:ffff:ffff:ffff:ffff:ffff:ffff,SC
+2001:42f0::,2001:42f0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:42f8::,2001:42f8:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2001:4300::,2001:4300:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:4308::,2001:4308:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4310::,2001:4310:ffff:ffff:ffff:ffff:ffff:ffff,MA
+2001:4318::,2001:4318:ffff:ffff:ffff:ffff:ffff:ffff,CI
+2001:4320::,2001:4320:ffff:ffff:ffff:ffff:ffff:ffff,BJ
+2001:4328::,2001:4328:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2001:4330::,2001:4330:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4338::,2001:4338:ffff:ffff:ffff:ffff:ffff:ffff,SZ
+2001:4340::,2001:4340:ffff:ffff:ffff:ffff:ffff:ffff,DZ
+2001:4350::,2001:4350:ffff:ffff:ffff:ffff:ffff:ffff,TN
+2001:4358::,2001:4358:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:4368::,2001:4368:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:4370::,2001:4370:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:4378::,2001:4378:ffff:ffff:ffff:ffff:ffff:ffff,MZ
+2001:4388::,2001:4388:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:4398::,2001:4398:ffff:ffff:ffff:ffff:ffff:ffff,MG
+2001:43a0::,2001:43a0:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43a8::,2001:43a8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43b0::,2001:43b0:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2001:43b8::,2001:43b8:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2001:43c0::,2001:43c0:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2001:43c8::,2001:43c8:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:43d0::,2001:43d0:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:43d8::,2001:43d8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43e0::,2001:43e0:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2001:43e8::,2001:43e8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f0::,2001:43f0:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2001:43f8::,2001:43f8:0:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:10::,2001:43f8:10:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:20::,2001:43f8:20:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:30::,2001:43f8:30:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:50::,2001:43f8:50:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:60::,2001:43f8:60:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:70::,2001:43f8:77:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:80::,2001:43f8:80:ffff:ffff:ffff:ffff:ffff,NA
+2001:43f8:90::,2001:43f8:90:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:a0::,2001:43f8:a0:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:b0::,2001:43f8:b0:ffff:ffff:ffff:ffff:ffff,SL
+2001:43f8:c0::,2001:43f8:c0:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:d0::,2001:43f8:d0:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:e0::,2001:43f8:e0:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:100::,2001:43f8:100:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:110::,2001:43f8:110:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:120::,2001:43f8:120:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:130::,2001:43f8:130:ffff:ffff:ffff:ffff:ffff,UG
+2001:43f8:140::,2001:43f8:140:ffff:ffff:ffff:ffff:ffff,ZM
+2001:43f8:150::,2001:43f8:150:ffff:ffff:ffff:ffff:ffff,RW
+2001:43f8:160::,2001:43f8:160:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:170::,2001:43f8:170:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:180::,2001:43f8:180:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:1a0::,2001:43f8:1a0:ffff:ffff:ffff:ffff:ffff,GH
+2001:43f8:1c0::,2001:43f8:1c0:ffff:ffff:ffff:ffff:ffff,DZ
+2001:43f8:1d0::,2001:43f8:1d0:ffff:ffff:ffff:ffff:ffff,GH
+2001:43f8:1e0::,2001:43f8:1e0:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:1f0::,2001:43f8:1f2:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:200::,2001:43f8:200:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:210::,2001:43f8:210:ffff:ffff:ffff:ffff:ffff,LS
+2001:43f8:220::,2001:43f8:220:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:230::,2001:43f8:230:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:240::,2001:43f8:241:ffff:ffff:ffff:ffff:ffff,GH
+2001:43f8:250::,2001:43f8:250:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:260::,2001:43f8:260:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:270::,2001:43f8:270:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:290::,2001:43f8:290:ffff:ffff:ffff:ffff:ffff,MG
+2001:43f8:2a0::,2001:43f8:2a0:ffff:ffff:ffff:ffff:ffff,BW
+2001:43f8:2b0::,2001:43f8:2b0:ffff:ffff:ffff:ffff:ffff,BW
+2001:43f8:2c0::,2001:43f8:2c0:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:2e0::,2001:43f8:2e0:ffff:ffff:ffff:ffff:ffff,EG
+2001:43f8:2f0::,2001:43f8:2f0:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:300::,2001:43f8:300:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:310::,2001:43f8:310:ffff:ffff:ffff:ffff:ffff,ZW
+2001:43f8:320::,2001:43f8:320:ffff:ffff:ffff:ffff:ffff,TN
+2001:43f8:330::,2001:43f8:330:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:340::,2001:43f8:340:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:360::,2001:43f8:360:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:370::,2001:43f8:370:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:380::,2001:43f8:380:ffff:ffff:ffff:ffff:ffff,MW
+2001:43f8:390::,2001:43f8:390:ffff:ffff:ffff:ffff:ffff,AO
+2001:43f8:3a0::,2001:43f8:3a0:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:3b0::,2001:43f8:3b0:ffff:ffff:ffff:ffff:ffff,NA
+2001:43f8:3c0::,2001:43f8:3c0:ffff:ffff:ffff:ffff:ffff,CD
+2001:43f8:400::,2001:43f8:4ff:ffff:ffff:ffff:ffff:ffff,AO
+2001:43f8:600::,2001:43f8:60f:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:610::,2001:43f8:610:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:620::,2001:43f8:620:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:630::,2001:43f8:630:ffff:ffff:ffff:ffff:ffff,MW
+2001:43f8:640::,2001:43f8:640:ffff:ffff:ffff:ffff:ffff,MZ
+2001:43f8:650::,2001:43f8:650:ffff:ffff:ffff:ffff:ffff,MA
+2001:43f8:660::,2001:43f8:660:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:670::,2001:43f8:670:ffff:ffff:ffff:ffff:ffff,AO
+2001:43f8:680::,2001:43f8:680:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:690::,2001:43f8:690:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:6a0::,2001:43f8:6a0:ffff:ffff:ffff:ffff:ffff,CG
+2001:43f8:6b0::,2001:43f8:6b3:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:6c0::,2001:43f8:6c0:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:6d0::,2001:43f8:6d3:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:6e0::,2001:43f8:6e0:ffff:ffff:ffff:ffff:ffff,KE
+2001:4400::,2001:4403:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:4408::,2001:4408:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:4410::,2001:4410:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:4418::,2001:4418:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:4420::,2001:4420:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4428::,2001:4428:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:4430::,2001:4430:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:4438::,2001:4438:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:4450::,2001:4450:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:4458::,2001:4458:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:4460::,2001:4460:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:4470::,2001:4470:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:4478::,2001:447b:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:4480::,2001:4480:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:4488::,2001:448b:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:4490::,2001:4493:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:4498::,2001:4498:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:44a0::,2001:44a0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:44a8::,2001:44a8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:44b0::,2001:44b0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:44b8::,2001:44b8:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:44c0::,2001:44c0:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:44c8::,2001:44c8:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:44d0::,2001:44df:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:44f0::,2001:44f0:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4500::,2001:4500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4508::,2001:4508:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4510::,2001:4517:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:4520::,2001:4520:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:4528::,2001:452b:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:4530::,2001:4530:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:4538::,2001:4538:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2001:4540::,2001:455f:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4580::,2001:45bf:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4600::,2001:46ff:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4800::,2001:4808:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4810::,2001:4810:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4818::,2001:4818:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4828::,2001:4828:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4830::,2001:4830:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4838::,2001:4838:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4840::,2001:4840:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4848::,2001:4848:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4850::,2001:4850:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4858::,2001:4858:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4860::,2001:4860:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4868::,2001:4868:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4870::,2001:4871:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4878::,2001:4878:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4880::,2001:4880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4888::,2001:4888:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4890::,2001:4890:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4898::,2001:489a:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48a0::,2001:48a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48a8::,2001:48a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48b0::,2001:48b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48b8::,2001:48b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48c0::,2001:48c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48c8::,2001:48c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48d0::,2001:48d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48d8::,2001:48d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48e0::,2001:48e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48e8::,2001:48e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48f0::,2001:48f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48f8::,2001:48f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4900::,2001:4900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4908::,2001:4908:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4910::,2001:4910:ffff:ffff:ffff:ffff:ffff:ffff,BM
+2001:4918::,2001:4918:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4920::,2001:4920:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4928::,2001:4928:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4930::,2001:4930:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4938::,2001:4938:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4940::,2001:4940:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4948::,2001:4948:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4950::,2001:4950:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4958::,2001:4958:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4960::,2001:4960:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4968::,2001:4968:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4970::,2001:4970:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4978::,2001:4978:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4980::,2001:4980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4988::,2001:4988:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4990::,2001:4990:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4998::,2001:4998:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49a0::,2001:49a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49a8::,2001:49a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49b0::,2001:49b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49b8::,2001:49b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49c0::,2001:49c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49c8::,2001:49c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49d0::,2001:49d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49d8::,2001:49d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49e0::,2001:49e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49e8::,2001:49e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49f0::,2001:49f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49f8::,2001:49f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4a00::,2001:4a1f:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4b00::,2001:4b00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4b08::,2001:4b08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4b10::,2001:4b10:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4b18::,2001:4b18:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4b20::,2001:4b20:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4b28::,2001:4b28:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4b30::,2001:4b30:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4b38::,2001:4b38:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4b40::,2001:4b40:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4b48::,2001:4b48:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4b50::,2001:4b50:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:4b58::,2001:4b58:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2001:4b60::,2001:4b60:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4b68::,2001:4b68:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4b70::,2001:4b70:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4b78::,2001:4b78:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4b80::,2001:4b80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4b88::,2001:4b88:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4b90::,2001:4b90:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4b98::,2001:4b98:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4ba0::,2001:4ba0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ba8::,2001:4ba8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:4bb0::,2001:4bb0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4bb8::,2001:4bb8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4bc0::,2001:4bc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4bc8::,2001:4bc8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4bd0::,2001:4bd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4bd8::,2001:4bd8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4be0::,2001:4be0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:4be8::,2001:4be8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4bf0::,2001:4bf0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4bf8::,2001:4bf8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4c00::,2001:4c00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4c08::,2001:4c08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4c10::,2001:4c10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4c20::,2001:4c20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4c28::,2001:4c28:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4c30::,2001:4c30:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4c38::,2001:4c38:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4c40::,2001:4c40:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:4c48::,2001:4c4f:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2001:4c50::,2001:4c57:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4c58::,2001:4c58:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4c60::,2001:4c60:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4c68::,2001:4c68:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4c70::,2001:4c70:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4c78::,2001:4c78:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4c80::,2001:4c80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4c88::,2001:4c88:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:4c90::,2001:4c90:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4c98::,2001:4c98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ca0::,2001:4ca0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ca8::,2001:4ca8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4cb0::,2001:4cb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4cb8::,2001:4cb8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4cc0::,2001:4cc0:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:4cc8::,2001:4cc8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:4cd0::,2001:4cd0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2001:4cd8::,2001:4cd8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ce0::,2001:4ce0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ce8::,2001:4cf0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4cf8::,2001:4cf8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d00::,2001:4d00:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2001:4d08::,2001:4d08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d10::,2001:4d10:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4d18::,2001:4d18:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2001:4d20::,2001:4d20:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d28::,2001:4d28:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4d30::,2001:4d30:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4d38::,2001:4d38:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4d40::,2001:4d40:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:4d48::,2001:4d48:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4d50::,2001:4d50:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d58::,2001:4d58:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4d60::,2001:4d60:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4d68::,2001:4d68:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:4d70::,2001:4d70:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2001:4d78::,2001:4d78:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4d80::,2001:4d80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2001:4d88::,2001:4d88:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d90::,2001:4d90:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4d98::,2001:4d98:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4da0::,2001:4da7:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4da8::,2001:4da8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4db0::,2001:4db0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4db8::,2001:4db8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:4dc0::,2001:4dc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4dc8::,2001:4dc8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4dd0::,2001:4dd7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4dd8::,2001:4dd8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4de0::,2001:4de0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4de8::,2001:4de8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:4df0::,2001:4df0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2001:5000::,2001:57ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:8000::,2001:8fff:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:a000::,2001:a7ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:b000::,2001:b7ff:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2003::,2003:1fff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2400::,2400:fff:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:1000::,2400:1000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:1100::,2400:1100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:1200::,2400:1200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:1300::,2400:1300:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2400:1400::,2400:1400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:1500::,2400:1500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2400:1600::,2400:1600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:1700::,2400:1700:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:1800::,2400:1800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:1900::,2400:1900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:1a00::,2400:1a00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:1b00::,2400:1b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:1c00::,2400:1c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:1d00::,2400:1d00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:1e00::,2400:1e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:1f00::,2400:1f00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:2000::,2400:3000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:3100::,2400:3100:ffff:ffff:ffff:ffff:ffff:ffff,VU
+2400:3200::,2400:3200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:3300::,2400:3300:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:3400::,2400:3400:ffff:ffff:ffff:ffff:ffff:ffff,VU
+2400:3500::,2400:3500:ffff:ffff:ffff:ffff:ffff:ffff,TV
+2400:3600::,2400:3600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:3700::,2400:3700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:3800::,2400:3800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:3900::,2400:3900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:3a00::,2400:3a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:3b00::,2400:3b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:3c00::,2400:3c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:3d00::,2400:3d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:3e00::,2400:3e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:3f00::,2400:3f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:4000::,2400:43ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:4400::,2400:4400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:4500::,2400:4500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2400:4600::,2400:4600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:4700::,2400:4700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:4800::,2400:4800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:4900::,2400:4900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:4a00::,2400:4a00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:4b00::,2400:4b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:4c00::,2400:4c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:4d00::,2400:4d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:4e00::,2400:4e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:4f00::,2400:4f00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2400:5000::,2400:5000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:5100::,2400:5100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:5200::,2400:5200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:5300::,2400:5300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:5400::,2400:5400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:5500::,2400:5500:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:5600::,2400:5600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:5700::,2400:5700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:5800::,2400:5800:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2400:5900::,2400:5900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:5a00::,2400:5a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:5b00::,2400:5b00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:5c00::,2400:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:5d00::,2400:5d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:5e00::,2400:5e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:5f00::,2400:5f00:ffff:ffff:ffff:ffff:ffff:ffff,PF
+2400:6000::,2400:6000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6100::,2400:6100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:6200::,2400:6200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6300::,2400:6300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:6400::,2400:6400:ffff:ffff:ffff:ffff:ffff:ffff,TO
+2400:6500::,2400:6500:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:6600::,2400:6600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6700::,2400:6700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:6800::,2400:6800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:6900::,2400:6900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:6a00::,2400:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6b00::,2400:6b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:6c00::,2400:6c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:6d00::,2400:6d00:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2400:6e00::,2400:6e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6f00::,2400:6f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:7000::,2400:7000:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2400:7100::,2400:7100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:7200::,2400:7200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:7300::,2400:7300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:7400::,2400:7400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:7500::,2400:7500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:7600::,2400:7600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:7700::,2400:7700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:7800::,2400:7800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:7900::,2400:7900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:7a00::,2400:7a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:7b00::,2400:7b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:7c00::,2400:7c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:7d00::,2400:7d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:7e00::,2400:7e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:7f00::,2400:7f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:8000::,2400:8000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:8100::,2400:8100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:8200::,2400:8200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:8300::,2400:8300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:8400::,2400:8400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:8500::,2400:8500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:8600::,2400:8600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:8700::,2400:8700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:8800::,2400:8800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:8900::,2400:8900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:8a00::,2400:8a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:8b00::,2400:8b00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:8c00::,2400:8c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:8d00::,2400:8d00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:8e00::,2400:8e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:8f00::,2400:8f00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:9000::,2400:9000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:9100::,2400:9100:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2400:9200::,2400:9200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:9300::,2400:9300:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2400:9400::,2400:9400:ffff:ffff:ffff:ffff:ffff:ffff,BN
+2400:9500::,2400:9500:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:9600::,2400:9600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:9700::,2400:9700:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:9800::,2400:9800:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:9900::,2400:9900:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:9a00::,2400:9a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:9b00::,2400:9b00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:9c00::,2400:9c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:9d00::,2400:9d00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:9e00::,2400:9e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:a000::,2400:a000:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:a100::,2400:a100:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:a300::,2400:a300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:a400::,2400:a400:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:a500::,2400:a500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:a600::,2400:a600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:a700::,2400:a700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:a800::,2400:a800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:a900::,2400:a900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:aa00::,2400:aa00:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2400:ab00::,2400:ab00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:ac00::,2400:ac00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:ad00::,2400:ad00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:ae00::,2400:ae00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:af00::,2400:af00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:b000::,2400:b000:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:b100::,2400:b100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:b200::,2400:b200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:b300::,2400:b300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:b400::,2400:b400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:b500::,2400:b500:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:b600::,2400:b600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:b700::,2400:b700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:b800::,2400:b800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:b900::,2400:b900:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:ba00::,2400:ba00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:bb00::,2400:bb00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:bc00::,2400:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:bd00::,2400:bd00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:be00::,2400:be00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:bf00::,2400:bf00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:c000::,2400:c000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:c100::,2400:c100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:c200::,2400:c200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:c300::,2400:c300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:c400::,2400:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:c500::,2400:c500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:c600::,2400:c600:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2400:c700::,2400:c700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:c800::,2400:c800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:c900::,2400:c900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:ca00::,2400:ca00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2400:cb00::,2400:cb00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:cc00::,2400:cc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:cd00::,2400:cd00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2400:ce00::,2400:ce00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:cf00::,2400:cf00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:d000::,2400:d000:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:d100::,2400:d100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:d200::,2400:d200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:d300::,2400:d300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:d400::,2400:d400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:d500::,2400:d500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:d600::,2400:d600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:d700::,2400:d700:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:d800::,2400:d803:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:d900::,2400:d900:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2400:da00::,2400:da00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:db00::,2400:db00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:dc00::,2400:dc00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:dd00::,2400:dd0f:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:de00::,2400:de00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:df00::,2400:df00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:e000::,2400:e000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:e100::,2400:e100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:e200::,2400:e200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:e300::,2400:e300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:e400::,2400:e400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:e500::,2400:e500:ffff:ffff:ffff:ffff:ffff:ffff,AF
+2400:e700::,2400:e700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:e800::,2400:e800:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:e900::,2400:e900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:ea00::,2400:ea00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2400:eb00::,2400:eb00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:ec00::,2400:ec00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:ed00::,2400:ed00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:ee00::,2400:ee00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:ef00::,2400:ef00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f000::,2400:f000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f100::,2400:f100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f200::,2400:f200:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:f300::,2400:f300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:f400::,2400:f400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:f600::,2400:f600:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:f700::,2400:f700:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f800::,2400:f800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f900::,2400:f900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:fa00::,2400:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:fb00::,2400:fb00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:fc00::,2400:fc00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2400:fd00::,2400:fd00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2400:fe00::,2400:fe00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:ff00::,2400:ff00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2401::,2401:0:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:100::,2401:100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:200::,2401:200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:300::,2401:300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:400::,2401:400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:500::,2401:500:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:600::,2401:600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:700::,2401:700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:800::,2401:800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:900::,2401:900:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:a00::,2401:a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:b00::,2401:b00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:c00::,2401:c00:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2401:d00::,2401:d00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:e00::,2401:e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:f00::,2401:f00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:1000::,2401:1000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:1100::,2401:1100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:1200::,2401:1200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:1300::,2401:1300:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:1400::,2401:1400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:1500::,2401:1500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:1600::,2401:1600:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:1700::,2401:1700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:1800::,2401:1800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:1900::,2401:1900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:1a00::,2401:1a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:1b00::,2401:1b00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:1c00::,2401:1c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:1d00::,2401:1d00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:1e00::,2401:1e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:1f00::,2401:1f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:2000::,2401:2000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:2001::,2401:2001:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:2100::,2401:2100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:2200::,2401:2200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:2300::,2401:2300:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:2400::,2401:2400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:2500::,2401:2500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:2600::,2401:2600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:2700::,2401:2700:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:2800::,2401:2800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:2900::,2401:2900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:2a00::,2401:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:2b00::,2401:2b00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:2c00::,2401:2c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:2d00::,2401:2d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:2e00::,2401:2e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:2f00::,2401:2f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:3000::,2401:3000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:3100::,2401:3100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:3200::,2401:3200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:3300::,2401:3300:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:3400::,2401:3400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:3500::,2401:3500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:3600::,2401:3600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:3700::,2401:3700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:3800::,2401:3800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:3900::,2401:3900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3a00::,2401:3a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:3b00::,2401:3b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:3c00::,2401:3c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:3d00::,2401:3d0f:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:3e00::,2401:3e00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2401:3f00::,2401:3f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:4000::,2401:4000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:4100::,2401:4100:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:4200::,2401:4200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:4300::,2401:4300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:4400::,2401:4400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:4500::,2401:4500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:4600::,2401:4600:ffff:ffff:ffff:ffff:ffff:ffff,AP
+2401:4700::,2401:4700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:4800::,2401:4800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:4900::,2401:4900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:4a00::,2401:4a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:4b00::,2401:4b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:4c00::,2401:4c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:4d00::,2401:4d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:4e00::,2401:4e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:4f00::,2401:4f00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:5000::,2401:5000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:5100::,2401:5100:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2401:5200::,2401:5200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:5300::,2401:5300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:5400::,2401:5400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:5500::,2401:5500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:5700::,2401:5700:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:5800::,2401:5800:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:5900::,2401:5900:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:5a00::,2401:5a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:5b00::,2401:5b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:5c00::,2401:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:5d00::,2401:5d00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:5e00::,2401:5e00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:5f00::,2401:5f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:6000::,2401:6fff:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7000::,2401:7000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:7100::,2401:7100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7200::,2401:7200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7300::,2401:7300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7400::,2401:7401:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:7500::,2401:7500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:7600::,2401:7600:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:7700::,2401:7700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:7800::,2401:7800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:7900::,2401:7900:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2401:7a00::,2401:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:7b00::,2401:7b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7c00::,2401:7c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:7d00::,2401:7d00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:7e00::,2401:7e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:7f00::,2401:7f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:8000::,2401:803f:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:8100::,2401:8100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:8200::,2401:8200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:8300::,2401:8300:ffff:ffff:ffff:ffff:ffff:ffff,MV
+2401:8400::,2401:8400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:8500::,2401:8500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:8600::,2401:8600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:8700::,2401:8700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:8800::,2401:8800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:8900::,2401:8900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:8a00::,2401:8a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:8b00::,2401:8b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:8c00::,2401:8c01:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:8d00::,2401:8d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:8e00::,2401:8e00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:8f00::,2401:8f00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:9000::,2401:9000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:9100::,2401:9100:ffff:ffff:ffff:ffff:ffff:ffff,MO
+2401:9200::,2401:9200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:9300::,2401:9300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:9400::,2401:9400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:9500::,2401:9500:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:9600::,2401:9600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:9700::,2401:9700:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2401:9800::,2401:9800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:9900::,2401:9900:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2401:9a00::,2401:9a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:9b00::,2401:9b00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:9c00::,2401:9c00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:9d00::,2401:9d00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:9e00::,2401:9e00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:9f00::,2401:9f00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:a000::,2401:a000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:a100::,2401:a100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:a200::,2401:a200:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:a300::,2401:a300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:a400::,2401:a400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:a500::,2401:a500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:a600::,2401:a600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:a700::,2401:a700:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2401:a800::,2401:a800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:a900::,2401:a900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:aa00::,2401:aa00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:ab00::,2401:ab00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:ac00::,2401:ac00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:ad00::,2401:ad00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:ae00::,2401:ae00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:af00::,2401:af00:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2401:b000::,2401:b000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:b100::,2401:b100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:b200::,2401:b200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:b300::,2401:b300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:b400::,2401:b400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:b500::,2401:b500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:b600::,2401:b600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:b700::,2401:b700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:b800::,2401:b800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2401:b900::,2401:b900:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:ba00::,2401:ba00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:bb00::,2401:bb00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:bc00::,2401:bc00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:bd00::,2401:bd00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:be00::,2401:be00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:bf00::,2401:bf00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:c000::,2401:c000:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:c100::,2401:c100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:c200::,2401:c200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:c300::,2401:c300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:c400::,2401:c400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:c500::,2401:c500:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:c600::,2401:c600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:c700::,2401:c700:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:c800::,2401:c800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:c900::,2401:c900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:ca00::,2401:ca00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:cb00::,2401:cb00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2401:cc00::,2401:cc00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:cd00::,2401:cd00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:ce00::,2401:ce00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:cf00::,2401:cf00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:d000::,2401:d000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:d100::,2401:d100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:d200::,2401:d200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:d300::,2401:d300:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:d400::,2401:d400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:d500::,2401:d500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:d600::,2401:d600:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2401:d700::,2401:d700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:d800::,2401:d800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2401:d900::,2401:d900:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:da00::,2401:da00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:db00::,2401:db00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:dc00::,2401:dc00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:dd00::,2401:dd00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2401:de00::,2401:de00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:df00::,2401:df01:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:e000::,2401:e000:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:e100::,2401:e100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:e200::,2401:e200:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:e300::,2401:e300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:e400::,2401:e400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:e500::,2401:e500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:e600::,2401:e600:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2401:e700::,2401:e700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:e800::,2401:e800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2401:e900::,2401:e900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:ea00::,2401:ea00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:eb00::,2401:eb00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:ec00::,2401:ec00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:ed00::,2401:ed00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:ee00::,2401:ee00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:ef00::,2401:ef00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:f000::,2401:f000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:f100::,2401:f100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:f200::,2401:f200:ffff:ffff:ffff:ffff:ffff:ffff,MM
+2401:f300::,2401:f300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:f400::,2401:f400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:f500::,2401:f500:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:f600::,2401:f600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:f700::,2401:f700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:f800::,2401:f800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:f900::,2401:f900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:fa00::,2401:fa00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:fb00::,2401:fb00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:fc00::,2401:fc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:fd00::,2401:fd00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:fe00::,2401:fe00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:ff00::,2401:ff00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402::,2402:3ff:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:400::,2402:400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:500::,2402:500:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:600::,2402:600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:700::,2402:700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:800::,2402:800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2402:900::,2402:900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:a00::,2402:a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:b00::,2402:b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:c00::,2402:c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:d00::,2402:d00:ffff:ffff:ffff:ffff:ffff:ffff,AF
+2402:e00::,2402:e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:f00::,2402:f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1000::,2402:1000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:1100::,2402:1100:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:1200::,2402:1200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:1300::,2402:1300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1400::,2402:1400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:1500::,2402:1500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:1600::,2402:1600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:1700::,2402:1700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1800::,2402:1800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1900::,2402:1900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1a00::,2402:1a00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:1b00::,2402:1b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:1c00::,2402:1c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:1d00::,2402:1d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:1e00::,2402:1e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1f00::,2402:1f00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:2000::,2402:2000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:2100::,2402:2100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:2200::,2402:2200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:2300::,2402:2300:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2402:2400::,2402:2400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:2500::,2402:2500:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:2600::,2402:2600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:2700::,2402:2700:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2402:2800::,2402:2800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:2900::,2402:2900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:2a00::,2402:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:2b00::,2402:2b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:2c00::,2402:2c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:2d00::,2402:2d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:2e00::,2402:2e00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2402:2f00::,2402:2f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3000::,2402:3000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:3100::,2402:3100:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:3200::,2402:3200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3300::,2402:3300:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:3400::,2402:3400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3500::,2402:3500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3600::,2402:3600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3700::,2402:3700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:3800::,2402:3800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:3900::,2402:3900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3a00::,2402:3a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3b00::,2402:3b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:3c00::,2402:3c00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:3d00::,2402:3d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:3e00::,2402:3e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:3f00::,2402:3f00:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2402:4000::,2402:4000:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2402:4100::,2402:4100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:4200::,2402:4200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:4300::,2402:4300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:4400::,2402:4400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:4500::,2402:4500:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:4600::,2402:4600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:4700::,2402:4700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:4800::,2402:4800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:4900::,2402:4900:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2402:4a00::,2402:4a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:4b00::,2402:4b00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:4c00::,2402:4c01:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:4d00::,2402:4d00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:4e00::,2402:4e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:4f00::,2402:4f00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:5100::,2402:5100:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2402:5200::,2402:5200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:5300::,2402:5300:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2402:5400::,2402:5400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:5500::,2402:5500:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2402:5600::,2402:5600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:5700::,2402:5700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:5800::,2402:5800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:5900::,2402:5900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:5a00::,2402:5a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:5b00::,2402:5b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:5c00::,2402:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:5d00::,2402:5d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:5e00::,2402:5e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:5f00::,2402:5f00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:6000::,2402:6000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:6100::,2402:6100:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:6200::,2402:6200:ffff:ffff:ffff:ffff:ffff:ffff,GU
+2402:6300::,2402:6300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6400::,2402:6400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6500::,2402:6500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6600::,2402:6600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6700::,2402:6700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:6800::,2402:6800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:6900::,2402:6900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6a00::,2402:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:6b00::,2402:6b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:6c00::,2402:6c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:6d00::,2402:6d00:ffff:ffff:ffff:ffff:ffff:ffff,PF
+2402:6e00::,2402:6e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:6f00::,2402:6f00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:7000::,2402:7000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:7100::,2402:7100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:7200::,2402:7200:ffff:ffff:ffff:ffff:ffff:ffff,TK
+2402:7300::,2402:7300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:7400::,2402:7400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:7500::,2402:7500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2402:7600::,2402:7600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:7700::,2402:7700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:7800::,2402:7800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:7900::,2402:7900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:7a00::,2402:7a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:7b00::,2402:7b00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:7c00::,2402:7c00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2402:7d00::,2402:7d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:7e00::,2402:7e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:7f00::,2402:7f00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8000::,2402:8000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:8100::,2402:8100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8200::,2402:8200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:8300::,2402:8300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:8400::,2402:8400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8500::,2402:8500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:8600::,2402:8600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:8700::,2402:8700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:8800::,2402:8800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:8900::,2402:8900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:8a00::,2402:8a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8b00::,2402:8b00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:8c00::,2402:8c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8d00::,2402:8d03:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:8e00::,2402:8e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8f00::,2402:8f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:9100::,2402:9100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9200::,2402:9200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9300::,2402:9300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:9400::,2402:9400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9500::,2402:9500:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:9700::,2402:9700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9800::,2402:9800:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:9900::,2402:9900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9a00::,2402:9a00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:9b00::,2402:9b00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2402:9c00::,2402:9c00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2402:9d00::,2402:9d00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2402:9e00::,2402:9e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:9f00::,2402:9f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:a000::,2402:a000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:a100::,2402:a100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:a200::,2402:a200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:a300::,2402:a300:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2402:a400::,2402:a400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:a500::,2402:a500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:a600::,2402:a600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:a700::,2402:a700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:a800::,2402:a800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:a900::,2402:a900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:aa00::,2402:aa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ab00::,2402:ab00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:ac00::,2402:ac00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:ad00::,2402:ad00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ae00::,2402:ae00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:af00::,2402:af00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:b000::,2402:b000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:b100::,2402:b100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:b200::,2402:b200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:b300::,2402:b300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:b400::,2402:b400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:b500::,2402:b500:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2402:b600::,2402:b600:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2402:b700::,2402:b700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:b800::,2402:b801:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:b900::,2402:b900:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2402:ba00::,2402:ba00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2402:bb00::,2402:bb00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:bc00::,2402:bc07:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:bd00::,2402:bd00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:be00::,2402:be00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:bf00::,2402:bf00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:c000::,2402:c000:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2402:c100::,2402:c100:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2402:c200::,2402:c200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:c300::,2402:c300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:c400::,2402:c400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:c500::,2402:c500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:c600::,2402:c600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:c700::,2402:c700:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2402:c800::,2402:c800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:c900::,2402:c900:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2402:ca00::,2402:ca00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:cb00::,2402:cb00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2402:cc00::,2402:cc00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:cd00::,2402:cd00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:ce00::,2402:ce00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:cf00::,2402:cf00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:d000::,2402:d000:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2402:d100::,2402:d100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:d200::,2402:d200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:d300::,2402:d300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:d400::,2402:d400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:d500::,2402:d500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:d600::,2402:d600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:d700::,2402:d700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:d800::,2402:d800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:d900::,2402:d900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:da00::,2402:da00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:db00::,2402:db00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:dc00::,2402:dc00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:dd00::,2402:dd00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:de00::,2402:de00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:df00::,2402:df00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:e000::,2402:e000:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2402:e100::,2402:e100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:e200::,2402:e200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:e300::,2402:e300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:e400::,2402:e400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:e500::,2402:e500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:e600::,2402:e600:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:e800::,2402:e800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:e900::,2402:e900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ea00::,2402:ea00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:eb00::,2402:eb00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ec00::,2402:ec00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ed00::,2402:ed00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:ee00::,2402:ee00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ef00::,2402:ef3f:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:f000::,2402:f000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:f100::,2402:f100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:f200::,2402:f200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:f300::,2402:f300:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:f400::,2402:f400:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:f500::,2402:f500:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2402:f600::,2402:f600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:f700::,2402:f700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:f800::,2402:f800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2402:f900::,2402:f900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:fa00::,2402:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:fb00::,2402:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2402:fc00::,2402:fc00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:fd00::,2402:fd00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2402:fe00::,2402:fe00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2402:ff00::,2402:ff00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403::,2403:1:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:100::,2403:100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:200::,2403:200:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2403:300::,2403:300:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:400::,2403:400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:500::,2403:500:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2403:600::,2403:600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:700::,2403:700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:800::,2403:801:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:900::,2403:900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:a00::,2403:a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:b00::,2403:b00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:c00::,2403:c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:d00::,2403:d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:e00::,2403:e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:f00::,2403:f00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:1000::,2403:1000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:1100::,2403:1100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:1300::,2403:1300:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:1400::,2403:1400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:1500::,2403:1500:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:1600::,2403:1600:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2403:1700::,2403:1700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:1800::,2403:1800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:1900::,2403:1900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:1a00::,2403:1a00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:1b00::,2403:1b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:1c00::,2403:1c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:1d00::,2403:1d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:1e00::,2403:1e00:ffff:ffff:ffff:ffff:ffff:ffff,AS
+2403:1f00::,2403:1f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:2000::,2403:2000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:2100::,2403:2100:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:2200::,2403:2200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:2300::,2403:2300:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:2400::,2403:2400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:2500::,2403:2500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:2600::,2403:2600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:2700::,2403:2700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:2800::,2403:2801:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:2900::,2403:2900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:2a00::,2403:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:2b00::,2403:2b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:2c00::,2403:2c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:2d00::,2403:2d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:2e00::,2403:2e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:2f00::,2403:2f00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:3100::,2403:3100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:3200::,2403:3200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:3300::,2403:3300:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2403:3400::,2403:3400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3500::,2403:3500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3600::,2403:3600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3700::,2403:3700:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2403:3800::,2403:3800:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2403:3900::,2403:3900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:3a00::,2403:3a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:3b00::,2403:3b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3c00::,2403:3c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3d00::,2403:3d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:3e00::,2403:3e00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2403:3f00::,2403:3f00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:4000::,2403:4000:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:4100::,2403:4100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:4200::,2403:4200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:4300::,2403:4300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:4400::,2403:4400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:4500::,2403:4500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:4600::,2403:4600:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2403:4700::,2403:4700:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:4800::,2403:4800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:4900::,2403:4900:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:4a00::,2403:4a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:4b00::,2403:4b00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:4c00::,2403:4c00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:4d00::,2403:4d00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:4e00::,2403:4e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:4f00::,2403:4f00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:5000::,2403:5000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:5100::,2403:5100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:5200::,2403:5200:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2403:5300::,2403:5300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:5400::,2403:5400:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:5500::,2403:5500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:5600::,2403:5600:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:5700::,2403:5700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:5800::,2403:5800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:5900::,2403:5900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:5a00::,2403:5a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:5b00::,2403:5b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:5c00::,2403:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:5d00::,2403:5d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:5e00::,2403:5e00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2403:5f00::,2403:5f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:6000::,2403:6000:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2403:6100::,2403:6100:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:6200::,2403:6200:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:6300::,2403:6300:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2403:6400::,2403:6400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:6500::,2403:6500:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2403:6600::,2403:6600:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2403:6700::,2403:6700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:6800::,2403:6800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:6900::,2403:6900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:6a00::,2403:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:6b00::,2403:6b00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:6c00::,2403:6c00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:6d00::,2403:6d00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:6e00::,2403:6e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:6f00::,2403:6f00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:7000::,2403:7000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:7100::,2403:7100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:7200::,2403:7200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:7300::,2403:7300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7400::,2403:7400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7500::,2403:7500:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2403:7600::,2403:7600:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:7700::,2403:7700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:7800::,2403:7800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7900::,2403:7900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:7a00::,2403:7a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7b00::,2403:7b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:7c00::,2403:7c00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7d00::,2403:7d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:7e00::,2403:7e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:7f00::,2403:7f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:8000::,2403:8000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:8100::,2403:8100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:8200::,2403:8200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:8300::,2403:8300:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2403:8400::,2403:8400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:8500::,2403:8500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:8600::,2403:8600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:8700::,2403:8700:ffff:ffff:ffff:ffff:ffff:ffff,BT
+2403:8800::,2403:8800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:8900::,2403:8900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:8a00::,2403:8a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:8b00::,2403:8b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:8c00::,2403:8c00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:8d00::,2403:8d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:8e00::,2403:8e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:8f00::,2403:8f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9000::,2403:9000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:9100::,2403:9100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:9200::,2403:9200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9300::,2403:9300:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:9400::,2403:9400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9500::,2403:9500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:9600::,2403:9600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9700::,2403:9700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:9800::,2403:9800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:9900::,2403:9a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9b00::,2403:9b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:9c00::,2403:9c00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9d00::,2403:9d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:9e00::,2403:9e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:9f00::,2403:9f00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2403:a000::,2403:a000:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2403:a100::,2403:a100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:a200::,2403:a200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:a300::,2403:a300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:a400::,2403:a400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:a500::,2403:a500:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2403:a600::,2403:a600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:a700::,2403:a700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:a800::,2403:a800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:a900::,2403:a900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:aa00::,2403:aa00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:ab00::,2403:ab00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:ac00::,2403:ac00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:ad00::,2403:ad00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:ae00::,2403:ae00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:af00::,2403:af00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:b000::,2403:b000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:b100::,2403:b100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:b200::,2403:b200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:b300::,2403:b300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:b400::,2403:b400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:b500::,2403:b500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:b600::,2403:b600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:b700::,2403:b700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:b800::,2403:b800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:b900::,2403:b900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:ba00::,2403:ba00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:bb00::,2403:bb00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:bc00::,2403:bc00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:bd00::,2403:bd00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:be00::,2403:be00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:bf00::,2403:bf00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:c000::,2403:c000:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:c100::,2403:c100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:c200::,2403:c200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:c300::,2403:c300:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2403:c400::,2403:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:c500::,2403:c500:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:c600::,2403:c600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:c700::,2403:c700:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2403:c800::,2403:c800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:c900::,2403:c900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:ca00::,2403:ca00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:cb00::,2403:cb00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:cc00::,2403:cc00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:cd00::,2403:cd00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2403:ce00::,2403:ce00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:cf00::,2403:cf00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:d000::,2403:d000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:d100::,2403:d100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:d200::,2403:d200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:d300::,2403:d300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:d400::,2403:d400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:d500::,2403:d500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:d600::,2403:d600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:d700::,2403:d700:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2403:d800::,2403:d800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:d900::,2403:d900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:da00::,2403:da00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:db00::,2403:db00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:dc00::,2403:dc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:dd00::,2403:dd00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:de00::,2403:de00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:df00::,2403:df00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:e000::,2403:e000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:e100::,2403:e100:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:e200::,2403:e200:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2403:e300::,2403:e300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:e400::,2403:e400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:e500::,2403:e500:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:e600::,2403:e600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:e700::,2403:e700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:e800::,2403:e800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:e900::,2403:e900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:ea00::,2403:ea00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:eb00::,2403:eb00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:ec00::,2403:ec00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:ed00::,2403:ed00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:ee00::,2403:ee00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2403:f000::,2403:f000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:f100::,2403:f100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:f200::,2403:f200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:f300::,2403:f300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:f400::,2403:f400:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:f500::,2403:f500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:f600::,2403:f600:ffff:ffff:ffff:ffff:ffff:ffff,NR
+2403:f700::,2403:f700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:f800::,2403:f800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:f900::,2403:f900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:fa00::,2403:fa00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:fb00::,2403:fb00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:fc00::,2403:fc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:fd00::,2403:fd00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:fe00::,2403:fe00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:ff00::,2403:ff00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404::,2404:3f:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:80::,2404:8f:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:a0::,2404:a0:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:a8::,2404:a8:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:b0::,2404:b0:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:b8::,2404:b8:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:c0::,2404:c0:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:c8::,2404:c8:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:d0::,2404:d0:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:d8::,2404:d8:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:e0::,2404:ef:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:100::,2404:100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:130::,2404:130:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:138::,2404:139:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:140::,2404:140:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:148::,2404:148:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:150::,2404:150:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:158::,2404:158:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:160::,2404:160:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:168::,2404:168:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:170::,2404:170:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:178::,2404:178:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:180::,2404:18f:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2404:1a0::,2404:1a3:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:1a8::,2404:1a8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1b0::,2404:1b0:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:1b8::,2404:1b8:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:200::,2404:200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:300::,2404:300:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2404:400::,2404:400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:500::,2404:500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:600::,2404:600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:700::,2404:700:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2404:800::,2404:800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2404:900::,2404:900:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:a00::,2404:a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:b00::,2404:b00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:c00::,2404:c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:d00::,2404:d00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:e00::,2404:e00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:f00::,2404:f00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:1000::,2404:1000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1100::,2404:1100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:1200::,2404:1200:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:1300::,2404:1300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1400::,2404:1400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:1500::,2404:1500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:1600::,2404:1600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:1700::,2404:1700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1800::,2404:1800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:1900::,2404:1900:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1a00::,2404:1a00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:1b00::,2404:1b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1c00::,2404:1c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:1d00::,2404:1d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:1e00::,2404:1e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:1f00::,2404:1f00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:2000::,2404:2000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:2100::,2404:2100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:2200::,2404:2200:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2404:2300::,2404:2300:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2404:2400::,2404:2400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:2500::,2404:2500:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:2600::,2404:2600:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:2700::,2404:2700:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2404:2800::,2404:2800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:2900::,2404:2900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:2a00::,2404:2a00:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2404:2b00::,2404:2b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:2c00::,2404:2c00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2404:2d00::,2404:2d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:2e00::,2404:2e00:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2404:2f00::,2404:2f00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:3100::,2404:3100:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:3200::,2404:3200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:3300::,2404:3300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:3400::,2404:3400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:3500::,2404:3500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:3600::,2404:3601:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:3700::,2404:3700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:3800::,2404:3800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:3900::,2404:3900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:3a00::,2404:3a00:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2404:3b00::,2404:3b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:3c00::,2404:3c00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:3d00::,2404:3d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:3e00::,2404:3e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:3f00::,2404:3f00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:4100::,2404:4100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:4200::,2404:4200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:4300::,2404:4300:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:4400::,2404:440f:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:4500::,2404:4500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:4600::,2404:4600:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2404:4700::,2404:4700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:4800::,2404:4800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:4900::,2404:4900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:4a00::,2404:4a00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:4b00::,2404:4b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:4c00::,2404:4c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:4d00::,2404:4d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:4e00::,2404:4e00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:4f00::,2404:4f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5000::,2404:5000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5100::,2404:5100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:5200::,2404:5200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:5300::,2404:5300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5400::,2404:5400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5500::,2404:5500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5600::,2404:5600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:5700::,2404:5700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:5800::,2404:5800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:5900::,2404:5900:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:5a00::,2404:5a00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:5b00::,2404:5b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:5c00::,2404:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5d00::,2404:5d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:5e00::,2404:5e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5f00::,2404:5f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:6000::,2404:6000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:6100::,2404:6100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:6200::,2404:6200:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:6300::,2404:6300:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:6400::,2404:6400:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2404:6500::,2404:6500:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:6600::,2404:6600:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:6700::,2404:6700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:6800::,2404:6800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:6900::,2404:6900:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:6a00::,2404:6a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:6b00::,2404:6b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:6c00::,2404:6c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:6d00::,2404:6d00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:6e00::,2404:6e00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:6f00::,2404:6f00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:7000::,2404:7000:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:7100::,2404:7100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:7200::,2404:7200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:7300::,2404:7300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:7400::,2404:7400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:7500::,2404:7500:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:7600::,2404:7600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:7700::,2404:7700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:7800::,2404:7800:ffff:ffff:ffff:ffff:ffff:ffff,PW
+2404:7900::,2404:7900:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:7a00::,2404:7a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:7b00::,2404:7b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:7c00::,2404:7c00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2404:7d00::,2404:7d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:7e00::,2404:7e00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:7f00::,2404:7f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:8000::,2404:8000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:8100::,2404:8100:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:8200::,2404:8200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:8300::,2404:8300:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:8500::,2404:8500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:8600::,2404:8600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:8700::,2404:8700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:8800::,2404:8800:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:8900::,2404:8900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:8a00::,2404:8a00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2404:8b00::,2404:8b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:8c00::,2404:8c00:ffff:ffff:ffff:ffff:ffff:ffff,GU
+2404:8d00::,2404:8d00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:8e00::,2404:8e01:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:8f00::,2404:8f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9000::,2404:9000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:9100::,2404:9100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:9200::,2404:9200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:9300::,2404:9300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9400::,2404:9400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9500::,2404:9500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:9600::,2404:9600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9700::,2404:9700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9800::,2404:9800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:9900::,2404:9900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:9a00::,2404:9a00:ffff:ffff:ffff:ffff:ffff:ffff,GU
+2404:9b00::,2404:9b00:ffff:ffff:ffff:ffff:ffff:ffff,AF
+2404:9c00::,2404:9c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9d00::,2404:9d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:9e00::,2404:9e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:9f00::,2404:9f00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:a000::,2404:a000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:a100::,2404:a100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:a200::,2404:a200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:a300::,2404:a300:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:a400::,2404:a400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:a500::,2404:a500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:a600::,2404:a600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:a700::,2404:a700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:a800::,2404:a800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:aa00::,2404:aa00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:ab00::,2404:ab00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:ac00::,2404:ac00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:ad00::,2404:ad00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:ae00::,2404:ae00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:af00::,2404:af00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:b000::,2404:b000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:b100::,2404:b100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:b200::,2404:b200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:b300::,2404:b300:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2404:b400::,2404:b400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:b500::,2404:b500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:b600::,2404:b600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:b700::,2404:b700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:b800::,2404:b800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:b900::,2404:b900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:ba00::,2404:ba00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:bb00::,2404:bb00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:bc00::,2404:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:bd00::,2404:bd00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:be00::,2404:be00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:bf00::,2404:bf00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:c000::,2404:c000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:c100::,2404:c100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:c200::,2404:c200:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2404:c300::,2404:c300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:c400::,2404:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:c500::,2404:c500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:c600::,2404:c600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:c700::,2404:c700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:c800::,2404:c800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:c900::,2404:c900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:ca00::,2404:ca00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:cb00::,2404:cb00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:cc00::,2404:cc00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2404:cd00::,2404:cd00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:ce00::,2404:ce00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:cf00::,2404:cf00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:d000::,2404:d000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:d100::,2404:d100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d200::,2404:d200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d300::,2404:d300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d400::,2404:d400:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:d500::,2404:d500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d600::,2404:d600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d700::,2404:d700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d800::,2404:d800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:d900::,2404:d900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:da00::,2404:da00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:db00::,2404:db00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:dc00::,2404:dc00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:dd00::,2404:dd00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:de00::,2404:de00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:df00::,2404:df00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:e000::,2404:e000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:e100::,2404:e100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:e200::,2404:e200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:e300::,2404:e300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:e400::,2404:e400:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2404:e500::,2404:e500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:e600::,2404:e600:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:e700::,2404:e700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:e800::,2404:e801:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:e900::,2404:e900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:ea00::,2404:ea00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:eb00::,2404:eb00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:ec00::,2404:ec00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:ed00::,2404:ed00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:ee00::,2404:ee00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:ef00::,2404:ef00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f000::,2404:f000:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2404:f100::,2404:f100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:f200::,2404:f200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:f300::,2404:f300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f400::,2404:f400:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:f500::,2404:f500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f600::,2404:f600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f700::,2404:f700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f800::,2404:f800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:f900::,2404:f900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:fa00::,2404:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:fb00::,2404:fb00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:fc00::,2404:fc00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:fd00::,2404:fd00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:fe00::,2404:fe00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:ff00::,2404:ff00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405::,2405:0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:100::,2405:100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:200::,2405:207:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:400::,2405:400:ffff:ffff:ffff:ffff:ffff:ffff,MH
+2405:500::,2405:500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:600::,2405:600:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2405:700::,2405:700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:800::,2405:800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:900::,2405:900:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2405:a00::,2405:a00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:b00::,2405:b00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:c00::,2405:c00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2405:d00::,2405:d00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:e00::,2405:e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:f00::,2405:f00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:1000::,2405:1000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:1100::,2405:1100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:1200::,2405:1200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:1300::,2405:1300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:1400::,2405:1400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:1500::,2405:1500:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:1600::,2405:1600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:1700::,2405:1700:ffff:ffff:ffff:ffff:ffff:ffff,BN
+2405:1800::,2405:1800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:1900::,2405:1900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:1a00::,2405:1a00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:1b00::,2405:1b00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2405:1c00::,2405:1c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:1d00::,2405:1d00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:1e00::,2405:1e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:1f00::,2405:1f00:ffff:ffff:ffff:ffff:ffff:ffff,TL
+2405:2000::,2405:2000:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:2100::,2405:2100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2200::,2405:2200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:2300::,2405:2300:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:2400::,2405:2400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:2500::,2405:2500:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2405:2600::,2405:2600:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:2700::,2405:2700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:2800::,2405:2800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:2900::,2405:2900:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:2a00::,2405:2a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:2b00::,2405:2b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2c00::,2405:2c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2d00::,2405:2d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2e00::,2405:2e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2f00::,2405:2f00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:3000::,2405:3001:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:3100::,2405:3100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:3200::,2405:3200:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:3300::,2405:3300:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:3400::,2405:3400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:3500::,2405:3500:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:3600::,2405:3600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:3700::,2405:3700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:3800::,2405:3800:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:3900::,2405:3900:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:3a00::,2405:3a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:3b00::,2405:3b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:3c00::,2405:3c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:3d00::,2405:3d00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:3e00::,2405:3e00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:3f00::,2405:3f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:4000::,2405:4000:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2405:4100::,2405:4100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:4200::,2405:4200:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:4300::,2405:4300:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:4400::,2405:4400:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2405:4500::,2405:4500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:4600::,2405:4600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:4700::,2405:4700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:4800::,2405:4800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2405:4900::,2405:4900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:4a00::,2405:4a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:4b00::,2405:4b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:4c00::,2405:4c00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:4d00::,2405:4d00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:4e00::,2405:4e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:4f00::,2405:4f00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:5000::,2405:5000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:5100::,2405:5100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:5200::,2405:5200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:5300::,2405:5300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:5400::,2405:5400:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2405:5600::,2405:5600:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:5800::,2405:5800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:5a00::,2405:5a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:5c00::,2405:5c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:5e00::,2405:5e00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:6000::,2405:6000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:6200::,2405:6200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:6400::,2405:6400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:6600::,2405:6600:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2405:6800::,2405:6800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:6a00::,2405:6a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:6c00::,2405:6c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:6e00::,2405:6e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:7000::,2405:7000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:7200::,2405:7200:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:7400::,2405:7400:ffff:ffff:ffff:ffff:ffff:ffff,GU
+2405:7600::,2405:7600:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:7800::,2405:7800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:7a00::,2405:7a00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:7c00::,2405:7c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:7e00::,2405:7e00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:8000::,2405:8000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:8200::,2405:8200:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:8400::,2405:8400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:8600::,2405:8600:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:8800::,2405:8800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:8a00::,2405:8a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:8c00::,2405:8c00:ffff:ffff:ffff:ffff:ffff:ffff,WS
+2405:8e00::,2405:8e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:9000::,2405:9000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:9200::,2405:9200:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:9400::,2405:9400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:9600::,2405:9600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:9800::,2405:9800:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2405:9a00::,2405:9a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:9c00::,2405:9c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:9e00::,2405:9e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:a000::,2405:a000:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2405:a200::,2405:a200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:a400::,2405:a400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:a600::,2405:a600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:aa00::,2405:aa00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:ac00::,2405:ac00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:ae00::,2405:ae00:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2405:b000::,2405:b000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:b200::,2405:b200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:b400::,2405:b400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:b600::,2405:b600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:b800::,2405:b800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:ba00::,2405:ba00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:bc00::,2405:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:be00::,2405:be00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:c000::,2405:c000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:c200::,2405:c200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:c400::,2405:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:c600::,2405:c600:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:c800::,2405:c800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:ca00::,2405:ca00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:cc00::,2405:cc00:ffff:ffff:ffff:ffff:ffff:ffff,PF
+2405:ce00::,2405:ce00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:d000::,2405:d000:ffff:ffff:ffff:ffff:ffff:ffff,BT
+2405:d200::,2405:d200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:d400::,2405:d400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:d600::,2405:d600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:d800::,2405:d800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:da00::,2405:da00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:dc00::,2405:dc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:e000::,2405:e000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:e200::,2405:e200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:e400::,2405:e400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:e600::,2405:e600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:e800::,2405:e800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:ea00::,2405:ea00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:ec00::,2405:ec00:ffff:ffff:ffff:ffff:ffff:ffff,BT
+2405:ee00::,2405:ee00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:f000::,2405:f000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:f200::,2405:f200:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:f400::,2405:f400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:f600::,2405:f600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:f800::,2405:f800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:fa00::,2405:fa00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:fc00::,2405:fc00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:fe00::,2405:fe00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2406::,2406:0:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:200::,2406:200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:400::,2406:400:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2406:600::,2406:600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:800::,2406:800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:a00::,2406:a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:c00::,2406:c00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2406:e00::,2406:e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:1000::,2406:1000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:1200::,2406:1200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:1400::,2406:1400:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2406:1600::,2406:1600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:1a00::,2406:1a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:1c00::,2406:1c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:1e00::,2406:1e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:2000::,2406:2000:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2406:2200::,2406:2200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:2400::,2406:2400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:2600::,2406:2600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:2800::,2406:2800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:2a00::,2406:2a00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2406:2c00::,2406:2c00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:2e00::,2406:2e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:3000::,2406:3003:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:3200::,2406:3200:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2406:3400::,2406:3400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3600::,2406:3600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3800::,2406:3800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3a00::,2406:3a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3c00::,2406:3c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3e00::,2406:3e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:4000::,2406:4000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:4200::,2406:4200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:4400::,2406:4400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2406:4600::,2406:4600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:4800::,2406:4800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:4a00::,2406:4a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:4c00::,2406:4c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:4e00::,2406:4e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:5000::,2406:5000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:5200::,2406:5200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:5400::,2406:5400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:5600::,2406:5600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:5800::,2406:5800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:5a00::,2406:5a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:5c00::,2406:5c00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:5e00::,2406:5e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:6000::,2406:6000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2406:6200::,2406:6200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:6400::,2406:6400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:6600::,2406:6600:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:6800::,2406:6800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:6a00::,2406:6a00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:6c00::,2406:6c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:6e00::,2406:6e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:7000::,2406:7000:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2406:7200::,2406:7200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:7400::,2406:7400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:7600::,2406:7600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:7800::,2406:7801:ffff:ffff:ffff:ffff:ffff:ffff,BN
+2406:7a00::,2406:7a00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:7c00::,2406:7c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:7e00::,2406:7e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:8000::,2406:8000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:8200::,2406:8200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:8400::,2406:8400:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2406:8600::,2406:8600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:8800::,2406:8800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:8a00::,2406:8a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:8c00::,2406:8c00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:8e00::,2406:8e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:9000::,2406:9000:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2406:9200::,2406:9200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2406:9400::,2406:9400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:9600::,2406:9600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:9800::,2406:9800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:9a00::,2406:9a01:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:9c00::,2406:9c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:9e00::,2406:9e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:a000::,2406:a000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:a200::,2406:a200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:a400::,2406:a400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:a600::,2406:a600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:a800::,2406:a800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:aa00::,2406:aa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:ac00::,2406:ac00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2406:ae00::,2406:ae00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:b000::,2406:b000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:b200::,2406:b200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:b400::,2406:b400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:b600::,2406:b600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:b800::,2406:b800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:ba00::,2406:ba00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:bc00::,2406:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:be00::,2406:be00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c000::,2406:c000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c200::,2406:c200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c400::,2406:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c600::,2406:c600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c800::,2406:c800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:ca00::,2406:ca00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:cc00::,2406:cc00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:ce00::,2406:ce07:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:d000::,2406:d000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:d200::,2406:d200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:d400::,2406:d400:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2406:d600::,2406:d600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:d800::,2406:d800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:da00::,2406:da00:ffff:ffff:ffff:ffff:ffff:ffff,AP
+2406:dc00::,2406:dc00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2406:de00::,2406:de00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:e000::,2406:e000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:e200::,2406:e200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:e400::,2406:e400:ffff:ffff:ffff:ffff:ffff:ffff,MV
+2406:e600::,2406:e600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:e800::,2406:e800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:ea00::,2406:ea00:ffff:ffff:ffff:ffff:ffff:ffff,MM
+2406:ec00::,2406:ec00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:ee00::,2406:ee00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:f000::,2406:f000:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:f200::,2406:f200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:f400::,2406:f400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:f600::,2406:f600:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:f800::,2406:f800:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2406:fa00::,2406:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:fc00::,2406:fc00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:fe00::,2406:fe00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407::,2407:0:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:200::,2407:200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:400::,2407:400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:600::,2407:600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:800::,2407:800:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2407:a00::,2407:a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:c00::,2407:c00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2407:e00::,2407:e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:1000::,2407:1000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:1200::,2407:1200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:1400::,2407:1400:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2407:1600::,2407:1600:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:1800::,2407:1800:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2407:1a00::,2407:1a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:1c00::,2407:1c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:1e00::,2407:1e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:2000::,2407:2000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2407:2200::,2407:2200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:2400::,2407:2400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:2600::,2407:2600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:2800::,2407:2800:ffff:ffff:ffff:ffff:ffff:ffff,WS
+2407:2a00::,2407:2a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:2c00::,2407:2c00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2407:2e00::,2407:2e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:3000::,2407:3000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:3400::,2407:3400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:3600::,2407:3600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:3800::,2407:3800:ffff:ffff:ffff:ffff:ffff:ffff,SB
+2407:3a00::,2407:3a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:3c00::,2407:3c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:3e00::,2407:3e00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:4000::,2407:4000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:4200::,2407:4200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:4400::,2407:4400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:4600::,2407:4600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:4800::,2407:4800:ffff:ffff:ffff:ffff:ffff:ffff,FM
+2407:4a00::,2407:4a00:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2407:4c00::,2407:4c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:4e00::,2407:4e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:5000::,2407:5000:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2407:5200::,2407:5200:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2407:5400::,2407:5400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:5600::,2407:5600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:5800::,2407:5800:ffff:ffff:ffff:ffff:ffff:ffff,CK
+2407:5a00::,2407:5a00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2407:5c00::,2407:5c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:5e00::,2407:5e00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2407:6000::,2407:6000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:6200::,2407:6200:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2407:6400::,2407:6400:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2407:6600::,2407:6600:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2407:6800::,2407:6800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:6a00::,2407:6a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:6c00::,2407:6c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:6e00::,2407:6e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:7000::,2407:7000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:7200::,2407:7200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:7400::,2407:7400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:7600::,2407:7600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:7800::,2407:7800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:7a00::,2407:7a00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2407:7c00::,2407:7c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:7e00::,2407:7e00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:8000::,2407:8000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:8200::,2407:8200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:8400::,2407:8400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:8600::,2407:8600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:8800::,2407:8800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:8a00::,2407:8a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:8c00::,2407:8c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:8e00::,2407:8e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:9000::,2407:9000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:9200::,2407:9200:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2407:9400::,2407:9400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:9600::,2407:9600:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:9800::,2407:9800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2407:9a00::,2407:9a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:9c00::,2407:9c00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2407:9e00::,2407:9e00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2407:a000::,2407:a000:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2407:a200::,2407:a200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:a600::,2407:a600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:a800::,2407:a800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:aa00::,2407:aa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:ac00::,2407:ac00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:ae00::,2407:ae00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:b000::,2407:b000:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:b200::,2407:b200:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2407:b400::,2407:b400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:b600::,2407:b600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:b800::,2407:b800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2407:ba00::,2407:ba00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2407:bc00::,2407:bc00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2407:be00::,2407:be00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:c000::,2407:c000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2407:c200::,2407:c200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:c400::,2407:c400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2407:c600::,2407:c600:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:c800::,2407:c800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:ca00::,2407:ca00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:cc00::,2407:cc00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:ce00::,2407:ce00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:d000::,2407:d000:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2407:d200::,2407:d200:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:d400::,2407:d400:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2407:d600::,2407:d600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:d800::,2407:d800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:da00::,2407:da00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:dc00::,2407:dc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:de00::,2407:de00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:e000::,2407:e000:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:e200::,2407:e200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:e400::,2407:e400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:e600::,2407:e600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:e800::,2407:e800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2407:ea00::,2407:ea00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:ec00::,2407:ec00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:ee00::,2407:ee00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:f000::,2407:f000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:f200::,2407:f200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:f400::,2407:f400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:f600::,2407:f600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:f800::,2407:f800:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:fa00::,2407:fa00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:fc00::,2407:fc00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:fe00::,2407:fe00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2408::,2408:3ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2408:8000::,2408:8fff:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2409::,2409:3ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2409:8000::,2409:8fff:ffff:ffff:ffff:ffff:ffff:ffff,CN
+240a::,240a:7f:ffff:ffff:ffff:ffff:ffff:ffff,JP
+240b::,240b:3ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+240c::,240c:f:ffff:ffff:ffff:ffff:ffff:ffff,CN
+240d::,240d:1f:ffff:ffff:ffff:ffff:ffff:ffff,JP
+240e::,240e:fff:ffff:ffff:ffff:ffff:ffff:ffff,CN
+240f::,240f:ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2600::,2600:7:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:100::,2600:10f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:200::,2600:20f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:300::,2600:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:800::,2600:81f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:900::,2600:90f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:a00::,2600:a01:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:b00::,2600:b0f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:c00::,2600:c14:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:d00::,2600:d0f:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2600:f00::,2600:1017:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1100::,2600:110f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1200::,2600:130f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1400::,2600:141f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1800::,2600:180f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1c00::,2600:1c0f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:2000::,2600:200f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:2400::,2600:2407:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:2800::,2600:2803:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:2c00::,2600:2c03:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:3000::,2600:3007:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:3400::,2600:340f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:3800::,2600:380f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:3c00::,2600:3c03:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:4000::,2600:40ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:4400::,2600:4407:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:4800::,2600:480f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:4c00::,2600:4c01:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:5000::,2600:500f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:5400::,2600:541f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:5800::,2600:5801:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:5c00::,2600:5c01:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:6000::,2600:6001:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:6400::,2600:640f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:6800::,2600:68ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:6c00::,2600:6cff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:7000::,2600:70ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:8000::,2600:80ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:e000::,2600:e00f:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2601::,2601:f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602::,2602:10f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602:200::,2602:200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2602:210::,2602:210:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2602:220::,2602:220:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2602:230::,2602:230:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602:240::,2602:24f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602:300::,2602:3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604::,2604:0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:10::,2604:10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:100::,2604:100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:180::,2604:180:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:200::,2604:200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:280::,2604:280:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:300::,2604:300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:380::,2604:380:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:400::,2604:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:480::,2604:480:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:500::,2604:500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:580::,2604:580:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:600::,2604:600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:680::,2604:680:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:700::,2604:700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:780::,2604:780:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:800::,2604:800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:880::,2604:880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:900::,2604:900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:980::,2604:980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a00::,2604:a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a80::,2604:a80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b00::,2604:b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b80::,2604:b80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c00::,2604:c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c80::,2604:c80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d00::,2604:d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d80::,2604:d80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e00::,2604:e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e80::,2604:e80:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:f00::,2604:f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f80::,2604:f80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1000::,2604:1000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1080::,2604:1080:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1100::,2604:1100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1180::,2604:1180:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1200::,2604:1200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1280::,2604:1280:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1300::,2604:1300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1380::,2604:1380:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1400::,2604:1400:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2604:1480::,2604:1480:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1500::,2604:1500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1580::,2604:1580:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1600::,2604:1600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1680::,2604:1680:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1700::,2604:1700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1780::,2604:1780:ffff:ffff:ffff:ffff:ffff:ffff,KY
+2604:1800::,2604:1800:ffff:ffff:ffff:ffff:ffff:ffff,GP
+2604:1880::,2604:1880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1900::,2604:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1980::,2604:1980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1a00::,2604:1a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1a80::,2604:1a80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1b00::,2604:1b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1b80::,2604:1b80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1c00::,2604:1c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1c80::,2604:1c80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1d00::,2604:1d00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1d80::,2604:1d80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1e00::,2604:1e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1e80::,2604:1e80:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1f00::,2604:1f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1f80::,2604:1f80:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:2000::,2604:2000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2080::,2604:2080:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2100::,2604:2100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2200::,2604:2200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2300::,2604:2300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2400::,2604:2400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2500::,2604:2500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2600::,2604:2600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2700::,2604:2700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2800::,2604:2800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2900::,2604:2900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2a00::,2604:2a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2b00::,2604:2b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2c00::,2604:2c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2d00::,2604:2d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2e00::,2604:2e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2f00::,2604:2f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3000::,2604:3000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3100::,2604:3100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3200::,2604:3200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3300::,2604:3300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3400::,2604:3400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3500::,2604:3500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3600::,2604:3600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3700::,2604:3700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3800::,2604:3800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3900::,2604:3900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3a00::,2604:3a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3b00::,2604:3b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:3c00::,2604:3c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3d00::,2604:3d00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:3e00::,2604:3e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3f00::,2604:3f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4000::,2604:4000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:4100::,2604:4100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4200::,2604:4200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4300::,2604:4300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4400::,2604:4400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4500::,2604:4500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4600::,2604:4600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4700::,2604:4700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4800::,2604:4800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4900::,2604:4900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4a00::,2604:4a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4b00::,2604:4b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4c00::,2604:4c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:4d00::,2604:4d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4e00::,2604:4e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4f00::,2604:4f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5000::,2604:5000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5100::,2604:5100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5200::,2604:5200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5300::,2604:5300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5400::,2604:5400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5500::,2604:5500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5600::,2604:5600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5700::,2604:5700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5800::,2604:5800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5900::,2604:5900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5a00::,2604:5a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5b00::,2604:5b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5c00::,2604:5c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5d00::,2604:5d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5e00::,2604:5e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5f00::,2604:5f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6000::,2604:6000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6100::,2604:6100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6200::,2604:6200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6300::,2604:6300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6400::,2604:6400:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:6500::,2604:6500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:6600::,2604:6600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6700::,2604:6700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6800::,2604:6800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6900::,2604:6900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6a00::,2604:6a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6b00::,2604:6b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6c00::,2604:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6d00::,2604:6d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6e00::,2604:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6f00::,2604:6f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7000::,2604:7000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7100::,2604:7100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7200::,2604:7200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7300::,2604:7300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7400::,2604:7400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7500::,2604:7500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7600::,2604:7600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7700::,2604:7700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7800::,2604:7800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7900::,2604:7900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7a00::,2604:7a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7b00::,2604:7b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7c00::,2604:7c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7d00::,2604:7d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7e00::,2604:7e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7f00::,2604:7f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:8000::,2604:8000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8100::,2604:8100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8200::,2604:8200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8300::,2604:8300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8400::,2604:8400:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:8500::,2604:8500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8600::,2604:8600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:8700::,2604:8700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8800::,2604:8800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8900::,2604:8900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8a00::,2604:8a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8b00::,2604:8b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8c00::,2604:8c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8d00::,2604:8d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8e00::,2604:8e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8f00::,2604:8f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9000::,2604:9000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9100::,2604:9100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9200::,2604:9200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9300::,2604:9300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9400::,2604:9400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9500::,2604:9500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9600::,2604:9600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9700::,2604:9700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9800::,2604:9800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9900::,2604:9900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9a00::,2604:9a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9b00::,2604:9b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9c00::,2604:9c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9d00::,2604:9d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9e00::,2604:9e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9f00::,2604:9f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a000::,2604:a000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a100::,2604:a100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a200::,2604:a200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a300::,2604:a300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a400::,2604:a400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a500::,2604:a500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a600::,2604:a600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a700::,2604:a700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a800::,2604:a800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a900::,2604:a900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:aa00::,2604:aa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ab00::,2604:ab00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ac00::,2604:ac00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ad00::,2604:ad00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ae00::,2604:ae00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:af00::,2604:af00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b000::,2604:b000:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2604:b100::,2604:b100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b200::,2604:b200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b300::,2604:b300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b400::,2604:b400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b500::,2604:b500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b600::,2604:b600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b700::,2604:b700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b800::,2604:b800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b900::,2604:b900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ba00::,2604:ba00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:bb00::,2604:bb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:bc00::,2604:bc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:bd00::,2604:bd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:be00::,2604:be00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:bf00::,2604:bf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c000::,2604:c000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c100::,2604:c100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c200::,2604:c200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c300::,2604:c300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c400::,2604:c400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c500::,2604:c500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c600::,2604:c600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c700::,2604:c700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c800::,2604:c800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c900::,2604:c900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ca00::,2604:ca00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:cb00::,2604:cb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:cc00::,2604:cc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:cd00::,2604:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ce00::,2604:ce00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:cf00::,2604:cf00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:d000::,2604:d000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d100::,2604:d100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d200::,2604:d200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d300::,2604:d300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d400::,2604:d400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d500::,2604:d500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d600::,2604:d600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d700::,2604:d700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d800::,2604:d801:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d900::,2604:d900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:da00::,2604:da00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:db00::,2604:db00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:dc00::,2604:dc00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:dd00::,2604:dd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:de00::,2604:de00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:df00::,2604:df00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e000::,2604:e000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e100::,2604:e100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:e200::,2604:e200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e300::,2604:e300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e400::,2604:e400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e500::,2604:e500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e600::,2604:e600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e700::,2604:e700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e800::,2604:e800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e900::,2604:e900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ea00::,2604:ea00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:eb00::,2604:eb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ec00::,2604:ec00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:ed00::,2604:ed00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ee00::,2604:ee00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ef00::,2604:ef00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:f000::,2604:f000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:f100::,2604:f100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f200::,2604:f200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f300::,2604:f300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f400::,2604:f400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f500::,2604:f500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f600::,2604:f600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f700::,2604:f700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f800::,2604:f800:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:f900::,2604:f900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fa00::,2604:fa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fb00::,2604:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fc00::,2604:fc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fd00::,2604:fd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fe00::,2604:fe00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ff00::,2604:ff00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605::,2605:0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:100::,2605:100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:200::,2605:200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:300::,2605:300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:400::,2605:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:500::,2605:500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:600::,2605:600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:700::,2605:700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:800::,2605:800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:900::,2605:900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a00::,2605:a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b00::,2605:b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c00::,2605:c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:d00::,2605:d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e00::,2605:e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f00::,2605:f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1000::,2605:1000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1100::,2605:1100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1200::,2605:1200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1300::,2605:1300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1400::,2605:1400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1500::,2605:1500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1600::,2605:1600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1700::,2605:1700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1800::,2605:1800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1900::,2605:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1a00::,2605:1a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1b00::,2605:1b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1c00::,2605:1c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1d00::,2605:1d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1e00::,2605:1e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1f00::,2605:1f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2000::,2605:2000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2100::,2605:2100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2200::,2605:2200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2300::,2605:2300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2400::,2605:2400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2500::,2605:2500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2600::,2605:2600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2700::,2605:2700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2800::,2605:2800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2900::,2605:2900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2a00::,2605:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2b00::,2605:2b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2c00::,2605:2c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2d00::,2605:2d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2e00::,2605:2e00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2f00::,2605:2f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3000::,2605:3000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3100::,2605:3100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3200::,2605:3200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3300::,2605:3300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3400::,2605:3400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3500::,2605:3500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3600::,2605:3600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3700::,2605:3700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3800::,2605:3800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3900::,2605:3900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3a00::,2605:3a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3b00::,2605:3b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3c00::,2605:3c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3d00::,2605:3d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3e00::,2605:3e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3f00::,2605:3f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:4000::,2605:4000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4100::,2605:4100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4200::,2605:4200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4300::,2605:4300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4400::,2605:4400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4500::,2605:4500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4600::,2605:4600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4700::,2605:4700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4800::,2605:4800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4900::,2605:4900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4a00::,2605:4a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4b00::,2605:4b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4c00::,2605:4c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4d00::,2605:4d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4e00::,2605:4e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4f00::,2605:4f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:5000::,2605:5000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5100::,2605:5100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5200::,2605:5200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5300::,2605:5300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5400::,2605:5400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5500::,2605:5500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5600::,2605:5600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5700::,2605:5700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5800::,2605:5800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5900::,2605:5900:ffff:ffff:ffff:ffff:ffff:ffff,JM
+2605:5a00::,2605:5a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5b00::,2605:5b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5c00::,2605:5c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5d00::,2605:5d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5e00::,2605:5e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5f00::,2605:5f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6000::,2605:6000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6100::,2605:6100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6200::,2605:6200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6300::,2605:6300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6400::,2605:6400:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:6500::,2605:6500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6600::,2605:6600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6700::,2605:6700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6800::,2605:6800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6900::,2605:6900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6a00::,2605:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:6b00::,2605:6b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:6c00::,2605:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6d00::,2605:6d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6e00::,2605:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6f00::,2605:6f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:7000::,2605:7000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7100::,2605:7100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7200::,2605:7200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:7300::,2605:7300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7400::,2605:7400:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:7500::,2605:7500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7600::,2605:7600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7700::,2605:7700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7800::,2605:7801:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7900::,2605:7900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7a00::,2605:7a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7b00::,2605:7b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7c00::,2605:7c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:7d00::,2605:7d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7e00::,2605:7e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7f00::,2605:7f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8000::,2605:8000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8100::,2605:8100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:8200::,2605:8200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8300::,2605:8300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8400::,2605:8400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8500::,2605:8500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8600::,2605:8600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8700::,2605:8700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8800::,2605:8800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8900::,2605:8900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8a00::,2605:8a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8b00::,2605:8b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8c00::,2605:8c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8d00::,2605:8d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8e00::,2605:8e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8f00::,2605:8f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9000::,2605:9000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:9100::,2605:9100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9200::,2605:9200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9300::,2605:9300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:9400::,2605:9400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9500::,2605:9500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9600::,2605:9600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9700::,2605:9700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9800::,2605:9800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9900::,2605:9900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9a00::,2605:9a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9b00::,2605:9b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9c00::,2605:9c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9d00::,2605:9d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9e00::,2605:9e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9f00::,2605:9f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a000::,2605:a000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a100::,2605:a100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a200::,2605:a200:ffff:ffff:ffff:ffff:ffff:ffff,JM
+2605:a300::,2605:a300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a400::,2605:a407:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a500::,2605:a500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a600::,2605:a601:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a700::,2605:a700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a800::,2605:a800:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:a900::,2605:a900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:aa00::,2605:aa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ab00::,2605:ab00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:ac00::,2605:ac00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:ad00::,2605:ad00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ae00::,2605:ae00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:af00::,2605:af00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b000::,2605:b000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:b100::,2605:b100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:b200::,2605:b200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b300::,2605:b300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b400::,2605:b400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b500::,2605:b500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b600::,2605:b600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:b700::,2605:b700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b800::,2605:b800:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2605:b900::,2605:b900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:ba00::,2605:ba00:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2605:bb00::,2605:bb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:bc00::,2605:bc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:bd00::,2605:bd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:be00::,2605:be00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:bf00::,2605:bf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c000::,2605:c000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c100::,2605:c100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c200::,2605:c200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c300::,2605:c300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c400::,2605:c400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c500::,2605:c500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:c600::,2605:c600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c700::,2605:c700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:c800::,2605:c800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c900::,2605:c900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ca00::,2605:ca00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:cb00::,2605:cb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:cc00::,2605:cc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:cd00::,2605:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ce00::,2605:ce00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:cf00::,2605:cf00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:d000::,2605:d000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d100::,2605:d100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d200::,2605:d200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d300::,2605:d300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d400::,2605:d400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d500::,2605:d500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:d600::,2605:d600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d700::,2605:d700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d800::,2605:d800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d900::,2605:d900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:da00::,2605:da00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:db00::,2605:db00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:dc00::,2605:dc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:dd00::,2605:dd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:de00::,2605:de00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:df00::,2605:df00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e000::,2605:e000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e100::,2605:e100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e200::,2605:e200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:e300::,2605:e300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e400::,2605:e400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e500::,2605:e500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e600::,2605:e600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e700::,2605:e700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e800::,2605:e800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e900::,2605:e900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ea00::,2605:ea00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:eb00::,2605:eb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ec00::,2605:ec00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ed00::,2605:ed00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ee00::,2605:ee00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ef00::,2605:ef00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f000::,2605:f000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f100::,2605:f100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f200::,2605:f200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f300::,2605:f300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f400::,2605:f400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f500::,2605:f500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f600::,2605:f600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f700::,2605:f700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f800::,2605:f800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f900::,2605:f900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:fa00::,2605:fa00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:fb00::,2605:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:fc00::,2605:fc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:fd00::,2605:fd00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:fe00::,2605:fe00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ff00::,2605:ff00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606::,2606:0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:100::,2606:100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:200::,2606:200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:300::,2606:300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:400::,2606:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:500::,2606:500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:600::,2606:600:ffff:ffff:ffff:ffff:ffff:ffff,KY
+2606:700::,2606:700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:800::,2606:800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:900::,2606:900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a00::,2606:a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b00::,2606:b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c00::,2606:c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d00::,2606:d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e00::,2606:e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f00::,2606:f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1000::,2606:1000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1100::,2606:1100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1200::,2606:1200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1300::,2606:1300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1400::,2606:1400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1500::,2606:1500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1600::,2606:1600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1700::,2606:1700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1800::,2606:1800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1900::,2606:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1b00::,2606:1b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1c00::,2606:1c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1d00::,2606:1d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1e00::,2606:1e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1f00::,2606:1f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:2000::,2606:2000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2100::,2606:2100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2200::,2606:2200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2300::,2606:2300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2400::,2606:2400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2500::,2606:2500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2600::,2606:2600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2700::,2606:2700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:2800::,2606:2800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2900::,2606:2900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2a00::,2606:2a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2b00::,2606:2b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2c00::,2606:2c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2d00::,2606:2d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2e00::,2606:2e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2f00::,2606:2f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3000::,2606:3000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:3100::,2606:3100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:3200::,2606:3200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3300::,2606:3300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3400::,2606:3400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3500::,2606:3500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3600::,2606:3600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3700::,2606:3700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3800::,2606:3800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3900::,2606:3900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3a00::,2606:3a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3b00::,2606:3b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3c00::,2606:3c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:3d00::,2606:3d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3e00::,2606:3e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3f00::,2606:3f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4000::,2606:4000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4100::,2606:4100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4200::,2606:4200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4300::,2606:4300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4400::,2606:4400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4500::,2606:4500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4600::,2606:4600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4700::,2606:4700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4800::,2606:4800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4900::,2606:4900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4a00::,2606:4a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4b00::,2606:4b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4c00::,2606:4c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4d00::,2606:4d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4e00::,2606:4e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4f00::,2606:4f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5000::,2606:5000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5100::,2606:5100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5200::,2606:5200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5300::,2606:5300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:5400::,2606:5400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5500::,2606:5500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5600::,2606:5600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5700::,2606:5700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5800::,2606:5800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5900::,2606:5900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5a00::,2606:5a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5b00::,2606:5b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5c00::,2606:5c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5d00::,2606:5d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5e00::,2606:5e00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:5f00::,2606:5f00:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2606:6000::,2606:6000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6100::,2606:6100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6200::,2606:6200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:6300::,2606:6300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:6400::,2606:6400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6500::,2606:6500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6600::,2606:6600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6700::,2606:6700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6900::,2606:6900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6a00::,2606:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:6b00::,2606:6b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6c00::,2606:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6d00::,2606:6d00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:6e00::,2606:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6f00::,2606:6f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7000::,2606:7000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7100::,2606:7100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7200::,2606:7200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7300::,2606:7300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7400::,2606:7400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7500::,2606:7500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7600::,2606:7600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7700::,2606:7700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7800::,2606:7800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7900::,2606:7900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7a00::,2606:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:7b00::,2606:7b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7c00::,2606:7c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7d00::,2606:7d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7e00::,2606:7e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7f00::,2606:7f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8000::,2606:8000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8100::,2606:8100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8200::,2606:8200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8300::,2606:8300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:8400::,2606:8400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8500::,2606:8500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8600::,2606:8600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8700::,2606:8700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8800::,2606:8800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8a00::,2606:8a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8b00::,2606:8b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8c00::,2606:8c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:8d00::,2606:8d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8e00::,2606:8e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8f00::,2606:8f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9100::,2606:9100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9200::,2606:9200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9300::,2606:9300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9400::,2606:9400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9500::,2606:9500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9600::,2606:9600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9700::,2606:9700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9800::,2606:9800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9900::,2606:9900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9a00::,2606:9a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9b00::,2606:9b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9c00::,2606:9c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9d00::,2606:9d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9e00::,2606:9e00:ffff:ffff:ffff:ffff:ffff:ffff,BM
+2606:9f00::,2606:9f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a000::,2606:a000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a100::,2606:a100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a200::,2606:a200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a300::,2606:a300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a400::,2606:a400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a500::,2606:a500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a600::,2606:a600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a700::,2606:a700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a800::,2606:a800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a900::,2606:a900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:aa00::,2606:aa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ab00::,2606:ab00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ac00::,2606:ac00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ad00::,2606:ad00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ae00::,2606:ae00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:af00::,2606:af00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:b000::,2606:b000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b100::,2606:b100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b200::,2606:b200:ffff:ffff:ffff:ffff:ffff:ffff,KY
+2606:b300::,2606:b300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b400::,2606:b400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b500::,2606:b500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b600::,2606:b600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b700::,2606:b700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b800::,2606:b800:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:b900::,2606:b900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ba00::,2606:ba00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:bb00::,2606:bb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:bc00::,2606:bc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:bd00::,2606:bd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:be00::,2606:be00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:bf00::,2606:bf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c000::,2606:c000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c100::,2606:c100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c200::,2606:c200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c300::,2606:c300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c400::,2606:c400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c500::,2606:c500:ffff:ffff:ffff:ffff:ffff:ffff,JM
+2606:c600::,2606:c600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:c700::,2606:c700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c800::,2606:c800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c900::,2606:c900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ca00::,2606:ca00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:cb00::,2606:cb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:cc00::,2606:cc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:cd00::,2606:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ce00::,2606:ce00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:cf00::,2606:cf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d000::,2606:d000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d100::,2606:d100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d200::,2606:d200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d300::,2606:d300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d400::,2606:d400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d500::,2606:d500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d600::,2606:d600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d700::,2606:d700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d800::,2606:d800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d900::,2606:d900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:da00::,2606:da00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:db00::,2606:db00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:dc00::,2606:dc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:dd00::,2606:dd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:de00::,2606:de00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:df00::,2606:df00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e000::,2606:e000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:e100::,2606:e100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e200::,2606:e200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e300::,2606:e300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e400::,2606:e400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e500::,2606:e500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e600::,2606:e600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e700::,2606:e700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e800::,2606:e800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e900::,2606:e900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ea00::,2606:ea00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:eb00::,2606:eb00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:ec00::,2606:ec00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ed00::,2606:ed00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ee00::,2606:ee00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:ef00::,2606:ef00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f000::,2606:f000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f100::,2606:f100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f200::,2606:f200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f300::,2606:f300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f400::,2606:f40f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f500::,2606:f500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f600::,2606:f600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f700::,2606:f700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:f800::,2606:f800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f900::,2606:f900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:fa00::,2606:fa00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:fb00::,2606:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:fc00::,2606:fc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:fd00::,2606:fd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:fe00::,2606:fe00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ff00::,2606:ff00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607::,2607:0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:100::,2607:100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:200::,2607:200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:300::,2607:300:ffff:ffff:ffff:ffff:ffff:ffff,BS
+2607:400::,2607:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:500::,2607:500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:600::,2607:600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:700::,2607:700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:800::,2607:800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:900::,2607:900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a00::,2607:a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:b00::,2607:b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c00::,2607:c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d00::,2607:d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e00::,2607:e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f00::,2607:f00:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2607:1000::,2607:1000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1100::,2607:1100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1200::,2607:1200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1300::,2607:1300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1400::,2607:1400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1500::,2607:1500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1600::,2607:1600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1700::,2607:1700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1800::,2607:1800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1900::,2607:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1a00::,2607:1a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1b00::,2607:1b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1c00::,2607:1c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1d00::,2607:1d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1e00::,2607:1e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1f00::,2607:1f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2000::,2607:2000:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2607:2100::,2607:2100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2200::,2607:2200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2300::,2607:2300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2400::,2607:2400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2500::,2607:2500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2600::,2607:2600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2700::,2607:2700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2800::,2607:2800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2900::,2607:2900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2a00::,2607:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2b00::,2607:2b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2c00::,2607:2c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2d00::,2607:2d00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2e00::,2607:2e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2f00::,2607:2f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3000::,2607:3000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3100::,2607:3100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3200::,2607:3200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3300::,2607:3300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3400::,2607:3400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3500::,2607:3500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3600::,2607:3600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3700::,2607:3700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3800::,2607:3800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3900::,2607:3900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3a00::,2607:3a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3b00::,2607:3b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3c00::,2607:3c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3d00::,2607:3d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3e00::,2607:3e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3f00::,2607:3f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4000::,2607:4000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4100::,2607:4100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:4200::,2607:4200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4300::,2607:4300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:4400::,2607:4400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4500::,2607:4500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4600::,2607:4600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4700::,2607:4700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4800::,2607:4800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4900::,2607:4900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4a00::,2607:4a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4b00::,2607:4b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4c00::,2607:4c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:4d00::,2607:4d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4e00::,2607:4e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4f00::,2607:4f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5000::,2607:5006:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5100::,2607:5100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5200::,2607:5200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5300::,2607:5300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:5400::,2607:5400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5500::,2607:5500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5600::,2607:5600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5700::,2607:5700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5800::,2607:5800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5900::,2607:5900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:5a00::,2607:5a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5b00::,2607:5b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5c00::,2607:5c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5d00::,2607:5d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5e00::,2607:5e00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:5f00::,2607:5f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6000::,2607:6000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6100::,2607:6100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6200::,2607:6200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6300::,2607:6300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6400::,2607:6400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6500::,2607:6500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:6600::,2607:6600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6700::,2607:6700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6800::,2607:6800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6900::,2607:6900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6a00::,2607:6a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6b00::,2607:6b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6c00::,2607:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6d00::,2607:6d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6e00::,2607:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6f00::,2607:6f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7000::,2607:7000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7100::,2607:7100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7200::,2607:7200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:7300::,2607:7300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:7400::,2607:7400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7500::,2607:7500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7600::,2607:7600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:7700::,2607:7700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7800::,2607:7800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7900::,2607:7900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7a00::,2607:7a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7b00::,2607:7b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:7c00::,2607:7c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7d00::,2607:7d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7e00::,2607:7e00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:8000::,2607:8000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8100::,2607:8100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8200::,2607:8200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8300::,2607:8300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8400::,2607:8400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8500::,2607:8500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8600::,2607:8600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8700::,2607:8700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8800::,2607:8800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8900::,2607:8900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8a00::,2607:8a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8b00::,2607:8b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8c00::,2607:8c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8d00::,2607:8d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8e00::,2607:8e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8f00::,2607:8f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9000::,2607:9000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9100::,2607:9100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9200::,2607:9200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9300::,2607:9300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9400::,2607:9400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9500::,2607:9500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:9600::,2607:9600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9700::,2607:9700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9800::,2607:9800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9900::,2607:9900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:9a00::,2607:9a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9b00::,2607:9b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9c00::,2607:9c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9d00::,2607:9d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9e00::,2607:9e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9f00::,2607:9f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a000::,2607:a000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:a100::,2607:a10f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a200::,2607:a200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a300::,2607:a300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a400::,2607:a400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a500::,2607:a500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a600::,2607:a600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a700::,2607:a700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a800::,2607:a800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a900::,2607:a900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:aa00::,2607:aa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ab00::,2607:ab00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ac00::,2607:ac00:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2607:ad00::,2607:ad00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ae00::,2607:ae00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:af00::,2607:af00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b000::,2607:b000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b100::,2607:b100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b200::,2607:b200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b300::,2607:b300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b400::,2607:b400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b500::,2607:b500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b600::,2607:b600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b700::,2607:b700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b800::,2607:b800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b900::,2607:b900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ba00::,2607:ba00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:bb00::,2607:bb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:bc00::,2607:bc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:bd00::,2607:bd00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:be00::,2607:be00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:bf00::,2607:bf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c000::,2607:c000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:c100::,2607:c100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c200::,2607:c200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c300::,2607:c300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c400::,2607:c400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c500::,2607:c500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c600::,2607:c600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c700::,2607:c700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c800::,2607:c800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c900::,2607:c900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ca00::,2607:ca00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:cb00::,2607:cb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:cc00::,2607:cc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:cd00::,2607:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ce00::,2607:ce00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:cf00::,2607:cf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d000::,2607:d000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d200::,2607:d200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d300::,2607:d300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d400::,2607:d400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d500::,2607:d500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:d600::,2607:d600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d700::,2607:d700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:d800::,2607:d800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d900::,2607:d900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:da00::,2607:da00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:db00::,2607:db00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:dc00::,2607:dc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:dd00::,2607:dd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:de00::,2607:de00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:df00::,2607:df00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e000::,2607:e000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e100::,2607:e100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e200::,2607:e200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e300::,2607:e300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e400::,2607:e400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e500::,2607:e500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e600::,2607:e600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e700::,2607:e700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e800::,2607:e800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e900::,2607:e900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ea00::,2607:ea00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:eb00::,2607:eb00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ec00::,2607:ec00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ed00::,2607:ed00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ee00::,2607:ee00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ef00::,2607:ef00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f000::,2607:f000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f008::,2607:f008:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f010::,2607:f010:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f018::,2607:f018:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f020::,2607:f020:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f028::,2607:f028:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f030::,2607:f030:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f038::,2607:f038:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f040::,2607:f040:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f048::,2607:f048:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f050::,2607:f050:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f058::,2607:f058:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f060::,2607:f060:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f068::,2607:f068:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f070::,2607:f070:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f078::,2607:f078:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f080::,2607:f080:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f088::,2607:f088:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f090::,2607:f090:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f098::,2607:f098:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0a0::,2607:f0a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0a8::,2607:f0a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0b0::,2607:f0b0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f0c0::,2607:f0c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0c8::,2607:f0c8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f0d0::,2607:f0d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0d8::,2607:f0e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0e8::,2607:f0e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0f8::,2607:f0f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f100::,2607:f100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f108::,2607:f108:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f110::,2607:f110:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f118::,2607:f118:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f128::,2607:f128:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f130::,2607:f130:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f138::,2607:f138:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f140::,2607:f140:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f148::,2607:f148:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f150::,2607:f150:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f158::,2607:f158:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f160::,2607:f160:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f168::,2607:f168:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f170::,2607:f170:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f178::,2607:f178:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f180::,2607:f180:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f188::,2607:f188:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f190::,2607:f190:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f198::,2607:f198:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1a0::,2607:f1a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1a8::,2607:f1a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1b0::,2607:f1b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1b8::,2607:f1b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1c0::,2607:f1c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1c8::,2607:f1c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1d0::,2607:f1d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1d8::,2607:f1d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1e0::,2607:f1e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1e8::,2607:f1e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1f0::,2607:f1f0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f1f8::,2607:f1f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f200::,2607:f200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f208::,2607:f208:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f210::,2607:f210:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f218::,2607:f218:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f220::,2607:f220:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f228::,2607:f228:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f230::,2607:f230:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f238::,2607:f238:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f240::,2607:f240:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f248::,2607:f248:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f250::,2607:f250:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f258::,2607:f258:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f260::,2607:f260:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f270::,2607:f270:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f278::,2607:f278:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f280::,2607:f281:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f288::,2607:f288:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f290::,2607:f290:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f298::,2607:f298:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2a8::,2607:f2a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2b0::,2607:f2b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2c0::,2607:f2c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f2c8::,2607:f2c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2d0::,2607:f2d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2d8::,2607:f2d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2e0::,2607:f2e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2e8::,2607:f2e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2f0::,2607:f2f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2f8::,2607:f2f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f300::,2607:f300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f308::,2607:f308:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f310::,2607:f310:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f318::,2607:f318:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f330::,2607:f330:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f338::,2607:f338:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f340::,2607:f340:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f348::,2607:f348:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f350::,2607:f350:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f358::,2607:f358:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f360::,2607:f360:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f368::,2607:f368:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f370::,2607:f370:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f378::,2607:f378:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f380::,2607:f380:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f388::,2607:f388:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f390::,2607:f390:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f398::,2607:f398:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3a0::,2607:f3a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3b0::,2607:f3b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3b8::,2607:f3b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3c0::,2607:f3c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3c8::,2607:f3c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3d0::,2607:f3d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3d8::,2607:f3d8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f3e0::,2607:f3e0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f3e8::,2607:f3e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3f0::,2607:f3f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3f8::,2607:f3f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f400::,2607:f400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f408::,2607:f408:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f410::,2607:f410:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f418::,2607:f418:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f420::,2607:f420:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f428::,2607:f428:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f430::,2607:f430:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f438::,2607:f438:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f440::,2607:f440:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f448::,2607:f448:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f450::,2607:f450:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f458::,2607:f458:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f460::,2607:f460:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f468::,2607:f468:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f470::,2607:f470:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f478::,2607:f478:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f480::,2607:f480:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f488::,2607:f488:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f490::,2607:f490:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f498::,2607:f498:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4a0::,2607:f4a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4a8::,2607:f4a8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f4b0::,2607:f4b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4b8::,2607:f4b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4c0::,2607:f4c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4c8::,2607:f4c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4d0::,2607:f4d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4d8::,2607:f4d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4e0::,2607:f4e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4e8::,2607:f4e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4f0::,2607:f4f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4f8::,2607:f4f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f500::,2607:f500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f508::,2607:f508:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f510::,2607:f510:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f518::,2607:f518:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f520::,2607:f520:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f528::,2607:f528:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f530::,2607:f530:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f538::,2607:f538:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f540::,2607:f540:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f548::,2607:f548:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f550::,2607:f550:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f558::,2607:f558:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f560::,2607:f560:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f568::,2607:f568:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f570::,2607:f570:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f578::,2607:f578:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f580::,2607:f580:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f588::,2607:f588:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f590::,2607:f590:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f598::,2607:f598:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5a0::,2607:f5a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5a8::,2607:f5a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5b0::,2607:f5b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5b8::,2607:f5b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5c0::,2607:f5c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5c8::,2607:f5c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5d0::,2607:f5d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5d8::,2607:f5d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5e0::,2607:f5e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5e8::,2607:f5e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5f0::,2607:f5f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5f8::,2607:f5f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f600::,2607:f600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f608::,2607:f608:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f610::,2607:f610:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f618::,2607:f618:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f620::,2607:f620:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f628::,2607:f628:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f630::,2607:f630:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f638::,2607:f638:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f640::,2607:f640:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f648::,2607:f648:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f650::,2607:f650:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f658::,2607:f658:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f660::,2607:f660:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f668::,2607:f668:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f670::,2607:f670:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f678::,2607:f678:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f680::,2607:f680:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f688::,2607:f688:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f690::,2607:f690:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f698::,2607:f698:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f6a0::,2607:f6a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6a8::,2607:f6a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6b0::,2607:f6b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6b8::,2607:f6b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6c0::,2607:f6c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f6c8::,2607:f6c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6d0::,2607:f6d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6d8::,2607:f6d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6e0::,2607:f6e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6e8::,2607:f6e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6f0::,2607:f6f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6f8::,2607:f6f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f700::,2607:f700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f708::,2607:f708:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f710::,2607:f710:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f718::,2607:f718:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f720::,2607:f720:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f728::,2607:f728:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f730::,2607:f730:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f738::,2607:f738:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f740::,2607:f740:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f748::,2607:f748:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f750::,2607:f750:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f758::,2607:f758:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f760::,2607:f760:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f768::,2607:f768:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f770::,2607:f770:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f778::,2607:f778:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f788::,2607:f788:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f790::,2607:f790:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f798::,2607:f798:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f7a0::,2607:f7a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7a8::,2607:f7a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7b0::,2607:f7b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7b8::,2607:f7b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7c0::,2607:f7c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7c8::,2607:f7c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7d0::,2607:f7d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7d8::,2607:f7d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7e0::,2607:f7e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7e8::,2607:f7e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7f0::,2607:f7f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7f8::,2607:f7f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f800::,2607:f800:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f808::,2607:f808:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f810::,2607:f810:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f818::,2607:f818:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f820::,2607:f820:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f828::,2607:f828:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f830::,2607:f830:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f838::,2607:f838:ffff:ffff:ffff:ffff:ffff:ffff,VI
+2607:f848::,2607:f848:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f850::,2607:f850:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f858::,2607:f858:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f860::,2607:f860:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f868::,2607:f868:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f870::,2607:f870:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2607:f878::,2607:f878:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f880::,2607:f880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f888::,2607:f888:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f890::,2607:f890:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f898::,2607:f898:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8a0::,2607:f8a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8a8::,2607:f8a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8b0::,2607:f8b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8b8::,2607:f8b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8c0::,2607:f8c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8c8::,2607:f8c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8d0::,2607:f8d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8d8::,2607:f8d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8e0::,2607:f8e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8e8::,2607:f8e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8f0::,2607:f8f0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f8f8::,2607:f8f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f900::,2607:f900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f908::,2607:f908:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f910::,2607:f910:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f920::,2607:f920:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f928::,2607:f928:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f930::,2607:f930:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f938::,2607:f938:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f940::,2607:f940:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f948::,2607:f948:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f950::,2607:f950:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f958::,2607:f958:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f960::,2607:f960:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f968::,2607:f968:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f978::,2607:f978:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f980::,2607:f980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f990::,2607:f990:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f998::,2607:f998:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9a0::,2607:f9a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9a8::,2607:f9a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9b0::,2607:f9b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9b8::,2607:f9b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9c0::,2607:f9c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9c8::,2607:f9c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9d0::,2607:f9d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9d8::,2607:f9d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9e0::,2607:f9e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9f0::,2607:f9f1:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9f8::,2607:f9f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa00::,2607:fa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa08::,2607:fa08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa10::,2607:fa10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa18::,2607:fa18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa20::,2607:fa20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa28::,2607:fa28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa38::,2607:fa38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa40::,2607:fa40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa48::,2607:fa48:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fa58::,2607:fa58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa60::,2607:fa60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa68::,2607:fa68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa70::,2607:fa70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa78::,2607:fa78:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa80::,2607:fa80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa88::,2607:fa88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa90::,2607:fa90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa98::,2607:fa98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:faa0::,2607:faa0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:faa8::,2607:faa8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fab0::,2607:fab0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fab8::,2607:fab8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fac0::,2607:fac0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fac8::,2607:fac8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fad0::,2607:fad0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fad8::,2607:fad8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fae0::,2607:fae0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fae8::,2607:fae8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:faf0::,2607:faf0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:faf8::,2607:faf8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb00::,2607:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb08::,2607:fb08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb10::,2607:fb10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb18::,2607:fb18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb20::,2607:fb20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb28::,2607:fb28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb30::,2607:fb30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb38::,2607:fb38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb40::,2607:fb40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb48::,2607:fb48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb50::,2607:fb50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb58::,2607:fb58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb60::,2607:fb60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb68::,2607:fb68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb70::,2607:fb70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb78::,2607:fb78:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb80::,2607:fb80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb88::,2607:fb88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb90::,2607:fb90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb98::,2607:fb98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fba0::,2607:fba0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fba8::,2607:fba8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbb0::,2607:fbb0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbb8::,2607:fbb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbc0::,2607:fbc0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbc8::,2607:fbc8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbd0::,2607:fbd0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbd8::,2607:fbd8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fbe0::,2607:fbe0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbe8::,2607:fbe8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbf0::,2607:fbf0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbf8::,2607:fbf8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc00::,2607:fc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc08::,2607:fc08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc10::,2607:fc10:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fc18::,2607:fc18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc20::,2607:fc20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc28::,2607:fc28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc30::,2607:fc30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc38::,2607:fc38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc40::,2607:fc40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc48::,2607:fc48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc50::,2607:fc50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc58::,2607:fc58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc60::,2607:fc60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc68::,2607:fc68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc70::,2607:fc70:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fc78::,2607:fc78:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fc80::,2607:fc80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc88::,2607:fc88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc90::,2607:fc90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc98::,2607:fc98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fca0::,2607:fca0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fca8::,2607:fca8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcb8::,2607:fcb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcc0::,2607:fcc0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fcc8::,2607:fcc8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcd0::,2607:fcd0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcd8::,2607:fcd8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fce0::,2607:fce0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fce8::,2607:fce8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcf0::,2607:fcf0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcf8::,2607:fcf8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fd00::,2607:fd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd08::,2607:fd08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd10::,2607:fd10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd18::,2607:fd18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd20::,2607:fd20:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fd28::,2607:fd28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd30::,2607:fd30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd38::,2607:fd38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd40::,2607:fd40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd48::,2607:fd48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd50::,2607:fd50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd60::,2607:fd60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd68::,2607:fd68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd70::,2607:fd70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd78::,2607:fd78:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fd80::,2607:fd80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd88::,2607:fd88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd90::,2607:fd90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd98::,2607:fd98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fda0::,2607:fda0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fda8::,2607:fda8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdb0::,2607:fdb0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdb8::,2607:fdb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdc0::,2607:fdc0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdc8::,2607:fdc8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdd0::,2607:fdd0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdd8::,2607:fdd8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fde0::,2607:fde0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fde8::,2607:fde8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdf0::,2607:fdf0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdf8::,2607:fdf8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe00::,2607:fe00:ffff:ffff:ffff:ffff:ffff:ffff,JM
+2607:fe08::,2607:fe08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe10::,2607:fe10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe18::,2607:fe18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe20::,2607:fe20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe28::,2607:fe28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe30::,2607:fe30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe38::,2607:fe38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe40::,2607:fe40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe48::,2607:fe48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe50::,2607:fe50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe58::,2607:fe58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe60::,2607:fe60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe68::,2607:fe68:ffff:ffff:ffff:ffff:ffff:ffff,BS
+2607:fe70::,2607:fe70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe78::,2607:fe78:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe80::,2607:fe80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe88::,2607:fe88:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fe90::,2607:fe90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe98::,2607:fe98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fea0::,2607:fea0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fea8::,2607:fea8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:feb0::,2607:feb0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:feb8::,2607:feb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fec0::,2607:fec0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fec8::,2607:fec8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fed0::,2607:fed0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fed8::,2607:fed8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fee0::,2607:fee0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fee8::,2607:fee8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fef8::,2607:fef8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff00::,2607:ff00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff08::,2607:ff08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff10::,2607:ff10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff18::,2607:ff18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff28::,2607:ff28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff30::,2607:ff30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff38::,2607:ff38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff40::,2607:ff40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff48::,2607:ff48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff50::,2607:ff50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff58::,2607:ff58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff60::,2607:ff60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff68::,2607:ff68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff70::,2607:ff70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff78::,2607:ff78:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ff80::,2607:ff80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff90::,2607:ff90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffa0::,2607:ffa0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffa8::,2607:ffa8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffb0::,2607:ffb0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ffb8::,2607:ffb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffc0::,2607:ffc0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ffc8::,2607:ffc8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffd0::,2607:ffd0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffd8::,2607:ffd8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffe0::,2607:ffe0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ffe8::,2607:ffe8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fff0::,2607:fff0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fff8::,2607:fff8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2608::,2608:3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2608:4000::,2608:43ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2608:8000::,2608:83ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2608:c000::,2608:c3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609::,2609:3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:4000::,2609:43ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:8000::,2609:83ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:a000::,2609:a3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:c000::,2609:c3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:e000::,2609:e3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+260c:d000::,260c:d3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+260c:f000::,260c:f3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+260f:d000::,260f:d3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+260f:f000::,260f:f3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610::,2610:0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:8::,2610:8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:10::,2610:10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:18::,2610:18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:20::,2610:20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:28::,2610:28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:30::,2610:30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:38::,2610:38:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:40::,2610:40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:48::,2610:48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:50::,2610:50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:58::,2610:58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:60::,2610:60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:68::,2610:68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:78::,2610:78:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:80::,2610:88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:90::,2610:90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:98::,2610:98:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:a0::,2610:a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:b0::,2610:b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:b8::,2610:b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:c0::,2610:c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:c8::,2610:c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:d0::,2610:d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:d8::,2610:d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:e0::,2610:e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:e8::,2610:e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:f0::,2610:f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:f8::,2610:f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:100::,2610:100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:108::,2610:108:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:110::,2610:110:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:120::,2610:120:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:128::,2610:128:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:130::,2610:130:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:140::,2610:140:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:148::,2610:148:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:150::,2610:150:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:158::,2610:158:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:160::,2610:160:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:168::,2610:168:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:170::,2610:170:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:178::,2610:178:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:180::,2610:180:ffff:ffff:ffff:ffff:ffff:ffff,BS
+2610:188::,2610:188:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:190::,2610:190:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:198::,2610:198:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1a0::,2610:1a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1a8::,2610:1a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1b0::,2610:1b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1c0::,2610:1c2:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1c8::,2610:1c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1d0::,2610:1d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1d8::,2610:1d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1e0::,2610:1e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1e8::,2610:1e8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:1f0::,2610:1f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1f8::,2610:1f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620::,2620::ffff:ffff:ffff:ffff:ffff,US
+2620:0:10::,2620:0:10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:20::,2620:0:20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:30::,2620:0:37:ffff:ffff:ffff:ffff:ffff,US
+2620:0:40::,2620:0:40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:60::,2620:0:60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:70::,2620:0:70:ffff:ffff:ffff:ffff:ffff,US
+2620:0:80::,2620:0:80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:90::,2620:0:90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:a0::,2620:0:a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b0::,2620:0:b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c0::,2620:0:c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:f0::,2620:0:f0:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:100::,2620:0:100:ffff:ffff:ffff:ffff:ffff,US
+2620:0:110::,2620:0:110:ffff:ffff:ffff:ffff:ffff,US
+2620:0:120::,2620:0:120:ffff:ffff:ffff:ffff:ffff,US
+2620:0:140::,2620:0:140:ffff:ffff:ffff:ffff:ffff,US
+2620:0:150::,2620:0:150:ffff:ffff:ffff:ffff:ffff,US
+2620:0:160::,2620:0:160:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:170::,2620:0:170:ffff:ffff:ffff:ffff:ffff,US
+2620:0:180::,2620:0:180:ffff:ffff:ffff:ffff:ffff,US
+2620:0:190::,2620:0:190:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a0::,2620:0:1a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1b0::,2620:0:1b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1c0::,2620:0:1c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1d0::,2620:0:1d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1f0::,2620:0:1f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:200::,2620:0:200:ffff:ffff:ffff:ffff:ffff,US
+2620:0:210::,2620:0:210:ffff:ffff:ffff:ffff:ffff,US
+2620:0:220::,2620:0:220:ffff:ffff:ffff:ffff:ffff,US
+2620:0:230::,2620:0:230:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:240::,2620:0:240:ffff:ffff:ffff:ffff:ffff,US
+2620:0:250::,2620:0:250:ffff:ffff:ffff:ffff:ffff,US
+2620:0:260::,2620:0:260:ffff:ffff:ffff:ffff:ffff,US
+2620:0:270::,2620:0:270:ffff:ffff:ffff:ffff:ffff,US
+2620:0:280::,2620:0:280:ffff:ffff:ffff:ffff:ffff,US
+2620:0:290::,2620:0:290:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b0::,2620:0:2b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2c0::,2620:0:2c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2d0::,2620:0:2d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2f0::,2620:0:2f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:300::,2620:0:300:ffff:ffff:ffff:ffff:ffff,US
+2620:0:310::,2620:0:310:ffff:ffff:ffff:ffff:ffff,US
+2620:0:320::,2620:0:320:ffff:ffff:ffff:ffff:ffff,US
+2620:0:340::,2620:0:340:ffff:ffff:ffff:ffff:ffff,US
+2620:0:350::,2620:0:353:ffff:ffff:ffff:ffff:ffff,US
+2620:0:360::,2620:0:361:ffff:ffff:ffff:ffff:ffff,US
+2620:0:370::,2620:0:370:ffff:ffff:ffff:ffff:ffff,US
+2620:0:380::,2620:0:380:ffff:ffff:ffff:ffff:ffff,US
+2620:0:390::,2620:0:390:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3a0::,2620:0:3a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3b0::,2620:0:3b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3c0::,2620:0:3c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3d0::,2620:0:3d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3e0::,2620:0:3e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3f0::,2620:0:3f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:400::,2620:0:57f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:600::,2620:0:600:ffff:ffff:ffff:ffff:ffff,US
+2620:0:610::,2620:0:610:ffff:ffff:ffff:ffff:ffff,US
+2620:0:630::,2620:0:630:ffff:ffff:ffff:ffff:ffff,US
+2620:0:640::,2620:0:640:ffff:ffff:ffff:ffff:ffff,US
+2620:0:650::,2620:0:650:ffff:ffff:ffff:ffff:ffff,US
+2620:0:660::,2620:0:660:ffff:ffff:ffff:ffff:ffff,US
+2620:0:670::,2620:0:671:ffff:ffff:ffff:ffff:ffff,US
+2620:0:680::,2620:0:680:ffff:ffff:ffff:ffff:ffff,US
+2620:0:690::,2620:0:691:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6a0::,2620:0:6a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6b0::,2620:0:6b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6c0::,2620:0:6c7:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6d0::,2620:0:6d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6e0::,2620:0:6e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6f0::,2620:0:6f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:700::,2620:0:77f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:800::,2620:0:802:ffff:ffff:ffff:ffff:ffff,US
+2620:0:810::,2620:0:810:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:820::,2620:0:820:ffff:ffff:ffff:ffff:ffff,US
+2620:0:840::,2620:0:840:ffff:ffff:ffff:ffff:ffff,US
+2620:0:850::,2620:0:850:ffff:ffff:ffff:ffff:ffff,US
+2620:0:860::,2620:0:863:ffff:ffff:ffff:ffff:ffff,US
+2620:0:870::,2620:0:877:ffff:ffff:ffff:ffff:ffff,US
+2620:0:880::,2620:0:880:ffff:ffff:ffff:ffff:ffff,US
+2620:0:890::,2620:0:890:ffff:ffff:ffff:ffff:ffff,US
+2620:0:8a0::,2620:0:8a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:8d0::,2620:0:8d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:8e0::,2620:0:8e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:8f0::,2620:0:8f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:900::,2620:0:900:ffff:ffff:ffff:ffff:ffff,US
+2620:0:910::,2620:0:910:ffff:ffff:ffff:ffff:ffff,US
+2620:0:920::,2620:0:920:ffff:ffff:ffff:ffff:ffff,US
+2620:0:930::,2620:0:930:ffff:ffff:ffff:ffff:ffff,US
+2620:0:940::,2620:0:940:ffff:ffff:ffff:ffff:ffff,US
+2620:0:950::,2620:0:950:ffff:ffff:ffff:ffff:ffff,US
+2620:0:960::,2620:0:960:ffff:ffff:ffff:ffff:ffff,US
+2620:0:970::,2620:0:970:ffff:ffff:ffff:ffff:ffff,US
+2620:0:980::,2620:0:980:ffff:ffff:ffff:ffff:ffff,US
+2620:0:990::,2620:0:990:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9a0::,2620:0:9a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9b0::,2620:0:9b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9c0::,2620:0:9c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9e0::,2620:0:9e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9f0::,2620:0:9f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:a00::,2620:0:a1f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b00::,2620:0:b00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b10::,2620:0:b13:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b20::,2620:0:b20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b30::,2620:0:b30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b40::,2620:0:b40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b50::,2620:0:b50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b60::,2620:0:b61:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b80::,2620:0:b80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b90::,2620:0:b90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ba0::,2620:0:ba0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:bb0::,2620:0:bb0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:bc0::,2620:0:bc0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:bd0::,2620:0:bd0:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:be0::,2620:0:be0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:bf0::,2620:0:bf0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c10::,2620:0:c10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c20::,2620:0:c20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c30::,2620:0:c30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c40::,2620:0:c40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c60::,2620:0:c60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c70::,2620:0:c70:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c80::,2620:0:c80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c90::,2620:0:c90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ca0::,2620:0:ca0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:cb0::,2620:0:cb0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:cc0::,2620:0:ccf:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ce0::,2620:0:ce0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:cf0::,2620:0:cf0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d00::,2620:0:d00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d20::,2620:0:d20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d30::,2620:0:d30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d50::,2620:0:d50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d60::,2620:0:d63:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d70::,2620:0:d77:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d80::,2620:0:d80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d90::,2620:0:d90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:dc0::,2620:0:dc0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:dd0::,2620:0:dd0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:de0::,2620:0:de0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:df0::,2620:0:df0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e00::,2620:0:e00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e10::,2620:0:e10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e20::,2620:0:e23:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e30::,2620:0:e30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e40::,2620:0:e40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e50::,2620:0:e50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e60::,2620:0:e60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e80::,2620:0:e80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e90::,2620:0:e90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ea0::,2620:0:eb0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ed0::,2620:0:ed0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ee0::,2620:0:ee0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ef0::,2620:0:ef0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:f00::,2620:0:f7f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1000::,2620:0:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1400::,2620:0:143f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1500::,2620:0:157f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1600::,2620:0:167f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1700::,2620:0:170f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1800::,2620:0:181f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a00::,2620:0:1a00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a10::,2620:0:1a10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a20::,2620:0:1a20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a30::,2620:0:1a30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a40::,2620:0:1a40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a50::,2620:0:1a50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a60::,2620:0:1a60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a70::,2620:0:1a70:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a80::,2620:0:1a80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1aa0::,2620:0:1aa0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1ab0::,2620:0:1ab0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1ac0::,2620:0:1ac0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1ad0::,2620:0:1ad7:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1ae0::,2620:0:1ae0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1af0::,2620:0:1af0:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:1b00::,2620:0:1b07:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1c00::,2620:0:1cff:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2000::,2620:0:203f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2100::,2620:0:213f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2210::,2620:0:2210:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2220::,2620:0:2220:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:2240::,2620:0:2240:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2250::,2620:0:2250:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2260::,2620:0:2260:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2270::,2620:0:2270:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2280::,2620:0:2280:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2290::,2620:0:2290:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22a0::,2620:0:22a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22b0::,2620:0:22b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22c0::,2620:0:22c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22d0::,2620:0:22d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22e0::,2620:0:22e0:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:22f0::,2620:0:22f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2300::,2620:0:230f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2400::,2620:0:24ff:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2800::,2620:0:2800:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2810::,2620:0:2810:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2820::,2620:0:2820:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2830::,2620:0:2830:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2840::,2620:0:2840:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2850::,2620:0:2850:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2860::,2620:0:2860:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2870::,2620:0:2870:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2880::,2620:0:2880:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28a0::,2620:0:28a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28b0::,2620:0:28b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28c0::,2620:0:28c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28d0::,2620:0:28d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28f0::,2620:0:28f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2900::,2620:0:290f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2a00::,2620:0:2a1f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b00::,2620:0:2b00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b10::,2620:0:2b10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b20::,2620:0:2b20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b30::,2620:0:2b30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b40::,2620:0:2b40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b50::,2620:0:2b50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b60::,2620:0:2b60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b70::,2620:0:2b70:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b80::,2620:0:2b8f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2bc0::,2620:0:2bc3:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2bd0::,2620:0:2bd0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2be0::,2620:0:2be0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2bf0::,2620:0:2bf0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2d00::,2620:0:2d7f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e00::,2620:0:2e00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e10::,2620:0:2e10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e30::,2620:0:2e30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e40::,2620:0:2e40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e50::,2620:0:2e50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e60::,2620:0:2e60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e70::,2620:0:2e80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2ea0::,2620:0:2ea0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2eb0::,2620:0:2eb0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2ed0::,2620:0:2ed0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2ee0::,2620:0:2ee0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2f00::,2620:0:2f7f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3000::,2620:0:31ff:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5000::,2620:0:5000:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5010::,2620:0:5010:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5030::,2620:0:5030:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5040::,2620:0:5040:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5050::,2620:0:5050:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5060::,2620:0:5060:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:5070::,2620:0:5070:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5080::,2620:0:5080:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5090::,2620:0:5090:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50a0::,2620:0:50a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50b0::,2620:0:50b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50c0::,2620:0:50c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50d0::,2620:0:50d1:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50e0::,2620:0:50e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50f0::,2620:0:50f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5100::,2620:0:510f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5200::,2620:0:5200:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5300::,2620:0:530f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:aa00::,2620:0:aa00:ffff:ffff:ffff:ffff:ffff,US
+2620:1::,2620:1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1:4000::,2620:1:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:1:8000::,2620:1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1:c000::,2620:1:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:2::,2620:2:0:ffff:ffff:ffff:ffff:ffff,US
+2620:2:4000::,2620:2:4000:ffff:ffff:ffff:ffff:ffff,CA
+2620:2:8000::,2620:2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2:c000::,2620:2:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:3::,2620:3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3:4000::,2620:3:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:3:8000::,2620:3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3:c000::,2620:3:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:4::,2620:4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4:4000::,2620:4:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:4:8000::,2620:4:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4:c000::,2620:4:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:5::,2620:5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5:4000::,2620:5:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:5:8000::,2620:5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5:c000::,2620:5:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:6::,2620:6:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:6:4000::,2620:6:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:6:8000::,2620:6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6:c000::,2620:6:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:7::,2620:7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:7:4000::,2620:7:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:7:8000::,2620:7:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7:c000::,2620:7:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:8::,2620:8:7f:ffff:ffff:ffff:ffff:ffff,CA
+2620:8:8200::,2620:8:8200:ffff:ffff:ffff:ffff:ffff,US
+2620:9::,2620:9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9:4000::,2620:9:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:9:8000::,2620:9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9:c000::,2620:9:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:a::,2620:a:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:a:4000::,2620:a:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:a:8000::,2620:a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a:c000::,2620:a:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:b::,2620:b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b:4000::,2620:b:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:b:8000::,2620:b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b:c000::,2620:b:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:c::,2620:c:3:ffff:ffff:ffff:ffff:ffff,US
+2620:c:8000::,2620:c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d:8000::,2620:d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e::,2620:e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e:8000::,2620:e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f::,2620:f:3:ffff:ffff:ffff:ffff:ffff,US
+2620:f:8000::,2620:f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:10::,2620:10:0:ffff:ffff:ffff:ffff:ffff,US
+2620:10:8000::,2620:10:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:11::,2620:11:0:ffff:ffff:ffff:ffff:ffff,US
+2620:11:8000::,2620:11:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:12::,2620:12:0:ffff:ffff:ffff:ffff:ffff,US
+2620:12:8000::,2620:12:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:13::,2620:13:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:13:8000::,2620:13:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:14::,2620:14:0:ffff:ffff:ffff:ffff:ffff,US
+2620:14:8000::,2620:14:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:15::,2620:15:0:ffff:ffff:ffff:ffff:ffff,US
+2620:15:8000::,2620:15:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:16::,2620:16:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:16:8000::,2620:16:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:17::,2620:17:0:ffff:ffff:ffff:ffff:ffff,US
+2620:17:8000::,2620:17:8001:ffff:ffff:ffff:ffff:ffff,US
+2620:18::,2620:18:0:ffff:ffff:ffff:ffff:ffff,US
+2620:18:8000::,2620:18:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:19::,2620:19:0:ffff:ffff:ffff:ffff:ffff,US
+2620:19:8000::,2620:19:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1a::,2620:1a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1a:8000::,2620:1a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1b::,2620:1b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1b:8000::,2620:1b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1c::,2620:1c:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1c:8000::,2620:1c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1d::,2620:1d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1d:8000::,2620:1d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1e::,2620:1e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1e:8000::,2620:1e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1f::,2620:1f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1f:8000::,2620:1f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:20::,2620:20:0:ffff:ffff:ffff:ffff:ffff,US
+2620:20:8000::,2620:20:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:21::,2620:21:0:ffff:ffff:ffff:ffff:ffff,US
+2620:21:8000::,2620:21:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:22::,2620:22:0:ffff:ffff:ffff:ffff:ffff,US
+2620:22:8000::,2620:22:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:23::,2620:23:0:ffff:ffff:ffff:ffff:ffff,US
+2620:23:8000::,2620:23:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:24::,2620:24:1f:ffff:ffff:ffff:ffff:ffff,US
+2620:24:8080::,2620:24:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:25::,2620:25:0:ffff:ffff:ffff:ffff:ffff,US
+2620:25:8000::,2620:25:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:26::,2620:26:0:ffff:ffff:ffff:ffff:ffff,US
+2620:26:8000::,2620:26:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:27::,2620:27:f:ffff:ffff:ffff:ffff:ffff,US
+2620:27:8080::,2620:27:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:28::,2620:28:0:ffff:ffff:ffff:ffff:ffff,US
+2620:28:8000::,2620:28:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:29::,2620:29:0:ffff:ffff:ffff:ffff:ffff,US
+2620:29:8000::,2620:29:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2a::,2620:2a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:2a:8000::,2620:2a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2b::,2620:2b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:2b:8000::,2620:2b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2c::,2620:2c:f:ffff:ffff:ffff:ffff:ffff,US
+2620:2c:8080::,2620:2c:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:2d::,2620:2d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:2d:8000::,2620:2d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2e::,2620:2e:3f:ffff:ffff:ffff:ffff:ffff,US
+2620:2e:8080::,2620:2e:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:2f::,2620:2f:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:2f:8000::,2620:2f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:30::,2620:30:0:ffff:ffff:ffff:ffff:ffff,US
+2620:30:8000::,2620:30:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:31::,2620:31:0:ffff:ffff:ffff:ffff:ffff,US
+2620:31:8000::,2620:31:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:32::,2620:32:0:ffff:ffff:ffff:ffff:ffff,US
+2620:32:8000::,2620:32:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:33::,2620:33:0:ffff:ffff:ffff:ffff:ffff,US
+2620:33:8000::,2620:33:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:34::,2620:34:0:ffff:ffff:ffff:ffff:ffff,US
+2620:34:8000::,2620:34:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:35::,2620:35:0:ffff:ffff:ffff:ffff:ffff,US
+2620:35:8000::,2620:35:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:36::,2620:36:0:ffff:ffff:ffff:ffff:ffff,US
+2620:36:8000::,2620:36:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:37::,2620:37:0:ffff:ffff:ffff:ffff:ffff,US
+2620:37:8000::,2620:37:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:38::,2620:38:0:ffff:ffff:ffff:ffff:ffff,US
+2620:38:8000::,2620:38:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:39::,2620:39:0:ffff:ffff:ffff:ffff:ffff,US
+2620:39:8000::,2620:39:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3a::,2620:3a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3a:8000::,2620:3a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3b::,2620:3b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3b:8000::,2620:3b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3c::,2620:3c:3f:ffff:ffff:ffff:ffff:ffff,US
+2620:3c:8080::,2620:3c:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:3d::,2620:3d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3d:8000::,2620:3d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3e::,2620:3e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3e:8000::,2620:3e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3f::,2620:3f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3f:8000::,2620:3f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:40::,2620:40:0:ffff:ffff:ffff:ffff:ffff,US
+2620:40:8000::,2620:40:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:41::,2620:41:0:ffff:ffff:ffff:ffff:ffff,US
+2620:41:8000::,2620:41:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:42::,2620:42:0:ffff:ffff:ffff:ffff:ffff,US
+2620:42:8000::,2620:42:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:43::,2620:43:0:ffff:ffff:ffff:ffff:ffff,US
+2620:43:8000::,2620:43:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:44::,2620:44:1:ffff:ffff:ffff:ffff:ffff,US
+2620:44:8000::,2620:44:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:45::,2620:45:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:45:8000::,2620:45:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:46::,2620:46:0:ffff:ffff:ffff:ffff:ffff,US
+2620:46:8000::,2620:46:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:47::,2620:47:0:ffff:ffff:ffff:ffff:ffff,US
+2620:47:8000::,2620:47:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:48::,2620:48:0:ffff:ffff:ffff:ffff:ffff,US
+2620:48:8000::,2620:48:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:49::,2620:49:f:ffff:ffff:ffff:ffff:ffff,CA
+2620:49:8080::,2620:49:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:4a::,2620:4a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4a:8000::,2620:4a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4b::,2620:4b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4b:8000::,2620:4b:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:4c::,2620:4c:1:ffff:ffff:ffff:ffff:ffff,US
+2620:4c:8000::,2620:4c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4d::,2620:4d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4d:8000::,2620:4d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4e::,2620:4e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4e:8000::,2620:4e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4f::,2620:4f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4f:8000::,2620:4f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:50::,2620:50:f:ffff:ffff:ffff:ffff:ffff,US
+2620:50:8080::,2620:50:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:51::,2620:51:0:ffff:ffff:ffff:ffff:ffff,US
+2620:51:8000::,2620:51:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:52::,2620:52:3:ffff:ffff:ffff:ffff:ffff,US
+2620:52:8000::,2620:52:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:53::,2620:53:0:ffff:ffff:ffff:ffff:ffff,US
+2620:53:8000::,2620:53:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:54::,2620:54:0:ffff:ffff:ffff:ffff:ffff,US
+2620:54:8000::,2620:54:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:55::,2620:55:0:ffff:ffff:ffff:ffff:ffff,US
+2620:55:8000::,2620:55:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:56::,2620:56:0:ffff:ffff:ffff:ffff:ffff,US
+2620:56:8000::,2620:56:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:57::,2620:57:0:ffff:ffff:ffff:ffff:ffff,US
+2620:57:8000::,2620:57:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:58::,2620:58:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:59::,2620:59:0:ffff:ffff:ffff:ffff:ffff,US
+2620:59:8000::,2620:59:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5a::,2620:5a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5a:8000::,2620:5a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5b::,2620:5b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5b:8000::,2620:5b:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:5c::,2620:5c:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5c:8000::,2620:5c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5d::,2620:5d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5d:8000::,2620:5d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5e::,2620:5e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5e:8000::,2620:5e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5f::,2620:5f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5f:8000::,2620:5f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:60::,2620:60:0:ffff:ffff:ffff:ffff:ffff,US
+2620:60:8000::,2620:60:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:61::,2620:61:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:61:8000::,2620:61:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:62::,2620:62:0:ffff:ffff:ffff:ffff:ffff,US
+2620:62:8000::,2620:62:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:63::,2620:63:0:ffff:ffff:ffff:ffff:ffff,US
+2620:63:8000::,2620:63:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:64::,2620:64:0:ffff:ffff:ffff:ffff:ffff,US
+2620:64:8000::,2620:64:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:65::,2620:65:0:ffff:ffff:ffff:ffff:ffff,US
+2620:65:8000::,2620:65:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:66::,2620:66:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:66:8000::,2620:66:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:67::,2620:67:0:ffff:ffff:ffff:ffff:ffff,US
+2620:68::,2620:68:0:ffff:ffff:ffff:ffff:ffff,US
+2620:68:8000::,2620:68:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:69::,2620:69:0:ffff:ffff:ffff:ffff:ffff,US
+2620:69:8000::,2620:69:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6a::,2620:6a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6a:8000::,2620:6a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6b::,2620:6b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6b:8000::,2620:6b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6c::,2620:6c:3f:ffff:ffff:ffff:ffff:ffff,US
+2620:6c:8080::,2620:6c:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:6d::,2620:6d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6d:8000::,2620:6d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6e::,2620:6e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6e:8000::,2620:6e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6f::,2620:6f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6f:8000::,2620:6f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:70::,2620:70:0:ffff:ffff:ffff:ffff:ffff,US
+2620:70:8000::,2620:70:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:71::,2620:71:0:ffff:ffff:ffff:ffff:ffff,US
+2620:71:8000::,2620:71:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:72::,2620:72:0:ffff:ffff:ffff:ffff:ffff,US
+2620:72:8000::,2620:72:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:73::,2620:73:0:ffff:ffff:ffff:ffff:ffff,US
+2620:73:8000::,2620:73:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:74::,2620:74:1f:ffff:ffff:ffff:ffff:ffff,US
+2620:74:8080::,2620:74:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:75::,2620:75:0:ffff:ffff:ffff:ffff:ffff,US
+2620:75:8000::,2620:75:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:76::,2620:76:0:ffff:ffff:ffff:ffff:ffff,US
+2620:76:8000::,2620:76:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:77::,2620:77:0:ffff:ffff:ffff:ffff:ffff,US
+2620:77:8000::,2620:77:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:78::,2620:78:0:ffff:ffff:ffff:ffff:ffff,US
+2620:78:8000::,2620:78:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:79::,2620:79:0:ffff:ffff:ffff:ffff:ffff,US
+2620:79:8000::,2620:79:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7a::,2620:7a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:7a:8000::,2620:7a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7b::,2620:7b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:7b:8000::,2620:7b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7b:e000::,2620:7b:e000:ffff:ffff:ffff:ffff:ffff,US
+2620:7c:4000::,2620:7c:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:7c:a000::,2620:7c:a000:ffff:ffff:ffff:ffff:ffff,US
+2620:7d::,2620:7d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:7d:8000::,2620:7d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7e::,2620:7e:f:ffff:ffff:ffff:ffff:ffff,US
+2620:7e:60c0::,2620:7e:60c0:ffff:ffff:ffff:ffff:ffff,US
+2620:7e:c080::,2620:7e:c080:ffff:ffff:ffff:ffff:ffff,US
+2620:7f:2040::,2620:7f:2040:ffff:ffff:ffff:ffff:ffff,US
+2620:7f:8000::,2620:7f:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:80::,2620:80:0:ffff:ffff:ffff:ffff:ffff,US
+2620:80:8000::,2620:80:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:81::,2620:81:0:ffff:ffff:ffff:ffff:ffff,US
+2620:81:8000::,2620:81:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:82::,2620:82:0:ffff:ffff:ffff:ffff:ffff,US
+2620:82:8000::,2620:82:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:83::,2620:83:0:ffff:ffff:ffff:ffff:ffff,US
+2620:83:8000::,2620:83:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:84::,2620:84:1:ffff:ffff:ffff:ffff:ffff,US
+2620:84:8000::,2620:84:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:85::,2620:85:0:ffff:ffff:ffff:ffff:ffff,US
+2620:85:8000::,2620:85:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:86::,2620:86:0:ffff:ffff:ffff:ffff:ffff,US
+2620:86:8000::,2620:86:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:87::,2620:87:0:ffff:ffff:ffff:ffff:ffff,US
+2620:87:8000::,2620:87:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:88::,2620:88:0:ffff:ffff:ffff:ffff:ffff,US
+2620:88:8000::,2620:88:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:89::,2620:89:0:ffff:ffff:ffff:ffff:ffff,US
+2620:89:8000::,2620:89:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8a::,2620:8a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8a:8000::,2620:8a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8b::,2620:8b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8b:8000::,2620:8b:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:8c::,2620:8c:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8c:8000::,2620:8c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8d::,2620:8d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8d:8000::,2620:8d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8e::,2620:8e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8e:8000::,2620:8e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8f::,2620:8f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8f:8000::,2620:8f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:90::,2620:90:0:ffff:ffff:ffff:ffff:ffff,US
+2620:90:8000::,2620:90:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:91::,2620:91:0:ffff:ffff:ffff:ffff:ffff,US
+2620:91:8000::,2620:91:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:92::,2620:92:0:ffff:ffff:ffff:ffff:ffff,US
+2620:92:8000::,2620:92:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:93::,2620:93:0:ffff:ffff:ffff:ffff:ffff,US
+2620:93:8000::,2620:93:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:94::,2620:94:0:ffff:ffff:ffff:ffff:ffff,US
+2620:94:8000::,2620:94:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:95::,2620:95:0:ffff:ffff:ffff:ffff:ffff,US
+2620:95:8000::,2620:95:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:96::,2620:96:0:ffff:ffff:ffff:ffff:ffff,US
+2620:96:8000::,2620:96:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:97::,2620:97:0:ffff:ffff:ffff:ffff:ffff,US
+2620:97:8000::,2620:97:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:98::,2620:98:0:ffff:ffff:ffff:ffff:ffff,US
+2620:98:8000::,2620:98:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:99::,2620:99:0:ffff:ffff:ffff:ffff:ffff,US
+2620:99:8000::,2620:99:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9a::,2620:9a:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:9a:8000::,2620:9a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9b::,2620:9b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9b:8000::,2620:9b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9c::,2620:9c:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9c:8000::,2620:9c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9d::,2620:9d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9d:8000::,2620:9d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9e::,2620:9e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9e:8000::,2620:9e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9f::,2620:9f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9f:8000::,2620:9f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a0::,2620:a0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a0:8000::,2620:a0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a1::,2620:a1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a1:8000::,2620:a1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a2::,2620:a2:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a2:8000::,2620:a2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a3::,2620:a3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a3:8000::,2620:a3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a4::,2620:a4:f:ffff:ffff:ffff:ffff:ffff,US
+2620:a4:8080::,2620:a4:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:a5::,2620:a5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a5:8000::,2620:a5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a6::,2620:a6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a6:8000::,2620:a6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a7::,2620:a7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a7:8000::,2620:a7:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a8::,2620:a8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a8:8000::,2620:a8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a9::,2620:a9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a9:8000::,2620:a9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:aa::,2620:aa:0:ffff:ffff:ffff:ffff:ffff,US
+2620:aa:8000::,2620:aa:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ab::,2620:ab:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ab:8000::,2620:ab:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ac::,2620:ac:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ac:8000::,2620:ac:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ad::,2620:ad:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ad:8000::,2620:ad:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ae::,2620:ae:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:ae:8000::,2620:ae:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:af::,2620:af:0:ffff:ffff:ffff:ffff:ffff,US
+2620:af:8000::,2620:af:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b0::,2620:b0:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:b0:8000::,2620:b0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b1::,2620:b1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b1:8000::,2620:b1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b2:8000::,2620:b2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b3::,2620:b3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b3:8000::,2620:b3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b4::,2620:b4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b4:8000::,2620:b4:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:b5::,2620:b5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b5:8000::,2620:b5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b6::,2620:b6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b6:8000::,2620:b6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b7::,2620:b7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b7:8000::,2620:b7:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:b8::,2620:b8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b8:8000::,2620:b8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b9::,2620:b9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b9:8000::,2620:b9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ba::,2620:ba:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ba:8000::,2620:ba:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:bb::,2620:bb:0:ffff:ffff:ffff:ffff:ffff,US
+2620:bb:8000::,2620:bb:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:bc::,2620:bc:0:ffff:ffff:ffff:ffff:ffff,US
+2620:bc:8000::,2620:bc:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:bd::,2620:bd:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:bd:8000::,2620:bd:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:be::,2620:be:0:ffff:ffff:ffff:ffff:ffff,US
+2620:be:8000::,2620:be:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:bf::,2620:bf:0:ffff:ffff:ffff:ffff:ffff,US
+2620:bf:8000::,2620:bf:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c0::,2620:c0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c0:8000::,2620:c0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c1::,2620:c1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c1:8000::,2620:c1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c2::,2620:c2:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:c2:8000::,2620:c2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c3::,2620:c3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c3:8000::,2620:c3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c4::,2620:c4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c4:8000::,2620:c4:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c5::,2620:c5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c5:8000::,2620:c5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c6::,2620:c6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c6:8000::,2620:c6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c7::,2620:c7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c7:8000::,2620:c7:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c8::,2620:c8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c8:8000::,2620:c8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c9::,2620:c9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c9:8000::,2620:c9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ca::,2620:ca:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ca:8000::,2620:ca:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:cb::,2620:cb:0:ffff:ffff:ffff:ffff:ffff,US
+2620:cb:8000::,2620:cb:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:cc::,2620:cc:0:ffff:ffff:ffff:ffff:ffff,US
+2620:cc:8000::,2620:cc:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:cd::,2620:cd:0:ffff:ffff:ffff:ffff:ffff,US
+2620:cd:8000::,2620:cd:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ce::,2620:ce:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ce:8000::,2620:ce:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:cf::,2620:cf:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d0::,2620:d0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d0:8000::,2620:d0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d1::,2620:d1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d1:8000::,2620:d1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d2::,2620:d2:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d2:8000::,2620:d2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d3::,2620:d3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d3:8000::,2620:d3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d4::,2620:d4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d5::,2620:d5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d5:8000::,2620:d5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d6::,2620:d6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d6:8000::,2620:d6:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:d7::,2620:d7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d8::,2620:d8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d8:8000::,2620:d8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d9::,2620:d9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:da::,2620:da:0:ffff:ffff:ffff:ffff:ffff,US
+2620:db::,2620:db:0:ffff:ffff:ffff:ffff:ffff,US
+2620:db:8000::,2620:db:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:dc::,2620:dc:0:ffff:ffff:ffff:ffff:ffff,US
+2620:dc:8::,2620:dc:8:ffff:ffff:ffff:ffff:ffff,US
+2620:dc:8000::,2620:dc:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:dd::,2620:dd:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:dd:8000::,2620:dd:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:de::,2620:de:0:ffff:ffff:ffff:ffff:ffff,US
+2620:de:8000::,2620:de:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:df::,2620:df:0:ffff:ffff:ffff:ffff:ffff,US
+2620:df:8000::,2620:df:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e0::,2620:e0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e0:8000::,2620:e0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e1::,2620:e1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e1:8000::,2620:e1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e2::,2620:e2:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e2:8000::,2620:e2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e3::,2620:e3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e3:8000::,2620:e3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e4::,2620:e4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e4:8000::,2620:e4:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e5::,2620:e5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e5:8000::,2620:e5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e6::,2620:e6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e6:8000::,2620:e6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e7::,2620:e7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e7:8000::,2620:e7:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:e8::,2620:e8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e8:8000::,2620:e8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e9::,2620:e9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e9:8000::,2620:e9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ea::,2620:ea:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ea:8000::,2620:ea:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:eb::,2620:eb:0:ffff:ffff:ffff:ffff:ffff,US
+2620:eb:8000::,2620:eb:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ec::,2620:ec:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ec:8000::,2620:ec:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ed::,2620:ed:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ed:8000::,2620:ed:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ee::,2620:ee:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ee:8000::,2620:ee:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ef::,2620:ef:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ef:8000::,2620:ef:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f0::,2620:f0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f0:8000::,2620:f0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f1::,2620:f1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f1:8000::,2620:f1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f2::,2620:f2:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:f2:8000::,2620:f2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f3::,2620:f3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f3:8000::,2620:f3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f4::,2620:f4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f4:8000::,2620:f4:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:f5::,2620:f5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f5:8000::,2620:f5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f6::,2620:f6:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:f6:8000::,2620:f6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f7::,2620:f7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f7:8000::,2620:f7:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f8::,2620:f8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f8:8000::,2620:f8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f9::,2620:f9:f:ffff:ffff:ffff:ffff:ffff,US
+2620:f9:8000::,2620:f9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:fa::,2620:fa:0:ffff:ffff:ffff:ffff:ffff,US
+2620:fa:8000::,2620:fa:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:fb::,2620:fb:0:ffff:ffff:ffff:ffff:ffff,US
+2620:fb:8000::,2620:fb:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:fc::,2620:fc:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:fc:8000::,2620:fc:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:fd::,2620:fd:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:fd:8000::,2620:fd:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:fe::,2620:fe:0:ffff:ffff:ffff:ffff:ffff,US
+2620:fe:8000::,2620:fe:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ff::,2620:ff:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ff:8000::,2620:ff:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:100::,2620:100:f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:1000::,2620:100:1001:ffff:ffff:ffff:ffff:ffff,US
+2620:100:3000::,2620:100:3007:ffff:ffff:ffff:ffff:ffff,US
+2620:100:4000::,2620:100:403f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:5000::,2620:100:5007:ffff:ffff:ffff:ffff:ffff,US
+2620:100:6000::,2620:100:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:7000::,2620:100:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:8000::,2620:100:8003:ffff:ffff:ffff:ffff:ffff,US
+2620:100:9000::,2620:100:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:a000::,2620:100:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:c000::,2620:100:c03f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:d000::,2620:100:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:e000::,2620:100:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:f000::,2620:100:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:101::,2620:101:3:ffff:ffff:ffff:ffff:ffff,US
+2620:101:1000::,2620:101:103f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:2000::,2620:101:201f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:3000::,2620:101:303f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:4000::,2620:101:403f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:5000::,2620:101:503f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:6000::,2620:101:6001:ffff:ffff:ffff:ffff:ffff,US
+2620:101:7000::,2620:101:7001:ffff:ffff:ffff:ffff:ffff,US
+2620:101:8000::,2620:101:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:9000::,2620:101:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:a000::,2620:101:a001:ffff:ffff:ffff:ffff:ffff,US
+2620:101:b000::,2620:101:b07f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:c000::,2620:101:c00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:101:d000::,2620:101:d007:ffff:ffff:ffff:ffff:ffff,US
+2620:101:e000::,2620:101:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:f000::,2620:101:f001:ffff:ffff:ffff:ffff:ffff,CA
+2620:102::,2620:102:f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:1000::,2620:102:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:2000::,2620:102:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:3000::,2620:102:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:4000::,2620:102:403f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:5000::,2620:102:501f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:6000::,2620:102:6003:ffff:ffff:ffff:ffff:ffff,US
+2620:102:7000::,2620:102:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:8000::,2620:102:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:9000::,2620:102:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:102:a000::,2620:102:a01f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:b000::,2620:102:b001:ffff:ffff:ffff:ffff:ffff,US
+2620:102:c000::,2620:102:c007:ffff:ffff:ffff:ffff:ffff,US
+2620:102:d000::,2620:102:d07f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:e000::,2620:102:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:f000::,2620:102:f003:ffff:ffff:ffff:ffff:ffff,US
+2620:103::,2620:103:7:ffff:ffff:ffff:ffff:ffff,US
+2620:103:1000::,2620:103:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:2000::,2620:103:200f:ffff:ffff:ffff:ffff:ffff,CA
+2620:103:3000::,2620:103:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:103:4000::,2620:103:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:5000::,2620:103:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:6000::,2620:103:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:7000::,2620:103:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:8000::,2620:103:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:103:9000::,2620:103:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:103:a000::,2620:103:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:b000::,2620:103:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:c000::,2620:103:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:d000::,2620:103:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:e000::,2620:103:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:103:f000::,2620:103:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:104::,2620:104:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:1000::,2620:104:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:2000::,2620:104:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:3000::,2620:104:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:4000::,2620:104:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:5000::,2620:104:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:6000::,2620:104:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:7000::,2620:104:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:8000::,2620:104:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:9000::,2620:104:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:a000::,2620:104:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:b000::,2620:104:b01f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:c000::,2620:104:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:d000::,2620:104:d0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:e000::,2620:104:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:f000::,2620:104:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:105::,2620:105:f:ffff:ffff:ffff:ffff:ffff,CA
+2620:105:1000::,2620:105:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:2000::,2620:105:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:3000::,2620:105:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:4000::,2620:105:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:5000::,2620:105:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:6000::,2620:105:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:7000::,2620:105:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:8000::,2620:105:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:9000::,2620:105:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:a000::,2620:105:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:b000::,2620:105:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:c000::,2620:105:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:d000::,2620:105:d0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:e000::,2620:105:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:f000::,2620:105:f0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106::,2620:106:f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:1000::,2620:106:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:2000::,2620:106:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:3000::,2620:106:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:4000::,2620:106:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:5000::,2620:106:50ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:6000::,2620:106:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:7000::,2620:106:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:8000::,2620:106:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:9000::,2620:106:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:a000::,2620:106:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:b000::,2620:106:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:c000::,2620:106:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:d000::,2620:106:d0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:e000::,2620:106:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:f000::,2620:106:f00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:107::,2620:107:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:1000::,2620:107:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:2000::,2620:107:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:3000::,2620:107:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:4000::,2620:107:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:5000::,2620:107:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:6000::,2620:107:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:7000::,2620:107:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:8000::,2620:107:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:9000::,2620:107:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:a000::,2620:107:a0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:b000::,2620:107:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:c000::,2620:107:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:d000::,2620:107:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:e000::,2620:107:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:f000::,2620:107:f0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108::,2620:108:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:1000::,2620:108:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:2000::,2620:108:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:3000::,2620:108:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:4000::,2620:108:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:5000::,2620:108:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:6000::,2620:108:60ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:7000::,2620:108:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:8000::,2620:108:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:9000::,2620:108:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:a000::,2620:108:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:b000::,2620:108:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:c000::,2620:108:c0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:d000::,2620:108:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:e000::,2620:108:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:f000::,2620:108:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109::,2620:109:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:1000::,2620:109:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:2000::,2620:109:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:3000::,2620:109:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:4000::,2620:109:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:5000::,2620:109:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:6000::,2620:109:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:7000::,2620:109:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:8000::,2620:109:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:9000::,2620:109:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:a000::,2620:109:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:b000::,2620:109:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:c000::,2620:109:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:d000::,2620:109:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:e000::,2620:109:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:f000::,2620:109:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a::,2620:10a:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:1000::,2620:10a:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:2000::,2620:10a:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:3000::,2620:10a:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:4000::,2620:10a:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:5000::,2620:10a:50ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:6000::,2620:10a:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:7000::,2620:10a:700f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10a:8000::,2620:10a:800f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10a:9000::,2620:10a:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:a000::,2620:10a:a0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:b000::,2620:10a:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:c000::,2620:10a:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:d000::,2620:10a:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:e000::,2620:10a:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:f000::,2620:10a:f0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b::,2620:10b:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:1000::,2620:10b:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:2000::,2620:10b:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:3000::,2620:10b:30ff:ffff:ffff:ffff:ffff:ffff,CA
+2620:10b:4000::,2620:10b:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:5000::,2620:10b:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:6000::,2620:10b:60ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:7000::,2620:10b:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:8000::,2620:10b:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:9000::,2620:10b:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:a000::,2620:10b:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:b000::,2620:10b:b00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10b:c000::,2620:10b:c0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:d000::,2620:10b:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:e000::,2620:10b:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:f000::,2620:10b:f0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c::,2620:10c:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:1000::,2620:10c:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:2000::,2620:10c:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:3000::,2620:10c:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:4000::,2620:10c:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:5000::,2620:10c:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:6000::,2620:10c:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:7000::,2620:10c:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:8000::,2620:10c:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:9000::,2620:10c:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:a000::,2620:10c:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:b000::,2620:10c:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:c000::,2620:10c:c0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:d000::,2620:10c:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:e000::,2620:10c:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:f000::,2620:10c:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d::,2620:10d:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:1000::,2620:10d:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:2000::,2620:10d:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:3000::,2620:10d:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:4000::,2620:10d:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:5000::,2620:10d:50ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:6000::,2620:10d:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:7000::,2620:10d:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:8000::,2620:10d:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:9000::,2620:10d:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:a000::,2620:10d:a0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:b000::,2620:10d:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:c000::,2620:10d:c0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:d000::,2620:10d:d00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10d:e000::,2620:10d:e00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10d:f000::,2620:10d:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e::,2620:10e:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:1000::,2620:10e:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:2000::,2620:10e:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:3000::,2620:10e:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:4000::,2620:10e:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:5000::,2620:10e:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:6000::,2620:10e:60ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:7000::,2620:10e:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:8000::,2620:10e:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:9000::,2620:10e:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:a000::,2620:10e:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:b000::,2620:10e:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:c000::,2620:10e:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:d000::,2620:10e:d00f:ffff:ffff:ffff:ffff:ffff,BL
+2620:10e:e000::,2620:10e:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:f000::,2620:10e:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f::,2620:10f:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:1000::,2620:10f:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:2000::,2620:10f:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:3000::,2620:10f:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:4000::,2620:10f:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:5000::,2620:10f:50ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:6000::,2620:10f:60ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:7000::,2620:10f:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:8000::,2620:10f:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:9000::,2620:10f:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:a000::,2620:10f:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:b000::,2620:10f:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:c000::,2620:10f:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:d000::,2620:10f:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:e000::,2620:10f:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:f000::,2620:10f:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110::,2620:110:f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:1000::,2620:110:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:2000::,2620:110:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:110:3000::,2620:110:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:110:4000::,2620:110:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:5000::,2620:110:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:6000::,2620:110:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:7000::,2620:110:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:8000::,2620:110:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:110:9000::,2620:110:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:a000::,2620:110:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:b000::,2620:110:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:c000::,2620:110:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:d000::,2620:110:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:e000::,2620:110:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:f000::,2620:110:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:140::,2620:140:3ff:ffff:ffff:ffff:ffff:ffff,US
+2620:141::,2620:141:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:143::,2620:143:7ff:ffff:ffff:ffff:ffff:ffff,US
+2620:144::,2620:145:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:146::,2620:146:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:147::,2620:147:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:148::,2620:148:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:149::,2620:149:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14a::,2620:14a:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14b::,2620:14b:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14c::,2620:14c:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14d::,2620:14d:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14e::,2620:14e:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14f::,2620:14f:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:150::,2620:150:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:151::,2620:151:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:152::,2620:152:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:153::,2620:153:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:154::,2620:154:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:155::,2620:155:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:156::,2620:156:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:157::,2620:157:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:158::,2620:158:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:159::,2620:159:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15a::,2620:15a:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15b::,2620:15b:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15c::,2620:15c:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15d::,2620:15e:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15f::,2620:15f:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:160::,2620:160:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:162::,2620:162:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:163::,2620:163:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:164::,2620:164:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:165::,2620:165:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:166::,2620:166:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:180::,2620:180:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:190::,2620:190:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1a0::,2620:1a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1b0::,2620:1b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1c0::,2620:1c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1d0::,2620:1d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1e0::,2620:1e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1f0::,2620:1f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2800:8::,2800:8:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:10::,2800:10:ffff:ffff:ffff:ffff:ffff:ffff,NI
+2800:18::,2800:18:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:20::,2800:2f:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:30::,2800:30:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:38::,2800:38:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:40::,2800:40:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:48::,2800:48:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:60::,2800:60:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:68::,2800:68:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:70::,2800:70:ffff:ffff:ffff:ffff:ffff:ffff,TT
+2800:78::,2800:78:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:80::,2800:80:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:88::,2800:88:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2800:90::,2800:90:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2800:98::,2800:98:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2800:a0::,2800:af:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2800:e0::,2800:ef:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:f0::,2800:f0:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:100::,2800:100:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:110::,2800:110:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:120::,2800:120:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:130::,2800:130:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:140::,2800:140:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:150::,2800:150:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:160::,2800:160:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:170::,2800:170:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2800:180::,2800:180:ffff:ffff:ffff:ffff:ffff:ffff,TT
+2800:190::,2800:190:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:1a0::,2800:1a0:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2800:1b0::,2800:1b0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:1c0::,2800:1c0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:1d0::,2800:1d0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:1e0::,2800:1e0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:1f0::,2800:1f0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:200::,2800:200:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:220::,2800:220:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:230::,2800:230:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2800:240::,2800:240:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:250::,2800:250:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2800:260::,2800:26f:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:270::,2800:270:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:280::,2800:280:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:290::,2800:290:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:2a0::,2800:2a0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:2b0::,2800:2b0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:2c0::,2800:2c0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:2d0::,2800:2d0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:2e0::,2800:2e0:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:2f0::,2800:2f0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:300::,2800:300:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:310::,2800:310:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:320::,2800:320:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2800:330::,2800:330:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:340::,2800:340:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:350::,2800:350:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:360::,2800:360:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2800:370::,2800:370:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:380::,2800:380:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:390::,2800:390:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2800:3a0::,2800:3a0:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2800:3b0::,2800:3b0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:3c0::,2800:3c0:ffff:ffff:ffff:ffff:ffff:ffff,GY
+2800:3d0::,2800:3d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:3e0::,2800:3e0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:3f0::,2800:3f0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:400::,2800:400:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:410::,2800:410:ffff:ffff:ffff:ffff:ffff:ffff,BZ
+2800:420::,2800:423:ffff:ffff:ffff:ffff:ffff:ffff,TT
+2800:430::,2800:430:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:440::,2800:440:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:450::,2800:450:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:460::,2800:460:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:470::,2800:470:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:480::,2800:480:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:490::,2800:490:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:4a0::,2800:4a0:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:4b0::,2800:4b0:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:4c0::,2800:4c0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:4d0::,2800:4d0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:4e0::,2800:4e0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:4f0::,2800:4f0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:500::,2800:500:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:510::,2800:510:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:520::,2800:520:ffff:ffff:ffff:ffff:ffff:ffff,TT
+2800:530::,2800:530:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:540::,2800:540:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:550::,2800:550:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:560::,2800:560:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:570::,2800:570:ffff:ffff:ffff:ffff:ffff:ffff,HT
+2800:580::,2800:580:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:590::,2800:590:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:5a0::,2800:5a0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:5b0::,2800:5b0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:5c0::,2800:5c0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:5d0::,2800:5d0:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:5e0::,2800:5e0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:5f0::,2800:5f0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:600::,2800:600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:610::,2800:610:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:620::,2800:620:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:630::,2800:630:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:640::,2800:640:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:650::,2800:650:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:660::,2800:660:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:670::,2800:670:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:680::,2800:680:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:690::,2800:690:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:6a0::,2800:6a0:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2800:6b0::,2800:6b0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:6c0::,2800:6c0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:6d0::,2800:6d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:6e0::,2800:6e0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:6f0::,2800:6f0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:700::,2800:700:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2800:800::,2800:800:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:810::,2800:810:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:820::,2800:820:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:830::,2800:831:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:840::,2800:840:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2800:850::,2800:850:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:860::,2800:860:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:870::,2800:870:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:880::,2800:883:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2800:890::,2800:890:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2800:8a0::,2800:8a0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:8b0::,2800:8b0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:8c0::,2800:8c0:ffff:ffff:ffff:ffff:ffff:ffff,NI
+2800:8d0::,2800:8d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:8e0::,2800:8e0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:8f0::,2800:8f0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:900::,2800:900:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:910::,2800:910:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2800:920::,2800:920:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:930::,2800:930:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:940::,2800:940:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:950::,2800:950:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:960::,2800:960:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2800:970::,2800:970:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:980::,2800:980:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:990::,2800:990:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:9a0::,2800:9a7:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:9b0::,2800:9b0:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:9c0::,2800:9c0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:9d0::,2800:9d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:9e0::,2800:9e0:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:9f0::,2800:9f0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:a00::,2800:a00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a10::,2800:a10:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a20::,2800:a20:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:a30::,2800:a30:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a40::,2800:a40:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a50::,2800:a50:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a60::,2800:a60:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:a70::,2800:a70:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:a80::,2800:a80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a90::,2800:a90:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:aa0::,2800:aa0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:ab0::,2800:ab0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:ac0::,2800:ac0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:ad0::,2800:ad0:ffff:ffff:ffff:ffff:ffff:ffff,AW
+2800:ae0::,2800:ae0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:af0::,2800:af0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:b00::,2800:b00:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:b10::,2800:b10:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2800:b20::,2800:b23:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2800:b30::,2800:b31:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:b40::,2800:b40:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:b50::,2800:b50:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:b60::,2800:b60:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:b70::,2800:b70:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:b80::,2800:b80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:b90::,2800:b90:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:ba0::,2800:ba0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:bb0::,2800:bb0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:bc0::,2800:bc0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2800:bd0::,2800:bd0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:be0::,2800:be0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:bf0::,2800:bf0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:c00::,2800:c00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:c10::,2800:c10:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:c20::,2800:c20:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:c30::,2800:c30:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:c40::,2800:c40:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:c50::,2800:c50:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:c60::,2800:c60:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:c70::,2800:c70:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2800:c80::,2800:c80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:c90::,2800:c90:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2800:ca0::,2800:ca0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:cb0::,2800:cb0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:cc0::,2800:cc0:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:cd0::,2800:cd0:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2800:ce0::,2800:ce0:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:cf0::,2800:cf0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:d00::,2800:d00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:d10::,2800:d10:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:d20::,2800:d20:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2800:1000::,2800:10ff:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:2000::,2800:2fff:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a000::,2800:a000:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a008::,2800:a008:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a010::,2800:a010:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a018::,2800:a018:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a020::,2800:a020:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a028::,2800:a028:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a030::,2800:a030:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a038::,2800:a038:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:b000::,2800:b000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:d300::,2800:d307:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2801::,2801::ffff:ffff:ffff:ffff:ffff,UY
+2801:0:10::,2801:0:10:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:20::,2801:0:20:ffff:ffff:ffff:ffff:ffff,EC
+2801:0:30::,2801:0:30:ffff:ffff:ffff:ffff:ffff,HN
+2801:0:40::,2801:0:40:ffff:ffff:ffff:ffff:ffff,TT
+2801:0:50::,2801:0:50:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:60::,2801:0:63:ffff:ffff:ffff:ffff:ffff,EC
+2801:0:70::,2801:0:70:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:80::,2801:0:80:ffff:ffff:ffff:ffff:ffff,DO
+2801:0:90::,2801:0:90:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:a0::,2801:0:a0:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:b0::,2801:0:b7:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:c0::,2801:0:df:ffff:ffff:ffff:ffff:ffff,CR
+2801:0:100::,2801:0:100:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:110::,2801:0:110:ffff:ffff:ffff:ffff:ffff,GT
+2801:0:120::,2801:0:120:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:130::,2801:0:130:ffff:ffff:ffff:ffff:ffff,PY
+2801:0:140::,2801:0:140:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:150::,2801:0:150:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:160::,2801:0:160:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:170::,2801:0:170:ffff:ffff:ffff:ffff:ffff,BO
+2801:0:180::,2801:0:180:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:190::,2801:0:190:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:1a0::,2801:0:1a0:ffff:ffff:ffff:ffff:ffff,HN
+2801:0:1b0::,2801:0:1b0:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:1c0::,2801:0:1c7:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:1d0::,2801:0:1d7:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:1e0::,2801:0:1e0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:1f0::,2801:0:1f0:ffff:ffff:ffff:ffff:ffff,PY
+2801:0:200::,2801:0:200:ffff:ffff:ffff:ffff:ffff,VE
+2801:0:210::,2801:0:210:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:220::,2801:0:22f:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:240::,2801:0:240:ffff:ffff:ffff:ffff:ffff,PA
+2801:0:250::,2801:0:250:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:260::,2801:0:260:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:270::,2801:0:270:ffff:ffff:ffff:ffff:ffff,EC
+2801:0:280::,2801:0:280:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:290::,2801:0:290:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:2a0::,2801:0:2a0:ffff:ffff:ffff:ffff:ffff,CR
+2801:0:2b0::,2801:0:2b0:ffff:ffff:ffff:ffff:ffff,PA
+2801:0:2c0::,2801:0:2c0:ffff:ffff:ffff:ffff:ffff,HN
+2801:0:2d0::,2801:0:2d0:ffff:ffff:ffff:ffff:ffff,PA
+2801:0:2e0::,2801:0:2e0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:2f0::,2801:0:2f0:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:300::,2801:0:300:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:310::,2801:0:310:ffff:ffff:ffff:ffff:ffff,CW
+2801:0:320::,2801:0:320:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:330::,2801:0:330:ffff:ffff:ffff:ffff:ffff,HT
+2801:0:340::,2801:0:340:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:350::,2801:0:350:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:380::,2801:0:380:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:390::,2801:0:390:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3a0::,2801:0:3a0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3b0::,2801:0:3b0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3c0::,2801:0:3c0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3d0::,2801:0:3d0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3e0::,2801:0:3e0:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:2000::,2801:0:2fff:ffff:ffff:ffff:ffff:ffff,UY
+2801:1::,2801:1:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2801:2::,2801:2:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2801:10::,2801:10:7:ffff:ffff:ffff:ffff:ffff,AR
+2801:18::,2801:18:0:ffff:ffff:ffff:ffff:ffff,CR
+2801:80::,2801:bf:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2801:c0::,2801:c0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4::,2801:c4:0:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:10::,2801:c4:10:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:20::,2801:c4:20:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:30::,2801:c4:30:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:40::,2801:c4:40:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:50::,2801:c4:50:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:60::,2801:c4:60:ffff:ffff:ffff:ffff:ffff,MX
+2801:d0::,2801:d0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2801:f0::,2801:f0:0:ffff:ffff:ffff:ffff:ffff,MX
+2801:f0:16::,2801:f0:16:ffff:ffff:ffff:ffff:ffff,MX
+2801:f0:20::,2801:f0:20:ffff:ffff:ffff:ffff:ffff,MX
+2801:f0:28::,2801:f0:28:ffff:ffff:ffff:ffff:ffff,MX
+2801:100::,2801:100:ff:ffff:ffff:ffff:ffff:ffff,AR
+2802::,2802:3:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803::,2803:0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:100::,2803:100:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:200::,2803:200:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:400::,2803:400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:600::,2803:600:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:800::,2803:800:ffff:ffff:ffff:ffff:ffff:ffff,NI
+2803:a00::,2803:a00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:c00::,2803:c00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:e00::,2803:e00:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:1000::,2803:1000:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2803:1200::,2803:1200:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:1400::,2803:1400:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2803:1600::,2803:1600:ffff:ffff:ffff:ffff:ffff:ffff,BQ
+2803:1800::,2803:1800:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:1a00::,2803:1a00:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:1c00::,2803:1c00:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:1e00::,2803:1e00:ffff:ffff:ffff:ffff:ffff:ffff,NI
+2803:2000::,2803:2000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:2200::,2803:2200:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:2400::,2803:2400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:2600::,2803:2600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:2800::,2803:2800:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:2a00::,2803:2a00:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2803:2c00::,2803:2c00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:2e00::,2803:2e00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:3000::,2803:3000:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:3200::,2803:3200:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:3400::,2803:3400:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:3600::,2803:3600:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:3800::,2803:3800:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:3a00::,2803:3a00:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:3c00::,2803:3c00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:3e00::,2803:3e00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:4000::,2803:4000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:4100::,2803:4100:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:4200::,2803:4200:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:4400::,2803:4400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:4600::,2803:4600:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:4800::,2803:4800:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2803:4a00::,2803:4a00:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:4c00::,2803:4c00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:4e00::,2803:4e00:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2803:5000::,2803:5000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:5200::,2803:5200:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:5400::,2803:5400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:5600::,2803:5600:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:5800::,2803:5800:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2803:5a00::,2803:5a00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:5c00::,2803:5c00:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2803:5e00::,2803:5e00:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2803:6000::,2803:6000:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:6200::,2803:6200:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:6400::,2803:6400:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2803:6600::,2803:6600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:6800::,2803:6800:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:6a00::,2803:6a00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:6c00::,2803:6c00:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:6e00::,2803:6e00:ffff:ffff:ffff:ffff:ffff:ffff,SR
+2803:7000::,2803:7000:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:7200::,2803:7200:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:7400::,2803:7400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:7600::,2803:7600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:7800::,2803:7800:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2803:7a00::,2803:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:7c00::,2803:7c00:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:7e00::,2803:7e00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:8000::,2803:8000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:8100::,2803:8100:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2803:8200::,2803:8200:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:8400::,2803:8400:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:8600::,2803:8600:ffff:ffff:ffff:ffff:ffff:ffff,HT
+2803:8800::,2803:8800:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:8a00::,2803:8a00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:8c00::,2803:8c00:ffff:ffff:ffff:ffff:ffff:ffff,BZ
+2803:8e00::,2803:8e00:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:9000::,2803:9000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:9200::,2803:9200:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2803:9400::,2803:9400:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2803:9600::,2803:9600:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2803:9800::,2803:9800:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:9a00::,2803:9a00:ffff:ffff:ffff:ffff:ffff:ffff,BZ
+2803:9c00::,2803:9c00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:9e00::,2803:9e00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:a000::,2803:a000:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2803:a200::,2803:a200:ffff:ffff:ffff:ffff:ffff:ffff,SR
+2803:a400::,2803:a400:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:a600::,2803:a600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:a800::,2803:a800:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:aa00::,2803:aa00:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:ac00::,2803:ac00:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:ae00::,2803:ae00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:b000::,2803:b000:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:b200::,2803:b200:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2803:b400::,2803:b400:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2803:b600::,2803:b600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:b800::,2803:b800:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:ba00::,2803:ba00:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:bc00::,2803:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:be00::,2803:be00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:c000::,2803:c000:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2803:c200::,2803:c200:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2803:c400::,2803:c400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:c600::,2803:c600:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:c800::,2803:c800:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:ca00::,2803:ca00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:cc00::,2803:cc00:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:ce00::,2803:ce00:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:d000::,2803:d000:ffff:ffff:ffff:ffff:ffff:ffff,BZ
+2803:d200::,2803:d200:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:d400::,2803:d400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:d600::,2803:d600:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2803:d800::,2803:d800:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:da00::,2803:da00:ffff:ffff:ffff:ffff:ffff:ffff,GY
+2803:dc00::,2803:dc00:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:de00::,2803:de00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:e000::,2803:e000:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:e200::,2803:e200:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:e400::,2803:e400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:e600::,2803:e600:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:e800::,2803:e800:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:ea00::,2803:ea00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:ec00::,2803:ec00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:ee00::,2803:ee00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:f000::,2803:f000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:f200::,2803:f200:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:f400::,2803:f400:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:f600::,2803:f600:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:f800::,2803:f800:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:fa00::,2803:fa00:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2803:fc00::,2803:fc00:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2803:fe00::,2803:fe00:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2804::,2804:ffff:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2806::,2806:f:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:200::,2806:200:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:220::,2806:220:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:230::,2806:230:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:240::,2806:240:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:250::,2806:250:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:260::,2806:260:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:270::,2806:270:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:290::,2806:290:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:2a0::,2806:2a0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:2b0::,2806:2b0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:2d0::,2806:2d0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:2e0::,2806:2e0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:1000::,2806:10ff:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2a00::,2a00:3ff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:800::,2a00:87f:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:c00::,2a00:c00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:c08::,2a00:c08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c10::,2a00:c10:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:c18::,2a00:c18:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c20::,2a00:c20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c28::,2a00:c28:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c30::,2a00:c37:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:c38::,2a00:c38:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:c40::,2a00:c40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:c50::,2a00:c50:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c58::,2a00:c58:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c60::,2a00:c60:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c68::,2a00:c68:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:c70::,2a00:c70:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c78::,2a00:c78:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:c80::,2a00:c80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:c88::,2a00:c88:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:c90::,2a00:c90:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:c98::,2a00:c98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ca0::,2a00:ca0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:ca8::,2a00:ca8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:cb0::,2a00:cb0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cb8::,2a00:cb8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:cc0::,2a00:cc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cc8::,2a00:cc8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:cd0::,2a00:cd0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cd8::,2a00:cd8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:ce0::,2a00:ce0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ce8::,2a00:ce8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:cf0::,2a00:cf0:ffff:ffff:ffff:ffff:ffff:ffff,MC
+2a00:cf8::,2a00:cf8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:d00::,2a00:d00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d08::,2a00:d08:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d10::,2a00:d10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d18::,2a00:d18:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:d20::,2a00:d20:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:d28::,2a00:d28:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d30::,2a00:d30:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a00:d38::,2a00:d38:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:d40::,2a00:d40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:d50::,2a00:d50:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d58::,2a00:d58:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d60::,2a00:d60:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:d68::,2a00:d68:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d70::,2a00:d70:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d78::,2a00:d78:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d80::,2a00:d80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d88::,2a00:d88:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:d90::,2a00:d90:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:d98::,2a00:d98:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:da0::,2a00:da0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:da8::,2a00:da9:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:db0::,2a00:db0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:db8::,2a00:db8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:dc0::,2a00:dc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:dc8::,2a00:dc8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:dd0::,2a00:dd0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:dd8::,2a00:dd8:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:de8::,2a00:de8:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:df0::,2a00:df0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:df8::,2a00:df8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:e00::,2a00:e00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e08::,2a00:e08:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:e10::,2a00:e10:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e18::,2a00:e18:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:e20::,2a00:e20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e28::,2a00:e28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e30::,2a00:e30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e38::,2a00:e38:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:e40::,2a00:e40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:e48::,2a00:e48:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:e50::,2a00:e50:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e58::,2a00:e58:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e60::,2a00:e60:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e68::,2a00:e68:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e70::,2a00:e70:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:e78::,2a00:e78:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e80::,2a00:e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e88::,2a00:e88:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e90::,2a00:e90:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:e98::,2a00:e98:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:ea0::,2a00:ea0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:ea8::,2a00:ea8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:eb0::,2a00:eb0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:eb8::,2a00:eb8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:ec0::,2a00:ec0:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a00:ec8::,2a00:ec8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:ed0::,2a00:ed0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ed8::,2a00:ed8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:ee0::,2a00:ee0:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:ee8::,2a00:ee8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ef0::,2a00:ef0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:ef8::,2a00:ef8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:f00::,2a00:f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f08::,2a00:f08:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f10::,2a00:f10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:f18::,2a00:f18:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f20::,2a00:f20:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:f28::,2a00:f28:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a00:f30::,2a00:f30:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f38::,2a00:f38:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a00:f40::,2a00:f40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:f48::,2a00:f48:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f50::,2a00:f50:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:f58::,2a00:f58:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:f60::,2a00:f60:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:f68::,2a00:f68:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f70::,2a00:f70:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f78::,2a00:f78:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:f80::,2a00:f80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:f88::,2a00:f88:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f90::,2a00:f90:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:f98::,2a00:f98:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:fa0::,2a00:fa0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:fa8::,2a00:fa8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fb8::,2a00:fb8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fc0::,2a00:fc0:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:fc8::,2a00:fc8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:fd0::,2a00:fd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:fd8::,2a00:fd8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:fe0::,2a00:fe0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fe8::,2a00:fe8:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:ff0::,2a00:ff0:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:ff8::,2a00:ff8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1000::,2a00:1000:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1008::,2a00:1008:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1010::,2a00:1010:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1018::,2a00:1018:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1020::,2a00:1020:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1028::,2a00:1028:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1030::,2a00:1030:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1038::,2a00:1038:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1040::,2a00:1040:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1048::,2a00:1048:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1050::,2a00:1050:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1058::,2a00:1058:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1060::,2a00:1060:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a00:1068::,2a00:1068:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1070::,2a00:1070:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1078::,2a00:1078:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1080::,2a00:1080:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1088::,2a00:1088:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1090::,2a00:1090:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1098::,2a00:1098:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:10a0::,2a00:10a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:10a8::,2a00:10a8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:10b0::,2a00:10b7:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:10b8::,2a00:10b8:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:10c0::,2a00:10c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:10c8::,2a00:10c8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:10d0::,2a00:10d0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:10d8::,2a00:10d8:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:10e0::,2a00:10e0:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:10e8::,2a00:10f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:10f8::,2a00:10f8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:1100::,2a00:1100:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1108::,2a00:1108:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:1110::,2a00:1110:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1118::,2a00:1118:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:1120::,2a00:1120:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1128::,2a00:1128:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1130::,2a00:1130:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1138::,2a00:1138:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1140::,2a00:1140:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1148::,2a00:1148:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1150::,2a00:1150:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a00:1158::,2a00:1158:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1160::,2a00:1160:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1168::,2a00:1168:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1170::,2a00:1170:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:1178::,2a00:1178:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1180::,2a00:1180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1188::,2a00:1188:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1190::,2a00:1190:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1198::,2a00:1198:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:11a8::,2a00:11a8:ffff:ffff:ffff:ffff:ffff:ffff,OM
+2a00:11b0::,2a00:11b0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:11b8::,2a00:11b8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:11c0::,2a00:11c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:11c8::,2a00:11c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:11d0::,2a00:11d0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:11d8::,2a00:11d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:11e0::,2a00:11e0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:11e8::,2a00:11e8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:11f0::,2a00:11f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:11f8::,2a00:11f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1200::,2a00:1200:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1208::,2a00:1208:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1210::,2a00:1210:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1218::,2a00:1218:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a00:1220::,2a00:1220:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1228::,2a00:1228:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1230::,2a00:1237:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1238::,2a00:1238:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1240::,2a00:1240:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1248::,2a00:1248:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1250::,2a00:1250:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1258::,2a00:1258:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1260::,2a00:1260:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1268::,2a00:1268:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1270::,2a00:1270:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a00:1278::,2a00:1278:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1280::,2a00:1280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1288::,2a00:1288:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1290::,2a00:1290:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1298::,2a00:1298:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:12a0::,2a00:12a0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:12a8::,2a00:12a8:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:12b0::,2a00:12b0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:12b8::,2a00:12b8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:12c0::,2a00:12c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:12c8::,2a00:12c8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:12d0::,2a00:12d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:12d8::,2a00:12d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:12e0::,2a00:12e0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:12e8::,2a00:12e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:12f0::,2a00:12f0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:12f8::,2a00:12f8:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a00:1300::,2a00:1300:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1308::,2a00:1308:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1310::,2a00:1310:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:1318::,2a00:1318:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1320::,2a00:1320:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1328::,2a00:1328:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1330::,2a00:1330:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1338::,2a00:1338:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1340::,2a00:1340:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1348::,2a00:1348:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1350::,2a00:1350:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1358::,2a00:1358:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a00:1360::,2a00:1360:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1368::,2a00:1368:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1370::,2a00:1370:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1378::,2a00:1378:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1380::,2a00:1380:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1388::,2a00:1388:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1390::,2a00:1390:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1398::,2a00:1398:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:13a0::,2a00:13a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:13a8::,2a00:13a8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:13b0::,2a00:13b0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:13b8::,2a00:13b8:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:13c0::,2a00:13c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:13c8::,2a00:13c8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:13d0::,2a00:13d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:13d8::,2a00:13d8:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:13e0::,2a00:13e0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:13e8::,2a00:13e8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:13f0::,2a00:13f0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:13f8::,2a00:13f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1400::,2a00:1400:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1408::,2a00:1408:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1410::,2a00:1410:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1418::,2a00:1418:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1420::,2a00:1420:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1428::,2a00:1428:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:1430::,2a00:1430:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1438::,2a00:1438:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1440::,2a00:1440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1448::,2a00:1448:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1450::,2a00:1457:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:1458::,2a00:1458:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1460::,2a00:1460:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1468::,2a00:1468:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1470::,2a00:1470:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1478::,2a00:1478:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1480::,2a00:1480:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:1488::,2a00:1488:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1490::,2a00:1490:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1498::,2a00:1498:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:14a0::,2a00:14a0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:14a8::,2a00:14a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:14b0::,2a00:14b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:14b8::,2a00:14b8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:14c0::,2a00:14c0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:14c8::,2a00:14c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:14d0::,2a00:14d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:14d8::,2a00:14d8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:14e0::,2a00:14e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:14e8::,2a00:14e8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:14f0::,2a00:14f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:14f8::,2a00:14f8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1500::,2a00:1500:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a00:1508::,2a00:1508:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1510::,2a00:1510:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1518::,2a00:1518:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1520::,2a00:1520:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1528::,2a00:1528:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1530::,2a00:1530:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1538::,2a00:1538:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1540::,2a00:1540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1548::,2a00:1548:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1550::,2a00:1550:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1558::,2a00:1558:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1560::,2a00:1560:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1568::,2a00:1568:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1570::,2a00:1570:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1578::,2a00:1578:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1580::,2a00:1580:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:1588::,2a00:1588:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1590::,2a00:1590:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:1598::,2a00:1598:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:15a0::,2a00:15a0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:15a8::,2a00:15a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:15b0::,2a00:15b0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:15b8::,2a00:15b8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:15c0::,2a00:15c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:15c8::,2a00:15c8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:15d0::,2a00:15d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:15d8::,2a00:15d8:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:15e0::,2a00:15e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:15e8::,2a00:15e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:15f0::,2a00:15f0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:15f8::,2a00:15f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1600::,2a00:1600:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1608::,2a00:1608:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:1610::,2a00:1610:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1618::,2a00:1618:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1620::,2a00:1620:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1628::,2a00:1628:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1630::,2a00:1630:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1638::,2a00:1638:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1640::,2a00:1640:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1648::,2a00:1648:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1650::,2a00:1650:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:1660::,2a00:1660:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1668::,2a00:1668:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1670::,2a00:1670:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1678::,2a00:1678:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1680::,2a00:1680:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1688::,2a00:1688:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1690::,2a00:1690:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1698::,2a00:1698:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:16a0::,2a00:16a0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:16a8::,2a00:16a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:16b0::,2a00:16b0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:16c8::,2a00:16c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:16d0::,2a00:16d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:16d8::,2a00:16d8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:16e0::,2a00:16e0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:16e8::,2a00:16e8:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:16f0::,2a00:16f0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:16f8::,2a00:16f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1700::,2a00:1700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1708::,2a00:1708:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1710::,2a00:1710:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:1718::,2a00:1718:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1720::,2a00:1720:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1728::,2a00:1728:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:1730::,2a00:1730:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1748::,2a00:1748:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1750::,2a00:1750:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1758::,2a00:1758:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1760::,2a00:1760:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a00:1768::,2a00:1768:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1778::,2a00:1778:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1780::,2a00:1780:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:1788::,2a00:1788:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1790::,2a00:1790:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1798::,2a00:1798:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:17a0::,2a00:17a0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:17a8::,2a00:17a8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:17b0::,2a00:17b0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:17b8::,2a00:17b8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:17c0::,2a00:17c0:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:17c8::,2a00:17c8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:17d0::,2a00:17d0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:17d8::,2a00:17d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:17e0::,2a00:17e0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:17e8::,2a00:17e8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:17f0::,2a00:17f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:17f8::,2a00:17f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1800::,2a00:1800:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1808::,2a00:1808:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1810::,2a00:1810:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:1818::,2a00:1818:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1828::,2a00:1828:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1830::,2a00:1830:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1838::,2a00:1838:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1840::,2a00:1840:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1848::,2a00:1848:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1850::,2a00:1850:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a00:1858::,2a00:1858:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:1860::,2a00:1860:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1868::,2a00:1868:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1870::,2a00:1870:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1878::,2a00:1878:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1880::,2a00:1880:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:1888::,2a00:1888:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1890::,2a00:1890:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1898::,2a00:1898:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:18a0::,2a00:18a0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:18a8::,2a00:18a8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:18b0::,2a00:18b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:18b8::,2a00:18b8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:18c0::,2a00:18c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:18c8::,2a00:18c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:18d0::,2a00:18d0:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a00:18d8::,2a00:18d8:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a00:18e0::,2a00:18e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:18e8::,2a00:18e8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:18f0::,2a00:18f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:18f8::,2a00:18f8:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1900::,2a00:1900:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1908::,2a00:1908:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1910::,2a00:1910:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1918::,2a00:1918:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1920::,2a00:1920:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1928::,2a00:1928:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1930::,2a00:1930:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1938::,2a00:1938:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1940::,2a00:1940:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1948::,2a00:1948:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1950::,2a00:1950:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1958::,2a00:1958:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1960::,2a00:1960:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1968::,2a00:1968:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1970::,2a00:1970:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1978::,2a00:1978:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1980::,2a00:1980:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1988::,2a00:1988:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1990::,2a00:1990:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1998::,2a00:1998:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:19a0::,2a00:19a0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:19a8::,2a00:19a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:19b0::,2a00:19b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:19b8::,2a00:19b8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:19c0::,2a00:19c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:19c8::,2a00:19c8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:19d0::,2a00:19d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:19d8::,2a00:19d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:19e0::,2a00:19e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:19e8::,2a00:19e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:19f0::,2a00:19f0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:19f8::,2a00:19f8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1a00::,2a00:1a00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1a08::,2a00:1a08:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a00:1a10::,2a00:1a10:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a18::,2a00:1a18:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1a20::,2a00:1a20:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1a28::,2a00:1a28:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1a30::,2a00:1a30:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a38::,2a00:1a38:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1a40::,2a00:1a40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1a48::,2a00:1a48:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a50::,2a00:1a50:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1a58::,2a00:1a58:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1a60::,2a00:1a60:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1a68::,2a00:1a68:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1a70::,2a00:1a70:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1a78::,2a00:1a78:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1a80::,2a00:1a80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a88::,2a00:1a88:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1a90::,2a00:1a90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a98::,2a00:1a98:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:1aa0::,2a00:1aa0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1aa8::,2a00:1aa8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1ab0::,2a00:1ab0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1ab8::,2a00:1ab8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1ac0::,2a00:1ac0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1ac8::,2a00:1ac8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1ad0::,2a00:1ad0:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:1ad8::,2a00:1ad8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1ae0::,2a00:1ae0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1ae8::,2a00:1ae8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1af0::,2a00:1af0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1af8::,2a00:1af8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b00::,2a00:1b00:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a00:1b08::,2a00:1b08:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b10::,2a00:1b10:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1b18::,2a00:1b18:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1b20::,2a00:1b20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1b28::,2a00:1b28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1b30::,2a00:1b30:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b38::,2a00:1b38:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1b40::,2a00:1b40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1b48::,2a00:1b48:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b50::,2a00:1b50:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1b58::,2a00:1b58:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1b60::,2a00:1b60:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1b68::,2a00:1b68:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b70::,2a00:1b70:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1b78::,2a00:1b78:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b80::,2a00:1b80:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:1b88::,2a00:1b88:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1b90::,2a00:1b90:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1b98::,2a00:1b98:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1ba0::,2a00:1ba0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1ba8::,2a00:1ba8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1bb0::,2a00:1bb0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1bb8::,2a00:1bb8:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:1bc0::,2a00:1bc0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1bc8::,2a00:1bc8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1bd0::,2a00:1bd0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1bd8::,2a00:1bd8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1be0::,2a00:1be0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1be8::,2a00:1be8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1bf0::,2a00:1bf0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1bf8::,2a00:1bf8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1c00::,2a00:1c00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1c08::,2a00:1c08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1c10::,2a00:1c10:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1c18::,2a00:1c18:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1c20::,2a00:1c20:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1c28::,2a00:1c28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c30::,2a00:1c30:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1c38::,2a00:1c3f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1c40::,2a00:1c40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1c48::,2a00:1c48:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c50::,2a00:1c50:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1c58::,2a00:1c58:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1c60::,2a00:1c60:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:1c68::,2a00:1c68:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1c70::,2a00:1c70:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c78::,2a00:1c78:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c80::,2a00:1c80:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1c88::,2a00:1c88:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c90::,2a00:1c90:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1c98::,2a00:1c98:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1ca0::,2a00:1ca0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1ca8::,2a00:1ca8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1cb0::,2a00:1cb0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1cb8::,2a00:1cb8:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a00:1cc0::,2a00:1cc0:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a00:1cc8::,2a00:1cc8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1cd0::,2a00:1cd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1cd8::,2a00:1cd8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1ce0::,2a00:1ce0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1ce8::,2a00:1ce8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1cf0::,2a00:1cf0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1cf8::,2a00:1cf8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1d00::,2a00:1d00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1d08::,2a00:1d08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1d10::,2a00:1d10:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:1d18::,2a00:1d18:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1d20::,2a00:1d20:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1d28::,2a00:1d28:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1d30::,2a00:1d30:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:1d38::,2a00:1d38:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1d40::,2a00:1d40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1d48::,2a00:1d48:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1d50::,2a00:1d50:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1d58::,2a00:1d58:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:1d60::,2a00:1d60:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1d68::,2a00:1d68:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1d70::,2a00:1d70:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1d78::,2a00:1d78:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1d80::,2a00:1d80:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1d88::,2a00:1d88:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1d90::,2a00:1d90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1da0::,2a00:1da0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1da8::,2a00:1da8:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1db0::,2a00:1db0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1db8::,2a00:1db8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1dc0::,2a00:1dc0:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:1dc8::,2a00:1dc8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1dd0::,2a00:1dd0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1dd8::,2a00:1ddf:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:1de0::,2a00:1de0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1de8::,2a00:1de8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1df0::,2a00:1df0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1df8::,2a00:1df8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1e00::,2a00:1e00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e08::,2a00:1e08:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1e10::,2a00:1e10:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e18::,2a00:1e18:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1e20::,2a00:1e20:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1e28::,2a00:1e28:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1e30::,2a00:1e30:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1e38::,2a00:1e38:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1e40::,2a00:1e40:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:1e48::,2a00:1e48:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e50::,2a00:1e50:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1e58::,2a00:1e58:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1e60::,2a00:1e60:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1e68::,2a00:1e68:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e70::,2a00:1e70:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1e78::,2a00:1e78:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1e80::,2a00:1e80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1e88::,2a00:1e88:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e90::,2a00:1e90:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1e98::,2a00:1e98:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1ea0::,2a00:1ea0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1ea8::,2a00:1ea8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1eb0::,2a00:1eb0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1eb8::,2a00:1eb8:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:1ec0::,2a00:1ec0:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a00:1ec8::,2a00:1ec8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1ed0::,2a00:1ed0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1ed8::,2a00:1ed8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:1ee0::,2a00:1ee0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1ee8::,2a00:1ee8:ffff:ffff:ffff:ffff:ffff:ffff,SY
+2a00:1ef0::,2a00:1ef0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:1ef8::,2a00:1ef8:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1f00::,2a00:1f00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1f08::,2a00:1f08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1f10::,2a00:1f10:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1f18::,2a00:1f18:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1f20::,2a00:1f20:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1f28::,2a00:1f28:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a00:1f30::,2a00:1f30:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1f38::,2a00:1f38:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1f40::,2a00:1f40:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1f48::,2a00:1f48:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1f50::,2a00:1f50:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1f58::,2a00:1f58:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1f60::,2a00:1f60:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1f68::,2a00:1f68:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a00:1f70::,2a00:1f70:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1f78::,2a00:1f78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1f80::,2a00:1f80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1f88::,2a00:1f88:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1f90::,2a00:1f90:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:1f98::,2a00:1f98:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1fa0::,2a00:1fa0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1fa8::,2a00:1fa8:ffff:ffff:ffff:ffff:ffff:ffff,GL
+2a00:1fb0::,2a00:1fb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1fb8::,2a00:1fb8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1fc0::,2a00:1fc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1fc8::,2a00:1fc8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1fd0::,2a00:1fd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1fd8::,2a00:1fd8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1fe0::,2a00:1fe0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1fe8::,2a00:1fe8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1ff0::,2a00:1ff0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1ff8::,2a00:1ff8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:2000::,2a00:23ff:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4000::,2a00:4000:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:4040::,2a00:4040:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4080::,2a00:4080:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:40c0::,2a00:40c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:4100::,2a00:4100:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4140::,2a00:4140:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:4180::,2a00:4180:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:41c0::,2a00:41c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:4200::,2a00:4200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4240::,2a00:4240:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4280::,2a00:4280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:42c0::,2a00:42c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4300::,2a00:4300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4340::,2a00:4340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4380::,2a00:4380:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:43c0::,2a00:43c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:4400::,2a00:4400:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:4440::,2a00:4440:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:4480::,2a00:4480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:44c0::,2a00:44c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4500::,2a00:4500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4540::,2a00:4540:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:4580::,2a00:4580:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:45c0::,2a00:45c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:4600::,2a00:4600:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:4640::,2a00:4640:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4680::,2a00:4680:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:46c0::,2a00:46c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:4700::,2a00:4700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4740::,2a00:4740:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:4780::,2a00:4780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:47c0::,2a00:47c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4800::,2a00:4800:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:4840::,2a00:4840:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4880::,2a00:4880:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:48c0::,2a00:48c0:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a00:4900::,2a00:4900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4940::,2a00:4940:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a00:4980::,2a00:4987:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:49c0::,2a00:49c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:4a00::,2a00:4a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4a40::,2a00:4a40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:4a80::,2a00:4a80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4ac0::,2a00:4ac0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4b00::,2a00:4b00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4b40::,2a00:4b40:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:4b80::,2a00:4b80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:4bc0::,2a00:4bc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:4c00::,2a00:4c00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4c40::,2a00:4c40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4c80::,2a00:4c80:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:4cc0::,2a00:4cc0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:4d00::,2a00:4d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:4d40::,2a00:4d40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4d80::,2a00:4d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4dc0::,2a00:4dc0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:4e00::,2a00:4e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4e40::,2a00:4e40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:4e80::,2a00:4e80:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a00:4ec0::,2a00:4ec0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:4f00::,2a00:4f00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:4f40::,2a00:4f40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4f80::,2a00:4f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4fc0::,2a00:4fc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:5000::,2a00:5000:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:5040::,2a00:5040:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:5080::,2a00:5080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:50c0::,2a00:50c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5100::,2a00:5100:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:5140::,2a00:5140:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:5180::,2a00:5180:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:51c0::,2a00:51c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:5200::,2a00:5200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5240::,2a00:5240:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:5280::,2a00:5280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:52c0::,2a00:52c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:5300::,2a00:5300:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5340::,2a00:5340:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:5380::,2a00:5380:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:53c0::,2a00:53c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5400::,2a00:5400:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:5440::,2a00:5440:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a00:5480::,2a00:5480:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:54c0::,2a00:54c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:5500::,2a00:5500:ffff:ffff:ffff:ffff:ffff:ffff,AX
+2a00:5540::,2a00:5540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5580::,2a00:5580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:55c0::,2a00:55c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5600::,2a00:5600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5640::,2a00:5640:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5680::,2a00:5680:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:56c0::,2a00:56c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5700::,2a00:5700:ffff:ffff:ffff:ffff:ffff:ffff,KG
+2a00:5740::,2a00:5740:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:5780::,2a00:5780:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:57c0::,2a00:57c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:5800::,2a00:5800:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:5840::,2a00:5840:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5880::,2a00:5880:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:58c0::,2a00:58c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5900::,2a00:5900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5940::,2a00:5940:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:5980::,2a00:5980:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:59c0::,2a00:59c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5a00::,2a00:5a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5a40::,2a00:5a40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:5a80::,2a00:5a80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5ac0::,2a00:5ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:5b00::,2a00:5b00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:5b40::,2a00:5b40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:5b80::,2a00:5b80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:5bc0::,2a00:5bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5c00::,2a00:5c00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:5c40::,2a00:5c40:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a00:5c80::,2a00:5c80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5cc0::,2a00:5cc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5d00::,2a00:5d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5d40::,2a00:5d40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:5d80::,2a00:5d80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5dc0::,2a00:5dc0:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:5e00::,2a00:5e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5e40::,2a00:5e40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:5e80::,2a00:5e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:5ec0::,2a00:5ec0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5f00::,2a00:5f00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5f40::,2a00:5f40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5fc0::,2a00:5fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6000::,2a00:6000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6040::,2a00:6040:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:6080::,2a00:6080:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:60c0::,2a00:60c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:6100::,2a00:6100:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:6140::,2a00:6140:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6180::,2a00:6180:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:61c0::,2a00:61c0:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:6200::,2a00:6200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6240::,2a00:6240:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6280::,2a00:6280:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:62c0::,2a00:62c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6300::,2a00:6300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:6340::,2a00:6340:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:6380::,2a00:6380:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:63c0::,2a00:63c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:6400::,2a00:6400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6440::,2a00:6440:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a00:6480::,2a00:6480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:64c0::,2a00:64c0:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:6500::,2a00:6500:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:6540::,2a00:6540:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6580::,2a00:6580:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:65c0::,2a00:65c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:6600::,2a00:6600:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a00:6640::,2a00:6640:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:6680::,2a00:6680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:6740::,2a00:6740:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:6780::,2a00:6780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:67c0::,2a00:67c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:6800::,2a00:6800:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6840::,2a00:6840:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:68c0::,2a00:68c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6900::,2a00:6900:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6940::,2a00:6940:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:6980::,2a00:6980:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:69c0::,2a00:69c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6a00::,2a00:6a00:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:6a40::,2a00:6a40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6a80::,2a00:6a80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:6ac0::,2a00:6ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:6b00::,2a00:6b00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:6b40::,2a00:6b40:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:6b80::,2a00:6b80:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a00:6bc0::,2a00:6bc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:6c00::,2a00:6c00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6c40::,2a00:6c40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:6c80::,2a00:6c80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6d40::,2a00:6d40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:6d80::,2a00:6d80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:6dc0::,2a00:6dc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:6e00::,2a00:6e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6e40::,2a00:6e40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6e80::,2a00:6e80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:6ec0::,2a00:6ec0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:6f00::,2a00:6f00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:6f40::,2a00:6f40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:6f80::,2a00:6f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6fc0::,2a00:6fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7000::,2a00:7000:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:7040::,2a00:7040:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:7080::,2a00:7080:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:70c0::,2a00:70c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7100::,2a00:7100:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7140::,2a00:7140:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7180::,2a00:7180:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:71c0::,2a00:71c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7200::,2a00:7200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7240::,2a00:7240:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:7280::,2a00:7280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:72c0::,2a00:72c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7300::,2a00:7300:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:7340::,2a00:7340:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:7380::,2a00:7380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:73c0::,2a00:73c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7400::,2a00:7400:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:7440::,2a00:7440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7480::,2a00:7480:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:74c0::,2a00:74c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7500::,2a00:7500:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7540::,2a00:7540:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7580::,2a00:7580:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:75c0::,2a00:75c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7600::,2a00:7600:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:7640::,2a00:7640:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7680::,2a00:7680:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:76c0::,2a00:76c0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:7700::,2a00:7700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7740::,2a00:7740:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7780::,2a00:7780:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:77c0::,2a00:77c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:7800::,2a00:7800:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:7840::,2a00:7840:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:7880::,2a00:7880:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:78c0::,2a00:78c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7900::,2a00:7900:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7940::,2a00:7940:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7980::,2a00:7980:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:79c0::,2a00:79c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7a00::,2a00:7a00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:7a40::,2a00:7a40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7a80::,2a00:7a80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:7ac0::,2a00:7ac0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7b00::,2a00:7b00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7b40::,2a00:7b40:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:7b80::,2a00:7b80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7bc0::,2a00:7bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7c00::,2a00:7c00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7c40::,2a00:7c40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7c80::,2a00:7c80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7cc0::,2a00:7cc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7d00::,2a00:7d00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:7d40::,2a00:7d40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7d80::,2a00:7d80:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:7dc0::,2a00:7dc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7e00::,2a00:7e00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:7e40::,2a00:7e40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7e80::,2a00:7e80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:7ec0::,2a00:7ec0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7f00::,2a00:7f00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7f40::,2a00:7f40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7f80::,2a00:7f80:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:7fc0::,2a00:7fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8040::,2a00:8040:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8080::,2a00:8080:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:80c0::,2a00:80c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:8100::,2a00:8100:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:8140::,2a00:8140:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8180::,2a00:8180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:81c0::,2a00:81c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8200::,2a00:8200:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:8240::,2a00:8240:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8280::,2a00:8280:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:82c0::,2a00:82c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:8300::,2a00:8300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8340::,2a00:8340:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:8380::,2a00:8380:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:83c0::,2a00:83c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8400::,2a00:8400:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:8440::,2a00:8440:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8480::,2a00:8480:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:84c0::,2a00:84c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8500::,2a00:8500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8540::,2a00:8540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8580::,2a00:8580:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:85c0::,2a00:85c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8600::,2a00:8600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8640::,2a00:8640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8680::,2a00:8680:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:86c0::,2a00:86c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8700::,2a00:8700:ffff:ffff:ffff:ffff:ffff:ffff,ME
+2a00:8740::,2a00:8740:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8780::,2a00:8780:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:87c0::,2a00:87c0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:8800::,2a00:8800:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8840::,2a00:8840:ffff:ffff:ffff:ffff:ffff:ffff,UZ
+2a00:8880::,2a00:8880:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:88c0::,2a00:88c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8900::,2a00:8900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8940::,2a00:8940:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8980::,2a00:8980:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:89c0::,2a00:89c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:8a00::,2a00:8a00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:8a40::,2a00:8a40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:8a80::,2a00:8a80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:8ac0::,2a00:8ac0:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a00:8b00::,2a00:8b00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8b80::,2a00:8b80:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:8bc0::,2a00:8bc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8c00::,2a00:8c00:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:8c40::,2a00:8c40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8c80::,2a00:8c80:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:8cc0::,2a00:8cc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:8d00::,2a00:8d00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:8d40::,2a00:8d40:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a00:8d80::,2a00:8d80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:8dc0::,2a00:8dc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:8e00::,2a00:8e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8e40::,2a00:8e40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8ec0::,2a00:8ec0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8f00::,2a00:8f00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:8f40::,2a00:8f40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8fc0::,2a00:8fc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9000::,2a00:9000:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:9040::,2a00:9040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9080::,2a00:9080:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:90c0::,2a00:90c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:9100::,2a00:9100:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a00:9140::,2a00:9140:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:9180::,2a00:9180:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:91c0::,2a00:91c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9200::,2a00:9200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9240::,2a00:9240:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:9280::,2a00:9280:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:92c0::,2a00:92c0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:9300::,2a00:9300:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:9340::,2a00:9340:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:9380::,2a00:9380:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:93c0::,2a00:93c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:9400::,2a00:9400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9440::,2a00:9440:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:9480::,2a00:9480:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:94c0::,2a00:94c0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:9500::,2a00:9500:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:9540::,2a00:9540:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:9580::,2a00:9580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:95c0::,2a00:95c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9600::,2a00:9600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9640::,2a00:9640:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:9680::,2a00:9680:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:96c0::,2a00:96c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:9700::,2a00:9700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9740::,2a00:9740:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:9780::,2a00:9780:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:97c0::,2a00:97c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:9800::,2a00:9800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9840::,2a00:9840:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:9880::,2a00:9880:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:98c0::,2a00:98c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:9900::,2a00:9900:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:9940::,2a00:9940:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:9980::,2a00:9980:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:99c0::,2a00:99c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:9a00::,2a00:9a00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9a40::,2a00:9a40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:9a80::,2a00:9a80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9ac0::,2a00:9ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:9b00::,2a00:9b00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:9b40::,2a00:9b40:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a00:9b80::,2a00:9b80:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:9bc0::,2a00:9bc0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:9c00::,2a00:9c00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:9c40::,2a00:9c40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9c80::,2a00:9c80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:9cc0::,2a00:9cc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:9d00::,2a00:9d00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9d40::,2a00:9d40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:9d80::,2a00:9d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:9dc0::,2a00:9dc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:9e00::,2a00:9e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:9e40::,2a00:9e40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9e80::,2a00:9e80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9ec0::,2a00:9ec0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:9f00::,2a00:9f00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:9f40::,2a00:9f40:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a00:9f80::,2a00:9f80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:9fc0::,2a00:9fc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:a000::,2a00:a000:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a040::,2a00:a040:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a00:a080::,2a00:a080:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:a0c0::,2a00:a0c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a100::,2a00:a100:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:a140::,2a00:a140:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:a180::,2a00:a180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:a1c0::,2a00:a1c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:a200::,2a00:a200:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:a240::,2a00:a240:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:a280::,2a00:a280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a2c0::,2a00:a2c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a300::,2a00:a300:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:a340::,2a00:a340:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:a380::,2a00:a380:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:a3c0::,2a00:a3c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a400::,2a00:a400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a440::,2a00:a440:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:a480::,2a00:a480:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:a4c0::,2a00:a4c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:a500::,2a00:a500:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:a540::,2a00:a540:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:a580::,2a00:a580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:a5c0::,2a00:a5c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a600::,2a00:a600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a640::,2a00:a640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a680::,2a00:a680:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:a6c0::,2a00:a6c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:a700::,2a00:a700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:a740::,2a00:a740:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:a780::,2a00:a780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:a7c0::,2a00:a7c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a800::,2a00:a800:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a840::,2a00:a840:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:a880::,2a00:a880:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a00:a900::,2a00:a900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a980::,2a00:a980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:a9c0::,2a00:a9c0:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a00:aa00::,2a00:aa00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:aa40::,2a00:aa40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:aa80::,2a00:aa80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:aac0::,2a00:aac0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:ab00::,2a00:ab00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:ab40::,2a00:ab40:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a00:ab80::,2a00:ab80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ac00::,2a00:ac00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:ac40::,2a00:ac40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ac80::,2a00:ac80:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:acc0::,2a00:acc0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:ad00::,2a00:ad00:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:ad40::,2a00:ad40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ad80::,2a00:ad87:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:adc0::,2a00:adc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:ae00::,2a00:ae00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:ae40::,2a00:ae40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:ae80::,2a00:ae80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:aec0::,2a00:aec0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:af00::,2a00:af00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:af40::,2a00:af40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:af80::,2a00:af80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:afc0::,2a00:afc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:b000::,2a00:b000:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:b040::,2a00:b040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b080::,2a00:b080:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:b0c0::,2a00:b0c0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:b100::,2a00:b100:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b140::,2a00:b140:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:b180::,2a00:b180:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:b1c0::,2a00:b1c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b200::,2a00:b200:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:b240::,2a00:b240:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:b280::,2a00:b280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:b2c0::,2a00:b2c0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:b300::,2a00:b300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b340::,2a00:b340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b380::,2a00:b380:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:b3c0::,2a00:b3c0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:b400::,2a00:b400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:b440::,2a00:b440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b480::,2a00:b480:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:b4c0::,2a00:b4c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b500::,2a00:b500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b540::,2a00:b540:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:b580::,2a00:b580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:b5c0::,2a00:b5c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:b600::,2a00:b607:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b640::,2a00:b640:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:b680::,2a00:b680:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:b6c0::,2a00:b6c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:b700::,2a00:b700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b740::,2a00:b740:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:b780::,2a00:b780:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:b7c0::,2a00:b7c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:b800::,2a00:b800:ffff:ffff:ffff:ffff:ffff:ffff,SY
+2a00:b840::,2a00:b840:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b880::,2a00:b880:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b8c0::,2a00:b8c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:b900::,2a00:b900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b980::,2a00:b981:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b9c0::,2a00:b9c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ba00::,2a00:ba00:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:ba40::,2a00:ba40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ba80::,2a00:ba80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bac0::,2a00:bac0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:bb00::,2a00:bb00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:bb40::,2a00:bb40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:bb80::,2a00:bb80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:bbc0::,2a00:bbc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bc00::,2a00:bc00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:bc40::,2a00:bc40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:bc80::,2a00:bc80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bcc0::,2a00:bcc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:bd00::,2a00:bd00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:bd40::,2a00:bd40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:bd80::,2a00:bd80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:bdc0::,2a00:bdc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:be00::,2a00:be00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:be40::,2a00:be40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:be80::,2a00:be80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bec0::,2a00:bec7:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:bf00::,2a00:bf00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:bf40::,2a00:bf40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bf80::,2a00:bf80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:bfc0::,2a00:bfc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c000::,2a00:c000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c040::,2a00:c040:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c080::,2a00:c080:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c0c0::,2a00:c0c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c100::,2a00:c100:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:c140::,2a00:c140:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:c180::,2a00:c180:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:c1c0::,2a00:c1c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:c200::,2a00:c200:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:c240::,2a00:c240:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a00:c280::,2a00:c280:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a00:c2c0::,2a00:c2c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c300::,2a00:c300:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c340::,2a00:c340:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c380::,2a00:c380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:c3c0::,2a00:c3c0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:c400::,2a00:c400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c440::,2a00:c440:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:c480::,2a00:c480:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c4c0::,2a00:c4c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c500::,2a00:c500:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:c540::,2a00:c540:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:c580::,2a00:c580:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:c5c0::,2a00:c5c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c600::,2a00:c600:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c640::,2a00:c640:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:c680::,2a00:c680:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c6c0::,2a00:c6c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c700::,2a00:c700:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:c740::,2a00:c740:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:c780::,2a00:c780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c7c0::,2a00:c7c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c800::,2a00:c800:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:c840::,2a00:c840:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:c880::,2a00:c880:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c8c0::,2a00:c8c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c900::,2a00:c900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c940::,2a00:c940:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:c980::,2a00:c980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c9c0::,2a00:c9c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:ca00::,2a00:ca00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ca40::,2a00:ca40:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:ca80::,2a00:ca80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:cac0::,2a00:cac0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:cb00::,2a00:cb00:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:cb40::,2a00:cb40:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:cb80::,2a00:cb80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:cbc0::,2a00:cbc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:cc00::,2a00:cc00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:cc40::,2a00:cc40:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a00:cc80::,2a00:cc80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ccc0::,2a00:ccc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cd00::,2a00:cd00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:cd40::,2a00:cd40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:cd80::,2a00:cd80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:cdc0::,2a00:cdc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ce00::,2a00:ce00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:ce40::,2a00:ce40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ce80::,2a00:ce80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:cec0::,2a00:cec0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:cf00::,2a00:cf00:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:cf40::,2a00:cf40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cf80::,2a00:cf80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:cfc0::,2a00:cfc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:d000::,2a00:d000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d040::,2a00:d040:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:d080::,2a00:d080:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:d0c0::,2a00:d0c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d100::,2a00:d100:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:d140::,2a00:d140:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:d180::,2a00:d180:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:d1c0::,2a00:d1c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d200::,2a00:d200:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d240::,2a00:d240:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:d280::,2a00:d280:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:d2c0::,2a00:d2c0:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a00:d300::,2a00:d300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d340::,2a00:d340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d380::,2a00:d380:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d400::,2a00:d400:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:d440::,2a00:d447:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:d480::,2a00:d480:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:d4c0::,2a00:d4c0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:d500::,2a00:d500:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:d540::,2a00:d540:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d580::,2a00:d580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d5c0::,2a00:d5c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:d600::,2a00:d600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d640::,2a00:d640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d680::,2a00:d680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d6c0::,2a00:d6c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d700::,2a00:d700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d740::,2a00:d747:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:d780::,2a00:d780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:d7c0::,2a00:d7c0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:d800::,2a00:d800:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:d840::,2a00:d840:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:d880::,2a00:d880:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d8c0::,2a00:d8c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:d900::,2a00:d900:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:d940::,2a00:d940:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:d980::,2a00:d980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d9c0::,2a00:d9c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:da00::,2a00:da00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:da40::,2a00:da40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:da80::,2a00:da80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:dac0::,2a00:dac0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:db00::,2a00:db00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:db40::,2a00:db40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:db80::,2a00:db80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:dbc0::,2a00:dbc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:dc00::,2a00:dc00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:dc40::,2a00:dc40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:dc80::,2a00:dc80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:dcc0::,2a00:dcc7:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:dd00::,2a00:dd00:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a00:dd40::,2a00:dd40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:dd80::,2a00:dd80:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:ddc0::,2a00:ddc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:de00::,2a00:de00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:de40::,2a00:de40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:de80::,2a00:de80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:dec0::,2a00:dec0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:df00::,2a00:df00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:df40::,2a00:df40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:df80::,2a00:df80:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:dfc0::,2a00:dfc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e000::,2a00:e000:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:e040::,2a00:e040:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:e080::,2a00:e080:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e0c0::,2a00:e0c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e100::,2a00:e100:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e140::,2a00:e140:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:e180::,2a00:e180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e1c0::,2a00:e1c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e200::,2a00:e200:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:e240::,2a00:e240:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e280::,2a00:e280:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:e2c0::,2a00:e2c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:e300::,2a00:e300:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:e340::,2a00:e340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e380::,2a00:e380:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:e3c0::,2a00:e3c0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:e400::,2a00:e400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e440::,2a00:e440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e480::,2a00:e480:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:e4c0::,2a00:e4c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:e500::,2a00:e500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e540::,2a00:e540:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:e580::,2a00:e580:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:e5c0::,2a00:e5c0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:e600::,2a00:e600:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:e640::,2a00:e640:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:e680::,2a00:e680:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:e6c0::,2a00:e6c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:e700::,2a00:e700:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e740::,2a00:e740:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e780::,2a00:e780:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:e7c0::,2a00:e7c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:e800::,2a00:e807:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:e840::,2a00:e840:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e880::,2a00:e880:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e8c0::,2a00:e8c0:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a00:e900::,2a00:e900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:e940::,2a00:e940:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:e980::,2a00:e980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e9c0::,2a00:e9c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:ea00::,2a00:ea00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:ea40::,2a00:ea40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ea80::,2a00:ea80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:eac0::,2a00:eac0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:eb00::,2a00:eb00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:eb40::,2a00:eb40:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:eb80::,2a00:eb80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ebc0::,2a00:ebc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:ec00::,2a00:ec00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:ec40::,2a00:ec47:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ec80::,2a00:ec80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ecc0::,2a00:ecc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ed00::,2a00:ed00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ed40::,2a00:ed40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ed80::,2a00:ed80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:ee00::,2a00:ee00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ee40::,2a00:ee40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ee80::,2a00:ee80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:eec0::,2a00:eec0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:ef00::,2a00:ef00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:ef40::,2a00:ef40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:ef80::,2a00:ef80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:efc0::,2a00:efc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f000::,2a00:f000:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:f040::,2a00:f040:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f080::,2a00:f080:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:f0c0::,2a00:f0c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f100::,2a00:f100:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:f140::,2a00:f140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f180::,2a00:f180:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f1c0::,2a00:f1c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f200::,2a00:f200:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:f240::,2a00:f240:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:f280::,2a00:f280:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f2c0::,2a00:f2c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:f300::,2a00:f300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f340::,2a00:f340:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:f380::,2a00:f380:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:f3c0::,2a00:f3c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f400::,2a00:f400:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:f440::,2a00:f440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f480::,2a00:f480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f4c0::,2a00:f4c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f500::,2a00:f500:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:f540::,2a00:f540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f580::,2a00:f580:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:f5c0::,2a00:f5c0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:f600::,2a00:f600:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f640::,2a00:f640:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:f680::,2a00:f680:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f6c0::,2a00:f6c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:f700::,2a00:f700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f740::,2a00:f740:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:f780::,2a00:f780:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:f7c0::,2a00:f7c7:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:f800::,2a00:f800:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:f840::,2a00:f840:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:f880::,2a00:f880:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f8c0::,2a00:f8c0:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a00:f900::,2a00:f900:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:f940::,2a00:f940:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f980::,2a00:f980:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:f9c0::,2a00:f9c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:fa00::,2a00:fa00:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:fa40::,2a00:fa40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fa80::,2a00:fa80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:fac0::,2a00:fac0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fb00::,2a00:fb00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:fb40::,2a00:fb40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:fb80::,2a00:fb80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fbc0::,2a00:fbc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:fc00::,2a00:fc00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:fc40::,2a00:fc40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:fc80::,2a00:fc80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:fcc0::,2a00:fcc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fd00::,2a00:fd00:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:fd40::,2a00:fd40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:fd80::,2a00:fd80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:fdc0::,2a00:fdc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:fe00::,2a00:fe00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fe40::,2a00:fe40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:fe80::,2a00:fe80:ffff:ffff:ffff:ffff:ffff:ffff,ME
+2a00:fec0::,2a00:fec0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:ff00::,2a00:ff00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:ff40::,2a00:ff40:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:ff80::,2a00:ff80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:ffc0::,2a00:ffc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01::,2a01:0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:8::,2a01:8:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a01:10::,2a01:10:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a01:18::,2a01:18:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:20::,2a01:20:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:28::,2a01:28:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:30::,2a01:30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:38::,2a01:38:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:40::,2a01:40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:48::,2a01:48:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:50::,2a01:50:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:58::,2a01:58:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:68::,2a01:68:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:70::,2a01:70:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:78::,2a01:78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:80::,2a01:80:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a01:88::,2a01:88:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:90::,2a01:90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:98::,2a01:98:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a0::,2a01:a0:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a01:a8::,2a01:a8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:b0::,2a01:b1:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:b8::,2a01:b8:ffff:ffff:ffff:ffff:ffff:ffff,VA
+2a01:c0::,2a01:c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:c8::,2a01:c8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:d0::,2a01:d0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:d8::,2a01:d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:e0::,2a01:e0:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:e8::,2a01:e8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:f0::,2a01:f0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:f8::,2a01:f8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:100::,2a01:100:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:108::,2a01:108:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:110::,2a01:111:ffff:ffff:ffff:ffff:ffff:ffff,DZ
+2a01:120::,2a01:120:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:128::,2a01:128:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:130::,2a01:130:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:138::,2a01:138:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:140::,2a01:140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:148::,2a01:148:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:150::,2a01:150:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:158::,2a01:158:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a01:160::,2a01:160:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:168::,2a01:168:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:170::,2a01:170:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:178::,2a01:178:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:180::,2a01:180:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a01:188::,2a01:188:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:190::,2a01:190:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:198::,2a01:198:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:1a0::,2a01:1a0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:1a8::,2a01:1a8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:1b0::,2a01:1b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:1b8::,2a01:1b8:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a01:1c0::,2a01:1c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:1c8::,2a01:1c8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:1d0::,2a01:1d0:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a01:1d8::,2a01:1d8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:1e0::,2a01:1e0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:1e8::,2a01:1e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:1f0::,2a01:1f0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:1f8::,2a01:1f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:200::,2a01:200:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:208::,2a01:208:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:210::,2a01:210:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:220::,2a01:220:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:228::,2a01:228:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:230::,2a01:230:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:238::,2a01:238:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:240::,2a01:240:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:248::,2a01:248:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:250::,2a01:250:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:258::,2a01:258:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:260::,2a01:260:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a01:268::,2a01:268:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:270::,2a01:270:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:278::,2a01:278:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:280::,2a01:280:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:288::,2a01:288:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:290::,2a01:290:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:298::,2a01:298:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:2a0::,2a01:2a0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:2a8::,2a01:2a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:2b0::,2a01:2b7:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:2b8::,2a01:2b8:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a01:2c0::,2a01:2c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:2c8::,2a01:2c8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:2d0::,2a01:2d0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:2d8::,2a01:2d8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:2e0::,2a01:2ef:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:300::,2a01:307:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a01:308::,2a01:308:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:310::,2a01:310:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:320::,2a01:320:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a01:328::,2a01:328:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:330::,2a01:330:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:338::,2a01:338:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:340::,2a01:340:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:348::,2a01:348:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:350::,2a01:350:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:358::,2a01:358:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:360::,2a01:360:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:368::,2a01:36f:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:378::,2a01:378:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:380::,2a01:380:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:388::,2a01:388:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:390::,2a01:390:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:398::,2a01:398:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:3a0::,2a01:3a0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:3a8::,2a01:3a8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:3b0::,2a01:3b0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a01:3b8::,2a01:3b8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:3c0::,2a01:3c0:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a01:3c8::,2a01:3c8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:3d8::,2a01:3d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:3e0::,2a01:3e0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a01:3e8::,2a01:3e8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:3f0::,2a01:3f0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:3f8::,2a01:3f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:400::,2a01:400:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:408::,2a01:408:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:410::,2a01:410:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:418::,2a01:418:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:420::,2a01:420:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:428::,2a01:428:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:430::,2a01:430:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:438::,2a01:438:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:440::,2a01:440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:448::,2a01:448:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:450::,2a01:450:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:458::,2a01:458:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:460::,2a01:460:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:468::,2a01:468:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:470::,2a01:470:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:478::,2a01:47f:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a01:480::,2a01:480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:488::,2a01:488:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:490::,2a01:490:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:498::,2a01:498:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:4a0::,2a01:4a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4a8::,2a01:4a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4b0::,2a01:4b0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:4c0::,2a01:4c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:4c8::,2a01:4cf:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4d0::,2a01:4d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4d8::,2a01:4d8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:4e0::,2a01:4e0:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a01:4e8::,2a01:4e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4f0::,2a01:4f0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:4f8::,2a01:4ff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:500::,2a01:500:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:508::,2a01:508:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:510::,2a01:510:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:518::,2a01:518:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:520::,2a01:520:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:528::,2a01:528:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:530::,2a01:530:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:538::,2a01:538:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:540::,2a01:540:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:548::,2a01:548:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:550::,2a01:550:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:558::,2a01:558:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:560::,2a01:560:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:568::,2a01:568:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:570::,2a01:570:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:578::,2a01:578:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:580::,2a01:580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:590::,2a01:590:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:598::,2a01:59f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5a0::,2a01:5a0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5a8::,2a01:5a8:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:5b0::,2a01:5b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5b8::,2a01:5b8:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a01:5c0::,2a01:5c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5c8::,2a01:5c8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5d0::,2a01:5d0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:5d8::,2a01:5d8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:5e0::,2a01:5e0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:5e8::,2a01:5e8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:5f0::,2a01:5f0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:5f8::,2a01:5f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:600::,2a01:600:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:608::,2a01:608:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a01:610::,2a01:610:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:618::,2a01:618:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:620::,2a01:620:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:628::,2a01:628:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:630::,2a01:630:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:638::,2a01:638:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a01:640::,2a01:647:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:648::,2a01:648:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:650::,2a01:650:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:658::,2a01:658:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:660::,2a01:667:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:668::,2a01:668:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:670::,2a01:670:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:678::,2a01:678:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:680::,2a01:680:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:688::,2a01:688:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:690::,2a01:690:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:698::,2a01:698:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6a0::,2a01:6a0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:6a8::,2a01:6a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:6b0::,2a01:6b0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:6b8::,2a01:6b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6c0::,2a01:6c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6c8::,2a01:6c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6d0::,2a01:6d0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:6d8::,2a01:6d8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6e0::,2a01:6e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6e8::,2a01:6e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6f0::,2a01:6f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6f8::,2a01:6f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:700::,2a01:700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:710::,2a01:710:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:718::,2a01:718:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:720::,2a01:720:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:728::,2a01:72f:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:730::,2a01:730:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:738::,2a01:738:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:740::,2a01:740:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:748::,2a01:748:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:750::,2a01:750:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:758::,2a01:758:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:760::,2a01:760:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:768::,2a01:768:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:770::,2a01:770:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:778::,2a01:778:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:780::,2a01:780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:788::,2a01:788:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:790::,2a01:790:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:798::,2a01:79f:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:7a0::,2a01:7a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7a8::,2a01:7a8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7b0::,2a01:7b0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:7b8::,2a01:7b8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7c0::,2a01:7c0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:7c8::,2a01:7c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:7d0::,2a01:7d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7d8::,2a01:7d8:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a01:7e0::,2a01:7e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7e8::,2a01:7e8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:7f0::,2a01:7f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7f8::,2a01:7f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:800::,2a01:8ff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:c00::,2a01:c3f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:e00::,2a01:e3f:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:1000::,2a01:17ff:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:2000::,2a01:2fff:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4000::,2a01:4000:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a01:4040::,2a01:4040:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:4080::,2a01:4080:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:40c0::,2a01:40c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:41c0::,2a01:41c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4200::,2a01:4200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4240::,2a01:4240:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:4280::,2a01:4280:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a01:42c0::,2a01:42c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:4300::,2a01:4300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4340::,2a01:4340:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:4380::,2a01:4380:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:43c0::,2a01:43c0:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a01:4400::,2a01:4400:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:4440::,2a01:4440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4480::,2a01:4480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:44c0::,2a01:44c0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:4500::,2a01:4500:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a01:4540::,2a01:4540:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4580::,2a01:4580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:45c0::,2a01:45c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:4600::,2a01:4600:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a01:4640::,2a01:4640:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4680::,2a01:4680:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a01:46c0::,2a01:46c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:4700::,2a01:4700:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4740::,2a01:4740:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a01:4780::,2a01:4780:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a01:47c0::,2a01:47c0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:4800::,2a01:4800:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4840::,2a01:4840:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4880::,2a01:4880:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:48c0::,2a01:48c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4900::,2a01:4900:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a01:4940::,2a01:4940:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4980::,2a01:4980:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:49c0::,2a01:49c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4a00::,2a01:4a00:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a01:4a40::,2a01:4a40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:4a80::,2a01:4a80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:4ac0::,2a01:4ac0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:4b00::,2a01:4b00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4b40::,2a01:4b40:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:4b80::,2a01:4b80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:4bc0::,2a01:4bc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4c00::,2a01:4c00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:4c40::,2a01:4c40:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:4c80::,2a01:4c80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4cc0::,2a01:4cc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4d00::,2a01:4d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4d40::,2a01:4d40:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:4d80::,2a01:4d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4dc0::,2a01:4dc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4e00::,2a01:4e00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:4e40::,2a01:4e40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4e80::,2a01:4e80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4ec0::,2a01:4ec0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4f00::,2a01:4f00:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a01:4f40::,2a01:4f40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4f80::,2a01:4f80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4fc0::,2a01:4fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5000::,2a01:5000:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5040::,2a01:5047:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:5080::,2a01:5080:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:50c0::,2a01:50c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5100::,2a01:5100:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:5140::,2a01:5140:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:5180::,2a01:5180:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:51c0::,2a01:51c0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:5200::,2a01:5200:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:5240::,2a01:5240:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5280::,2a01:5280:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:52c0::,2a01:52c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5300::,2a01:5300:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:5340::,2a01:5340:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5380::,2a01:5380:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:53c0::,2a01:53c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5400::,2a01:5400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5440::,2a01:5440:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:5480::,2a01:5480:ffff:ffff:ffff:ffff:ffff:ffff,GG
+2a01:54c0::,2a01:54c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:5500::,2a01:5500:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:5540::,2a01:5540:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:5580::,2a01:5580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:55c0::,2a01:55c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5600::,2a01:5600:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:5640::,2a01:5640:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5680::,2a01:5680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:56c0::,2a01:56c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5700::,2a01:5700:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:5740::,2a01:5740:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:5780::,2a01:5780:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:57c0::,2a01:57c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5800::,2a01:5800:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:5840::,2a01:5840:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:5900::,2a01:5900:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5940::,2a01:5940:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:5980::,2a01:5980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:59c0::,2a01:59c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5a00::,2a01:5a00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:5a40::,2a01:5a40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5a80::,2a01:5a80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a01:5ac0::,2a01:5ac0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5b00::,2a01:5b00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5b40::,2a01:5b40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:5b80::,2a01:5b80:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:5bc0::,2a01:5bc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:5c00::,2a01:5c00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:5c40::,2a01:5c40:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:5c80::,2a01:5c80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5cc0::,2a01:5cc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:5d00::,2a01:5d00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5d40::,2a01:5d40:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:5d80::,2a01:5d80:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a01:5dc0::,2a01:5dc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:5e00::,2a01:5e00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:5e40::,2a01:5e40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5e80::,2a01:5e80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:5ec0::,2a01:5ec0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:5f00::,2a01:5f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5f40::,2a01:5f40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5f80::,2a01:5f80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:5fc0::,2a01:5fc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6000::,2a01:6000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6040::,2a01:6040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6080::,2a01:6080:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:60c0::,2a01:60c0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:6100::,2a01:6100:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6140::,2a01:6140:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:6180::,2a01:6180:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:61c0::,2a01:61c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6200::,2a01:6200:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:6240::,2a01:6240:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6280::,2a01:6280:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:62c0::,2a01:62c0:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a01:6300::,2a01:6300:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:6340::,2a01:6340:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:6380::,2a01:6380:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:63c0::,2a01:63c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:6400::,2a01:6400:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:6440::,2a01:6440:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a01:6480::,2a01:6480:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a01:64c0::,2a01:64c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6500::,2a01:6500:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a01:6540::,2a01:6540:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6580::,2a01:6580:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:65c0::,2a01:65c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:6600::,2a01:6600:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6640::,2a01:6640:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:6680::,2a01:6680:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:66c0::,2a01:66c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6700::,2a01:6700:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a01:6740::,2a01:6740:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6780::,2a01:6780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:67c0::,2a01:67c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:6800::,2a01:6800:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6840::,2a01:6840:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:6880::,2a01:6880:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:68c0::,2a01:68c0:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:6900::,2a01:6900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:6940::,2a01:6940:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6980::,2a01:6980:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:69c0::,2a01:69c0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:6a00::,2a01:6a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6a40::,2a01:6a40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:6a80::,2a01:6a80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:6ac0::,2a01:6ac0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6b00::,2a01:6b00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6b40::,2a01:6b40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:6b80::,2a01:6b80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:6bc0::,2a01:6bc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6c00::,2a01:6c00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6c40::,2a01:6c40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:6c80::,2a01:6c80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:6cc0::,2a01:6cc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6d00::,2a01:6d00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:6d40::,2a01:6d40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:6d80::,2a01:6d80:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:6dc0::,2a01:6dc0:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a01:6e00::,2a01:6e00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6e40::,2a01:6e40:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a01:6e80::,2a01:6e80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6ec0::,2a01:6ec0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6f00::,2a01:6f00:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:6f40::,2a01:6f40:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:6f80::,2a01:6f80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:6fc0::,2a01:6fc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:7000::,2a01:7000:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7040::,2a01:7040:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:7080::,2a01:7080:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:70c0::,2a01:70c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7100::,2a01:7100:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7140::,2a01:7140:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7180::,2a01:7180:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:71c0::,2a01:71c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:7200::,2a01:7200:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:7240::,2a01:7240:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:7280::,2a01:7280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7300::,2a01:7300:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:7340::,2a01:7340:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:7380::,2a01:7380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:73c0::,2a01:73c0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a01:7400::,2a01:7400:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:7440::,2a01:7440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7480::,2a01:7480:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:74c0::,2a01:74c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7500::,2a01:7500:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:7540::,2a01:7540:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7580::,2a01:7580:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:75c0::,2a01:75c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7600::,2a01:7600:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:7640::,2a01:7640:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:7680::,2a01:7680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:76c0::,2a01:76c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7700::,2a01:7700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7740::,2a01:7740:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7780::,2a01:7780:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a01:77c0::,2a01:77c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:7800::,2a01:7800:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7840::,2a01:7840:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7880::,2a01:7880:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:78c0::,2a01:78c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7900::,2a01:7900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:7940::,2a01:7940:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7980::,2a01:7980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:79c0::,2a01:79c0:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a01:7a00::,2a01:7a00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:7a40::,2a01:7a40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7a80::,2a01:7a80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:7ac0::,2a01:7ac0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7b00::,2a01:7b00:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a01:7b40::,2a01:7b40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7b80::,2a01:7b80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7bc0::,2a01:7bc0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:7c00::,2a01:7c00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:7c40::,2a01:7c40:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a01:7c80::,2a01:7c80:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a01:7cc0::,2a01:7cc0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:7d00::,2a01:7d00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:7d40::,2a01:7d40:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:7d80::,2a01:7d80:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:7e00::,2a01:7e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7e40::,2a01:7e40:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a01:7e80::,2a01:7e80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7ec0::,2a01:7ec0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:7f00::,2a01:7f00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7f40::,2a01:7f40:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a01:7f80::,2a01:7f80:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a01:7fc0::,2a01:7fc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8000::,2a01:8000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8040::,2a01:8040:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8080::,2a01:8080:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a01:80c0::,2a01:80c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:8100::,2a01:8100:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:8140::,2a01:8140:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:8180::,2a01:8180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:81c0::,2a01:81c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8200::,2a01:8200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:8240::,2a01:8240:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8280::,2a01:8280:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:82c0::,2a01:82c0:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a01:8300::,2a01:8300:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:8340::,2a01:8340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8380::,2a01:8380:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:83c0::,2a01:83c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:8400::,2a01:8400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8440::,2a01:8440:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:8480::,2a01:8480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:84c0::,2a01:84c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8500::,2a01:8500:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:8540::,2a01:8540:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:8580::,2a01:8580:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:85c0::,2a01:85c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8600::,2a01:8600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8640::,2a01:8640:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8680::,2a01:8680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:86c0::,2a01:86c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:8700::,2a01:8700:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a01:8740::,2a01:8740:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:8780::,2a01:8780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:87c0::,2a01:87c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8800::,2a01:8800:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:8840::,2a01:8840:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:8880::,2a01:8880:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:88c0::,2a01:88c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8900::,2a01:8900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8940::,2a01:8940:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8980::,2a01:8980:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:89c0::,2a01:89c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:8a00::,2a01:8a00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8a40::,2a01:8a40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8a80::,2a01:8a80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:8ac0::,2a01:8ac0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:8b00::,2a01:8b00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:8b40::,2a01:8b40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:8b80::,2a01:8b80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:8bc0::,2a01:8bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8c00::,2a01:8c00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:8c40::,2a01:8c40:ffff:ffff:ffff:ffff:ffff:ffff,GI
+2a01:8c80::,2a01:8c80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:8cc0::,2a01:8cc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:8d00::,2a01:8d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:8d40::,2a01:8d47:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:8d80::,2a01:8d80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:8dc0::,2a01:8dc0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:8e00::,2a01:8e00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:8e40::,2a01:8e40:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a01:8e80::,2a01:8e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:8ec0::,2a01:8ec0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:8f00::,2a01:8f00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8f40::,2a01:8f40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:8f80::,2a01:8f80:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:8fc0::,2a01:8fc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:9000::,2a01:9000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9040::,2a01:9040:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a01:9080::,2a01:9080:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:90c0::,2a01:90c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9100::,2a01:9100:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:9140::,2a01:9140:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:9180::,2a01:9180:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:91c0::,2a01:91c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:9240::,2a01:9240:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a01:9280::,2a01:9280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:92c0::,2a01:92c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9300::,2a01:9300:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9340::,2a01:9340:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:9380::,2a01:9380:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:93c0::,2a01:93c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9400::,2a01:9400:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:9440::,2a01:9440:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:9480::,2a01:9480:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:94c0::,2a01:94c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9500::,2a01:9500:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9540::,2a01:9540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9580::,2a01:9580:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:95c0::,2a01:95c0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:9600::,2a01:9600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9640::,2a01:9640:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:9680::,2a01:9680:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:96c0::,2a01:96c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9700::,2a01:9700:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a01:9740::,2a01:9740:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9780::,2a01:9780:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:97c0::,2a01:97c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:9800::,2a01:9800:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:9840::,2a01:9840:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9880::,2a01:9880:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:98c0::,2a01:98c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9900::,2a01:9900:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:9940::,2a01:9940:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9980::,2a01:9980:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:9a00::,2a01:9a00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9a40::,2a01:9a40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9a80::,2a01:9a80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9ac0::,2a01:9ac0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9b00::,2a01:9b00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:9b40::,2a01:9b40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:9b80::,2a01:9b80:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:9bc0::,2a01:9bc0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:9c00::,2a01:9c00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9c40::,2a01:9c41:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9c80::,2a01:9c80:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a01:9cc0::,2a01:9cc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9d00::,2a01:9d00:ffff:ffff:ffff:ffff:ffff:ffff,KG
+2a01:9d40::,2a01:9d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:9d80::,2a01:9d80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9dc0::,2a01:9dc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:9e00::,2a01:9e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9e40::,2a01:9e40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:9e80::,2a01:9e80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9ec0::,2a01:9ec0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:9f00::,2a01:9f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9f40::,2a01:9f40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:9f80::,2a01:9f80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:9fc0::,2a01:9fc0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:a000::,2a01:a000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a040::,2a01:a040:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:a080::,2a01:a080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a0c0::,2a01:a0c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a100::,2a01:a100:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:a140::,2a01:a140:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a180::,2a01:a180:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a01:a1c0::,2a01:a1c0:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a01:a200::,2a01:a200:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a240::,2a01:a240:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:a280::,2a01:a280:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:a2c0::,2a01:a2c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a300::,2a01:a300:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:a340::,2a01:a340:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:a380::,2a01:a380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a3c0::,2a01:a3c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a400::,2a01:a400:ffff:ffff:ffff:ffff:ffff:ffff,JE
+2a01:a440::,2a01:a440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:a480::,2a01:a480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a4c0::,2a01:a4c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:a500::,2a01:a500:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a540::,2a01:a540:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:a580::,2a01:a580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:a5c0::,2a01:a5c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a600::,2a01:a600:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:a640::,2a01:a640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a680::,2a01:a680:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a6c0::,2a01:a6c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:a700::,2a01:a700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a740::,2a01:a740:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a780::,2a01:a780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a7c0::,2a01:a7c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:a800::,2a01:a800:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:a840::,2a01:a840:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:a880::,2a01:a880:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a01:a8c0::,2a01:a8c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:a900::,2a01:a900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:a940::,2a01:a940:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:a980::,2a01:a980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a9c0::,2a01:a9c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:aa00::,2a01:aa00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:aa40::,2a01:aa40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:aa80::,2a01:aa80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:aac0::,2a01:aac0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:ab00::,2a01:ab00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:ab40::,2a01:ab40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:abc0::,2a01:abc0:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a01:ac00::,2a01:ac00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:ac40::,2a01:ac40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:ac80::,2a01:ac80:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a01:acc0::,2a01:acc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:ad00::,2a01:ad00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:ad40::,2a01:ad40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:ad80::,2a01:ad80:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:adc0::,2a01:adc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:ae00::,2a01:ae00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:ae40::,2a01:ae40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:ae80::,2a01:ae80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:aec0::,2a01:aec0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:af00::,2a01:af00:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:af40::,2a01:af40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:af80::,2a01:af80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:afc0::,2a01:afc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:b000::,2a01:b000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b040::,2a01:b040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b080::,2a01:b080:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:b0c0::,2a01:b0c0:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:b100::,2a01:b100:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b140::,2a01:b140:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:b180::,2a01:b180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:b1c0::,2a01:b1c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:b200::,2a01:b200:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:b240::,2a01:b240:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b280::,2a01:b280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b2c0::,2a01:b2c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b300::,2a01:b307:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:b340::,2a01:b340:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:b380::,2a01:b380:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:b3c0::,2a01:b3c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b400::,2a01:b400:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b440::,2a01:b440:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:b480::,2a01:b480:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:b4c0::,2a01:b4c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:b500::,2a01:b500:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a01:b540::,2a01:b540:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b580::,2a01:b580:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:b5c0::,2a01:b5c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:b600::,2a01:b600:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:b640::,2a01:b640:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:b680::,2a01:b680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:b6c0::,2a01:b6c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:b700::,2a01:b700:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:b740::,2a01:b740:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:b780::,2a01:b780:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a01:b7c0::,2a01:b7c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b800::,2a01:b800:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a01:b840::,2a01:b840:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b880::,2a01:b880:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:b8c0::,2a01:b8c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:b900::,2a01:b900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:b940::,2a01:b940:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:b980::,2a01:b980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b9c0::,2a01:b9c0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:ba00::,2a01:ba00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:ba40::,2a01:ba40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:ba80::,2a01:ba80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:bac0::,2a01:bac0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:bb40::,2a01:bb40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:bb80::,2a01:bb80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:bbc0::,2a01:bbc0:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a01:bc00::,2a01:bc00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:bc40::,2a01:bc40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:bc80::,2a01:bc80:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a01:bcc0::,2a01:bcc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:bd00::,2a01:bd00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:bd40::,2a01:bd40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:bd80::,2a01:bd80:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:bdc0::,2a01:bdc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:be00::,2a01:be00:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:be40::,2a01:be40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:be80::,2a01:be80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:bec0::,2a01:bec0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:bf00::,2a01:bf00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:bf40::,2a01:bf40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:bf80::,2a01:bf80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:bfc0::,2a01:bfc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:c000::,2a01:dfff:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02::,2a02:0:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:8::,2a02:8:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:10::,2a02:10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:18::,2a02:18:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:20::,2a02:20:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:28::,2a02:28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:30::,2a02:30:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:38::,2a02:38:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:40::,2a02:40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:48::,2a02:48:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:50::,2a02:50:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:58::,2a02:58:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:60::,2a02:60:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:68::,2a02:68:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:70::,2a02:70:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:78::,2a02:78:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:80::,2a02:80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:88::,2a02:88:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:90::,2a02:90:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:98::,2a02:98:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:a0::,2a02:a0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:a8::,2a02:a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b0::,2a02:b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b8::,2a02:b8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:c0::,2a02:c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:c8::,2a02:c8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:d0::,2a02:d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:d8::,2a02:d8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:e0::,2a02:e0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:e8::,2a02:e8:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:f0::,2a02:f0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:f8::,2a02:f8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:100::,2a02:100:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:108::,2a02:108:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:110::,2a02:110:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:118::,2a02:118:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:120::,2a02:120:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:128::,2a02:128:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:130::,2a02:130:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:138::,2a02:138:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:140::,2a02:140:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:148::,2a02:148:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:150::,2a02:150:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:158::,2a02:158:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:160::,2a02:160:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:168::,2a02:168:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:170::,2a02:170:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:178::,2a02:178:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:180::,2a02:180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:188::,2a02:18f:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:190::,2a02:190:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:198::,2a02:198:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:1a0::,2a02:1a0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1a8::,2a02:1a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1b0::,2a02:1b0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:1b8::,2a02:1b8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:1c0::,2a02:1c0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:1c8::,2a02:1c8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1d0::,2a02:1d0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1d8::,2a02:1d8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1e0::,2a02:1e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1e8::,2a02:1e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1f0::,2a02:1f0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1f8::,2a02:1f8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:200::,2a02:200:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:208::,2a02:208:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:210::,2a02:210:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:218::,2a02:218:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:220::,2a02:220:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:228::,2a02:22f:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:230::,2a02:230:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:238::,2a02:238:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:240::,2a02:240:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:248::,2a02:248:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:250::,2a02:250:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:258::,2a02:258:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:260::,2a02:260:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:268::,2a02:268:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:270::,2a02:270:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:278::,2a02:278:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:280::,2a02:280:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:288::,2a02:288:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:290::,2a02:290:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:298::,2a02:298:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2a0::,2a02:2a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2a8::,2a02:2a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2b0::,2a02:2b0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2b8::,2a02:2b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2c0::,2a02:2c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2c8::,2a02:2c8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2d0::,2a02:2d0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2d8::,2a02:2d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2e0::,2a02:2e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2e8::,2a02:2e8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2f0::,2a02:2f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2f8::,2a02:2f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:300::,2a02:300:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:308::,2a02:308:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:310::,2a02:310:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:318::,2a02:318:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:320::,2a02:320:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:328::,2a02:328:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:330::,2a02:330:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:338::,2a02:338:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:340::,2a02:340:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:348::,2a02:348:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:350::,2a02:350:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:358::,2a02:358:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:360::,2a02:360:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:368::,2a02:368:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:370::,2a02:370:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:380::,2a02:380:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a02:388::,2a02:388:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:390::,2a02:390:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:398::,2a02:398:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:3a0::,2a02:3a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:3a8::,2a02:3a8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:3b0::,2a02:3b0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:3b8::,2a02:3b8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:3c0::,2a02:3c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:3c8::,2a02:3c8:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:3d0::,2a02:3d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a02:3d8::,2a02:3d8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:3e0::,2a02:3e0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:3e8::,2a02:3e8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:3f0::,2a02:3f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:3f8::,2a02:3f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:400::,2a02:400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:408::,2a02:408:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:410::,2a02:410:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:418::,2a02:418:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:420::,2a02:420:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:428::,2a02:428:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:430::,2a02:430:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:438::,2a02:438:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:440::,2a02:440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:448::,2a02:448:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:450::,2a02:450:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:458::,2a02:458:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:460::,2a02:460:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:468::,2a02:468:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:470::,2a02:470:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:478::,2a02:478:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:480::,2a02:480:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:488::,2a02:488:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:490::,2a02:490:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:498::,2a02:498:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4a0::,2a02:4a0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:4a8::,2a02:4a8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:4b0::,2a02:4b0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:4b8::,2a02:4b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:4c0::,2a02:4c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:4c8::,2a02:4c8:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:4d0::,2a02:4d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4d8::,2a02:4d8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:4e0::,2a02:4e0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:4e8::,2a02:4e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4f0::,2a02:4f0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:4f8::,2a02:4f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:500::,2a02:500:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:508::,2a02:508:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:510::,2a02:510:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:518::,2a02:518:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:520::,2a02:520:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:530::,2a02:530:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:538::,2a02:538:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:540::,2a02:540:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:548::,2a02:548:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:550::,2a02:550:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:558::,2a02:558:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:560::,2a02:560:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:568::,2a02:568:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:570::,2a02:570:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:578::,2a02:578:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:580::,2a02:587:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:588::,2a02:588:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:590::,2a02:590:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:598::,2a02:598:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5a0::,2a02:5a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:5b0::,2a02:5b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:5b8::,2a02:5b8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5c0::,2a02:5c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:5c8::,2a02:5c8:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:5d0::,2a02:5d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:5d8::,2a02:5d8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:5e0::,2a02:5e0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:5f0::,2a02:5f0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:5f8::,2a02:5f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:600::,2a02:600:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:608::,2a02:608:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:610::,2a02:610:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:618::,2a02:618:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:620::,2a02:620:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:628::,2a02:628:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:630::,2a02:630:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:638::,2a02:638:ffff:ffff:ffff:ffff:ffff:ffff,GI
+2a02:640::,2a02:640:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:648::,2a02:648:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:650::,2a02:650:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:658::,2a02:658:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:660::,2a02:660:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a02:668::,2a02:668:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:670::,2a02:670:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:678::,2a02:678:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:680::,2a02:680:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:688::,2a02:688:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:690::,2a02:690:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:698::,2a02:698:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6a0::,2a02:6a0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:6a8::,2a02:6a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:6b0::,2a02:6b0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6b8::,2a02:6b8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6c0::,2a02:6c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:6c8::,2a02:6c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:6d0::,2a02:6d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6d8::,2a02:6d8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:6e0::,2a02:6e0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:6e8::,2a02:6e8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6f0::,2a02:6f0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6f8::,2a02:6f8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:700::,2a02:700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:708::,2a02:708:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:710::,2a02:710:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:718::,2a02:718:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:720::,2a02:720:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:728::,2a02:728:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:730::,2a02:730:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:738::,2a02:738:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:740::,2a02:740:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:748::,2a02:748:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:750::,2a02:750:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:758::,2a02:758:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:760::,2a02:760:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:768::,2a02:768:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:770::,2a02:770:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:778::,2a02:778:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:780::,2a02:780:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:788::,2a02:788:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:790::,2a02:790:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:798::,2a02:798:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:7a0::,2a02:7a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7a8::,2a02:7a8:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:7b0::,2a02:7b0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:7b8::,2a02:7b8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:7c0::,2a02:7c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7c8::,2a02:7c8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:7d0::,2a02:7d0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:7d8::,2a02:7d8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:7e0::,2a02:7e0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:7e8::,2a02:7e8:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:7f0::,2a02:7f0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:7f8::,2a02:7f8:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:800::,2a02:800:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:808::,2a02:808:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:810::,2a02:810:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:818::,2a02:818:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:820::,2a02:820:ffff:ffff:ffff:ffff:ffff:ffff,KG
+2a02:828::,2a02:828:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:830::,2a02:830:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:838::,2a02:838:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:840::,2a02:840:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:848::,2a02:848:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:850::,2a02:850:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:858::,2a02:858:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:860::,2a02:860:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:868::,2a02:868:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:870::,2a02:870:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:878::,2a02:878:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:880::,2a02:880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:888::,2a02:888:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:890::,2a02:890:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:898::,2a02:898:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:8a0::,2a02:8a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8a8::,2a02:8a8:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:8b0::,2a02:8b0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:8b8::,2a02:8b8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8c0::,2a02:8c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8c8::,2a02:8c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:8d0::,2a02:8d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:8d8::,2a02:8d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:8e0::,2a02:8e0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:8e8::,2a02:8e8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:8f0::,2a02:8f0:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:8f8::,2a02:8f8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:900::,2a02:900:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:908::,2a02:908:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:910::,2a02:910:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:918::,2a02:918:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:920::,2a02:920:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:928::,2a02:928:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:930::,2a02:930:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:938::,2a02:938:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:940::,2a02:940:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:948::,2a02:948:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:950::,2a02:950:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:958::,2a02:958:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:960::,2a02:960:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:968::,2a02:968:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:970::,2a02:970:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:978::,2a02:978:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:980::,2a02:980:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:988::,2a02:988:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:990::,2a02:990:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:998::,2a02:998:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:9a0::,2a02:9a0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:9a8::,2a02:9a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:9b0::,2a02:9b0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:9b8::,2a02:9b9:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:9c0::,2a02:9c0:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a02:9c8::,2a02:9c8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:9d0::,2a02:9d0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:9d8::,2a02:9d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:9e0::,2a02:9e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:9e8::,2a02:9e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:9f0::,2a02:9f0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:9f8::,2a02:9f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:a00::,2a02:a00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:a08::,2a02:a08:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a10::,2a02:a10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a18::,2a02:a18:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:a20::,2a02:a20:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:a28::,2a02:a28:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:a30::,2a02:a30:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a02:a38::,2a02:a38:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:a40::,2a02:a40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:a48::,2a02:a48:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:a50::,2a02:a50:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:a58::,2a02:a58:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:a60::,2a02:a60:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:a68::,2a02:a68:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:a70::,2a02:a70:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a78::,2a02:a78:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:a80::,2a02:a80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:a88::,2a02:a88:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:a90::,2a02:a90:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:a98::,2a02:a98:ffff:ffff:ffff:ffff:ffff:ffff,UZ
+2a02:aa0::,2a02:aa0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:aa8::,2a02:aa9:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:ab0::,2a02:ab0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:ab8::,2a02:ab8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:ac0::,2a02:ac0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:ac8::,2a02:ac8:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a02:ad0::,2a02:ad0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ad8::,2a02:ad8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:ae0::,2a02:ae0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ae8::,2a02:ae8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:af0::,2a02:af0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:af8::,2a02:af8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b00::,2a02:b00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b08::,2a02:b08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b10::,2a02:b10:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b18::,2a02:b18:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:b20::,2a02:b20:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:b28::,2a02:b28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b30::,2a02:b30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b38::,2a02:b38:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:b48::,2a02:b48:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:b50::,2a02:b50:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b58::,2a02:b58:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a02:b60::,2a02:b60:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a02:b70::,2a02:b70:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:b78::,2a02:b78:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b80::,2a02:b87:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b88::,2a02:b88:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:b90::,2a02:b90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b98::,2a02:b98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ba0::,2a02:ba0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:ba8::,2a02:ba8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:bb0::,2a02:bb0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:bb8::,2a02:bb8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:bc0::,2a02:bc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:bc8::,2a02:bc8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:bd0::,2a02:bd0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:bd8::,2a02:bd8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:be0::,2a02:be0:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:be8::,2a02:be8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:bf0::,2a02:bf0:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a02:bf8::,2a02:bf8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c00::,2a02:c00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c08::,2a02:c08:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a02:c10::,2a02:c10:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:c18::,2a02:c18:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:c20::,2a02:c20:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:c28::,2a02:c28:ffff:ffff:ffff:ffff:ffff:ffff,JE
+2a02:c30::,2a02:c30:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c38::,2a02:c38:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:c40::,2a02:c47:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:c48::,2a02:c48:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c50::,2a02:c50:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c58::,2a02:c58:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:c60::,2a02:c60:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:c68::,2a02:c68:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c70::,2a02:c70:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:c78::,2a02:c7f:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c80::,2a02:c80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:c88::,2a02:c88:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:c90::,2a02:c90:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c98::,2a02:c98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ca0::,2a02:ca0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:ca8::,2a02:ca8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:cb0::,2a02:cb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:cb8::,2a02:cb8:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:cc0::,2a02:cc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:cc8::,2a02:cc8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:cd0::,2a02:cd0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:cd8::,2a02:cd8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:ce0::,2a02:ce0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:ce8::,2a02:ce8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:cf0::,2a02:cf0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:d00::,2a02:d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:d08::,2a02:d08:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:d10::,2a02:d10:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:d18::,2a02:d18:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a02:d20::,2a02:d20:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:d28::,2a02:d28:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:d30::,2a02:d30:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:d38::,2a02:d38:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:d40::,2a02:d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:d48::,2a02:d48:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:d50::,2a02:d50:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:d58::,2a02:d58:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:d60::,2a02:d60:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:d68::,2a02:d68:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:d70::,2a02:d70:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:d78::,2a02:d78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:d80::,2a02:d80:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:d88::,2a02:d88:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:d90::,2a02:d90:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:d98::,2a02:d98:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:da8::,2a02:da8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:db0::,2a02:db0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:db8::,2a02:db8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:dc0::,2a02:dc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:dc8::,2a02:dc8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:dd0::,2a02:dd0:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a02:dd8::,2a02:dd8:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:de0::,2a02:de0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:de8::,2a02:de8:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:df0::,2a02:df0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:df8::,2a02:df8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:e00::,2a02:e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:e08::,2a02:e08:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:e10::,2a02:e10:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:e20::,2a02:e20:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:e28::,2a02:e28:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:e30::,2a02:e30:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:e38::,2a02:e38:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:e40::,2a02:e40:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a02:e48::,2a02:e48:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a02:e50::,2a02:e50:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:e58::,2a02:e58:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:e60::,2a02:e60:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:e68::,2a02:e68:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:e70::,2a02:e70:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:e78::,2a02:e78:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a02:e80::,2a02:e80:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:e88::,2a02:e88:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:e90::,2a02:e90:ffff:ffff:ffff:ffff:ffff:ffff,FO
+2a02:e98::,2a02:e98:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:ea0::,2a02:ea0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ea8::,2a02:ea8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:eb0::,2a02:eb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:eb8::,2a02:eb8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:ec0::,2a02:ec0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:ec8::,2a02:ec8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:ed0::,2a02:ed0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:ed8::,2a02:ed8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:ee0::,2a02:ee0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:ee8::,2a02:ee8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:ef0::,2a02:ef0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:ef8::,2a02:ef8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:f00::,2a02:f00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:f08::,2a02:f08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:f10::,2a02:f10:ffff:ffff:ffff:ffff:ffff:ffff,UZ
+2a02:f18::,2a02:f18:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:f20::,2a02:f20:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:f28::,2a02:f28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:f30::,2a02:f30:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:f38::,2a02:f38:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:f40::,2a02:f40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:f48::,2a02:f48:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:f50::,2a02:f50:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:f58::,2a02:f58:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:f60::,2a02:f60:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:f68::,2a02:f68:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:f70::,2a02:f70:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:f78::,2a02:f78:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:f80::,2a02:f80:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:f88::,2a02:f88:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a02:f90::,2a02:f90:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:f98::,2a02:f98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:fa0::,2a02:fa0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:fa8::,2a02:fa8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:fb0::,2a02:fb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:fb8::,2a02:fb8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:fc0::,2a02:fc0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:fc8::,2a02:fc8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:fd0::,2a02:fd0:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a02:fd8::,2a02:fd8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:fe0::,2a02:fe0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:fe8::,2a02:fe8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:ff0::,2a02:ff0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:ff8::,2a02:ff8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:1000::,2a02:103f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1200::,2a02:121f:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:1300::,2a02:1300:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:1308::,2a02:1308:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1310::,2a02:1310:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1318::,2a02:1318:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1320::,2a02:1320:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:1328::,2a02:1328:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1330::,2a02:1330:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1338::,2a02:1338:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:1340::,2a02:1340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1348::,2a02:1348:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1350::,2a02:1350:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1358::,2a02:1358:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:1360::,2a02:1360:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1368::,2a02:1368:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:1370::,2a02:1370:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:1378::,2a02:1378:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1380::,2a02:1380:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1388::,2a02:1388:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:1390::,2a02:1390:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:1398::,2a02:1398:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:13a0::,2a02:13a0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:13a8::,2a02:13a8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:13b0::,2a02:13b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:13b8::,2a02:13b8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:13c0::,2a02:13c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:13c8::,2a02:13c8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:13d0::,2a02:13d0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:13d8::,2a02:13d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:13e0::,2a02:13e0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:13e8::,2a02:13e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:13f0::,2a02:13f0:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:13f8::,2a02:13f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1400::,2a02:143f:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1600::,2a02:1600:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:1608::,2a02:1608:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1610::,2a02:1610:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1618::,2a02:1618:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a02:1620::,2a02:1620:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1628::,2a02:1628:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1630::,2a02:1630:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:1638::,2a02:1638:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1640::,2a02:1640:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:1648::,2a02:1648:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1650::,2a02:1650:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:1658::,2a02:1658:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1660::,2a02:1660:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:1668::,2a02:1668:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1670::,2a02:1670:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1678::,2a02:1678:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:1680::,2a02:1680:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1688::,2a02:1688:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:1690::,2a02:1690:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1698::,2a02:1698:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:16a0::,2a02:16a0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:16a8::,2a02:16a8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:16b0::,2a02:16b0:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a02:16b8::,2a02:16b8:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:16c0::,2a02:16c0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:16c8::,2a02:16c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:16d0::,2a02:16d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:16d8::,2a02:16d8:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:16e0::,2a02:16e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:16e8::,2a02:16e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:16f0::,2a02:16f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:16f8::,2a02:16f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1700::,2a02:1700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1708::,2a02:1708:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1710::,2a02:1710:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1718::,2a02:1718:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a02:1720::,2a02:1720:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1730::,2a02:1730:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:1738::,2a02:1738:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:1740::,2a02:1740:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:1748::,2a02:1748:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:1750::,2a02:1750:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1758::,2a02:1758:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:1760::,2a02:1760:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:1768::,2a02:1768:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1770::,2a02:1770:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:1778::,2a02:1778:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:1780::,2a02:1780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1788::,2a02:1788:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1790::,2a02:1790:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:1798::,2a02:179f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:17a0::,2a02:17a0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:17a8::,2a02:17a8:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:17b0::,2a02:17b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:17b8::,2a02:17b8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:17c0::,2a02:17c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:17c8::,2a02:17c8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:17d0::,2a02:17d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:17d8::,2a02:17d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:17e0::,2a02:17e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:17e8::,2a02:17e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:17f0::,2a02:17f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:17f8::,2a02:17f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1800::,2a02:18ff:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2000::,2a02:2000:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2008::,2a02:2008:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2010::,2a02:2010:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:2018::,2a02:2018:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2020::,2a02:2020:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:2028::,2a02:2028:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2030::,2a02:2030:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:2038::,2a02:2038:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2040::,2a02:2040:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2048::,2a02:2048:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2050::,2a02:2050:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2058::,2a02:2058:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2060::,2a02:2060:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2068::,2a02:2068:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2070::,2a02:2070:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2078::,2a02:2078:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:2080::,2a02:2080:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2088::,2a02:2088:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2090::,2a02:2090:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2098::,2a02:2098:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:20a0::,2a02:20a0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:20a8::,2a02:20a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:20b0::,2a02:20b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:20b8::,2a02:20b8:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a02:20c0::,2a02:20c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:20c8::,2a02:20c8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:20d0::,2a02:20d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:20d8::,2a02:20d8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:20e0::,2a02:20e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:20e8::,2a02:20e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:20f0::,2a02:20f0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:20f8::,2a02:20f8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2100::,2a02:2100:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2108::,2a02:2108:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2110::,2a02:2110:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2118::,2a02:211f:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2120::,2a02:2123:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2140::,2a02:2140:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2148::,2a02:214f:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:2150::,2a02:2150:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2158::,2a02:2158:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:2160::,2a02:2160:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:2168::,2a02:216f:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2170::,2a02:2170:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2178::,2a02:2178:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2180::,2a02:2180:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2188::,2a02:2188:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2190::,2a02:2190:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2198::,2a02:2198:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:21a0::,2a02:21a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:21a8::,2a02:21a8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:21b0::,2a02:21b0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:21b8::,2a02:21b8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:21c0::,2a02:21c0:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:21c8::,2a02:21c8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:21d0::,2a02:21d0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:21d8::,2a02:21d8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:21e0::,2a02:21e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:21e8::,2a02:21e8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:21f0::,2a02:21f0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:21f8::,2a02:21f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2200::,2a02:2200:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2208::,2a02:2208:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a02:2210::,2a02:2210:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2218::,2a02:2218:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2220::,2a02:2220:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2228::,2a02:2228:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2230::,2a02:2230:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:2238::,2a02:2238:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2240::,2a02:2240:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2248::,2a02:2248:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:2250::,2a02:2250:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2258::,2a02:2258:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2260::,2a02:2260:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2268::,2a02:2268:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2270::,2a02:2270:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2278::,2a02:2278:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2280::,2a02:2280:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2288::,2a02:2288:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2290::,2a02:2290:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:2298::,2a02:2298:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:22a0::,2a02:22a0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:22a8::,2a02:22a8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:22b0::,2a02:22b0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:22b8::,2a02:22b8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:22c0::,2a02:22c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:22c8::,2a02:22c8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:22d0::,2a02:22d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:22d8::,2a02:22d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:22e0::,2a02:22e0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:22e8::,2a02:22e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:22f0::,2a02:22f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:22f8::,2a02:22f8:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:2300::,2a02:2300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2308::,2a02:2308:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2310::,2a02:2310:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2318::,2a02:2318:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2320::,2a02:2320:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2328::,2a02:2328:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2330::,2a02:2330:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:2338::,2a02:2338:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2340::,2a02:2340:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2348::,2a02:2348:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2350::,2a02:2350:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2358::,2a02:2358:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2360::,2a02:2360:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2368::,2a02:2368:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2370::,2a02:2370:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:2378::,2a02:2378:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2380::,2a02:2380:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2388::,2a02:2388:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2390::,2a02:2390:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a02:2398::,2a02:2398:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:23a0::,2a02:23a0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:23a8::,2a02:23a8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:23b0::,2a02:23b0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:23b8::,2a02:23b8:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:23c0::,2a02:23c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:23c8::,2a02:23c8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:23d0::,2a02:23d0:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:23d8::,2a02:23d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:23e0::,2a02:23e0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:23e8::,2a02:23e8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:23f0::,2a02:23f0:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a02:23f8::,2a02:23f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2400::,2a02:2400:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2408::,2a02:2408:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2410::,2a02:2410:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2418::,2a02:2418:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2420::,2a02:2420:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2428::,2a02:2428:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2430::,2a02:2430:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2438::,2a02:2438:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2440::,2a02:2440:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2448::,2a02:2448:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2450::,2a02:2450:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2458::,2a02:2458:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2460::,2a02:2460:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:2468::,2a02:2468:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2470::,2a02:2470:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2478::,2a02:2478:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2480::,2a02:2480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2488::,2a02:2488:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2490::,2a02:2490:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2498::,2a02:2498:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:24a0::,2a02:24a0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:24a8::,2a02:24a8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:24b0::,2a02:24b0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:24b8::,2a02:24b8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:24c0::,2a02:24c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:24c8::,2a02:24c8:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:24d0::,2a02:24d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:24d8::,2a02:24d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:24e0::,2a02:24e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:24e8::,2a02:24e8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:24f0::,2a02:24f0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:24f8::,2a02:24f8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2500::,2a02:2500:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2508::,2a02:2508:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2510::,2a02:2510:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2518::,2a02:2518:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2520::,2a02:2520:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2528::,2a02:2528:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2530::,2a02:2530:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2538::,2a02:2538:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2540::,2a02:2540:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2548::,2a02:2548:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2550::,2a02:2550:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2558::,2a02:2558:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a02:2560::,2a02:2560:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2568::,2a02:2568:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2570::,2a02:2570:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2578::,2a02:2578:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a02:2580::,2a02:2580:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2588::,2a02:2588:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2590::,2a02:2590:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:2598::,2a02:2598:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:25a0::,2a02:25a0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:25a8::,2a02:25a8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:25b0::,2a02:25b0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:25b8::,2a02:25b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:25c0::,2a02:25c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:25c8::,2a02:25c8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:25d0::,2a02:25d0:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:25d8::,2a02:25d8:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a02:25e0::,2a02:25e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:25e8::,2a02:25e8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:25f0::,2a02:25f0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:25f8::,2a02:25f8:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:2600::,2a02:2600:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2608::,2a02:2608:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a02:2610::,2a02:2610:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2618::,2a02:2618:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2620::,2a02:2620:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2628::,2a02:2628:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:2630::,2a02:2630:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:2638::,2a02:2638:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2640::,2a02:2647:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2648::,2a02:2648:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2650::,2a02:2650:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2658::,2a02:2658:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2660::,2a02:2660:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:2668::,2a02:2668:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2670::,2a02:2670:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2678::,2a02:2678:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2680::,2a02:2680:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2688::,2a02:2688:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2690::,2a02:2690:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2698::,2a02:2698:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:26a0::,2a02:26a0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:26a8::,2a02:26a8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:26b0::,2a02:26b0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:26b8::,2a02:26b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:26c0::,2a02:26c0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:26c8::,2a02:26c8:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:26d0::,2a02:26d0:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a02:26d8::,2a02:26d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:26e0::,2a02:26e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:26e8::,2a02:26e8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:26f0::,2a02:26f0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:26f8::,2a02:26f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2700::,2a02:2700:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a02:2708::,2a02:2708:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2710::,2a02:2710:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2718::,2a02:2718:ffff:ffff:ffff:ffff:ffff:ffff,YE
+2a02:2720::,2a02:2720:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:2728::,2a02:2728:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2730::,2a02:2730:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2738::,2a02:2738:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2740::,2a02:2740:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2748::,2a02:2748:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2750::,2a02:2750:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2758::,2a02:2758:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2760::,2a02:2760:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2768::,2a02:2768:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2770::,2a02:2770:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2778::,2a02:2778:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2780::,2a02:2780:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2788::,2a02:2788:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2790::,2a02:2790:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2798::,2a02:2798:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:27a0::,2a02:27a0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:27a8::,2a02:27a8:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:27b0::,2a02:27b0:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:27b8::,2a02:27b8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:27c0::,2a02:27c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:27c8::,2a02:27c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:27d0::,2a02:27d0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:27d8::,2a02:27d8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:27e0::,2a02:27e0:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:27e8::,2a02:27e8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:27f0::,2a02:27f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:27f8::,2a02:27f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2800::,2a02:2800:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2808::,2a02:2808:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2810::,2a02:2810:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2818::,2a02:2818:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2820::,2a02:2820:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2828::,2a02:2828:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2830::,2a02:2830:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2838::,2a02:2838:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2840::,2a02:2840:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2848::,2a02:2848:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2850::,2a02:2850:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2858::,2a02:2858:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2860::,2a02:2860:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2868::,2a02:2868:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:2870::,2a02:2870:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2878::,2a02:2878:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2880::,2a02:2880:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:2888::,2a02:2888:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2890::,2a02:2890:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2898::,2a02:2898:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:28a0::,2a02:28a0:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:28a8::,2a02:28a8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:28b0::,2a02:28b7:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:28b8::,2a02:28b8:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:28c0::,2a02:28c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:28c8::,2a02:28c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:28d0::,2a02:28d0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:28d8::,2a02:28d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:28e0::,2a02:28e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:28e8::,2a02:28e8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:28f0::,2a02:28f0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:28f8::,2a02:28f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2900::,2a02:2900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2908::,2a02:2908:ffff:ffff:ffff:ffff:ffff:ffff,OM
+2a02:2910::,2a02:2910:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2918::,2a02:2918:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2920::,2a02:2920:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2928::,2a02:2928:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2930::,2a02:2930:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2938::,2a02:2938:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2940::,2a02:2940:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2948::,2a02:2948:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2950::,2a02:2950:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:2958::,2a02:2958:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2960::,2a02:2960:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:2968::,2a02:2968:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2970::,2a02:2970:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2978::,2a02:2978:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2980::,2a02:2980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2988::,2a02:2988:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2990::,2a02:2990:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2998::,2a02:2998:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:29a0::,2a02:29a0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:29a8::,2a02:29a8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:29b0::,2a02:29b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:29b8::,2a02:29b8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:29c0::,2a02:29c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:29c8::,2a02:29c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:29d0::,2a02:29d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:29d8::,2a02:29d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:29e0::,2a02:29e0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:29e8::,2a02:29e8:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:29f0::,2a02:29f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:29f8::,2a02:29f8:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a02:2a00::,2a02:2a00:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:2a08::,2a02:2a08:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2a10::,2a02:2a10:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2a18::,2a02:2a18:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2a20::,2a02:2a20:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2a28::,2a02:2a28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2a30::,2a02:2a30:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2a38::,2a02:2a38:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2a40::,2a02:2a40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2a48::,2a02:2a48:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2a50::,2a02:2a50:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a02:2a58::,2a02:2a58:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2a60::,2a02:2a60:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:2a68::,2a02:2a68:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2a70::,2a02:2a70:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:2a78::,2a02:2a78:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2a80::,2a02:2a80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2a88::,2a02:2a88:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2a90::,2a02:2a90:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:2a98::,2a02:2a98:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:2aa0::,2a02:2aa0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2aa8::,2a02:2aa8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2ab0::,2a02:2ab0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2ab8::,2a02:2ab8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2ac0::,2a02:2ac0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2ac8::,2a02:2ac8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2ad0::,2a02:2ad0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2ad8::,2a02:2ad8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2ae0::,2a02:2ae0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2ae8::,2a02:2ae8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2af0::,2a02:2af0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2af8::,2a02:2af8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2b00::,2a02:2b00:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2b08::,2a02:2b08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2b10::,2a02:2b10:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2b18::,2a02:2b18:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2b20::,2a02:2b20:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2b28::,2a02:2b28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2b30::,2a02:2b30:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2b38::,2a02:2b38:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2b40::,2a02:2b40:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:2b48::,2a02:2b48:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2b50::,2a02:2b50:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2b58::,2a02:2b58:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:2b80::,2a02:2b80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2b88::,2a02:2b88:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2b90::,2a02:2b90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2b98::,2a02:2b98:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2ba0::,2a02:2ba0:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a02:2ba8::,2a02:2ba8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2bb0::,2a02:2bb0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:2bb8::,2a02:2bb8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2bc0::,2a02:2bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2c00::,2a02:2c00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2c40::,2a02:2c40:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2c80::,2a02:2c80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2cc0::,2a02:2cc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2d00::,2a02:2d00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2d40::,2a02:2d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2d80::,2a02:2d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2dc0::,2a02:2dc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2e00::,2a02:2e1f:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2f00::,2a02:2f0f:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:2f80::,2a02:2f80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2fc0::,2a02:2fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:3000::,2a02:31ff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4000::,2a02:4000:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:4040::,2a02:4040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4080::,2a02:4080:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:40c0::,2a02:40c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4100::,2a02:4100:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4140::,2a02:4140:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:4180::,2a02:4180:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:41c0::,2a02:41c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:4200::,2a02:4200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:4240::,2a02:4240:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4280::,2a02:4280:ffff:ffff:ffff:ffff:ffff:ffff,ME
+2a02:42c0::,2a02:42c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4300::,2a02:4300:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:4340::,2a02:4340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4380::,2a02:4380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:43c0::,2a02:43c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4400::,2a02:4400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4440::,2a02:4440:ffff:ffff:ffff:ffff:ffff:ffff,QA
+2a02:4480::,2a02:4480:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:44c0::,2a02:44c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4500::,2a02:4500:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4540::,2a02:4540:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:4580::,2a02:4580:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:45c0::,2a02:45c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4600::,2a02:4600:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4640::,2a02:4640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4680::,2a02:4680:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:46c0::,2a02:46c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:4700::,2a02:4700:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:4740::,2a02:4740:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4780::,2a02:4780:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:47c0::,2a02:47c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4800::,2a02:4800:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:4840::,2a02:4840:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:4880::,2a02:4880:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:48c0::,2a02:48c0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:4900::,2a02:4900:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:4940::,2a02:4940:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:4980::,2a02:4980:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:49c0::,2a02:49c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4a00::,2a02:4a00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:4a40::,2a02:4a40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:4ac0::,2a02:4ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:4b00::,2a02:4b00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:4b40::,2a02:4b40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4b80::,2a02:4b80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4bc0::,2a02:4bc0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:4c00::,2a02:4c00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4c40::,2a02:4c40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4c80::,2a02:4c80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:4cc0::,2a02:4cc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4d00::,2a02:4d00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4d40::,2a02:4d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4d80::,2a02:4d80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4dc0::,2a02:4dc0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:4e40::,2a02:4e40:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:4ec0::,2a02:4ec0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4f00::,2a02:4f00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:4f40::,2a02:4f40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:4f80::,2a02:4f80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:4fc0::,2a02:4fc0:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:5000::,2a02:5000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:5040::,2a02:5040:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:5080::,2a02:5080:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:50c0::,2a02:50c0:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a02:5100::,2a02:5100:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5140::,2a02:5140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5180::,2a02:5180:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:51c0::,2a02:51c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5200::,2a02:5200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5240::,2a02:5240:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:5280::,2a02:5280:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:52c0::,2a02:52c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:5300::,2a02:5300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5340::,2a02:5340:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:5380::,2a02:5380:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:53c0::,2a02:53c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5400::,2a02:5400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5440::,2a02:5440:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:5480::,2a02:5480:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:54c0::,2a02:54c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:5500::,2a02:5500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5540::,2a02:5540:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5580::,2a02:5580:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a02:55c0::,2a02:55c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5600::,2a02:5600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5640::,2a02:5640:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:5680::,2a02:5680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:56c0::,2a02:56c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5740::,2a02:5740:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:5780::,2a02:5780:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:57c0::,2a02:57c0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:5800::,2a02:5800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5840::,2a02:5840:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5880::,2a02:5880:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:58c0::,2a02:58c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:5900::,2a02:5900:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:5940::,2a02:5940:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:5980::,2a02:5980:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:59c0::,2a02:59c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5a00::,2a02:5a00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5a40::,2a02:5a40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:5a80::,2a02:5a80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:5ac0::,2a02:5ac0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:5b00::,2a02:5b00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5b40::,2a02:5b40:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:5b80::,2a02:5b80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:5bc0::,2a02:5bc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5c40::,2a02:5c40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5c80::,2a02:5c80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:5cc0::,2a02:5cc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:5d00::,2a02:5d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5d40::,2a02:5d40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5d80::,2a02:5d80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5dc0::,2a02:5dc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5e00::,2a02:5e00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:5e40::,2a02:5e40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5e80::,2a02:5e80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5ec0::,2a02:5ec0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:5f00::,2a02:5f00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:5f40::,2a02:5f40:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a02:5f80::,2a02:5f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5fc0::,2a02:5fc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:6000::,2a02:6000:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:6040::,2a02:6040:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:60c0::,2a02:60c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6100::,2a02:6100:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6140::,2a02:6140:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6180::,2a02:6180:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:61c0::,2a02:61c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:6200::,2a02:6200:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:6240::,2a02:6240:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:6280::,2a02:6280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:62c0::,2a02:62c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:6300::,2a02:6300:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:6340::,2a02:6340:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:6380::,2a02:6380:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:63c0::,2a02:63c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6400::,2a02:6400:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:6440::,2a02:6440:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:6480::,2a02:6480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:64c0::,2a02:64c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6500::,2a02:6500:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:6540::,2a02:6540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6580::,2a02:6580:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:65c0::,2a02:65c0:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:6600::,2a02:6600:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:6640::,2a02:6640:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:6680::,2a02:6680:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:66c0::,2a02:66c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6700::,2a02:6700:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:6740::,2a02:6740:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:6780::,2a02:6780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:67c0::,2a02:67c0:ffff:ffff:ffff:ffff:ffff:ffff,SY
+2a02:6800::,2a02:6800:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:6840::,2a02:6840:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6880::,2a02:6880:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:68c0::,2a02:68c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6900::,2a02:6900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:6940::,2a02:6940:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:6980::,2a02:6980:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:69c0::,2a02:69c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6a00::,2a02:6a00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:6a40::,2a02:6a40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:6a80::,2a02:6a80:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:6ac0::,2a02:6ac0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6b00::,2a02:6b00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6b40::,2a02:6b40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:6b80::,2a02:6b80:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:6bc0::,2a02:6bc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6c00::,2a02:6c00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6c40::,2a02:6c40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6c80::,2a02:6c80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6cc0::,2a02:6cc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6d00::,2a02:6d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6d40::,2a02:6d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:6d80::,2a02:6d80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6dc0::,2a02:6dc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:6e00::,2a02:6e00:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:6e80::,2a02:6e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6ec0::,2a02:6ec0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:6f00::,2a02:6f00:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:6f40::,2a02:6f40:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:6f80::,2a02:6f80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6fc0::,2a02:6fc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7000::,2a02:7000:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:7040::,2a02:7040:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:7080::,2a02:7080:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:70c0::,2a02:70c0:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:7100::,2a02:7100:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:7140::,2a02:7140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7180::,2a02:7180:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:71c0::,2a02:71c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7200::,2a02:7200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7240::,2a02:7240:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:7280::,2a02:7280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:72c0::,2a02:72c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:7300::,2a02:7300:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a02:7340::,2a02:7340:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:7380::,2a02:7380:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:73c0::,2a02:73c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7400::,2a02:7400:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:7440::,2a02:7440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7480::,2a02:7480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:74c0::,2a02:74c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:7500::,2a02:7500:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a02:7540::,2a02:7540:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:7580::,2a02:7580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:75c0::,2a02:75c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:7600::,2a02:7600:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:7640::,2a02:7640:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:7680::,2a02:7680:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:76c0::,2a02:76c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7700::,2a02:7700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7740::,2a02:7740:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:7780::,2a02:7780:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:77c0::,2a02:77c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7800::,2a02:7800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7840::,2a02:7840:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:7880::,2a02:7880:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:78c0::,2a02:78c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7900::,2a02:7900:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:7940::,2a02:7940:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7980::,2a02:7980:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:79c0::,2a02:79c0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:7a00::,2a02:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:7a40::,2a02:7a40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:7a80::,2a02:7a80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:7ac0::,2a02:7ac0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:7b00::,2a02:7b00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7b40::,2a02:7b40:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:7b80::,2a02:7b80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:7bc0::,2a02:7bc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7c00::,2a02:7c00:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:7c40::,2a02:7c40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7c80::,2a02:7c80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:7cc0::,2a02:7cc0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:7d00::,2a02:7d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:7d40::,2a02:7d40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:7d80::,2a02:7d80:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:7dc0::,2a02:7dc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:7e00::,2a02:7e00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:7e40::,2a02:7e40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7e80::,2a02:7e80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7f00::,2a02:7f00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7f80::,2a02:7f80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:8010::,2a02:8017:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:8020::,2a02:8023:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8040::,2a02:8043:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:8060::,2a02:8061:ffff:ffff:ffff:ffff:ffff:ffff,AD
+2a02:8070::,2a02:8071:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8080::,2a02:8087:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:80c0::,2a02:80c3:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:80e0::,2a02:80e3:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:8100::,2a02:811f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8200::,2a02:821f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8300::,2a02:830f:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:8380::,2a02:838f:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:8400::,2a02:847f:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:8800::,2a02:88ff:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:9000::,2a02:91ff:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:a000::,2a02:a03f:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:a200::,2a02:a21f:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a300::,2a02:a31f:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:a400::,2a02:a47f:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a800::,2a02:a83f:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:aa00::,2a02:aa1f:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:ab00::,2a02:ab07:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:ab40::,2a02:ab47:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:ab80::,2a02:ab8f:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:ac00::,2a02:ac07:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:ac40::,2a02:ac47:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:ac80::,2a02:ac87:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:acc0::,2a02:acc7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ad00::,2a02:ad07:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ad40::,2a02:ad47:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ad80::,2a02:ad87:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:adc0::,2a02:adc7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ae00::,2a02:ae07:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:ae40::,2a02:ae47:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:ae80::,2a02:ae87:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:aec0::,2a02:aec7:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:af00::,2a02:af07:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:af40::,2a02:af47:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:af80::,2a02:af87:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:afc0::,2a02:afc7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b000::,2a02:b1ff:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c000::,2a02:c007:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c040::,2a02:c047:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:c080::,2a02:c087:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:c0c0::,2a02:c0c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c100::,2a02:c107:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c140::,2a02:c147:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c180::,2a02:c187:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:c1c0::,2a02:c1c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c200::,2a02:c207:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c240::,2a02:c247:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:c280::,2a02:c287:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:c2c0::,2a02:c2c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c300::,2a02:c307:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c340::,2a02:c347:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:c380::,2a02:c381:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:c390::,2a02:c391:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:c3a0::,2a02:c3a3:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:c3c0::,2a02:c3c7:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a02:c400::,2a02:c407:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a02:c440::,2a02:c447:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:c480::,2a02:c487:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c4c0::,2a02:c4c7:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:c500::,2a02:c507:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:c540::,2a02:c547:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:c580::,2a02:c587:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:c5c0::,2a02:c5c7:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:c600::,2a02:c607:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:c640::,2a02:c647:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:c680::,2a02:c681:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c690::,2a02:c691:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:c6a0::,2a02:c6a3:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c6c0::,2a02:c6c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c700::,2a02:c707:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c740::,2a02:c747:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c780::,2a02:c787:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:c7c0::,2a02:c7c7:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c800::,2a02:c807:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c840::,2a02:c847:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c880::,2a02:c887:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:c8c0::,2a02:c8c7:ffff:ffff:ffff:ffff:ffff:ffff,UZ
+2a02:c900::,2a02:c907:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:c940::,2a02:c947:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:c980::,2a02:c987:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c9c0::,2a02:c9c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ca00::,2a02:ca07:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ca40::,2a02:ca47:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:ca80::,2a02:ca87:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:cac0::,2a02:cac7:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:cb00::,2a02:cb07:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:cb40::,2a02:cb47:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:cb80::,2a02:cb87:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a03:80::,2a03:80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:100::,2a03:100:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a03:180::,2a03:180:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a03:200::,2a03:200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:280::,2a03:280:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a03:300::,2a03:300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:380::,2a03:380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:400::,2a03:400:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:480::,2a03:480:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:500::,2a03:500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:580::,2a03:580:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:600::,2a03:600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:680::,2a03:680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:700::,2a03:700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:780::,2a03:780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:800::,2a03:800:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:880::,2a03:880:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:900::,2a03:900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:980::,2a03:980:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a03:a00::,2a03:a00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:a80::,2a03:a80:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a03:b00::,2a03:b00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:b80::,2a03:b80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:c00::,2a03:c00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:c80::,2a03:c80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:d00::,2a03:d00:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:d80::,2a03:d80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:e00::,2a03:e00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:e80::,2a03:e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:f00::,2a03:f00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:f80::,2a03:f87:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:1000::,2a03:1000:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:1080::,2a03:1080:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a03:1100::,2a03:1100:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:1180::,2a03:1180:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:1200::,2a03:1200:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:1280::,2a03:1280:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:1300::,2a03:1300:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a03:1380::,2a03:1380:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:1400::,2a03:1400:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:1480::,2a03:1480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:1500::,2a03:1500:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:1580::,2a03:1580:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:1600::,2a03:1600:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:1680::,2a03:1680:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:1700::,2a03:1707:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:1780::,2a03:1780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:1800::,2a03:1800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:1880::,2a03:1880:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:1900::,2a03:1900:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a03:1980::,2a03:1980:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:1a00::,2a03:1a00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:1a80::,2a03:1a80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:1b00::,2a03:1b00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:1b80::,2a03:1b80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:1c00::,2a03:1c00:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a03:1c80::,2a03:1c80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:1d00::,2a03:1d00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:1d80::,2a03:1d80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a03:1e00::,2a03:1e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:1e80::,2a03:1e80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:1f00::,2a03:1f00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:1f80::,2a03:1f80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:2000::,2a03:2000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2080::,2a03:2080:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:2100::,2a03:2100:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:2180::,2a03:2180:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:2200::,2a03:2200:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:2280::,2a03:2280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:2300::,2a03:2300:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a03:2380::,2a03:2380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2400::,2a03:2400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2480::,2a03:2480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:2500::,2a03:2500:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2580::,2a03:2580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2600::,2a03:2600:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:2680::,2a03:2680:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:2700::,2a03:2700:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:2780::,2a03:2780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:2800::,2a03:2800:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2880::,2a03:2880:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:2900::,2a03:2900:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2980::,2a03:2980:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:2a00::,2a03:2a00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2a80::,2a03:2a80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:2b00::,2a03:2b00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:2b80::,2a03:2b80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:2c00::,2a03:2c00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:2c80::,2a03:2c80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2d00::,2a03:2d00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2d80::,2a03:2d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2e00::,2a03:2e00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:2f00::,2a03:2f00:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a03:2f80::,2a03:2f80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:3000::,2a03:3000:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a03:3100::,2a03:3100:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3180::,2a03:3180:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:3200::,2a03:3200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3280::,2a03:3280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:3300::,2a03:3300:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:3380::,2a03:3380:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:3400::,2a03:3400:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:3480::,2a03:3480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3500::,2a03:3500:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:3580::,2a03:3580:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a03:3600::,2a03:3600:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:3680::,2a03:3680:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:3700::,2a03:3700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3800::,2a03:3800:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:3880::,2a03:3880:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:3900::,2a03:3900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:3980::,2a03:3980:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a03:3a00::,2a03:3a00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:3a80::,2a03:3a80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3b00::,2a03:3b00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:3b80::,2a03:3b80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:3c00::,2a03:3c00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:3c80::,2a03:3c80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:3d00::,2a03:3d00:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a03:3d80::,2a03:3d80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:3e00::,2a03:3e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:3e80::,2a03:3e80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:3f00::,2a03:3f00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:3f80::,2a03:3f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4000::,2a03:4000:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:4080::,2a03:4080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:4100::,2a03:4100:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:4180::,2a03:4180:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:4200::,2a03:4200:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:4280::,2a03:4280:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a03:4300::,2a03:4300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:4380::,2a03:4380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:4400::,2a03:4400:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:4480::,2a03:4480:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a03:4500::,2a03:4500:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:4580::,2a03:4580:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:4600::,2a03:4600:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:4680::,2a03:4680:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:4700::,2a03:4700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4780::,2a03:4780:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a03:4800::,2a03:4800:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:4880::,2a03:4880:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4900::,2a03:4900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4980::,2a03:4980:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:4a00::,2a03:4a00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4a80::,2a03:4a80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:4b00::,2a03:4b00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:4b80::,2a03:4b80:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a03:4c00::,2a03:4c00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:4c80::,2a03:4c80:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a03:4d00::,2a03:4d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4d80::,2a03:4d80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:4e00::,2a03:4e00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:4e80::,2a03:4e80:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a03:4f00::,2a03:4f00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:4f80::,2a03:4f80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5000::,2a03:5000:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:5080::,2a03:5080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:5100::,2a03:5100:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:5180::,2a03:5180:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:5200::,2a03:5200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5280::,2a03:5280:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:5300::,2a03:5300:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:5380::,2a03:5380:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5400::,2a03:5400:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:5480::,2a03:5480:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a03:5500::,2a03:5500:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5580::,2a03:5580:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:5600::,2a03:5600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5680::,2a03:5680:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:5700::,2a03:5700:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5780::,2a03:5780:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a03:5800::,2a03:5800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5880::,2a03:5880:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a03:5900::,2a03:5900:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a03:5980::,2a03:5980:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:5a00::,2a03:5a00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5a80::,2a03:5a80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5b00::,2a03:5b00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:5b80::,2a03:5b80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5c00::,2a03:5c00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:5c80::,2a03:5c80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5d00::,2a03:5d00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:5d80::,2a03:5d80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5e00::,2a03:5e00:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a03:5e80::,2a03:5e80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:5f00::,2a03:5f00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:5f80::,2a03:5f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6000::,2a03:6000:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:6080::,2a03:6087:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6100::,2a03:6100:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a03:6180::,2a03:6180:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:6200::,2a03:6200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6300::,2a03:6300:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a03:6380::,2a03:6380:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a03:6400::,2a03:6400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:6480::,2a03:6480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:6500::,2a03:6500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6580::,2a03:6580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:6600::,2a03:6600:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:6680::,2a03:6680:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:6700::,2a03:6700:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a03:6780::,2a03:6780:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:6800::,2a03:6800:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:6880::,2a03:6880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:6900::,2a03:6900:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a03:6980::,2a03:6980:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:6a00::,2a03:6a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:6a80::,2a03:6a80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:6b00::,2a03:6b00:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a03:6b80::,2a03:6b80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:6c00::,2a03:6c00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:6c80::,2a03:6c80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:6d00::,2a03:6d00:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a03:6d80::,2a03:6d80:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:6e00::,2a03:6e00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:6e80::,2a03:6e80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:6f00::,2a03:6f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6f80::,2a03:6f80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:7000::,2a03:7000:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:7080::,2a03:7080:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:7100::,2a03:7100:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:7180::,2a03:7180:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a03:7200::,2a03:7200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:7280::,2a03:7280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:7300::,2a03:7300:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:7380::,2a03:7380:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a03:7400::,2a03:7400:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:7480::,2a03:7480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:7500::,2a03:7500:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:7580::,2a03:7580:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:7600::,2a03:7600:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:7680::,2a03:7680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:7700::,2a03:7700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:7780::,2a03:7780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:7800::,2a03:7800:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:7880::,2a03:7880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:7900::,2a03:7900:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:7a00::,2a03:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:7a80::,2a03:7a80:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a03:7b00::,2a03:7b00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:7b80::,2a03:7b80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:7c00::,2a03:7c00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:7c80::,2a03:7c80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:7d00::,2a03:7d00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:7e00::,2a03:7e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:7e80::,2a03:7e80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:7f00::,2a03:7f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:7f80::,2a03:7f80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8000::,2a03:8000:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:8080::,2a03:8080:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8100::,2a03:8100:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:8180::,2a03:8180:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:8200::,2a03:8200:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8280::,2a03:8280:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8300::,2a03:8300:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:8380::,2a03:8380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:8400::,2a03:8400:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8480::,2a03:8480:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a03:8500::,2a03:8500:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a03:8580::,2a03:8580:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:8600::,2a03:8600:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:8680::,2a03:8680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8700::,2a03:8700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8780::,2a03:8780:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:8800::,2a03:8800:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:8880::,2a03:8880:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:8900::,2a03:8900:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:8980::,2a03:8980:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:8a00::,2a03:8a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8a80::,2a03:8a80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:8b00::,2a03:8b00:ffff:ffff:ffff:ffff:ffff:ffff,SM
+2a03:8b80::,2a03:8b80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:8c00::,2a03:8c00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8c80::,2a03:8c87:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:8d00::,2a03:8d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8e00::,2a03:8e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8e80::,2a03:8e80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:8f00::,2a03:8f00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:8f80::,2a03:8f80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:9000::,2a03:9000:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:9080::,2a03:9080:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:9100::,2a03:9100:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:9180::,2a03:9180:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:9280::,2a03:9280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9300::,2a03:9300:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:9380::,2a03:9380:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9400::,2a03:9400:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:9480::,2a03:9480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:9500::,2a03:9500:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:9580::,2a03:9580:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:9600::,2a03:9600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9680::,2a03:9680:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a03:9700::,2a03:9700:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:9780::,2a03:9780:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:9800::,2a03:9800:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9880::,2a03:9880:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:9900::,2a03:9900:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:9980::,2a03:9980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:9a00::,2a03:9a00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:9a80::,2a03:9a80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:9b00::,2a03:9b00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:9b80::,2a03:9b80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:9c00::,2a03:9c00:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:9c80::,2a03:9c80:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a03:9d00::,2a03:9d00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:9d80::,2a03:9d80:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a03:9e00::,2a03:9e00:ffff:ffff:ffff:ffff:ffff:ffff,IM
+2a03:9e80::,2a03:9e80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9f00::,2a03:9f00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9f80::,2a03:9f80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:a000::,2a03:a000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:a080::,2a03:a080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:a100::,2a03:a100:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a03:a180::,2a03:a180:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:a200::,2a03:a200:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a03:a280::,2a03:a280:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:a300::,2a03:a300:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a03:a380::,2a03:a380:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:a400::,2a03:a400:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:a480::,2a03:a480:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:a500::,2a03:a500:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:a580::,2a03:a580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:a600::,2a03:a600:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a03:a680::,2a03:a680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:a780::,2a03:a780:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:a800::,2a03:a800:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:a900::,2a03:a900:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:a980::,2a03:a980:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:aa00::,2a03:aa00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:aa80::,2a03:aa80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ab00::,2a03:ab00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:ab80::,2a03:ab80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:ac00::,2a03:ac00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:ac80::,2a03:ac80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:ad00::,2a03:ad00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:ad80::,2a03:ad80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:ae00::,2a03:ae00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:ae80::,2a03:ae80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:af00::,2a03:af00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:af80::,2a03:af80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:b000::,2a03:b000:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:b080::,2a03:b080:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a03:b100::,2a03:b100:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:b180::,2a03:b180:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a03:b200::,2a03:b207:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:b280::,2a03:b280:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:b300::,2a03:b300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:b380::,2a03:b380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b400::,2a03:b400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b480::,2a03:b480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b500::,2a03:b500:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:b580::,2a03:b580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b600::,2a03:b600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:b680::,2a03:b680:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:b700::,2a03:b700:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:b780::,2a03:b780:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:b800::,2a03:b800:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:b880::,2a03:b887:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b900::,2a03:b900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:b980::,2a03:b980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:ba00::,2a03:ba00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:ba80::,2a03:ba80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:bb00::,2a03:bb00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:bb80::,2a03:bb80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:bc00::,2a03:bc00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:bc80::,2a03:bc80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:bd00::,2a03:bd00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:bd80::,2a03:bd80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:be00::,2a03:be00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:be80::,2a03:be80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:bf00::,2a03:bf00:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:bf80::,2a03:bf80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:c000::,2a03:c007:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:c080::,2a03:c080:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a03:c100::,2a03:c100:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:c180::,2a03:c180:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:c200::,2a03:c200:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:c280::,2a03:c280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:c300::,2a03:c300:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:c380::,2a03:c380:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:c400::,2a03:c400:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:c480::,2a03:c480:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a03:c500::,2a03:c500:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:c580::,2a03:c580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:c600::,2a03:c600:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:c680::,2a03:c680:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:c700::,2a03:c700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:c780::,2a03:c780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:c800::,2a03:c800:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a03:c880::,2a03:c880:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:c900::,2a03:c900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:c980::,2a03:c980:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ca00::,2a03:ca00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ca80::,2a03:ca80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:cb00::,2a03:cb00:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a03:cb80::,2a03:cb80:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a03:cc00::,2a03:cc00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:cc80::,2a03:cc80:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a03:cd00::,2a03:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a03:cd80::,2a03:cd80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a03:ce00::,2a03:ce00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ce80::,2a03:ce80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:cf00::,2a03:cf00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:cf80::,2a03:cf80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:d000::,2a03:d000:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:d080::,2a03:d080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:d100::,2a03:d100:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:d180::,2a03:d180:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a03:d200::,2a03:d200:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:d280::,2a03:d280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:d300::,2a03:d300:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:d380::,2a03:d380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:d400::,2a03:d400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:d480::,2a03:d480:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:d500::,2a03:d500:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:d580::,2a03:d580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:d600::,2a03:d600:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:d680::,2a03:d680:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:d700::,2a03:d700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:d780::,2a03:d780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:d800::,2a03:d800:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:d880::,2a03:d880:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:d900::,2a03:d900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:d980::,2a03:d980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:da00::,2a03:da00:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:da80::,2a03:da80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:db00::,2a03:db00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:db80::,2a03:db80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:dc00::,2a03:dc00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:dc80::,2a03:dc80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:dd00::,2a03:dd00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:dd80::,2a03:dd80:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a03:de00::,2a03:de00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:de80::,2a03:de80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:df00::,2a03:df00:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:df80::,2a03:df80:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a03:e000::,2a03:e000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:e080::,2a03:e080:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:e100::,2a03:e100:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:e180::,2a03:e180:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a03:e200::,2a03:e200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:e280::,2a03:e280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:e380::,2a03:e380:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a03:e400::,2a03:e400:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:e480::,2a03:e480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:e500::,2a03:e500:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a03:e580::,2a03:e580:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:e600::,2a03:e600:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:e680::,2a03:e680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:e700::,2a03:e700:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:e780::,2a03:e780:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:e800::,2a03:e800:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:e880::,2a03:e880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:e900::,2a03:e900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:e980::,2a03:e980:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a03:ea00::,2a03:ea00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:ea80::,2a03:ea80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:eb00::,2a03:eb00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:eb80::,2a03:eb80:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a03:ec00::,2a03:ec00:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a03:ec80::,2a03:ec80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:ed00::,2a03:ed00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:ed80::,2a03:ed80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ee00::,2a03:ee00:ffff:ffff:ffff:ffff:ffff:ffff,FO
+2a03:ee80::,2a03:ee80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:ef00::,2a03:ef00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:ef80::,2a03:ef80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:f000::,2a03:f000:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a03:f080::,2a03:f080:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:f100::,2a03:f100:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:f180::,2a03:f180:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a03:f200::,2a03:f200:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:f280::,2a03:f280:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:f300::,2a03:f300:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:f380::,2a03:f380:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:f400::,2a03:f400:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:f480::,2a03:f480:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a03:f500::,2a03:f500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:f580::,2a03:f580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:f600::,2a03:f600:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:f680::,2a03:f680:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a03:f700::,2a03:f700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:f780::,2a03:f780:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:f800::,2a03:f800:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a03:f880::,2a03:f880:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:f900::,2a03:f907:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:f980::,2a03:f980:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:fa00::,2a03:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:fa80::,2a03:fa80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:fb00::,2a03:fb00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:fb80::,2a03:fb80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:fc00::,2a03:fc00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:fc80::,2a03:fc80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:fe00::,2a03:fe00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:fe80::,2a03:fe80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:ff00::,2a03:ff00:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a03:ff80::,2a03:ff80:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2c0f:f800::,2c0f:f80f:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:f810::,2c0f:f810:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:f818::,2c0f:f818:ffff:ffff:ffff:ffff:ffff:ffff,LY
+2c0f:f820::,2c0f:f820:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:f828::,2c0f:f828:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:f830::,2c0f:f830:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:f838::,2c0f:f838:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:f840::,2c0f:f840:ffff:ffff:ffff:ffff:ffff:ffff,GQ
+2c0f:f848::,2c0f:f848:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:f850::,2c0f:f850:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:f858::,2c0f:f858:ffff:ffff:ffff:ffff:ffff:ffff,DZ
+2c0f:f860::,2c0f:f860:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2c0f:f868::,2c0f:f868:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:f870::,2c0f:f870:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:f878::,2c0f:f878:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:f880::,2c0f:f880:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:f888::,2c0f:f888:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa00::,2c0f:fa00:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fa08::,2c0f:fa08:ffff:ffff:ffff:ffff:ffff:ffff,CD
+2c0f:fa10::,2c0f:fa10:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fa18::,2c0f:fa18:ffff:ffff:ffff:ffff:ffff:ffff,MA
+2c0f:fa20::,2c0f:fa20:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:fa28::,2c0f:fa28:ffff:ffff:ffff:ffff:ffff:ffff,MG
+2c0f:fa30::,2c0f:fa30:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fa38::,2c0f:fa38:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa40::,2c0f:fa40:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa48::,2c0f:fa48:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa58::,2c0f:fa58:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa60::,2c0f:fa60:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa68::,2c0f:fa68:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fa70::,2c0f:fa70:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa78::,2c0f:fa78:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa80::,2c0f:fa80:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa88::,2c0f:fa88:ffff:ffff:ffff:ffff:ffff:ffff,ST
+2c0f:fa90::,2c0f:fa90:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa98::,2c0f:fa98:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:faa0::,2c0f:faa7:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:fab0::,2c0f:fabf:ffff:ffff:ffff:ffff:ffff:ffff,TN
+2c0f:fac0::,2c0f:fac0:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fac8::,2c0f:fac8:ffff:ffff:ffff:ffff:ffff:ffff,BW
+2c0f:fad0::,2c0f:fad0:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2c0f:fad8::,2c0f:fad8:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fae0::,2c0f:fae0:ffff:ffff:ffff:ffff:ffff:ffff,CM
+2c0f:fae8::,2c0f:fae8:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:faf0::,2c0f:faf0:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:faf8::,2c0f:faf8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb00::,2c0f:fb00:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fb08::,2c0f:fb08:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb10::,2c0f:fb10:ffff:ffff:ffff:ffff:ffff:ffff,LY
+2c0f:fb18::,2c0f:fb18:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb20::,2c0f:fb20:ffff:ffff:ffff:ffff:ffff:ffff,MA
+2c0f:fb28::,2c0f:fb28:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb30::,2c0f:fb30:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb38::,2c0f:fb38:ffff:ffff:ffff:ffff:ffff:ffff,SO
+2c0f:fb40::,2c0f:fb40:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb48::,2c0f:fb48:ffff:ffff:ffff:ffff:ffff:ffff,MZ
+2c0f:fb50::,2c0f:fb50:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fb58::,2c0f:fb58:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fb60::,2c0f:fb60:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fb68::,2c0f:fb68:ffff:ffff:ffff:ffff:ffff:ffff,LS
+2c0f:fb70::,2c0f:fb70:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fb78::,2c0f:fb78:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fb80::,2c0f:fb80:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb88::,2c0f:fb88:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fb90::,2c0f:fb90:ffff:ffff:ffff:ffff:ffff:ffff,MZ
+2c0f:fb98::,2c0f:fb98:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fba0::,2c0f:fba0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fba8::,2c0f:fba8:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fbb0::,2c0f:fbb0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fbb8::,2c0f:fbb8:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fbc0::,2c0f:fbc0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fbc8::,2c0f:fbc8:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fbd0::,2c0f:fbd0:ffff:ffff:ffff:ffff:ffff:ffff,GN
+2c0f:fbd8::,2c0f:fbd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fbe0::,2c0f:fc1f:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fc40::,2c0f:fc40:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2c0f:fc48::,2c0f:fc48:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fc50::,2c0f:fc50:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:fc58::,2c0f:fc58:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fc60::,2c0f:fc61:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fc68::,2c0f:fc68:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fc70::,2c0f:fc70:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fc78::,2c0f:fc78:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:fc80::,2c0f:fc80:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fc88::,2c0f:fc88:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2c0f:fc90::,2c0f:fc90:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fc98::,2c0f:fc98:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fca0::,2c0f:fca0:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fca8::,2c0f:fca8:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fcb0::,2c0f:fcb0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fcb8::,2c0f:fcb8:ffff:ffff:ffff:ffff:ffff:ffff,GM
+2c0f:fcc8::,2c0f:fcc8:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fcd0::,2c0f:fcd0:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fcd8::,2c0f:fcd8:ffff:ffff:ffff:ffff:ffff:ffff,SO
+2c0f:fce0::,2c0f:fce0:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fce8::,2c0f:fce8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fcf0::,2c0f:fcf0:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fcf8::,2c0f:fcf8:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fd00::,2c0f:fd00:ffff:ffff:ffff:ffff:ffff:ffff,LS
+2c0f:fd08::,2c0f:fd08:ffff:ffff:ffff:ffff:ffff:ffff,GM
+2c0f:fd10::,2c0f:fd10:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fd18::,2c0f:fd18:ffff:ffff:ffff:ffff:ffff:ffff,SC
+2c0f:fd20::,2c0f:fd20:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fd28::,2c0f:fd28:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fd30::,2c0f:fd30:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fd38::,2c0f:fd38:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fd40::,2c0f:fd40:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fd48::,2c0f:fd48:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:fd50::,2c0f:fd50:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fd58::,2c0f:fd58:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fd60::,2c0f:fd60:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fd68::,2c0f:fd68:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fd70::,2c0f:fd70:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fd78::,2c0f:fd78:ffff:ffff:ffff:ffff:ffff:ffff,BI
+2c0f:fd80::,2c0f:fd80:ffff:ffff:ffff:ffff:ffff:ffff,BF
+2c0f:fd88::,2c0f:fd88:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fd90::,2c0f:fd90:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fd98::,2c0f:fd98:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fda0::,2c0f:fda0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fda8::,2c0f:fda8:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fdb0::,2c0f:fdb0:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fdb8::,2c0f:fdb8:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fdc0::,2c0f:fdc0:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fdc8::,2c0f:fdc8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fdd0::,2c0f:fdd0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fdd8::,2c0f:fdd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fde0::,2c0f:fde0:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fde8::,2c0f:fde8:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fdf0::,2c0f:fdf0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fdf8::,2c0f:fdf8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe08::,2c0f:fe08:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fe10::,2c0f:fe10:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fe18::,2c0f:fe18:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe20::,2c0f:fe20:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe28::,2c0f:fe28:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe30::,2c0f:fe30:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2c0f:fe38::,2c0f:fe38:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fe40::,2c0f:fe40:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fe48::,2c0f:fe48:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe50::,2c0f:fe50:ffff:ffff:ffff:ffff:ffff:ffff,DZ
+2c0f:fe58::,2c0f:fe58:ffff:ffff:ffff:ffff:ffff:ffff,LS
+2c0f:fe60::,2c0f:fe60:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2c0f:fe68::,2c0f:fe68:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2c0f:fe70::,2c0f:fe70:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fe78::,2c0f:fe78:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe80::,2c0f:fe80:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fe88::,2c0f:fe88:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fe90::,2c0f:fe90:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe98::,2c0f:fe98:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fea0::,2c0f:fea0:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fea8::,2c0f:fea8:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:feb0::,2c0f:feb0:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2c0f:feb8::,2c0f:feb8:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fec0::,2c0f:fec0:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fec8::,2c0f:fec8:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:fed0::,2c0f:fed0:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fed8::,2c0f:fed8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fee0::,2c0f:fee0:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2c0f:fef0::,2c0f:fef0:ffff:ffff:ffff:ffff:ffff:ffff,SC
+2c0f:fef8::,2c0f:fef8:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:ff00::,2c0f:ff00:ffff:ffff:ffff:ffff:ffff:ffff,BW
+2c0f:ff08::,2c0f:ff08:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ff10::,2c0f:ff10:ffff:ffff:ffff:ffff:ffff:ffff,CD
+2c0f:ff18::,2c0f:ff18:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:ff20::,2c0f:ff20:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:ff28::,2c0f:ff28:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:ff30::,2c0f:ff30:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ff40::,2c0f:ff80:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ff88::,2c0f:ff88:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:ff90::,2c0f:ff90:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:ff98::,2c0f:ff98:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:ffa0::,2c0f:ffa0:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:ffa8::,2c0f:ffa8:ffff:ffff:ffff:ffff:ffff:ffff,LS
+2c0f:ffb0::,2c0f:ffb0:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:ffb8::,2c0f:ffb8:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:ffc0::,2c0f:ffc0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffc8::,2c0f:ffc8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffd0::,2c0f:ffd0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffd8::,2c0f:ffd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffe0::,2c0f:ffe0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffe8::,2c0f:ffe8:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fff0::,2c0f:fff0:ffff:ffff:ffff:ffff:ffff:ffff,NG
diff --git a/src/config/include.am b/src/config/include.am
new file mode 100644
index 0000000000..35961b829a
--- /dev/null
+++ b/src/config/include.am
@@ -0,0 +1,16 @@
+confdir = $(sysconfdir)/tor
+
+tordatadir = $(datadir)/tor
+
+EXTRA_DIST+= src/config/geoip src/config/geoip6
+# fallback-consensus
+
+conf_DATA = src/config/torrc.sample
+
+tordata_DATA = src/config/geoip src/config/geoip6
+# fallback_consensus
+
+# If we don't have it, fake it.
+src_config_fallback-consensus:
+ touch src/config/fallback-consensus
+
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index a1a08aa8f9..c667efc5c9 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -1,5 +1,5 @@
## Configuration file for a typical Tor user
-## Last updated 22 April 2012 for Tor 0.2.3.14-alpha.
+## Last updated 12 September 2012 for Tor 0.2.4.3-alpha.
## (may or may not work for much older or much newer versions of Tor.)
##
## Lines that begin with "## " try to explain what's going on. Lines
@@ -16,7 +16,7 @@
## configure one below. Set "SocksPort 0" if you plan to run Tor only
## as a relay, and not make any local application connections yourself.
#SocksPort 9050 # Default: Bind to localhost:9050 for local connections.
-#SocksPort 192.168.0.1:9100 # Bind to this adddress:port too.
+#SocksPort 192.168.0.1:9100 # Bind to this address:port too.
## Entry policies to allow/deny SOCKS requests based on IP address.
## First entry that matches wins. If no SocksPolicy is set, we accept
diff --git a/src/common/OpenBSD_malloc_Linux.c b/src/ext/OpenBSD_malloc_Linux.c
index da82729811..da82729811 100644
--- a/src/common/OpenBSD_malloc_Linux.c
+++ b/src/ext/OpenBSD_malloc_Linux.c
diff --git a/src/ext/README b/src/ext/README
new file mode 100644
index 0000000000..8c850bef66
--- /dev/null
+++ b/src/ext/README
@@ -0,0 +1,39 @@
+
+OpenBSD_malloc_Linux.c:
+
+ The OpenBSD malloc implementation, ported to Linux. Used only when
+ --enable-openbsd-malloc is passed to the configure script.
+
+strlcat.c
+strlcpy.c
+
+ Implementations of strlcat and strlcpy, the more sane replacements
+ for strcat and strcpy. These are nonstandard, and some libc
+ implementations refuse to add them for religious reasons.
+
+eventdns.[ch]
+
+ A fork of Libevent's DNS implementation, used by Tor when Libevent
+ 2.0 or later is not available. Once Libevent 2.0 is required, we
+ should throw this away; it has diverged from evdns.[ch], and is
+ no longer easily mergeable.
+
+ht.h
+
+ An implementation of a hash table in the style of Niels Provos's
+ tree.h. Shared with Libevent.
+
+tinytest.[ch]
+tinytest_demos.c
+tinytest_macros.h
+
+ A unit testing framework. https://github.com/nmathewson/tinytest
+
+tor_queue.h
+
+ A copy of sys/queue.h from OpenBSD. We keep our own copy rather
+ than using sys/queue.h, since some platforms don't have a
+ sys/queue.h, and the ones that do have diverged in incompatible
+ ways. (CIRCLEQ or no CIRCLEQ? SIMPLQ or STAILQ?)
+
+
diff --git a/src/or/eventdns.c b/src/ext/eventdns.c
index 768693aba6..7e99f55626 100644
--- a/src/or/eventdns.c
+++ b/src/ext/eventdns.c
@@ -130,7 +130,7 @@ typedef int socklen_t;
#define mm_realloc(x,y) tor_realloc((x),(y))
#define mm_free(x) tor_free(x)
#define mm_strdup(x) tor_strdup(x)
-#define _mm_free(x) _tor_free(x)
+#define _mm_free(x) tor_free_(x)
#undef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
diff --git a/src/or/eventdns.h b/src/ext/eventdns.h
index 1c130b2a12..ad8c100dd6 100644
--- a/src/or/eventdns.h
+++ b/src/ext/eventdns.h
@@ -209,8 +209,8 @@
* with the next probe.
*/
-#ifndef _TOR_EVENTDNS_H
-#define _TOR_EVENTDNS_H
+#ifndef TOR_EVENTDNS_H
+#define TOR_EVENTDNS_H
/* Error codes 0-5 are as described in RFC 1035. */
#define DNS_ERR_NONE 0
diff --git a/src/common/ht.h b/src/ext/ht.h
index 25156c4165..385aff2a9b 100644
--- a/src/common/ht.h
+++ b/src/ext/ht.h
@@ -5,8 +5,8 @@
/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
-#ifndef _TOR_HT_H
-#define _TOR_HT_H
+#ifndef HT_H_INCLUDED_
+#define HT_H_INCLUDED_
#define HT_HEAD(name, type) \
struct name { \
diff --git a/src/ext/include.am b/src/ext/include.am
new file mode 100644
index 0000000000..ea7e58e79e
--- /dev/null
+++ b/src/ext/include.am
@@ -0,0 +1,17 @@
+
+AM_CPPFLAGS += -I$(srcdir)/src/ext -Isrc/ext
+
+EXTRA_DIST += src/ext/README
+
+EXTHEADERS = \
+ src/ext/ht.h \
+ src/ext/eventdns.h \
+ src/ext/tinytest.h \
+ src/ext/strlcat.c \
+ src/ext/strlcpy.c \
+ src/ext/tinytest_macros.h \
+ src/ext/tor_queue.h
+
+noinst_HEADERS+= $(EXTHEADERS)
+
+
diff --git a/src/common/strlcat.c b/src/ext/strlcat.c
index 316733bccc..316733bccc 100644
--- a/src/common/strlcat.c
+++ b/src/ext/strlcat.c
diff --git a/src/common/strlcpy.c b/src/ext/strlcpy.c
index 9fc47903a1..9fc47903a1 100644
--- a/src/common/strlcpy.c
+++ b/src/ext/strlcpy.c
diff --git a/src/test/tinytest.c b/src/ext/tinytest.c
index 4d9afacce4..4d9afacce4 100644
--- a/src/test/tinytest.c
+++ b/src/ext/tinytest.c
diff --git a/src/test/tinytest.h b/src/ext/tinytest.h
index bcac9f079c..bcac9f079c 100644
--- a/src/test/tinytest.h
+++ b/src/ext/tinytest.h
diff --git a/src/test/tinytest_demo.c b/src/ext/tinytest_demo.c
index be95ce4c1d..be95ce4c1d 100644
--- a/src/test/tinytest_demo.c
+++ b/src/ext/tinytest_demo.c
diff --git a/src/test/tinytest_macros.h b/src/ext/tinytest_macros.h
index 9ff69b1d50..9ff69b1d50 100644
--- a/src/test/tinytest_macros.h
+++ b/src/ext/tinytest_macros.h
diff --git a/src/ext/tor_queue.h b/src/ext/tor_queue.h
new file mode 100644
index 0000000000..595e4a3423
--- /dev/null
+++ b/src/ext/tor_queue.h
@@ -0,0 +1,573 @@
+/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+/* XXXX This macro name conflicts with a typedef in winnt.h, so Tor
+ * has to redefine it. */
+#define TOR_SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+#ifndef _WIN32
+#define SLIST_ENTRY(type) TOR_SLIST_ENTRY(type)
+#endif
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST(head); \
+ (var) && ((tvar) = SLIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field) do { \
+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->slh_first; \
+ \
+ while (curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ _Q_INVALIDATE((elm)->field.sle_next); \
+ } \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST(head); \
+ (var) && ((tvar) = LIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SIMPLEQ_FIRST(head); \
+ (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+ == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * tail queue access methods
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head) && \
+ ((tvar) = TAILQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head) && \
+ ((tvar) = TAILQ_PREV(var, headname, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define CIRCLEQ_EMPTY(head) \
+ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head) && \
+ ((tvar) = CIRCLEQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for((var) = CIRCLEQ_LAST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_PREV(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = CIRCLEQ_LAST(head, headname); \
+ (var) != CIRCLEQ_END(head) && \
+ ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = CIRCLEQ_END(head); \
+ (head)->cqh_last = CIRCLEQ_END(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
+ if ((head)->cqh_last == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+ _Q_INVALIDATE((elm)->field.cqe_prev); \
+ _Q_INVALIDATE((elm)->field.cqe_next); \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_last = (elm2); \
+ else \
+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_first = (elm2); \
+ else \
+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
+ _Q_INVALIDATE((elm)->field.cqe_prev); \
+ _Q_INVALIDATE((elm)->field.cqe_next); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/src/ext/tor_queue.txt b/src/ext/tor_queue.txt
new file mode 100644
index 0000000000..f284e7192f
--- /dev/null
+++ b/src/ext/tor_queue.txt
@@ -0,0 +1,883 @@
+Below follows the manpage for tor_queue.h, as included with OpenBSD's
+sys/queue.h. License follows at the end of the file.
+
+======================================================================
+QUEUE(3) OpenBSD Programmer's Manual QUEUE(3)
+
+NAME
+ SLIST_ENTRY, SLIST_HEAD, SLIST_HEAD_INITIALIZER, SLIST_FIRST, SLIST_NEXT,
+ SLIST_END, SLIST_EMPTY, SLIST_FOREACH, SLIST_FOREACH_SAFE, SLIST_INIT,
+ SLIST_INSERT_AFTER, SLIST_INSERT_HEAD, SLIST_REMOVE_AFTER,
+ SLIST_REMOVE_HEAD, SLIST_REMOVE, LIST_ENTRY, LIST_HEAD,
+ LIST_HEAD_INITIALIZER, LIST_FIRST, LIST_NEXT, LIST_END, LIST_EMPTY,
+ LIST_FOREACH, LIST_FOREACH_SAFE, LIST_INIT, LIST_INSERT_AFTER,
+ LIST_INSERT_BEFORE, LIST_INSERT_HEAD, LIST_REMOVE, LIST_REPLACE,
+ SIMPLEQ_ENTRY, SIMPLEQ_HEAD, SIMPLEQ_HEAD_INITIALIZER, SIMPLEQ_FIRST,
+ SIMPLEQ_NEXT, SIMPLEQ_END, SIMPLEQ_EMPTY, SIMPLEQ_FOREACH,
+ SIMPLEQ_FOREACH_SAFE, SIMPLEQ_INIT, SIMPLEQ_INSERT_AFTER,
+ SIMPLEQ_INSERT_HEAD, SIMPLEQ_INSERT_TAIL, SIMPLEQ_REMOVE_AFTER,
+ SIMPLEQ_REMOVE_HEAD, TAILQ_ENTRY, TAILQ_HEAD, TAILQ_HEAD_INITIALIZER,
+ TAILQ_FIRST, TAILQ_NEXT, TAILQ_END, TAILQ_LAST, TAILQ_PREV, TAILQ_EMPTY,
+ TAILQ_FOREACH, TAILQ_FOREACH_SAFE, TAILQ_FOREACH_REVERSE,
+ TAILQ_FOREACH_REVERSE_SAFE, TAILQ_INIT, TAILQ_INSERT_AFTER,
+ TAILQ_INSERT_BEFORE, TAILQ_INSERT_HEAD, TAILQ_INSERT_TAIL, TAILQ_REMOVE,
+ TAILQ_REPLACE, CIRCLEQ_ENTRY, CIRCLEQ_HEAD, CIRCLEQ_HEAD_INITIALIZER,
+ CIRCLEQ_FIRST, CIRCLEQ_LAST, CIRCLEQ_END, CIRCLEQ_NEXT, CIRCLEQ_PREV,
+ CIRCLEQ_EMPTY, CIRCLEQ_FOREACH, CIRCLEQ_FOREACH_SAFE,
+ CIRCLEQ_FOREACH_REVERSE_SAFE, CIRCLEQ_INIT, CIRCLEQ_INSERT_AFTER,
+ CIRCLEQ_INSERT_BEFORE, CIRCLEQ_INSERT_HEAD, CIRCLEQ_INSERT_TAIL,
+ CIRCLEQ_REMOVE, CIRCLEQ_REPLACE - implementations of singly-linked lists,
+ doubly-linked lists, simple queues, tail queues, and circular queues
+
+SYNOPSIS
+ #include <sys/queue.h>
+
+ SLIST_ENTRY(TYPE);
+
+ SLIST_HEAD(HEADNAME, TYPE);
+
+ SLIST_HEAD_INITIALIZER(SLIST_HEAD head);
+
+ struct TYPE *
+ SLIST_FIRST(SLIST_HEAD *head);
+
+ struct TYPE *
+ SLIST_NEXT(struct TYPE *listelm, SLIST_ENTRY NAME);
+
+ struct TYPE *
+ SLIST_END(SLIST_HEAD *head);
+
+ int
+ SLIST_EMPTY(SLIST_HEAD *head);
+
+ SLIST_FOREACH(VARNAME, SLIST_HEAD *head, SLIST_ENTRY NAME);
+
+ SLIST_FOREACH_SAFE(VARNAME, SLIST_HEAD *head, SLIST_ENTRY
+ NAME, TEMP_VARNAME);
+
+ void
+ SLIST_INIT(SLIST_HEAD *head);
+
+ void
+ SLIST_INSERT_AFTER(struct TYPE *listelm, struct TYPE *elm, SLIST_ENTRY
+ NAME);
+
+ void
+ SLIST_INSERT_HEAD(SLIST_HEAD *head, struct TYPE *elm, SLIST_ENTRY NAME);
+
+ void
+ SLIST_REMOVE_AFTER(struct TYPE *elm, SLIST_ENTRY NAME);
+
+ void
+ SLIST_REMOVE_HEAD(SLIST_HEAD *head, SLIST_ENTRY NAME);
+
+ void
+ SLIST_REMOVE(SLIST_HEAD *head, struct TYPE *elm, TYPE, SLIST_ENTRY NAME);
+
+ LIST_ENTRY(TYPE);
+
+ LIST_HEAD(HEADNAME, TYPE);
+
+ LIST_HEAD_INITIALIZER(LIST_HEAD head);
+
+ struct TYPE *
+ LIST_FIRST(LIST_HEAD *head);
+
+ struct TYPE *
+ LIST_NEXT(struct TYPE *listelm, LIST_ENTRY NAME);
+
+ struct TYPE *
+ LIST_END(LIST_HEAD *head);
+
+ int
+ LIST_EMPTY(LIST_HEAD *head);
+
+ LIST_FOREACH(VARNAME, LIST_HEAD *head, LIST_ENTRY NAME);
+
+ LIST_FOREACH_SAFE(VARNAME, LIST_HEAD *head, LIST_ENTRY
+ NAME, TEMP_VARNAME);
+
+ void
+ LIST_INIT(LIST_HEAD *head);
+
+ void
+ LIST_INSERT_AFTER(struct TYPE *listelm, struct TYPE *elm, LIST_ENTRY
+ NAME);
+
+ void
+ LIST_INSERT_BEFORE(struct TYPE *listelm, struct TYPE *elm, LIST_ENTRY
+ NAME);
+
+ void
+ LIST_INSERT_HEAD(LIST_HEAD *head, struct TYPE *elm, LIST_ENTRY NAME);
+
+ void
+ LIST_REMOVE(struct TYPE *elm, LIST_ENTRY NAME);
+
+ void
+ LIST_REPLACE(struct TYPE *elm, struct TYPE *elm2, LIST_ENTRY NAME);
+
+ SIMPLEQ_ENTRY(TYPE);
+
+ SIMPLEQ_HEAD(HEADNAME, TYPE);
+
+ SIMPLEQ_HEAD_INITIALIZER(SIMPLEQ_HEAD head);
+
+ struct TYPE *
+ SIMPLEQ_FIRST(SIMPLEQ_HEAD *head);
+
+ struct TYPE *
+ SIMPLEQ_NEXT(struct TYPE *listelm, SIMPLEQ_ENTRY NAME);
+
+ struct TYPE *
+ SIMPLEQ_END(SIMPLEQ_HEAD *head);
+
+ int
+ SIMPLEQ_EMPTY(SIMPLEQ_HEAD *head);
+
+ SIMPLEQ_FOREACH(VARNAME, SIMPLEQ_HEAD *head, SIMPLEQ_ENTRY NAME);
+
+ SIMPLEQ_FOREACH_SAFE(VARNAME, SIMPLEQ_HEAD *head, SIMPLEQ_ENTRY
+ NAME, TEMP_VARNAME);
+
+ void
+ SIMPLEQ_INIT(SIMPLEQ_HEAD *head);
+
+ void
+ SIMPLEQ_INSERT_AFTER(SIMPLEQ_HEAD *head, struct TYPE *listelm, struct
+ TYPE *elm, SIMPLEQ_ENTRY NAME);
+
+ void
+ SIMPLEQ_INSERT_HEAD(SIMPLEQ_HEAD *head, struct TYPE *elm, SIMPLEQ_ENTRY
+ NAME);
+
+ void
+ SIMPLEQ_INSERT_TAIL(SIMPLEQ_HEAD *head, struct TYPE *elm, SIMPLEQ_ENTRY
+ NAME);
+
+ void
+ SIMPLEQ_REMOVE_AFTER(SIMPLEQ_HEAD *head, struct TYPE *elm, SIMPLEQ_ENTRY
+ NAME);
+
+ void
+ SIMPLEQ_REMOVE_HEAD(SIMPLEQ_HEAD *head, SIMPLEQ_ENTRY NAME);
+
+ TAILQ_ENTRY(TYPE);
+
+ TAILQ_HEAD(HEADNAME, TYPE);
+
+ TAILQ_HEAD_INITIALIZER(TAILQ_HEAD head);
+
+ struct TYPE *
+ TAILQ_FIRST(TAILQ_HEAD *head);
+
+ struct TYPE *
+ TAILQ_NEXT(struct TYPE *listelm, TAILQ_ENTRY NAME);
+
+ struct TYPE *
+ TAILQ_END(TAILQ_HEAD *head);
+
+ struct TYPE *
+ TAILQ_LAST(TAILQ_HEAD *head, HEADNAME NAME);
+
+ struct TYPE *
+ TAILQ_PREV(struct TYPE *listelm, HEADNAME NAME, TAILQ_ENTRY NAME);
+
+ int
+ TAILQ_EMPTY(TAILQ_HEAD *head);
+
+ TAILQ_FOREACH(VARNAME, TAILQ_HEAD *head, TAILQ_ENTRY NAME);
+
+ TAILQ_FOREACH_SAFE(VARNAME, TAILQ_HEAD *head, TAILQ_ENTRY
+ NAME, TEMP_VARNAME);
+
+ TAILQ_FOREACH_REVERSE(VARNAME, TAILQ_HEAD *head, HEADNAME, TAILQ_ENTRY
+ NAME);
+
+ TAILQ_FOREACH_REVERSE_SAFE(VARNAME, TAILQ_HEAD
+ *head, HEADNAME, TAILQ_ENTRY NAME, TEMP_VARNAME);
+
+ void
+ TAILQ_INIT(TAILQ_HEAD *head);
+
+ void
+ TAILQ_INSERT_AFTER(TAILQ_HEAD *head, struct TYPE *listelm, struct TYPE
+ *elm, TAILQ_ENTRY NAME);
+
+ void
+ TAILQ_INSERT_BEFORE(struct TYPE *listelm, struct TYPE *elm, TAILQ_ENTRY
+ NAME);
+
+ void
+ TAILQ_INSERT_HEAD(TAILQ_HEAD *head, struct TYPE *elm, TAILQ_ENTRY NAME);
+
+ void
+ TAILQ_INSERT_TAIL(TAILQ_HEAD *head, struct TYPE *elm, TAILQ_ENTRY NAME);
+
+ void
+ TAILQ_REMOVE(TAILQ_HEAD *head, struct TYPE *elm, TAILQ_ENTRY NAME);
+
+ void
+ TAILQ_REPLACE(TAILQ_HEAD *head, struct TYPE *elm, struct TYPE
+ *elm2, TAILQ_ENTRY NAME);
+
+ CIRCLEQ_ENTRY(TYPE);
+
+ CIRCLEQ_HEAD(HEADNAME, TYPE);
+
+ CIRCLEQ_HEAD_INITIALIZER(CIRCLEQ_HEAD head);
+
+ struct TYPE *
+ CIRCLEQ_FIRST(CIRCLEQ_HEAD *head);
+
+ struct TYPE *
+ CIRCLEQ_LAST(CIRCLEQ_HEAD *head);
+
+ struct TYPE *
+ CIRCLEQ_END(CIRCLEQ_HEAD *head);
+
+ struct TYPE *
+ CIRCLEQ_NEXT(struct TYPE *listelm, CIRCLEQ_ENTRY NAME);
+
+ struct TYPE *
+ CIRCLEQ_PREV(struct TYPE *listelm, CIRCLEQ_ENTRY NAME);
+
+ int
+ CIRCLEQ_EMPTY(CIRCLEQ_HEAD *head);
+
+ CIRCLEQ_FOREACH(VARNAME, CIRCLEQ_HEAD *head, CIRCLEQ_ENTRY NAME);
+
+ CIRCLEQ_FOREACH_SAFE(VARNAME, CIRCLEQ_HEAD *head, CIRCLEQ_ENTRY
+ NAME, TEMP_VARNAME);
+
+ CIRCLEQ_FOREACH_REVERSE(VARNAME, CIRCLEQ_HEAD *head, CIRCLEQ_ENTRY NAME);
+
+ CIRCLEQ_FOREACH_REVERSE_SAFE(VARNAME, CIRCLEQ_HEAD *head, CIRCLEQ_ENTRY
+ NAME, TEMP_VARNAME);
+
+ void
+ CIRCLEQ_INIT(CIRCLEQ_HEAD *head);
+
+ void
+ CIRCLEQ_INSERT_AFTER(CIRCLEQ_HEAD *head, struct TYPE *listelm, struct
+ TYPE *elm, CIRCLEQ_ENTRY NAME);
+
+ void
+ CIRCLEQ_INSERT_BEFORE(CIRCLEQ_HEAD *head, struct TYPE *listelm, struct
+ TYPE *elm, CIRCLEQ_ENTRY NAME);
+
+ void
+ CIRCLEQ_INSERT_HEAD(CIRCLEQ_HEAD *head, struct TYPE *elm, CIRCLEQ_ENTRY
+ NAME);
+
+ void
+ CIRCLEQ_INSERT_TAIL(CIRCLEQ_HEAD *head, struct TYPE *elm, CIRCLEQ_ENTRY
+ NAME);
+
+ void
+ CIRCLEQ_REMOVE(CIRCLEQ_HEAD *head, struct TYPE *elm, CIRCLEQ_ENTRY NAME);
+
+ void
+ CIRCLEQ_REPLACE(CIRCLEQ_HEAD *head, struct TYPE *elm, struct TYPE
+ *elm2, CIRCLEQ_ENTRY NAME);
+
+DESCRIPTION
+ These macros define and operate on five types of data structures: singly-
+ linked lists, simple queues, lists, tail queues, and circular queues.
+ All five structures support the following functionality:
+
+ 1. Insertion of a new entry at the head of the list.
+ 2. Insertion of a new entry after any element in the list.
+ 3. Removal of an entry from the head of the list.
+ 4. Forward traversal through the list.
+
+ Singly-linked lists are the simplest of the five data structures and
+ support only the above functionality. Singly-linked lists are ideal for
+ applications with large datasets and few or no removals, or for
+ implementing a LIFO queue.
+
+ Simple queues add the following functionality:
+
+ 1. Entries can be added at the end of a list.
+
+ However:
+
+ 1. All list insertions must specify the head of the list.
+ 2. Each head entry requires two pointers rather than one.
+ 3. Code size is about 15% greater and operations run about 20%
+ slower than singly-linked lists.
+
+ Simple queues are ideal for applications with large datasets and few or
+ no removals, or for implementing a FIFO queue.
+
+ All doubly linked types of data structures (lists, tail queues, and
+ circle queues) additionally allow:
+
+ 1. Insertion of a new entry before any element in the list.
+ 2. Removal of any entry in the list.
+
+ However:
+
+ 1. Each element requires two pointers rather than one.
+ 2. Code size and execution time of operations (except for
+ removal) is about twice that of the singly-linked data-
+ structures.
+
+ Lists are the simplest of the doubly linked data structures and support
+ only the above functionality over singly-linked lists.
+
+ Tail queues add the following functionality:
+
+ 1. Entries can be added at the end of a list.
+ 2. They may be traversed backwards, at a cost.
+
+ However:
+
+ 1. All list insertions and removals must specify the head of the
+ list.
+ 2. Each head entry requires two pointers rather than one.
+ 3. Code size is about 15% greater and operations run about 20%
+ slower than singly-linked lists.
+
+ Circular queues add the following functionality:
+
+ 1. Entries can be added at the end of a list.
+ 2. They may be traversed backwards, from tail to head.
+
+ However:
+
+ 1. All list insertions and removals must specify the head of the
+ list.
+ 2. Each head entry requires two pointers rather than one.
+ 3. The termination condition for traversal is more complex.
+ 4. Code size is about 40% greater and operations run about 45%
+ slower than lists.
+
+ In the macro definitions, TYPE is the name tag of a user defined
+ structure that must contain a field of type SLIST_ENTRY, LIST_ENTRY,
+ SIMPLEQ_ENTRY, TAILQ_ENTRY, or CIRCLEQ_ENTRY, named NAME. The argument
+ HEADNAME is the name tag of a user defined structure that must be
+ declared using the macros SLIST_HEAD(), LIST_HEAD(), SIMPLEQ_HEAD(),
+ TAILQ_HEAD(), or CIRCLEQ_HEAD(). See the examples below for further
+ explanation of how these macros are used.
+
+SINGLY-LINKED LISTS
+ A singly-linked list is headed by a structure defined by the SLIST_HEAD()
+ macro. This structure contains a single pointer to the first element on
+ the list. The elements are singly linked for minimum space and pointer
+ manipulation overhead at the expense of O(n) removal for arbitrary
+ elements. New elements can be added to the list after an existing
+ element or at the head of the list. A SLIST_HEAD structure is declared
+ as follows:
+
+ SLIST_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the list. A pointer
+ to the head of the list can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The HEADNAME facility is often not used, leading to the following bizarre
+ code:
+
+ SLIST_HEAD(, TYPE) head, *headp;
+
+ The SLIST_ENTRY() macro declares a structure that connects the elements
+ in the list.
+
+ The SLIST_INIT() macro initializes the list referenced by head.
+
+ The list can also be initialized statically by using the
+ SLIST_HEAD_INITIALIZER() macro like this:
+
+ SLIST_HEAD(HEADNAME, TYPE) head = SLIST_HEAD_INITIALIZER(head);
+
+ The SLIST_INSERT_HEAD() macro inserts the new element elm at the head of
+ the list.
+
+ The SLIST_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The SLIST_REMOVE_HEAD() macro removes the first element of the list
+ pointed by head.
+
+ The SLIST_REMOVE_AFTER() macro removes the list element immediately
+ following elm.
+
+ The SLIST_REMOVE() macro removes the element elm of the list pointed by
+ head.
+
+ The SLIST_FIRST() and SLIST_NEXT() macros can be used to traverse the
+ list:
+
+ for (np = SLIST_FIRST(&head); np != NULL; np = SLIST_NEXT(np, NAME))
+
+ Or, for simplicity, one can use the SLIST_FOREACH() macro:
+
+ SLIST_FOREACH(np, head, NAME)
+
+ The macro SLIST_FOREACH_SAFE() traverses the list referenced by head in a
+ forward direction, assigning each element in turn to var. However,
+ unlike SLIST_FOREACH() it is permitted to remove var as well as free it
+ from within the loop safely without interfering with the traversal.
+
+ The SLIST_EMPTY() macro should be used to check whether a simple list is
+ empty.
+
+SINGLY-LINKED LIST EXAMPLE
+ SLIST_HEAD(listhead, entry) head;
+ struct entry {
+ ...
+ SLIST_ENTRY(entry) entries; /* Simple list. */
+ ...
+ } *n1, *n2, *np;
+
+ SLIST_INIT(&head); /* Initialize simple list. */
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ SLIST_INSERT_HEAD(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ SLIST_INSERT_AFTER(n1, n2, entries);
+
+ SLIST_FOREACH(np, &head, entries) /* Forward traversal. */
+ np-> ...
+
+ while (!SLIST_EMPTY(&head)) { /* Delete. */
+ n1 = SLIST_FIRST(&head);
+ SLIST_REMOVE_HEAD(&head, entries);
+ free(n1);
+ }
+
+
+LISTS
+ A list is headed by a structure defined by the LIST_HEAD() macro. This
+ structure contains a single pointer to the first element on the list.
+ The elements are doubly linked so that an arbitrary element can be
+ removed without traversing the list. New elements can be added to the
+ list after an existing element, before an existing element, or at the
+ head of the list. A LIST_HEAD structure is declared as follows:
+
+ LIST_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the list. A pointer
+ to the head of the list can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The HEADNAME facility is often not used, leading to the following bizarre
+ code:
+
+ LIST_HEAD(, TYPE) head, *headp;
+
+ The LIST_ENTRY() macro declares a structure that connects the elements in
+ the list.
+
+ The LIST_INIT() macro initializes the list referenced by head.
+
+ The list can also be initialized statically by using the
+ LIST_HEAD_INITIALIZER() macro like this:
+
+ LIST_HEAD(HEADNAME, TYPE) head = LIST_HEAD_INITIALIZER(head);
+
+ The LIST_INSERT_HEAD() macro inserts the new element elm at the head of
+ the list.
+
+ The LIST_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The LIST_INSERT_BEFORE() macro inserts the new element elm before the
+ element listelm.
+
+ The LIST_REMOVE() macro removes the element elm from the list.
+
+ The LIST_REPLACE() macro replaces the list element elm with the new
+ element elm2.
+
+ The LIST_FIRST() and LIST_NEXT() macros can be used to traverse the list:
+
+ for (np = LIST_FIRST(&head); np != NULL; np = LIST_NEXT(np, NAME))
+
+ Or, for simplicity, one can use the LIST_FOREACH() macro:
+
+ LIST_FOREACH(np, head, NAME)
+
+ The macro LIST_FOREACH_SAFE() traverses the list referenced by head in a
+ forward direction, assigning each element in turn to var. However,
+ unlike LIST_FOREACH() it is permitted to remove var as well as free it
+ from within the loop safely without interfering with the traversal.
+
+ The LIST_EMPTY() macro should be used to check whether a list is empty.
+
+LIST EXAMPLE
+ LIST_HEAD(listhead, entry) head;
+ struct entry {
+ ...
+ LIST_ENTRY(entry) entries; /* List. */
+ ...
+ } *n1, *n2, *np;
+
+ LIST_INIT(&head); /* Initialize list. */
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ LIST_INSERT_HEAD(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ LIST_INSERT_AFTER(n1, n2, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert before. */
+ LIST_INSERT_BEFORE(n1, n2, entries);
+ /* Forward traversal. */
+ LIST_FOREACH(np, &head, entries)
+ np-> ...
+
+ while (!LIST_EMPTY(&head)) /* Delete. */
+ n1 = LIST_FIRST(&head);
+ LIST_REMOVE(n1, entries);
+ free(n1);
+ }
+
+SIMPLE QUEUES
+ A simple queue is headed by a structure defined by the SIMPLEQ_HEAD()
+ macro. This structure contains a pair of pointers, one to the first
+ element in the simple queue and the other to the last element in the
+ simple queue. The elements are singly linked. New elements can be added
+ to the queue after an existing element, at the head of the queue or at
+ the tail of the queue. A SIMPLEQ_HEAD structure is declared as follows:
+
+ SIMPLEQ_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the queue. A pointer
+ to the head of the queue can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The SIMPLEQ_ENTRY() macro declares a structure that connects the elements
+ in the queue.
+
+ The SIMPLEQ_INIT() macro initializes the queue referenced by head.
+
+ The queue can also be initialized statically by using the
+ SIMPLEQ_HEAD_INITIALIZER() macro like this:
+
+ SIMPLEQ_HEAD(HEADNAME, TYPE) head = SIMPLEQ_HEAD_INITIALIZER(head);
+
+ The SIMPLEQ_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The SIMPLEQ_INSERT_HEAD() macro inserts the new element elm at the head
+ of the queue.
+
+ The SIMPLEQ_INSERT_TAIL() macro inserts the new element elm at the end of
+ the queue.
+
+ The SIMPLEQ_REMOVE_AFTER() macro removes the queue element immediately
+ following elm.
+
+ The SIMPLEQ_REMOVE_HEAD() macro removes the first element from the queue.
+
+ The SIMPLEQ_FIRST() and SIMPLEQ_NEXT() macros can be used to traverse the
+ queue. The SIMPLEQ_FOREACH() is used for queue traversal:
+
+ SIMPLEQ_FOREACH(np, head, NAME)
+
+ The macro SIMPLEQ_FOREACH_SAFE() traverses the queue referenced by head
+ in a forward direction, assigning each element in turn to var. However,
+ unlike SIMPLEQ_FOREACH() it is permitted to remove var as well as free it
+ from within the loop safely without interfering with the traversal.
+
+ The SIMPLEQ_EMPTY() macro should be used to check whether a list is
+ empty.
+
+SIMPLE QUEUE EXAMPLE
+ SIMPLEQ_HEAD(listhead, entry) head = SIMPLEQ_HEAD_INITIALIZER(head);
+ struct entry {
+ ...
+ SIMPLEQ_ENTRY(entry) entries; /* Simple queue. */
+ ...
+ } *n1, *n2, *np;
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ SIMPLEQ_INSERT_HEAD(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ SIMPLEQ_INSERT_AFTER(&head, n1, n2, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert at the tail. */
+ SIMPLEQ_INSERT_TAIL(&head, n2, entries);
+ /* Forward traversal. */
+ SIMPLEQ_FOREACH(np, &head, entries)
+ np-> ...
+ /* Delete. */
+ while (!SIMPLEQ_EMPTY(&head)) {
+ n1 = SIMPLEQ_FIRST(&head);
+ SIMPLEQ_REMOVE_HEAD(&head, entries);
+ free(n1);
+ }
+
+TAIL QUEUES
+ A tail queue is headed by a structure defined by the TAILQ_HEAD() macro.
+ This structure contains a pair of pointers, one to the first element in
+ the tail queue and the other to the last element in the tail queue. The
+ elements are doubly linked so that an arbitrary element can be removed
+ without traversing the tail queue. New elements can be added to the
+ queue after an existing element, before an existing element, at the head
+ of the queue, or at the end of the queue. A TAILQ_HEAD structure is
+ declared as follows:
+
+ TAILQ_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the tail queue. A
+ pointer to the head of the tail queue can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The TAILQ_ENTRY() macro declares a structure that connects the elements
+ in the tail queue.
+
+ The TAILQ_INIT() macro initializes the tail queue referenced by head.
+
+ The tail queue can also be initialized statically by using the
+ TAILQ_HEAD_INITIALIZER() macro.
+
+ The TAILQ_INSERT_HEAD() macro inserts the new element elm at the head of
+ the tail queue.
+
+ The TAILQ_INSERT_TAIL() macro inserts the new element elm at the end of
+ the tail queue.
+
+ The TAILQ_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The TAILQ_INSERT_BEFORE() macro inserts the new element elm before the
+ element listelm.
+
+ The TAILQ_REMOVE() macro removes the element elm from the tail queue.
+
+ The TAILQ_REPLACE() macro replaces the list element elm with the new
+ element elm2.
+
+ TAILQ_FOREACH() and TAILQ_FOREACH_REVERSE() are used for traversing a
+ tail queue. TAILQ_FOREACH() starts at the first element and proceeds
+ towards the last. TAILQ_FOREACH_REVERSE() starts at the last element and
+ proceeds towards the first.
+
+ TAILQ_FOREACH(np, &head, NAME)
+ TAILQ_FOREACH_REVERSE(np, &head, HEADNAME, NAME)
+
+ The macros TAILQ_FOREACH_SAFE() and TAILQ_FOREACH_REVERSE_SAFE() traverse
+ the list referenced by head in a forward or reverse direction
+ respectively, assigning each element in turn to var. However, unlike
+ their unsafe counterparts, they permit both the removal of var as well as
+ freeing it from within the loop safely without interfering with the
+ traversal.
+
+ The TAILQ_FIRST(), TAILQ_NEXT(), TAILQ_LAST() and TAILQ_PREV() macros can
+ be used to manually traverse a tail queue or an arbitrary part of one.
+
+ The TAILQ_EMPTY() macro should be used to check whether a tail queue is
+ empty.
+
+TAIL QUEUE EXAMPLE
+ TAILQ_HEAD(tailhead, entry) head;
+ struct entry {
+ ...
+ TAILQ_ENTRY(entry) entries; /* Tail queue. */
+ ...
+ } *n1, *n2, *np;
+
+ TAILQ_INIT(&head); /* Initialize queue. */
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ TAILQ_INSERT_HEAD(&head, n1, entries);
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */
+ TAILQ_INSERT_TAIL(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ TAILQ_INSERT_AFTER(&head, n1, n2, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert before. */
+ TAILQ_INSERT_BEFORE(n1, n2, entries);
+ /* Forward traversal. */
+ TAILQ_FOREACH(np, &head, entries)
+ np-> ...
+ /* Manual forward traversal. */
+ for (np = n2; np != NULL; np = TAILQ_NEXT(np, entries))
+ np-> ...
+ /* Delete. */
+ while ((np = TAILQ_FIRST(&head))) {
+ TAILQ_REMOVE(&head, np, entries);
+ free(np);
+ }
+
+
+CIRCULAR QUEUES
+ A circular queue is headed by a structure defined by the CIRCLEQ_HEAD()
+ macro. This structure contains a pair of pointers, one to the first
+ element in the circular queue and the other to the last element in the
+ circular queue. The elements are doubly linked so that an arbitrary
+ element can be removed without traversing the queue. New elements can be
+ added to the queue after an existing element, before an existing element,
+ at the head of the queue, or at the end of the queue. A CIRCLEQ_HEAD
+ structure is declared as follows:
+
+ CIRCLEQ_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the circular queue. A
+ pointer to the head of the circular queue can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The CIRCLEQ_ENTRY() macro declares a structure that connects the elements
+ in the circular queue.
+
+ The CIRCLEQ_INIT() macro initializes the circular queue referenced by
+ head.
+
+ The circular queue can also be initialized statically by using the
+ CIRCLEQ_HEAD_INITIALIZER() macro.
+
+ The CIRCLEQ_INSERT_HEAD() macro inserts the new element elm at the head
+ of the circular queue.
+
+ The CIRCLEQ_INSERT_TAIL() macro inserts the new element elm at the end of
+ the circular queue.
+
+ The CIRCLEQ_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The CIRCLEQ_INSERT_BEFORE() macro inserts the new element elm before the
+ element listelm.
+
+ The CIRCLEQ_REMOVE() macro removes the element elm from the circular
+ queue.
+
+ The CIRCLEQ_REPLACE() macro replaces the list element elm with the new
+ element elm2.
+
+ The CIRCLEQ_FIRST(), CIRCLEQ_LAST(), CIRCLEQ_END(), CIRCLEQ_NEXT() and
+ CIRCLEQ_PREV() macros can be used to traverse a circular queue. The
+ CIRCLEQ_FOREACH() is used for circular queue forward traversal:
+
+ CIRCLEQ_FOREACH(np, head, NAME)
+
+ The CIRCLEQ_FOREACH_REVERSE() macro acts like CIRCLEQ_FOREACH() but
+ traverses the circular queue backwards.
+
+ The macros CIRCLEQ_FOREACH_SAFE() and CIRCLEQ_FOREACH_REVERSE_SAFE()
+ traverse the list referenced by head in a forward or reverse direction
+ respectively, assigning each element in turn to var. However, unlike
+ their unsafe counterparts, they permit both the removal of var as well as
+ freeing it from within the loop safely without interfering with the
+ traversal.
+
+ The CIRCLEQ_EMPTY() macro should be used to check whether a circular
+ queue is empty.
+
+CIRCULAR QUEUE EXAMPLE
+ CIRCLEQ_HEAD(circleq, entry) head;
+ struct entry {
+ ...
+ CIRCLEQ_ENTRY(entry) entries; /* Circular queue. */
+ ...
+ } *n1, *n2, *np;
+
+ CIRCLEQ_INIT(&head); /* Initialize circular queue. */
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ CIRCLEQ_INSERT_HEAD(&head, n1, entries);
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */
+ CIRCLEQ_INSERT_TAIL(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ CIRCLEQ_INSERT_AFTER(&head, n1, n2, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert before. */
+ CIRCLEQ_INSERT_BEFORE(&head, n1, n2, entries);
+ /* Forward traversal. */
+ CIRCLEQ_FOREACH(np, &head, entries)
+ np-> ...
+ /* Reverse traversal. */
+ CIRCLEQ_FOREACH_REVERSE(np, &head, entries)
+ np-> ...
+ /* Delete. */
+ while (!CIRCLEQ_EMPTY(&head)) {
+ n1 = CIRCLEQ_FIRST(&head);
+ CIRCLEQ_REMOVE(&head, n1, entries);
+ free(n1);
+ }
+
+NOTES
+ It is an error to assume the next and previous fields are preserved after
+ an element has been removed from a list or queue. Using any macro
+ (except the various forms of insertion) on an element removed from a list
+ or queue is incorrect. An example of erroneous usage is removing the
+ same element twice.
+
+ The SLIST_END(), LIST_END(), SIMPLEQ_END() and TAILQ_END() macros are
+ provided for symmetry with CIRCLEQ_END(). They expand to NULL and don't
+ serve any useful purpose.
+
+ Trying to free a list in the following way is a common error:
+
+ LIST_FOREACH(var, head, entry)
+ free(var);
+ free(head);
+
+ Since var is free'd, the FOREACH macros refer to a pointer that may have
+ been reallocated already. A similar situation occurs when the current
+ element is deleted from the list. In cases like these the data
+ structure's FOREACH_SAFE macros should be used instead.
+
+HISTORY
+ The queue functions first appeared in 4.4BSD.
+
+OpenBSD 5.0 April 11, 2012 OpenBSD 5.0
+======================================================================
+.\" $OpenBSD: queue.3,v 1.56 2012/04/11 13:29:14 naddy Exp $
+.\" $NetBSD: queue.3,v 1.4 1995/07/03 00:25:36 mycroft Exp $
+.\"
+.\" Copyright (c) 1993 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+
diff --git a/src/include.am b/src/include.am
new file mode 100644
index 0000000000..d0693e25b0
--- /dev/null
+++ b/src/include.am
@@ -0,0 +1,7 @@
+include src/ext/include.am
+include src/common/include.am
+include src/or/include.am
+include src/test/include.am
+include src/tools/include.am
+include src/win32/include.am
+include src/config/include.am
diff --git a/src/or/Makefile.am b/src/or/Makefile.am
deleted file mode 100644
index 3cc789a1be..0000000000
--- a/src/or/Makefile.am
+++ /dev/null
@@ -1,158 +0,0 @@
-bin_PROGRAMS = tor
-noinst_LIBRARIES = libtor.a
-
-if BUILD_NT_SERVICES
-tor_platform_source=ntmain.c
-else
-tor_platform_source=
-endif
-
-EXTRA_DIST=ntmain.c or_sha1.i Makefile.nmake
-
-if USE_EXTERNAL_EVDNS
-evdns_source=
-else
-evdns_source=eventdns.c
-endif
-
-libtor_a_SOURCES = \
- buffers.c \
- circuitbuild.c \
- circuitlist.c \
- circuituse.c \
- command.c \
- config.c \
- connection.c \
- connection_edge.c \
- connection_or.c \
- control.c \
- cpuworker.c \
- directory.c \
- dirserv.c \
- dirvote.c \
- dns.c \
- dnsserv.c \
- geoip.c \
- hibernate.c \
- main.c \
- microdesc.c \
- networkstatus.c \
- nodelist.c \
- onion.c \
- transports.c \
- policies.c \
- reasons.c \
- relay.c \
- rendclient.c \
- rendcommon.c \
- rendmid.c \
- rendservice.c \
- rephist.c \
- router.c \
- routerlist.c \
- routerparse.c \
- status.c \
- $(evdns_source) \
- $(tor_platform_source) \
- config_codedigest.c
-
-#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
-# ../common/libor-event.a
-
-
-tor_SOURCES = tor_main.c
-
-AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
- -DLOCALSTATEDIR="\"$(localstatedir)\"" \
- -DBINDIR="\"$(bindir)\""
-
-# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
-# This seems to matter nowhere but on windows, but I assure you that it
-# matters a lot there, and is quite hard to debug if you forget to do it.
-
-
-tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
-tor_LDADD = ./libtor.a ../common/libor.a ../common/libor-crypto.a \
- ../common/libor-event.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-noinst_HEADERS = \
- buffers.h \
- circuitbuild.h \
- circuitlist.h \
- circuituse.h \
- command.h \
- config.h \
- connection.h \
- connection_edge.h \
- connection_or.h \
- control.h \
- cpuworker.h \
- directory.h \
- dirserv.h \
- dirvote.h \
- dns.h \
- dnsserv.h \
- eventdns.h \
- eventdns_tor.h \
- geoip.h \
- hibernate.h \
- main.h \
- microdesc.h \
- networkstatus.h \
- nodelist.h \
- ntmain.h \
- onion.h \
- or.h \
- transports.h \
- policies.h \
- reasons.h \
- relay.h \
- rendclient.h \
- rendcommon.h \
- rendmid.h \
- rendservice.h \
- rephist.h \
- router.h \
- routerlist.h \
- routerparse.h \
- status.h \
- micro-revision.i
-
-config_codedigest.o: or_sha1.i
-
-tor_main.o: micro-revision.i
-
-micro-revision.i: FORCE
- @rm -f micro-revision.tmp; \
- if test -d "$(top_srcdir)/.git" && \
- test -x "`which git 2>&1;true`"; then \
- HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \
- echo \"$$HASH\" > micro-revision.tmp; \
- fi; \
- if test ! -f micro-revision.tmp ; then \
- if test ! -f micro-revision.i ; then \
- echo '""' > micro-revision.i; \
- fi; \
- elif test ! -f micro-revision.i || \
- test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \
- mv micro-revision.tmp micro-revision.i; \
- fi; true
-
-or_sha1.i: $(tor_SOURCES) $(libtor_a_SOURCES)
- if test "@SHA1SUM@" != none; then \
- (cd "$(srcdir)" && "@SHA1SUM@" $(tor_SOURCES) $(libtor_a_SOURCES)) | \
- "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > or_sha1.i; \
- elif test "@OPENSSL@" != none; then \
- (cd "$(srcdir)" && "@OPENSSL@" sha1 $(tor_SOURCES) $(libtor_a_SOURCES)) | \
- "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > or_sha1.i; \
- else \
- rm or_sha1.i; \
- touch or_sha1.i; \
- fi
-
-CLEANFILES = micro-revision.i
-
-#Dummy target to ensure that micro-revision.i _always_ gets built.
-FORCE:
diff --git a/src/or/Makefile.nmake b/src/or/Makefile.nmake
index 3181e79c20..677618e74f 100644
--- a/src/or/Makefile.nmake
+++ b/src/or/Makefile.nmake
@@ -8,15 +8,15 @@ LIBS = ..\..\..\build-alpha\lib\libevent.a \
..\..\..\build-alpha\lib\libz.a \
ws2_32.lib advapi32.lib shell32.lib
-LIBTOR_OBJECTS = buffers.obj circuitbuild.obj circuitlist.obj circuituse.obj \
+LIBTOR_OBJECTS = buffers.obj channel.obj channeltls.obj circuitbuild.obj \
+ circuitlist.obj circuitmux.obj circuitmux_ewma.obj circuituse.obj \
command.obj config.obj connection.obj connection_edge.obj \
connection_or.obj control.obj cpuworker.obj directory.obj \
- dirserv.obj dirvote.obj dns.obj dnsserv.obj geoip.obj \
- hibernate.obj main.obj microdesc.obj networkstatus.obj \
- nodelist.obj onion.obj policies.obj reasons.obj relay.obj \
- rendclient.obj rendcommon.obj rendmid.obj rendservice.obj \
- rephist.obj router.obj routerlist.obj routerparse.obj status.obj \
- config_codedigest.obj ntmain.obj
+ dirserv.obj dirvote.obj dns.obj dnsserv.obj geoip.obj hibernate.obj \
+ main.obj microdesc.obj networkstatus.obj nodelist.obj onion.obj \
+ policies.obj reasons.obj relay.obj rendclient.obj rendcommon.obj \
+ rendmid.obj rendservice.obj rephist.obj router.obj routerlist.obj \
+ routerparse.obj status.obj config_codedigest.obj ntmain.obj
libtor.lib: $(LIBTOR_OBJECTS)
lib $(LIBTOR_OBJECTS) /out:libtor.lib
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
new file mode 100644
index 0000000000..98448ebddf
--- /dev/null
+++ b/src/or/addressmap.c
@@ -0,0 +1,974 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "addressmap.h"
+#include "circuituse.h"
+#include "config.h"
+#include "connection_edge.h"
+#include "control.h"
+#include "dns.h"
+#include "routerset.h"
+#include "nodelist.h"
+
+/** A client-side struct to remember requests to rewrite addresses
+ * to new addresses. These structs are stored in the hash table
+ * "addressmap" below.
+ *
+ * There are 5 ways to set an address mapping:
+ * - A MapAddress command from the controller [permanent]
+ * - An AddressMap directive in the torrc [permanent]
+ * - When a TrackHostExits torrc directive is triggered [temporary]
+ * - When a DNS resolve succeeds [temporary]
+ * - When a DNS resolve fails [temporary]
+ *
+ * When an addressmap request is made but one is already registered,
+ * the new one is replaced only if the currently registered one has
+ * no "new_address" (that is, it's in the process of DNS resolve),
+ * or if the new one is permanent (expires==0 or 1).
+ *
+ * (We overload the 'expires' field, using "0" for mappings set via
+ * the configuration file, "1" for mappings set from the control
+ * interface, and other values for DNS and TrackHostExit mappings that can
+ * expire.)
+ *
+ * A mapping may be 'wildcarded'. If "src_wildcard" is true, then
+ * any address that ends with a . followed by the key for this entry will
+ * get remapped by it. If "dst_wildcard" is also true, then only the
+ * matching suffix of such addresses will get replaced by new_address.
+ */
+typedef struct {
+ char *new_address;
+ time_t expires;
+ addressmap_entry_source_t source:3;
+ unsigned src_wildcard:1;
+ unsigned dst_wildcard:1;
+ short num_resolve_failures;
+} addressmap_entry_t;
+
+/** Entry for mapping addresses to which virtual address we mapped them to. */
+typedef struct {
+ char *ipv4_address;
+ char *hostname_address;
+} virtaddress_entry_t;
+
+/** A hash table to store client-side address rewrite instructions. */
+static strmap_t *addressmap=NULL;
+/**
+ * Table mapping addresses to which virtual address, if any, we
+ * assigned them to.
+ *
+ * We maintain the following invariant: if [A,B] is in
+ * virtaddress_reversemap, then B must be a virtual address, and [A,B]
+ * must be in addressmap. We do not require that the converse hold:
+ * if it fails, then we could end up mapping two virtual addresses to
+ * the same address, which is no disaster.
+ **/
+static strmap_t *virtaddress_reversemap=NULL;
+
+/** Initialize addressmap. */
+void
+addressmap_init(void)
+{
+ addressmap = strmap_new();
+ virtaddress_reversemap = strmap_new();
+}
+
+/** Free the memory associated with the addressmap entry <b>_ent</b>. */
+static void
+addressmap_ent_free(void *_ent)
+{
+ addressmap_entry_t *ent;
+ if (!_ent)
+ return;
+
+ ent = _ent;
+ tor_free(ent->new_address);
+ tor_free(ent);
+}
+
+/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
+static void
+addressmap_virtaddress_ent_free(void *_ent)
+{
+ virtaddress_entry_t *ent;
+ if (!_ent)
+ return;
+
+ ent = _ent;
+ tor_free(ent->ipv4_address);
+ tor_free(ent->hostname_address);
+ tor_free(ent);
+}
+
+/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
+static void
+addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
+{
+ if (ent && ent->new_address &&
+ address_is_in_virtual_range(ent->new_address)) {
+ virtaddress_entry_t *ve =
+ strmap_get(virtaddress_reversemap, ent->new_address);
+ /*log_fn(LOG_NOTICE,"remove reverse mapping for %s",ent->new_address);*/
+ if (ve) {
+ if (!strcmp(address, ve->ipv4_address))
+ tor_free(ve->ipv4_address);
+ if (!strcmp(address, ve->hostname_address))
+ tor_free(ve->hostname_address);
+ if (!ve->ipv4_address && !ve->hostname_address) {
+ tor_free(ve);
+ strmap_remove(virtaddress_reversemap, ent->new_address);
+ }
+ }
+ }
+}
+
+/** Remove <b>ent</b> (which must be mapped to by <b>address</b>) from the
+ * client address maps. */
+static void
+addressmap_ent_remove(const char *address, addressmap_entry_t *ent)
+{
+ addressmap_virtaddress_remove(address, ent);
+ addressmap_ent_free(ent);
+}
+
+/** Unregister all TrackHostExits mappings from any address to
+ * *.exitname.exit. */
+void
+clear_trackexithost_mappings(const char *exitname)
+{
+ char *suffix = NULL;
+ if (!addressmap || !exitname)
+ return;
+ tor_asprintf(&suffix, ".%s.exit", exitname);
+ tor_strlower(suffix);
+
+ STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
+ if (ent->source == ADDRMAPSRC_TRACKEXIT &&
+ !strcmpend(ent->new_address, suffix)) {
+ addressmap_ent_remove(address, ent);
+ MAP_DEL_CURRENT(address);
+ }
+ } STRMAP_FOREACH_END;
+
+ tor_free(suffix);
+}
+
+/** Remove all TRACKEXIT mappings from the addressmap for which the target
+ * host is unknown or no longer allowed, or for which the source address
+ * is no longer in trackexithosts. */
+void
+addressmap_clear_excluded_trackexithosts(const or_options_t *options)
+{
+ const routerset_t *allow_nodes = options->ExitNodes;
+ const routerset_t *exclude_nodes = options->ExcludeExitNodesUnion_;
+
+ if (!addressmap)
+ return;
+ if (routerset_is_empty(allow_nodes))
+ allow_nodes = NULL;
+ if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
+ return;
+
+ STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
+ size_t len;
+ const char *target = ent->new_address, *dot;
+ char *nodename;
+ const node_t *node;
+
+ if (!target) {
+ /* DNS resolving in progress */
+ continue;
+ } else if (strcmpend(target, ".exit")) {
+ /* Not a .exit mapping */
+ continue;
+ } else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
+ /* Not a trackexit mapping. */
+ continue;
+ }
+ len = strlen(target);
+ if (len < 6)
+ continue; /* malformed. */
+ dot = target + len - 6; /* dot now points to just before .exit */
+ while (dot > target && *dot != '.')
+ dot--;
+ if (*dot == '.') dot++;
+ nodename = tor_strndup(dot, len-5-(dot-target));;
+ node = node_get_by_nickname(nodename, 0);
+ tor_free(nodename);
+ if (!node ||
+ (allow_nodes && !routerset_contains_node(allow_nodes, node)) ||
+ routerset_contains_node(exclude_nodes, node) ||
+ !hostname_in_track_host_exits(options, address)) {
+ /* We don't know this one, or we want to be rid of it. */
+ addressmap_ent_remove(address, ent);
+ MAP_DEL_CURRENT(address);
+ }
+ } STRMAP_FOREACH_END;
+}
+
+/** Remove all AUTOMAP mappings from the addressmap for which the
+ * source address no longer matches AutomapHostsSuffixes, which is
+ * no longer allowed by AutomapHostsOnResolve, or for which the
+ * target address is no longer in the virtual network. */
+void
+addressmap_clear_invalid_automaps(const or_options_t *options)
+{
+ int clear_all = !options->AutomapHostsOnResolve;
+ const smartlist_t *suffixes = options->AutomapHostsSuffixes;
+
+ if (!addressmap)
+ return;
+
+ if (!suffixes)
+ clear_all = 1; /* This should be impossible, but let's be sure. */
+
+ STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) {
+ int remove = clear_all;
+ if (ent->source != ADDRMAPSRC_AUTOMAP)
+ continue; /* not an automap mapping. */
+
+ if (!remove) {
+ int suffix_found = 0;
+ SMARTLIST_FOREACH(suffixes, const char *, suffix, {
+ if (!strcasecmpend(src_address, suffix)) {
+ suffix_found = 1;
+ break;
+ }
+ });
+ if (!suffix_found)
+ remove = 1;
+ }
+
+ if (!remove && ! address_is_in_virtual_range(ent->new_address))
+ remove = 1;
+
+ if (remove) {
+ addressmap_ent_remove(src_address, ent);
+ MAP_DEL_CURRENT(src_address);
+ }
+ } STRMAP_FOREACH_END;
+}
+
+/** Remove all entries from the addressmap that were set via the
+ * configuration file or the command line. */
+void
+addressmap_clear_configured(void)
+{
+ addressmap_get_mappings(NULL, 0, 0, 0);
+}
+
+/** Remove all entries from the addressmap that are set to expire, ever. */
+void
+addressmap_clear_transient(void)
+{
+ addressmap_get_mappings(NULL, 2, TIME_MAX, 0);
+}
+
+/** Clean out entries from the addressmap cache that were
+ * added long enough ago that they are no longer valid.
+ */
+void
+addressmap_clean(time_t now)
+{
+ addressmap_get_mappings(NULL, 2, now, 0);
+}
+
+/** Free all the elements in the addressmap, and free the addressmap
+ * itself. */
+void
+addressmap_free_all(void)
+{
+ strmap_free(addressmap, addressmap_ent_free);
+ addressmap = NULL;
+
+ strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
+ virtaddress_reversemap = NULL;
+}
+
+/** Try to find a match for AddressMap expressions that use
+ * wildcard notation such as '*.c.d *.e.f' (so 'a.c.d' will map to 'a.e.f') or
+ * '*.c.d a.b.c' (so 'a.c.d' will map to a.b.c).
+ * Return the matching entry in AddressMap or NULL if no match is found.
+ * For expressions such as '*.c.d *.e.f', truncate <b>address</b> 'a.c.d'
+ * to 'a' before we return the matching AddressMap entry.
+ *
+ * This function does not handle the case where a pattern of the form "*.c.d"
+ * matches the address c.d -- that's done by the main addressmap_rewrite
+ * function.
+ */
+static addressmap_entry_t *
+addressmap_match_superdomains(char *address)
+{
+ addressmap_entry_t *val;
+ char *cp;
+
+ cp = address;
+ while ((cp = strchr(cp, '.'))) {
+ /* cp now points to a suffix of address that begins with a . */
+ val = strmap_get_lc(addressmap, cp+1);
+ if (val && val->src_wildcard) {
+ if (val->dst_wildcard)
+ *cp = '\0';
+ return val;
+ }
+ ++cp;
+ }
+ return NULL;
+}
+
+/** Look at address, and rewrite it until it doesn't want any
+ * more rewrites; but don't get into an infinite loop.
+ * Don't write more than maxlen chars into address. Return true if the
+ * address changed; false otherwise. Set *<b>expires_out</b> to the
+ * expiry time of the result, or to <b>time_max</b> if the result does
+ * not expire.
+ *
+ * If <b>exit_source_out</b> is non-null, we set it as follows. If we the
+ * address starts out as a non-exit address, and we remap it to an .exit
+ * address at any point, then set *<b>exit_source_out</b> to the
+ * address_entry_source_t of the first such rule. Set *<b>exit_source_out</b>
+ * to ADDRMAPSRC_NONE if there is no such rewrite, or if the original address
+ * was a .exit.
+ */
+int
+addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out,
+ addressmap_entry_source_t *exit_source_out)
+{
+ addressmap_entry_t *ent;
+ int rewrites;
+ time_t expires = TIME_MAX;
+ addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE;
+ char *addr_orig = tor_strdup(address);
+ char *log_addr_orig = NULL;
+
+ for (rewrites = 0; rewrites < 16; rewrites++) {
+ int exact_match = 0;
+ log_addr_orig = tor_strdup(escaped_safe_str_client(address));
+
+ ent = strmap_get(addressmap, address);
+
+ if (!ent || !ent->new_address) {
+ ent = addressmap_match_superdomains(address);
+ } else {
+ if (ent->src_wildcard && !ent->dst_wildcard &&
+ !strcasecmp(address, ent->new_address)) {
+ /* This is a rule like *.example.com example.com, and we just got
+ * "example.com" */
+ goto done;
+ }
+
+ exact_match = 1;
+ }
+
+ if (!ent || !ent->new_address) {
+ goto done;
+ }
+
+ if (ent->dst_wildcard && !exact_match) {
+ strlcat(address, ".", maxlen);
+ strlcat(address, ent->new_address, maxlen);
+ } else {
+ strlcpy(address, ent->new_address, maxlen);
+ }
+
+ if (!strcmpend(address, ".exit") &&
+ strcmpend(addr_orig, ".exit") &&
+ exit_source == ADDRMAPSRC_NONE) {
+ exit_source = ent->source;
+ }
+
+ log_info(LD_APP, "Addressmap: rewriting %s to %s",
+ log_addr_orig, escaped_safe_str_client(address));
+ if (ent->expires > 1 && ent->expires < expires)
+ expires = ent->expires;
+
+ tor_free(log_addr_orig);
+ }
+ log_warn(LD_CONFIG,
+ "Loop detected: we've rewritten %s 16 times! Using it as-is.",
+ escaped_safe_str_client(address));
+ /* it's fine to rewrite a rewrite, but don't loop forever */
+
+ done:
+ tor_free(addr_orig);
+ tor_free(log_addr_orig);
+ if (exit_source_out)
+ *exit_source_out = exit_source;
+ if (expires_out)
+ *expires_out = TIME_MAX;
+ return (rewrites > 0);
+}
+
+/** If we have a cached reverse DNS entry for the address stored in the
+ * <b>maxlen</b>-byte buffer <b>address</b> (typically, a dotted quad) then
+ * rewrite to the cached value and return 1. Otherwise return 0. Set
+ * *<b>expires_out</b> to the expiry time of the result, or to <b>time_max</b>
+ * if the result does not expire. */
+int
+addressmap_rewrite_reverse(char *address, size_t maxlen, time_t *expires_out)
+{
+ char *s, *cp;
+ addressmap_entry_t *ent;
+ int r = 0;
+ tor_asprintf(&s, "REVERSE[%s]", address);
+ ent = strmap_get(addressmap, s);
+ if (ent) {
+ cp = tor_strdup(escaped_safe_str_client(ent->new_address));
+ log_info(LD_APP, "Rewrote reverse lookup %s -> %s",
+ escaped_safe_str_client(s), cp);
+ tor_free(cp);
+ strlcpy(address, ent->new_address, maxlen);
+ r = 1;
+ }
+
+ if (expires_out)
+ *expires_out = (ent && ent->expires > 1) ? ent->expires : TIME_MAX;
+
+ tor_free(s);
+ return r;
+}
+
+/** Return 1 if <b>address</b> is already registered, else return 0. If address
+ * is already registered, and <b>update_expires</b> is non-zero, then update
+ * the expiry time on the mapping with update_expires if it is a
+ * mapping created by TrackHostExits. */
+int
+addressmap_have_mapping(const char *address, int update_expiry)
+{
+ addressmap_entry_t *ent;
+ if (!(ent=strmap_get_lc(addressmap, address)))
+ return 0;
+ if (update_expiry && ent->source==ADDRMAPSRC_TRACKEXIT)
+ ent->expires=time(NULL) + update_expiry;
+ return 1;
+}
+
+/** Register a request to map <b>address</b> to <b>new_address</b>,
+ * which will expire on <b>expires</b> (or 0 if never expires from
+ * config file, 1 if never expires from controller, 2 if never expires
+ * (virtual address mapping) from the controller.)
+ *
+ * <b>new_address</b> should be a newly dup'ed string, which we'll use or
+ * free as appropriate. We will leave address alone.
+ *
+ * If <b>wildcard_addr</b> is true, then the mapping will match any address
+ * equal to <b>address</b>, or any address ending with a period followed by
+ * <b>address</b>. If <b>wildcard_addr</b> and <b>wildcard_new_addr</b> are
+ * both true, the mapping will rewrite addresses that end with
+ * ".<b>address</b>" into ones that end with ".<b>new_address</b>."
+ *
+ * If <b>new_address</b> is NULL, or <b>new_address</b> is equal to
+ * <b>address</b> and <b>wildcard_addr</b> is equal to
+ * <b>wildcard_new_addr</b>, remove any mappings that exist from
+ * <b>address</b>.
+ *
+ *
+ * It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is
+ * not set. */
+void
+addressmap_register(const char *address, char *new_address, time_t expires,
+ addressmap_entry_source_t source,
+ const int wildcard_addr,
+ const int wildcard_new_addr)
+{
+ addressmap_entry_t *ent;
+
+ if (wildcard_new_addr)
+ tor_assert(wildcard_addr);
+
+ ent = strmap_get(addressmap, address);
+ if (!new_address || (!strcasecmp(address,new_address) &&
+ wildcard_addr == wildcard_new_addr)) {
+ /* Remove the mapping, if any. */
+ tor_free(new_address);
+ if (ent) {
+ addressmap_ent_remove(address,ent);
+ strmap_remove(addressmap, address);
+ }
+ return;
+ }
+ if (!ent) { /* make a new one and register it */
+ ent = tor_malloc_zero(sizeof(addressmap_entry_t));
+ strmap_set(addressmap, address, ent);
+ } else if (ent->new_address) { /* we need to clean up the old mapping. */
+ if (expires > 1) {
+ log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
+ "since it's already mapped to '%s'",
+ safe_str_client(address),
+ safe_str_client(new_address),
+ safe_str_client(ent->new_address));
+ tor_free(new_address);
+ return;
+ }
+ if (address_is_in_virtual_range(ent->new_address) &&
+ expires != 2) {
+ /* XXX This isn't the perfect test; we want to avoid removing
+ * mappings set from the control interface _as virtual mapping */
+ addressmap_virtaddress_remove(address, ent);
+ }
+ tor_free(ent->new_address);
+ } /* else { we have an in-progress resolve with no mapping. } */
+
+ ent->new_address = new_address;
+ ent->expires = expires==2 ? 1 : expires;
+ ent->num_resolve_failures = 0;
+ ent->source = source;
+ ent->src_wildcard = wildcard_addr ? 1 : 0;
+ ent->dst_wildcard = wildcard_new_addr ? 1 : 0;
+
+ log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
+ safe_str_client(address),
+ safe_str_client(ent->new_address));
+ control_event_address_mapped(address, ent->new_address, expires, NULL);
+}
+
+/** An attempt to resolve <b>address</b> failed at some OR.
+ * Increment the number of resolve failures we have on record
+ * for it, and then return that number.
+ */
+int
+client_dns_incr_failures(const char *address)
+{
+ addressmap_entry_t *ent = strmap_get(addressmap, address);
+ if (!ent) {
+ ent = tor_malloc_zero(sizeof(addressmap_entry_t));
+ ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE;
+ strmap_set(addressmap,address,ent);
+ }
+ if (ent->num_resolve_failures < SHORT_MAX)
+ ++ent->num_resolve_failures; /* don't overflow */
+ log_info(LD_APP, "Address %s now has %d resolve failures.",
+ safe_str_client(address),
+ ent->num_resolve_failures);
+ return ent->num_resolve_failures;
+}
+
+/** If <b>address</b> is in the client DNS addressmap, reset
+ * the number of resolve failures we have on record for it.
+ * This is used when we fail a stream because it won't resolve:
+ * otherwise future attempts on that address will only try once.
+ */
+void
+client_dns_clear_failures(const char *address)
+{
+ addressmap_entry_t *ent = strmap_get(addressmap, address);
+ if (ent)
+ ent->num_resolve_failures = 0;
+}
+
+/** Record the fact that <b>address</b> resolved to <b>name</b>.
+ * We can now use this in subsequent streams via addressmap_rewrite()
+ * so we can more correctly choose an exit that will allow <b>address</b>.
+ *
+ * If <b>exitname</b> is defined, then append the addresses with
+ * ".exitname.exit" before registering the mapping.
+ *
+ * If <b>ttl</b> is nonnegative, the mapping will be valid for
+ * <b>ttl</b>seconds; otherwise, we use the default.
+ */
+static void
+client_dns_set_addressmap_impl(origin_circuit_t *on_circ,
+ const char *address, const char *name,
+ const char *exitname,
+ int ttl)
+{
+ char *extendedaddress=NULL, *extendedval=NULL;
+ (void)on_circ;
+
+ tor_assert(address);
+ tor_assert(name);
+
+ if (ttl<0)
+ ttl = DEFAULT_DNS_TTL;
+ else
+ ttl = dns_clip_ttl(ttl);
+
+ if (exitname) {
+ /* XXXX fails to ever get attempts to get an exit address of
+ * google.com.digest[=~]nickname.exit; we need a syntax for this that
+ * won't make strict RFC952-compliant applications (like us) barf. */
+ tor_asprintf(&extendedaddress,
+ "%s.%s.exit", address, exitname);
+ tor_asprintf(&extendedval,
+ "%s.%s.exit", name, exitname);
+ } else {
+ tor_asprintf(&extendedaddress,
+ "%s", address);
+ tor_asprintf(&extendedval,
+ "%s", name);
+ }
+ addressmap_register(extendedaddress, extendedval,
+ time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0);
+ tor_free(extendedaddress);
+}
+
+/** Record the fact that <b>address</b> resolved to <b>val</b>.
+ * We can now use this in subsequent streams via addressmap_rewrite()
+ * so we can more correctly choose an exit that will allow <b>address</b>.
+ *
+ * If <b>exitname</b> is defined, then append the addresses with
+ * ".exitname.exit" before registering the mapping.
+ *
+ * If <b>ttl</b> is nonnegative, the mapping will be valid for
+ * <b>ttl</b>seconds; otherwise, we use the default.
+ */
+void
+client_dns_set_addressmap(origin_circuit_t *on_circ,
+ const char *address,
+ const tor_addr_t *val,
+ const char *exitname,
+ int ttl)
+{
+ tor_addr_t addr_tmp;
+ char valbuf[TOR_ADDR_BUF_LEN];
+
+ tor_assert(address);
+ tor_assert(val);
+
+ if (tor_addr_parse(&addr_tmp, address) == 0)
+ return; /* If address was an IP address already, don't add a mapping. */
+
+ /* XXXXX For now, don't cache IPv6 addresses. */
+ if (tor_addr_family(val) != AF_INET)
+ return;
+
+ if (! tor_addr_to_str(valbuf, val, sizeof(valbuf), 1))
+ return;
+
+ client_dns_set_addressmap_impl(on_circ, address, valbuf, exitname, ttl);
+}
+
+/** Add a cache entry noting that <b>address</b> (ordinarily a dotted quad)
+ * resolved via a RESOLVE_PTR request to the hostname <b>v</b>.
+ *
+ * If <b>exitname</b> is defined, then append the addresses with
+ * ".exitname.exit" before registering the mapping.
+ *
+ * If <b>ttl</b> is nonnegative, the mapping will be valid for
+ * <b>ttl</b>seconds; otherwise, we use the default.
+ */
+void
+client_dns_set_reverse_addressmap(origin_circuit_t *on_circ,
+ const char *address, const char *v,
+ const char *exitname,
+ int ttl)
+{
+ char *s = NULL;
+ tor_asprintf(&s, "REVERSE[%s]", address);
+ client_dns_set_addressmap_impl(on_circ, s, v, exitname, ttl);
+ tor_free(s);
+}
+
+/* By default, we hand out 127.192.0.1 through 127.254.254.254.
+ * These addresses should map to localhost, so even if the
+ * application accidentally tried to connect to them directly (not
+ * via Tor), it wouldn't get too far astray.
+ *
+ * These options are configured by parse_virtual_addr_network().
+ */
+/** Which network should we use for virtual IPv4 addresses? Only the first
+ * bits of this value are fixed. */
+static uint32_t virtual_addr_network = 0x7fc00000u;
+/** How many bits of <b>virtual_addr_network</b> are fixed? */
+static maskbits_t virtual_addr_netmask_bits = 10;
+/** What's the next virtual address we will hand out? */
+static uint32_t next_virtual_addr = 0x7fc00000u;
+
+/** Read a netmask of the form 127.192.0.0/10 from "val", and check whether
+ * it's a valid set of virtual addresses to hand out in response to MAPADDRESS
+ * requests. Return 0 on success; set *msg (if provided) to a newly allocated
+ * string and return -1 on failure. If validate_only is false, sets the
+ * actual virtual address range to the parsed value. */
+int
+parse_virtual_addr_network(const char *val, int validate_only,
+ char **msg)
+{
+ uint32_t addr;
+ uint16_t port_min, port_max;
+ maskbits_t bits;
+
+ if (parse_addr_and_port_range(val, &addr, &bits, &port_min, &port_max)) {
+ if (msg) *msg = tor_strdup("Error parsing VirtualAddressNetwork");
+ return -1;
+ }
+
+ if (port_min != 1 || port_max != 65535) {
+ if (msg) *msg = tor_strdup("Can't specify ports on VirtualAddressNetwork");
+ return -1;
+ }
+
+ if (bits > 16) {
+ if (msg) *msg = tor_strdup("VirtualAddressNetwork expects a /16 "
+ "network or larger");
+ return -1;
+ }
+
+ if (validate_only)
+ return 0;
+
+ virtual_addr_network = (uint32_t)( addr & (0xfffffffful << (32-bits)) );
+ virtual_addr_netmask_bits = bits;
+
+ if (addr_mask_cmp_bits(next_virtual_addr, addr, bits))
+ next_virtual_addr = addr;
+
+ return 0;
+}
+
+/**
+ * Return true iff <b>addr</b> is likely to have been returned by
+ * client_dns_get_unused_address.
+ **/
+int
+address_is_in_virtual_range(const char *address)
+{
+ struct in_addr in;
+ tor_assert(address);
+ if (!strcasecmpend(address, ".virtual")) {
+ return 1;
+ } else if (tor_inet_aton(address, &in)) {
+ uint32_t addr = ntohl(in.s_addr);
+ if (!addr_mask_cmp_bits(addr, virtual_addr_network,
+ virtual_addr_netmask_bits))
+ return 1;
+ }
+ return 0;
+}
+
+/** Increment the value of next_virtual_addr; reset it to the start of the
+ * virtual address range if it wraps around.
+ */
+static INLINE void
+increment_virtual_addr(void)
+{
+ ++next_virtual_addr;
+ if (addr_mask_cmp_bits(next_virtual_addr, virtual_addr_network,
+ virtual_addr_netmask_bits))
+ next_virtual_addr = virtual_addr_network;
+}
+
+/** Return a newly allocated string holding an address of <b>type</b>
+ * (one of RESOLVED_TYPE_{IPV4|HOSTNAME}) that has not yet been mapped,
+ * and that is very unlikely to be the address of any real host.
+ *
+ * May return NULL if we have run out of virtual addresses.
+ */
+static char *
+addressmap_get_virtual_address(int type)
+{
+ char buf[64];
+ tor_assert(addressmap);
+
+ if (type == RESOLVED_TYPE_HOSTNAME) {
+ char rand[10];
+ do {
+ crypto_rand(rand, sizeof(rand));
+ base32_encode(buf,sizeof(buf),rand,sizeof(rand));
+ strlcat(buf, ".virtual", sizeof(buf));
+ } while (strmap_get(addressmap, buf));
+ return tor_strdup(buf);
+ } else if (type == RESOLVED_TYPE_IPV4) {
+ // This is an imperfect estimate of how many addresses are available, but
+ // that's ok.
+ struct in_addr in;
+ uint32_t available = 1u << (32-virtual_addr_netmask_bits);
+ while (available) {
+ /* Don't hand out any .0 or .255 address. */
+ while ((next_virtual_addr & 0xff) == 0 ||
+ (next_virtual_addr & 0xff) == 0xff) {
+ increment_virtual_addr();
+ if (! --available) {
+ log_warn(LD_CONFIG, "Ran out of virtual addresses!");
+ return NULL;
+ }
+ }
+ in.s_addr = htonl(next_virtual_addr);
+ tor_inet_ntoa(&in, buf, sizeof(buf));
+ if (!strmap_get(addressmap, buf)) {
+ increment_virtual_addr();
+ break;
+ }
+
+ increment_virtual_addr();
+ --available;
+ // log_info(LD_CONFIG, "%d addrs available", (int)available);
+ if (! available) {
+ log_warn(LD_CONFIG, "Ran out of virtual addresses!");
+ return NULL;
+ }
+ }
+ return tor_strdup(buf);
+ } else {
+ log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
+ return NULL;
+ }
+}
+
+/** A controller has requested that we map some address of type
+ * <b>type</b> to the address <b>new_address</b>. Choose an address
+ * that is unlikely to be used, and map it, and return it in a newly
+ * allocated string. If another address of the same type is already
+ * mapped to <b>new_address</b>, try to return a copy of that address.
+ *
+ * The string in <b>new_address</b> may be freed or inserted into a map
+ * as appropriate. May return NULL if are out of virtual addresses.
+ **/
+const char *
+addressmap_register_virtual_address(int type, char *new_address)
+{
+ char **addrp;
+ virtaddress_entry_t *vent;
+ int vent_needs_to_be_added = 0;
+
+ tor_assert(new_address);
+ tor_assert(addressmap);
+ tor_assert(virtaddress_reversemap);
+
+ vent = strmap_get(virtaddress_reversemap, new_address);
+ if (!vent) {
+ vent = tor_malloc_zero(sizeof(virtaddress_entry_t));
+ vent_needs_to_be_added = 1;
+ }
+
+ addrp = (type == RESOLVED_TYPE_IPV4) ?
+ &vent->ipv4_address : &vent->hostname_address;
+ if (*addrp) {
+ addressmap_entry_t *ent = strmap_get(addressmap, *addrp);
+ if (ent && ent->new_address &&
+ !strcasecmp(new_address, ent->new_address)) {
+ tor_free(new_address);
+ tor_assert(!vent_needs_to_be_added);
+ return tor_strdup(*addrp);
+ } else
+ log_warn(LD_BUG,
+ "Internal confusion: I thought that '%s' was mapped to by "
+ "'%s', but '%s' really maps to '%s'. This is a harmless bug.",
+ safe_str_client(new_address),
+ safe_str_client(*addrp),
+ safe_str_client(*addrp),
+ ent?safe_str_client(ent->new_address):"(nothing)");
+ }
+
+ tor_free(*addrp);
+ *addrp = addressmap_get_virtual_address(type);
+ if (!*addrp) {
+ tor_free(vent);
+ tor_free(new_address);
+ return NULL;
+ }
+ log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
+ if (vent_needs_to_be_added)
+ strmap_set(virtaddress_reversemap, new_address, vent);
+ addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0);
+
+#if 0
+ {
+ /* Try to catch possible bugs */
+ addressmap_entry_t *ent;
+ ent = strmap_get(addressmap, *addrp);
+ tor_assert(ent);
+ tor_assert(!strcasecmp(ent->new_address,new_address));
+ vent = strmap_get(virtaddress_reversemap, new_address);
+ tor_assert(vent);
+ tor_assert(!strcasecmp(*addrp,
+ (type == RESOLVED_TYPE_IPV4) ?
+ vent->ipv4_address : vent->hostname_address));
+ log_info(LD_APP, "Map from %s to %s okay.",
+ safe_str_client(*addrp),
+ safe_str_client(new_address));
+ }
+#endif
+
+ return *addrp;
+}
+
+/** Return 1 if <b>address</b> has funny characters in it like colons. Return
+ * 0 if it's fine, or if we're configured to allow it anyway. <b>client</b>
+ * should be true if we're using this address as a client; false if we're
+ * using it as a server.
+ */
+int
+address_is_invalid_destination(const char *address, int client)
+{
+ if (client) {
+ if (get_options()->AllowNonRFC953Hostnames)
+ return 0;
+ } else {
+ if (get_options()->ServerDNSAllowNonRFC953Hostnames)
+ return 0;
+ }
+
+ /* It might be an IPv6 address! */
+ {
+ tor_addr_t a;
+ if (tor_addr_parse(&a, address) >= 0)
+ return 0;
+ }
+
+ while (*address) {
+ if (TOR_ISALNUM(*address) ||
+ *address == '-' ||
+ *address == '.' ||
+ *address == '_') /* Underscore is not allowed, but Windows does it
+ * sometimes, just to thumb its nose at the IETF. */
+ ++address;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/** Iterate over all address mappings which have expiry times between
+ * min_expires and max_expires, inclusive. If sl is provided, add an
+ * "old-addr new-addr expiry" string to sl for each mapping, omitting
+ * the expiry time if want_expiry is false. If sl is NULL, remove the
+ * mappings.
+ */
+void
+addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
+ time_t max_expires, int want_expiry)
+{
+ strmap_iter_t *iter;
+ const char *key;
+ void *val_;
+ addressmap_entry_t *val;
+
+ if (!addressmap)
+ addressmap_init();
+
+ for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) {
+ strmap_iter_get(iter, &key, &val_);
+ val = val_;
+ if (val->expires >= min_expires && val->expires <= max_expires) {
+ if (!sl) {
+ iter = strmap_iter_next_rmv(addressmap,iter);
+ addressmap_ent_remove(key, val);
+ continue;
+ } else if (val->new_address) {
+ const char *src_wc = val->src_wildcard ? "*." : "";
+ const char *dst_wc = val->dst_wildcard ? "*." : "";
+ if (want_expiry) {
+ if (val->expires < 3 || val->expires == TIME_MAX)
+ smartlist_add_asprintf(sl, "%s%s %s%s NEVER",
+ src_wc, key, dst_wc, val->new_address);
+ else {
+ char time[ISO_TIME_LEN+1];
+ format_iso_time(time, val->expires);
+ smartlist_add_asprintf(sl, "%s%s %s%s \"%s\"",
+ src_wc, key, dst_wc, val->new_address,
+ time);
+ }
+ } else {
+ smartlist_add_asprintf(sl, "%s%s %s%s",
+ src_wc, key, dst_wc, val->new_address);
+ }
+ }
+ }
+ iter = strmap_iter_next(addressmap,iter);
+ }
+}
+
diff --git a/src/or/addressmap.h b/src/or/addressmap.h
new file mode 100644
index 0000000000..9b07341479
--- /dev/null
+++ b/src/or/addressmap.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_ADDRESSMAP_H
+#define TOR_ADDRESSMAP_H
+
+void addressmap_init(void);
+void addressmap_clear_excluded_trackexithosts(const or_options_t *options);
+void addressmap_clear_invalid_automaps(const or_options_t *options);
+void addressmap_clean(time_t now);
+void addressmap_clear_configured(void);
+void addressmap_clear_transient(void);
+void addressmap_free_all(void);
+int addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out,
+ addressmap_entry_source_t *exit_source_out);
+int addressmap_rewrite_reverse(char *address, size_t maxlen,
+ time_t *expires_out);
+int addressmap_have_mapping(const char *address, int update_timeout);
+
+void addressmap_register(const char *address, char *new_address,
+ time_t expires, addressmap_entry_source_t source,
+ const int address_wildcard,
+ const int new_address_wildcard);
+int parse_virtual_addr_network(const char *val, int validate_only,
+ char **msg);
+int client_dns_incr_failures(const char *address);
+void client_dns_clear_failures(const char *address);
+void client_dns_set_addressmap(origin_circuit_t *on_circ,
+ const char *address, const tor_addr_t *val,
+ const char *exitname, int ttl);
+const char *addressmap_register_virtual_address(int type, char *new_address);
+void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
+ time_t max_expires, int want_expiry);
+int address_is_in_virtual_range(const char *addr);
+void clear_trackexithost_mappings(const char *exitname);
+void client_dns_set_reverse_addressmap(origin_circuit_t *on_circ,
+ const char *address, const char *v,
+ const char *exitname, int ttl);
+
+#endif
+
diff --git a/src/or/buffers.c b/src/or/buffers.c
index ad5ab83e4f..3a1b4d54f8 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -12,6 +12,7 @@
**/
#define BUFFERS_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
#include "config.h"
#include "connection_edge.h"
@@ -192,8 +193,6 @@ chunk_new_with_alloc_size(size_t alloc)
freelist->lowest_length = freelist->cur_length;
++freelist->n_hit;
} else {
- /* XXXX take advantage of tor_malloc_roundup, once we know how that
- * affects freelists. */
if (freelist)
++freelist->n_alloc;
else
@@ -216,7 +215,7 @@ static INLINE chunk_t *
chunk_new_with_alloc_size(size_t alloc)
{
chunk_t *ch;
- ch = tor_malloc_roundup(&alloc);
+ ch = tor_malloc(alloc);
ch->next = NULL;
ch->datalen = 0;
ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
diff --git a/src/or/buffers.h b/src/or/buffers.h
index a5886adc7a..f31d2910f7 100644
--- a/src/or/buffers.h
+++ b/src/or/buffers.h
@@ -9,8 +9,8 @@
* \brief Header file for buffers.c.
**/
-#ifndef _TOR_BUFFERS_H
-#define _TOR_BUFFERS_H
+#ifndef TOR_BUFFERS_H
+#define TOR_BUFFERS_H
buf_t *buf_new(void);
buf_t *buf_new_with_capacity(size_t size);
diff --git a/src/or/channel.c b/src/or/channel.c
new file mode 100644
index 0000000000..625d957811
--- /dev/null
+++ b/src/or/channel.c
@@ -0,0 +1,4094 @@
+/* * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file channel.c
+ * \brief OR-to-OR channel abstraction layer
+ **/
+
+/*
+ * Define this so channel.h gives us things only channel_t subclasses
+ * should touch.
+ */
+
+#define TOR_CHANNEL_INTERNAL_
+
+#include "or.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "circuitbuild.h"
+#include "circuitlist.h"
+#include "circuitstats.h"
+#include "connection_or.h" /* For var_cell_free() */
+#include "circuitmux.h"
+#include "entrynodes.h"
+#include "geoip.h"
+#include "nodelist.h"
+#include "relay.h"
+#include "rephist.h"
+#include "router.h"
+#include "routerlist.h"
+
+/* Cell queue structure */
+
+typedef struct cell_queue_entry_s cell_queue_entry_t;
+struct cell_queue_entry_s {
+ SIMPLEQ_ENTRY(cell_queue_entry_s) next;
+ enum {
+ CELL_QUEUE_FIXED,
+ CELL_QUEUE_VAR,
+ CELL_QUEUE_PACKED
+ } type;
+ union {
+ struct {
+ cell_t *cell;
+ } fixed;
+ struct {
+ var_cell_t *var_cell;
+ } var;
+ struct {
+ packed_cell_t *packed_cell;
+ } packed;
+ } u;
+};
+
+/* Global lists of channels */
+
+/* All channel_t instances */
+static smartlist_t *all_channels = NULL;
+
+/* All channel_t instances not in ERROR or CLOSED states */
+static smartlist_t *active_channels = NULL;
+
+/* All channel_t instances in ERROR or CLOSED states */
+static smartlist_t *finished_channels = NULL;
+
+/* All channel_listener_t instances */
+static smartlist_t *all_listeners = NULL;
+
+/* All channel_listener_t instances in LISTENING state */
+static smartlist_t *active_listeners = NULL;
+
+/* All channel_listener_t instances in LISTENING state */
+static smartlist_t *finished_listeners = NULL;
+
+/* Counter for ID numbers */
+static uint64_t n_channels_allocated = 0;
+
+/* Digest->channel map
+ *
+ * Similar to the one used in connection_or.c, this maps from the identity
+ * digest of a remote endpoint to a channel_t to that endpoint. Channels
+ * should be placed here when registered and removed when they close or error.
+ * If more than one channel exists, follow the next_with_same_id pointer
+ * as a linked list.
+ */
+HT_HEAD(channel_idmap, channel_idmap_entry_s) channel_identity_map =
+ HT_INITIALIZER();
+
+typedef struct channel_idmap_entry_s {
+ HT_ENTRY(channel_idmap_entry_s) node;
+ uint8_t digest[DIGEST_LEN];
+ LIST_HEAD(channel_list_s, channel_s) channel_list;
+} channel_idmap_entry_t;
+
+static INLINE unsigned
+channel_idmap_hash(const channel_idmap_entry_t *ent)
+{
+ const unsigned *a = (const unsigned *)ent->digest;
+#if SIZEOF_INT == 4
+ return a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4];
+#elif SIZEOF_INT == 8
+ return a[0] ^ a[1];
+#endif
+}
+
+static INLINE int
+channel_idmap_eq(const channel_idmap_entry_t *a,
+ const channel_idmap_entry_t *b)
+{
+ return tor_memeq(a->digest, b->digest, DIGEST_LEN);
+}
+
+HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
+ channel_idmap_eq);
+HT_GENERATE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
+ channel_idmap_eq, 0.5, tor_malloc, tor_realloc, tor_free_);
+
+static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q);
+static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off);
+static int cell_queue_entry_is_padding(cell_queue_entry_t *q);
+static cell_queue_entry_t *
+cell_queue_entry_new_fixed(cell_t *cell);
+static cell_queue_entry_t *
+cell_queue_entry_new_var(var_cell_t *var_cell);
+
+/* Functions to maintain the digest map */
+static void channel_add_to_digest_map(channel_t *chan);
+static void channel_remove_from_digest_map(channel_t *chan);
+
+/*
+ * Flush cells from just the outgoing queue without trying to get them
+ * from circuits; used internall by channel_flush_some_cells().
+ */
+static ssize_t
+channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
+ ssize_t num_cells);
+static void channel_force_free(channel_t *chan);
+static void
+channel_free_list(smartlist_t *channels, int mark_for_close);
+static void
+channel_listener_free_list(smartlist_t *channels, int mark_for_close);
+static void channel_listener_force_free(channel_listener_t *chan_l);
+static void
+channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q);
+
+/***********************************
+ * Channel state utility functions *
+ **********************************/
+
+/**
+ * Indicate whether a given channel state is valid
+ */
+
+int
+channel_state_is_valid(channel_state_t state)
+{
+ int is_valid;
+
+ switch (state) {
+ case CHANNEL_STATE_CLOSED:
+ case CHANNEL_STATE_CLOSING:
+ case CHANNEL_STATE_ERROR:
+ case CHANNEL_STATE_MAINT:
+ case CHANNEL_STATE_OPENING:
+ case CHANNEL_STATE_OPEN:
+ is_valid = 1;
+ break;
+ case CHANNEL_STATE_LAST:
+ default:
+ is_valid = 0;
+ }
+
+ return is_valid;
+}
+
+/**
+ * Indicate whether a given channel listener state is valid
+ */
+
+int
+channel_listener_state_is_valid(channel_listener_state_t state)
+{
+ int is_valid;
+
+ switch (state) {
+ case CHANNEL_LISTENER_STATE_CLOSED:
+ case CHANNEL_LISTENER_STATE_LISTENING:
+ case CHANNEL_LISTENER_STATE_CLOSING:
+ case CHANNEL_LISTENER_STATE_ERROR:
+ is_valid = 1;
+ break;
+ case CHANNEL_LISTENER_STATE_LAST:
+ default:
+ is_valid = 0;
+ }
+
+ return is_valid;
+}
+
+/**
+ * Indicate whether a channel state transition is valid
+ *
+ * This function takes two channel states and indicates whether a
+ * transition between them is permitted (see the state definitions and
+ * transition table in or.h at the channel_state_t typedef).
+ */
+
+int
+channel_state_can_transition(channel_state_t from, channel_state_t to)
+{
+ int is_valid;
+
+ switch (from) {
+ case CHANNEL_STATE_CLOSED:
+ is_valid = (to == CHANNEL_STATE_OPENING);
+ break;
+ case CHANNEL_STATE_CLOSING:
+ is_valid = (to == CHANNEL_STATE_CLOSED ||
+ to == CHANNEL_STATE_ERROR);
+ break;
+ case CHANNEL_STATE_ERROR:
+ is_valid = 0;
+ break;
+ case CHANNEL_STATE_MAINT:
+ is_valid = (to == CHANNEL_STATE_CLOSING ||
+ to == CHANNEL_STATE_ERROR ||
+ to == CHANNEL_STATE_OPEN);
+ break;
+ case CHANNEL_STATE_OPENING:
+ is_valid = (to == CHANNEL_STATE_CLOSING ||
+ to == CHANNEL_STATE_ERROR ||
+ to == CHANNEL_STATE_OPEN);
+ break;
+ case CHANNEL_STATE_OPEN:
+ is_valid = (to == CHANNEL_STATE_CLOSING ||
+ to == CHANNEL_STATE_ERROR ||
+ to == CHANNEL_STATE_MAINT);
+ break;
+ case CHANNEL_STATE_LAST:
+ default:
+ is_valid = 0;
+ }
+
+ return is_valid;
+}
+
+/**
+ * Indicate whether a channel listener state transition is valid
+ *
+ * This function takes two channel listener states and indicates whether a
+ * transition between them is permitted (see the state definitions and
+ * transition table in or.h at the channel_listener_state_t typedef).
+ */
+
+int
+channel_listener_state_can_transition(channel_listener_state_t from,
+ channel_listener_state_t to)
+{
+ int is_valid;
+
+ switch (from) {
+ case CHANNEL_LISTENER_STATE_CLOSED:
+ is_valid = (to == CHANNEL_LISTENER_STATE_LISTENING);
+ break;
+ case CHANNEL_LISTENER_STATE_CLOSING:
+ is_valid = (to == CHANNEL_LISTENER_STATE_CLOSED ||
+ to == CHANNEL_LISTENER_STATE_ERROR);
+ break;
+ case CHANNEL_LISTENER_STATE_ERROR:
+ is_valid = 0;
+ break;
+ case CHANNEL_LISTENER_STATE_LISTENING:
+ is_valid = (to == CHANNEL_LISTENER_STATE_CLOSING ||
+ to == CHANNEL_LISTENER_STATE_ERROR);
+ break;
+ case CHANNEL_LISTENER_STATE_LAST:
+ default:
+ is_valid = 0;
+ }
+
+ return is_valid;
+}
+
+/**
+ * Return a human-readable description for a channel state
+ */
+
+const char *
+channel_state_to_string(channel_state_t state)
+{
+ const char *descr;
+
+ switch (state) {
+ case CHANNEL_STATE_CLOSED:
+ descr = "closed";
+ break;
+ case CHANNEL_STATE_CLOSING:
+ descr = "closing";
+ break;
+ case CHANNEL_STATE_ERROR:
+ descr = "channel error";
+ break;
+ case CHANNEL_STATE_MAINT:
+ descr = "temporarily suspended for maintenance";
+ break;
+ case CHANNEL_STATE_OPENING:
+ descr = "opening";
+ break;
+ case CHANNEL_STATE_OPEN:
+ descr = "open";
+ break;
+ case CHANNEL_STATE_LAST:
+ default:
+ descr = "unknown or invalid channel state";
+ }
+
+ return descr;
+}
+
+/**
+ * Return a human-readable description for a channel listenier state
+ */
+
+const char *
+channel_listener_state_to_string(channel_listener_state_t state)
+{
+ const char *descr;
+
+ switch (state) {
+ case CHANNEL_LISTENER_STATE_CLOSED:
+ descr = "closed";
+ break;
+ case CHANNEL_LISTENER_STATE_CLOSING:
+ descr = "closing";
+ break;
+ case CHANNEL_LISTENER_STATE_ERROR:
+ descr = "channel listener error";
+ break;
+ case CHANNEL_LISTENER_STATE_LISTENING:
+ descr = "listening";
+ break;
+ case CHANNEL_LISTENER_STATE_LAST:
+ default:
+ descr = "unknown or invalid channel listener state";
+ }
+
+ return descr;
+}
+
+/***************************************
+ * Channel registration/unregistration *
+ ***************************************/
+
+/**
+ * Register a channel
+ *
+ * This function registers a newly created channel in the global lists/maps
+ * of active channels.
+ */
+
+void
+channel_register(channel_t *chan)
+{
+ tor_assert(chan);
+
+ /* No-op if already registered */
+ if (chan->registered) return;
+
+ log_debug(LD_CHANNEL,
+ "Registering channel %p (ID " U64_FORMAT ") "
+ "in state %s (%d) with digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state), chan->state,
+ hex_str(chan->identity_digest, DIGEST_LEN));
+
+ /* Make sure we have all_channels, then add it */
+ if (!all_channels) all_channels = smartlist_new();
+ smartlist_add(all_channels, chan);
+
+ /* Is it finished? */
+ if (chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) {
+ /* Put it in the finished list, creating it if necessary */
+ if (!finished_channels) finished_channels = smartlist_new();
+ smartlist_add(finished_channels, chan);
+ } else {
+ /* Put it in the active list, creating it if necessary */
+ if (!active_channels) active_channels = smartlist_new();
+ smartlist_add(active_channels, chan);
+
+ if (chan->state != CHANNEL_STATE_CLOSING) {
+ /* It should have a digest set */
+ if (!tor_digest_is_zero(chan->identity_digest)) {
+ /* Yeah, we're good, add it to the map */
+ channel_add_to_digest_map(chan);
+ } else {
+ log_info(LD_CHANNEL,
+ "Channel %p (global ID " U64_FORMAT ") "
+ "in state %s (%d) registered with no identity digest",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state), chan->state);
+ }
+ }
+ }
+
+ /* Mark it as registered */
+ chan->registered = 1;
+}
+
+/**
+ * Unregister a channel
+ *
+ * This function removes a channel from the global lists and maps and is used
+ * when freeing a closed/errored channel.
+ */
+
+void
+channel_unregister(channel_t *chan)
+{
+ tor_assert(chan);
+
+ /* No-op if not registered */
+ if (!(chan->registered)) return;
+
+ /* Is it finished? */
+ if (chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) {
+ /* Get it out of the finished list */
+ if (finished_channels) smartlist_remove(finished_channels, chan);
+ } else {
+ /* Get it out of the active list */
+ if (active_channels) smartlist_remove(active_channels, chan);
+ }
+
+ /* Get it out of all_channels */
+ if (all_channels) smartlist_remove(all_channels, chan);
+
+ /* Mark it as unregistered */
+ chan->registered = 0;
+
+ /* Should it be in the digest map? */
+ if (!tor_digest_is_zero(chan->identity_digest) &&
+ !(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ /* Remove it */
+ channel_remove_from_digest_map(chan);
+ }
+}
+
+/**
+ * Register a channel listener
+ *
+ * This function registers a newly created channel listner in the global
+ * lists/maps of active channel listeners.
+ */
+
+void
+channel_listener_register(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ /* No-op if already registered */
+ if (chan_l->registered) return;
+
+ log_debug(LD_CHANNEL,
+ "Registering channel listener %p (ID " U64_FORMAT ") "
+ "in state %s (%d)",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier),
+ channel_listener_state_to_string(chan_l->state),
+ chan_l->state);
+
+ /* Make sure we have all_channels, then add it */
+ if (!all_listeners) all_listeners = smartlist_new();
+ smartlist_add(all_listeners, chan_l);
+
+ /* Is it finished? */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) {
+ /* Put it in the finished list, creating it if necessary */
+ if (!finished_listeners) finished_listeners = smartlist_new();
+ smartlist_add(finished_listeners, chan_l);
+ } else {
+ /* Put it in the active list, creating it if necessary */
+ if (!active_listeners) active_listeners = smartlist_new();
+ smartlist_add(active_listeners, chan_l);
+ }
+
+ /* Mark it as registered */
+ chan_l->registered = 1;
+}
+
+/**
+ * Unregister a channel listener
+ *
+ * This function removes a channel listener from the global lists and maps
+ * and is used when freeing a closed/errored channel listener.
+ */
+
+void
+channel_listener_unregister(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ /* No-op if not registered */
+ if (!(chan_l->registered)) return;
+
+ /* Is it finished? */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) {
+ /* Get it out of the finished list */
+ if (finished_listeners) smartlist_remove(finished_listeners, chan_l);
+ } else {
+ /* Get it out of the active list */
+ if (active_listeners) smartlist_remove(active_listeners, chan_l);
+ }
+
+ /* Get it out of all_channels */
+ if (all_listeners) smartlist_remove(all_listeners, chan_l);
+
+ /* Mark it as unregistered */
+ chan_l->registered = 0;
+}
+
+/*********************************
+ * Channel digest map maintenance
+ *********************************/
+
+/**
+ * Add a channel to the digest map
+ *
+ * This function adds a channel to the digest map and inserts it into the
+ * correct linked list if channels with that remote endpoint identity digest
+ * already exist.
+ */
+
+static void
+channel_add_to_digest_map(channel_t *chan)
+{
+ channel_idmap_entry_t *ent, search;
+
+ tor_assert(chan);
+
+ /* Assert that the state makes sense */
+ tor_assert(!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR));
+
+ /* Assert that there is a digest */
+ tor_assert(!tor_digest_is_zero(chan->identity_digest));
+
+ memcpy(search.digest, chan->identity_digest, DIGEST_LEN);
+ ent = HT_FIND(channel_idmap, &channel_identity_map, &search);
+ if (! ent) {
+ ent = tor_malloc(sizeof(channel_idmap_entry_t));
+ memcpy(ent->digest, chan->identity_digest, DIGEST_LEN);
+ LIST_INIT(&ent->channel_list);
+ HT_INSERT(channel_idmap, &channel_identity_map, ent);
+ }
+ LIST_INSERT_HEAD(&ent->channel_list, chan, next_with_same_id);
+
+ log_debug(LD_CHANNEL,
+ "Added channel %p (global ID " U64_FORMAT ") "
+ "to identity map in state %s (%d) with digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state), chan->state,
+ hex_str(chan->identity_digest, DIGEST_LEN));
+}
+
+/**
+ * Remove a channel from the digest map
+ *
+ * This function removes a channel from the digest map and the linked list of
+ * channels for that digest if more than one exists.
+ */
+
+static void
+channel_remove_from_digest_map(channel_t *chan)
+{
+ channel_idmap_entry_t *ent, search;
+
+ tor_assert(chan);
+
+ /* Assert that there is a digest */
+ tor_assert(!tor_digest_is_zero(chan->identity_digest));
+
+#if 0
+ /* Make sure we have a map */
+ if (!channel_identity_map) {
+ /*
+ * No identity map, so we can't find it by definition. This
+ * case is similar to digestmap_get() failing below.
+ */
+ log_warn(LD_BUG,
+ "Trying to remove channel %p (global ID " U64_FORMAT ") "
+ "with digest %s from identity map, but didn't have any identity "
+ "map",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN));
+ /* Clear out its next/prev pointers */
+ if (chan->next_with_same_id) {
+ chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id;
+ }
+ if (chan->prev_with_same_id) {
+ chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id;
+ }
+ chan->next_with_same_id = NULL;
+ chan->prev_with_same_id = NULL;
+
+ return;
+ }
+#endif
+
+ /* Pull it out of its list, wherever that list is */
+ LIST_REMOVE(chan, next_with_same_id);
+
+ memcpy(search.digest, chan->identity_digest, DIGEST_LEN);
+ ent = HT_FIND(channel_idmap, &channel_identity_map, &search);
+
+ /* Look for it in the map */
+ if (ent) {
+ /* Okay, it's here */
+
+ if (LIST_EMPTY(&ent->channel_list)) {
+ HT_REMOVE(channel_idmap, &channel_identity_map, ent);
+ tor_free(ent);
+ }
+
+ log_debug(LD_CHANNEL,
+ "Removed channel %p (global ID " U64_FORMAT ") from "
+ "identity map in state %s (%d) with digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state), chan->state,
+ hex_str(chan->identity_digest, DIGEST_LEN));
+ } else {
+ /* Shouldn't happen */
+ log_warn(LD_BUG,
+ "Trying to remove channel %p (global ID " U64_FORMAT ") with "
+ "digest %s from identity map, but couldn't find any with "
+ "that digest",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN));
+ }
+}
+
+/****************************
+ * Channel lookup functions *
+ ***************************/
+
+/**
+ * Find channel by global ID
+ *
+ * This function searches for a channel by the global_identifier assigned
+ * at initialization time. This identifier is unique for the lifetime of the
+ * Tor process.
+ */
+
+channel_t *
+channel_find_by_global_id(uint64_t global_identifier)
+{
+ channel_t *rv = NULL;
+
+ if (all_channels && smartlist_len(all_channels) > 0) {
+ SMARTLIST_FOREACH_BEGIN(all_channels, channel_t *, curr) {
+ if (curr->global_identifier == global_identifier) {
+ rv = curr;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(curr);
+ }
+
+ return rv;
+}
+
+/**
+ * Find channel by digest of the remote endpoint
+ *
+ * This function looks up a channel by the digest of its remote endpoint in
+ * the channel digest map. It's possible that more than one channel to a
+ * given endpoint exists. Use channel_next_with_digest() to walk the list.
+ */
+
+channel_t *
+channel_find_by_remote_digest(const char *identity_digest)
+{
+ channel_t *rv = NULL;
+ channel_idmap_entry_t *ent, search;
+
+ tor_assert(identity_digest);
+
+ memcpy(search.digest, identity_digest, DIGEST_LEN);
+ ent = HT_FIND(channel_idmap, &channel_identity_map, &search);
+ if (ent) {
+ rv = LIST_FIRST(&ent->channel_list);
+ }
+
+ return rv;
+}
+
+/**
+ * Get next channel with digest
+ *
+ * This function takes a channel and finds the next channel in the list
+ * with the same digest.
+ */
+
+channel_t *
+channel_next_with_digest(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return LIST_NEXT(chan, next_with_same_id);
+}
+
+/**
+ * Initialize a channel
+ *
+ * This function should be called by subclasses to set up some per-channel
+ * variables. I.e., this is the superclass constructor. Before this, the
+ * channel should be allocated with tor_malloc_zero().
+ */
+
+void
+channel_init(channel_t *chan)
+{
+ tor_assert(chan);
+
+ /* Assign an ID and bump the counter */
+ chan->global_identifier = n_channels_allocated++;
+
+ /* Init timestamp */
+ chan->timestamp_last_added_nonpadding = time(NULL);
+
+ /* Init next_circ_id */
+ chan->next_circ_id = crypto_rand_int(1 << 15);
+
+ /* Initialize queues. */
+ SIMPLEQ_INIT(&chan->incoming_queue);
+ SIMPLEQ_INIT(&chan->outgoing_queue);
+
+ /* Initialize list entries. */
+ memset(&chan->next_with_same_id, 0, sizeof(chan->next_with_same_id));
+
+ /* Timestamp it */
+ channel_timestamp_created(chan);
+}
+
+/**
+ * Initialize a channel listener
+ *
+ * This function should be called by subclasses to set up some per-channel
+ * variables. I.e., this is the superclass constructor. Before this, the
+ * channel listener should be allocated with tor_malloc_zero().
+ */
+
+void
+channel_init_listener(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ /* Assign an ID and bump the counter */
+ chan_l->global_identifier = n_channels_allocated++;
+
+ /* Timestamp it */
+ channel_listener_timestamp_created(chan_l);
+}
+
+/**
+ * Free a channel; nothing outside of channel.c and subclasses should call
+ * this - it frees channels after they have closed and been unregistered.
+ */
+
+void
+channel_free(channel_t *chan)
+{
+ if (!chan) return;
+
+ /* It must be closed or errored */
+ tor_assert(chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+ /* It must be deregistered */
+ tor_assert(!(chan->registered));
+
+ log_debug(LD_CHANNEL,
+ "Freeing channel " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+
+ /*
+ * Get rid of cmux policy before we do anything, so cmux policies don't
+ * see channels in weird half-freed states.
+ */
+ if (chan->cmux) {
+ circuitmux_set_policy(chan->cmux, NULL);
+ }
+
+ /* Call a free method if there is one */
+ if (chan->free) chan->free(chan);
+
+ channel_clear_remote_end(chan);
+
+ /* Get rid of cmux */
+ if (chan->cmux) {
+ circuitmux_detach_all_circuits(chan->cmux);
+ circuitmux_free(chan->cmux);
+ chan->cmux = NULL;
+ }
+
+ /* We're in CLOSED or ERROR, so the cell queue is already empty */
+
+ tor_free(chan);
+}
+
+/**
+ * Free a channel listener; nothing outside of channel.c and subclasses
+ * should call this - it frees channel listeners after they have closed and
+ * been unregistered.
+ */
+
+void
+channel_listener_free(channel_listener_t *chan_l)
+{
+ if (!chan_l) return;
+
+ log_debug(LD_CHANNEL,
+ "Freeing channel_listener_t " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan_l->global_identifier),
+ chan_l);
+
+ /* It must be closed or errored */
+ tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR);
+ /* It must be deregistered */
+ tor_assert(!(chan_l->registered));
+
+ /* Call a free method if there is one */
+ if (chan_l->free) chan_l->free(chan_l);
+
+ /*
+ * We're in CLOSED or ERROR, so the incoming channel queue is already
+ * empty.
+ */
+
+ tor_free(chan_l);
+}
+
+/**
+ * Free a channel and skip the state/registration asserts; this internal-
+ * use-only function should be called only from channel_free_all() when
+ * shutting down the Tor process.
+ */
+
+static void
+channel_force_free(channel_t *chan)
+{
+ cell_queue_entry_t *cell, *cell_tmp;
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Force-freeing channel " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+
+ /*
+ * Get rid of cmux policy before we do anything, so cmux policies don't
+ * see channels in weird half-freed states.
+ */
+ if (chan->cmux) {
+ circuitmux_set_policy(chan->cmux, NULL);
+ }
+
+ /* Call a free method if there is one */
+ if (chan->free) chan->free(chan);
+
+ channel_clear_remote_end(chan);
+
+ /* Get rid of cmux */
+ if (chan->cmux) {
+ circuitmux_free(chan->cmux);
+ chan->cmux = NULL;
+ }
+
+ /* We might still have a cell queue; kill it */
+ SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) {
+ cell_queue_entry_free(cell, 0);
+ }
+ SIMPLEQ_INIT(&chan->incoming_queue);
+
+ /* Outgoing cell queue is similar, but we can have to free packed cells */
+ SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) {
+ cell_queue_entry_free(cell, 0);
+ }
+ SIMPLEQ_INIT(&chan->outgoing_queue);
+
+ tor_free(chan);
+}
+
+/**
+ * Free a channel listener and skip the state/reigstration asserts; this
+ * internal-use-only function should be called only from channel_free_all()
+ * when shutting down the Tor process.
+ */
+
+static void
+channel_listener_force_free(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ log_debug(LD_CHANNEL,
+ "Force-freeing channel_listener_t " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan_l->global_identifier),
+ chan_l);
+
+ /* Call a free method if there is one */
+ if (chan_l->free) chan_l->free(chan_l);
+
+ /*
+ * The incoming list just gets emptied and freed; we request close on
+ * any channels we find there, but since we got called while shutting
+ * down they will get deregistered and freed elsewhere anyway.
+ */
+ if (chan_l->incoming_list) {
+ SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list,
+ channel_t *, qchan) {
+ channel_mark_for_close(qchan);
+ } SMARTLIST_FOREACH_END(qchan);
+
+ smartlist_free(chan_l->incoming_list);
+ chan_l->incoming_list = NULL;
+ }
+
+ tor_free(chan_l);
+}
+
+/**
+ * Return the current registered listener for a channel listener
+ *
+ * This function returns a function pointer to the current registered
+ * handler for new incoming channels on a channel listener.
+ */
+
+channel_listener_fn_ptr
+channel_listener_get_listener_fn(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ if (chan_l->state == CHANNEL_LISTENER_STATE_LISTENING)
+ return chan_l->listener;
+
+ return NULL;
+}
+
+/**
+ * Set the listener for a channel listener
+ *
+ * This function sets the handler for new incoming channels on a channel
+ * listener.
+ */
+
+void
+channel_listener_set_listener_fn(channel_listener_t *chan_l,
+ channel_listener_fn_ptr listener)
+{
+ tor_assert(chan_l);
+ tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_LISTENING);
+
+ log_debug(LD_CHANNEL,
+ "Setting listener callback for channel listener %p "
+ "(global ID " U64_FORMAT ") to %p",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier),
+ listener);
+
+ chan_l->listener = listener;
+ if (chan_l->listener) channel_listener_process_incoming(chan_l);
+}
+
+/**
+ * Return the fixed-length cell handler for a channel
+ *
+ * This function gets the handler for incoming fixed-length cells installed
+ * on a channel.
+ */
+
+channel_cell_handler_fn_ptr
+channel_get_cell_handler(channel_t *chan)
+{
+ tor_assert(chan);
+
+ if (chan->state == CHANNEL_STATE_OPENING ||
+ chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT)
+ return chan->cell_handler;
+
+ return NULL;
+}
+
+/**
+ * Return the variable-length cell handler for a channel
+ *
+ * This function gets the handler for incoming variable-length cells
+ * installed on a channel.
+ */
+
+channel_var_cell_handler_fn_ptr
+channel_get_var_cell_handler(channel_t *chan)
+{
+ tor_assert(chan);
+
+ if (chan->state == CHANNEL_STATE_OPENING ||
+ chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT)
+ return chan->var_cell_handler;
+
+ return NULL;
+}
+
+/**
+ * Set both cell handlers for a channel
+ *
+ * This function sets both the fixed-length and variable length cell handlers
+ * for a channel and processes any incoming cells that had been blocked in the
+ * queue because none were available.
+ */
+
+void
+channel_set_cell_handlers(channel_t *chan,
+ channel_cell_handler_fn_ptr cell_handler,
+ channel_var_cell_handler_fn_ptr
+ var_cell_handler)
+{
+ int try_again = 0;
+
+ tor_assert(chan);
+ tor_assert(chan->state == CHANNEL_STATE_OPENING ||
+ chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT);
+
+ log_debug(LD_CHANNEL,
+ "Setting cell_handler callback for channel %p to %p",
+ chan, cell_handler);
+ log_debug(LD_CHANNEL,
+ "Setting var_cell_handler callback for channel %p to %p",
+ chan, var_cell_handler);
+
+ /* Should we try the queue? */
+ if (cell_handler &&
+ cell_handler != chan->cell_handler) try_again = 1;
+ if (var_cell_handler &&
+ var_cell_handler != chan->var_cell_handler) try_again = 1;
+
+ /* Change them */
+ chan->cell_handler = cell_handler;
+ chan->var_cell_handler = var_cell_handler;
+
+ /* Re-run the queue if we have one and there's any reason to */
+ if (! SIMPLEQ_EMPTY(&chan->incoming_queue) &&
+ try_again &&
+ (chan->cell_handler ||
+ chan->var_cell_handler)) channel_process_cells(chan);
+}
+
+/*
+ * On closing channels
+ *
+ * There are three functions that close channels, for use in
+ * different circumstances:
+ *
+ * - Use channel_mark_for_close() for most cases
+ * - Use channel_close_from_lower_layer() if you are connection_or.c
+ * and the other end closes the underlying connection.
+ * - Use channel_close_for_error() if you are connection_or.c and
+ * some sort of error has occurred.
+ */
+
+/**
+ * Mark a channel for closure
+ *
+ * This function tries to close a channel_t; it will go into the CLOSING
+ * state, and eventually the lower layer should put it into the CLOSED or
+ * ERROR state. Then, channel_run_cleanup() will eventually free it.
+ */
+
+void
+channel_mark_for_close(channel_t *chan)
+{
+ tor_assert(chan != NULL);
+ tor_assert(chan->close != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel %p (global ID " U64_FORMAT ") "
+ "by request",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ /* Note closing by request from above */
+ chan->reason_for_closing = CHANNEL_CLOSE_REQUESTED;
+
+ /* Change state to CLOSING */
+ channel_change_state(chan, CHANNEL_STATE_CLOSING);
+
+ /* Tell the lower layer */
+ chan->close(chan);
+
+ /*
+ * It's up to the lower layer to change state to CLOSED or ERROR when we're
+ * ready; we'll try to free channels that are in the finished list from
+ * channel_run_cleanup(). The lower layer should do this by calling
+ * channel_closed().
+ */
+}
+
+/**
+ * Mark a channel listener for closure
+ *
+ * This function tries to close a channel_listener_t; it will go into the
+ * CLOSING state, and eventually the lower layer should put it into the CLOSED
+ * or ERROR state. Then, channel_run_cleanup() will eventually free it.
+ */
+
+void
+channel_listener_mark_for_close(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l != NULL);
+ tor_assert(chan_l->close != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel listener %p (global ID " U64_FORMAT ") "
+ "by request",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
+
+ /* Note closing by request from above */
+ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_REQUESTED;
+
+ /* Change state to CLOSING */
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
+
+ /* Tell the lower layer */
+ chan_l->close(chan_l);
+
+ /*
+ * It's up to the lower layer to change state to CLOSED or ERROR when we're
+ * ready; we'll try to free channels that are in the finished list from
+ * channel_run_cleanup(). The lower layer should do this by calling
+ * channel_listener_closed().
+ */
+}
+
+/**
+ * Close a channel from the lower layer
+ *
+ * Notify the channel code that the channel is being closed due to a non-error
+ * condition in the lower layer. This does not call the close() method, since
+ * the lower layer already knows.
+ */
+
+void
+channel_close_from_lower_layer(channel_t *chan)
+{
+ tor_assert(chan != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel %p (global ID " U64_FORMAT ") "
+ "due to lower-layer event",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ /* Note closing by event from below */
+ chan->reason_for_closing = CHANNEL_CLOSE_FROM_BELOW;
+
+ /* Change state to CLOSING */
+ channel_change_state(chan, CHANNEL_STATE_CLOSING);
+}
+
+/**
+ * Close a channel listener from the lower layer
+ *
+ * Notify the channel code that the channel listener is being closed due to a
+ * non-error condition in the lower layer. This does not call the close()
+ * method, since the lower layer already knows.
+ */
+
+void
+channel_listener_close_from_lower_layer(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel listener %p (global ID " U64_FORMAT ") "
+ "due to lower-layer event",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
+
+ /* Note closing by event from below */
+ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FROM_BELOW;
+
+ /* Change state to CLOSING */
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
+}
+
+/**
+ * Notify that the channel is being closed due to an error condition
+ *
+ * This function is called by the lower layer implementing the transport
+ * when a channel must be closed due to an error condition. This does not
+ * call the channel's close method, since the lower layer already knows.
+ */
+
+void
+channel_close_for_error(channel_t *chan)
+{
+ tor_assert(chan != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel %p due to lower-layer error",
+ chan);
+
+ /* Note closing by event from below */
+ chan->reason_for_closing = CHANNEL_CLOSE_FOR_ERROR;
+
+ /* Change state to CLOSING */
+ channel_change_state(chan, CHANNEL_STATE_CLOSING);
+}
+
+/**
+ * Notify that the channel listener is being closed due to an error condition
+ *
+ * This function is called by the lower layer implementing the transport
+ * when a channel listener must be closed due to an error condition. This
+ * does not call the channel listener's close method, since the lower layer
+ * already knows.
+ */
+
+void
+channel_listener_close_for_error(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel listener %p (global ID " U64_FORMAT ") "
+ "due to lower-layer error",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
+
+ /* Note closing by event from below */
+ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FOR_ERROR;
+
+ /* Change state to CLOSING */
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
+}
+
+/**
+ * Notify that the lower layer is finished closing the channel
+ *
+ * This function should be called by the lower layer when a channel
+ * is finished closing and it should be regarded as inactive and
+ * freed by the channel code.
+ */
+
+void
+channel_closed(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+
+ /* No-op if already inactive */
+ if (chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) return;
+
+ if (chan->reason_for_closing == CHANNEL_CLOSE_FOR_ERROR) {
+ /* Inform any pending (not attached) circs that they should
+ * give up. */
+ circuit_n_chan_done(chan, 0);
+ }
+ /* Now close all the attached circuits on it. */
+ circuit_unlink_all_from_channel(chan, END_CIRC_REASON_CHANNEL_CLOSED);
+
+ if (chan->reason_for_closing != CHANNEL_CLOSE_FOR_ERROR) {
+ channel_change_state(chan, CHANNEL_STATE_CLOSED);
+ } else {
+ channel_change_state(chan, CHANNEL_STATE_ERROR);
+ }
+}
+
+/**
+ * Notify that the lower layer is finished closing the channel listener
+ *
+ * This function should be called by the lower layer when a channel listener
+ * is finished closing and it should be regarded as inactive and
+ * freed by the channel code.
+ */
+
+void
+channel_listener_closed(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+ tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR);
+
+ /* No-op if already inactive */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
+
+ if (chan_l->reason_for_closing != CHANNEL_LISTENER_CLOSE_FOR_ERROR) {
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED);
+ } else {
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_ERROR);
+ }
+}
+
+/**
+ * Clear the identity_digest of a channel
+ *
+ * This function clears the identity digest of the remote endpoint for a
+ * channel; this is intended for use by the lower layer.
+ */
+
+void
+channel_clear_identity_digest(channel_t *chan)
+{
+ int state_not_in_map;
+
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Clearing remote endpoint digest on channel %p with "
+ "global ID " U64_FORMAT,
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ state_not_in_map =
+ (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+
+ if (!state_not_in_map && chan->registered &&
+ !tor_digest_is_zero(chan->identity_digest))
+ /* if it's registered get it out of the digest map */
+ channel_remove_from_digest_map(chan);
+
+ memset(chan->identity_digest, 0,
+ sizeof(chan->identity_digest));
+}
+
+/**
+ * Set the identity_digest of a channel
+ *
+ * This function sets the identity digest of the remote endpoint for a
+ * channel; this is intended for use by the lower layer.
+ */
+
+void
+channel_set_identity_digest(channel_t *chan,
+ const char *identity_digest)
+{
+ int was_in_digest_map, should_be_in_digest_map, state_not_in_map;
+
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Setting remote endpoint digest on channel %p with "
+ "global ID " U64_FORMAT " to digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ identity_digest ?
+ hex_str(identity_digest, DIGEST_LEN) : "(null)");
+
+ state_not_in_map =
+ (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+ was_in_digest_map =
+ !state_not_in_map &&
+ chan->registered &&
+ !tor_digest_is_zero(chan->identity_digest);
+ should_be_in_digest_map =
+ !state_not_in_map &&
+ chan->registered &&
+ (identity_digest &&
+ !tor_digest_is_zero(identity_digest));
+
+ if (was_in_digest_map)
+ /* We should always remove it; we'll add it back if we're writing
+ * in a new digest.
+ */
+ channel_remove_from_digest_map(chan);
+
+ if (identity_digest) {
+ memcpy(chan->identity_digest,
+ identity_digest,
+ sizeof(chan->identity_digest));
+ } else {
+ memset(chan->identity_digest, 0,
+ sizeof(chan->identity_digest));
+ }
+
+ /* Put it in the digest map if we should */
+ if (should_be_in_digest_map)
+ channel_add_to_digest_map(chan);
+}
+
+/**
+ * Clear the remote end metadata (identity_digest/nickname) of a channel
+ *
+ * This function clears all the remote end info from a channel; this is
+ * intended for use by the lower layer.
+ */
+
+void
+channel_clear_remote_end(channel_t *chan)
+{
+ int state_not_in_map;
+
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Clearing remote endpoint identity on channel %p with "
+ "global ID " U64_FORMAT,
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ state_not_in_map =
+ (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+
+ if (!state_not_in_map && chan->registered &&
+ !tor_digest_is_zero(chan->identity_digest))
+ /* if it's registered get it out of the digest map */
+ channel_remove_from_digest_map(chan);
+
+ memset(chan->identity_digest, 0,
+ sizeof(chan->identity_digest));
+ tor_free(chan->nickname);
+}
+
+/**
+ * Set the remote end metadata (identity_digest/nickname) of a channel
+ *
+ * This function sets new remote end info on a channel; this is intended
+ * for use by the lower layer.
+ */
+
+void
+channel_set_remote_end(channel_t *chan,
+ const char *identity_digest,
+ const char *nickname)
+{
+ int was_in_digest_map, should_be_in_digest_map, state_not_in_map;
+
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Setting remote endpoint identity on channel %p with "
+ "global ID " U64_FORMAT " to nickname %s, digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ nickname ? nickname : "(null)",
+ identity_digest ?
+ hex_str(identity_digest, DIGEST_LEN) : "(null)");
+
+ state_not_in_map =
+ (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+ was_in_digest_map =
+ !state_not_in_map &&
+ chan->registered &&
+ !tor_digest_is_zero(chan->identity_digest);
+ should_be_in_digest_map =
+ !state_not_in_map &&
+ chan->registered &&
+ (identity_digest &&
+ !tor_digest_is_zero(identity_digest));
+
+ if (was_in_digest_map)
+ /* We should always remove it; we'll add it back if we're writing
+ * in a new digest.
+ */
+ channel_remove_from_digest_map(chan);
+
+ if (identity_digest) {
+ memcpy(chan->identity_digest,
+ identity_digest,
+ sizeof(chan->identity_digest));
+
+ } else {
+ memset(chan->identity_digest, 0,
+ sizeof(chan->identity_digest));
+ }
+
+ tor_free(chan->nickname);
+ if (nickname)
+ chan->nickname = tor_strdup(nickname);
+
+ /* Put it in the digest map if we should */
+ if (should_be_in_digest_map)
+ channel_add_to_digest_map(chan);
+}
+
+/**
+ * Duplicate a cell queue entry; this is a shallow copy intended for use
+ * in channel_write_cell_queue_entry().
+ */
+
+static cell_queue_entry_t *
+cell_queue_entry_dup(cell_queue_entry_t *q)
+{
+ cell_queue_entry_t *rv = NULL;
+
+ tor_assert(q);
+
+ rv = tor_malloc(sizeof(*rv));
+ memcpy(rv, q, sizeof(*rv));
+
+ return rv;
+}
+
+/**
+ * Free a cell_queue_entry_t; the handed_off parameter indicates whether
+ * the contents were passed to the lower layer (it is responsible for
+ * them) or not (we should free).
+ */
+
+static void
+cell_queue_entry_free(cell_queue_entry_t *q, int handed_off)
+{
+ if (!q) return;
+
+ if (!handed_off) {
+ /*
+ * If we handed it off, the recipient becomes responsible (or
+ * with packed cells the channel_t subclass calls packed_cell
+ * free after writing out its contents; see, e.g.,
+ * channel_tls_write_packed_cell_method(). Otherwise, we have
+ * to take care of it here if possible.
+ */
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ if (q->u.fixed.cell) {
+ /*
+ * There doesn't seem to be a cell_free() function anywhere in the
+ * pre-channel code; just use tor_free()
+ */
+ tor_free(q->u.fixed.cell);
+ }
+ break;
+ case CELL_QUEUE_PACKED:
+ if (q->u.packed.packed_cell) {
+ packed_cell_free(q->u.packed.packed_cell);
+ }
+ break;
+ case CELL_QUEUE_VAR:
+ if (q->u.var.var_cell) {
+ /*
+ * This one's in connection_or.c; it'd be nice to figure out the
+ * whole flow of cells from one end to the other and factor the
+ * cell memory management functions like this out of the specific
+ * TLS lower layer.
+ */
+ var_cell_free(q->u.var.var_cell);
+ }
+ break;
+ default:
+ /*
+ * Nothing we can do if we don't know the type; this will
+ * have been warned about elsewhere.
+ */
+ break;
+ }
+ }
+ tor_free(q);
+}
+
+/**
+ * Check whether a cell queue entry is padding; this is a helper function
+ * for channel_write_cell_queue_entry()
+ */
+
+static int
+cell_queue_entry_is_padding(cell_queue_entry_t *q)
+{
+ tor_assert(q);
+
+ if (q->type == CELL_QUEUE_FIXED) {
+ if (q->u.fixed.cell) {
+ if (q->u.fixed.cell->command == CELL_PADDING ||
+ q->u.fixed.cell->command == CELL_VPADDING) {
+ return 1;
+ }
+ }
+ } else if (q->type == CELL_QUEUE_VAR) {
+ if (q->u.var.var_cell) {
+ if (q->u.var.var_cell->command == CELL_PADDING ||
+ q->u.var.var_cell->command == CELL_VPADDING) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Allocate a new cell queue entry for a fixed-size cell
+ */
+
+static cell_queue_entry_t *
+cell_queue_entry_new_fixed(cell_t *cell)
+{
+ cell_queue_entry_t *q = NULL;
+
+ tor_assert(cell);
+
+ q = tor_malloc(sizeof(*q));
+ q->type = CELL_QUEUE_FIXED;
+ q->u.fixed.cell = cell;
+
+ return q;
+}
+
+/**
+ * Allocate a new cell queue entry for a variable-size cell
+ */
+
+static cell_queue_entry_t *
+cell_queue_entry_new_var(var_cell_t *var_cell)
+{
+ cell_queue_entry_t *q = NULL;
+
+ tor_assert(var_cell);
+
+ q = tor_malloc(sizeof(*q));
+ q->type = CELL_QUEUE_VAR;
+ q->u.var.var_cell = var_cell;
+
+ return q;
+}
+
+/**
+ * Write to a channel based on a cell_queue_entry_t
+ *
+ * Given a cell_queue_entry_t filled out by the caller, try to send the cell
+ * and queue it if we can't.
+ */
+
+static void
+channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
+{
+ int result = 0, sent = 0;
+ cell_queue_entry_t *tmp = NULL;
+
+ tor_assert(chan);
+ tor_assert(q);
+
+ /* Assert that the state makes sense for a cell write */
+ tor_assert(chan->state == CHANNEL_STATE_OPENING ||
+ chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT);
+
+ /* Increment the timestamp unless it's padding */
+ if (!cell_queue_entry_is_padding(q)) {
+ chan->timestamp_last_added_nonpadding = approx_time();
+ }
+
+ /* Can we send it right out? If so, try */
+ if (SIMPLEQ_EMPTY(&chan->outgoing_queue) &&
+ chan->state == CHANNEL_STATE_OPEN) {
+ /* Pick the right write function for this cell type and save the result */
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ tor_assert(chan->write_cell);
+ tor_assert(q->u.fixed.cell);
+ result = chan->write_cell(chan, q->u.fixed.cell);
+ break;
+ case CELL_QUEUE_PACKED:
+ tor_assert(chan->write_packed_cell);
+ tor_assert(q->u.packed.packed_cell);
+ result = chan->write_packed_cell(chan, q->u.packed.packed_cell);
+ break;
+ case CELL_QUEUE_VAR:
+ tor_assert(chan->write_var_cell);
+ tor_assert(q->u.var.var_cell);
+ result = chan->write_var_cell(chan, q->u.var.var_cell);
+ break;
+ default:
+ tor_assert(1);
+ }
+
+ /* Check if we got it out */
+ if (result > 0) {
+ sent = 1;
+ /* Timestamp for transmission */
+ channel_timestamp_xmit(chan);
+ /* If we're here the queue is empty, so it's drained too */
+ channel_timestamp_drained(chan);
+ /* Update the counter */
+ ++(chan->n_cells_xmitted);
+ }
+ }
+
+ if (!sent) {
+ /* Not sent, queue it */
+ /*
+ * We have to copy the queue entry passed in, since the caller probably
+ * used the stack.
+ */
+ tmp = cell_queue_entry_dup(q);
+ SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next);
+ /* Try to process the queue? */
+ if (chan->state == CHANNEL_STATE_OPEN) channel_flush_cells(chan);
+ }
+}
+
+/**
+ * Write a cell to a channel
+ *
+ * Write a fixed-length cell to a channel using the write_cell() method.
+ * This is equivalent to the pre-channels connection_or_write_cell_to_buf();
+ * it is called by the transport-independent code to deliver a cell to a
+ * channel for transmission.
+ */
+
+void
+channel_write_cell(channel_t *chan, cell_t *cell)
+{
+ cell_queue_entry_t q;
+
+ tor_assert(chan);
+ tor_assert(cell);
+
+ log_debug(LD_CHANNEL,
+ "Writing cell_t %p to channel %p with global ID "
+ U64_FORMAT,
+ cell, chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ q.type = CELL_QUEUE_FIXED;
+ q.u.fixed.cell = cell;
+ channel_write_cell_queue_entry(chan, &q);
+}
+
+/**
+ * Write a packed cell to a channel
+ *
+ * Write a packed cell to a channel using the write_cell() method. This is
+ * called by the transport-independent code to deliver a packed cell to a
+ * channel for transmission.
+ */
+
+void
+channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell)
+{
+ cell_queue_entry_t q;
+
+ tor_assert(chan);
+ tor_assert(packed_cell);
+
+ log_debug(LD_CHANNEL,
+ "Writing packed_cell_t %p to channel %p with global ID "
+ U64_FORMAT,
+ packed_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ q.type = CELL_QUEUE_PACKED;
+ q.u.packed.packed_cell = packed_cell;
+ channel_write_cell_queue_entry(chan, &q);
+}
+
+/**
+ * Write a variable-length cell to a channel
+ *
+ * Write a variable-length cell to a channel using the write_cell() method.
+ * This is equivalent to the pre-channels
+ * connection_or_write_var_cell_to_buf(); it's called by the transport-
+ * independent code to deliver a var_cell to a channel for transmission.
+ */
+
+void
+channel_write_var_cell(channel_t *chan, var_cell_t *var_cell)
+{
+ cell_queue_entry_t q;
+
+ tor_assert(chan);
+ tor_assert(var_cell);
+
+ log_debug(LD_CHANNEL,
+ "Writing var_cell_t %p to channel %p with global ID "
+ U64_FORMAT,
+ var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ q.type = CELL_QUEUE_VAR;
+ q.u.var.var_cell = var_cell;
+ channel_write_cell_queue_entry(chan, &q);
+}
+
+/**
+ * Change channel state
+ *
+ * This internal and subclass use only function is used to change channel
+ * state, performing all transition validity checks and whatever actions
+ * are appropriate to the state transition in question.
+ */
+
+void
+channel_change_state(channel_t *chan, channel_state_t to_state)
+{
+ channel_state_t from_state;
+ unsigned char was_active, is_active;
+ unsigned char was_in_id_map, is_in_id_map;
+
+ tor_assert(chan);
+ from_state = chan->state;
+
+ tor_assert(channel_state_is_valid(from_state));
+ tor_assert(channel_state_is_valid(to_state));
+ tor_assert(channel_state_can_transition(chan->state, to_state));
+
+ /* Check for no-op transitions */
+ if (from_state == to_state) {
+ log_debug(LD_CHANNEL,
+ "Got no-op transition from \"%s\" to itself on channel %p"
+ "(global ID " U64_FORMAT ")",
+ channel_state_to_string(to_state),
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ return;
+ }
+
+ /* If we're going to a closing or closed state, we must have a reason set */
+ if (to_state == CHANNEL_STATE_CLOSING ||
+ to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR) {
+ tor_assert(chan->reason_for_closing != CHANNEL_NOT_CLOSING);
+ }
+
+ /*
+ * We need to maintain the queues here for some transitions:
+ * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT)
+ * we may have a backlog of cells to transmit, so drain the queues in
+ * that case, and when going to CHANNEL_STATE_CLOSED the subclass
+ * should have made sure to finish sending things (or gone to
+ * CHANNEL_STATE_ERROR if not possible), so we assert for that here.
+ */
+
+ log_debug(LD_CHANNEL,
+ "Changing state of channel %p (global ID " U64_FORMAT
+ ") from \"%s\" to \"%s\"",
+ chan,
+ U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state),
+ channel_state_to_string(to_state));
+
+ chan->state = to_state;
+
+ /* Need to add to the right lists if the channel is registered */
+ if (chan->registered) {
+ was_active = !(from_state == CHANNEL_STATE_CLOSED ||
+ from_state == CHANNEL_STATE_ERROR);
+ is_active = !(to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR);
+
+ /* Need to take off active list and put on finished list? */
+ if (was_active && !is_active) {
+ if (active_channels) smartlist_remove(active_channels, chan);
+ if (!finished_channels) finished_channels = smartlist_new();
+ smartlist_add(finished_channels, chan);
+ }
+ /* Need to put on active list? */
+ else if (!was_active && is_active) {
+ if (finished_channels) smartlist_remove(finished_channels, chan);
+ if (!active_channels) active_channels = smartlist_new();
+ smartlist_add(active_channels, chan);
+ }
+
+ if (!tor_digest_is_zero(chan->identity_digest)) {
+ /* Now we need to handle the identity map */
+ was_in_id_map = !(from_state == CHANNEL_STATE_CLOSING ||
+ from_state == CHANNEL_STATE_CLOSED ||
+ from_state == CHANNEL_STATE_ERROR);
+ is_in_id_map = !(to_state == CHANNEL_STATE_CLOSING ||
+ to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR);
+
+ if (!was_in_id_map && is_in_id_map) channel_add_to_digest_map(chan);
+ else if (was_in_id_map && !is_in_id_map)
+ channel_remove_from_digest_map(chan);
+ }
+ }
+
+ /* Tell circuits if we opened and stuff */
+ if (to_state == CHANNEL_STATE_OPEN) {
+ channel_do_open_actions(chan);
+
+ /* Check for queued cells to process */
+ if (! SIMPLEQ_EMPTY(&chan->incoming_queue))
+ channel_process_cells(chan);
+ if (! SIMPLEQ_EMPTY(&chan->outgoing_queue))
+ channel_flush_cells(chan);
+ } else if (to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR) {
+ /* Assert that all queues are empty */
+ tor_assert(SIMPLEQ_EMPTY(&chan->incoming_queue));
+ tor_assert(SIMPLEQ_EMPTY(&chan->outgoing_queue));
+ }
+}
+
+/**
+ * Change channel listener state
+ *
+ * This internal and subclass use only function is used to change channel
+ * listener state, performing all transition validity checks and whatever
+ * actions are appropriate to the state transition in question.
+ */
+
+void
+channel_listener_change_state(channel_listener_t *chan_l,
+ channel_listener_state_t to_state)
+{
+ channel_listener_state_t from_state;
+ unsigned char was_active, is_active;
+
+ tor_assert(chan_l);
+ from_state = chan_l->state;
+
+ tor_assert(channel_listener_state_is_valid(from_state));
+ tor_assert(channel_listener_state_is_valid(to_state));
+ tor_assert(channel_listener_state_can_transition(chan_l->state, to_state));
+
+ /* Check for no-op transitions */
+ if (from_state == to_state) {
+ log_debug(LD_CHANNEL,
+ "Got no-op transition from \"%s\" to itself on channel "
+ "listener %p (global ID " U64_FORMAT ")",
+ channel_listener_state_to_string(to_state),
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
+ return;
+ }
+
+ /* If we're going to a closing or closed state, we must have a reason set */
+ if (to_state == CHANNEL_LISTENER_STATE_CLOSING ||
+ to_state == CHANNEL_LISTENER_STATE_CLOSED ||
+ to_state == CHANNEL_LISTENER_STATE_ERROR) {
+ tor_assert(chan_l->reason_for_closing != CHANNEL_LISTENER_NOT_CLOSING);
+ }
+
+ /*
+ * We need to maintain the queues here for some transitions:
+ * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT)
+ * we may have a backlog of cells to transmit, so drain the queues in
+ * that case, and when going to CHANNEL_STATE_CLOSED the subclass
+ * should have made sure to finish sending things (or gone to
+ * CHANNEL_STATE_ERROR if not possible), so we assert for that here.
+ */
+
+ log_debug(LD_CHANNEL,
+ "Changing state of channel listener %p (global ID " U64_FORMAT
+ "from \"%s\" to \"%s\"",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier),
+ channel_listener_state_to_string(chan_l->state),
+ channel_listener_state_to_string(to_state));
+
+ chan_l->state = to_state;
+
+ /* Need to add to the right lists if the channel listener is registered */
+ if (chan_l->registered) {
+ was_active = !(from_state == CHANNEL_LISTENER_STATE_CLOSED ||
+ from_state == CHANNEL_LISTENER_STATE_ERROR);
+ is_active = !(to_state == CHANNEL_LISTENER_STATE_CLOSED ||
+ to_state == CHANNEL_LISTENER_STATE_ERROR);
+
+ /* Need to take off active list and put on finished list? */
+ if (was_active && !is_active) {
+ if (active_listeners) smartlist_remove(active_listeners, chan_l);
+ if (!finished_listeners) finished_listeners = smartlist_new();
+ smartlist_add(finished_listeners, chan_l);
+ }
+ /* Need to put on active list? */
+ else if (!was_active && is_active) {
+ if (finished_listeners) smartlist_remove(finished_listeners, chan_l);
+ if (!active_listeners) active_listeners = smartlist_new();
+ smartlist_add(active_listeners, chan_l);
+ }
+ }
+
+ if (to_state == CHANNEL_LISTENER_STATE_CLOSED ||
+ to_state == CHANNEL_LISTENER_STATE_ERROR) {
+ /* Assert that the queue is empty */
+ tor_assert(!(chan_l->incoming_list) ||
+ smartlist_len(chan_l->incoming_list) == 0);
+ }
+}
+
+/**
+ * Try to flush cells to the lower layer
+ *
+ * this is called by the lower layer to indicate that it wants more cells;
+ * it will try to write up to num_cells cells from the channel's cell queue or
+ * from circuits active on that channel, or as many as it has available if
+ * num_cells == -1.
+ */
+
+#define MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED 256
+
+ssize_t
+channel_flush_some_cells(channel_t *chan, ssize_t num_cells)
+{
+ unsigned int unlimited = 0;
+ ssize_t flushed = 0;
+ int num_cells_from_circs, clamped_num_cells;
+
+ tor_assert(chan);
+
+ if (num_cells < 0) unlimited = 1;
+ if (!unlimited && num_cells <= flushed) goto done;
+
+ /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */
+ if (chan->state == CHANNEL_STATE_OPEN) {
+ /* Try to flush as much as we can that's already queued */
+ flushed += channel_flush_some_cells_from_outgoing_queue(chan,
+ (unlimited ? -1 : num_cells - flushed));
+ if (!unlimited && num_cells <= flushed) goto done;
+
+ if (circuitmux_num_cells(chan->cmux) > 0) {
+ /* Calculate number of cells, including clamp */
+ if (unlimited) {
+ clamped_num_cells = MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED;
+ } else {
+ if (num_cells - flushed >
+ MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED) {
+ clamped_num_cells = MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED;
+ } else {
+ clamped_num_cells = (int)(num_cells - flushed);
+ }
+ }
+ /* Try to get more cells from any active circuits */
+ num_cells_from_circs = channel_flush_from_first_active_circuit(
+ chan, clamped_num_cells);
+
+ /* If it claims we got some, process the queue again */
+ if (num_cells_from_circs > 0) {
+ flushed += channel_flush_some_cells_from_outgoing_queue(chan,
+ (unlimited ? -1 : num_cells - flushed));
+ }
+ }
+ }
+
+ done:
+ return flushed;
+}
+
+/**
+ * Flush cells from just the channel's outgoing cell queue
+ *
+ * This gets called from channel_flush_some_cells() above to flush cells
+ * just from the queue without trying for active_circuits.
+ */
+
+static ssize_t
+channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
+ ssize_t num_cells)
+{
+ unsigned int unlimited = 0;
+ ssize_t flushed = 0;
+ cell_queue_entry_t *q = NULL;
+
+ tor_assert(chan);
+ tor_assert(chan->write_cell);
+ tor_assert(chan->write_packed_cell);
+ tor_assert(chan->write_var_cell);
+
+ if (num_cells < 0) unlimited = 1;
+ if (!unlimited && num_cells <= flushed) return 0;
+
+ /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */
+ if (chan->state == CHANNEL_STATE_OPEN) {
+ while ((unlimited || num_cells > flushed) &&
+ NULL != (q = SIMPLEQ_FIRST(&chan->outgoing_queue))) {
+
+ if (1) {
+ /*
+ * Okay, we have a good queue entry, try to give it to the lower
+ * layer.
+ */
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ if (q->u.fixed.cell) {
+ if (chan->write_cell(chan,
+ q->u.fixed.cell)) {
+ ++flushed;
+ channel_timestamp_xmit(chan);
+ ++(chan->n_cells_xmitted);
+ cell_queue_entry_free(q, 1);
+ q = NULL;
+ }
+ /* Else couldn't write it; leave it on the queue */
+ } else {
+ /* This shouldn't happen */
+ log_info(LD_CHANNEL,
+ "Saw broken cell queue entry of type CELL_QUEUE_FIXED "
+ "with no cell on channel %p "
+ "(global ID " U64_FORMAT ").",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ /* Throw it away */
+ cell_queue_entry_free(q, 0);
+ q = NULL;
+ }
+ break;
+ case CELL_QUEUE_PACKED:
+ if (q->u.packed.packed_cell) {
+ if (chan->write_packed_cell(chan,
+ q->u.packed.packed_cell)) {
+ ++flushed;
+ channel_timestamp_xmit(chan);
+ ++(chan->n_cells_xmitted);
+ cell_queue_entry_free(q, 1);
+ q = NULL;
+ }
+ /* Else couldn't write it; leave it on the queue */
+ } else {
+ /* This shouldn't happen */
+ log_info(LD_CHANNEL,
+ "Saw broken cell queue entry of type CELL_QUEUE_PACKED "
+ "with no cell on channel %p "
+ "(global ID " U64_FORMAT ").",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ /* Throw it away */
+ cell_queue_entry_free(q, 0);
+ q = NULL;
+ }
+ break;
+ case CELL_QUEUE_VAR:
+ if (q->u.var.var_cell) {
+ if (chan->write_var_cell(chan,
+ q->u.var.var_cell)) {
+ ++flushed;
+ channel_timestamp_xmit(chan);
+ ++(chan->n_cells_xmitted);
+ cell_queue_entry_free(q, 1);
+ q = NULL;
+ }
+ /* Else couldn't write it; leave it on the queue */
+ } else {
+ /* This shouldn't happen */
+ log_info(LD_CHANNEL,
+ "Saw broken cell queue entry of type CELL_QUEUE_VAR "
+ "with no cell on channel %p "
+ "(global ID " U64_FORMAT ").",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ /* Throw it away */
+ cell_queue_entry_free(q, 0);
+ q = NULL;
+ }
+ break;
+ default:
+ /* Unknown type, log and free it */
+ log_info(LD_CHANNEL,
+ "Saw an unknown cell queue entry type %d on channel %p "
+ "(global ID " U64_FORMAT "; ignoring it."
+ " Someone should fix this.",
+ q->type, chan, U64_PRINTF_ARG(chan->global_identifier));
+ cell_queue_entry_free(q, 0);
+ q = NULL;
+ }
+
+ /* if q got NULLed out, we used it and should remove the queue entry */
+ if (!q) SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next);
+ /* No cell removed from list, so we can't go on any further */
+ else break;
+ }
+ }
+ }
+
+ /* Did we drain the queue? */
+ if (SIMPLEQ_EMPTY(&chan->outgoing_queue)) {
+ channel_timestamp_drained(chan);
+ }
+
+ return flushed;
+}
+
+/**
+ * Flush as many cells as we possibly can from the queue
+ *
+ * This tries to flush as many cells from the queue as the lower layer
+ * will take. It just calls channel_flush_some_cells_from_outgoing_queue()
+ * in unlimited mode.
+ */
+
+void
+channel_flush_cells(channel_t *chan)
+{
+ channel_flush_some_cells_from_outgoing_queue(chan, -1);
+}
+
+/**
+ * Check if any cells are available
+ *
+ * This gets used from the lower layer to check if any more cells are
+ * available.
+ */
+
+int
+channel_more_to_flush(channel_t *chan)
+{
+ tor_assert(chan);
+
+ /* Check if we have any queued */
+ if (! SIMPLEQ_EMPTY(&chan->incoming_queue))
+ return 1;
+
+ /* Check if any circuits would like to queue some */
+ if (circuitmux_num_cells(chan->cmux) > 0) return 1;
+
+ /* Else no */
+ return 0;
+}
+
+/**
+ * Notify the channel we're done flushing the output in the lower layer
+ *
+ * Connection.c will call this when we've flushed the output; there's some
+ * dirreq-related maintenance to do.
+ */
+
+void
+channel_notify_flushed(channel_t *chan)
+{
+ tor_assert(chan);
+
+ if (chan->dirreq_id != 0)
+ geoip_change_dirreq_state(chan->dirreq_id,
+ DIRREQ_TUNNELED,
+ DIRREQ_CHANNEL_BUFFER_FLUSHED);
+}
+
+/**
+ * Process the queue of incoming channels on a listener
+ *
+ * Use a listener's registered callback to process as many entries in the
+ * queue of incoming channels as possible.
+ */
+
+void
+channel_listener_process_incoming(channel_listener_t *listener)
+{
+ tor_assert(listener);
+
+ /*
+ * CHANNEL_LISTENER_STATE_CLOSING permitted because we drain the queue
+ * while closing a listener.
+ */
+ tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING ||
+ listener->state == CHANNEL_LISTENER_STATE_CLOSING);
+ tor_assert(listener->listener);
+
+ log_debug(LD_CHANNEL,
+ "Processing queue of incoming connections for channel "
+ "listener %p (global ID " U64_FORMAT ")",
+ listener, U64_PRINTF_ARG(listener->global_identifier));
+
+ if (!(listener->incoming_list)) return;
+
+ SMARTLIST_FOREACH_BEGIN(listener->incoming_list,
+ channel_t *, chan) {
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Handling incoming channel %p (" U64_FORMAT ") "
+ "for listener %p (" U64_FORMAT ")",
+ chan,
+ U64_PRINTF_ARG(chan->global_identifier),
+ listener,
+ U64_PRINTF_ARG(listener->global_identifier));
+ /* Make sure this is set correctly */
+ channel_mark_incoming(chan);
+ listener->listener(listener, chan);
+ } SMARTLIST_FOREACH_END(chan);
+
+ smartlist_free(listener->incoming_list);
+ listener->incoming_list = NULL;
+}
+
+/**
+ * Take actions required when a channel becomes open
+ *
+ * Handle actions we should do when we know a channel is open; a lot of
+ * this comes from the old connection_or_set_state_open() of connection_or.c.
+ *
+ * Because of this mechanism, future channel_t subclasses should take care
+ * not to change a channel to from CHANNEL_STATE_OPENING to CHANNEL_STATE_OPEN
+ * until there is positive confirmation that the network is operational.
+ * In particular, anything UDP-based should not make this transition until a
+ * packet is received from the other side.
+ */
+
+void
+channel_do_open_actions(channel_t *chan)
+{
+ tor_addr_t remote_addr;
+ int started_here, not_using = 0;
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ started_here = channel_is_outgoing(chan);
+
+ if (started_here) {
+ circuit_build_times_network_is_live(&circ_times);
+ rep_hist_note_connect_succeeded(chan->identity_digest, now);
+ if (entry_guard_register_connect_status(
+ chan->identity_digest, 1, 0, now) < 0) {
+ /* Close any circuits pending on this channel. We leave it in state
+ * 'open' though, because it didn't actually *fail* -- we just
+ * chose not to use it. */
+ log_debug(LD_OR,
+ "New entry guard was reachable, but closing this "
+ "connection so we can retry the earlier entry guards.");
+ circuit_n_chan_done(chan, 0);
+ not_using = 1;
+ }
+ router_set_status(chan->identity_digest, 1);
+ } else {
+ /* only report it to the geoip module if it's not a known router */
+ if (!router_get_by_id_digest(chan->identity_digest)) {
+ if (channel_get_addr_if_possible(chan, &remote_addr)) {
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &remote_addr,
+ now);
+ }
+ /* Otherwise the underlying transport can't tell us this, so skip it */
+ }
+ }
+
+ if (!not_using) circuit_n_chan_done(chan, 1);
+}
+
+/**
+ * Queue an incoming channel on a listener
+ *
+ * Internal and subclass use only function to queue an incoming channel from
+ * a listener. A subclass of channel_listener_t should call this when a new
+ * incoming channel is created.
+ */
+
+void
+channel_listener_queue_incoming(channel_listener_t *listener,
+ channel_t *incoming)
+{
+ int need_to_queue = 0;
+
+ tor_assert(listener);
+ tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING);
+ tor_assert(incoming);
+
+ log_debug(LD_CHANNEL,
+ "Queueing incoming channel %p (global ID " U64_FORMAT ") on "
+ "channel listener %p (global ID " U64_FORMAT ")",
+ incoming, U64_PRINTF_ARG(incoming->global_identifier),
+ listener, U64_PRINTF_ARG(listener->global_identifier));
+
+ /* Do we need to queue it, or can we just call the listener right away? */
+ if (!(listener->listener)) need_to_queue = 1;
+ if (listener->incoming_list &&
+ (smartlist_len(listener->incoming_list) > 0))
+ need_to_queue = 1;
+
+ /* If we need to queue and have no queue, create one */
+ if (need_to_queue && !(listener->incoming_list)) {
+ listener->incoming_list = smartlist_new();
+ }
+
+ /* Bump the counter and timestamp it */
+ channel_listener_timestamp_active(listener);
+ channel_listener_timestamp_accepted(listener);
+ ++(listener->n_accepted);
+
+ /* If we don't need to queue, process it right away */
+ if (!need_to_queue) {
+ tor_assert(listener->listener);
+ listener->listener(listener, incoming);
+ }
+ /*
+ * Otherwise, we need to queue; queue and then process the queue if
+ * we can.
+ */
+ else {
+ tor_assert(listener->incoming_list);
+ smartlist_add(listener->incoming_list, incoming);
+ if (listener->listener) channel_listener_process_incoming(listener);
+ }
+}
+
+/**
+ * Process queued incoming cells
+ *
+ * Process as many queued cells as we can from the incoming
+ * cell queue.
+ */
+
+void
+channel_process_cells(channel_t *chan)
+{
+ cell_queue_entry_t *q;
+ tor_assert(chan);
+ tor_assert(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_MAINT ||
+ chan->state == CHANNEL_STATE_OPEN);
+
+ log_debug(LD_CHANNEL,
+ "Processing as many incoming cells as we can for channel %p",
+ chan);
+
+ /* Nothing we can do if we have no registered cell handlers */
+ if (!(chan->cell_handler ||
+ chan->var_cell_handler)) return;
+ /* Nothing we can do if we have no cells */
+ if (SIMPLEQ_EMPTY(&chan->incoming_queue)) return;
+
+ /*
+ * Process cells until we're done or find one we have no current handler
+ * for.
+ */
+ while (NULL != (q = SIMPLEQ_FIRST(&chan->incoming_queue))) {
+ tor_assert(q);
+ tor_assert(q->type == CELL_QUEUE_FIXED ||
+ q->type == CELL_QUEUE_VAR);
+
+ if (q->type == CELL_QUEUE_FIXED &&
+ chan->cell_handler) {
+ /* Handle a fixed-length cell */
+ SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next);
+ tor_assert(q->u.fixed.cell);
+ log_debug(LD_CHANNEL,
+ "Processing incoming cell_t %p for channel %p (global ID "
+ U64_FORMAT ")",
+ q->u.fixed.cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->cell_handler(chan, q->u.fixed.cell);
+ tor_free(q);
+ } else if (q->type == CELL_QUEUE_VAR &&
+ chan->var_cell_handler) {
+ /* Handle a variable-length cell */
+ SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next);
+ tor_assert(q->u.var.var_cell);
+ log_debug(LD_CHANNEL,
+ "Processing incoming var_cell_t %p for channel %p (global ID "
+ U64_FORMAT ")",
+ q->u.var.var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->var_cell_handler(chan, q->u.var.var_cell);
+ tor_free(q);
+ } else {
+ /* Can't handle this one */
+ break;
+ }
+ }
+}
+
+/**
+ * Queue incoming cell
+ *
+ * This should be called by a channel_t subclass to queue an incoming fixed-
+ * length cell for processing, and process it if possible.
+ */
+
+void
+channel_queue_cell(channel_t *chan, cell_t *cell)
+{
+ int need_to_queue = 0;
+ cell_queue_entry_t *q;
+
+ tor_assert(chan);
+ tor_assert(cell);
+ tor_assert(chan->state == CHANNEL_STATE_OPEN);
+
+ /* Do we need to queue it, or can we just call the handler right away? */
+ if (!(chan->cell_handler)) need_to_queue = 1;
+ if (! SIMPLEQ_EMPTY(&chan->incoming_queue))
+ need_to_queue = 1;
+
+ /* Timestamp for receiving */
+ channel_timestamp_recv(chan);
+
+ /* Update the counter */
+ ++(chan->n_cells_recved);
+
+ /* If we don't need to queue we can just call cell_handler */
+ if (!need_to_queue) {
+ tor_assert(chan->cell_handler);
+ log_debug(LD_CHANNEL,
+ "Directly handling incoming cell_t %p for channel %p "
+ "(global ID " U64_FORMAT ")",
+ cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->cell_handler(chan, cell);
+ } else {
+ /* Otherwise queue it and then process the queue if possible. */
+ q = cell_queue_entry_new_fixed(cell);
+ log_debug(LD_CHANNEL,
+ "Queueing incoming cell_t %p for channel %p "
+ "(global ID " U64_FORMAT ")",
+ cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next);
+ if (chan->cell_handler ||
+ chan->var_cell_handler) {
+ channel_process_cells(chan);
+ }
+ }
+}
+
+/**
+ * Queue incoming variable-length cell
+ *
+ * This should be called by a channel_t subclass to queue an incoming
+ * variable-length cell for processing, and process it if possible.
+ */
+
+void
+channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
+{
+ int need_to_queue = 0;
+ cell_queue_entry_t *q;
+
+ tor_assert(chan);
+ tor_assert(var_cell);
+ tor_assert(chan->state == CHANNEL_STATE_OPEN);
+
+ /* Do we need to queue it, or can we just call the handler right away? */
+ if (!(chan->var_cell_handler)) need_to_queue = 1;
+ if (! SIMPLEQ_EMPTY(&chan->incoming_queue))
+ need_to_queue = 1;
+
+ /* Timestamp for receiving */
+ channel_timestamp_recv(chan);
+
+ /* Update the counter */
+ ++(chan->n_cells_recved);
+
+ /* If we don't need to queue we can just call cell_handler */
+ if (!need_to_queue) {
+ tor_assert(chan->var_cell_handler);
+ log_debug(LD_CHANNEL,
+ "Directly handling incoming var_cell_t %p for channel %p "
+ "(global ID " U64_FORMAT ")",
+ var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->var_cell_handler(chan, var_cell);
+ } else {
+ /* Otherwise queue it and then process the queue if possible. */
+ q = cell_queue_entry_new_var(var_cell);
+ log_debug(LD_CHANNEL,
+ "Queueing incoming var_cell_t %p for channel %p "
+ "(global ID " U64_FORMAT ")",
+ var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next);
+ if (chan->cell_handler ||
+ chan->var_cell_handler) {
+ channel_process_cells(chan);
+ }
+ }
+}
+
+/**
+ * Send destroy cell on a channel
+ *
+ * Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
+ * onto channel <b>chan</b>. Don't perform range-checking on reason:
+ * we may want to propagate reasons from other cells.
+ */
+
+int
+channel_send_destroy(circid_t circ_id, channel_t *chan, int reason)
+{
+ cell_t cell;
+
+ tor_assert(chan);
+
+ /* Check to make sure we can send on this channel first */
+ if (!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ memset(&cell, 0, sizeof(cell_t));
+ cell.circ_id = circ_id;
+ cell.command = CELL_DESTROY;
+ cell.payload[0] = (uint8_t) reason;
+ log_debug(LD_OR,
+ "Sending destroy (circID %d) on channel %p "
+ "(global ID " U64_FORMAT ")",
+ circ_id, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ channel_write_cell(chan, &cell);
+ } else {
+ log_warn(LD_BUG,
+ "Someone called channel_send_destroy() for circID %d "
+ "on a channel " U64_FORMAT " at %p in state %s (%d)",
+ circ_id, U64_PRINTF_ARG(chan->global_identifier),
+ chan, channel_state_to_string(chan->state),
+ chan->state);
+ }
+
+ return 0;
+}
+
+/**
+ * Dump channel statistics to the log
+ *
+ * This is called from dumpstats() in main.c and spams the log with
+ * statistics on channels.
+ */
+
+void
+channel_dumpstats(int severity)
+{
+ if (all_channels && smartlist_len(all_channels) > 0) {
+ log(severity, LD_GENERAL,
+ "Dumping statistics about %d channels:",
+ smartlist_len(all_channels));
+ log(severity, LD_GENERAL,
+ "%d are active, and %d are done and waiting for cleanup",
+ (active_channels != NULL) ?
+ smartlist_len(active_channels) : 0,
+ (finished_channels != NULL) ?
+ smartlist_len(finished_channels) : 0);
+
+ SMARTLIST_FOREACH(all_channels, channel_t *, chan,
+ channel_dump_statistics(chan, severity));
+
+ log(severity, LD_GENERAL,
+ "Done spamming about channels now");
+ } else {
+ log(severity, LD_GENERAL,
+ "No channels to dump");
+ }
+}
+
+/**
+ * Dump channel listener statistics to the log
+ *
+ * This is called from dumpstats() in main.c and spams the log with
+ * statistics on channel listeners.
+ */
+
+void
+channel_listener_dumpstats(int severity)
+{
+ if (all_listeners && smartlist_len(all_listeners) > 0) {
+ log(severity, LD_GENERAL,
+ "Dumping statistics about %d channel listeners:",
+ smartlist_len(all_listeners));
+ log(severity, LD_GENERAL,
+ "%d are active and %d are done and waiting for cleanup",
+ (active_listeners != NULL) ?
+ smartlist_len(active_listeners) : 0,
+ (finished_listeners != NULL) ?
+ smartlist_len(finished_listeners) : 0);
+
+ SMARTLIST_FOREACH(all_listeners, channel_listener_t *, chan_l,
+ channel_listener_dump_statistics(chan_l, severity));
+
+ log(severity, LD_GENERAL,
+ "Done spamming about channel listeners now");
+ } else {
+ log(severity, LD_GENERAL,
+ "No channel listeners to dump");
+ }
+}
+
+/**
+ * Set the cmux policy on all active channels
+ */
+
+void
+channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol)
+{
+ if (!active_channels) return;
+
+ SMARTLIST_FOREACH_BEGIN(active_channels, channel_t *, curr) {
+ if (curr->cmux) {
+ circuitmux_set_policy(curr->cmux, pol);
+ }
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Clean up channels
+ *
+ * This gets called periodically from run_scheduled_events() in main.c;
+ * it cleans up after closed channels.
+ */
+
+void
+channel_run_cleanup(void)
+{
+ channel_t *tmp = NULL;
+
+ /* Check if we need to do anything */
+ if (!finished_channels || smartlist_len(finished_channels) == 0) return;
+
+ /* Iterate through finished_channels and get rid of them */
+ SMARTLIST_FOREACH_BEGIN(finished_channels, channel_t *, curr) {
+ tmp = curr;
+ /* Remove it from the list */
+ SMARTLIST_DEL_CURRENT(finished_channels, curr);
+ /* Also unregister it */
+ channel_unregister(tmp);
+ /* ... and free it */
+ channel_free(tmp);
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Clean up channel listeners
+ *
+ * This gets called periodically from run_scheduled_events() in main.c;
+ * it cleans up after closed channel listeners.
+ */
+
+void
+channel_listener_run_cleanup(void)
+{
+ channel_listener_t *tmp = NULL;
+
+ /* Check if we need to do anything */
+ if (!finished_listeners || smartlist_len(finished_listeners) == 0) return;
+
+ /* Iterate through finished_channels and get rid of them */
+ SMARTLIST_FOREACH_BEGIN(finished_listeners, channel_listener_t *, curr) {
+ tmp = curr;
+ /* Remove it from the list */
+ SMARTLIST_DEL_CURRENT(finished_listeners, curr);
+ /* Also unregister it */
+ channel_listener_unregister(tmp);
+ /* ... and free it */
+ channel_listener_free(tmp);
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Free a list of channels for channel_free_all()
+ */
+
+static void
+channel_free_list(smartlist_t *channels, int mark_for_close)
+{
+ if (!channels) return;
+
+ SMARTLIST_FOREACH_BEGIN(channels, channel_t *, curr) {
+ /* Deregister and free it */
+ tor_assert(curr);
+ log_debug(LD_CHANNEL,
+ "Cleaning up channel %p (global ID " U64_FORMAT ") "
+ "in state %s (%d)",
+ curr, U64_PRINTF_ARG(curr->global_identifier),
+ channel_state_to_string(curr->state), curr->state);
+ /* Detach circuits early so they can find the channel */
+ if (curr->cmux) {
+ circuitmux_detach_all_circuits(curr->cmux);
+ }
+ channel_unregister(curr);
+ if (mark_for_close) {
+ if (!(curr->state == CHANNEL_STATE_CLOSING ||
+ curr->state == CHANNEL_STATE_CLOSED ||
+ curr->state == CHANNEL_STATE_ERROR)) {
+ channel_mark_for_close(curr);
+ }
+ channel_force_free(curr);
+ } else channel_free(curr);
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Free a list of channel listeners for channel_free_all()
+ */
+
+static void
+channel_listener_free_list(smartlist_t *listeners, int mark_for_close)
+{
+ if (!listeners) return;
+
+ SMARTLIST_FOREACH_BEGIN(listeners, channel_listener_t *, curr) {
+ /* Deregister and free it */
+ tor_assert(curr);
+ log_debug(LD_CHANNEL,
+ "Cleaning up channel listener %p (global ID " U64_FORMAT ") "
+ "in state %s (%d)",
+ curr, U64_PRINTF_ARG(curr->global_identifier),
+ channel_listener_state_to_string(curr->state), curr->state);
+ channel_listener_unregister(curr);
+ if (mark_for_close) {
+ if (!(curr->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ curr->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ curr->state == CHANNEL_LISTENER_STATE_ERROR)) {
+ channel_listener_mark_for_close(curr);
+ }
+ channel_listener_force_free(curr);
+ } else channel_listener_free(curr);
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Close all channels and free everything
+ *
+ * This gets called from tor_free_all() in main.c to clean up on exit.
+ * It will close all registered channels and free associated storage,
+ * then free the all_channels, active_channels, listening_channels and
+ * finished_channels lists and also channel_identity_map.
+ */
+
+void
+channel_free_all(void)
+{
+ log_debug(LD_CHANNEL,
+ "Shutting down channels...");
+
+ /* First, let's go for finished channels */
+ if (finished_channels) {
+ channel_free_list(finished_channels, 0);
+ smartlist_free(finished_channels);
+ finished_channels = NULL;
+ }
+
+ /* Now the finished listeners */
+ if (finished_listeners) {
+ channel_listener_free_list(finished_listeners, 0);
+ smartlist_free(finished_listeners);
+ finished_listeners = NULL;
+ }
+
+ /* Now all active channels */
+ if (active_channels) {
+ channel_free_list(active_channels, 1);
+ smartlist_free(active_channels);
+ active_channels = NULL;
+ }
+
+ /* Now all active listeners */
+ if (active_listeners) {
+ channel_listener_free_list(active_listeners, 1);
+ smartlist_free(active_listeners);
+ active_listeners = NULL;
+ }
+
+ /* Now all channels, in case any are left over */
+ if (all_channels) {
+ channel_free_list(all_channels, 1);
+ smartlist_free(all_channels);
+ all_channels = NULL;
+ }
+
+ /* Now all listeners, in case any are left over */
+ if (all_listeners) {
+ channel_listener_free_list(all_listeners, 1);
+ smartlist_free(all_listeners);
+ all_listeners = NULL;
+ }
+
+ /* Now free channel_identity_map */
+ log_debug(LD_CHANNEL,
+ "Freeing channel_identity_map");
+ /* Geez, anything still left over just won't die ... let it leak then */
+ HT_CLEAR(channel_idmap, &channel_identity_map);
+
+ log_debug(LD_CHANNEL,
+ "Done cleaning up after channels");
+}
+
+/**
+ * Connect to a given addr/port/digest
+ *
+ * This sets up a new outgoing channel; in the future if multiple
+ * channel_t subclasses are available, this is where the selection policy
+ * should go. It may also be desirable to fold port into tor_addr_t
+ * or make a new type including a tor_addr_t and port, so we have a
+ * single abstract object encapsulating all the protocol details of
+ * how to contact an OR.
+ */
+
+channel_t *
+channel_connect(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest)
+{
+ return channel_tls_connect(addr, port, id_digest);
+}
+
+/**
+ * Decide which of two channels to prefer for extending a circuit
+ *
+ * This function is called while extending a circuit and returns true iff
+ * a is 'better' than b. The most important criterion here is that a
+ * canonical channel is always better than a non-canonical one, but the
+ * number of circuits and the age are used as tie-breakers.
+ *
+ * This is based on the former connection_or_is_better() of connection_or.c
+ */
+
+int
+channel_is_better(time_t now, channel_t *a, channel_t *b,
+ int forgive_new_connections)
+{
+ int a_grace, b_grace;
+ int a_is_canonical, b_is_canonical;
+ int a_has_circs, b_has_circs;
+
+ /*
+ * Do not definitively deprecate a new channel with no circuits on it
+ * until this much time has passed.
+ */
+#define NEW_CHAN_GRACE_PERIOD (15*60)
+
+ tor_assert(a);
+ tor_assert(b);
+
+ /* Check if one is canonical and the other isn't first */
+ a_is_canonical = channel_is_canonical(a);
+ b_is_canonical = channel_is_canonical(b);
+
+ if (a_is_canonical && !b_is_canonical) return 1;
+ if (!a_is_canonical && b_is_canonical) return 0;
+
+ /*
+ * Okay, if we're here they tied on canonicity. Next we check if
+ * they have any circuits, and if one does and the other doesn't,
+ * we prefer the one that does, unless we are forgiving and the
+ * one that has no circuits is in its grace period.
+ */
+
+ a_has_circs = (channel_num_circuits(a) > 0);
+ b_has_circs = (channel_num_circuits(b) > 0);
+ a_grace = (forgive_new_connections &&
+ (now < channel_when_created(a) + NEW_CHAN_GRACE_PERIOD));
+ b_grace = (forgive_new_connections &&
+ (now < channel_when_created(b) + NEW_CHAN_GRACE_PERIOD));
+
+ if (a_has_circs && !b_has_circs && !b_grace) return 1;
+ if (!a_has_circs && b_has_circs && !a_grace) return 0;
+
+ /* They tied on circuits too; just prefer whichever is newer */
+
+ if (channel_when_created(a) > channel_when_created(b)) return 1;
+ else return 0;
+}
+
+/**
+ * Get a channel to extend a circuit
+ *
+ * Pick a suitable channel to extend a circuit to given the desired digest
+ * the address we believe is correct for that digest; this tries to see
+ * if we already have one for the requested endpoint, but if there is no good
+ * channel, set *msg_out to a message describing the channel's state
+ * and our next action, and set *launch_out to a boolean indicated whether
+ * the caller should try to launch a new channel with channel_connect().
+ */
+
+channel_t *
+channel_get_for_extend(const char *digest,
+ const tor_addr_t *target_addr,
+ const char **msg_out,
+ int *launch_out)
+{
+ channel_t *chan, *best = NULL;
+ int n_inprogress_goodaddr = 0, n_old = 0;
+ int n_noncanonical = 0, n_possible = 0;
+ time_t now = approx_time();
+
+ tor_assert(msg_out);
+ tor_assert(launch_out);
+
+ chan = channel_find_by_remote_digest(digest);
+
+ /* Walk the list, unrefing the old one and refing the new at each
+ * iteration.
+ */
+ for (; chan; chan = channel_next_with_digest(chan)) {
+ tor_assert(tor_memeq(chan->identity_digest,
+ digest, DIGEST_LEN));
+
+ if (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)
+ continue;
+
+ /* Never return a channel on which the other end appears to be
+ * a client. */
+ if (channel_is_client(chan)) {
+ continue;
+ }
+
+ /* Never return a non-open connection. */
+ if (chan->state != CHANNEL_STATE_OPEN) {
+ /* If the address matches, don't launch a new connection for this
+ * circuit. */
+ if (!channel_matches_target_addr_for_extend(chan, target_addr))
+ ++n_inprogress_goodaddr;
+ continue;
+ }
+
+ /* Never return a connection that shouldn't be used for circs. */
+ if (channel_is_bad_for_new_circs(chan)) {
+ ++n_old;
+ continue;
+ }
+
+ /* Never return a non-canonical connection using a recent link protocol
+ * if the address is not what we wanted.
+ *
+ * The channel_is_canonical_is_reliable() function asks the lower layer
+ * if we should trust channel_is_canonical(). The below is from the
+ * comments of the old circuit_or_get_for_extend() and applies when
+ * the lower-layer transport is channel_tls_t.
+ *
+ * (For old link protocols, we can't rely on is_canonical getting
+ * set properly if we're talking to the right address, since we might
+ * have an out-of-date descriptor, and we will get no NETINFO cell to
+ * tell us about the right address.)
+ */
+ if (!channel_is_canonical(chan) &&
+ channel_is_canonical_is_reliable(chan) &&
+ !channel_matches_target_addr_for_extend(chan, target_addr)) {
+ ++n_noncanonical;
+ continue;
+ }
+
+ ++n_possible;
+
+ if (!best) {
+ best = chan; /* If we have no 'best' so far, this one is good enough. */
+ continue;
+ }
+
+ if (channel_is_better(now, chan, best, 0))
+ best = chan;
+ }
+
+ if (best) {
+ *msg_out = "Connection is fine; using it.";
+ *launch_out = 0;
+ return best;
+ } else if (n_inprogress_goodaddr) {
+ *msg_out = "Connection in progress; waiting.";
+ *launch_out = 0;
+ return NULL;
+ } else if (n_old || n_noncanonical) {
+ *msg_out = "Connections all too old, or too non-canonical. "
+ " Launching a new one.";
+ *launch_out = 1;
+ return NULL;
+ } else {
+ *msg_out = "Not connected. Connecting.";
+ *launch_out = 1;
+ return NULL;
+ }
+}
+
+/**
+ * Describe the transport subclass for a channel
+ *
+ * Invoke a method to get a string description of the lower-layer
+ * transport for this channel.
+ */
+
+const char *
+channel_describe_transport(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->describe_transport);
+
+ return chan->describe_transport(chan);
+}
+
+/**
+ * Describe the transport subclass for a channel listener
+ *
+ * Invoke a method to get a string description of the lower-layer
+ * transport for this channel listener.
+ */
+
+const char *
+channel_listener_describe_transport(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+ tor_assert(chan_l->describe_transport);
+
+ return chan_l->describe_transport(chan_l);
+}
+
+/**
+ * Return the number of entries in <b>queue</b>
+ */
+static int
+chan_cell_queue_len(const chan_cell_queue_t *queue)
+{
+ int r = 0;
+ cell_queue_entry_t *cell;
+ SIMPLEQ_FOREACH(cell, queue, next)
+ ++r;
+ return r;
+}
+
+/**
+ * Dump channel statistics
+ *
+ * Dump statistics for one channel to the log
+ */
+
+void
+channel_dump_statistics(channel_t *chan, int severity)
+{
+ double avg, interval, age;
+ time_t now = time(NULL);
+ tor_addr_t remote_addr;
+ int have_remote_addr;
+ char *remote_addr_str;
+
+ tor_assert(chan);
+
+ age = (double)(now - chan->timestamp_created);
+
+ log(severity, LD_GENERAL,
+ "Channel " U64_FORMAT " (at %p) with transport %s is in state "
+ "%s (%d)",
+ U64_PRINTF_ARG(chan->global_identifier), chan,
+ channel_describe_transport(chan),
+ channel_state_to_string(chan->state), chan->state);
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " was created at " U64_FORMAT
+ " (" U64_FORMAT " seconds ago) "
+ "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_created),
+ U64_PRINTF_ARG(now - chan->timestamp_created),
+ U64_PRINTF_ARG(chan->timestamp_active),
+ U64_PRINTF_ARG(now - chan->timestamp_active));
+
+ /* Handle digest and nickname */
+ if (!tor_digest_is_zero(chan->identity_digest)) {
+ if (chan->nickname) {
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " says it is connected "
+ "to an OR with digest %s and nickname %s",
+ U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN),
+ chan->nickname);
+ } else {
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " says it is connected "
+ "to an OR with digest %s and no known nickname",
+ U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN));
+ }
+ } else {
+ if (chan->nickname) {
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " does not know the digest"
+ " of the OR it is connected to, but reports its nickname is %s",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan->nickname);
+ } else {
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " does not know the digest"
+ " or the nickname of the OR it is connected to",
+ U64_PRINTF_ARG(chan->global_identifier));
+ }
+ }
+
+ /* Handle remote address and descriptions */
+ have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr);
+ if (have_remote_addr) {
+ char *actual = tor_strdup(channel_get_actual_remote_descr(chan));
+ remote_addr_str = tor_dup_addr(&remote_addr);
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " says its remote address"
+ " is %s, and gives a canonical description of \"%s\" and an "
+ "actual description of \"%s\"",
+ U64_PRINTF_ARG(chan->global_identifier),
+ remote_addr_str,
+ channel_get_canonical_remote_descr(chan),
+ actual);
+ tor_free(remote_addr_str);
+ tor_free(actual);
+ } else {
+ char *actual = tor_strdup(channel_get_actual_remote_descr(chan));
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " does not know its remote "
+ "address, but gives a canonical description of \"%s\" and an "
+ "actual description of \"%s\"",
+ U64_PRINTF_ARG(chan->global_identifier),
+ channel_get_canonical_remote_descr(chan),
+ actual);
+ tor_free(actual);
+ }
+
+ /* Handle marks */
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has these marks: %s %s %s "
+ "%s %s %s",
+ U64_PRINTF_ARG(chan->global_identifier),
+ channel_is_bad_for_new_circs(chan) ?
+ "bad_for_new_circs" : "!bad_for_new_circs",
+ channel_is_canonical(chan) ?
+ "canonical" : "!canonical",
+ channel_is_canonical_is_reliable(chan) ?
+ "is_canonical_is_reliable" :
+ "!is_canonical_is_reliable",
+ channel_is_client(chan) ?
+ "client" : "!client",
+ channel_is_local(chan) ?
+ "local" : "!local",
+ channel_is_incoming(chan) ?
+ "incoming" : "outgoing");
+
+ /* Describe queues */
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has %d queued incoming cells"
+ " and %d queued outgoing cells",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan_cell_queue_len(&chan->incoming_queue),
+ chan_cell_queue_len(&chan->outgoing_queue));
+
+ /* Describe circuits */
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has %d active circuits out of"
+ " %d in total",
+ U64_PRINTF_ARG(chan->global_identifier),
+ (chan->cmux != NULL) ?
+ circuitmux_num_active_circuits(chan->cmux) : 0,
+ (chan->cmux != NULL) ?
+ circuitmux_num_circuits(chan->cmux) : 0);
+
+ /* Describe timestamps */
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " was last used by a "
+ "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_client),
+ U64_PRINTF_ARG(now - chan->timestamp_client));
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " was last drained at "
+ U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_drained),
+ U64_PRINTF_ARG(now - chan->timestamp_drained));
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " last received a cell "
+ "at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_recv),
+ U64_PRINTF_ARG(now - chan->timestamp_recv));
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " last trasmitted a cell "
+ "at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_xmit),
+ U64_PRINTF_ARG(now - chan->timestamp_xmit));
+
+ /* Describe counters and rates */
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has received "
+ U64_FORMAT " cells and transmitted " U64_FORMAT,
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->n_cells_recved),
+ U64_PRINTF_ARG(chan->n_cells_xmitted));
+ if (now > chan->timestamp_created &&
+ chan->timestamp_created > 0) {
+ if (chan->n_cells_recved > 0) {
+ avg = (double)(chan->n_cells_recved) / age;
+ if (avg >= 1.0) {
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "cells received per second",
+ U64_PRINTF_ARG(chan->global_identifier), avg);
+ } else if (avg >= 0.0) {
+ interval = 1.0 / avg;
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "seconds between received cells",
+ U64_PRINTF_ARG(chan->global_identifier), interval);
+ }
+ }
+ if (chan->n_cells_xmitted > 0) {
+ avg = (double)(chan->n_cells_xmitted) / age;
+ if (avg >= 1.0) {
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "cells transmitted per second",
+ U64_PRINTF_ARG(chan->global_identifier), avg);
+ } else if (avg >= 0.0) {
+ interval = 1.0 / avg;
+ log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "seconds between transmitted cells",
+ U64_PRINTF_ARG(chan->global_identifier), interval);
+ }
+ }
+ }
+
+ /* Dump anything the lower layer has to say */
+ channel_dump_transport_statistics(chan, severity);
+}
+
+/**
+ * Dump channel listener statistics
+ *
+ * Dump statistics for one channel listener to the log
+ */
+
+void
+channel_listener_dump_statistics(channel_listener_t *chan_l, int severity)
+{
+ double avg, interval, age;
+ time_t now = time(NULL);
+
+ tor_assert(chan_l);
+
+ age = (double)(now - chan_l->timestamp_created);
+
+ log(severity, LD_GENERAL,
+ "Channel listener " U64_FORMAT " (at %p) with transport %s is in "
+ "state %s (%d)",
+ U64_PRINTF_ARG(chan_l->global_identifier), chan_l,
+ channel_listener_describe_transport(chan_l),
+ channel_listener_state_to_string(chan_l->state), chan_l->state);
+ log(severity, LD_GENERAL,
+ " * Channel listener " U64_FORMAT " was created at " U64_FORMAT
+ " (" U64_FORMAT " seconds ago) "
+ "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan_l->global_identifier),
+ U64_PRINTF_ARG(chan_l->timestamp_created),
+ U64_PRINTF_ARG(now - chan_l->timestamp_created),
+ U64_PRINTF_ARG(chan_l->timestamp_active),
+ U64_PRINTF_ARG(now - chan_l->timestamp_active));
+
+ log(severity, LD_GENERAL,
+ " * Channel listener " U64_FORMAT " last accepted an incoming "
+ "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) "
+ "and has accepted " U64_FORMAT " channels in total",
+ U64_PRINTF_ARG(chan_l->global_identifier),
+ U64_PRINTF_ARG(chan_l->timestamp_accepted),
+ U64_PRINTF_ARG(now - chan_l->timestamp_accepted),
+ U64_PRINTF_ARG(chan_l->n_accepted));
+
+ /*
+ * If it's sensible to do so, get the rate of incoming channels on this
+ * listener
+ */
+ if (now > chan_l->timestamp_created &&
+ chan_l->timestamp_created > 0 &&
+ chan_l->n_accepted > 0) {
+ avg = (double)(chan_l->n_accepted) / age;
+ if (avg >= 1.0) {
+ log(severity, LD_GENERAL,
+ " * Channel listener " U64_FORMAT " has averaged %f incoming "
+ "channels per second",
+ U64_PRINTF_ARG(chan_l->global_identifier), avg);
+ } else if (avg >= 0.0) {
+ interval = 1.0 / avg;
+ log(severity, LD_GENERAL,
+ " * Channel listener " U64_FORMAT " has averaged %f seconds "
+ "between incoming channels",
+ U64_PRINTF_ARG(chan_l->global_identifier), interval);
+ }
+ }
+
+ /* Dump anything the lower layer has to say */
+ channel_listener_dump_transport_statistics(chan_l, severity);
+}
+
+/**
+ * Invoke transport-specific stats dump for channel
+ *
+ * If there is a lower-layer statistics dump method, invoke it
+ */
+
+void
+channel_dump_transport_statistics(channel_t *chan, int severity)
+{
+ tor_assert(chan);
+
+ if (chan->dumpstats) chan->dumpstats(chan, severity);
+}
+
+/**
+ * Invoke transport-specific stats dump for channel listener
+ *
+ * If there is a lower-layer statistics dump method, invoke it
+ */
+
+void
+channel_listener_dump_transport_statistics(channel_listener_t *chan_l,
+ int severity)
+{
+ tor_assert(chan_l);
+
+ if (chan_l->dumpstats) chan_l->dumpstats(chan_l, severity);
+}
+
+/**
+ * Return text description of the remote endpoint
+ *
+ * This function return a test provided by the lower layer of the remote
+ * endpoint for this channel; it should specify the actual address connected
+ * to/from.
+ *
+ * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
+ * may invalidate the return value from this function.
+ */
+const char *
+channel_get_actual_remote_descr(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->get_remote_descr);
+
+ /* Param 1 indicates the actual description */
+ return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL);
+}
+
+/**
+ * Return the text address of the remote endpoint.
+ *
+ * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
+ * may invalidate the return value from this function.
+ */
+const char *
+channel_get_actual_remote_address(channel_t *chan)
+{
+ /* Param 1 indicates the actual description */
+ return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY);
+}
+
+/**
+ * Return text description of the remote endpoint canonical address
+ *
+ * This function return a test provided by the lower layer of the remote
+ * endpoint for this channel; it should use the known canonical address for
+ * this OR's identity digest if possible.
+ *
+ * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
+ * may invalidate the return value from this function.
+ */
+const char *
+channel_get_canonical_remote_descr(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->get_remote_descr);
+
+ /* Param 0 indicates the canonicalized description */
+ return chan->get_remote_descr(chan, 0);
+}
+
+/**
+ * Get remote address if possible.
+ *
+ * Write the remote address out to a tor_addr_t if the underlying transport
+ * supports this operation, and return 1. Return 0 if the underlying transport
+ * doesn't let us do this.
+ */
+int
+channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out)
+{
+ tor_assert(chan);
+ tor_assert(addr_out);
+
+ if (chan->get_remote_addr)
+ return chan->get_remote_addr(chan, addr_out);
+ /* Else no support, method not implemented */
+ else return 0;
+}
+
+/**
+ * Check if there are outgoing queue writes on this channel
+ *
+ * Indicate if either we have queued cells, or if not, whether the underlying
+ * lower-layer transport thinks it has an output queue.
+ */
+
+int
+channel_has_queued_writes(channel_t *chan)
+{
+ int has_writes = 0;
+
+ tor_assert(chan);
+ tor_assert(chan->has_queued_writes);
+
+ if (! SIMPLEQ_EMPTY(&chan->outgoing_queue)) {
+ has_writes = 1;
+ } else {
+ /* Check with the lower layer */
+ has_writes = chan->has_queued_writes(chan);
+ }
+
+ return has_writes;
+}
+
+/**
+ * Check the is_bad_for_new_circs flag
+ *
+ * This function returns the is_bad_for_new_circs flag of the specified
+ * channel.
+ */
+
+int
+channel_is_bad_for_new_circs(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->is_bad_for_new_circs;
+}
+
+/**
+ * Mark a channel as bad for new circuits
+ *
+ * Set the is_bad_for_new_circs_flag on chan.
+ */
+
+void
+channel_mark_bad_for_new_circs(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_bad_for_new_circs = 1;
+}
+
+/**
+ * Get the client flag
+ *
+ * This returns the client flag of a channel, which will be set if
+ * command_process_create_cell() in command.c thinks this is a connection
+ * from a client.
+ */
+
+int
+channel_is_client(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->is_client;
+}
+
+/**
+ * Set the client flag
+ *
+ * Mark a channel as being from a client
+ */
+
+void
+channel_mark_client(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_client = 1;
+}
+
+/**
+ * Get the canonical flag for a channel
+ *
+ * This returns the is_canonical for a channel; this flag is determined by
+ * the lower layer and can't be set in a transport-independent way.
+ */
+
+int
+channel_is_canonical(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->is_canonical);
+
+ return chan->is_canonical(chan, 0);
+}
+
+/**
+ * Test if the canonical flag is reliable
+ *
+ * This function asks if the lower layer thinks it's safe to trust the
+ * result of channel_is_canonical()
+ */
+
+int
+channel_is_canonical_is_reliable(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->is_canonical);
+
+ return chan->is_canonical(chan, 1);
+}
+
+/**
+ * Test incoming flag
+ *
+ * This function gets the incoming flag; this is set when a listener spawns
+ * a channel. If this returns true the channel was remotely initiated.
+ */
+
+int
+channel_is_incoming(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->is_incoming;
+}
+
+/**
+ * Set the incoming flag
+ *
+ * This function is called when a channel arrives on a listening channel
+ * to mark it as incoming.
+ */
+
+void
+channel_mark_incoming(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_incoming = 1;
+}
+
+/**
+ * Test local flag
+ *
+ * This function gets the local flag; the lower layer should set this when
+ * setting up the channel if is_local_addr() is true for all of the
+ * destinations it will communicate with on behalf of this channel. It's
+ * used to decide whether to declare the network reachable when seeing incoming
+ * traffic on the channel.
+ */
+
+int
+channel_is_local(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->is_local;
+}
+
+/**
+ * Set the local flag
+ *
+ * This internal-only function should be called by the lower layer if the
+ * channel is to a local address. See channel_is_local() above or the
+ * description of the is_local bit in channel.h
+ */
+
+void
+channel_mark_local(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_local = 1;
+}
+
+/**
+ * Test outgoing flag
+ *
+ * This function gets the outgoing flag; this is the inverse of the incoming
+ * bit set when a listener spawns a channel. If this returns true the channel
+ * was locally initiated.
+ */
+
+int
+channel_is_outgoing(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return !(chan->is_incoming);
+}
+
+/**
+ * Mark a channel as outgoing
+ *
+ * This function clears the incoming flag and thus marks a channel as
+ * outgoing.
+ */
+
+void
+channel_mark_outgoing(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_incoming = 0;
+}
+
+/*********************
+ * Timestamp updates *
+ ********************/
+
+/**
+ * Update the created timestamp for a channel
+ *
+ * This updates the channel's created timestamp and should only be called
+ * from channel_init().
+ */
+
+void
+channel_timestamp_created(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_created = now;
+}
+
+/**
+ * Update the created timestamp for a channel listener
+ *
+ * This updates the channel listener's created timestamp and should only be
+ * called from channel_init_listener().
+ */
+
+void
+channel_listener_timestamp_created(channel_listener_t *chan_l)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan_l);
+
+ chan_l->timestamp_created = now;
+}
+
+/**
+ * Update the last active timestamp for a channel
+ *
+ * This function updates the channel's last active timestamp; it should be
+ * called by the lower layer whenever there is activity on the channel which
+ * does not lead to a cell being transmitted or received; the active timestamp
+ * is also updated from channel_timestamp_recv() and channel_timestamp_xmit(),
+ * but it should be updated for things like the v3 handshake and stuff that
+ * produce activity only visible to the lower layer.
+ */
+
+void
+channel_timestamp_active(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_active = now;
+}
+
+/**
+ * Update the last active timestamp for a channel listener
+ */
+
+void
+channel_listener_timestamp_active(channel_listener_t *chan_l)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan_l);
+
+ chan_l->timestamp_active = now;
+}
+
+/**
+ * Update the last accepted timestamp.
+ *
+ * This function updates the channel listener's last accepted timestamp; it
+ * should be called whenever a new incoming channel is accepted on a
+ * listener.
+ */
+
+void
+channel_listener_timestamp_accepted(channel_listener_t *chan_l)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan_l);
+
+ chan_l->timestamp_active = now;
+ chan_l->timestamp_accepted = now;
+}
+
+/**
+ * Update client timestamp
+ *
+ * This function is called by relay.c to timestamp a channel that appears to
+ * be used as a client.
+ */
+
+void
+channel_timestamp_client(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_client = now;
+}
+
+/**
+ * Update the last drained timestamp
+ *
+ * This is called whenever we transmit a cell which leaves the outgoing cell
+ * queue completely empty. It also updates the xmit time and the active time.
+ */
+
+void
+channel_timestamp_drained(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_active = now;
+ chan->timestamp_drained = now;
+ chan->timestamp_xmit = now;
+}
+
+/**
+ * Update the recv timestamp
+ *
+ * This is called whenever we get an incoming cell from the lower layer.
+ * This also updates the active timestamp.
+ */
+
+void
+channel_timestamp_recv(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_active = now;
+ chan->timestamp_recv = now;
+}
+
+/**
+ * Update the xmit timestamp
+ * This is called whenever we pass an outgoing cell to the lower layer. This
+ * also updates the active timestamp.
+ */
+
+void
+channel_timestamp_xmit(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_active = now;
+ chan->timestamp_xmit = now;
+}
+
+/***************************************************************
+ * Timestamp queries - see above for definitions of timestamps *
+ **************************************************************/
+
+/**
+ * Query created timestamp for a channel
+ */
+
+time_t
+channel_when_created(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_created;
+}
+
+/**
+ * Query created timestamp for a channel listener
+ */
+
+time_t
+channel_listener_when_created(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return chan_l->timestamp_created;
+}
+
+/**
+ * Query last active timestamp for a channel
+ */
+
+time_t
+channel_when_last_active(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_active;
+}
+
+/**
+ * Query last active timestamp for a channel listener
+ */
+
+time_t
+channel_listener_when_last_active(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return chan_l->timestamp_active;
+}
+
+/**
+ * Query last accepted timestamp for a channel listener
+ */
+
+time_t
+channel_listener_when_last_accepted(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return chan_l->timestamp_accepted;
+}
+
+/**
+ * Query client timestamp
+ */
+
+time_t
+channel_when_last_client(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_client;
+}
+
+/**
+ * Query drained timestamp
+ */
+
+time_t
+channel_when_last_drained(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_drained;
+}
+
+/**
+ * Query recv timestamp
+ */
+
+time_t
+channel_when_last_recv(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_recv;
+}
+
+/**
+ * Query xmit timestamp
+ */
+
+time_t
+channel_when_last_xmit(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_xmit;
+}
+
+/**
+ * Query accepted counter
+ */
+
+uint64_t
+channel_listener_count_accepted(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return chan_l->n_accepted;
+}
+
+/**
+ * Query received cell counter
+ */
+
+uint64_t
+channel_count_recved(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->n_cells_recved;
+}
+
+/**
+ * Query transmitted cell counter
+ */
+
+uint64_t
+channel_count_xmitted(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->n_cells_xmitted;
+}
+
+/**
+ * Check if a channel matches an extend_info_t
+ *
+ * This function calls the lower layer and asks if this channel matches a
+ * given extend_info_t.
+ */
+
+int
+channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
+{
+ tor_assert(chan);
+ tor_assert(chan->matches_extend_info);
+ tor_assert(extend_info);
+
+ return chan->matches_extend_info(chan, extend_info);
+}
+
+/**
+ * Check if a channel matches a given target address
+ *
+ * This function calls into the lower layer and asks if this channel thinks
+ * it matches a given target address for circuit extension purposes.
+ */
+
+int
+channel_matches_target_addr_for_extend(channel_t *chan,
+ const tor_addr_t *target)
+{
+ tor_assert(chan);
+ tor_assert(chan->matches_target);
+ tor_assert(target);
+
+ return chan->matches_target(chan, target);
+}
+
+/**
+ * Return the total number of circuits used by a channel
+ *
+ * @param chan Channel to query
+ * @return Number of circuits using this as n_chan or p_chan
+ */
+
+unsigned int
+channel_num_circuits(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->num_n_circuits +
+ chan->num_p_circuits;
+}
+
+/**
+ * Set up circuit ID generation
+ *
+ * This is called when setting up a channel and replaces the old
+ * connection_or_set_circid_type()
+ */
+
+void
+channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd)
+{
+ int started_here;
+ crypto_pk_t *our_identity;
+
+ tor_assert(chan);
+
+ started_here = channel_is_outgoing(chan);
+ our_identity = started_here ?
+ get_tlsclient_identity_key() : get_server_identity_key();
+
+ if (identity_rcvd) {
+ if (crypto_pk_cmp_keys(our_identity, identity_rcvd) < 0) {
+ chan->circ_id_type = CIRC_ID_TYPE_LOWER;
+ } else {
+ chan->circ_id_type = CIRC_ID_TYPE_HIGHER;
+ }
+ } else {
+ chan->circ_id_type = CIRC_ID_TYPE_NEITHER;
+ }
+}
+
diff --git a/src/or/channel.h b/src/or/channel.h
new file mode 100644
index 0000000000..d2106551aa
--- /dev/null
+++ b/src/or/channel.h
@@ -0,0 +1,478 @@
+/* * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file channel.h
+ * \brief Header file for channel.c
+ **/
+
+#ifndef TOR_CHANNEL_H
+#define TOR_CHANNEL_H
+
+#include "or.h"
+#include "tor_queue.h"
+#include "circuitmux.h"
+
+/* Channel handler function pointer typedefs */
+typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *);
+typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *);
+typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *);
+
+struct cell_queue_entry_s;
+SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue;
+typedef struct chan_cell_queue chan_cell_queue_t;
+
+/*
+ * Channel struct; see the channel_t typedef in or.h. A channel is an
+ * abstract interface for the OR-to-OR connection, similar to connection_or_t,
+ * but without the strong coupling to the underlying TLS implementation. They
+ * are constructed by calling a protocol-specific function to open a channel
+ * to a particular node, and once constructed support the abstract operations
+ * defined below.
+ */
+
+struct channel_s {
+ /* Magic number for type-checking cast macros */
+ uint32_t magic;
+
+ /* Current channel state */
+ channel_state_t state;
+
+ /* Globally unique ID number for a channel over the lifetime of a Tor
+ * process.
+ */
+ uint64_t global_identifier;
+
+ /* Should we expect to see this channel in the channel lists? */
+ unsigned char registered:1;
+
+ /** Why did we close?
+ */
+ enum {
+ CHANNEL_NOT_CLOSING = 0,
+ CHANNEL_CLOSE_REQUESTED,
+ CHANNEL_CLOSE_FROM_BELOW,
+ CHANNEL_CLOSE_FOR_ERROR
+ } reason_for_closing;
+
+ /* Timestamps for both cell channels and listeners */
+ time_t timestamp_created; /* Channel created */
+ time_t timestamp_active; /* Any activity */
+
+ /* Methods implemented by the lower layer */
+
+ /* Free a channel */
+ void (*free)(channel_t *);
+ /* Close an open channel */
+ void (*close)(channel_t *);
+ /* Describe the transport subclass for this channel */
+ const char * (*describe_transport)(channel_t *);
+ /* Optional method to dump transport-specific statistics on the channel */
+ void (*dumpstats)(channel_t *, int);
+
+ /* Registered handlers for incoming cells */
+ channel_cell_handler_fn_ptr cell_handler;
+ channel_var_cell_handler_fn_ptr var_cell_handler;
+
+ /* Methods implemented by the lower layer */
+
+ /*
+ * Ask the underlying transport what the remote endpoint address is, in
+ * a tor_addr_t. This is optional and subclasses may leave this NULL.
+ * If they implement it, they should write the address out to the
+ * provided tor_addr_t *, and return 1 if successful or 0 if no address
+ * available.
+ */
+ int (*get_remote_addr)(channel_t *, tor_addr_t *);
+#define GRD_FLAG_ORIGINAL 1
+#define GRD_FLAG_ADDR_ONLY 2
+ /*
+ * Get a text description of the remote endpoint; canonicalized if the flag
+ * GRD_FLAG_ORIGINAL is not set, or the one we originally connected
+ * to/received from if it is. If GRD_FLAG_ADDR_ONLY is set, we return only
+ * the original address.
+ */
+ const char * (*get_remote_descr)(channel_t *, int);
+ /* Check if the lower layer has queued writes */
+ int (*has_queued_writes)(channel_t *);
+ /*
+ * If the second param is zero, ask the lower layer if this is
+ * 'canonical', for a transport-specific definition of canonical; if
+ * it is 1, ask if the answer to the preceding query is safe to rely
+ * on.
+ */
+ int (*is_canonical)(channel_t *, int);
+ /* Check if this channel matches a specified extend_info_t */
+ int (*matches_extend_info)(channel_t *, extend_info_t *);
+ /* Check if this channel matches a target address when extending */
+ int (*matches_target)(channel_t *, const tor_addr_t *);
+ /* Write a cell to an open channel */
+ int (*write_cell)(channel_t *, cell_t *);
+ /* Write a packed cell to an open channel */
+ int (*write_packed_cell)(channel_t *, packed_cell_t *);
+ /* Write a variable-length cell to an open channel */
+ int (*write_var_cell)(channel_t *, var_cell_t *);
+
+ /*
+ * Hash of the public RSA key for the other side's identity key, or
+ * zeroes if the other side hasn't shown us a valid identity key.
+ */
+ char identity_digest[DIGEST_LEN];
+ /* Nickname of the OR on the other side, or NULL if none. */
+ char *nickname;
+
+ /*
+ * Linked list of channels with the same identity digest, for the
+ * digest->channel map
+ */
+ LIST_ENTRY(channel_s) next_with_same_id;
+
+ /* List of incoming cells to handle */
+ chan_cell_queue_t incoming_queue;
+
+ /* List of queued outgoing cells */
+ chan_cell_queue_t outgoing_queue;
+
+ /* Circuit mux for circuits sending on this channel */
+ circuitmux_t *cmux;
+
+ /* Circuit ID generation stuff for use by circuitbuild.c */
+
+ /*
+ * When we send CREATE cells along this connection, which half of the
+ * space should we use?
+ */
+ circ_id_type_t circ_id_type:2;
+ /*
+ * Which circ_id do we try to use next on this connection? This is
+ * always in the range 0..1<<15-1.
+ */
+ circid_t next_circ_id;
+
+ /* For how many circuits are we n_chan? What about p_chan? */
+ unsigned int num_n_circuits, num_p_circuits;
+
+ /*
+ * True iff this channel shouldn't get any new circs attached to it,
+ * because the connection is too old, or because there's a better one.
+ * More generally, this flag is used to note an unhealthy connection;
+ * for example, if a bad connection fails we shouldn't assume that the
+ * router itself has a problem.
+ */
+ unsigned int is_bad_for_new_circs:1;
+
+ /** True iff we have decided that the other end of this connection
+ * is a client. Channels with this flag set should never be used
+ * to satisfy an EXTEND request. */
+ unsigned int is_client:1;
+
+ /** Set if the channel was initiated remotely (came from a listener) */
+ unsigned int is_incoming:1;
+
+ /** Set by lower layer if this is local; i.e., everything it communicates
+ * with for this channel returns true for is_local_addr(). This is used
+ * to decide whether to declare reachability when we receive something on
+ * this channel in circuitbuild.c
+ */
+ unsigned int is_local:1;
+
+ /** Channel timestamps for cell channels */
+ time_t timestamp_client; /* Client used this, according to relay.c */
+ time_t timestamp_drained; /* Output queue empty */
+ time_t timestamp_recv; /* Cell received from lower layer */
+ time_t timestamp_xmit; /* Cell sent to lower layer */
+
+ /* Timestamp for relay.c */
+ time_t timestamp_last_added_nonpadding;
+
+ /** Unique ID for measuring direct network status requests;vtunneled ones
+ * come over a circuit_t, which has a dirreq_id field as well, but is a
+ * distinct namespace. */
+ uint64_t dirreq_id;
+
+ /** Channel counters for cell channels */
+ uint64_t n_cells_recved;
+ uint64_t n_cells_xmitted;
+};
+
+struct channel_listener_s {
+ /* Current channel listener state */
+ channel_listener_state_t state;
+
+ /* Globally unique ID number for a channel over the lifetime of a Tor
+ * process.
+ */
+ uint64_t global_identifier;
+
+ /* Should we expect to see this channel in the channel lists? */
+ unsigned char registered:1;
+
+ /** Why did we close?
+ */
+ enum {
+ CHANNEL_LISTENER_NOT_CLOSING = 0,
+ CHANNEL_LISTENER_CLOSE_REQUESTED,
+ CHANNEL_LISTENER_CLOSE_FROM_BELOW,
+ CHANNEL_LISTENER_CLOSE_FOR_ERROR
+ } reason_for_closing;
+
+ /* Timestamps for both cell channels and listeners */
+ time_t timestamp_created; /* Channel created */
+ time_t timestamp_active; /* Any activity */
+
+ /* Methods implemented by the lower layer */
+
+ /* Free a channel */
+ void (*free)(channel_listener_t *);
+ /* Close an open channel */
+ void (*close)(channel_listener_t *);
+ /* Describe the transport subclass for this channel */
+ const char * (*describe_transport)(channel_listener_t *);
+ /* Optional method to dump transport-specific statistics on the channel */
+ void (*dumpstats)(channel_listener_t *, int);
+
+ /* Registered listen handler to call on incoming connection */
+ channel_listener_fn_ptr listener;
+
+ /* List of pending incoming connections */
+ smartlist_t *incoming_list;
+
+ /* Timestamps for listeners */
+ time_t timestamp_accepted;
+
+ /* Counters for listeners */
+ uint64_t n_accepted;
+};
+
+/* Channel state manipulations */
+
+int channel_state_is_valid(channel_state_t state);
+int channel_listener_state_is_valid(channel_listener_state_t state);
+
+int channel_state_can_transition(channel_state_t from, channel_state_t to);
+int channel_listener_state_can_transition(channel_listener_state_t from,
+ channel_listener_state_t to);
+
+const char * channel_state_to_string(channel_state_t state);
+const char *
+channel_listener_state_to_string(channel_listener_state_t state);
+
+/* Abstract channel operations */
+
+void channel_mark_for_close(channel_t *chan);
+void channel_write_cell(channel_t *chan, cell_t *cell);
+void channel_write_packed_cell(channel_t *chan, packed_cell_t *cell);
+void channel_write_var_cell(channel_t *chan, var_cell_t *cell);
+
+void channel_listener_mark_for_close(channel_listener_t *chan_l);
+
+/* Channel callback registrations */
+
+/* Listener callback */
+channel_listener_fn_ptr
+channel_listener_get_listener_fn(channel_listener_t *chan);
+
+void channel_listener_set_listener_fn(channel_listener_t *chan,
+ channel_listener_fn_ptr listener);
+
+/* Incoming cell callbacks */
+channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan);
+
+channel_var_cell_handler_fn_ptr
+channel_get_var_cell_handler(channel_t *chan);
+
+void channel_set_cell_handlers(channel_t *chan,
+ channel_cell_handler_fn_ptr cell_handler,
+ channel_var_cell_handler_fn_ptr
+ var_cell_handler);
+
+/* Clean up closed channels and channel listeners periodically; these are
+ * called from run_scheduled_events() in main.c.
+ */
+void channel_run_cleanup(void);
+void channel_listener_run_cleanup(void);
+
+/* Close all channels and deallocate everything */
+void channel_free_all(void);
+
+/* Dump some statistics in the log */
+void channel_dumpstats(int severity);
+void channel_listener_dumpstats(int severity);
+
+/* Set the cmux policy on all active channels */
+void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol);
+
+#ifdef TOR_CHANNEL_INTERNAL_
+
+/* Channel operations for subclasses and internal use only */
+
+/* Initialize a newly allocated channel - do this first in subclass
+ * constructors.
+ */
+
+void channel_init(channel_t *chan);
+void channel_init_listener(channel_listener_t *chan);
+
+/* Channel registration/unregistration */
+void channel_register(channel_t *chan);
+void channel_unregister(channel_t *chan);
+
+/* Channel listener registration/unregistration */
+void channel_listener_register(channel_listener_t *chan_l);
+void channel_listener_unregister(channel_listener_t *chan_l);
+
+/* Close from below */
+void channel_close_from_lower_layer(channel_t *chan);
+void channel_close_for_error(channel_t *chan);
+void channel_closed(channel_t *chan);
+
+void channel_listener_close_from_lower_layer(channel_listener_t *chan_l);
+void channel_listener_close_for_error(channel_listener_t *chan_l);
+void channel_listener_closed(channel_listener_t *chan_l);
+
+/* Free a channel */
+void channel_free(channel_t *chan);
+void channel_listener_free(channel_listener_t *chan_l);
+
+/* State/metadata setters */
+
+void channel_change_state(channel_t *chan, channel_state_t to_state);
+void channel_clear_identity_digest(channel_t *chan);
+void channel_clear_remote_end(channel_t *chan);
+void channel_mark_local(channel_t *chan);
+void channel_mark_incoming(channel_t *chan);
+void channel_mark_outgoing(channel_t *chan);
+void channel_set_identity_digest(channel_t *chan,
+ const char *identity_digest);
+void channel_set_remote_end(channel_t *chan,
+ const char *identity_digest,
+ const char *nickname);
+
+void channel_listener_change_state(channel_listener_t *chan_l,
+ channel_listener_state_t to_state);
+
+/* Timestamp updates */
+void channel_timestamp_created(channel_t *chan);
+void channel_timestamp_active(channel_t *chan);
+void channel_timestamp_drained(channel_t *chan);
+void channel_timestamp_recv(channel_t *chan);
+void channel_timestamp_xmit(channel_t *chan);
+
+void channel_listener_timestamp_created(channel_listener_t *chan_l);
+void channel_listener_timestamp_active(channel_listener_t *chan_l);
+void channel_listener_timestamp_accepted(channel_listener_t *chan_l);
+
+/* Incoming channel handling */
+void channel_listener_process_incoming(channel_listener_t *listener);
+void channel_listener_queue_incoming(channel_listener_t *listener,
+ channel_t *incoming);
+
+/* Incoming cell handling */
+void channel_process_cells(channel_t *chan);
+void channel_queue_cell(channel_t *chan, cell_t *cell);
+void channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell);
+
+/* Outgoing cell handling */
+void channel_flush_cells(channel_t *chan);
+
+/* Request from lower layer for more cells if available */
+ssize_t channel_flush_some_cells(channel_t *chan, ssize_t num_cells);
+
+/* Query if data available on this channel */
+int channel_more_to_flush(channel_t *chan);
+
+/* Notify flushed outgoing for dirreq handling */
+void channel_notify_flushed(channel_t *chan);
+
+/* Handle stuff we need to do on open like notifying circuits */
+void channel_do_open_actions(channel_t *chan);
+
+#endif
+
+/* Helper functions to perform operations on channels */
+
+int channel_send_destroy(circid_t circ_id, channel_t *chan,
+ int reason);
+
+/*
+ * Outside abstract interfaces that should eventually get turned into
+ * something transport/address format independent.
+ */
+
+channel_t * channel_connect(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest);
+
+channel_t * channel_get_for_extend(const char *digest,
+ const tor_addr_t *target_addr,
+ const char **msg_out,
+ int *launch_out);
+
+/* Ask which of two channels is better for circuit-extension purposes */
+int channel_is_better(time_t now,
+ channel_t *a, channel_t *b,
+ int forgive_new_connections);
+
+/** Channel lookups
+ */
+
+channel_t * channel_find_by_global_id(uint64_t global_identifier);
+channel_t * channel_find_by_remote_digest(const char *identity_digest);
+
+/** For things returned by channel_find_by_remote_digest(), walk the list.
+ */
+channel_t * channel_next_with_digest(channel_t *chan);
+
+/*
+ * Metadata queries/updates
+ */
+
+const char * channel_describe_transport(channel_t *chan);
+void channel_dump_statistics(channel_t *chan, int severity);
+void channel_dump_transport_statistics(channel_t *chan, int severity);
+const char * channel_get_actual_remote_descr(channel_t *chan);
+const char * channel_get_actual_remote_address(channel_t *chan);
+int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out);
+const char * channel_get_canonical_remote_descr(channel_t *chan);
+int channel_has_queued_writes(channel_t *chan);
+int channel_is_bad_for_new_circs(channel_t *chan);
+void channel_mark_bad_for_new_circs(channel_t *chan);
+int channel_is_canonical(channel_t *chan);
+int channel_is_canonical_is_reliable(channel_t *chan);
+int channel_is_client(channel_t *chan);
+int channel_is_local(channel_t *chan);
+int channel_is_incoming(channel_t *chan);
+int channel_is_outgoing(channel_t *chan);
+void channel_mark_client(channel_t *chan);
+int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info);
+int channel_matches_target_addr_for_extend(channel_t *chan,
+ const tor_addr_t *target);
+unsigned int channel_num_circuits(channel_t *chan);
+void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd);
+void channel_timestamp_client(channel_t *chan);
+
+const char * channel_listener_describe_transport(channel_listener_t *chan_l);
+void channel_listener_dump_statistics(channel_listener_t *chan_l,
+ int severity);
+void channel_listener_dump_transport_statistics(channel_listener_t *chan_l,
+ int severity);
+
+/* Timestamp queries */
+time_t channel_when_created(channel_t *chan);
+time_t channel_when_last_active(channel_t *chan);
+time_t channel_when_last_client(channel_t *chan);
+time_t channel_when_last_drained(channel_t *chan);
+time_t channel_when_last_recv(channel_t *chan);
+time_t channel_when_last_xmit(channel_t *chan);
+
+time_t channel_listener_when_created(channel_listener_t *chan_l);
+time_t channel_listener_when_last_active(channel_listener_t *chan_l);
+time_t channel_listener_when_last_accepted(channel_listener_t *chan_l);
+
+/* Counter queries */
+uint64_t channel_count_recved(channel_t *chan);
+uint64_t channel_count_xmitted(channel_t *chan);
+
+uint64_t channel_listener_count_accepted(channel_listener_t *chan_l);
+
+#endif
+
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
new file mode 100644
index 0000000000..ede245894e
--- /dev/null
+++ b/src/or/channeltls.c
@@ -0,0 +1,1932 @@
+/* * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file channeltls.c
+ * \brief channel_t concrete subclass using or_connection_t
+ **/
+
+/*
+ * Define this so channel.h gives us things only channel_t subclasses
+ * should touch.
+ */
+
+#define TOR_CHANNEL_INTERNAL_
+
+#include "or.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "circuitmux.h"
+#include "circuitmux_ewma.h"
+#include "config.h"
+#include "connection.h"
+#include "connection_or.h"
+#include "control.h"
+#include "relay.h"
+#include "router.h"
+#include "routerlist.h"
+
+/** How many CELL_PADDING cells have we received, ever? */
+uint64_t stats_n_padding_cells_processed = 0;
+/** How many CELL_VERSIONS cells have we received, ever? */
+uint64_t stats_n_versions_cells_processed = 0;
+/** How many CELL_NETINFO cells have we received, ever? */
+uint64_t stats_n_netinfo_cells_processed = 0;
+/** How many CELL_VPADDING cells have we received, ever? */
+uint64_t stats_n_vpadding_cells_processed = 0;
+/** How many CELL_CERTS cells have we received, ever? */
+uint64_t stats_n_certs_cells_processed = 0;
+/** How many CELL_AUTH_CHALLENGE cells have we received, ever? */
+uint64_t stats_n_auth_challenge_cells_processed = 0;
+/** How many CELL_AUTHENTICATE cells have we received, ever? */
+uint64_t stats_n_authenticate_cells_processed = 0;
+/** How many CELL_AUTHORIZE cells have we received, ever? */
+uint64_t stats_n_authorize_cells_processed = 0;
+
+/** Active listener, if any */
+channel_listener_t *channel_tls_listener = NULL;
+
+/* Utility function declarations */
+static void channel_tls_common_init(channel_tls_t *tlschan);
+
+/* channel_tls_t method declarations */
+
+static void channel_tls_close_method(channel_t *chan);
+static const char * channel_tls_describe_transport_method(channel_t *chan);
+static int
+channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out);
+static const char *
+channel_tls_get_remote_descr_method(channel_t *chan, int flags);
+static int channel_tls_has_queued_writes_method(channel_t *chan);
+static int channel_tls_is_canonical_method(channel_t *chan, int req);
+static int
+channel_tls_matches_extend_info_method(channel_t *chan,
+ extend_info_t *extend_info);
+static int channel_tls_matches_target_method(channel_t *chan,
+ const tor_addr_t *target);
+static int channel_tls_write_cell_method(channel_t *chan,
+ cell_t *cell);
+static int channel_tls_write_packed_cell_method(channel_t *chan,
+ packed_cell_t *packed_cell);
+static int channel_tls_write_var_cell_method(channel_t *chan,
+ var_cell_t *var_cell);
+
+/* channel_listener_tls_t method declarations */
+
+static void channel_tls_listener_close_method(channel_listener_t *chan_l);
+static const char *
+channel_tls_listener_describe_transport_method(channel_listener_t *chan_l);
+
+/** Handle incoming cells for the handshake stuff here rather than
+ * passing them on up. */
+
+static void channel_tls_process_versions_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+static void channel_tls_process_netinfo_cell(cell_t *cell,
+ channel_tls_t *tlschan);
+static void channel_tls_process_certs_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+static void channel_tls_process_auth_challenge_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+static void channel_tls_process_authenticate_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+static int command_allowed_before_handshake(uint8_t command);
+static int enter_v3_handshake_with_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+
+/**
+ * Do parts of channel_tls_t initialization common to channel_tls_connect()
+ * and channel_tls_handle_incoming().
+ */
+
+static void
+channel_tls_common_init(channel_tls_t *tlschan)
+{
+ channel_t *chan;
+
+ tor_assert(tlschan);
+
+ chan = &(tlschan->base_);
+ channel_init(chan);
+ chan->magic = TLS_CHAN_MAGIC;
+ chan->state = CHANNEL_STATE_OPENING;
+ chan->close = channel_tls_close_method;
+ chan->describe_transport = channel_tls_describe_transport_method;
+ chan->get_remote_addr = channel_tls_get_remote_addr_method;
+ chan->get_remote_descr = channel_tls_get_remote_descr_method;
+ chan->has_queued_writes = channel_tls_has_queued_writes_method;
+ chan->is_canonical = channel_tls_is_canonical_method;
+ chan->matches_extend_info = channel_tls_matches_extend_info_method;
+ chan->matches_target = channel_tls_matches_target_method;
+ chan->write_cell = channel_tls_write_cell_method;
+ chan->write_packed_cell = channel_tls_write_packed_cell_method;
+ chan->write_var_cell = channel_tls_write_var_cell_method;
+
+ chan->cmux = circuitmux_alloc();
+ if (cell_ewma_enabled()) {
+ circuitmux_set_policy(chan->cmux, &ewma_policy);
+ }
+}
+
+/**
+ * Start a new TLS channel
+ *
+ * Launch a new OR connection to <b>addr</b>:<b>port</b> and expect to
+ * handshake with an OR with identity digest <b>id_digest</b>, and wrap
+ * it in a channel_tls_t.
+ */
+
+channel_t *
+channel_tls_connect(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest)
+{
+ channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan));
+ channel_t *chan = &(tlschan->base_);
+
+ channel_tls_common_init(tlschan);
+
+ log_debug(LD_CHANNEL,
+ "In channel_tls_connect() for channel %p "
+ "(global id " U64_FORMAT ")",
+ tlschan,
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ if (is_local_addr(addr)) channel_mark_local(chan);
+ channel_mark_outgoing(chan);
+
+ /* Set up or_connection stuff */
+ tlschan->conn = connection_or_connect(addr, port, id_digest, tlschan);
+ /* connection_or_connect() will fill in tlschan->conn */
+ if (!(tlschan->conn)) {
+ chan->reason_for_closing = CHANNEL_CLOSE_FOR_ERROR;
+ channel_change_state(chan, CHANNEL_STATE_ERROR);
+ goto err;
+ }
+
+ log_debug(LD_CHANNEL,
+ "Got orconn %p for channel with global id " U64_FORMAT,
+ tlschan->conn, U64_PRINTF_ARG(chan->global_identifier));
+
+ goto done;
+
+ err:
+ circuitmux_free(chan->cmux);
+ tor_free(tlschan);
+ chan = NULL;
+
+ done:
+ /* If we got one, we should register it */
+ if (chan) channel_register(chan);
+
+ return chan;
+}
+
+/**
+ * Return the current channel_tls_t listener
+ *
+ * Returns the current channel listener for incoming TLS connections, or
+ * NULL if none has been established
+ */
+
+channel_listener_t *
+channel_tls_get_listener(void)
+{
+ return channel_tls_listener;
+}
+
+/**
+ * Start a channel_tls_t listener if necessary
+ *
+ * Return the current channel_tls_t listener, or start one if we haven't yet,
+ * and return that.
+ */
+
+channel_listener_t *
+channel_tls_start_listener(void)
+{
+ channel_listener_t *listener;
+
+ if (!channel_tls_listener) {
+ listener = tor_malloc_zero(sizeof(*listener));
+ channel_init_listener(listener);
+ listener->state = CHANNEL_LISTENER_STATE_LISTENING;
+ listener->close = channel_tls_listener_close_method;
+ listener->describe_transport =
+ channel_tls_listener_describe_transport_method;
+
+ channel_tls_listener = listener;
+
+ log_debug(LD_CHANNEL,
+ "Starting TLS channel listener %p with global id " U64_FORMAT,
+ listener, U64_PRINTF_ARG(listener->global_identifier));
+
+ channel_listener_register(listener);
+ } else listener = channel_tls_listener;
+
+ return listener;
+}
+
+/**
+ * Free everything on shutdown
+ *
+ * Not much to do here, since channel_free_all() takes care of a lot, but let's
+ * get rid of the listener.
+ */
+
+void
+channel_tls_free_all(void)
+{
+ channel_listener_t *old_listener = NULL;
+
+ log_debug(LD_CHANNEL,
+ "Shutting down TLS channels...");
+
+ if (channel_tls_listener) {
+ /*
+ * When we close it, channel_tls_listener will get nulled out, so save
+ * a pointer so we can free it.
+ */
+ old_listener = channel_tls_listener;
+ log_debug(LD_CHANNEL,
+ "Closing channel_tls_listener with ID " U64_FORMAT
+ " at %p.",
+ U64_PRINTF_ARG(old_listener->global_identifier),
+ old_listener);
+ channel_listener_unregister(old_listener);
+ channel_listener_mark_for_close(old_listener);
+ channel_listener_free(old_listener);
+ tor_assert(channel_tls_listener == NULL);
+ }
+
+ log_debug(LD_CHANNEL,
+ "Done shutting down TLS channels");
+}
+
+/**
+ * Create a new channel around an incoming or_connection_t
+ */
+
+channel_t *
+channel_tls_handle_incoming(or_connection_t *orconn)
+{
+ channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan));
+ channel_t *chan = &(tlschan->base_);
+
+ tor_assert(orconn);
+ tor_assert(!(orconn->chan));
+
+ channel_tls_common_init(tlschan);
+
+ /* Link the channel and orconn to each other */
+ tlschan->conn = orconn;
+ orconn->chan = tlschan;
+
+ if (is_local_addr(&(TO_CONN(orconn)->addr))) channel_mark_local(chan);
+ channel_mark_incoming(chan);
+
+ /* If we got one, we should register it */
+ if (chan) channel_register(chan);
+
+ return chan;
+}
+
+/*********
+ * Casts *
+ ********/
+
+/**
+ * Cast a channel_tls_t to a channel_t.
+ */
+
+channel_t *
+channel_tls_to_base(channel_tls_t *tlschan)
+{
+ if (!tlschan) return NULL;
+
+ return &(tlschan->base_);
+}
+
+/**
+ * Cast a channel_t to a channel_tls_t, with appropriate type-checking
+ * asserts.
+ */
+
+channel_tls_t *
+channel_tls_from_base(channel_t *chan)
+{
+ if (!chan) return NULL;
+
+ tor_assert(chan->magic == TLS_CHAN_MAGIC);
+
+ return (channel_tls_t *)(chan);
+}
+
+/********************************************
+ * Method implementations for channel_tls_t *
+ *******************************************/
+
+/**
+ * Close a channel_tls_t
+ *
+ * This implements the close method for channel_tls_t
+ */
+
+static void
+channel_tls_close_method(channel_t *chan)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+
+ if (tlschan->conn) connection_or_close_normally(tlschan->conn, 1);
+ else {
+ /* Weird - we'll have to change the state ourselves, I guess */
+ log_info(LD_CHANNEL,
+ "Tried to close channel_tls_t %p with NULL conn",
+ tlschan);
+ channel_change_state(chan, CHANNEL_STATE_ERROR);
+ }
+}
+
+/**
+ * Describe the transport for a channel_tls_t
+ *
+ * This returns the string "TLS channel on connection <id>" to the upper
+ * layer.
+ */
+
+static const char *
+channel_tls_describe_transport_method(channel_t *chan)
+{
+ static char *buf = NULL;
+ uint64_t id;
+ channel_tls_t *tlschan;
+ const char *rv = NULL;
+
+ tor_assert(chan);
+
+ tlschan = BASE_CHAN_TO_TLS(chan);
+
+ if (tlschan->conn) {
+ id = TO_CONN(tlschan->conn)->global_identifier;
+
+ if (buf) tor_free(buf);
+ tor_asprintf(&buf,
+ "TLS channel (connection " U64_FORMAT ")",
+ U64_PRINTF_ARG(id));
+
+ rv = buf;
+ } else {
+ rv = "TLS channel (no connection)";
+ }
+
+ return rv;
+}
+
+/**
+ * Get the remote address of a channel_tls_t
+ *
+ * This implements the get_remote_addr method for channel_tls_t; copy the
+ * remote endpoint of the channel to addr_out and return 1 (always
+ * succeeds for this transport).
+ */
+
+static int
+channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(addr_out);
+ tor_assert(tlschan->conn);
+
+ tor_addr_copy(addr_out, &(TO_CONN(tlschan->conn)->addr));
+
+ return 1;
+}
+
+/**
+ * Get endpoint description of a channel_tls_t
+ *
+ * This implements the get_remote_descr method for channel_tls_t; it returns
+ * a text description of the remote endpoint of the channel suitable for use
+ * in log messages. The req parameter is 0 for the canonical address or 1 for
+ * the actual address seen.
+ */
+
+static const char *
+channel_tls_get_remote_descr_method(channel_t *chan, int flags)
+{
+#define MAX_DESCR_LEN 32
+
+ static char buf[MAX_DESCR_LEN + 1];
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ connection_t *conn;
+ const char *answer = NULL;
+ char *addr_str;
+
+ tor_assert(tlschan);
+ tor_assert(tlschan->conn);
+
+ conn = TO_CONN(tlschan->conn);
+
+ switch (flags) {
+ case 0:
+ /* Canonical address with port*/
+ tor_snprintf(buf, MAX_DESCR_LEN + 1,
+ "%s:%u", conn->address, conn->port);
+ answer = buf;
+ break;
+ case GRD_FLAG_ORIGINAL:
+ /* Actual address with port */
+ addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
+ tor_snprintf(buf, MAX_DESCR_LEN + 1,
+ "%s:%u", addr_str, conn->port);
+ tor_free(addr_str);
+ answer = buf;
+ break;
+ case GRD_FLAG_ADDR_ONLY:
+ /* Canonical address, no port */
+ strlcpy(buf, conn->address, sizeof(buf));
+ answer = buf;
+ break;
+ case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY:
+ /* Actual address, no port */
+ addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
+ strlcpy(buf, addr_str, sizeof(buf));
+ tor_free(addr_str);
+ answer = buf;
+ break;
+
+ default:
+ /* Something's broken in channel.c */
+ tor_assert(1);
+ }
+
+ return answer;
+}
+
+/**
+ * Tell the upper layer if we have queued writes
+ *
+ * This implements the has_queued_writes method for channel_tls t_; it returns
+ * 1 iff we have queued writes on the outbuf of the underlying or_connection_t.
+ */
+
+static int
+channel_tls_has_queued_writes_method(channel_t *chan)
+{
+ size_t outbuf_len;
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(tlschan->conn);
+
+ outbuf_len = connection_get_outbuf_len(TO_CONN(tlschan->conn));
+
+ return (outbuf_len > 0);
+}
+
+/**
+ * Tell the upper layer if we're canonical
+ *
+ * This implements the is_canonical method for channel_tls_t; if req is zero,
+ * it returns whether this is a canonical channel, and if it is one it returns
+ * whether that can be relied upon.
+ */
+
+static int
+channel_tls_is_canonical_method(channel_t *chan, int req)
+{
+ int answer = 0;
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(tlschan->conn);
+
+ switch (req) {
+ case 0:
+ answer = tlschan->conn->is_canonical;
+ break;
+ case 1:
+ /*
+ * Is the is_canonical bit reliable? In protocols version 2 and up
+ * we get the canonical address from a NETINFO cell, but in older
+ * versions it might be based on an obsolete descriptor.
+ */
+ answer = (tlschan->conn->link_proto >= 2);
+ break;
+ default:
+ /* This shouldn't happen; channel.c is broken if it does */
+ tor_assert(1);
+ }
+
+ return answer;
+}
+
+/**
+ * Check if we match an extend_info_t
+ *
+ * This implements the matches_extend_info method for channel_tls_t; the upper
+ * layer wants to know if this channel matches an extend_info_t.
+ */
+
+static int
+channel_tls_matches_extend_info_method(channel_t *chan,
+ extend_info_t *extend_info)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(extend_info);
+
+ return (tor_addr_eq(&(extend_info->addr),
+ &(TO_CONN(tlschan->conn)->addr)) &&
+ (extend_info->port == TO_CONN(tlschan->conn)->port));
+}
+
+/**
+ * Check if we match a target address
+ *
+ * This implements the matches_target method for channel_tls t_; the upper
+ * layer wants to know if this channel matches a target address when extending
+ * a circuit.
+ */
+
+static int
+channel_tls_matches_target_method(channel_t *chan,
+ const tor_addr_t *target)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(target);
+ tor_assert(tlschan->conn);
+
+ return tor_addr_compare(&(tlschan->conn->real_addr),
+ target, CMP_EXACT);
+}
+
+/**
+ * Write a cell to a channel_tls_t
+ *
+ * This implements the write_cell method for channel_tls_t; given a
+ * channel_tls_t and a cell_t, transmit the cell_t.
+ */
+
+static int
+channel_tls_write_cell_method(channel_t *chan, cell_t *cell)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(cell);
+ tor_assert(tlschan->conn);
+
+ connection_or_write_cell_to_buf(cell, tlschan->conn);
+
+ return 1;
+}
+
+/**
+ * Write a packed cell to a channel_tls_t
+ *
+ * This implements the write_packed_cell method for channel_tls_t; given a
+ * channel_tls_t and a packed_cell_t, transmit the packed_cell_t.
+ */
+
+static int
+channel_tls_write_packed_cell_method(channel_t *chan,
+ packed_cell_t *packed_cell)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(packed_cell);
+ tor_assert(tlschan->conn);
+
+ connection_write_to_buf(packed_cell->body, CELL_NETWORK_SIZE,
+ TO_CONN(tlschan->conn));
+
+ /* This is where the cell is finished; used to be done from relay.c */
+ packed_cell_free(packed_cell);
+
+ return 1;
+}
+
+/**
+ * Write a variable-length cell to a channel_tls_t
+ *
+ * This implements the write_var_cell method for channel_tls_t; given a
+ * channel_tls_t and a var_cell_t, transmit the var_cell_t.
+ */
+
+static int
+channel_tls_write_var_cell_method(channel_t *chan, var_cell_t *var_cell)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(var_cell);
+ tor_assert(tlschan->conn);
+
+ connection_or_write_var_cell_to_buf(var_cell, tlschan->conn);
+
+ return 1;
+}
+
+/*************************************************
+ * Method implementations for channel_listener_t *
+ ************************************************/
+
+/**
+ * Close a channel_listener_t
+ *
+ * This implements the close method for channel_listener_t
+ */
+
+static void
+channel_tls_listener_close_method(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ /*
+ * Listeners we just go ahead and change state through to CLOSED, but
+ * make sure to check if they're channel_tls_listener to NULL it out.
+ */
+ if (chan_l == channel_tls_listener)
+ channel_tls_listener = NULL;
+
+ if (!(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR)) {
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
+ }
+
+ if (chan_l->incoming_list) {
+ SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list,
+ channel_t *, ichan) {
+ channel_mark_for_close(ichan);
+ } SMARTLIST_FOREACH_END(ichan);
+
+ smartlist_free(chan_l->incoming_list);
+ chan_l->incoming_list = NULL;
+ }
+
+ if (!(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR)) {
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED);
+ }
+}
+
+/**
+ * Describe the transport for a channel_listener_t
+ *
+ * This returns the string "TLS channel (listening)" to the upper
+ * layer.
+ */
+
+static const char *
+channel_tls_listener_describe_transport_method(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return "TLS channel (listening)";
+}
+
+/*******************************************************
+ * Functions for handling events on an or_connection_t *
+ ******************************************************/
+
+/**
+ * Handle an orconn state change
+ *
+ * This function will be called by connection_or.c when the or_connection_t
+ * associated with this channel_tls_t changes state.
+ */
+
+void
+channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
+ or_connection_t *conn,
+ uint8_t old_state,
+ uint8_t state)
+{
+ channel_t *base_chan;
+
+ tor_assert(chan);
+ tor_assert(conn);
+ tor_assert(conn->chan == chan);
+ tor_assert(chan->conn == conn);
+ /* -Werror appeasement */
+ tor_assert(old_state == old_state);
+
+ base_chan = TLS_CHAN_TO_BASE(chan);
+
+ /* Make sure the base connection state makes sense - shouldn't be error,
+ * closed or listening. */
+
+ tor_assert(base_chan->state == CHANNEL_STATE_OPENING ||
+ base_chan->state == CHANNEL_STATE_OPEN ||
+ base_chan->state == CHANNEL_STATE_MAINT ||
+ base_chan->state == CHANNEL_STATE_CLOSING);
+
+ /* Did we just go to state open? */
+ if (state == OR_CONN_STATE_OPEN) {
+ /*
+ * We can go to CHANNEL_STATE_OPEN from CHANNEL_STATE_OPENING or
+ * CHANNEL_STATE_MAINT on this.
+ */
+ channel_change_state(base_chan, CHANNEL_STATE_OPEN);
+ } else {
+ /*
+ * Not open, so from CHANNEL_STATE_OPEN we go to CHANNEL_STATE_MAINT,
+ * otherwise no change.
+ */
+ if (base_chan->state == CHANNEL_STATE_OPEN) {
+ channel_change_state(base_chan, CHANNEL_STATE_MAINT);
+ }
+ }
+}
+
+/**
+ * Flush cells from a channel_tls_t
+ *
+ * Try to flush up to about num_cells cells, and return how many we flushed.
+ */
+
+ssize_t
+channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells)
+{
+ ssize_t flushed = 0;
+
+ tor_assert(chan);
+
+ if (flushed >= num_cells) goto done;
+
+ /*
+ * If channel_tls_t ever buffers anything below the channel_t layer, flush
+ * that first here.
+ */
+
+ flushed += channel_flush_some_cells(TLS_CHAN_TO_BASE(chan),
+ num_cells - flushed);
+
+ /*
+ * If channel_tls_t ever buffers anything below the channel_t layer, check
+ * how much we actually got and push it on down here.
+ */
+
+ done:
+ return flushed;
+}
+
+/**
+ * Check if a channel_tls_t has anything to flush
+ *
+ * Return true if there is any more to flush on this channel (cells in queue
+ * or active circuits).
+ */
+
+int
+channel_tls_more_to_flush(channel_tls_t *chan)
+{
+ tor_assert(chan);
+
+ /*
+ * If channel_tls_t ever buffers anything below channel_t, the
+ * check for that should go here first.
+ */
+
+ return channel_more_to_flush(TLS_CHAN_TO_BASE(chan));
+}
+
+#ifdef KEEP_TIMING_STATS
+
+/**
+ * Timing states wrapper
+ *
+ * This is a wrapper function around the actual function that processes the
+ * <b>cell</b> that just arrived on <b>chan</b>. Increment <b>*time</b>
+ * by the number of microseconds used by the call to <b>*func(cell, chan)</b>.
+ */
+
+static void
+channel_tls_time_process_cell(cell_t *cell, channel_tls_t *chan, int *time,
+ void (*func)(cell_t *, channel_tls_t *))
+{
+ struct timeval start, end;
+ long time_passed;
+
+ tor_gettimeofday(&start);
+
+ (*func)(cell, chan);
+
+ tor_gettimeofday(&end);
+ time_passed = tv_udiff(&start, &end) ;
+
+ if (time_passed > 10000) { /* more than 10ms */
+ log_debug(LD_OR,"That call just took %ld ms.",time_passed/1000);
+ }
+
+ if (time_passed < 0) {
+ log_info(LD_GENERAL,"That call took us back in time!");
+ time_passed = 0;
+ }
+
+ *time += time_passed;
+}
+#endif
+
+/**
+ * Handle an incoming cell on a channel_tls_t
+ *
+ * This is called from connection_or.c to handle an arriving cell; it checks
+ * for cell types specific to the handshake for this transport protocol and
+ * handles them, and queues all other cells to the channel_t layer, which
+ * eventually will hand them off to command.c.
+ */
+
+void
+channel_tls_handle_cell(cell_t *cell, or_connection_t *conn)
+{
+ channel_tls_t *chan;
+ int handshaking;
+
+#ifdef KEEP_TIMING_STATS
+#define PROCESS_CELL(tp, cl, cn) STMT_BEGIN { \
+ ++num ## tp; \
+ channel_tls_time_process_cell(cl, cn, & tp ## time , \
+ channel_tls_process_ ## tp ## _cell); \
+ } STMT_END
+#else
+#define PROCESS_CELL(tp, cl, cn) channel_tls_process_ ## tp ## _cell(cl, cn)
+#endif
+
+ tor_assert(cell);
+ tor_assert(conn);
+
+ chan = conn->chan;
+
+ if (!chan) {
+ log_warn(LD_CHANNEL,
+ "Got a cell_t on an OR connection with no channel");
+ return;
+ }
+
+ handshaking = (TO_CONN(conn)->state != OR_CONN_STATE_OPEN);
+
+ if (conn->base_.marked_for_close)
+ return;
+
+ /* Reject all but VERSIONS and NETINFO when handshaking. */
+ /* (VERSIONS should actually be impossible; it's variable-length.) */
+ if (handshaking && cell->command != CELL_VERSIONS &&
+ cell->command != CELL_NETINFO) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received unexpected cell command %d in chan state %s / "
+ "conn state %s; closing the connection.",
+ (int)cell->command,
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state));
+ connection_or_close_for_error(conn, 0);
+ return;
+ }
+
+ if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
+ or_handshake_state_record_cell(conn->handshake_state, cell, 1);
+
+ switch (cell->command) {
+ case CELL_PADDING:
+ ++stats_n_padding_cells_processed;
+ /* do nothing */
+ break;
+ case CELL_VERSIONS:
+ tor_fragile_assert();
+ break;
+ case CELL_NETINFO:
+ ++stats_n_netinfo_cells_processed;
+ PROCESS_CELL(netinfo, cell, chan);
+ break;
+ case CELL_CREATE:
+ case CELL_CREATE_FAST:
+ case CELL_CREATED:
+ case CELL_CREATED_FAST:
+ case CELL_RELAY:
+ case CELL_RELAY_EARLY:
+ case CELL_DESTROY:
+ /*
+ * These are all transport independent and we pass them up through the
+ * channel_t mechanism. They are ultimately handled in command.c.
+ */
+ channel_queue_cell(TLS_CHAN_TO_BASE(chan), cell);
+ break;
+ default:
+ log_fn(LOG_INFO, LD_PROTOCOL,
+ "Cell of unknown type (%d) received in channeltls.c. "
+ "Dropping.",
+ cell->command);
+ break;
+ }
+}
+
+/**
+ * Handle an incoming variable-length cell on a channel_tls_t
+ *
+ * Process a <b>var_cell</b> that was just received on <b>conn</b>. Keep
+ * internal statistics about how many of each cell we've processed so far
+ * this second, and the total number of microseconds it took to
+ * process each type of cell. All the var_cell commands are handshake-
+ * related and live below the channel_t layer, so no variable-length
+ * cells ever get delivered in the current implementation, but I've left
+ * the mechanism in place for future use.
+ */
+
+void
+channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn)
+{
+ channel_tls_t *chan;
+
+#ifdef KEEP_TIMING_STATS
+ /* how many of each cell have we seen so far this second? needs better
+ * name. */
+ static int num_versions = 0, num_certs = 0;
+ static time_t current_second = 0; /* from previous calls to time */
+ time_t now = time(NULL);
+
+ if (current_second == 0) current_second = now;
+ if (now > current_second) { /* the second has rolled over */
+ /* print stats */
+ log_info(LD_OR,
+ "At end of second: %d versions (%d ms), %d certs (%d ms)",
+ num_versions, versions_time / ((now - current_second) * 1000),
+ num_certs, certs_time / ((now - current_second) * 1000));
+
+ num_versions = num_certs = 0;
+ versions_time = certs_time = 0;
+
+ /* remember which second it is, for next time */
+ current_second = now;
+ }
+#endif
+
+ tor_assert(var_cell);
+ tor_assert(conn);
+
+ chan = conn->chan;
+
+ if (!chan) {
+ log_warn(LD_CHANNEL,
+ "Got a var_cell_t on an OR connection with no channel");
+ return;
+ }
+
+ if (TO_CONN(conn)->marked_for_close)
+ return;
+
+ switch (TO_CONN(conn)->state) {
+ case OR_CONN_STATE_OR_HANDSHAKING_V2:
+ if (var_cell->command != CELL_VERSIONS) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received a cell with command %d in unexpected "
+ "orconn state \"%s\" [%d], channel state \"%s\" [%d]; "
+ "closing the connection.",
+ (int)(var_cell->command),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state),
+ TO_CONN(conn)->state,
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(TLS_CHAN_TO_BASE(chan)->state));
+ /*
+ * The code in connection_or.c will tell channel_t to close for
+ * error; it will go to CHANNEL_STATE_CLOSING, and then to
+ * CHANNEL_STATE_ERROR when conn is closed.
+ */
+ connection_or_close_for_error(conn, 0);
+ return;
+ }
+ break;
+ case OR_CONN_STATE_TLS_HANDSHAKING:
+ /* If we're using bufferevents, it's entirely possible for us to
+ * notice "hey, data arrived!" before we notice "hey, the handshake
+ * finished!" And we need to be accepting both at once to handle both
+ * the v2 and v3 handshakes. */
+
+ /* fall through */
+ case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
+ if (!(command_allowed_before_handshake(var_cell->command))) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received a cell with command %d in unexpected "
+ "orconn state \"%s\" [%d], channel state \"%s\" [%d]; "
+ "closing the connection.",
+ (int)(var_cell->command),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state),
+ (int)(TO_CONN(conn)->state),
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(TLS_CHAN_TO_BASE(chan)->state));
+ /* see above comment about CHANNEL_STATE_ERROR */
+ connection_or_close_for_error(conn, 0);
+ return;
+ } else {
+ if (enter_v3_handshake_with_cell(var_cell, chan) < 0)
+ return;
+ }
+ break;
+ case OR_CONN_STATE_OR_HANDSHAKING_V3:
+ if (var_cell->command != CELL_AUTHENTICATE)
+ or_handshake_state_record_var_cell(conn->handshake_state, var_cell, 1);
+ break; /* Everything is allowed */
+ case OR_CONN_STATE_OPEN:
+ if (conn->link_proto < 3) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received a variable-length cell with command %d in orconn "
+ "state %s [%d], channel state %s [%d] with link protocol %d; "
+ "ignoring it.",
+ (int)(var_cell->command),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state),
+ (int)(TO_CONN(conn)->state),
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(conn->link_proto));
+ return;
+ }
+ break;
+ default:
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received var-length cell with command %d in unexpected "
+ "orconn state \"%s\" [%d], channel state \"%s\" [%d]; "
+ "ignoring it.",
+ (int)(var_cell->command),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state),
+ (int)(TO_CONN(conn)->state),
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(TLS_CHAN_TO_BASE(chan)->state));
+ return;
+ }
+
+ /* Now handle the cell */
+
+ switch (var_cell->command) {
+ case CELL_VERSIONS:
+ ++stats_n_versions_cells_processed;
+ PROCESS_CELL(versions, var_cell, chan);
+ break;
+ case CELL_VPADDING:
+ ++stats_n_vpadding_cells_processed;
+ /* Do nothing */
+ break;
+ case CELL_CERTS:
+ ++stats_n_certs_cells_processed;
+ PROCESS_CELL(certs, var_cell, chan);
+ break;
+ case CELL_AUTH_CHALLENGE:
+ ++stats_n_auth_challenge_cells_processed;
+ PROCESS_CELL(auth_challenge, var_cell, chan);
+ break;
+ case CELL_AUTHENTICATE:
+ ++stats_n_authenticate_cells_processed;
+ PROCESS_CELL(authenticate, var_cell, chan);
+ break;
+ case CELL_AUTHORIZE:
+ ++stats_n_authorize_cells_processed;
+ /* Ignored so far. */
+ break;
+ default:
+ log_fn(LOG_INFO, LD_PROTOCOL,
+ "Variable-length cell of unknown type (%d) received.",
+ (int)(var_cell->command));
+ break;
+ }
+}
+
+/**
+ * Check if this cell type is allowed before the handshake is finished
+ *
+ * Return true if <b>command</b> is a cell command that's allowed to start a
+ * V3 handshake.
+ */
+
+static int
+command_allowed_before_handshake(uint8_t command)
+{
+ switch (command) {
+ case CELL_VERSIONS:
+ case CELL_VPADDING:
+ case CELL_AUTHORIZE:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Start a V3 handshake on an incoming connection
+ *
+ * Called when we as a server receive an appropriate cell while waiting
+ * either for a cell or a TLS handshake. Set the connection's state to
+ * "handshaking_v3', initializes the or_handshake_state field as needed,
+ * and add the cell to the hash of incoming cells.)
+ */
+
+static int
+enter_v3_handshake_with_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ int started_here = 0;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+ started_here = connection_or_nonopen_was_started_here(chan->conn);
+
+ tor_assert(TO_CONN(chan->conn)->state == OR_CONN_STATE_TLS_HANDSHAKING ||
+ TO_CONN(chan->conn)->state ==
+ OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
+
+ if (started_here) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a cell while TLS-handshaking, not in "
+ "OR_HANDSHAKING_V3, on a connection we originated.");
+ }
+ connection_or_block_renegotiation(chan->conn);
+ chan->conn->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ if (connection_init_or_handshake_state(chan->conn, started_here) < 0) {
+ connection_or_close_for_error(chan->conn, 0);
+ return -1;
+ }
+ or_handshake_state_record_var_cell(chan->conn->handshake_state, cell, 1);
+ return 0;
+}
+
+/**
+ * Process a 'versions' cell.
+ *
+ * This function is called to handle an incoming VERSIONS cell; the current
+ * link protocol version must be 0 to indicate that no version has yet been
+ * negotiated. We compare the versions in the cell to the list of versions
+ * we support, pick the highest version we have in common, and continue the
+ * negotiation from there.
+ */
+
+static void
+channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ int highest_supported_version = 0;
+ const uint8_t *cp, *end;
+ int started_here = 0;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+ started_here = connection_or_nonopen_was_started_here(chan->conn);
+
+ if (chan->conn->link_proto != 0 ||
+ (chan->conn->handshake_state &&
+ chan->conn->handshake_state->received_versions)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a VERSIONS cell on a connection with its version "
+ "already set to %d; dropping",
+ (int)(chan->conn->link_proto));
+ return;
+ }
+ switch (chan->conn->base_.state)
+ {
+ case OR_CONN_STATE_OR_HANDSHAKING_V2:
+ case OR_CONN_STATE_OR_HANDSHAKING_V3:
+ break;
+ case OR_CONN_STATE_TLS_HANDSHAKING:
+ case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
+ default:
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "VERSIONS cell while in unexpected state");
+ return;
+ }
+
+ tor_assert(chan->conn->handshake_state);
+ end = cell->payload + cell->payload_len;
+ for (cp = cell->payload; cp+1 < end; ++cp) {
+ uint16_t v = ntohs(get_uint16(cp));
+ if (is_or_protocol_version_known(v) && v > highest_supported_version)
+ highest_supported_version = v;
+ }
+ if (!highest_supported_version) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Couldn't find a version in common between my version list and the "
+ "list in the VERSIONS cell; closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ } else if (highest_supported_version == 1) {
+ /* Negotiating version 1 makes no sense, since version 1 has no VERSIONS
+ * cells. */
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Used version negotiation protocol to negotiate a v1 connection. "
+ "That's crazily non-compliant. Closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ } else if (highest_supported_version < 3 &&
+ chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Negotiated link protocol 2 or lower after doing a v3 TLS "
+ "handshake. Closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ } else if (highest_supported_version != 2 &&
+ chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V2) {
+ /* XXXX This should eventually be a log_protocol_warn */
+ log_fn(LOG_WARN, LD_OR,
+ "Negotiated link with non-2 protocol after doing a v2 TLS "
+ "handshake with %s. Closing connection.",
+ fmt_addr(&chan->conn->base_.addr));
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+
+ chan->conn->link_proto = highest_supported_version;
+ chan->conn->handshake_state->received_versions = 1;
+
+ if (chan->conn->link_proto == 2) {
+ log_info(LD_OR,
+ "Negotiated version %d with %s:%d; sending NETINFO.",
+ highest_supported_version,
+ safe_str_client(chan->conn->base_.address),
+ chan->conn->base_.port);
+
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ } else {
+ const int send_versions = !started_here;
+ /* If we want to authenticate, send a CERTS cell */
+ const int send_certs = !started_here || public_server_mode(get_options());
+ /* If we're a relay that got a connection, ask for authentication. */
+ const int send_chall = !started_here && public_server_mode(get_options());
+ /* If our certs cell will authenticate us, we can send a netinfo cell
+ * right now. */
+ const int send_netinfo = !started_here;
+ const int send_any =
+ send_versions || send_certs || send_chall || send_netinfo;
+ tor_assert(chan->conn->link_proto >= 3);
+
+ log_info(LD_OR,
+ "Negotiated version %d with %s:%d; %s%s%s%s%s",
+ highest_supported_version,
+ safe_str_client(chan->conn->base_.address),
+ chan->conn->base_.port,
+ send_any ? "Sending cells:" : "Waiting for CERTS cell",
+ send_versions ? " VERSIONS" : "",
+ send_certs ? " CERTS" : "",
+ send_chall ? " AUTH_CHALLENGE" : "",
+ send_netinfo ? " NETINFO" : "");
+
+#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
+ if (1) {
+ connection_or_close_normally(chan->conn, 1);
+ return;
+ }
+#endif
+
+ if (send_versions) {
+ if (connection_or_send_versions(chan->conn, 1) < 0) {
+ log_warn(LD_OR, "Couldn't send versions cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+ if (send_certs) {
+ if (connection_or_send_certs_cell(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send certs cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+ if (send_chall) {
+ if (connection_or_send_auth_challenge_cell(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send auth_challenge cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+ if (send_netinfo) {
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send netinfo cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * Process a 'netinfo' cell
+ *
+ * This function is called to handle an incoming NETINFO cell; read and act
+ * on its contents, and set the connection state to "open".
+ */
+
+static void
+channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
+{
+ time_t timestamp;
+ uint8_t my_addr_type;
+ uint8_t my_addr_len;
+ const uint8_t *my_addr_ptr;
+ const uint8_t *cp, *end;
+ uint8_t n_other_addrs;
+ time_t now = time(NULL);
+
+ long apparent_skew = 0;
+ tor_addr_t my_apparent_addr = TOR_ADDR_NULL;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+ if (chan->conn->link_proto < 2) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a NETINFO cell on %s connection; dropping.",
+ chan->conn->link_proto == 0 ? "non-versioned" : "a v1");
+ return;
+ }
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
+ chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a NETINFO cell on non-handshaking connection; dropping.");
+ return;
+ }
+ tor_assert(chan->conn->handshake_state &&
+ chan->conn->handshake_state->received_versions);
+
+ if (chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
+ tor_assert(chan->conn->link_proto >= 3);
+ if (chan->conn->handshake_state->started_here) {
+ if (!(chan->conn->handshake_state->authenticated)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Got a NETINFO cell from server, "
+ "but no authentication. Closing the connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ } else {
+ /* we're the server. If the client never authenticated, we have
+ some housekeeping to do.*/
+ if (!(chan->conn->handshake_state->authenticated)) {
+ tor_assert(tor_digest_is_zero(
+ (const char*)(chan->conn->handshake_state->
+ authenticated_peer_id)));
+ channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL);
+
+ connection_or_init_conn_from_address(chan->conn,
+ &(chan->conn->base_.addr),
+ chan->conn->base_.port,
+ (const char*)(chan->conn->handshake_state->
+ authenticated_peer_id),
+ 0);
+ }
+ }
+ }
+
+ /* Decode the cell. */
+ timestamp = ntohl(get_uint32(cell->payload));
+ if (labs(now - chan->conn->handshake_state->sent_versions_at) < 180) {
+ apparent_skew = now - timestamp;
+ }
+
+ my_addr_type = (uint8_t) cell->payload[4];
+ my_addr_len = (uint8_t) cell->payload[5];
+ my_addr_ptr = (uint8_t*) cell->payload + 6;
+ end = cell->payload + CELL_PAYLOAD_SIZE;
+ cp = cell->payload + 6 + my_addr_len;
+ if (cp >= end) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Addresses too long in netinfo cell; closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ } else if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) {
+ tor_addr_from_ipv4n(&my_apparent_addr, get_uint32(my_addr_ptr));
+ } else if (my_addr_type == RESOLVED_TYPE_IPV6 && my_addr_len == 16) {
+ tor_addr_from_ipv6_bytes(&my_apparent_addr, (const char *) my_addr_ptr);
+ }
+
+ n_other_addrs = (uint8_t) *cp++;
+ while (n_other_addrs && cp < end-2) {
+ /* Consider all the other addresses; if any matches, this connection is
+ * "canonical." */
+ tor_addr_t addr;
+ const uint8_t *next =
+ decode_address_from_payload(&addr, cp, (int)(end-cp));
+ if (next == NULL) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Bad address in netinfo cell; closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ if (tor_addr_eq(&addr, &(chan->conn->real_addr))) {
+ chan->conn->is_canonical = 1;
+ break;
+ }
+ cp = next;
+ --n_other_addrs;
+ }
+
+ /* Act on apparent skew. */
+ /** Warn when we get a netinfo skew with at least this value. */
+#define NETINFO_NOTICE_SKEW 3600
+ if (labs(apparent_skew) > NETINFO_NOTICE_SKEW &&
+ router_get_by_id_digest(chan->conn->identity_digest)) {
+ char dbuf[64];
+ int severity;
+ /*XXXX be smarter about when everybody says we are skewed. */
+ if (router_digest_is_trusted_dir(chan->conn->identity_digest))
+ severity = LOG_WARN;
+ else
+ severity = LOG_INFO;
+ format_time_interval(dbuf, sizeof(dbuf), apparent_skew);
+ log_fn(severity, LD_GENERAL,
+ "Received NETINFO cell with skewed time from "
+ "server at %s:%d. It seems that our clock is %s by %s, or "
+ "that theirs is %s. Tor requires an accurate clock to work: "
+ "please check your time and date settings.",
+ chan->conn->base_.address,
+ (int)(chan->conn->base_.port),
+ apparent_skew > 0 ? "ahead" : "behind",
+ dbuf,
+ apparent_skew > 0 ? "behind" : "ahead");
+ if (severity == LOG_WARN) /* only tell the controller if an authority */
+ control_event_general_status(LOG_WARN,
+ "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d",
+ apparent_skew,
+ chan->conn->base_.address,
+ chan->conn->base_.port);
+ }
+
+ /* XXX maybe act on my_apparent_addr, if the source is sufficiently
+ * trustworthy. */
+
+ if (connection_or_set_state_open(chan->conn) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Got good NETINFO cell from %s:%d; but "
+ "was unable to make the OR connection become open.",
+ safe_str_client(chan->conn->base_.address),
+ chan->conn->base_.port);
+ connection_or_close_for_error(chan->conn, 0);
+ } else {
+ log_info(LD_OR,
+ "Got good NETINFO cell from %s:%d; OR connection is now "
+ "open, using protocol version %d. Its ID digest is %s. "
+ "Our address is apparently %s.",
+ safe_str_client(chan->conn->base_.address),
+ chan->conn->base_.port,
+ (int)(chan->conn->link_proto),
+ hex_str(TLS_CHAN_TO_BASE(chan)->identity_digest,
+ DIGEST_LEN),
+ tor_addr_is_null(&my_apparent_addr) ?
+ "<none>" : fmt_and_decorate_addr(&my_apparent_addr));
+ }
+ assert_connection_ok(TO_CONN(chan->conn),time(NULL));
+}
+
+/**
+ * Process a CERTS cell from a channel.
+ *
+ * This function is called to process an incoming CERTS cell on a
+ * channel_tls_t:
+ *
+ * If the other side should not have sent us a CERTS cell, or the cell is
+ * malformed, or it is supposed to authenticate the TLS key but it doesn't,
+ * then mark the connection.
+ *
+ * If the cell has a good cert chain and we're doing a v3 handshake, then
+ * store the certificates in or_handshake_state. If this is the client side
+ * of the connection, we then authenticate the server or mark the connection.
+ * If it's the server side, wait for an AUTHENTICATE cell.
+ */
+
+static void
+channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ tor_cert_t *link_cert = NULL;
+ tor_cert_t *id_cert = NULL;
+ tor_cert_t *auth_cert = NULL;
+ uint8_t *ptr;
+ int n_certs, i;
+ int send_netinfo = 0;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+#define ERR(s) \
+ do { \
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
+ "Received a bad CERTS cell from %s:%d: %s", \
+ safe_str(chan->conn->base_.address), \
+ chan->conn->base_.port, (s)); \
+ connection_or_close_for_error(chan->conn, 0); \
+ goto err; \
+ } while (0)
+
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
+ ERR("We're not doing a v3 handshake!");
+ if (chan->conn->link_proto < 3)
+ ERR("We're not using link protocol >= 3");
+ if (chan->conn->handshake_state->received_certs_cell)
+ ERR("We already got one");
+ if (chan->conn->handshake_state->authenticated) {
+ /* Should be unreachable, but let's make sure. */
+ ERR("We're already authenticated!");
+ }
+ if (cell->payload_len < 1)
+ ERR("It had no body");
+ if (cell->circ_id)
+ ERR("It had a nonzero circuit ID");
+
+ n_certs = cell->payload[0];
+ ptr = cell->payload + 1;
+ for (i = 0; i < n_certs; ++i) {
+ uint8_t cert_type;
+ uint16_t cert_len;
+ if (ptr + 3 > cell->payload + cell->payload_len) {
+ goto truncated;
+ }
+ cert_type = *ptr;
+ cert_len = ntohs(get_uint16(ptr+1));
+ if (ptr + 3 + cert_len > cell->payload + cell->payload_len) {
+ goto truncated;
+ }
+ if (cert_type == OR_CERT_TYPE_TLS_LINK ||
+ cert_type == OR_CERT_TYPE_ID_1024 ||
+ cert_type == OR_CERT_TYPE_AUTH_1024) {
+ tor_cert_t *cert = tor_cert_decode(ptr + 3, cert_len);
+ if (!cert) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received undecodable certificate in CERTS cell from %s:%d",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ } else {
+ if (cert_type == OR_CERT_TYPE_TLS_LINK) {
+ if (link_cert) {
+ tor_cert_free(cert);
+ ERR("Too many TLS_LINK certificates");
+ }
+ link_cert = cert;
+ } else if (cert_type == OR_CERT_TYPE_ID_1024) {
+ if (id_cert) {
+ tor_cert_free(cert);
+ ERR("Too many ID_1024 certificates");
+ }
+ id_cert = cert;
+ } else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
+ if (auth_cert) {
+ tor_cert_free(cert);
+ ERR("Too many AUTH_1024 certificates");
+ }
+ auth_cert = cert;
+ } else {
+ tor_cert_free(cert);
+ }
+ }
+ }
+ ptr += 3 + cert_len;
+ continue;
+
+ truncated:
+ ERR("It ends in the middle of a certificate");
+ }
+
+ if (chan->conn->handshake_state->started_here) {
+ int severity;
+ if (! (id_cert && link_cert))
+ ERR("The certs we wanted were missing");
+ /* Okay. We should be able to check the certificates now. */
+ if (! tor_tls_cert_matches_key(chan->conn->tls, link_cert)) {
+ ERR("The link certificate didn't match the TLS public key");
+ }
+ /* Note that this warns more loudly about time and validity if we were
+ * _trying_ to connect to an authority, not necessarily if we _did_ connect
+ * to one. */
+ if (router_digest_is_trusted_dir(
+ TLS_CHAN_TO_BASE(chan)->identity_digest))
+ severity = LOG_WARN;
+ else
+ severity = LOG_PROTOCOL_WARN;
+
+ if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, 0))
+ ERR("The link certificate was not valid");
+ if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, 1))
+ ERR("The ID certificate was not valid");
+
+ chan->conn->handshake_state->authenticated = 1;
+ {
+ const digests_t *id_digests = tor_cert_get_id_digests(id_cert);
+ crypto_pk_t *identity_rcvd;
+ if (!id_digests)
+ ERR("Couldn't compute digests for key in ID cert");
+
+ identity_rcvd = tor_tls_cert_get_key(id_cert);
+ if (!identity_rcvd)
+ ERR("Internal error: Couldn't get RSA key from ID cert.");
+ memcpy(chan->conn->handshake_state->authenticated_peer_id,
+ id_digests->d[DIGEST_SHA1], DIGEST_LEN);
+ channel_set_circid_type(TLS_CHAN_TO_BASE(chan), identity_rcvd);
+ crypto_pk_free(identity_rcvd);
+ }
+
+ if (connection_or_client_learned_peer_id(chan->conn,
+ chan->conn->handshake_state->authenticated_peer_id) < 0)
+ ERR("Problem setting or checking peer id");
+
+ log_info(LD_OR,
+ "Got some good certificates from %s:%d: Authenticated it.",
+ safe_str(chan->conn->base_.address), chan->conn->base_.port);
+
+ chan->conn->handshake_state->id_cert = id_cert;
+ id_cert = NULL;
+
+ if (!public_server_mode(get_options())) {
+ /* If we initiated the connection and we are not a public server, we
+ * aren't planning to authenticate at all. At this point we know who we
+ * are talking to, so we can just send a netinfo now. */
+ send_netinfo = 1;
+ }
+ } else {
+ if (! (id_cert && auth_cert))
+ ERR("The certs we wanted were missing");
+
+ /* Remember these certificates so we can check an AUTHENTICATE cell */
+ if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, 1))
+ ERR("The authentication certificate was not valid");
+ if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, 1))
+ ERR("The ID certificate was not valid");
+
+ log_info(LD_OR,
+ "Got some good certificates from %s:%d: "
+ "Waiting for AUTHENTICATE.",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ /* XXXX check more stuff? */
+
+ chan->conn->handshake_state->id_cert = id_cert;
+ chan->conn->handshake_state->auth_cert = auth_cert;
+ id_cert = auth_cert = NULL;
+ }
+
+ chan->conn->handshake_state->received_certs_cell = 1;
+
+ if (send_netinfo) {
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send netinfo cell");
+ connection_or_close_for_error(chan->conn, 0);
+ goto err;
+ }
+ }
+
+ err:
+ tor_cert_free(id_cert);
+ tor_cert_free(link_cert);
+ tor_cert_free(auth_cert);
+#undef ERR
+}
+
+/**
+ * Process an AUTH_CHALLENGE cell from a channel_tls_t
+ *
+ * This function is called to handle an incoming AUTH_CHALLENGE cell on a
+ * channel_tls_t; if we weren't supposed to get one (for example, because we're
+ * not the originator of the channel), or it's ill-formed, or we aren't doing
+ * a v3 handshake, mark the channel. If the cell is well-formed but we don't
+ * want to authenticate, just drop it. If the cell is well-formed *and* we
+ * want to authenticate, send an AUTHENTICATE cell and then a NETINFO cell.
+ */
+
+static void
+channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ int n_types, i, use_type = -1;
+ uint8_t *cp;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+#define ERR(s) \
+ do { \
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
+ "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \
+ safe_str(chan->conn->base_.address), \
+ chan->conn->base_.port, (s)); \
+ connection_or_close_for_error(chan->conn, 0); \
+ return; \
+ } while (0)
+
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
+ ERR("We're not currently doing a v3 handshake");
+ if (chan->conn->link_proto < 3)
+ ERR("We're not using link protocol >= 3");
+ if (!(chan->conn->handshake_state->started_here))
+ ERR("We didn't originate this connection");
+ if (chan->conn->handshake_state->received_auth_challenge)
+ ERR("We already received one");
+ if (!(chan->conn->handshake_state->received_certs_cell))
+ ERR("We haven't gotten a CERTS cell yet");
+ if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2)
+ ERR("It was too short");
+ if (cell->circ_id)
+ ERR("It had a nonzero circuit ID");
+
+ n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN));
+ if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types)
+ ERR("It looks truncated");
+
+ /* Now see if there is an authentication type we can use */
+ cp = cell->payload+OR_AUTH_CHALLENGE_LEN + 2;
+ for (i = 0; i < n_types; ++i, cp += 2) {
+ uint16_t authtype = ntohs(get_uint16(cp));
+ if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET)
+ use_type = authtype;
+ }
+
+ chan->conn->handshake_state->received_auth_challenge = 1;
+
+ if (! public_server_mode(get_options())) {
+ /* If we're not a public server then we don't want to authenticate on a
+ connection we originated, and we already sent a NETINFO cell when we
+ got the CERTS cell. We have nothing more to do. */
+ return;
+ }
+
+ if (use_type >= 0) {
+ log_info(LD_OR,
+ "Got an AUTH_CHALLENGE cell from %s:%d: Sending "
+ "authentication",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+
+ if (connection_or_send_authenticate_cell(chan->conn, use_type) < 0) {
+ log_warn(LD_OR,
+ "Couldn't send authenticate cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ } else {
+ log_info(LD_OR,
+ "Got an AUTH_CHALLENGE cell from %s:%d, but we don't "
+ "know any of its authentication types. Not authenticating.",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ }
+
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send netinfo cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+
+#undef ERR
+}
+
+/**
+ * Process an AUTHENTICATE cell from a channel_tls_t
+ *
+ * If it's ill-formed or we weren't supposed to get one or we're not doing a
+ * v3 handshake, then mark the connection. If it does not authenticate the
+ * other side of the connection successfully (because it isn't signed right,
+ * we didn't get a CERTS cell, etc) mark the connection. Otherwise, accept
+ * the identity of the router on the other side of the connection.
+ */
+
+static void
+channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ uint8_t expected[V3_AUTH_FIXED_PART_LEN];
+ const uint8_t *auth;
+ int authlen;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+#define ERR(s) \
+ do { \
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
+ "Received a bad AUTHENTICATE cell from %s:%d: %s", \
+ safe_str(chan->conn->base_.address), \
+ chan->conn->base_.port, (s)); \
+ connection_or_close_for_error(chan->conn, 0); \
+ return; \
+ } while (0)
+
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
+ ERR("We're not doing a v3 handshake");
+ if (chan->conn->link_proto < 3)
+ ERR("We're not using link protocol >= 3");
+ if (chan->conn->handshake_state->started_here)
+ ERR("We originated this connection");
+ if (chan->conn->handshake_state->received_authenticate)
+ ERR("We already got one!");
+ if (chan->conn->handshake_state->authenticated) {
+ /* Should be impossible given other checks */
+ ERR("The peer is already authenticated");
+ }
+ if (!(chan->conn->handshake_state->received_certs_cell))
+ ERR("We never got a certs cell");
+ if (chan->conn->handshake_state->auth_cert == NULL)
+ ERR("We never got an authentication certificate");
+ if (chan->conn->handshake_state->id_cert == NULL)
+ ERR("We never got an identity certificate");
+ if (cell->payload_len < 4)
+ ERR("Cell was way too short");
+
+ auth = cell->payload;
+ {
+ uint16_t type = ntohs(get_uint16(auth));
+ uint16_t len = ntohs(get_uint16(auth+2));
+ if (4 + len > cell->payload_len)
+ ERR("Authenticator was truncated");
+
+ if (type != AUTHTYPE_RSA_SHA256_TLSSECRET)
+ ERR("Authenticator type was not recognized");
+
+ auth += 4;
+ authlen = len;
+ }
+
+ if (authlen < V3_AUTH_BODY_LEN + 1)
+ ERR("Authenticator was too short");
+
+ if (connection_or_compute_authenticate_cell_body(
+ chan->conn, expected, sizeof(expected), NULL, 1) < 0)
+ ERR("Couldn't compute expected AUTHENTICATE cell body");
+
+ if (tor_memneq(expected, auth, sizeof(expected)))
+ ERR("Some field in the AUTHENTICATE cell body was not as expected");
+
+ {
+ crypto_pk_t *pk = tor_tls_cert_get_key(
+ chan->conn->handshake_state->auth_cert);
+ char d[DIGEST256_LEN];
+ char *signed_data;
+ size_t keysize;
+ int signed_len;
+
+ if (!pk)
+ ERR("Internal error: couldn't get RSA key from AUTH cert.");
+ crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256);
+
+ keysize = crypto_pk_keysize(pk);
+ signed_data = tor_malloc(keysize);
+ signed_len = crypto_pk_public_checksig(pk, signed_data, keysize,
+ (char*)auth + V3_AUTH_BODY_LEN,
+ authlen - V3_AUTH_BODY_LEN);
+ crypto_pk_free(pk);
+ if (signed_len < 0) {
+ tor_free(signed_data);
+ ERR("Signature wasn't valid");
+ }
+ if (signed_len < DIGEST256_LEN) {
+ tor_free(signed_data);
+ ERR("Not enough data was signed");
+ }
+ /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here,
+ * in case they're later used to hold a SHA3 digest or something. */
+ if (tor_memneq(signed_data, d, DIGEST256_LEN)) {
+ tor_free(signed_data);
+ ERR("Signature did not match data to be signed.");
+ }
+ tor_free(signed_data);
+ }
+
+ /* Okay, we are authenticated. */
+ chan->conn->handshake_state->received_authenticate = 1;
+ chan->conn->handshake_state->authenticated = 1;
+ chan->conn->handshake_state->digest_received_data = 0;
+ {
+ crypto_pk_t *identity_rcvd =
+ tor_tls_cert_get_key(chan->conn->handshake_state->id_cert);
+ const digests_t *id_digests =
+ tor_cert_get_id_digests(chan->conn->handshake_state->id_cert);
+
+ /* This must exist; we checked key type when reading the cert. */
+ tor_assert(id_digests);
+
+ memcpy(chan->conn->handshake_state->authenticated_peer_id,
+ id_digests->d[DIGEST_SHA1], DIGEST_LEN);
+
+ channel_set_circid_type(TLS_CHAN_TO_BASE(chan), identity_rcvd);
+ crypto_pk_free(identity_rcvd);
+
+ connection_or_init_conn_from_address(chan->conn,
+ &(chan->conn->base_.addr),
+ chan->conn->base_.port,
+ (const char*)(chan->conn->handshake_state->
+ authenticated_peer_id),
+ 0);
+
+ log_info(LD_OR,
+ "Got an AUTHENTICATE cell from %s:%d: Looks good.",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ }
+
+#undef ERR
+}
+
diff --git a/src/or/channeltls.h b/src/or/channeltls.h
new file mode 100644
index 0000000000..b7e0475de6
--- /dev/null
+++ b/src/or/channeltls.h
@@ -0,0 +1,57 @@
+/* * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file channeltls.h
+ * \brief Header file for channeltls.c
+ **/
+
+#ifndef TOR_CHANNELTLS_H
+#define TOR_CHANNELTLS_H
+
+#include "or.h"
+#include "channel.h"
+
+#define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c)))
+#define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c)))
+
+#define TLS_CHAN_MAGIC 0x8a192427U
+
+#ifdef TOR_CHANNEL_INTERNAL_
+
+struct channel_tls_s {
+ /* Base channel_t struct */
+ channel_t base_;
+ /* or_connection_t pointer */
+ or_connection_t *conn;
+};
+
+#endif /* TOR_CHANNEL_INTERNAL_ */
+
+channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest);
+channel_listener_t * channel_tls_get_listener(void);
+channel_listener_t * channel_tls_start_listener(void);
+channel_t * channel_tls_handle_incoming(or_connection_t *orconn);
+
+/* Casts */
+
+channel_t * channel_tls_to_base(channel_tls_t *tlschan);
+channel_tls_t * channel_tls_from_base(channel_t *chan);
+
+/* Things for connection_or.c to call back into */
+ssize_t channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells);
+int channel_tls_more_to_flush(channel_tls_t *chan);
+void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn);
+void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
+ or_connection_t *conn,
+ uint8_t old_state,
+ uint8_t state);
+void channel_tls_handle_var_cell(var_cell_t *var_cell,
+ or_connection_t *conn);
+
+/* Cleanup at shutdown */
+void channel_tls_free_all(void);
+
+#endif
+
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index f8521c5cff..73018740c2 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -9,18 +9,21 @@
* \brief The actual details of building circuits.
**/
-#define CIRCUIT_PRIVATE
-
#include "or.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitstats.h"
#include "circuituse.h"
+#include "command.h"
#include "config.h"
+#include "confparse.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
#include "directory.h"
+#include "entrynodes.h"
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
@@ -32,96 +35,23 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
#include "crypto.h"
-#undef log
-#include <math.h>
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
-#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2))
-
/********* START VARIABLES **********/
-/** Global list of circuit build times */
-// XXXX: Add this as a member for entry_guard_t instead of global?
-// Then we could do per-guard statistics, as guards are likely to
-// vary in their own latency. The downside of this is that guards
-// can change frequently, so we'd be building a lot more circuits
-// most likely.
-/* XXXX024 Make this static; add accessor functions. */
-circuit_build_times_t circ_times;
/** A global list of all circuits at this hop. */
extern circuit_t *global_circuitlist;
-/** An entry_guard_t represents our information about a chosen long-term
- * first hop, known as a "helper" node in the literature. We can't just
- * use a node_t, since we want to remember these even when we
- * don't have any directory info. */
-typedef struct {
- char nickname[MAX_NICKNAME_LEN+1];
- char identity[DIGEST_LEN];
- time_t chosen_on_date; /**< Approximately when was this guard added?
- * "0" if we don't know. */
- char *chosen_by_version; /**< What tor version added this guard? NULL
- * if we don't know. */
- unsigned int made_contact : 1; /**< 0 if we have never connected to this
- * router, 1 if we have. */
- unsigned int can_retry : 1; /**< Should we retry connecting to this entry,
- * in spite of having it marked as unreachable?*/
- unsigned int path_bias_notice : 1; /**< Did we alert the user about path bias
- * for this node already? */
- unsigned int path_bias_disabled : 1; /**< Have we disabled this node because
- * of path bias issues? */
- time_t bad_since; /**< 0 if this guard is currently usable, or the time at
- * which it was observed to become (according to the
- * directory or the user configuration) unusable. */
- time_t unreachable_since; /**< 0 if we can connect to this guard, or the
- * time at which we first noticed we couldn't
- * connect to it. */
- time_t last_attempted; /**< 0 if we can connect to this guard, or the time
- * at which we last failed to connect to it. */
-
- unsigned first_hops; /**< Number of first hops this guard has completed */
- unsigned circuit_successes; /**< Number of successfully built circuits using
- * this guard as first hop. */
-} entry_guard_t;
-
-/** Information about a configured bridge. Currently this just matches the
- * ones in the torrc file, but one day we may be able to learn about new
- * bridges on our own, and remember them in the state file. */
-typedef struct {
- /** Address of the bridge. */
- tor_addr_t addr;
- /** TLS port for the bridge. */
- uint16_t port;
- /** Boolean: We are re-parsing our bridge list, and we are going to remove
- * this one if we don't find it in the list of configured bridges. */
- unsigned marked_for_removal : 1;
- /** Expected identity digest, or all zero bytes if we don't know what the
- * digest should be. */
- char identity[DIGEST_LEN];
-
- /** Name of pluggable transport protocol taken from its config line. */
- char *transport_name;
-
- /** When should we next try to fetch a descriptor for this bridge? */
- download_status_t fetch_status;
-} bridge_info_t;
-
-/** A list of our chosen entry guards. */
-static smartlist_t *entry_guards = NULL;
-/** A value of 1 means that the entry_guards list has changed
- * and those changes need to be flushed to disk. */
-static int entry_guards_dirty = 0;
-
-/** If set, we're running the unit tests: we should avoid clobbering
- * our state file or accessing get_options() or get_or_state() */
-static int unit_tests = 0;
-
/********* END VARIABLES ************/
+static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
+ uint16_t port,
+ const char *id_digest);
static int circuit_deliver_create_cell(circuit_t *circ,
uint8_t cell_type, const char *payload);
static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
@@ -129,1548 +59,23 @@ static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
static int onion_extend_cpath(origin_circuit_t *circ);
static int count_acceptable_nodes(smartlist_t *routers);
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
-
-static void entry_guards_changed(void);
-static entry_guard_t *entry_guard_get_by_id_digest(const char *digest);
-
-static void bridge_free(bridge_info_t *bridge);
-
static int entry_guard_inc_first_hop_count(entry_guard_t *guard);
static void pathbias_count_success(origin_circuit_t *circ);
-/**
- * This function decides if CBT learning should be disabled. It returns
- * true if one or more of the following four conditions are met:
- *
- * 1. If the cbtdisabled consensus parameter is set.
- * 2. If the torrc option LearnCircuitBuildTimeout is false.
- * 3. If we are a directory authority
- * 4. If we fail to write circuit build time history to our state file.
- */
-static int
-circuit_build_times_disabled(void)
-{
- if (unit_tests) {
- return 0;
- } else {
- int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled",
- 0, 0, 1);
- int config_disabled = !get_options()->LearnCircuitBuildTimeout;
- int dirauth_disabled = get_options()->AuthoritativeDir;
- int state_disabled = did_last_state_file_write_fail() ? 1 : 0;
-
- if (consensus_disabled || config_disabled || dirauth_disabled ||
- state_disabled) {
- log_debug(LD_CIRC,
- "CircuitBuildTime learning is disabled. "
- "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d",
- consensus_disabled, config_disabled, dirauth_disabled,
- state_disabled);
- return 1;
- } else {
- log_debug(LD_CIRC,
- "CircuitBuildTime learning is not disabled. "
- "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d",
- consensus_disabled, config_disabled, dirauth_disabled,
- state_disabled);
- return 0;
- }
- }
-}
-
-/**
- * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter.
- *
- * Effect: When this many timeouts happen in the last 'cbtrecentcount'
- * circuit attempts, the client should discard all of its history and
- * begin learning a fresh timeout value.
- */
-static int32_t
-circuit_build_times_max_timeouts(void)
-{
- int32_t cbt_maxtimeouts;
-
- cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts",
- CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT,
- CBT_MIN_MAX_RECENT_TIMEOUT_COUNT,
- CBT_MAX_MAX_RECENT_TIMEOUT_COUNT);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is"
- " %d",
- cbt_maxtimeouts);
- }
-
- return cbt_maxtimeouts;
-}
-
-/**
- * Retrieve and bounds-check the cbtnummodes consensus paramter.
- *
- * Effect: This value governs how many modes to use in the weighted
- * average calculation of Pareto parameter Xm. A value of 3 introduces
- * some bias (2-5% of CDF) under ideal conditions, but allows for better
- * performance in the event that a client chooses guard nodes of radically
- * different performance characteristics.
- */
-static int32_t
-circuit_build_times_default_num_xm_modes(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbtnummodes",
- CBT_DEFAULT_NUM_XM_MODES,
- CBT_MIN_NUM_XM_MODES,
- CBT_MAX_NUM_XM_MODES);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_default_num_xm_modes() called, cbtnummodes"
- " is %d",
- num);
- }
-
- return num;
-}
-
-/**
- * Retrieve and bounds-check the cbtmincircs consensus paramter.
- *
- * Effect: This is the minimum number of circuits to build before
- * computing a timeout.
- */
-static int32_t
-circuit_build_times_min_circs_to_observe(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbtmincircs",
- CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE,
- CBT_MIN_MIN_CIRCUITS_TO_OBSERVE,
- CBT_MAX_MIN_CIRCUITS_TO_OBSERVE);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_min_circs_to_observe() called, cbtmincircs"
- " is %d",
- num);
- }
-
- return num;
-}
-
-/** Return true iff <b>cbt</b> has recorded enough build times that we
- * want to start acting on the timeout it implies. */
-int
-circuit_build_times_enough_to_compute(circuit_build_times_t *cbt)
-{
- return cbt->total_build_times >= circuit_build_times_min_circs_to_observe();
-}
-
-/**
- * Retrieve and bounds-check the cbtquantile consensus paramter.
- *
- * Effect: This is the position on the quantile curve to use to set the
- * timeout value. It is a percent (10-99).
- */
-double
-circuit_build_times_quantile_cutoff(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbtquantile",
- CBT_DEFAULT_QUANTILE_CUTOFF,
- CBT_MIN_QUANTILE_CUTOFF,
- CBT_MAX_QUANTILE_CUTOFF);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_quantile_cutoff() called, cbtquantile"
- " is %d",
- num);
- }
-
- return num/100.0;
-}
-
-/* DOCDOC circuit_build_times_get_bw_scale */
-int
-circuit_build_times_get_bw_scale(networkstatus_t *ns)
-{
- return networkstatus_get_param(ns, "bwweightscale",
- BW_WEIGHT_SCALE,
- BW_MIN_WEIGHT_SCALE,
- BW_MAX_WEIGHT_SCALE);
-}
-
-/**
- * Retrieve and bounds-check the cbtclosequantile consensus paramter.
- *
- * Effect: This is the position on the quantile curve to use to set the
- * timeout value to use to actually close circuits. It is a percent
- * (0-99).
- */
-static double
-circuit_build_times_close_quantile(void)
-{
- int32_t param;
- /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */
- int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff());
- param = networkstatus_get_param(NULL, "cbtclosequantile",
- CBT_DEFAULT_CLOSE_QUANTILE,
- CBT_MIN_CLOSE_QUANTILE,
- CBT_MAX_CLOSE_QUANTILE);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_close_quantile() called, cbtclosequantile"
- " is %d", param);
- }
-
- if (param < min) {
- log_warn(LD_DIR, "Consensus parameter cbtclosequantile is "
- "too small, raising to %d", min);
- param = min;
- }
- return param / 100.0;
-}
-
-/**
- * Retrieve and bounds-check the cbttestfreq consensus paramter.
- *
- * Effect: Describes how often in seconds to build a test circuit to
- * gather timeout values. Only applies if less than 'cbtmincircs'
- * have been recorded.
- */
-static int32_t
-circuit_build_times_test_frequency(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbttestfreq",
- CBT_DEFAULT_TEST_FREQUENCY,
- CBT_MIN_TEST_FREQUENCY,
- CBT_MAX_TEST_FREQUENCY);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_test_frequency() called, cbttestfreq is %d",
- num);
- }
-
- return num;
-}
-
-/**
- * Retrieve and bounds-check the cbtmintimeout consensus parameter.
- *
- * Effect: This is the minimum allowed timeout value in milliseconds.
- * The minimum is to prevent rounding to 0 (we only check once
- * per second).
- */
-static int32_t
-circuit_build_times_min_timeout(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbtmintimeout",
- CBT_DEFAULT_TIMEOUT_MIN_VALUE,
- CBT_MIN_TIMEOUT_MIN_VALUE,
- CBT_MAX_TIMEOUT_MIN_VALUE);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_min_timeout() called, cbtmintimeout is %d",
- num);
- }
-
- return num;
-}
-
-/**
- * Retrieve and bounds-check the cbtinitialtimeout consensus paramter.
- *
- * Effect: This is the timeout value to use before computing a timeout,
- * in milliseconds.
- */
-int32_t
-circuit_build_times_initial_timeout(void)
-{
- int32_t min = circuit_build_times_min_timeout();
- int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout",
- CBT_DEFAULT_TIMEOUT_INITIAL_VALUE,
- CBT_MIN_TIMEOUT_INITIAL_VALUE,
- CBT_MAX_TIMEOUT_INITIAL_VALUE);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_initial_timeout() called, "
- "cbtinitialtimeout is %d",
- param);
- }
-
- if (param < min) {
- log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, "
- "raising to %d", min);
- param = min;
- }
- return param;
-}
-
-/**
- * Retrieve and bounds-check the cbtrecentcount consensus paramter.
- *
- * Effect: This is the number of circuit build times to keep track of
- * for deciding if we hit cbtmaxtimeouts and need to reset our state
- * and learn a new timeout.
- */
-static int32_t
-circuit_build_times_recent_circuit_count(networkstatus_t *ns)
-{
- int32_t num;
- num = networkstatus_get_param(ns, "cbtrecentcount",
- CBT_DEFAULT_RECENT_CIRCUITS,
- CBT_MIN_RECENT_CIRCUITS,
- CBT_MAX_RECENT_CIRCUITS);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_recent_circuit_count() called, "
- "cbtrecentcount is %d",
- num);
- }
-
- return num;
-}
-
-/**
- * This function is called when we get a consensus update.
- *
- * It checks to see if we have changed any consensus parameters
- * that require reallocation or discard of previous stats.
- */
-void
-circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
- networkstatus_t *ns)
-{
- int32_t num;
-
- /*
- * First check if we're doing adaptive timeouts at all; nothing to
- * update if we aren't.
- */
-
- if (!circuit_build_times_disabled()) {
- num = circuit_build_times_recent_circuit_count(ns);
-
- if (num > 0) {
- if (num != cbt->liveness.num_recent_circs) {
- int8_t *recent_circs;
- log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many "
- "circuits we must track to detect network failures from %d "
- "to %d.", cbt->liveness.num_recent_circs, num);
-
- tor_assert(cbt->liveness.timeouts_after_firsthop ||
- cbt->liveness.num_recent_circs == 0);
-
- /*
- * Technically this is a circular array that we are reallocating
- * and memcopying. However, since it only consists of either 1s
- * or 0s, and is only used in a statistical test to determine when
- * we should discard our history after a sufficient number of 1's
- * have been reached, it is fine if order is not preserved or
- * elements are lost.
- *
- * cbtrecentcount should only be changing in cases of severe network
- * distress anyway, so memory correctness here is paramount over
- * doing acrobatics to preserve the array.
- */
- recent_circs = tor_malloc_zero(sizeof(int8_t)*num);
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop,
- sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs));
- }
-
- // Adjust the index if it needs it.
- if (num < cbt->liveness.num_recent_circs) {
- cbt->liveness.after_firsthop_idx = MIN(num-1,
- cbt->liveness.after_firsthop_idx);
- }
-
- tor_free(cbt->liveness.timeouts_after_firsthop);
- cbt->liveness.timeouts_after_firsthop = recent_circs;
- cbt->liveness.num_recent_circs = num;
- }
- /* else no change, nothing to do */
- } else { /* num == 0 */
- /*
- * Weird. This probably shouldn't happen, so log a warning, but try
- * to do something sensible anyway.
- */
-
- log_warn(LD_CIRC,
- "The cbtrecentcircs consensus parameter came back zero! "
- "This disables adaptive timeouts since we can't keep track of "
- "any recent circuits.");
-
- circuit_build_times_free_timeouts(cbt);
- }
- } else {
- /*
- * Adaptive timeouts are disabled; this might be because of the
- * LearnCircuitBuildTimes config parameter, and hence permanent, or
- * the cbtdisabled consensus parameter, so it may be a new condition.
- * Treat it like getting num == 0 above and free the circuit history
- * if we have any.
- */
-
- circuit_build_times_free_timeouts(cbt);
- }
-}
-
-/** Make a note that we're running unit tests (rather than running Tor
- * itself), so we avoid clobbering our state file. */
-void
-circuitbuild_running_unit_tests(void)
-{
- unit_tests = 1;
-}
-
-/**
- * Return the initial default or configured timeout in milliseconds
- */
-static double
-circuit_build_times_get_initial_timeout(void)
-{
- double timeout;
-
- /*
- * Check if we have LearnCircuitBuildTimeout, and if we don't,
- * always use CircuitBuildTimeout, no questions asked.
- */
- if (get_options()->LearnCircuitBuildTimeout) {
- if (!unit_tests && get_options()->CircuitBuildTimeout) {
- timeout = get_options()->CircuitBuildTimeout*1000;
- if (timeout < circuit_build_times_min_timeout()) {
- log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds",
- circuit_build_times_min_timeout()/1000);
- timeout = circuit_build_times_min_timeout();
- }
- } else {
- timeout = circuit_build_times_initial_timeout();
- }
- } else {
- timeout = get_options()->CircuitBuildTimeout*1000;
- }
-
- return timeout;
-}
-
-/**
- * Reset the build time state.
- *
- * Leave estimated parameters, timeout and network liveness intact
- * for future use.
- */
-void
-circuit_build_times_reset(circuit_build_times_t *cbt)
-{
- memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times));
- cbt->total_build_times = 0;
- cbt->build_times_idx = 0;
- cbt->have_computed_timeout = 0;
-}
-
-/**
- * Initialize the buildtimes structure for first use.
- *
- * Sets the initial timeout values based on either the config setting,
- * the consensus param, or the default (CBT_DEFAULT_TIMEOUT_INITIAL_VALUE).
- */
-void
-circuit_build_times_init(circuit_build_times_t *cbt)
-{
- memset(cbt, 0, sizeof(*cbt));
- /*
- * Check if we really are using adaptive timeouts, and don't keep
- * track of this stuff if not.
- */
- if (!circuit_build_times_disabled()) {
- cbt->liveness.num_recent_circs =
- circuit_build_times_recent_circuit_count(NULL);
- cbt->liveness.timeouts_after_firsthop =
- tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs);
- } else {
- cbt->liveness.num_recent_circs = 0;
- cbt->liveness.timeouts_after_firsthop = NULL;
- }
- cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout();
- control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
-}
-
-/**
- * Free the saved timeouts, if the cbtdisabled consensus parameter got turned
- * on or something.
- */
-
-void
-circuit_build_times_free_timeouts(circuit_build_times_t *cbt)
-{
- if (!cbt) return;
-
- if (cbt->liveness.timeouts_after_firsthop) {
- tor_free(cbt->liveness.timeouts_after_firsthop);
- }
-
- cbt->liveness.num_recent_circs = 0;
-}
-
-#if 0
-/**
- * Rewind our build time history by n positions.
+/** This function tries to get a channel to the specified endpoint,
+ * and then calls command_setup_channel() to give it the right
+ * callbacks.
*/
-static void
-circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
+static channel_t *
+channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest)
{
- int i = 0;
-
- cbt->build_times_idx -= n;
- cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE;
-
- for (i = 0; i < n; i++) {
- cbt->circuit_build_times[(i+cbt->build_times_idx)
- %CBT_NCIRCUITS_TO_OBSERVE]=0;
- }
+ channel_t *chan;
- if (cbt->total_build_times > n) {
- cbt->total_build_times -= n;
- } else {
- cbt->total_build_times = 0;
- }
+ chan = channel_connect(addr, port, id_digest);
+ if (chan) command_setup_channel(chan);
- log_info(LD_CIRC,
- "Rewound history by %d places. Current index: %d. "
- "Total: %d", n, cbt->build_times_idx, cbt->total_build_times);
-}
-#endif
-
-/**
- * Add a new build time value <b>time</b> to the set of build times. Time
- * units are milliseconds.
- *
- * circuit_build_times <b>cbt</b> is a circular array, so loop around when
- * array is full.
- */
-int
-circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
-{
- if (time <= 0 || time > CBT_BUILD_TIME_MAX) {
- log_warn(LD_BUG, "Circuit build time is too large (%u)."
- "This is probably a bug.", time);
- tor_fragile_assert();
- return -1;
- }
-
- log_debug(LD_CIRC, "Adding circuit build time %u", time);
-
- cbt->circuit_build_times[cbt->build_times_idx] = time;
- cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE;
- if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
- cbt->total_build_times++;
-
- if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) {
- /* Save state every n circuit builds */
- if (!unit_tests && !get_options()->AvoidDiskWrites)
- or_state_mark_dirty(get_or_state(), 0);
- }
-
- return 0;
-}
-
-/**
- * Return maximum circuit build time
- */
-static build_time_t
-circuit_build_times_max(circuit_build_times_t *cbt)
-{
- int i = 0;
- build_time_t max_build_time = 0;
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] > max_build_time
- && cbt->circuit_build_times[i] != CBT_BUILD_ABANDONED)
- max_build_time = cbt->circuit_build_times[i];
- }
- return max_build_time;
-}
-
-#if 0
-/** Return minimum circuit build time */
-build_time_t
-circuit_build_times_min(circuit_build_times_t *cbt)
-{
- int i = 0;
- build_time_t min_build_time = CBT_BUILD_TIME_MAX;
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */
- cbt->circuit_build_times[i] < min_build_time)
- min_build_time = cbt->circuit_build_times[i];
- }
- if (min_build_time == CBT_BUILD_TIME_MAX) {
- log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!");
- }
- return min_build_time;
-}
-#endif
-
-/**
- * Calculate and return a histogram for the set of build times.
- *
- * Returns an allocated array of histrogram bins representing
- * the frequency of index*CBT_BIN_WIDTH millisecond
- * build times. Also outputs the number of bins in nbins.
- *
- * The return value must be freed by the caller.
- */
-static uint32_t *
-circuit_build_times_create_histogram(circuit_build_times_t *cbt,
- build_time_t *nbins)
-{
- uint32_t *histogram;
- build_time_t max_build_time = circuit_build_times_max(cbt);
- int i, c;
-
- *nbins = 1 + (max_build_time / CBT_BIN_WIDTH);
- histogram = tor_malloc_zero(*nbins * sizeof(build_time_t));
-
- // calculate histogram
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] == 0
- || cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED)
- continue; /* 0 <-> uninitialized */
-
- c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH);
- histogram[c]++;
- }
-
- return histogram;
-}
-
-/**
- * Return the Pareto start-of-curve parameter Xm.
- *
- * Because we are not a true Pareto curve, we compute this as the
- * weighted average of the N most frequent build time bins. N is either
- * 1 if we don't have enough circuit build time data collected, or
- * determined by the consensus parameter cbtnummodes (default 3).
- */
-static build_time_t
-circuit_build_times_get_xm(circuit_build_times_t *cbt)
-{
- build_time_t i, nbins;
- build_time_t *nth_max_bin;
- int32_t bin_counts=0;
- build_time_t ret = 0;
- uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins);
- int n=0;
- int num_modes = circuit_build_times_default_num_xm_modes();
-
- tor_assert(nbins > 0);
- tor_assert(num_modes > 0);
-
- // Only use one mode if < 1000 buildtimes. Not enough data
- // for multiple.
- if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
- num_modes = 1;
-
- nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t));
-
- /* Determine the N most common build times */
- for (i = 0; i < nbins; i++) {
- if (histogram[i] >= histogram[nth_max_bin[0]]) {
- nth_max_bin[0] = i;
- }
-
- for (n = 1; n < num_modes; n++) {
- if (histogram[i] >= histogram[nth_max_bin[n]] &&
- (!histogram[nth_max_bin[n-1]]
- || histogram[i] < histogram[nth_max_bin[n-1]])) {
- nth_max_bin[n] = i;
- }
- }
- }
-
- for (n = 0; n < num_modes; n++) {
- bin_counts += histogram[nth_max_bin[n]];
- ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]];
- log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]),
- histogram[nth_max_bin[n]]);
- }
-
- /* The following assert is safe, because we don't get called when we
- * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */
- tor_assert(bin_counts > 0);
-
- ret /= bin_counts;
- tor_free(histogram);
- tor_free(nth_max_bin);
-
- return ret;
-}
-
-/**
- * Output a histogram of current circuit build times to
- * the or_state_t state structure.
- */
-void
-circuit_build_times_update_state(circuit_build_times_t *cbt,
- or_state_t *state)
-{
- uint32_t *histogram;
- build_time_t i = 0;
- build_time_t nbins = 0;
- config_line_t **next, *line;
-
- histogram = circuit_build_times_create_histogram(cbt, &nbins);
- // write to state
- config_free_lines(state->BuildtimeHistogram);
- next = &state->BuildtimeHistogram;
- *next = NULL;
-
- state->TotalBuildTimes = cbt->total_build_times;
- state->CircuitBuildAbandonedCount = 0;
-
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED)
- state->CircuitBuildAbandonedCount++;
- }
-
- for (i = 0; i < nbins; i++) {
- // compress the histogram by skipping the blanks
- if (histogram[i] == 0) continue;
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("CircuitBuildTimeBin");
- tor_asprintf(&line->value, "%d %d",
- CBT_BIN_TO_MS(i), histogram[i]);
- next = &(line->next);
- }
-
- if (!unit_tests) {
- if (!get_options()->AvoidDiskWrites)
- or_state_mark_dirty(get_or_state(), 0);
- }
-
- tor_free(histogram);
-}
-
-/**
- * Shuffle the build times array.
- *
- * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
- */
-static void
-circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
- build_time_t *raw_times,
- uint32_t num_times)
-{
- uint32_t n = num_times;
- if (num_times > CBT_NCIRCUITS_TO_OBSERVE) {
- log_notice(LD_CIRC, "The number of circuit times that this Tor version "
- "uses to calculate build times is less than the number stored "
- "in your state file. Decreasing the circuit time history from "
- "%lu to %d.", (unsigned long)num_times,
- CBT_NCIRCUITS_TO_OBSERVE);
- }
-
- if (n > INT_MAX-1) {
- log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build "
- "observations in your state file. That's far too many; probably "
- "there's a bug here.", (unsigned long)n);
- n = INT_MAX-1;
- }
-
- /* This code can only be run on a compact array */
- while (n-- > 1) {
- int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */
- build_time_t tmp = raw_times[k];
- raw_times[k] = raw_times[n];
- raw_times[n] = tmp;
- }
-
- /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE
- * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */
- for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) {
- circuit_build_times_add_time(cbt, raw_times[n]);
- }
-}
-
-/**
- * Filter old synthetic timeouts that were created before the
- * new right-censored Pareto calculation was deployed.
- *
- * Once all clients before 0.2.1.13-alpha are gone, this code
- * will be unused.
- */
-static int
-circuit_build_times_filter_timeouts(circuit_build_times_t *cbt)
-{
- int num_filtered=0, i=0;
- double timeout_rate = 0;
- build_time_t max_timeout = 0;
-
- timeout_rate = circuit_build_times_timeout_rate(cbt);
- max_timeout = (build_time_t)cbt->close_ms;
-
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] > max_timeout) {
- build_time_t replaced = cbt->circuit_build_times[i];
- num_filtered++;
- cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED;
-
- log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced,
- cbt->circuit_build_times[i]);
- }
- }
-
- log_info(LD_CIRC,
- "We had %d timeouts out of %d build times, "
- "and filtered %d above the max of %u",
- (int)(cbt->total_build_times*timeout_rate),
- cbt->total_build_times, num_filtered, max_timeout);
-
- return num_filtered;
-}
-
-/**
- * Load histogram from <b>state</b>, shuffling the resulting array
- * after we do so. Use this result to estimate parameters and
- * calculate the timeout.
- *
- * Return -1 on error.
- */
-int
-circuit_build_times_parse_state(circuit_build_times_t *cbt,
- or_state_t *state)
-{
- int tot_values = 0;
- uint32_t loaded_cnt = 0, N = 0;
- config_line_t *line;
- unsigned int i;
- build_time_t *loaded_times;
- int err = 0;
- circuit_build_times_init(cbt);
-
- if (circuit_build_times_disabled()) {
- return 0;
- }
-
- /* build_time_t 0 means uninitialized */
- loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes);
-
- for (line = state->BuildtimeHistogram; line; line = line->next) {
- smartlist_t *args = smartlist_new();
- smartlist_split_string(args, line->value, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- if (smartlist_len(args) < 2) {
- log_warn(LD_GENERAL, "Unable to parse circuit build times: "
- "Too few arguments to CircuitBuildTime");
- err = 1;
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- break;
- } else {
- const char *ms_str = smartlist_get(args,0);
- const char *count_str = smartlist_get(args,1);
- uint32_t count, k;
- build_time_t ms;
- int ok;
- ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0,
- CBT_BUILD_TIME_MAX, &ok, NULL);
- if (!ok) {
- log_warn(LD_GENERAL, "Unable to parse circuit build times: "
- "Unparsable bin number");
- err = 1;
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- break;
- }
- count = (uint32_t)tor_parse_ulong(count_str, 0, 0,
- UINT32_MAX, &ok, NULL);
- if (!ok) {
- log_warn(LD_GENERAL, "Unable to parse circuit build times: "
- "Unparsable bin count");
- err = 1;
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- break;
- }
-
- if (loaded_cnt+count+state->CircuitBuildAbandonedCount
- > state->TotalBuildTimes) {
- log_warn(LD_CIRC,
- "Too many build times in state file. "
- "Stopping short before %d",
- loaded_cnt+count);
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- break;
- }
-
- for (k = 0; k < count; k++) {
- loaded_times[loaded_cnt++] = ms;
- }
- N++;
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- }
- }
-
- log_info(LD_CIRC,
- "Adding %d timeouts.", state->CircuitBuildAbandonedCount);
- for (i=0; i < state->CircuitBuildAbandonedCount; i++) {
- loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED;
- }
-
- if (loaded_cnt != state->TotalBuildTimes) {
- log_warn(LD_CIRC,
- "Corrupt state file? Build times count mismatch. "
- "Read %d times, but file says %d", loaded_cnt,
- state->TotalBuildTimes);
- err = 1;
- circuit_build_times_reset(cbt);
- goto done;
- }
-
- circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt);
-
- /* Verify that we didn't overwrite any indexes */
- for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (!cbt->circuit_build_times[i])
- break;
- tot_values++;
- }
- log_info(LD_CIRC,
- "Loaded %d/%d values from %d lines in circuit time histogram",
- tot_values, cbt->total_build_times, N);
-
- if (cbt->total_build_times != tot_values
- || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) {
- log_warn(LD_CIRC,
- "Corrupt state file? Shuffled build times mismatch. "
- "Read %d times, but file says %d", tot_values,
- state->TotalBuildTimes);
- err = 1;
- circuit_build_times_reset(cbt);
- goto done;
- }
-
- circuit_build_times_set_timeout(cbt);
-
- if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) {
- circuit_build_times_filter_timeouts(cbt);
- }
-
- done:
- tor_free(loaded_times);
- return err ? -1 : 0;
-}
-
-/**
- * Estimates the Xm and Alpha parameters using
- * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation
- *
- * The notable difference is that we use mode instead of min to estimate Xm.
- * This is because our distribution is frechet-like. We claim this is
- * an acceptable approximation because we are only concerned with the
- * accuracy of the CDF of the tail.
- */
-int
-circuit_build_times_update_alpha(circuit_build_times_t *cbt)
-{
- build_time_t *x=cbt->circuit_build_times;
- double a = 0;
- int n=0,i=0,abandoned_count=0;
- build_time_t max_time=0;
-
- /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
- /* We sort of cheat here and make our samples slightly more pareto-like
- * and less frechet-like. */
- cbt->Xm = circuit_build_times_get_xm(cbt);
-
- tor_assert(cbt->Xm > 0);
-
- for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (!x[i]) {
- continue;
- }
-
- if (x[i] < cbt->Xm) {
- a += tor_mathlog(cbt->Xm);
- } else if (x[i] == CBT_BUILD_ABANDONED) {
- abandoned_count++;
- } else {
- a += tor_mathlog(x[i]);
- if (x[i] > max_time)
- max_time = x[i];
- }
- n++;
- }
-
- /*
- * We are erring and asserting here because this can only happen
- * in codepaths other than startup. The startup state parsing code
- * performs this same check, and resets state if it hits it. If we
- * hit it at runtime, something serious has gone wrong.
- */
- if (n!=cbt->total_build_times) {
- log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n,
- cbt->total_build_times);
- }
- tor_assert(n==cbt->total_build_times);
-
- if (max_time <= 0) {
- /* This can happen if Xm is actually the *maximum* value in the set.
- * It can also happen if we've abandoned every single circuit somehow.
- * In either case, tell the caller not to compute a new build timeout. */
- log_warn(LD_BUG,
- "Could not determine largest build time (%d). "
- "Xm is %dms and we've abandoned %d out of %d circuits.", max_time,
- cbt->Xm, abandoned_count, n);
- return 0;
- }
-
- a += abandoned_count*tor_mathlog(max_time);
-
- a -= n*tor_mathlog(cbt->Xm);
- // Estimator comes from Eq #4 in:
- // "Bayesian estimation based on trimmed samples from Pareto populations"
- // by Arturo J. Fernández. We are right-censored only.
- a = (n-abandoned_count)/a;
-
- cbt->alpha = a;
-
- return 1;
-}
-
-/**
- * This is the Pareto Quantile Function. It calculates the point x
- * in the distribution such that F(x) = quantile (ie quantile*100%
- * of the mass of the density function is below x on the curve).
- *
- * We use it to calculate the timeout and also to generate synthetic
- * values of time for circuits that timeout before completion.
- *
- * See http://en.wikipedia.org/wiki/Quantile_function,
- * http://en.wikipedia.org/wiki/Inverse_transform_sampling and
- * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_
- * random_sample_from_Pareto_distribution
- * That's right. I'll cite wikipedia all day long.
- *
- * Return value is in milliseconds.
- */
-double
-circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
- double quantile)
-{
- double ret;
- tor_assert(quantile >= 0);
- tor_assert(1.0-quantile > 0);
- tor_assert(cbt->Xm > 0);
-
- ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha);
- if (ret > INT32_MAX) {
- ret = INT32_MAX;
- }
- tor_assert(ret > 0);
- return ret;
-}
-
-/** Pareto CDF */
-double
-circuit_build_times_cdf(circuit_build_times_t *cbt, double x)
-{
- double ret;
- tor_assert(cbt->Xm > 0);
- ret = 1.0-pow(cbt->Xm/x,cbt->alpha);
- tor_assert(0 <= ret && ret <= 1.0);
- return ret;
-}
-
-/**
- * Generate a synthetic time using our distribution parameters.
- *
- * The return value will be within the [q_lo, q_hi) quantile points
- * on the CDF.
- */
-build_time_t
-circuit_build_times_generate_sample(circuit_build_times_t *cbt,
- double q_lo, double q_hi)
-{
- double randval = crypto_rand_double();
- build_time_t ret;
- double u;
-
- /* Generate between [q_lo, q_hi) */
- /*XXXX This is what nextafter is supposed to be for; we should use it on the
- * platforms that support it. */
- q_hi -= 1.0/(INT32_MAX);
-
- tor_assert(q_lo >= 0);
- tor_assert(q_hi < 1);
- tor_assert(q_lo < q_hi);
-
- u = q_lo + (q_hi-q_lo)*randval;
-
- tor_assert(0 <= u && u < 1.0);
- /* circuit_build_times_calculate_timeout returns <= INT32_MAX */
- ret = (build_time_t)
- tor_lround(circuit_build_times_calculate_timeout(cbt, u));
- tor_assert(ret > 0);
- return ret;
-}
-
-/**
- * Estimate an initial alpha parameter by solving the quantile
- * function with a quantile point and a specific timeout value.
- */
-void
-circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
- double quantile, double timeout_ms)
-{
- // Q(u) = Xm/((1-u)^(1/a))
- // Q(0.8) = Xm/((1-0.8))^(1/a)) = CircBuildTimeout
- // CircBuildTimeout = Xm/((1-0.8))^(1/a))
- // CircBuildTimeout = Xm*((1-0.8))^(-1/a))
- // ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a)
- // -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a
- tor_assert(quantile >= 0);
- tor_assert(cbt->Xm > 0);
- cbt->alpha = tor_mathlog(1.0-quantile)/
- (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms));
- tor_assert(cbt->alpha > 0);
-}
-
-/**
- * Returns true if we need circuits to be built
- */
-int
-circuit_build_times_needs_circuits(circuit_build_times_t *cbt)
-{
- /* Return true if < MIN_CIRCUITS_TO_OBSERVE */
- return !circuit_build_times_enough_to_compute(cbt);
-}
-
-/**
- * Returns true if we should build a timeout test circuit
- * right now.
- */
-int
-circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt)
-{
- return circuit_build_times_needs_circuits(cbt) &&
- approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency();
-}
-
-/**
- * Called to indicate that the network showed some signs of liveness,
- * i.e. we received a cell.
- *
- * This is used by circuit_build_times_network_check_live() to decide
- * if we should record the circuit build timeout or not.
- *
- * This function is called every time we receive a cell. Avoid
- * syscalls, events, and other high-intensity work.
- */
-void
-circuit_build_times_network_is_live(circuit_build_times_t *cbt)
-{
- time_t now = approx_time();
- if (cbt->liveness.nonlive_timeouts > 0) {
- log_notice(LD_CIRC,
- "Tor now sees network activity. Restoring circuit build "
- "timeout recording. Network was down for %d seconds "
- "during %d circuit attempts.",
- (int)(now - cbt->liveness.network_last_live),
- cbt->liveness.nonlive_timeouts);
- }
- cbt->liveness.network_last_live = now;
- cbt->liveness.nonlive_timeouts = 0;
-}
-
-/**
- * Called to indicate that we completed a circuit. Because this circuit
- * succeeded, it doesn't count as a timeout-after-the-first-hop.
- *
- * This is used by circuit_build_times_network_check_changed() to determine
- * if we had too many recent timeouts and need to reset our learned timeout
- * to something higher.
- */
-void
-circuit_build_times_network_circ_success(circuit_build_times_t *cbt)
-{
- /* Check for NULLness because we might not be using adaptive timeouts */
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]
- = 0;
- cbt->liveness.after_firsthop_idx++;
- cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
- }
-}
-
-/**
- * A circuit just timed out. If it failed after the first hop, record it
- * in our history for later deciding if the network speed has changed.
- *
- * This is used by circuit_build_times_network_check_changed() to determine
- * if we had too many recent timeouts and need to reset our learned timeout
- * to something higher.
- */
-static void
-circuit_build_times_network_timeout(circuit_build_times_t *cbt,
- int did_onehop)
-{
- /* Check for NULLness because we might not be using adaptive timeouts */
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- if (did_onehop) {
- cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]
- = 1;
- cbt->liveness.after_firsthop_idx++;
- cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
- }
- }
-}
-
-/**
- * A circuit was just forcibly closed. If there has been no recent network
- * activity at all, but this circuit was launched back when we thought the
- * network was live, increment the number of "nonlive" circuit timeouts.
- *
- * This is used by circuit_build_times_network_check_live() to decide
- * if we should record the circuit build timeout or not.
- */
-static void
-circuit_build_times_network_close(circuit_build_times_t *cbt,
- int did_onehop, time_t start_time)
-{
- time_t now = time(NULL);
- /*
- * Check if this is a timeout that was for a circuit that spent its
- * entire existence during a time where we have had no network activity.
- */
- if (cbt->liveness.network_last_live < start_time) {
- if (did_onehop) {
- char last_live_buf[ISO_TIME_LEN+1];
- char start_time_buf[ISO_TIME_LEN+1];
- char now_buf[ISO_TIME_LEN+1];
- format_local_iso_time(last_live_buf, cbt->liveness.network_last_live);
- format_local_iso_time(start_time_buf, start_time);
- format_local_iso_time(now_buf, now);
- log_warn(LD_BUG,
- "Circuit somehow completed a hop while the network was "
- "not live. Network was last live at %s, but circuit launched "
- "at %s. It's now %s.", last_live_buf, start_time_buf,
- now_buf);
- }
- cbt->liveness.nonlive_timeouts++;
- if (cbt->liveness.nonlive_timeouts == 1) {
- log_notice(LD_CIRC,
- "Tor has not observed any network activity for the past %d "
- "seconds. Disabling circuit build timeout recording.",
- (int)(now - cbt->liveness.network_last_live));
- } else {
- log_info(LD_CIRC,
- "Got non-live timeout. Current count is: %d",
- cbt->liveness.nonlive_timeouts);
- }
- }
-}
-
-/**
- * When the network is not live, we do not record circuit build times.
- *
- * The network is considered not live if there has been at least one
- * circuit build that began and ended (had its close_ms measurement
- * period expire) since we last received a cell.
- *
- * Also has the side effect of rewinding the circuit time history
- * in the case of recent liveness changes.
- */
-int
-circuit_build_times_network_check_live(circuit_build_times_t *cbt)
-{
- if (cbt->liveness.nonlive_timeouts > 0) {
- return 0;
- }
-
- return 1;
-}
-
-/**
- * Returns true if we have seen more than MAX_RECENT_TIMEOUT_COUNT of
- * the past RECENT_CIRCUITS time out after the first hop. Used to detect
- * if the network connection has changed significantly, and if so,
- * resets our circuit build timeout to the default.
- *
- * Also resets the entire timeout history in this case and causes us
- * to restart the process of building test circuits and estimating a
- * new timeout.
- */
-int
-circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
-{
- int total_build_times = cbt->total_build_times;
- int timeout_count=0;
- int i;
-
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- /* how many of our recent circuits made it to the first hop but then
- * timed out? */
- for (i = 0; i < cbt->liveness.num_recent_circs; i++) {
- timeout_count += cbt->liveness.timeouts_after_firsthop[i];
- }
- }
-
- /* If 80% of our recent circuits are timing out after the first hop,
- * we need to re-estimate a new initial alpha and timeout. */
- if (timeout_count < circuit_build_times_max_timeouts()) {
- return 0;
- }
-
- circuit_build_times_reset(cbt);
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- memset(cbt->liveness.timeouts_after_firsthop, 0,
- sizeof(*cbt->liveness.timeouts_after_firsthop)*
- cbt->liveness.num_recent_circs);
- }
- cbt->liveness.after_firsthop_idx = 0;
-
- /* Check to see if this has happened before. If so, double the timeout
- * to give people on abysmally bad network connections a shot at access */
- if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) {
- if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) {
- log_warn(LD_CIRC, "Insanely large circuit build timeout value. "
- "(timeout = %fmsec, close = %fmsec)",
- cbt->timeout_ms, cbt->close_ms);
- } else {
- cbt->timeout_ms *= 2;
- cbt->close_ms *= 2;
- }
- } else {
- cbt->close_ms = cbt->timeout_ms
- = circuit_build_times_get_initial_timeout();
- }
-
- control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
-
- log_notice(LD_CIRC,
- "Your network connection speed appears to have changed. Resetting "
- "timeout to %lds after %d timeouts and %d buildtimes.",
- tor_lround(cbt->timeout_ms/1000), timeout_count,
- total_build_times);
-
- return 1;
-}
-
-/**
- * Count the number of timeouts in a set of cbt data.
- */
-double
-circuit_build_times_timeout_rate(const circuit_build_times_t *cbt)
-{
- int i=0,timeouts=0;
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] >= cbt->timeout_ms) {
- timeouts++;
- }
- }
-
- if (!cbt->total_build_times)
- return 0;
-
- return ((double)timeouts)/cbt->total_build_times;
-}
-
-/**
- * Count the number of closed circuits in a set of cbt data.
- */
-double
-circuit_build_times_close_rate(const circuit_build_times_t *cbt)
-{
- int i=0,closed=0;
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) {
- closed++;
- }
- }
-
- if (!cbt->total_build_times)
- return 0;
-
- return ((double)closed)/cbt->total_build_times;
-}
-
-/**
- * Store a timeout as a synthetic value.
- *
- * Returns true if the store was successful and we should possibly
- * update our timeout estimate.
- */
-int
-circuit_build_times_count_close(circuit_build_times_t *cbt,
- int did_onehop,
- time_t start_time)
-{
- if (circuit_build_times_disabled()) {
- cbt->close_ms = cbt->timeout_ms
- = circuit_build_times_get_initial_timeout();
- return 0;
- }
-
- /* Record this force-close to help determine if the network is dead */
- circuit_build_times_network_close(cbt, did_onehop, start_time);
-
- /* Only count timeouts if network is live.. */
- if (!circuit_build_times_network_check_live(cbt)) {
- return 0;
- }
-
- circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED);
- return 1;
-}
-
-/**
- * Update timeout counts to determine if we need to expire
- * our build time history due to excessive timeouts.
- *
- * We do not record any actual time values at this stage;
- * we are only interested in recording the fact that a timeout
- * happened. We record the time values via
- * circuit_build_times_count_close() and circuit_build_times_add_time().
- */
-void
-circuit_build_times_count_timeout(circuit_build_times_t *cbt,
- int did_onehop)
-{
- if (circuit_build_times_disabled()) {
- cbt->close_ms = cbt->timeout_ms
- = circuit_build_times_get_initial_timeout();
- return;
- }
-
- /* Register the fact that a timeout just occurred. */
- circuit_build_times_network_timeout(cbt, did_onehop);
-
- /* If there are a ton of timeouts, we should reset
- * the circuit build timeout. */
- circuit_build_times_network_check_changed(cbt);
-}
-
-/**
- * Estimate a new timeout based on history and set our timeout
- * variable accordingly.
- */
-static int
-circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt)
-{
- build_time_t max_time;
- if (!circuit_build_times_enough_to_compute(cbt))
- return 0;
-
- if (!circuit_build_times_update_alpha(cbt))
- return 0;
-
- cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt,
- circuit_build_times_quantile_cutoff());
-
- cbt->close_ms = circuit_build_times_calculate_timeout(cbt,
- circuit_build_times_close_quantile());
-
- max_time = circuit_build_times_max(cbt);
-
- /* Sometimes really fast guard nodes give us such a steep curve
- * that this ends up being not that much greater than timeout_ms.
- * Make it be at least 1 min to handle this case. */
- cbt->close_ms = MAX(cbt->close_ms, circuit_build_times_initial_timeout());
-
- if (cbt->timeout_ms > max_time) {
- log_info(LD_CIRC,
- "Circuit build timeout of %dms is beyond the maximum build "
- "time we have ever observed. Capping it to %dms.",
- (int)cbt->timeout_ms, max_time);
- cbt->timeout_ms = max_time;
- }
-
- if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) {
- log_info(LD_CIRC,
- "Circuit build measurement period of %dms is more than twice "
- "the maximum build time we have ever observed. Capping it to "
- "%dms.", (int)cbt->close_ms, 2*max_time);
- cbt->close_ms = 2*max_time;
- }
-
- cbt->have_computed_timeout = 1;
- return 1;
-}
-
-/**
- * Exposed function to compute a new timeout. Dispatches events and
- * also filters out extremely high timeout values.
- */
-void
-circuit_build_times_set_timeout(circuit_build_times_t *cbt)
-{
- long prev_timeout = tor_lround(cbt->timeout_ms/1000);
- double timeout_rate;
-
- /*
- * Just return if we aren't using adaptive timeouts
- */
- if (circuit_build_times_disabled())
- return;
-
- if (!circuit_build_times_set_timeout_worker(cbt))
- return;
-
- if (cbt->timeout_ms < circuit_build_times_min_timeout()) {
- log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms",
- cbt->timeout_ms, circuit_build_times_min_timeout());
- cbt->timeout_ms = circuit_build_times_min_timeout();
- if (cbt->close_ms < cbt->timeout_ms) {
- /* This shouldn't happen because of MAX() in timeout_worker above,
- * but doing it just in case */
- cbt->close_ms = circuit_build_times_initial_timeout();
- }
- }
-
- control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED);
-
- timeout_rate = circuit_build_times_timeout_rate(cbt);
-
- if (prev_timeout > tor_lround(cbt->timeout_ms/1000)) {
- log_info(LD_CIRC,
- "Based on %d circuit times, it looks like we don't need to "
- "wait so long for circuits to finish. We will now assume a "
- "circuit is too slow to use after waiting %ld seconds.",
- cbt->total_build_times,
- tor_lround(cbt->timeout_ms/1000));
- log_info(LD_CIRC,
- "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
- cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
- timeout_rate);
- } else if (prev_timeout < tor_lround(cbt->timeout_ms/1000)) {
- log_info(LD_CIRC,
- "Based on %d circuit times, it looks like we need to wait "
- "longer for circuits to finish. We will now assume a "
- "circuit is too slow to use after waiting %ld seconds.",
- cbt->total_build_times,
- tor_lround(cbt->timeout_ms/1000));
- log_info(LD_CIRC,
- "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
- cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
- timeout_rate);
- } else {
- log_info(LD_CIRC,
- "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f,"
- " r: %f) based on %d circuit times",
- tor_lround(cbt->timeout_ms/1000),
- cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate,
- cbt->total_build_times);
- }
+ return chan;
}
/** Iterate over values of circ_id, starting from conn-\>next_circ_id,
@@ -1680,26 +85,29 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
* Return it, or 0 if can't get a unique circ_id.
*/
static circid_t
-get_unique_circ_id_by_conn(or_connection_t *conn)
+get_unique_circ_id_by_chan(channel_t *chan)
{
circid_t test_circ_id;
circid_t attempts=0;
circid_t high_bit;
- tor_assert(conn);
- if (conn->circ_id_type == CIRC_ID_TYPE_NEITHER) {
- log_warn(LD_BUG, "Trying to pick a circuit ID for a connection from "
+ tor_assert(chan);
+
+ if (chan->circ_id_type == CIRC_ID_TYPE_NEITHER) {
+ log_warn(LD_BUG,
+ "Trying to pick a circuit ID for a connection from "
"a client with no identity.");
return 0;
}
- high_bit = (conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0;
+ high_bit =
+ (chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0;
do {
/* Sequentially iterate over test_circ_id=1...1<<15-1 until we find a
* circID such that (high_bit|test_circ_id) is not already used. */
- test_circ_id = conn->next_circ_id++;
+ test_circ_id = chan->next_circ_id++;
if (test_circ_id == 0 || test_circ_id >= 1<<15) {
test_circ_id = 1;
- conn->next_circ_id = 2;
+ chan->next_circ_id = 2;
}
if (++attempts > 1<<15) {
/* Make sure we don't loop forever if all circ_id's are used. This
@@ -1709,7 +117,7 @@ get_unique_circ_id_by_conn(or_connection_t *conn)
return 0;
}
test_circ_id |= high_bit;
- } while (circuit_id_in_use_on_orconn(test_circ_id, conn));
+ } while (circuit_id_in_use_on_channel(test_circ_id, chan));
return test_circ_id;
}
@@ -1736,8 +144,8 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
circ->build_state->is_internal ? "internal" : "exit",
circ->build_state->need_uptime ? " (high-uptime)" : "",
circ->build_state->desired_path_len,
- circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ",
- circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
+ circ->base_.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ",
+ circ->base_.state == CIRCUIT_STATE_OPEN ? "" :
(nickname?nickname:"*unnamed*"));
}
@@ -1888,9 +296,9 @@ onion_populate_cpath(origin_circuit_t *circ)
origin_circuit_t *
origin_circuit_init(uint8_t purpose, int flags)
{
- /* sets circ->p_circ_id and circ->p_conn */
+ /* sets circ->p_circ_id and circ->p_chan */
origin_circuit_t *circ = origin_circuit_new();
- circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OR_WAIT);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_CHAN_WAIT);
circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
circ->build_state->onehop_tunnel =
((flags & CIRCLAUNCH_ONEHOP_TUNNEL) ? 1 : 0);
@@ -1900,7 +308,7 @@ origin_circuit_init(uint8_t purpose, int flags)
((flags & CIRCLAUNCH_NEED_CAPACITY) ? 1 : 0);
circ->build_state->is_internal =
((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0);
- circ->_base.purpose = purpose;
+ circ->base_.purpose = purpose;
return circ;
}
@@ -1942,7 +350,7 @@ int
circuit_handle_first_hop(origin_circuit_t *circ)
{
crypt_path_t *firsthop;
- or_connection_t *n_conn;
+ channel_t *n_chan;
int err_reason = 0;
const char *msg = NULL;
int should_launch = 0;
@@ -1952,29 +360,30 @@ circuit_handle_first_hop(origin_circuit_t *circ)
tor_assert(firsthop->extend_info);
/* now see if we're already connected to the first OR in 'route' */
- log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",
- fmt_addr(&firsthop->extend_info->addr),
- firsthop->extend_info->port);
+ log_debug(LD_CIRC,"Looking for firsthop '%s'",
+ fmt_addrport(&firsthop->extend_info->addr,
+ firsthop->extend_info->port));
- n_conn = connection_or_get_for_extend(firsthop->extend_info->identity_digest,
- &firsthop->extend_info->addr,
- &msg,
- &should_launch);
+ n_chan = channel_get_for_extend(firsthop->extend_info->identity_digest,
+ &firsthop->extend_info->addr,
+ &msg,
+ &should_launch);
- if (!n_conn) {
+ if (!n_chan) {
/* not currently connected in a useful way. */
log_info(LD_CIRC, "Next router is %s: %s",
safe_str_client(extend_info_describe(firsthop->extend_info)),
msg?msg:"???");
- circ->_base.n_hop = extend_info_dup(firsthop->extend_info);
+ circ->base_.n_hop = extend_info_dup(firsthop->extend_info);
if (should_launch) {
if (circ->build_state->onehop_tunnel)
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
- n_conn = connection_or_connect(&firsthop->extend_info->addr,
- firsthop->extend_info->port,
- firsthop->extend_info->identity_digest);
- if (!n_conn) { /* connect failed, forget the whole thing */
+ n_chan = channel_connect_for_circuit(
+ &firsthop->extend_info->addr,
+ firsthop->extend_info->port,
+ firsthop->extend_info->identity_digest);
+ if (!n_chan) { /* connect failed, forget the whole thing */
log_info(LD_CIRC,"connect to firsthop failed. Closing.");
return -END_CIRC_REASON_CONNECTFAILED;
}
@@ -1982,13 +391,13 @@ circuit_handle_first_hop(origin_circuit_t *circ)
log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
/* return success. The onion/circuit/etc will be taken care of
- * automatically (may already have been) whenever n_conn reaches
+ * automatically (may already have been) whenever n_chan reaches
* OR_CONN_STATE_OPEN.
*/
return 0;
} else { /* it's already open. use it. */
- tor_assert(!circ->_base.n_hop);
- circ->_base.n_conn = n_conn;
+ tor_assert(!circ->base_.n_hop);
+ circ->base_.n_chan = n_chan;
log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
@@ -2004,48 +413,49 @@ circuit_handle_first_hop(origin_circuit_t *circ)
* Status is 1 if connect succeeded, or 0 if connect failed.
*/
void
-circuit_n_conn_done(or_connection_t *or_conn, int status)
+circuit_n_chan_done(channel_t *chan, int status)
{
smartlist_t *pending_circs;
int err_reason = 0;
- log_debug(LD_CIRC,"or_conn to %s/%s, status=%d",
- or_conn->nickname ? or_conn->nickname : "NULL",
- or_conn->_base.address, status);
+ tor_assert(chan);
+
+ log_debug(LD_CIRC,"chan to %s/%s, status=%d",
+ chan->nickname ? chan->nickname : "NULL",
+ channel_get_canonical_remote_descr(chan), status);
pending_circs = smartlist_new();
- circuit_get_all_pending_on_or_conn(pending_circs, or_conn);
+ circuit_get_all_pending_on_channel(pending_circs, chan);
SMARTLIST_FOREACH_BEGIN(pending_circs, circuit_t *, circ)
{
/* These checks are redundant wrt get_all_pending_on_or_conn, but I'm
* leaving them in in case it's possible for the status of a circuit to
* change as we're going down the list. */
- if (circ->marked_for_close || circ->n_conn || !circ->n_hop ||
- circ->state != CIRCUIT_STATE_OR_WAIT)
+ if (circ->marked_for_close || circ->n_chan || !circ->n_hop ||
+ circ->state != CIRCUIT_STATE_CHAN_WAIT)
continue;
if (tor_digest_is_zero(circ->n_hop->identity_digest)) {
/* Look at addr/port. This is an unkeyed connection. */
- if (!tor_addr_eq(&circ->n_hop->addr, &or_conn->_base.addr) ||
- circ->n_hop->port != or_conn->_base.port)
+ if (!channel_matches_extend_info(chan, circ->n_hop))
continue;
} else {
/* We expected a key. See if it's the right one. */
- if (tor_memneq(or_conn->identity_digest,
+ if (tor_memneq(chan->identity_digest,
circ->n_hop->identity_digest, DIGEST_LEN))
continue;
}
- if (!status) { /* or_conn failed; close circ */
- log_info(LD_CIRC,"or_conn failed. Closing circ.");
- circuit_mark_for_close(circ, END_CIRC_REASON_OR_CONN_CLOSED);
+ if (!status) { /* chan failed; close circ */
+ log_info(LD_CIRC,"Channel failed; closing circ.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED);
continue;
}
log_debug(LD_CIRC, "Found circ, sending create cell.");
/* circuit_deliver_create_cell will set n_circ_id and add us to
- * orconn_circuid_circuit_map, so we don't need to call
- * set_circid_orconn here. */
- circ->n_conn = or_conn;
+ * chan_circuid_circuit_map, so we don't need to call
+ * set_circid_chan here. */
+ circ->n_chan = chan;
extend_info_free(circ->n_hop);
circ->n_hop = NULL;
@@ -2061,13 +471,13 @@ circuit_n_conn_done(or_connection_t *or_conn, int status)
}
} else {
/* pull the create cell out of circ->onionskin, and send it */
- tor_assert(circ->n_conn_onionskin);
+ tor_assert(circ->n_chan_onionskin);
if (circuit_deliver_create_cell(circ,CELL_CREATE,
- circ->n_conn_onionskin)<0) {
+ circ->n_chan_onionskin)<0) {
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
continue;
}
- tor_free(circ->n_conn_onionskin);
+ tor_free(circ->n_chan_onionskin);
circuit_set_state(circ, CIRCUIT_STATE_OPEN);
}
}
@@ -2076,7 +486,7 @@ circuit_n_conn_done(or_connection_t *or_conn, int status)
smartlist_free(pending_circs);
}
-/** Find a new circid that isn't currently in use on the circ->n_conn
+/** Find a new circid that isn't currently in use on the circ->n_chan
* for the outgoing
* circuit <b>circ</b>, and deliver a cell of type <b>cell_type</b>
* (either CELL_CREATE or CELL_CREATE_FAST) with payload <b>payload</b>
@@ -2091,29 +501,41 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
circid_t id;
tor_assert(circ);
- tor_assert(circ->n_conn);
+ tor_assert(circ->n_chan);
tor_assert(payload);
tor_assert(cell_type == CELL_CREATE || cell_type == CELL_CREATE_FAST);
- id = get_unique_circ_id_by_conn(circ->n_conn);
+ id = get_unique_circ_id_by_chan(circ->n_chan);
if (!id) {
log_warn(LD_CIRC,"failed to get unique circID.");
return -1;
}
log_debug(LD_CIRC,"Chosen circID %u.", id);
- circuit_set_n_circid_orconn(circ, id, circ->n_conn);
+ circuit_set_n_circid_chan(circ, id, circ->n_chan);
memset(&cell, 0, sizeof(cell_t));
cell.command = cell_type;
cell.circ_id = circ->n_circ_id;
memcpy(cell.payload, payload, ONIONSKIN_CHALLENGE_LEN);
- append_cell_to_circuit_queue(circ, circ->n_conn, &cell,
+ append_cell_to_circuit_queue(circ, circ->n_chan, &cell,
CELL_DIRECTION_OUT, 0);
if (CIRCUIT_IS_ORIGIN(circ)) {
+ /* Update began timestamp for circuits starting their first hop */
+ if (TO_ORIGIN_CIRCUIT(circ)->cpath->state == CPATH_STATE_CLOSED) {
+ if (circ->n_chan->state != CHANNEL_STATE_OPEN) {
+ log_warn(LD_CIRC,
+ "Got first hop for a circuit without an opened channel. "
+ "State: %s.", channel_state_to_string(circ->n_chan->state));
+ tor_fragile_assert();
+ }
+
+ tor_gettimeofday(&circ->timestamp_began);
+ }
+
/* mark it so it gets better rate limiting treatment. */
- circ->n_conn->client_used = time(NULL);
+ channel_timestamp_client(circ->n_chan);
}
return 0;
@@ -2215,7 +637,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
else
control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0);
- node = node_get_by_id(circ->_base.n_conn->identity_digest);
+ node = node_get_by_id(circ->base_.n_chan->identity_digest);
fast = should_use_create_fast_for_circuit(circ);
if (!fast) {
/* We are an OR and we know the right onion key: we should
@@ -2252,7 +674,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
node ? node_describe(node) : "<unnamed>");
} else {
tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
- tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING);
+ tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING);
log_debug(LD_CIRC,"starting to send subsequent skin.");
hop = onion_next_hop_in_cpath(circ->cpath);
if (!hop) {
@@ -2262,7 +684,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
struct timeval end;
long timediff;
tor_gettimeofday(&end);
- timediff = tv_mdiff(&circ->_base.timestamp_created, &end);
+ timediff = tv_mdiff(&circ->base_.timestamp_began, &end);
/*
* If the circuit build time is much greater than we would have cut
@@ -2272,8 +694,8 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
if (timediff < 0 || timediff > 2*circ_times.close_ms+1000) {
log_notice(LD_CIRC, "Strange value for circuit build time: %ldmsec. "
"Assuming clock jump. Purpose %d (%s)", timediff,
- circ->_base.purpose,
- circuit_purpose_to_string(circ->_base.purpose));
+ circ->base_.purpose,
+ circuit_purpose_to_string(circ->base_.purpose));
} else if (!circuit_build_times_disabled()) {
/* Only count circuit times if the network is live */
if (circuit_build_times_network_check_live(&circ_times)) {
@@ -2281,7 +703,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
circuit_build_times_set_timeout(&circ_times);
}
- if (circ->_base.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
circuit_build_times_network_circ_success(&circ_times);
}
}
@@ -2314,7 +736,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
circuit_has_opened(circ); /* do other actions as necessary */
/* We're done with measurement circuits here. Just close them */
- if (circ->_base.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
+ if (circ->base_.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
return 0;
}
@@ -2383,7 +805,7 @@ circuit_note_clock_jumped(int seconds_elapsed)
int
circuit_extend(cell_t *cell, circuit_t *circ)
{
- or_connection_t *n_conn;
+ channel_t *n_chan;
relay_header_t rh;
char *onionskin;
char *id_digest=NULL;
@@ -2393,9 +815,9 @@ circuit_extend(cell_t *cell, circuit_t *circ)
const char *msg = NULL;
int should_launch = 0;
- if (circ->n_conn) {
+ if (circ->n_chan) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "n_conn already set. Bug/attack. Closing.");
+ "n_chan already set. Bug/attack. Closing.");
return -1;
}
if (circ->n_hop) {
@@ -2454,52 +876,54 @@ circuit_extend(cell_t *cell, circuit_t *circ)
/* Next, check if we're being asked to connect to the hop that the
* extend cell came from. There isn't any reason for that, and it can
* assist circular-path attacks. */
- if (tor_memeq(id_digest, TO_OR_CIRCUIT(circ)->p_conn->identity_digest,
- DIGEST_LEN)) {
+ if (tor_memeq(id_digest,
+ TO_OR_CIRCUIT(circ)->p_chan->identity_digest,
+ DIGEST_LEN)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend back to the previous hop.");
return -1;
}
- n_conn = connection_or_get_for_extend(id_digest,
- &n_addr,
- &msg,
- &should_launch);
+ n_chan = channel_get_for_extend(id_digest,
+ &n_addr,
+ &msg,
+ &should_launch);
- if (!n_conn) {
- log_debug(LD_CIRC|LD_OR,"Next router (%s:%d): %s",
- fmt_addr(&n_addr), (int)n_port, msg?msg:"????");
+ if (!n_chan) {
+ log_debug(LD_CIRC|LD_OR,"Next router (%s): %s",
+ fmt_addrport(&n_addr, n_port), msg?msg:"????");
- circ->n_hop = extend_info_alloc(NULL /*nickname*/,
+ circ->n_hop = extend_info_new(NULL /*nickname*/,
id_digest,
NULL /*onion_key*/,
&n_addr, n_port);
- circ->n_conn_onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
- memcpy(circ->n_conn_onionskin, onionskin, ONIONSKIN_CHALLENGE_LEN);
- circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT);
+ circ->n_chan_onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
+ memcpy(circ->n_chan_onionskin, onionskin, ONIONSKIN_CHALLENGE_LEN);
+ circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
if (should_launch) {
/* we should try to open a connection */
- n_conn = connection_or_connect(&n_addr, n_port, id_digest);
- if (!n_conn) {
- log_info(LD_CIRC,"Launching n_conn failed. Closing circuit.");
+ n_chan = channel_connect_for_circuit(&n_addr, n_port, id_digest);
+ if (!n_chan) {
+ log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
return 0;
}
log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
}
/* return success. The onion/circuit/etc will be taken care of
- * automatically (may already have been) whenever n_conn reaches
+ * automatically (may already have been) whenever n_chan reaches
* OR_CONN_STATE_OPEN.
*/
return 0;
}
tor_assert(!circ->n_hop); /* Connection is already established. */
- circ->n_conn = n_conn;
- log_debug(LD_CIRC,"n_conn is %s:%u",
- n_conn->_base.address,n_conn->_base.port);
+ circ->n_chan = n_chan;
+ log_debug(LD_CIRC,
+ "n_chan is %s",
+ channel_get_canonical_remote_descr(n_chan));
if (circuit_deliver_create_cell(circ, CELL_CREATE, onionskin) < 0)
return -1;
@@ -2581,7 +1005,8 @@ pathbias_get_notice_rate(const or_options_t *options)
DFLT_PATH_BIAS_NOTICE_PCT, 0, 100)/100.0;
}
-static double
+/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */
+double
pathbias_get_disable_rate(const or_options_t *options)
{
// XXX: This needs tuning based on use + experimentation before we set it
@@ -2608,12 +1033,12 @@ pathbias_get_scale_threshold(const or_options_t *options)
static int
pathbias_get_scale_factor(const or_options_t *options)
{
-#define DFLT_PATH_BIAS_SCALE_FACTOR 4
+#define DFLT_PATH_BIAS_SCALE_FACTOR 2
if (options->PathBiasScaleFactor >= 1)
return options->PathBiasScaleFactor;
else
return networkstatus_get_param(NULL, "pb_scalefactor",
- DFLT_PATH_BIAS_SCALE_THRESHOLD, 1, INT32_MAX);
+ DFLT_PATH_BIAS_SCALE_FACTOR, 1, INT32_MAX);
}
static const char *
@@ -2645,6 +1070,14 @@ pathbias_count_first_hop(origin_circuit_t *circ)
RATELIM_INIT(FIRST_HOP_NOTICE_INTERVAL);
char *rate_msg = NULL;
+ /* We can't do path bias accounting without entry guards.
+ * Testing and controller circuits also have no guards. */
+ if (get_options()->UseEntryGuards == 0 ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_TESTING ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) {
+ return 0;
+ }
+
/* Completely ignore one hop circuits */
if (circ->build_state->onehop_tunnel ||
circ->build_state->desired_path_len == 1) {
@@ -2653,13 +1086,13 @@ pathbias_count_first_hop(origin_circuit_t *circ)
!circ->build_state->onehop_tunnel) {
if ((rate_msg = rate_limit_log(&first_hop_notice_limit,
approx_time()))) {
- log_info(LD_BUG,
+ log_notice(LD_BUG,
"One-hop circuit has length %d. Path state is %s. "
"Circuit is a %s currently %s.%s",
circ->build_state->desired_path_len,
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2677,8 +1110,8 @@ pathbias_count_first_hop(origin_circuit_t *circ)
"Opened circuit is in strange path state %s. "
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2688,8 +1121,8 @@ pathbias_count_first_hop(origin_circuit_t *circ)
if (!circ->has_opened) {
entry_guard_t *guard;
- guard = entry_guard_get_by_id_digest(
- circ->_base.n_conn->identity_digest);
+ guard =
+ entry_guard_get_by_id_digest(circ->base_.n_chan->identity_digest);
if (guard) {
if (circ->path_state == PATH_STATE_NEW_CIRC) {
circ->path_state = PATH_STATE_DID_FIRST_HOP;
@@ -2705,8 +1138,8 @@ pathbias_count_first_hop(origin_circuit_t *circ)
"Unopened circuit has strange path state %s. "
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2717,8 +1150,8 @@ pathbias_count_first_hop(origin_circuit_t *circ)
log_info(LD_BUG,
"Unopened circuit has no known guard. "
"Circuit is a %s currently %s.%s",
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2734,8 +1167,8 @@ pathbias_count_first_hop(origin_circuit_t *circ)
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
circ->cpath->state, circ->has_opened,
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2759,6 +1192,15 @@ pathbias_count_success(origin_circuit_t *circ)
static ratelim_t success_notice_limit =
RATELIM_INIT(SUCCESS_NOTICE_INTERVAL);
char *rate_msg = NULL;
+ entry_guard_t *guard = NULL;
+
+ /* We can't do path bias accounting without entry guards.
+ * Testing and controller circuits also have no guards. */
+ if (get_options()->UseEntryGuards == 0 ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_TESTING ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) {
+ return;
+ }
/* Ignore one hop circuits */
if (circ->build_state->onehop_tunnel ||
@@ -2768,13 +1210,13 @@ pathbias_count_success(origin_circuit_t *circ)
!circ->build_state->onehop_tunnel) {
if ((rate_msg = rate_limit_log(&success_notice_limit,
approx_time()))) {
- log_info(LD_BUG,
+ log_notice(LD_BUG,
"One-hop circuit has length %d. Path state is %s. "
"Circuit is a %s currently %s.%s",
circ->build_state->desired_path_len,
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2785,8 +1227,8 @@ pathbias_count_success(origin_circuit_t *circ)
/* Don't count cannibalized/reused circs for path bias */
if (!circ->has_opened) {
- entry_guard_t *guard =
- entry_guard_get_by_id_digest(circ->_base.n_conn->identity_digest);
+ guard =
+ entry_guard_get_by_id_digest(circ->base_.n_chan->identity_digest);
if (guard) {
if (circ->path_state == PATH_STATE_DID_FIRST_HOP) {
@@ -2803,27 +1245,30 @@ pathbias_count_success(origin_circuit_t *circ)
"Succeeded circuit is in strange path state %s. "
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
}
if (guard->first_hops < guard->circuit_successes) {
- log_info(LD_BUG, "Unexpectedly high circuit_successes (%u/%u) "
+ log_notice(LD_BUG, "Unexpectedly high circuit_successes (%u/%u) "
"for guard %s=%s",
guard->circuit_successes, guard->first_hops,
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
}
- } else {
+ /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
+ * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here.
+ * No need to log that case. */
+ } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
if ((rate_msg = rate_limit_log(&success_notice_limit,
approx_time()))) {
log_info(LD_BUG,
"Completed circuit has no known guard. "
"Circuit is a %s currently %s.%s",
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2836,8 +1281,8 @@ pathbias_count_success(origin_circuit_t *circ)
"Opened circuit is in strange path state %s. "
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2863,9 +1308,11 @@ entry_guard_inc_first_hop_count(entry_guard_t *guard)
if (guard->circuit_successes/((double)guard->first_hops)
< pathbias_get_disable_rate(options)) {
- log_info(LD_PROTOCOL,
+ /* This message is currently disabled by default. */
+ log_warn(LD_PROTOCOL,
"Extremely low circuit success rate %u/%u for guard %s=%s. "
- "This might indicate an attack, or a bug.",
+ "This indicates either an overloaded guard, an attack, or "
+ "a bug.",
guard->circuit_successes, guard->first_hops, guard->nickname,
hex_str(guard->identity, DIGEST_LEN));
@@ -2876,7 +1323,7 @@ entry_guard_inc_first_hop_count(entry_guard_t *guard)
< pathbias_get_notice_rate(options)
&& !guard->path_bias_notice) {
guard->path_bias_notice = 1;
- log_info(LD_PROTOCOL,
+ log_notice(LD_PROTOCOL,
"Low circuit success rate %u/%u for guard %s=%s.",
guard->circuit_successes, guard->first_hops, guard->nickname,
hex_str(guard->identity, DIGEST_LEN));
@@ -2886,8 +1333,18 @@ entry_guard_inc_first_hop_count(entry_guard_t *guard)
/* If we get a ton of circuits, just scale everything down */
if (guard->first_hops > (unsigned)pathbias_get_scale_threshold(options)) {
const int scale_factor = pathbias_get_scale_factor(options);
- guard->first_hops /= scale_factor;
- guard->circuit_successes /= scale_factor;
+ /* For now, only scale if there will be no rounding error...
+ * XXX024: We want to switch to a real moving average for 0.2.4. */
+ if ((guard->first_hops % scale_factor) == 0 &&
+ (guard->circuit_successes % scale_factor) == 0) {
+ log_info(LD_PROTOCOL,
+ "Scaling pathbias counts to (%u/%u)/%d for guard %s=%s",
+ guard->circuit_successes, guard->first_hops,
+ scale_factor, guard->nickname, hex_str(guard->identity,
+ DIGEST_LEN));
+ guard->first_hops /= scale_factor;
+ guard->circuit_successes /= scale_factor;
+ }
}
guard->first_hops++;
log_info(LD_PROTOCOL, "Got success count %u/%u for guard %s=%s",
@@ -2974,7 +1431,7 @@ circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
* just give up: for circ to close, and return 0.
*/
int
-circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
+circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason)
{
// crypt_path_t *victim;
// connection_t *stream;
@@ -2987,7 +1444,7 @@ circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
* just give up.
*/
circuit_mark_for_close(TO_CIRCUIT(circ),
- END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_OR_CONN_CLOSED);
+ END_CIRC_REASON_FLAG_REMOTE|reason);
return 0;
#if 0
@@ -3061,12 +1518,12 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
append_cell_to_circuit_queue(TO_CIRCUIT(circ),
- circ->p_conn, &cell, CELL_DIRECTION_IN, 0);
+ circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
log_debug(LD_CIRC,"Finished sending '%s' cell.",
circ->is_first_hop ? "created_fast" : "created");
- if (!is_local_addr(&circ->p_conn->_base.addr) &&
- !connection_or_nonopen_was_started_here(circ->p_conn)) {
+ if (!channel_is_local(circ->p_chan) &&
+ !channel_is_outgoing(circ->p_chan)) {
/* record that we could process create cells from a non-local conn
* that we didn't initiate; presumably this means that create cells
* can reach us too. */
@@ -3268,7 +1725,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
n_supported[i] = -1;
continue;
}
- if (routerset_contains_node(options->_ExcludeExitNodesUnion, node)) {
+ if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) {
n_supported[i] = -1;
continue; /* user asked us not to use it, no matter what */
}
@@ -3285,7 +1742,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
* we'll retry later in this function with need_update and
* need_capacity set to 0. */
}
- if (!(node->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) {
+ if (!(node->is_valid || options->AllowInvalid_ & ALLOW_INVALID_EXIT)) {
/* if it's invalid and we don't want it */
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.",
@@ -3371,7 +1828,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
}
log_notice(LD_CIRC, "All routers are down or won't exit%s -- "
"choosing a doomed exit at random.",
- options->_ExcludeExitNodesUnion ? " or are Excluded" : "");
+ options->ExcludeExitNodesUnion_ ? " or are Excluded" : "");
}
supporting = smartlist_new();
needed_ports = circuit_get_unhandled_ports(time(NULL));
@@ -3410,7 +1867,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
log_warn(LD_CIRC,
"No specified %sexit routers seem to be running: "
"can't choose an exit.",
- options->_ExcludeExitNodesUnion ? "non-excluded " : "");
+ options->ExcludeExitNodesUnion_ ? "non-excluded " : "");
}
return NULL;
}
@@ -3438,14 +1895,14 @@ choose_good_exit_server(uint8_t purpose,
switch (purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
- if (options->_AllowInvalid & ALLOW_INVALID_MIDDLE)
+ if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE)
flags |= CRN_ALLOW_INVALID;
if (is_internal) /* pick it like a middle hop */
return router_choose_random_node(NULL, options->ExcludeNodes, flags);
else
return choose_good_exit_server_general(need_uptime,need_capacity);
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
- if (options->_AllowInvalid & ALLOW_INVALID_RENDEZVOUS)
+ if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS)
flags |= CRN_ALLOW_INVALID;
return router_choose_random_node(NULL, options->ExcludeNodes, flags);
}
@@ -3462,7 +1919,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
const or_options_t *options = get_options();
routerset_t *rs = options->ExcludeNodes;
const char *description;
- uint8_t purpose = circ->_base.purpose;
+ uint8_t purpose = circ->base_.purpose;
if (circ->build_state->onehop_tunnel)
return;
@@ -3482,7 +1939,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
if (circ->build_state->is_internal)
return;
description = "requested exit node";
- rs = options->_ExcludeExitNodesUnion;
+ rs = options->ExcludeExitNodesUnion_;
break;
case CIRCUIT_PURPOSE_C_INTRODUCING:
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
@@ -3499,7 +1956,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
description = "chosen rendezvous point";
break;
case CIRCUIT_PURPOSE_CONTROLLER:
- rs = options->_ExcludeExitNodesUnion;
+ rs = options->ExcludeExitNodesUnion_;
description = "controller-selected circuit target";
break;
}
@@ -3541,7 +1998,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel.");
state->desired_path_len = 1;
} else {
- int r = new_route_len(circ->_base.purpose, exit, nodelist_get_list());
+ int r = new_route_len(circ->base_.purpose, exit, nodelist_get_list());
if (r < 1) /* must be at least 1 */
return -1;
state->desired_path_len = r;
@@ -3554,7 +2011,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
exit = extend_info_dup(exit);
} else { /* we have to decide one */
const node_t *node =
- choose_good_exit_server(circ->_base.purpose, state->need_uptime,
+ choose_good_exit_server(circ->base_.purpose, state->need_uptime,
state->need_capacity, state->is_internal);
if (!node) {
log_warn(LD_CIRC,"failed to choose an exit server");
@@ -3675,8 +2132,8 @@ choose_good_middle_server(uint8_t purpose,
smartlist_t *excluded;
const or_options_t *options = get_options();
router_crn_flags_t flags = CRN_NEED_DESC;
- tor_assert(_CIRCUIT_PURPOSE_MIN <= purpose &&
- purpose <= _CIRCUIT_PURPOSE_MAX);
+ tor_assert(CIRCUIT_PURPOSE_MIN_ <= purpose &&
+ purpose <= CIRCUIT_PURPOSE_MAX_);
log_debug(LD_CIRC, "Contemplating intermediate hop: random choice.");
excluded = smartlist_new();
@@ -3693,7 +2150,7 @@ choose_good_middle_server(uint8_t purpose,
flags |= CRN_NEED_UPTIME;
if (state->need_capacity)
flags |= CRN_NEED_CAPACITY;
- if (options->_AllowInvalid & ALLOW_INVALID_MIDDLE)
+ if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE)
flags |= CRN_ALLOW_INVALID;
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
smartlist_free(excluded);
@@ -3708,7 +2165,8 @@ choose_good_middle_server(uint8_t purpose,
* If <b>state</b> is NULL, we're choosing a router to serve as an entry
* guard, not for any particular circuit.
*/
-static const node_t *
+/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */
+const node_t *
choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
{
const node_t *choice;
@@ -3740,8 +2198,8 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
});
}
/* and exclude current entry guards and their families, if applicable */
- if (options->UseEntryGuards && entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
+ if (options->UseEntryGuards) {
+ SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry,
{
if ((node = node_get_by_id(entry->identity))) {
nodelist_add_node_and_family(excluded, node);
@@ -3755,7 +2213,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
if (state->need_capacity)
flags |= CRN_NEED_CAPACITY;
}
- if (options->_AllowInvalid & ALLOW_INVALID_ENTRY)
+ if (options->AllowInvalid_ & ALLOW_INVALID_ENTRY)
flags |= CRN_ALLOW_INVALID;
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
@@ -3783,7 +2241,7 @@ onion_next_hop_in_cpath(crypt_path_t *cpath)
static int
onion_extend_cpath(origin_circuit_t *circ)
{
- uint8_t purpose = circ->_base.purpose;
+ uint8_t purpose = circ->base_.purpose;
cpath_build_state_t *state = circ->build_state;
int cur_len = circuit_get_cpath_len(circ);
extend_info_t *info = NULL;
@@ -3802,12 +2260,10 @@ onion_extend_cpath(origin_circuit_t *circ)
} else if (cur_len == 0) { /* picking first node */
const node_t *r = choose_good_entry_server(purpose, state);
if (r) {
- /* If we're extending to a bridge, use the preferred address
- rather than the primary, for potentially extending to an IPv6
- bridge. */
- int use_pref_addr = (r->ri != NULL &&
- r->ri->purpose == ROUTER_PURPOSE_BRIDGE);
- info = extend_info_from_node(r, use_pref_addr);
+ /* If we're a client, use the preferred address rather than the
+ primary address, for potentially connecting to an IPv6 OR
+ port. */
+ info = extend_info_from_node(r, server_mode(get_options()) == 0);
tor_assert(info);
}
} else {
@@ -3858,7 +2314,7 @@ onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice)
/** Allocate a new extend_info object based on the various arguments. */
extend_info_t *
-extend_info_alloc(const char *nickname, const char *digest,
+extend_info_new(const char *nickname, const char *digest,
crypto_pk_t *onion_key,
const tor_addr_t *addr, uint16_t port)
{
@@ -3873,47 +2329,45 @@ extend_info_alloc(const char *nickname, const char *digest,
return info;
}
-/** Allocate and return a new extend_info_t that can be used to build
- * a circuit to or through the router <b>r</b>. Use the primary
- * address of the router unless <b>for_direct_connect</b> is true, in
- * which case the preferred address is used instead. */
+/** Allocate and return a new extend_info that can be used to build a
+ * circuit to or through the node <b>node</b>. Use the primary address
+ * of the node (i.e. its IPv4 address) unless
+ * <b>for_direct_connect</b> is true, in which case the preferred
+ * address is used instead. May return NULL if there is not enough
+ * info about <b>node</b> to extend to it--for example, if there is no
+ * routerinfo_t or microdesc_t.
+ **/
extend_info_t *
-extend_info_from_router(const routerinfo_t *r, int for_direct_connect)
+extend_info_from_node(const node_t *node, int for_direct_connect)
{
tor_addr_port_t ap;
- tor_assert(r);
+
+ if (node->ri == NULL && (node->rs == NULL || node->md == NULL))
+ return NULL;
if (for_direct_connect)
- router_get_pref_orport(r, &ap);
+ node_get_pref_orport(node, &ap);
else
- router_get_prim_orport(r, &ap);
- return extend_info_alloc(r->nickname, r->cache_info.identity_digest,
- r->onion_pkey, &ap.addr, ap.port);
-}
+ node_get_prim_orport(node, &ap);
-/** Allocate and return a new extend_info that can be used to build a
- * circuit to or through the node <b>node</b>. Use the primary address
- * of the node unless <b>for_direct_connect</b> is true, in which case
- * the preferred address is used instead. May return NULL if there is
- * not enough info about <b>node</b> to extend to it--for example, if
- * there is no routerinfo_t or microdesc_t.
- **/
-extend_info_t *
-extend_info_from_node(const node_t *node, int for_direct_connect)
-{
- if (node->ri) {
- return extend_info_from_router(node->ri, for_direct_connect);
- } else if (node->rs && node->md) {
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, node->rs->addr);
- return extend_info_alloc(node->rs->nickname,
+ log_debug(LD_CIRC, "using %s for %s",
+ fmt_addrport(&ap.addr, ap.port),
+ node->ri ? node->ri->nickname : node->rs->nickname);
+
+ if (node->ri)
+ return extend_info_new(node->ri->nickname,
+ node->identity,
+ node->ri->onion_pkey,
+ &ap.addr,
+ ap.port);
+ else if (node->rs && node->md)
+ return extend_info_new(node->rs->nickname,
node->identity,
node->md->onion_pkey,
- &addr,
- node->rs->or_port);
- } else {
+ &ap.addr,
+ ap.port);
+ else
return NULL;
- }
}
/** Release storage held by an extend_info_t struct. */
@@ -3966,2067 +2420,3 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
return state->chosen_exit->nickname;
}
-/** Check whether the entry guard <b>e</b> is usable, given the directory
- * authorities' opinion about the router (stored in <b>ri</b>) and the user's
- * configuration (in <b>options</b>). Set <b>e</b>-&gt;bad_since
- * accordingly. Return true iff the entry guard's status changes.
- *
- * If it's not usable, set *<b>reason</b> to a static string explaining why.
- */
-static int
-entry_guard_set_status(entry_guard_t *e, const node_t *node,
- time_t now, const or_options_t *options,
- const char **reason)
-{
- char buf[HEX_DIGEST_LEN+1];
- int changed = 0;
-
- *reason = NULL;
-
- /* Do we want to mark this guard as bad? */
- if (!node)
- *reason = "unlisted";
- else if (!node->is_running)
- *reason = "down";
- else if (options->UseBridges && (!node->ri ||
- node->ri->purpose != ROUTER_PURPOSE_BRIDGE))
- *reason = "not a bridge";
- else if (options->UseBridges && !node_is_a_configured_bridge(node))
- *reason = "not a configured bridge";
- else if (!options->UseBridges && !node->is_possible_guard &&
- !routerset_contains_node(options->EntryNodes,node))
- *reason = "not recommended as a guard";
- else if (routerset_contains_node(options->ExcludeNodes, node))
- *reason = "excluded";
- else if (e->path_bias_disabled)
- *reason = "path-biased";
-
- if (*reason && ! e->bad_since) {
- /* Router is newly bad. */
- base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
- log_info(LD_CIRC, "Entry guard %s (%s) is %s: marking as unusable.",
- e->nickname, buf, *reason);
-
- e->bad_since = now;
- control_event_guard(e->nickname, e->identity, "BAD");
- changed = 1;
- } else if (!*reason && e->bad_since) {
- /* There's nothing wrong with the router any more. */
- base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
- log_info(LD_CIRC, "Entry guard %s (%s) is no longer unusable: "
- "marking as ok.", e->nickname, buf);
-
- e->bad_since = 0;
- control_event_guard(e->nickname, e->identity, "GOOD");
- changed = 1;
- }
- return changed;
-}
-
-/** Return true iff enough time has passed since we last tried to connect
- * to the unreachable guard <b>e</b> that we're willing to try again. */
-static int
-entry_is_time_to_retry(entry_guard_t *e, time_t now)
-{
- long diff;
- if (e->last_attempted < e->unreachable_since)
- return 1;
- diff = now - e->unreachable_since;
- if (diff < 6*60*60)
- return now > (e->last_attempted + 60*60);
- else if (diff < 3*24*60*60)
- return now > (e->last_attempted + 4*60*60);
- else if (diff < 7*24*60*60)
- return now > (e->last_attempted + 18*60*60);
- else
- return now > (e->last_attempted + 36*60*60);
-}
-
-/** Return the node corresponding to <b>e</b>, if <b>e</b> is
- * working well enough that we are willing to use it as an entry
- * right now. (Else return NULL.) In particular, it must be
- * - Listed as either up or never yet contacted;
- * - Present in the routerlist;
- * - Listed as 'stable' or 'fast' by the current dirserver consensus,
- * if demanded by <b>need_uptime</b> or <b>need_capacity</b>
- * (unless it's a configured EntryNode);
- * - Allowed by our current ReachableORAddresses config option; and
- * - Currently thought to be reachable by us (unless <b>assume_reachable</b>
- * is true).
- *
- * If the answer is no, set *<b>msg</b> to an explanation of why.
- */
-static INLINE const node_t *
-entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
- int assume_reachable, const char **msg)
-{
- const node_t *node;
- const or_options_t *options = get_options();
- tor_assert(msg);
-
- if (e->path_bias_disabled) {
- *msg = "path-biased";
- return NULL;
- }
- if (e->bad_since) {
- *msg = "bad";
- return NULL;
- }
- /* no good if it's unreachable, unless assume_unreachable or can_retry. */
- if (!assume_reachable && !e->can_retry &&
- e->unreachable_since && !entry_is_time_to_retry(e, time(NULL))) {
- *msg = "unreachable";
- return NULL;
- }
- node = node_get_by_id(e->identity);
- if (!node || !node_has_descriptor(node)) {
- *msg = "no descriptor";
- return NULL;
- }
- if (get_options()->UseBridges) {
- if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) {
- *msg = "not a bridge";
- return NULL;
- }
- if (!node_is_a_configured_bridge(node)) {
- *msg = "not a configured bridge";
- return NULL;
- }
- } else { /* !get_options()->UseBridges */
- if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
- *msg = "not general-purpose";
- return NULL;
- }
- }
- if (routerset_contains_node(options->EntryNodes, node)) {
- /* they asked for it, they get it */
- need_uptime = need_capacity = 0;
- }
- if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
- *msg = "not fast/stable";
- return NULL;
- }
- if (!fascist_firewall_allows_node(node)) {
- *msg = "unreachable by config";
- return NULL;
- }
- return node;
-}
-
-/** Return the number of entry guards that we think are usable. */
-static int
-num_live_entry_guards(void)
-{
- int n = 0;
- const char *msg;
- if (! entry_guards)
- return 0;
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- if (entry_is_live(entry, 0, 1, 0, &msg))
- ++n;
- });
- return n;
-}
-
-/** If <b>digest</b> matches the identity of any node in the
- * entry_guards list, return that node. Else return NULL. */
-static entry_guard_t *
-entry_guard_get_by_id_digest(const char *digest)
-{
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- if (tor_memeq(digest, entry->identity, DIGEST_LEN))
- return entry;
- );
- return NULL;
-}
-
-/** Dump a description of our list of entry guards to the log at level
- * <b>severity</b>. */
-static void
-log_entry_guards(int severity)
-{
- smartlist_t *elements = smartlist_new();
- char *s;
-
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e)
- {
- const char *msg = NULL;
- if (entry_is_live(e, 0, 1, 0, &msg))
- smartlist_add_asprintf(elements, "%s [%s] (up %s)",
- e->nickname,
- hex_str(e->identity, DIGEST_LEN),
- e->made_contact ? "made-contact" : "never-contacted");
- else
- smartlist_add_asprintf(elements, "%s [%s] (%s, %s)",
- e->nickname,
- hex_str(e->identity, DIGEST_LEN),
- msg,
- e->made_contact ? "made-contact" : "never-contacted");
- }
- SMARTLIST_FOREACH_END(e);
-
- s = smartlist_join_strings(elements, ",", 0, NULL);
- SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp));
- smartlist_free(elements);
- log_fn(severity,LD_CIRC,"%s",s);
- tor_free(s);
-}
-
-/** Called when one or more guards that we would previously have used for some
- * purpose are no longer in use because a higher-priority guard has become
- * usable again. */
-static void
-control_event_guard_deferred(void)
-{
- /* XXXX We don't actually have a good way to figure out _how many_ entries
- * are live for some purpose. We need an entry_is_even_slightly_live()
- * function for this to work right. NumEntryGuards isn't reliable: if we
- * need guards with weird properties, we can have more than that number
- * live.
- **/
-#if 0
- int n = 0;
- const char *msg;
- const or_options_t *options = get_options();
- if (!entry_guards)
- return;
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- if (entry_is_live(entry, 0, 1, 0, &msg)) {
- if (n++ == options->NumEntryGuards) {
- control_event_guard(entry->nickname, entry->identity, "DEFERRED");
- return;
- }
- }
- });
-#endif
-}
-
-/** Add a new (preferably stable and fast) router to our
- * entry_guards list. Return a pointer to the router if we succeed,
- * or NULL if we can't find any more suitable entries.
- *
- * If <b>chosen</b> is defined, use that one, and if it's not
- * already in our entry_guards list, put it at the *beginning*.
- * Else, put the one we pick at the end of the list. */
-static const node_t *
-add_an_entry_guard(const node_t *chosen, int reset_status, int prepend)
-{
- const node_t *node;
- entry_guard_t *entry;
-
- if (chosen) {
- node = chosen;
- entry = entry_guard_get_by_id_digest(node->identity);
- if (entry) {
- if (reset_status) {
- entry->bad_since = 0;
- entry->can_retry = 1;
- }
- return NULL;
- }
- } else {
- node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL);
- if (!node)
- return NULL;
- }
- entry = tor_malloc_zero(sizeof(entry_guard_t));
- log_info(LD_CIRC, "Chose %s as new entry guard.",
- node_describe(node));
- strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname));
- memcpy(entry->identity, node->identity, DIGEST_LEN);
- /* Choose expiry time smudged over the past month. The goal here
- * is to a) spread out when Tor clients rotate their guards, so they
- * don't all select them on the same day, and b) avoid leaving a
- * precise timestamp in the state file about when we first picked
- * this guard. For details, see the Jan 2010 or-dev thread. */
- entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
- entry->chosen_by_version = tor_strdup(VERSION);
- if (prepend)
- smartlist_insert(entry_guards, 0, entry);
- else
- smartlist_add(entry_guards, entry);
- control_event_guard(entry->nickname, entry->identity, "NEW");
- control_event_guard_deferred();
- log_entry_guards(LOG_INFO);
- return node;
-}
-
-/** If the use of entry guards is configured, choose more entry guards
- * until we have enough in the list. */
-static void
-pick_entry_guards(const or_options_t *options)
-{
- int changed = 0;
-
- tor_assert(entry_guards);
-
- while (num_live_entry_guards() < options->NumEntryGuards) {
- if (!add_an_entry_guard(NULL, 0, 0))
- break;
- changed = 1;
- }
- if (changed)
- entry_guards_changed();
-}
-
-/** How long (in seconds) do we allow an entry guard to be nonfunctional,
- * unlisted, excluded, or otherwise nonusable before we give up on it? */
-#define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60)
-
-/** Release all storage held by <b>e</b>. */
-static void
-entry_guard_free(entry_guard_t *e)
-{
- if (!e)
- return;
- tor_free(e->chosen_by_version);
- tor_free(e);
-}
-
-/** Remove any entry guard which was selected by an unknown version of Tor,
- * or which was selected by a version of Tor that's known to select
- * entry guards badly, or which was selected more 2 months ago. */
-/* XXXX The "obsolete guards" and "chosen long ago guards" things should
- * probably be different functions. */
-static int
-remove_obsolete_entry_guards(time_t now)
-{
- int changed = 0, i;
-
- for (i = 0; i < smartlist_len(entry_guards); ++i) {
- entry_guard_t *entry = smartlist_get(entry_guards, i);
- const char *ver = entry->chosen_by_version;
- const char *msg = NULL;
- tor_version_t v;
- int version_is_bad = 0, date_is_bad = 0;
- if (!ver) {
- msg = "does not say what version of Tor it was selected by";
- version_is_bad = 1;
- } else if (tor_version_parse(ver, &v)) {
- msg = "does not seem to be from any recognized version of Tor";
- version_is_bad = 1;
- } else {
- char *tor_ver = NULL;
- tor_asprintf(&tor_ver, "Tor %s", ver);
- if ((tor_version_as_new_as(tor_ver, "0.1.0.10-alpha") &&
- !tor_version_as_new_as(tor_ver, "0.1.2.16-dev")) ||
- (tor_version_as_new_as(tor_ver, "0.2.0.0-alpha") &&
- !tor_version_as_new_as(tor_ver, "0.2.0.6-alpha")) ||
- /* above are bug 440; below are bug 1217 */
- (tor_version_as_new_as(tor_ver, "0.2.1.3-alpha") &&
- !tor_version_as_new_as(tor_ver, "0.2.1.23")) ||
- (tor_version_as_new_as(tor_ver, "0.2.2.0-alpha") &&
- !tor_version_as_new_as(tor_ver, "0.2.2.7-alpha"))) {
- msg = "was selected without regard for guard bandwidth";
- version_is_bad = 1;
- }
- tor_free(tor_ver);
- }
- if (!version_is_bad && entry->chosen_on_date + 3600*24*60 < now) {
- /* It's been 2 months since the date listed in our state file. */
- msg = "was selected several months ago";
- date_is_bad = 1;
- }
-
- if (version_is_bad || date_is_bad) { /* we need to drop it */
- char dbuf[HEX_DIGEST_LEN+1];
- tor_assert(msg);
- base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
- log_fn(version_is_bad ? LOG_NOTICE : LOG_INFO, LD_CIRC,
- "Entry guard '%s' (%s) %s. (Version=%s.) Replacing it.",
- entry->nickname, dbuf, msg, ver?escaped(ver):"none");
- control_event_guard(entry->nickname, entry->identity, "DROPPED");
- entry_guard_free(entry);
- smartlist_del_keeporder(entry_guards, i--);
- log_entry_guards(LOG_INFO);
- changed = 1;
- }
- }
-
- return changed ? 1 : 0;
-}
-
-/** Remove all entry guards that have been down or unlisted for so
- * long that we don't think they'll come up again. Return 1 if we
- * removed any, or 0 if we did nothing. */
-static int
-remove_dead_entry_guards(time_t now)
-{
- char dbuf[HEX_DIGEST_LEN+1];
- char tbuf[ISO_TIME_LEN+1];
- int i;
- int changed = 0;
-
- for (i = 0; i < smartlist_len(entry_guards); ) {
- entry_guard_t *entry = smartlist_get(entry_guards, i);
- if (entry->bad_since &&
- ! entry->path_bias_disabled &&
- entry->bad_since + ENTRY_GUARD_REMOVE_AFTER < now) {
-
- base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
- format_local_iso_time(tbuf, entry->bad_since);
- log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted "
- "since %s local time; removing.",
- entry->nickname, dbuf, tbuf);
- control_event_guard(entry->nickname, entry->identity, "DROPPED");
- entry_guard_free(entry);
- smartlist_del_keeporder(entry_guards, i);
- log_entry_guards(LOG_INFO);
- changed = 1;
- } else
- ++i;
- }
- return changed ? 1 : 0;
-}
-
-/** A new directory or router-status has arrived; update the down/listed
- * status of the entry guards.
- *
- * An entry is 'down' if the directory lists it as nonrunning.
- * An entry is 'unlisted' if the directory doesn't include it.
- *
- * Don't call this on startup; only on a fresh download. Otherwise we'll
- * think that things are unlisted.
- */
-void
-entry_guards_compute_status(const or_options_t *options, time_t now)
-{
- int changed = 0;
- digestmap_t *reasons;
-
- if (! entry_guards)
- return;
-
- if (options->EntryNodes) /* reshuffle the entry guard list if needed */
- entry_nodes_should_be_added();
-
- reasons = digestmap_new();
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry)
- {
- const node_t *r = node_get_by_id(entry->identity);
- const char *reason = NULL;
- if (entry_guard_set_status(entry, r, now, options, &reason))
- changed = 1;
-
- if (entry->bad_since)
- tor_assert(reason);
- if (reason)
- digestmap_set(reasons, entry->identity, (char*)reason);
- }
- SMARTLIST_FOREACH_END(entry);
-
- if (remove_dead_entry_guards(now))
- changed = 1;
- if (remove_obsolete_entry_guards(now))
- changed = 1;
-
- if (changed) {
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
- const char *reason = digestmap_get(reasons, entry->identity);
- const char *live_msg = "";
- const node_t *r = entry_is_live(entry, 0, 1, 0, &live_msg);
- log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.",
- entry->nickname,
- hex_str(entry->identity, DIGEST_LEN),
- entry->unreachable_since ? "unreachable" : "reachable",
- entry->bad_since ? "unusable" : "usable",
- reason ? ", ": "",
- reason ? reason : "",
- r ? "live" : "not live / ",
- r ? "" : live_msg);
- } SMARTLIST_FOREACH_END(entry);
- log_info(LD_CIRC, " (%d/%d entry guards are usable/new)",
- num_live_entry_guards(), smartlist_len(entry_guards));
- log_entry_guards(LOG_INFO);
- entry_guards_changed();
- }
-
- digestmap_free(reasons, NULL);
-}
-
-/** Called when a connection to an OR with the identity digest <b>digest</b>
- * is established (<b>succeeded</b>==1) or has failed (<b>succeeded</b>==0).
- * If the OR is an entry, change that entry's up/down status.
- * Return 0 normally, or -1 if we want to tear down the new connection.
- *
- * If <b>mark_relay_status</b>, also call router_set_status() on this
- * relay.
- *
- * XXX024 change succeeded and mark_relay_status into 'int flags'.
- */
-int
-entry_guard_register_connect_status(const char *digest, int succeeded,
- int mark_relay_status, time_t now)
-{
- int changed = 0;
- int refuse_conn = 0;
- int first_contact = 0;
- entry_guard_t *entry = NULL;
- int idx = -1;
- char buf[HEX_DIGEST_LEN+1];
-
- if (! entry_guards)
- return 0;
-
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- tor_assert(e);
- if (tor_memeq(e->identity, digest, DIGEST_LEN)) {
- entry = e;
- idx = e_sl_idx;
- break;
- }
- } SMARTLIST_FOREACH_END(e);
-
- if (!entry)
- return 0;
-
- base16_encode(buf, sizeof(buf), entry->identity, DIGEST_LEN);
-
- if (succeeded) {
- if (entry->unreachable_since) {
- log_info(LD_CIRC, "Entry guard '%s' (%s) is now reachable again. Good.",
- entry->nickname, buf);
- entry->can_retry = 0;
- entry->unreachable_since = 0;
- entry->last_attempted = now;
- control_event_guard(entry->nickname, entry->identity, "UP");
- changed = 1;
- }
- if (!entry->made_contact) {
- entry->made_contact = 1;
- first_contact = changed = 1;
- }
- } else { /* ! succeeded */
- if (!entry->made_contact) {
- /* We've never connected to this one. */
- log_info(LD_CIRC,
- "Connection to never-contacted entry guard '%s' (%s) failed. "
- "Removing from the list. %d/%d entry guards usable/new.",
- entry->nickname, buf,
- num_live_entry_guards()-1, smartlist_len(entry_guards)-1);
- control_event_guard(entry->nickname, entry->identity, "DROPPED");
- entry_guard_free(entry);
- smartlist_del_keeporder(entry_guards, idx);
- log_entry_guards(LOG_INFO);
- changed = 1;
- } else if (!entry->unreachable_since) {
- log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). "
- "Marking as unreachable.", entry->nickname, buf);
- entry->unreachable_since = entry->last_attempted = now;
- control_event_guard(entry->nickname, entry->identity, "DOWN");
- changed = 1;
- entry->can_retry = 0; /* We gave it an early chance; no good. */
- } else {
- char tbuf[ISO_TIME_LEN+1];
- format_iso_time(tbuf, entry->unreachable_since);
- log_debug(LD_CIRC, "Failed to connect to unreachable entry guard "
- "'%s' (%s). It has been unreachable since %s.",
- entry->nickname, buf, tbuf);
- entry->last_attempted = now;
- entry->can_retry = 0; /* We gave it an early chance; no good. */
- }
- }
-
- /* if the caller asked us to, also update the is_running flags for this
- * relay */
- if (mark_relay_status)
- router_set_status(digest, succeeded);
-
- if (first_contact) {
- /* We've just added a new long-term entry guard. Perhaps the network just
- * came back? We should give our earlier entries another try too,
- * and close this connection so we don't use it before we've given
- * the others a shot. */
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- if (e == entry)
- break;
- if (e->made_contact) {
- const char *msg;
- const node_t *r = entry_is_live(e, 0, 1, 1, &msg);
- if (r && e->unreachable_since) {
- refuse_conn = 1;
- e->can_retry = 1;
- }
- }
- } SMARTLIST_FOREACH_END(e);
- if (refuse_conn) {
- log_info(LD_CIRC,
- "Connected to new entry guard '%s' (%s). Marking earlier "
- "entry guards up. %d/%d entry guards usable/new.",
- entry->nickname, buf,
- num_live_entry_guards(), smartlist_len(entry_guards));
- log_entry_guards(LOG_INFO);
- changed = 1;
- }
- }
-
- if (changed)
- entry_guards_changed();
- return refuse_conn ? -1 : 0;
-}
-
-/** When we try to choose an entry guard, should we parse and add
- * config's EntryNodes first? */
-static int should_add_entry_nodes = 0;
-
-/** Called when the value of EntryNodes changes in our configuration. */
-void
-entry_nodes_should_be_added(void)
-{
- log_info(LD_CIRC, "EntryNodes config option set. Putting configured "
- "relays at the front of the entry guard list.");
- should_add_entry_nodes = 1;
-}
-
-/** Adjust the entry guards list so that it only contains entries from
- * EntryNodes, adding new entries from EntryNodes to the list as needed. */
-static void
-entry_guards_set_from_config(const or_options_t *options)
-{
- smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps;
- smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list;
- tor_assert(entry_guards);
-
- should_add_entry_nodes = 0;
-
- if (!options->EntryNodes) {
- /* It's possible that a controller set EntryNodes, thus making
- * should_add_entry_nodes set, then cleared it again, all before the
- * call to choose_random_entry() that triggered us. If so, just return.
- */
- return;
- }
-
- {
- char *string = routerset_to_string(options->EntryNodes);
- log_info(LD_CIRC,"Adding configured EntryNodes '%s'.", string);
- tor_free(string);
- }
-
- entry_nodes = smartlist_new();
- worse_entry_nodes = smartlist_new();
- entry_fps = smartlist_new();
- old_entry_guards_on_list = smartlist_new();
- old_entry_guards_not_on_list = smartlist_new();
-
- /* Split entry guards into those on the list and those not. */
-
- routerset_get_all_nodes(entry_nodes, options->EntryNodes,
- options->ExcludeNodes, 0);
- SMARTLIST_FOREACH(entry_nodes, const node_t *,node,
- smartlist_add(entry_fps, (void*)node->identity));
-
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, {
- if (smartlist_digest_isin(entry_fps, e->identity))
- smartlist_add(old_entry_guards_on_list, e);
- else
- smartlist_add(old_entry_guards_not_on_list, e);
- });
-
- /* Remove all currently configured guard nodes, excluded nodes, unreachable
- * nodes, or non-Guard nodes from entry_nodes. */
- SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
- if (entry_guard_get_by_id_digest(node->identity)) {
- SMARTLIST_DEL_CURRENT(entry_nodes, node);
- continue;
- } else if (routerset_contains_node(options->ExcludeNodes, node)) {
- SMARTLIST_DEL_CURRENT(entry_nodes, node);
- continue;
- } else if (!fascist_firewall_allows_node(node)) {
- SMARTLIST_DEL_CURRENT(entry_nodes, node);
- continue;
- } else if (! node->is_possible_guard) {
- smartlist_add(worse_entry_nodes, (node_t*)node);
- SMARTLIST_DEL_CURRENT(entry_nodes, node);
- }
- } SMARTLIST_FOREACH_END(node);
-
- /* Now build the new entry_guards list. */
- smartlist_clear(entry_guards);
- /* First, the previously configured guards that are in EntryNodes. */
- smartlist_add_all(entry_guards, old_entry_guards_on_list);
- /* Next, scramble the rest of EntryNodes, putting the guards first. */
- smartlist_shuffle(entry_nodes);
- smartlist_shuffle(worse_entry_nodes);
- smartlist_add_all(entry_nodes, worse_entry_nodes);
-
- /* Next, the rest of EntryNodes */
- SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
- add_an_entry_guard(node, 0, 0);
- if (smartlist_len(entry_guards) > options->NumEntryGuards * 10)
- break;
- } SMARTLIST_FOREACH_END(node);
- log_notice(LD_GENERAL, "%d entries in guards", smartlist_len(entry_guards));
- /* Finally, free the remaining previously configured guards that are not in
- * EntryNodes. */
- SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
- entry_guard_free(e));
-
- smartlist_free(entry_nodes);
- smartlist_free(worse_entry_nodes);
- smartlist_free(entry_fps);
- smartlist_free(old_entry_guards_on_list);
- smartlist_free(old_entry_guards_not_on_list);
- entry_guards_changed();
-}
-
-/** Return 0 if we're fine adding arbitrary routers out of the
- * directory to our entry guard list, or return 1 if we have a
- * list already and we must stick to it.
- */
-int
-entry_list_is_constrained(const or_options_t *options)
-{
- if (options->EntryNodes)
- return 1;
- if (options->UseBridges)
- return 1;
- return 0;
-}
-
-/** Pick a live (up and listed) entry guard from entry_guards. If
- * <b>state</b> is non-NULL, this is for a specific circuit --
- * make sure not to pick this circuit's exit or any node in the
- * exit's family. If <b>state</b> is NULL, we're looking for a random
- * guard (likely a bridge). */
-const node_t *
-choose_random_entry(cpath_build_state_t *state)
-{
- const or_options_t *options = get_options();
- smartlist_t *live_entry_guards = smartlist_new();
- smartlist_t *exit_family = smartlist_new();
- const node_t *chosen_exit =
- state?build_state_get_exit_node(state) : NULL;
- const node_t *node = NULL;
- int need_uptime = state ? state->need_uptime : 0;
- int need_capacity = state ? state->need_capacity : 0;
- int preferred_min, consider_exit_family = 0;
-
- if (chosen_exit) {
- nodelist_add_node_and_family(exit_family, chosen_exit);
- consider_exit_family = 1;
- }
-
- if (!entry_guards)
- entry_guards = smartlist_new();
-
- if (should_add_entry_nodes)
- entry_guards_set_from_config(options);
-
- if (!entry_list_is_constrained(options) &&
- smartlist_len(entry_guards) < options->NumEntryGuards)
- pick_entry_guards(options);
-
- retry:
- smartlist_clear(live_entry_guards);
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
- const char *msg;
- node = entry_is_live(entry, need_uptime, need_capacity, 0, &msg);
- if (!node)
- continue; /* down, no point */
- if (node == chosen_exit)
- continue; /* don't pick the same node for entry and exit */
- if (consider_exit_family && smartlist_isin(exit_family, node))
- continue; /* avoid relays that are family members of our exit */
-#if 0 /* since EntryNodes is always strict now, this clause is moot */
- if (options->EntryNodes &&
- !routerset_contains_node(options->EntryNodes, node)) {
- /* We've come to the end of our preferred entry nodes. */
- if (smartlist_len(live_entry_guards))
- goto choose_and_finish; /* only choose from the ones we like */
- if (options->StrictNodes) {
- /* in theory this case should never happen, since
- * entry_guards_set_from_config() drops unwanted relays */
- tor_fragile_assert();
- } else {
- log_info(LD_CIRC,
- "No relays from EntryNodes available. Using others.");
- }
- }
-#endif
- smartlist_add(live_entry_guards, (void*)node);
- if (!entry->made_contact) {
- /* Always start with the first not-yet-contacted entry
- * guard. Otherwise we might add several new ones, pick
- * the second new one, and now we've expanded our entry
- * guard list without needing to. */
- goto choose_and_finish;
- }
- if (smartlist_len(live_entry_guards) >= options->NumEntryGuards)
- goto choose_and_finish; /* we have enough */
- } SMARTLIST_FOREACH_END(entry);
-
- if (entry_list_is_constrained(options)) {
- /* If we prefer the entry nodes we've got, and we have at least
- * one choice, that's great. Use it. */
- preferred_min = 1;
- } else {
- /* Try to have at least 2 choices available. This way we don't
- * get stuck with a single live-but-crummy entry and just keep
- * using him.
- * (We might get 2 live-but-crummy entry guards, but so be it.) */
- preferred_min = 2;
- }
-
- if (smartlist_len(live_entry_guards) < preferred_min) {
- if (!entry_list_is_constrained(options)) {
- /* still no? try adding a new entry then */
- /* XXX if guard doesn't imply fast and stable, then we need
- * to tell add_an_entry_guard below what we want, or it might
- * be a long time til we get it. -RD */
- node = add_an_entry_guard(NULL, 0, 0);
- if (node) {
- entry_guards_changed();
- /* XXX we start over here in case the new node we added shares
- * a family with our exit node. There's a chance that we'll just
- * load up on entry guards here, if the network we're using is
- * one big family. Perhaps we should teach add_an_entry_guard()
- * to understand nodes-to-avoid-if-possible? -RD */
- goto retry;
- }
- }
- if (!node && need_uptime) {
- need_uptime = 0; /* try without that requirement */
- goto retry;
- }
- if (!node && need_capacity) {
- /* still no? last attempt, try without requiring capacity */
- need_capacity = 0;
- goto retry;
- }
-#if 0
- /* Removing this retry logic: if we only allow one exit, and it is in the
- same family as all our entries, then we are just plain not going to win
- here. */
- if (!node && entry_list_is_constrained(options) && consider_exit_family) {
- /* still no? if we're using bridges or have strictentrynodes
- * set, and our chosen exit is in the same family as all our
- * bridges/entry guards, then be flexible about families. */
- consider_exit_family = 0;
- goto retry;
- }
-#endif
- /* live_entry_guards may be empty below. Oh well, we tried. */
- }
-
- choose_and_finish:
- if (entry_list_is_constrained(options)) {
- /* We need to weight by bandwidth, because our bridges or entryguards
- * were not already selected proportional to their bandwidth. */
- node = node_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD);
- } else {
- /* We choose uniformly at random here, because choose_good_entry_server()
- * already weights its choices by bandwidth, so we don't want to
- * *double*-weight our guard selection. */
- node = smartlist_choose(live_entry_guards);
- }
- smartlist_free(live_entry_guards);
- smartlist_free(exit_family);
- return node;
-}
-
-/** Parse <b>state</b> and learn about the entry guards it describes.
- * If <b>set</b> is true, and there are no errors, replace the global
- * entry_list with what we find.
- * On success, return 0. On failure, alloc into *<b>msg</b> a string
- * describing the error, and return -1.
- */
-int
-entry_guards_parse_state(or_state_t *state, int set, char **msg)
-{
- entry_guard_t *node = NULL;
- smartlist_t *new_entry_guards = smartlist_new();
- config_line_t *line;
- time_t now = time(NULL);
- const char *state_version = state->TorVersion;
- digestmap_t *added_by = digestmap_new();
-
- *msg = NULL;
- for (line = state->EntryGuards; line; line = line->next) {
- if (!strcasecmp(line->key, "EntryGuard")) {
- smartlist_t *args = smartlist_new();
- node = tor_malloc_zero(sizeof(entry_guard_t));
- /* all entry guards on disk have been contacted */
- node->made_contact = 1;
- smartlist_add(new_entry_guards, node);
- smartlist_split_string(args, line->value, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- if (smartlist_len(args)<2) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Too few arguments to EntryGuard");
- } else if (!is_legal_nickname(smartlist_get(args,0))) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad nickname for EntryGuard");
- } else {
- strlcpy(node->nickname, smartlist_get(args,0), MAX_NICKNAME_LEN+1);
- if (base16_decode(node->identity, DIGEST_LEN, smartlist_get(args,1),
- strlen(smartlist_get(args,1)))<0) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad hex digest for EntryGuard");
- }
- }
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- if (*msg)
- break;
- } else if (!strcasecmp(line->key, "EntryGuardDownSince") ||
- !strcasecmp(line->key, "EntryGuardUnlistedSince")) {
- time_t when;
- time_t last_try = 0;
- if (!node) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "EntryGuardDownSince/UnlistedSince without EntryGuard");
- break;
- }
- if (parse_iso_time(line->value, &when)<0) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad time in EntryGuardDownSince/UnlistedSince");
- break;
- }
- if (when > now) {
- /* It's a bad idea to believe info in the future: you can wind
- * up with timeouts that aren't allowed to happen for years. */
- continue;
- }
- if (strlen(line->value) >= ISO_TIME_LEN+ISO_TIME_LEN+1) {
- /* ignore failure */
- (void) parse_iso_time(line->value+ISO_TIME_LEN+1, &last_try);
- }
- if (!strcasecmp(line->key, "EntryGuardDownSince")) {
- node->unreachable_since = when;
- node->last_attempted = last_try;
- } else {
- node->bad_since = when;
- }
- } else if (!strcasecmp(line->key, "EntryGuardAddedBy")) {
- char d[DIGEST_LEN];
- /* format is digest version date */
- if (strlen(line->value) < HEX_DIGEST_LEN+1+1+1+ISO_TIME_LEN) {
- log_warn(LD_BUG, "EntryGuardAddedBy line is not long enough.");
- continue;
- }
- if (base16_decode(d, sizeof(d), line->value, HEX_DIGEST_LEN)<0 ||
- line->value[HEX_DIGEST_LEN] != ' ') {
- log_warn(LD_BUG, "EntryGuardAddedBy line %s does not begin with "
- "hex digest", escaped(line->value));
- continue;
- }
- digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1));
- } else if (!strcasecmp(line->key, "EntryGuardPathBias")) {
- const or_options_t *options = get_options();
- unsigned hop_cnt, success_cnt;
-
- if (!node) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "EntryGuardPathBias without EntryGuard");
- break;
- }
-
- if (tor_sscanf(line->value, "%u %u", &success_cnt, &hop_cnt) != 2) {
- log_warn(LD_GENERAL, "Unable to parse guard path bias info: "
- "Misformated EntryGuardPathBias %s", escaped(line->value));
- continue;
- }
-
- node->first_hops = hop_cnt;
- node->circuit_successes = success_cnt;
- log_info(LD_GENERAL, "Read %u/%u path bias for node %s",
- node->circuit_successes, node->first_hops, node->nickname);
- /* Note: We rely on the < comparison here to allow us to set a 0
- * rate and disable the feature entirely. If refactoring, don't
- * change to <= */
- if (node->circuit_successes/((double)node->first_hops)
- < pathbias_get_disable_rate(options)) {
- node->path_bias_disabled = 1;
- log_info(LD_GENERAL,
- "Path bias is too high (%u/%u); disabling node %s",
- node->circuit_successes, node->first_hops, node->nickname);
- }
-
- } else {
- log_warn(LD_BUG, "Unexpected key %s", line->key);
- }
- }
-
- SMARTLIST_FOREACH_BEGIN(new_entry_guards, entry_guard_t *, e) {
- char *sp;
- char *val = digestmap_get(added_by, e->identity);
- if (val && (sp = strchr(val, ' '))) {
- time_t when;
- *sp++ = '\0';
- if (parse_iso_time(sp, &when)<0) {
- log_warn(LD_BUG, "Can't read time %s in EntryGuardAddedBy", sp);
- } else {
- e->chosen_by_version = tor_strdup(val);
- e->chosen_on_date = when;
- }
- } else {
- if (state_version) {
- e->chosen_by_version = tor_strdup(state_version);
- e->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
- }
- }
- if (e->path_bias_disabled && !e->bad_since)
- e->bad_since = time(NULL);
- }
- SMARTLIST_FOREACH_END(e);
-
- if (*msg || !set) {
- SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e,
- entry_guard_free(e));
- smartlist_free(new_entry_guards);
- } else { /* !err && set */
- if (entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- entry_guard_free(e));
- smartlist_free(entry_guards);
- }
- entry_guards = new_entry_guards;
- entry_guards_dirty = 0;
- /* XXX024 hand new_entry_guards to this func, and move it up a
- * few lines, so we don't have to re-dirty it */
- if (remove_obsolete_entry_guards(now))
- entry_guards_dirty = 1;
- }
- digestmap_free(added_by, _tor_free);
- return *msg ? -1 : 0;
-}
-
-/** Our list of entry guards has changed, or some element of one
- * of our entry guards has changed. Write the changes to disk within
- * the next few minutes.
- */
-static void
-entry_guards_changed(void)
-{
- time_t when;
- entry_guards_dirty = 1;
-
- /* or_state_save() will call entry_guards_update_state(). */
- when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600;
- or_state_mark_dirty(get_or_state(), when);
-}
-
-/** If the entry guard info has not changed, do nothing and return.
- * Otherwise, free the EntryGuards piece of <b>state</b> and create
- * a new one out of the global entry_guards list, and then mark
- * <b>state</b> dirty so it will get saved to disk.
- */
-void
-entry_guards_update_state(or_state_t *state)
-{
- config_line_t **next, *line;
- if (! entry_guards_dirty)
- return;
-
- config_free_lines(state->EntryGuards);
- next = &state->EntryGuards;
- *next = NULL;
- if (!entry_guards)
- entry_guards = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- char dbuf[HEX_DIGEST_LEN+1];
- if (!e->made_contact)
- continue; /* don't write this one to disk */
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuard");
- base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN);
- tor_asprintf(&line->value, "%s %s", e->nickname, dbuf);
- next = &(line->next);
- if (e->unreachable_since) {
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardDownSince");
- line->value = tor_malloc(ISO_TIME_LEN+1+ISO_TIME_LEN+1);
- format_iso_time(line->value, e->unreachable_since);
- if (e->last_attempted) {
- line->value[ISO_TIME_LEN] = ' ';
- format_iso_time(line->value+ISO_TIME_LEN+1, e->last_attempted);
- }
- next = &(line->next);
- }
- if (e->bad_since) {
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardUnlistedSince");
- line->value = tor_malloc(ISO_TIME_LEN+1);
- format_iso_time(line->value, e->bad_since);
- next = &(line->next);
- }
- if (e->chosen_on_date && e->chosen_by_version &&
- !strchr(e->chosen_by_version, ' ')) {
- char d[HEX_DIGEST_LEN+1];
- char t[ISO_TIME_LEN+1];
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardAddedBy");
- base16_encode(d, sizeof(d), e->identity, DIGEST_LEN);
- format_iso_time(t, e->chosen_on_date);
- tor_asprintf(&line->value, "%s %s %s",
- d, e->chosen_by_version, t);
- next = &(line->next);
- }
- if (e->first_hops) {
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardPathBias");
- tor_asprintf(&line->value, "%u %u",
- e->circuit_successes, e->first_hops);
- next = &(line->next);
- }
-
- } SMARTLIST_FOREACH_END(e);
- if (!get_options()->AvoidDiskWrites)
- or_state_mark_dirty(get_or_state(), 0);
- entry_guards_dirty = 0;
-}
-
-/** If <b>question</b> is the string "entry-guards", then dump
- * to *<b>answer</b> a newly allocated string describing all of
- * the nodes in the global entry_guards list. See control-spec.txt
- * for details.
- * For backward compatibility, we also handle the string "helper-nodes".
- * */
-int
-getinfo_helper_entry_guards(control_connection_t *conn,
- const char *question, char **answer,
- const char **errmsg)
-{
- (void) conn;
- (void) errmsg;
-
- if (!strcmp(question,"entry-guards") ||
- !strcmp(question,"helper-nodes")) {
- smartlist_t *sl = smartlist_new();
- char tbuf[ISO_TIME_LEN+1];
- char nbuf[MAX_VERBOSE_NICKNAME_LEN+1];
- if (!entry_guards)
- entry_guards = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- const char *status = NULL;
- time_t when = 0;
- const node_t *node;
-
- if (!e->made_contact) {
- status = "never-connected";
- } else if (e->bad_since) {
- when = e->bad_since;
- status = "unusable";
- } else {
- status = "up";
- }
-
- node = node_get_by_id(e->identity);
- if (node) {
- node_get_verbose_nickname(node, nbuf);
- } else {
- nbuf[0] = '$';
- base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN);
- /* e->nickname field is not very reliable if we don't know about
- * this router any longer; don't include it. */
- }
-
- if (when) {
- format_iso_time(tbuf, when);
- smartlist_add_asprintf(sl, "%s %s %s\n", nbuf, status, tbuf);
- } else {
- smartlist_add_asprintf(sl, "%s %s\n", nbuf, status);
- }
- } SMARTLIST_FOREACH_END(e);
- *answer = smartlist_join_strings(sl, "", 0, NULL);
- SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
- smartlist_free(sl);
- }
- return 0;
-}
-
-/** A list of configured bridges. Whenever we actually get a descriptor
- * for one, we add it as an entry guard. Note that the order of bridges
- * in this list does not necessarily correspond to the order of bridges
- * in the torrc. */
-static smartlist_t *bridge_list = NULL;
-
-/** Mark every entry of the bridge list to be removed on our next call to
- * sweep_bridge_list unless it has first been un-marked. */
-void
-mark_bridge_list(void)
-{
- if (!bridge_list)
- bridge_list = smartlist_new();
- SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b,
- b->marked_for_removal = 1);
-}
-
-/** Remove every entry of the bridge list that was marked with
- * mark_bridge_list if it has not subsequently been un-marked. */
-void
-sweep_bridge_list(void)
-{
- if (!bridge_list)
- bridge_list = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
- if (b->marked_for_removal) {
- SMARTLIST_DEL_CURRENT(bridge_list, b);
- bridge_free(b);
- }
- } SMARTLIST_FOREACH_END(b);
-}
-
-/** Initialize the bridge list to empty, creating it if needed. */
-static void
-clear_bridge_list(void)
-{
- if (!bridge_list)
- bridge_list = smartlist_new();
- SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b));
- smartlist_clear(bridge_list);
-}
-
-/** Free the bridge <b>bridge</b>. */
-static void
-bridge_free(bridge_info_t *bridge)
-{
- if (!bridge)
- return;
-
- tor_free(bridge->transport_name);
- tor_free(bridge);
-}
-
-/** A list of pluggable transports found in torrc. */
-static smartlist_t *transport_list = NULL;
-
-/** Mark every entry of the transport list to be removed on our next call to
- * sweep_transport_list unless it has first been un-marked. */
-void
-mark_transport_list(void)
-{
- if (!transport_list)
- transport_list = smartlist_new();
- SMARTLIST_FOREACH(transport_list, transport_t *, t,
- t->marked_for_removal = 1);
-}
-
-/** Remove every entry of the transport list that was marked with
- * mark_transport_list if it has not subsequently been un-marked. */
-void
-sweep_transport_list(void)
-{
- if (!transport_list)
- transport_list = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, t) {
- if (t->marked_for_removal) {
- SMARTLIST_DEL_CURRENT(transport_list, t);
- transport_free(t);
- }
- } SMARTLIST_FOREACH_END(t);
-}
-
-/** Initialize the pluggable transports list to empty, creating it if
- * needed. */
-void
-clear_transport_list(void)
-{
- if (!transport_list)
- transport_list = smartlist_new();
- SMARTLIST_FOREACH(transport_list, transport_t *, t, transport_free(t));
- smartlist_clear(transport_list);
-}
-
-/** Free the pluggable transport struct <b>transport</b>. */
-void
-transport_free(transport_t *transport)
-{
- if (!transport)
- return;
-
- tor_free(transport->name);
- tor_free(transport);
-}
-
-/** Returns the transport in our transport list that has the name <b>name</b>.
- * Else returns NULL. */
-transport_t *
-transport_get_by_name(const char *name)
-{
- tor_assert(name);
-
- if (!transport_list)
- return NULL;
-
- SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) {
- if (!strcmp(transport->name, name))
- return transport;
- } SMARTLIST_FOREACH_END(transport);
-
- return NULL;
-}
-
-/** Returns a transport_t struct for a transport proxy supporting the
- protocol <b>name</b> listening at <b>addr</b>:<b>port</b> using
- SOCKS version <b>socks_ver</b>. */
-transport_t *
-transport_new(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver)
-{
- transport_t *t = tor_malloc_zero(sizeof(transport_t));
-
- tor_addr_copy(&t->addr, addr);
- t->port = port;
- t->name = tor_strdup(name);
- t->socks_version = socks_ver;
-
- return t;
-}
-
-/** Resolve any conflicts that the insertion of transport <b>t</b>
- * might cause.
- * Return 0 if <b>t</b> is OK and should be registered, 1 if there is
- * a transport identical to <b>t</b> already registered and -1 if
- * <b>t</b> cannot be added due to conflicts. */
-static int
-transport_resolve_conflicts(transport_t *t)
-{
- /* This is how we resolve transport conflicts:
-
- If there is already a transport with the same name and addrport,
- we either have duplicate torrc lines OR we are here post-HUP and
- this transport was here pre-HUP as well. In any case, mark the
- old transport so that it doesn't get removed and ignore the new
- one. Our caller has to free the new transport so we return '1' to
- signify this.
-
- If there is already a transport with the same name but different
- addrport:
- * if it's marked for removal, it means that it either has a lower
- priority than 't' in torrc (otherwise the mark would have been
- cleared by the paragraph above), or it doesn't exist at all in
- the post-HUP torrc. We destroy the old transport and register 't'.
- * if it's *not* marked for removal, it means that it was newly
- added in the post-HUP torrc or that it's of higher priority, in
- this case we ignore 't'. */
- transport_t *t_tmp = transport_get_by_name(t->name);
- if (t_tmp) { /* same name */
- if (tor_addr_eq(&t->addr, &t_tmp->addr) && (t->port == t_tmp->port)) {
- /* same name *and* addrport */
- t_tmp->marked_for_removal = 0;
- return 1;
- } else { /* same name but different addrport */
- char *new_transport_addr = tor_strdup(fmt_addr(&t->addr));
- if (t_tmp->marked_for_removal) { /* marked for removal */
- log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' "
- "but there was already a transport marked for deletion at "
- "'%s:%u'. We deleted the old transport and registered the "
- "new one.", t->name, new_transport_addr, t->port,
- fmt_addr(&t_tmp->addr), t_tmp->port);
- smartlist_remove(transport_list, t_tmp);
- transport_free(t_tmp);
- tor_free(new_transport_addr);
- } else { /* *not* marked for removal */
- log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' "
- "but the same transport already exists at '%s:%u'. "
- "Skipping.", t->name, new_transport_addr, t->port,
- fmt_addr(&t_tmp->addr), t_tmp->port);
- tor_free(new_transport_addr);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-/** Add transport <b>t</b> to the internal list of pluggable
- * transports.
- * Returns 0 if the transport was added correctly, 1 if the same
- * transport was already registered (in this case the caller must
- * free the transport) and -1 if there was an error. */
-int
-transport_add(transport_t *t)
-{
- int r;
- tor_assert(t);
-
- r = transport_resolve_conflicts(t);
-
- switch (r) {
- case 0: /* should register transport */
- if (!transport_list)
- transport_list = smartlist_new();
- smartlist_add(transport_list, t);
- return 0;
- default: /* let our caller know the return code */
- return r;
- }
-}
-
-/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
- * <b>name</b> is set to the name of the protocol this proxy uses.
- * <b>socks_ver</b> is set to the SOCKS version of the proxy. */
-int
-transport_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver)
-{
- transport_t *t = transport_new(addr, port, name, socks_ver);
-
- int r = transport_add(t);
-
- switch (r) {
- case -1:
- default:
- log_notice(LD_GENERAL, "Could not add transport %s at %s:%u. Skipping.",
- t->name, fmt_addr(&t->addr), t->port);
- transport_free(t);
- return -1;
- case 1:
- log_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.",
- t->name, fmt_addr(&t->addr), t->port);
- transport_free(t); /* falling */
- return 0;
- case 0:
- log_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.",
- t->name, fmt_addr(&t->addr), t->port);
- return 0;
- }
-}
-
-/** Return a bridge pointer if <b>ri</b> is one of our known bridges
- * (either by comparing keys if possible, else by comparing addr/port).
- * Else return NULL. */
-static bridge_info_t *
-get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr,
- uint16_t port,
- const char *digest)
-{
- if (!bridge_list)
- return NULL;
- SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
- {
- if (tor_digest_is_zero(bridge->identity) &&
- !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) &&
- bridge->port == port)
- return bridge;
- if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN))
- return bridge;
- }
- SMARTLIST_FOREACH_END(bridge);
- return NULL;
-}
-
-/** Wrapper around get_configured_bridge_by_addr_port_digest() to look
- * it up via router descriptor <b>ri</b>. */
-static bridge_info_t *
-get_configured_bridge_by_routerinfo(const routerinfo_t *ri)
-{
- tor_addr_port_t ap;
-
- router_get_pref_orport(ri, &ap);
- return get_configured_bridge_by_addr_port_digest(&ap.addr, ap.port,
- ri->cache_info.identity_digest);
-}
-
-/** Return 1 if <b>ri</b> is one of our known bridges, else 0. */
-int
-routerinfo_is_a_configured_bridge(const routerinfo_t *ri)
-{
- return get_configured_bridge_by_routerinfo(ri) ? 1 : 0;
-}
-
-/** Return 1 if <b>node</b> is one of our configured bridges, else 0. */
-int
-node_is_a_configured_bridge(const node_t *node)
-{
- int retval = 0; /* Negative. */
- smartlist_t *orports = NULL;
-
- if (!node)
- goto out;
-
- orports = node_get_all_orports(node);
- if (orports == NULL)
- goto out;
-
- SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, orport) {
- if (get_configured_bridge_by_addr_port_digest(&orport->addr, orport->port,
- node->identity) != NULL) {
- retval = 1;
- goto out;
- }
- } SMARTLIST_FOREACH_END(orport);
-
- out:
- if (orports != NULL) {
- SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p));
- smartlist_free(orports);
- orports = NULL;
- }
- return retval;
-}
-
-/** We made a connection to a router at <b>addr</b>:<b>port</b>
- * without knowing its digest. Its digest turned out to be <b>digest</b>.
- * If it was a bridge, and we still don't know its digest, record it.
- */
-void
-learned_router_identity(const tor_addr_t *addr, uint16_t port,
- const char *digest)
-{
- bridge_info_t *bridge =
- get_configured_bridge_by_addr_port_digest(addr, port, digest);
- if (bridge && tor_digest_is_zero(bridge->identity)) {
- memcpy(bridge->identity, digest, DIGEST_LEN);
- log_notice(LD_DIR, "Learned fingerprint %s for bridge %s:%d",
- hex_str(digest, DIGEST_LEN), fmt_addr(addr), port);
- }
-}
-
-/** Return true if <b>bridge</b> has the same identity digest as
- * <b>digest</b>. If <b>digest</b> is NULL, it matches
- * bridges with unspecified identity digests. */
-static int
-bridge_has_digest(const bridge_info_t *bridge, const char *digest)
-{
- if (digest)
- return tor_memeq(digest, bridge->identity, DIGEST_LEN);
- else
- return tor_digest_is_zero(bridge->identity);
-}
-
-/** We are about to add a new bridge at <b>addr</b>:<b>port</b>, with optional
- * <b>digest</b> and <b>transport_name</b>. Mark for removal any previously
- * existing bridge with the same address and port, and warn the user as
- * appropriate.
- */
-static void
-bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
- const char *digest, const char *transport_name)
-{
- /* Iterate the already-registered bridge list:
-
- If you find a bridge with the same adress and port, mark it for
- removal. It doesn't make sense to have two active bridges with
- the same IP:PORT. If the bridge in question has a different
- digest or transport than <b>digest</b>/<b>transport_name</b>,
- it's probably a misconfiguration and we should warn the user.
- */
- SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) {
- if (bridge->marked_for_removal)
- continue;
-
- if (tor_addr_eq(&bridge->addr, addr) && (bridge->port == port)) {
-
- bridge->marked_for_removal = 1;
-
- if (!bridge_has_digest(bridge, digest) ||
- strcmp_opt(bridge->transport_name, transport_name)) {
- /* warn the user */
- char *bridge_description_new, *bridge_description_old;
- tor_asprintf(&bridge_description_new, "%s:%u:%s:%s",
- fmt_addr(addr), port,
- digest ? hex_str(digest, DIGEST_LEN) : "",
- transport_name ? transport_name : "");
- tor_asprintf(&bridge_description_old, "%s:%u:%s:%s",
- fmt_addr(&bridge->addr), bridge->port,
- tor_digest_is_zero(bridge->identity) ?
- "" : hex_str(bridge->identity,DIGEST_LEN),
- bridge->transport_name ? bridge->transport_name : "");
-
- log_warn(LD_GENERAL,"Tried to add bridge '%s', but we found a conflict"
- " with the already registered bridge '%s'. We will discard"
- " the old bridge and keep '%s'. If this is not what you"
- " wanted, please change your configuration file accordingly.",
- bridge_description_new, bridge_description_old,
- bridge_description_new);
-
- tor_free(bridge_description_new);
- tor_free(bridge_description_old);
- }
- }
- } SMARTLIST_FOREACH_END(bridge);
-}
-
-/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
- * is set, it tells us the identity key too. If we already had the
- * bridge in our list, unmark it, and don't actually add anything new.
- * If <b>transport_name</b> is non-NULL - the bridge is associated with a
- * pluggable transport - we assign the transport to the bridge. */
-void
-bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *digest, const char *transport_name)
-{
- bridge_info_t *b;
-
- bridge_resolve_conflicts(addr, port, digest, transport_name);
-
- b = tor_malloc_zero(sizeof(bridge_info_t));
- tor_addr_copy(&b->addr, addr);
- b->port = port;
- if (digest)
- memcpy(b->identity, digest, DIGEST_LEN);
- if (transport_name)
- b->transport_name = tor_strdup(transport_name);
- b->fetch_status.schedule = DL_SCHED_BRIDGE;
- if (!bridge_list)
- bridge_list = smartlist_new();
-
- smartlist_add(bridge_list, b);
-}
-
-/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */
-static int
-routerset_contains_bridge(const routerset_t *routerset,
- const bridge_info_t *bridge)
-{
- int result;
- extend_info_t *extinfo;
- tor_assert(bridge);
- if (!routerset)
- return 0;
-
- extinfo = extend_info_alloc(
- NULL, bridge->identity, NULL, &bridge->addr, bridge->port);
- result = routerset_contains_extendinfo(routerset, extinfo);
- extend_info_free(extinfo);
- return result;
-}
-
-/** If <b>digest</b> is one of our known bridges, return it. */
-static bridge_info_t *
-find_bridge_by_digest(const char *digest)
-{
- SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge,
- {
- if (tor_memeq(bridge->identity, digest, DIGEST_LEN))
- return bridge;
- });
- return NULL;
-}
-
-/* DOCDOC find_transport_name_by_bridge_addrport */
-const char *
-find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
-{
- if (!bridge_list)
- return NULL;
-
- SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
- if (tor_addr_eq(&bridge->addr, addr) &&
- (bridge->port == port))
- return bridge->transport_name;
- } SMARTLIST_FOREACH_END(bridge);
-
- return NULL;
-}
-
-/** If <b>addr</b> and <b>port</b> match the address and port of a
- * bridge of ours that uses pluggable transports, place its transport
- * in <b>transport</b>.
- *
- * Return 0 on success (found a transport, or found a bridge with no
- * transport, or found no bridge); return -1 if we should be using a
- * transport, but the transport could not be found.
- */
-int
-find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
- const transport_t **transport)
-{
- *transport = NULL;
- if (!bridge_list)
- return 0;
-
- SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
- if (tor_addr_eq(&bridge->addr, addr) &&
- (bridge->port == port)) { /* bridge matched */
- if (bridge->transport_name) { /* it also uses pluggable transports */
- *transport = transport_get_by_name(bridge->transport_name);
- if (*transport == NULL) { /* it uses pluggable transports, but
- the transport could not be found! */
- return -1;
- }
- return 0;
- } else { /* bridge matched, but it doesn't use transports. */
- break;
- }
- }
- } SMARTLIST_FOREACH_END(bridge);
-
- *transport = NULL;
- return 0;
-}
-
-/** We need to ask <b>bridge</b> for its server descriptor. */
-static void
-launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
-{
- char *address;
- const or_options_t *options = get_options();
-
- if (connection_get_by_type_addr_port_purpose(
- CONN_TYPE_DIR, &bridge->addr, bridge->port,
- DIR_PURPOSE_FETCH_SERVERDESC))
- return; /* it's already on the way */
-
- if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
- download_status_mark_impossible(&bridge->fetch_status);
- log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
- safe_str_client(fmt_addr(&bridge->addr)));
- return;
- }
-
- address = tor_dup_addr(&bridge->addr);
-
- directory_initiate_command(address, &bridge->addr,
- bridge->port, 0,
- 0, /* does not matter */
- 1, bridge->identity,
- DIR_PURPOSE_FETCH_SERVERDESC,
- ROUTER_PURPOSE_BRIDGE,
- 0, "authority.z", NULL, 0, 0);
- tor_free(address);
-}
-
-/** Fetching the bridge descriptor from the bridge authority returned a
- * "not found". Fall back to trying a direct fetch. */
-void
-retry_bridge_descriptor_fetch_directly(const char *digest)
-{
- bridge_info_t *bridge = find_bridge_by_digest(digest);
- if (!bridge)
- return; /* not found? oh well. */
-
- launch_direct_bridge_descriptor_fetch(bridge);
-}
-
-/** For each bridge in our list for which we don't currently have a
- * descriptor, fetch a new copy of its descriptor -- either directly
- * from the bridge or via a bridge authority. */
-void
-fetch_bridge_descriptors(const or_options_t *options, time_t now)
-{
- int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO);
- int ask_bridge_directly;
- int can_use_bridge_authority;
-
- if (!bridge_list)
- return;
-
- /* If we still have unconfigured managed proxies, don't go and
- connect to a bridge. */
- if (pt_proxies_configuration_pending())
- return;
-
- SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
- {
- if (!download_status_is_ready(&bridge->fetch_status, now,
- IMPOSSIBLE_TO_DOWNLOAD))
- continue; /* don't bother, no need to retry yet */
- if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
- download_status_mark_impossible(&bridge->fetch_status);
- log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
- safe_str_client(fmt_addr(&bridge->addr)));
- continue;
- }
-
- /* schedule another fetch as if this one will fail, in case it does */
- download_status_failed(&bridge->fetch_status, 0);
-
- can_use_bridge_authority = !tor_digest_is_zero(bridge->identity) &&
- num_bridge_auths;
- ask_bridge_directly = !can_use_bridge_authority ||
- !options->UpdateBridgesFromAuthority;
- log_debug(LD_DIR, "ask_bridge_directly=%d (%d, %d, %d)",
- ask_bridge_directly, tor_digest_is_zero(bridge->identity),
- !options->UpdateBridgesFromAuthority, !num_bridge_auths);
-
- if (ask_bridge_directly &&
- !fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) {
- log_notice(LD_DIR, "Bridge at '%s:%d' isn't reachable by our "
- "firewall policy. %s.", fmt_addr(&bridge->addr),
- bridge->port,
- can_use_bridge_authority ?
- "Asking bridge authority instead" : "Skipping");
- if (can_use_bridge_authority)
- ask_bridge_directly = 0;
- else
- continue;
- }
-
- if (ask_bridge_directly) {
- /* we need to ask the bridge itself for its descriptor. */
- launch_direct_bridge_descriptor_fetch(bridge);
- } else {
- /* We have a digest and we want to ask an authority. We could
- * combine all the requests into one, but that may give more
- * hints to the bridge authority than we want to give. */
- char resource[10 + HEX_DIGEST_LEN];
- memcpy(resource, "fp/", 3);
- base16_encode(resource+3, HEX_DIGEST_LEN+1,
- bridge->identity, DIGEST_LEN);
- memcpy(resource+3+HEX_DIGEST_LEN, ".z", 3);
- log_info(LD_DIR, "Fetching bridge info '%s' from bridge authority.",
- resource);
- directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,
- ROUTER_PURPOSE_BRIDGE, resource, 0);
- }
- }
- SMARTLIST_FOREACH_END(bridge);
-}
-
-/** If our <b>bridge</b> is configured to be a different address than
- * the bridge gives in <b>node</b>, rewrite the routerinfo
- * we received to use the address we meant to use. Now we handle
- * multihomed bridges better.
- */
-static void
-rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
-{
- /* XXXX move this function. */
- /* XXXX overridden addresses should really live in the node_t, so that the
- * routerinfo_t and the microdesc_t can be immutable. But we can only
- * do that safely if we know that no function that connects to an OR
- * does so through an address from any source other than node_get_addr().
- */
- tor_addr_t addr;
-
- if (node->ri) {
- routerinfo_t *ri = node->ri;
- tor_addr_from_ipv4h(&addr, ri->addr);
-
- if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
- bridge->port == ri->or_port) ||
- (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) &&
- bridge->port == ri->ipv6_orport)) {
- /* they match, so no need to do anything */
- } else {
- if (tor_addr_family(&bridge->addr) == AF_INET) {
- ri->addr = tor_addr_to_ipv4h(&bridge->addr);
- tor_free(ri->address);
- ri->address = tor_dup_ip(ri->addr);
- ri->or_port = bridge->port;
- log_info(LD_DIR,
- "Adjusted bridge routerinfo for '%s' to match configured "
- "address %s:%d.",
- ri->nickname, ri->address, ri->or_port);
- } else if (tor_addr_family(&bridge->addr) == AF_INET6) {
- tor_addr_copy(&ri->ipv6_addr, &bridge->addr);
- ri->ipv6_orport = bridge->port;
- log_info(LD_DIR,
- "Adjusted bridge routerinfo for '%s' to match configured "
- "address %s:%d.",
- ri->nickname, fmt_addr(&ri->ipv6_addr), ri->ipv6_orport);
- } else {
- log_err(LD_BUG, "Address family not supported: %d.",
- tor_addr_family(&bridge->addr));
- return;
- }
- }
-
- /* Indicate that we prefer connecting to this bridge over the
- protocol that the bridge address indicates. Last bridge
- descriptor handled wins. */
- ri->ipv6_preferred = tor_addr_family(&bridge->addr) == AF_INET6;
-
- /* XXXipv6 we lack support for falling back to another address for
- the same relay, warn the user */
- if (!tor_addr_is_null(&ri->ipv6_addr)) {
- tor_addr_port_t ap;
- router_get_pref_orport(ri, &ap);
- log_notice(LD_CONFIG,
- "Bridge '%s' has both an IPv4 and an IPv6 address. "
- "Will prefer using its %s address (%s:%d).",
- ri->nickname,
- ri->ipv6_preferred ? "IPv6" : "IPv4",
- fmt_addr(&ap.addr), ap.port);
- }
- }
- if (node->rs) {
- routerstatus_t *rs = node->rs;
- tor_addr_from_ipv4h(&addr, rs->addr);
-
- if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
- bridge->port == rs->or_port) {
- /* they match, so no need to do anything */
- } else {
- rs->addr = tor_addr_to_ipv4h(&bridge->addr);
- rs->or_port = bridge->port;
- log_info(LD_DIR,
- "Adjusted bridge routerstatus for '%s' to match "
- "configured address %s:%d.",
- rs->nickname, fmt_addr(&bridge->addr), rs->or_port);
- }
- }
-}
-
-/** We just learned a descriptor for a bridge. See if that
- * digest is in our entry guard list, and add it if not. */
-void
-learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
-{
- tor_assert(ri);
- tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
- if (get_options()->UseBridges) {
- int first = !any_bridge_descriptors_known();
- bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri);
- time_t now = time(NULL);
- router_set_status(ri->cache_info.identity_digest, 1);
-
- if (bridge) { /* if we actually want to use this one */
- node_t *node;
- /* it's here; schedule its re-fetch for a long time from now. */
- if (!from_cache)
- download_status_reset(&bridge->fetch_status);
-
- node = node_get_mutable_by_id(ri->cache_info.identity_digest);
- tor_assert(node);
- rewrite_node_address_for_bridge(bridge, node);
- add_an_entry_guard(node, 1, 1);
-
- log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
- from_cache ? "cached" : "fresh", router_describe(ri));
- /* set entry->made_contact so if it goes down we don't drop it from
- * our entry node list */
- entry_guard_register_connect_status(ri->cache_info.identity_digest,
- 1, 0, now);
- if (first)
- routerlist_retry_directory_downloads(now);
- }
- }
-}
-
-/** Return 1 if any of our entry guards have descriptors that
- * are marked with purpose 'bridge' and are running. Else return 0.
- *
- * We use this function to decide if we're ready to start building
- * circuits through our bridges, or if we need to wait until the
- * directory "server/authority" requests finish. */
-int
-any_bridge_descriptors_known(void)
-{
- tor_assert(get_options()->UseBridges);
- return choose_random_entry(NULL)!=NULL ? 1 : 0;
-}
-
-/** Return 1 if there are any directory conns fetching bridge descriptors
- * that aren't marked for close. We use this to guess if we should tell
- * the controller that we have a problem. */
-int
-any_pending_bridge_descriptor_fetches(void)
-{
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
- if (conn->type == CONN_TYPE_DIR &&
- conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
- TO_DIR_CONN(conn)->router_purpose == ROUTER_PURPOSE_BRIDGE &&
- !conn->marked_for_close &&
- conn->linked &&
- conn->linked_conn && !conn->linked_conn->marked_for_close) {
- log_debug(LD_DIR, "found one: %s", conn->address);
- return 1;
- }
- } SMARTLIST_FOREACH_END(conn);
- return 0;
-}
-
-/** Return 1 if we have at least one descriptor for an entry guard
- * (bridge or member of EntryNodes) and all descriptors we know are
- * down. Else return 0. If <b>act</b> is 1, then mark the down guards
- * up; else just observe and report. */
-static int
-entries_retry_helper(const or_options_t *options, int act)
-{
- const node_t *node;
- int any_known = 0;
- int any_running = 0;
- int need_bridges = options->UseBridges != 0;
- if (!entry_guards)
- entry_guards = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- node = node_get_by_id(e->identity);
- if (node && node_has_descriptor(node) &&
- node_is_bridge(node) == need_bridges) {
- any_known = 1;
- if (node->is_running)
- any_running = 1; /* some entry is both known and running */
- else if (act) {
- /* Mark all current connections to this OR as unhealthy, since
- * otherwise there could be one that started 30 seconds
- * ago, and in 30 seconds it will time out, causing us to mark
- * the node down and undermine the retry attempt. We mark even
- * the established conns, since if the network just came back
- * we'll want to attach circuits to fresh conns. */
- connection_or_set_bad_connections(node->identity, 1);
-
- /* mark this entry node for retry */
- router_set_status(node->identity, 1);
- e->can_retry = 1;
- e->bad_since = 0;
- }
- }
- } SMARTLIST_FOREACH_END(e);
- log_debug(LD_DIR, "%d: any_known %d, any_running %d",
- act, any_known, any_running);
- return any_known && !any_running;
-}
-
-/** Do we know any descriptors for our bridges / entrynodes, and are
- * all the ones we have descriptors for down? */
-int
-entries_known_but_down(const or_options_t *options)
-{
- tor_assert(entry_list_is_constrained(options));
- return entries_retry_helper(options, 0);
-}
-
-/** Mark all down known bridges / entrynodes up. */
-void
-entries_retry_all(const or_options_t *options)
-{
- tor_assert(entry_list_is_constrained(options));
- entries_retry_helper(options, 1);
-}
-
-/** Return true if we've ever had a bridge running a Tor version that can't
- * provide microdescriptors to us. In that case fall back to asking for
- * full descriptors. Eventually all bridges will support microdescriptors
- * and we can take this check out; see bug 4013. */
-int
-any_bridges_dont_support_microdescriptors(void)
-{
- const node_t *node;
- static int ever_answered_yes = 0;
- if (!get_options()->UseBridges || !entry_guards)
- return 0;
- if (ever_answered_yes)
- return 1; /* if we ever answer 'yes', always answer 'yes' */
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- node = node_get_by_id(e->identity);
- if (node && node->ri &&
- node_is_bridge(node) && node_is_a_configured_bridge(node) &&
- !tor_version_supports_microdescriptors(node->ri->platform)) {
- /* This is one of our current bridges, and we know enough about
- * it to know that it won't be able to answer our microdescriptor
- * questions. */
- ever_answered_yes = 1;
- return 1;
- }
- } SMARTLIST_FOREACH_END(e);
- return 0;
-}
-
-/** Release all storage held by the list of entry guards and related
- * memory structs. */
-void
-entry_guards_free_all(void)
-{
- if (entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- entry_guard_free(e));
- smartlist_free(entry_guards);
- entry_guards = NULL;
- }
- clear_bridge_list();
- clear_transport_list();
- smartlist_free(bridge_list);
- smartlist_free(transport_list);
- bridge_list = NULL;
- transport_list = NULL;
-}
-
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index 984d04a99e..78575afcf2 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -9,23 +9,8 @@
* \brief Header file for circuitbuild.c.
**/
-#ifndef _TOR_CIRCUITBUILD_H
-#define _TOR_CIRCUITBUILD_H
-
-/** Represents a pluggable transport proxy used by a bridge. */
-typedef struct {
- /** SOCKS version: One of PROXY_SOCKS4, PROXY_SOCKS5. */
- int socks_version;
- /** Name of pluggable transport protocol */
- char *name;
- /** Address of proxy */
- tor_addr_t addr;
- /** Port of proxy */
- uint16_t port;
- /** Boolean: We are re-parsing our transport list, and we are going to remove
- * this one if we don't find it in the list of configured transports. */
- unsigned marked_for_removal : 1;
-} transport_t;
+#ifndef TOR_CIRCUITBUILD_H
+#define TOR_CIRCUITBUILD_H
char *circuit_list_path(origin_circuit_t *circ, int verbose);
char *circuit_list_path_for_controller(origin_circuit_t *circ);
@@ -37,7 +22,7 @@ origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
extend_info_t *exit,
int flags);
int circuit_handle_first_hop(origin_circuit_t *circ);
-void circuit_n_conn_done(or_connection_t *or_conn, int status);
+void circuit_n_chan_done(channel_t *chan, int status);
int inform_testing_reachability(void);
int circuit_timeout_want_to_count_circ(origin_circuit_t *circ);
int circuit_send_next_onion_skin(origin_circuit_t *circ);
@@ -47,7 +32,8 @@ int circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
int reverse);
int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
const uint8_t *reply);
-int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer);
+int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer,
+ int reason);
int onionskin_answer(or_circuit_t *circ, uint8_t cell_type,
const char *payload, const char *keys);
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
@@ -56,116 +42,18 @@ int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
-extend_info_t *extend_info_alloc(const char *nickname, const char *digest,
+extend_info_t *extend_info_new(const char *nickname, const char *digest,
crypto_pk_t *onion_key,
const tor_addr_t *addr, uint16_t port);
-extend_info_t *extend_info_from_router(const routerinfo_t *r,
- int for_direct_connect);
-extend_info_t *extend_info_from_node(const node_t *node,
- int for_direct_connect);
+extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
extend_info_t *extend_info_dup(extend_info_t *info);
void extend_info_free(extend_info_t *info);
const node_t *build_state_get_exit_node(cpath_build_state_t *state);
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
-void entry_guards_compute_status(const or_options_t *options, time_t now);
-int entry_guard_register_connect_status(const char *digest, int succeeded,
- int mark_relay_status, time_t now);
-void entry_nodes_should_be_added(void);
-int entry_list_is_constrained(const or_options_t *options);
-const node_t *choose_random_entry(cpath_build_state_t *state);
-int entry_guards_parse_state(or_state_t *state, int set, char **msg);
-void entry_guards_update_state(or_state_t *state);
-int getinfo_helper_entry_guards(control_connection_t *conn,
- const char *question, char **answer,
- const char **errmsg);
-
-void mark_bridge_list(void);
-void sweep_bridge_list(void);
-void mark_transport_list(void);
-void sweep_transport_list(void);
-
-int routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
-int node_is_a_configured_bridge(const node_t *node);
-void learned_router_identity(const tor_addr_t *addr, uint16_t port,
- const char *digest);
-void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *digest,
- const char *transport_name);
-void retry_bridge_descriptor_fetch_directly(const char *digest);
-void fetch_bridge_descriptors(const or_options_t *options, time_t now);
-void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
-int any_bridge_descriptors_known(void);
-int any_pending_bridge_descriptor_fetches(void);
-int entries_known_but_down(const or_options_t *options);
-void entries_retry_all(const or_options_t *options);
-
-int any_bridges_dont_support_microdescriptors(void);
-
-void entry_guards_free_all(void);
-
-extern circuit_build_times_t circ_times;
-int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt);
-void circuit_build_times_update_state(circuit_build_times_t *cbt,
- or_state_t *state);
-int circuit_build_times_parse_state(circuit_build_times_t *cbt,
- or_state_t *state);
-void circuit_build_times_count_timeout(circuit_build_times_t *cbt,
- int did_onehop);
-int circuit_build_times_count_close(circuit_build_times_t *cbt,
- int did_onehop, time_t start_time);
-void circuit_build_times_set_timeout(circuit_build_times_t *cbt);
-int circuit_build_times_add_time(circuit_build_times_t *cbt,
- build_time_t time);
-int circuit_build_times_needs_circuits(circuit_build_times_t *cbt);
-
-int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt);
-void circuit_build_times_init(circuit_build_times_t *cbt);
-void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
-void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
- networkstatus_t *ns);
-double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
-double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
-
-#ifdef CIRCUIT_PRIVATE
-double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
- double quantile);
-build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt,
- double q_lo, double q_hi);
-void circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
- double quantile, double time_ms);
-int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
-double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
-void circuitbuild_running_unit_tests(void);
-void circuit_build_times_reset(circuit_build_times_t *cbt);
-
-/* Network liveness functions */
-int circuit_build_times_network_check_changed(circuit_build_times_t *cbt);
-#endif
-
-/* Network liveness functions */
-void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
-int circuit_build_times_network_check_live(circuit_build_times_t *cbt);
-void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
-
-/* DOCDOC circuit_build_times_get_bw_scale */
-int circuit_build_times_get_bw_scale(networkstatus_t *ns);
-
-void clear_transport_list(void);
-int transport_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver);
-int transport_add(transport_t *t);
-void transport_free(transport_t *transport);
-transport_t *transport_new(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver);
-
-/* DOCDOC find_transport_name_by_bridge_addrport */
-const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr,
- uint16_t port);
-
-int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
- const transport_t **transport);
-transport_t *transport_get_by_name(const char *name);
+const node_t *choose_good_entry_server(uint8_t purpose,
+ cpath_build_state_t *state);
+double pathbias_get_disable_rate(const or_options_t *options);
#endif
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 93ba69dcf0..8f06c0679e 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -10,9 +10,11 @@
**/
#include "or.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
+#include "circuitstats.h"
#include "connection.h"
#include "config.h"
#include "connection_edge.h"
@@ -26,6 +28,7 @@
#include "rendcommon.h"
#include "rephist.h"
#include "routerlist.h"
+#include "routerset.h"
#include "ht.h"
/********* START VARIABLES **********/
@@ -33,8 +36,8 @@
/** A global list of all circuits at this hop. */
circuit_t *global_circuitlist=NULL;
-/** A list of all the circuits in CIRCUIT_STATE_OR_WAIT. */
-static smartlist_t *circuits_pending_or_conns=NULL;
+/** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */
+static smartlist_t *circuits_pending_chans = NULL;
static void circuit_free(circuit_t *circ);
static void circuit_free_cpath(crypt_path_t *cpath);
@@ -43,154 +46,190 @@ static void cpath_ref_decref(crypt_path_reference_t *cpath_ref);
/********* END VARIABLES ************/
-/** A map from OR connection and circuit ID to circuit. (Lookup performance is
+/** A map from channel and circuit ID to circuit. (Lookup performance is
* very important here, since we need to do it every time a cell arrives.) */
-typedef struct orconn_circid_circuit_map_t {
- HT_ENTRY(orconn_circid_circuit_map_t) node;
- or_connection_t *or_conn;
+typedef struct chan_circid_circuit_map_t {
+ HT_ENTRY(chan_circid_circuit_map_t) node;
+ channel_t *chan;
circid_t circ_id;
circuit_t *circuit;
-} orconn_circid_circuit_map_t;
+} chan_circid_circuit_map_t;
-/** Helper for hash tables: compare the OR connection and circuit ID for a and
+/** Helper for hash tables: compare the channel and circuit ID for a and
* b, and return less than, equal to, or greater than zero appropriately.
*/
static INLINE int
-_orconn_circid_entries_eq(orconn_circid_circuit_map_t *a,
- orconn_circid_circuit_map_t *b)
+chan_circid_entries_eq_(chan_circid_circuit_map_t *a,
+ chan_circid_circuit_map_t *b)
{
- return a->or_conn == b->or_conn && a->circ_id == b->circ_id;
+ return a->chan == b->chan && a->circ_id == b->circ_id;
}
/** Helper: return a hash based on circuit ID and the pointer value of
- * or_conn in <b>a</b>. */
+ * chan in <b>a</b>. */
static INLINE unsigned int
-_orconn_circid_entry_hash(orconn_circid_circuit_map_t *a)
+chan_circid_entry_hash_(chan_circid_circuit_map_t *a)
{
- return (((unsigned)a->circ_id)<<8) ^ (unsigned)(uintptr_t)(a->or_conn);
+ return (((unsigned)a->circ_id)<<8) ^ (unsigned)(uintptr_t)(a->chan);
}
-/** Map from [orconn,circid] to circuit. */
-static HT_HEAD(orconn_circid_map, orconn_circid_circuit_map_t)
- orconn_circid_circuit_map = HT_INITIALIZER();
-HT_PROTOTYPE(orconn_circid_map, orconn_circid_circuit_map_t, node,
- _orconn_circid_entry_hash, _orconn_circid_entries_eq)
-HT_GENERATE(orconn_circid_map, orconn_circid_circuit_map_t, node,
- _orconn_circid_entry_hash, _orconn_circid_entries_eq, 0.6,
+/** Map from [chan,circid] to circuit. */
+static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t)
+ chan_circid_map = HT_INITIALIZER();
+HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node,
+ chan_circid_entry_hash_, chan_circid_entries_eq_)
+HT_GENERATE(chan_circid_map, chan_circid_circuit_map_t, node,
+ chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6,
malloc, realloc, free)
-/** The most recently returned entry from circuit_get_by_circid_orconn;
+/** The most recently returned entry from circuit_get_by_circid_chan;
* used to improve performance when many cells arrive in a row from the
* same circuit.
*/
-orconn_circid_circuit_map_t *_last_circid_orconn_ent = NULL;
+chan_circid_circuit_map_t *_last_circid_chan_ent = NULL;
-/** Implementation helper for circuit_set_{p,n}_circid_orconn: A circuit ID
- * and/or or_connection for circ has just changed from <b>old_conn, old_id</b>
- * to <b>conn, id</b>. Adjust the conn,circid map as appropriate, removing
+/** Implementation helper for circuit_set_{p,n}_circid_channel: A circuit ID
+ * and/or channel for circ has just changed from <b>old_chan, old_id</b>
+ * to <b>chan, id</b>. Adjust the chan,circid map as appropriate, removing
* the old entry (if any) and adding a new one. */
static void
-circuit_set_circid_orconn_helper(circuit_t *circ, int direction,
- circid_t id,
- or_connection_t *conn)
+circuit_set_circid_chan_helper(circuit_t *circ, int direction,
+ circid_t id,
+ channel_t *chan)
{
- orconn_circid_circuit_map_t search;
- orconn_circid_circuit_map_t *found;
- or_connection_t *old_conn, **conn_ptr;
+ chan_circid_circuit_map_t search;
+ chan_circid_circuit_map_t *found;
+ channel_t *old_chan, **chan_ptr;
circid_t old_id, *circid_ptr;
- int was_active, make_active;
+ int make_active, attached = 0;
if (direction == CELL_DIRECTION_OUT) {
- conn_ptr = &circ->n_conn;
+ chan_ptr = &circ->n_chan;
circid_ptr = &circ->n_circ_id;
- was_active = circ->next_active_on_n_conn != NULL;
- make_active = circ->n_conn_cells.n > 0;
+ make_active = circ->n_chan_cells.n > 0;
} else {
or_circuit_t *c = TO_OR_CIRCUIT(circ);
- conn_ptr = &c->p_conn;
+ chan_ptr = &c->p_chan;
circid_ptr = &c->p_circ_id;
- was_active = c->next_active_on_p_conn != NULL;
- make_active = c->p_conn_cells.n > 0;
+ make_active = c->p_chan_cells.n > 0;
}
- old_conn = *conn_ptr;
+ old_chan = *chan_ptr;
old_id = *circid_ptr;
- if (id == old_id && conn == old_conn)
+ if (id == old_id && chan == old_chan)
return;
- if (_last_circid_orconn_ent &&
- ((old_id == _last_circid_orconn_ent->circ_id &&
- old_conn == _last_circid_orconn_ent->or_conn) ||
- (id == _last_circid_orconn_ent->circ_id &&
- conn == _last_circid_orconn_ent->or_conn))) {
- _last_circid_orconn_ent = NULL;
+ if (_last_circid_chan_ent &&
+ ((old_id == _last_circid_chan_ent->circ_id &&
+ old_chan == _last_circid_chan_ent->chan) ||
+ (id == _last_circid_chan_ent->circ_id &&
+ chan == _last_circid_chan_ent->chan))) {
+ _last_circid_chan_ent = NULL;
}
- if (old_conn) { /* we may need to remove it from the conn-circid map */
- tor_assert(old_conn->_base.magic == OR_CONNECTION_MAGIC);
+ if (old_chan) {
+ /*
+ * If we're changing channels or ID and had an old channel and a non
+ * zero old ID and weren't marked for close (i.e., we should have been
+ * attached), detach the circuit. ID changes require this because
+ * circuitmux hashes on (channel_id, circuit_id).
+ */
+ if (old_id != 0 && (old_chan != chan || old_id != id) &&
+ !(circ->marked_for_close)) {
+ tor_assert(old_chan->cmux);
+ circuitmux_detach_circuit(old_chan->cmux, circ);
+ }
+
+ /* we may need to remove it from the conn-circid map */
search.circ_id = old_id;
- search.or_conn = old_conn;
- found = HT_REMOVE(orconn_circid_map, &orconn_circid_circuit_map, &search);
+ search.chan = old_chan;
+ found = HT_REMOVE(chan_circid_map, &chan_circid_map, &search);
if (found) {
tor_free(found);
- --old_conn->n_circuits;
+ if (direction == CELL_DIRECTION_OUT) {
+ /* One fewer circuits use old_chan as n_chan */
+ --(old_chan->num_n_circuits);
+ } else {
+ /* One fewer circuits use old_chan as p_chan */
+ --(old_chan->num_p_circuits);
+ }
}
- if (was_active && old_conn != conn)
- make_circuit_inactive_on_conn(circ,old_conn);
}
/* Change the values only after we have possibly made the circuit inactive
- * on the previous conn. */
- *conn_ptr = conn;
+ * on the previous chan. */
+ *chan_ptr = chan;
*circid_ptr = id;
- if (conn == NULL)
+ if (chan == NULL)
return;
/* now add the new one to the conn-circid map */
search.circ_id = id;
- search.or_conn = conn;
- found = HT_FIND(orconn_circid_map, &orconn_circid_circuit_map, &search);
+ search.chan = chan;
+ found = HT_FIND(chan_circid_map, &chan_circid_map, &search);
if (found) {
found->circuit = circ;
} else {
- found = tor_malloc_zero(sizeof(orconn_circid_circuit_map_t));
+ found = tor_malloc_zero(sizeof(chan_circid_circuit_map_t));
found->circ_id = id;
- found->or_conn = conn;
+ found->chan = chan;
found->circuit = circ;
- HT_INSERT(orconn_circid_map, &orconn_circid_circuit_map, found);
+ HT_INSERT(chan_circid_map, &chan_circid_map, found);
+ }
+
+ /*
+ * Attach to the circuitmux if we're changing channels or IDs and
+ * have a new channel and ID to use and the circuit is not marked for
+ * close.
+ */
+ if (chan && id != 0 && (old_chan != chan || old_id != id) &&
+ !(circ->marked_for_close)) {
+ tor_assert(chan->cmux);
+ circuitmux_attach_circuit(chan->cmux, circ, direction);
+ attached = 1;
}
- if (make_active && old_conn != conn)
- make_circuit_active_on_conn(circ,conn);
- ++conn->n_circuits;
+ /*
+ * This is a no-op if we have no cells, but if we do it marks us active to
+ * the circuitmux
+ */
+ if (make_active && attached)
+ update_circuit_on_cmux(circ, direction);
+
+ /* Adjust circuit counts on new channel */
+ if (direction == CELL_DIRECTION_OUT) {
+ ++chan->num_n_circuits;
+ } else {
+ ++chan->num_p_circuits;
+ }
}
/** Set the p_conn field of a circuit <b>circ</b>, along
* with the corresponding circuit ID, and add the circuit as appropriate
- * to the (orconn,id)-\>circuit map. */
+ * to the (chan,id)-\>circuit map. */
void
-circuit_set_p_circid_orconn(or_circuit_t *circ, circid_t id,
- or_connection_t *conn)
+circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
+ channel_t *chan)
{
- circuit_set_circid_orconn_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN,
- id, conn);
+ circuit_set_circid_chan_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN,
+ id, chan);
- if (conn)
- tor_assert(bool_eq(circ->p_conn_cells.n, circ->next_active_on_p_conn));
+ if (chan)
+ tor_assert(bool_eq(circ->p_chan_cells.n, circ->next_active_on_p_chan));
}
/** Set the n_conn field of a circuit <b>circ</b>, along
* with the corresponding circuit ID, and add the circuit as appropriate
- * to the (orconn,id)-\>circuit map. */
+ * to the (chan,id)-\>circuit map. */
void
-circuit_set_n_circid_orconn(circuit_t *circ, circid_t id,
- or_connection_t *conn)
+circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
+ channel_t *chan)
{
- circuit_set_circid_orconn_helper(circ, CELL_DIRECTION_OUT, id, conn);
+ circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan);
- if (conn)
- tor_assert(bool_eq(circ->n_conn_cells.n, circ->next_active_on_n_conn));
+ if (chan)
+ tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan));
}
/** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
@@ -201,18 +240,18 @@ circuit_set_state(circuit_t *circ, uint8_t state)
tor_assert(circ);
if (state == circ->state)
return;
- if (!circuits_pending_or_conns)
- circuits_pending_or_conns = smartlist_new();
- if (circ->state == CIRCUIT_STATE_OR_WAIT) {
+ if (!circuits_pending_chans)
+ circuits_pending_chans = smartlist_new();
+ if (circ->state == CIRCUIT_STATE_CHAN_WAIT) {
/* remove from waiting-circuit list. */
- smartlist_remove(circuits_pending_or_conns, circ);
+ smartlist_remove(circuits_pending_chans, circ);
}
- if (state == CIRCUIT_STATE_OR_WAIT) {
+ if (state == CIRCUIT_STATE_CHAN_WAIT) {
/* add to waiting-circuit list. */
- smartlist_add(circuits_pending_or_conns, circ);
+ smartlist_add(circuits_pending_chans, circ);
}
if (state == CIRCUIT_STATE_OPEN)
- tor_assert(!circ->n_conn_onionskin);
+ tor_assert(!circ->n_chan_onionskin);
circ->state = state;
}
@@ -231,51 +270,53 @@ circuit_add(circuit_t *circ)
}
}
-/** Append to <b>out</b> all circuits in state OR_WAIT waiting for
+/** Append to <b>out</b> all circuits in state CHAN_WAIT waiting for
* the given connection. */
void
-circuit_get_all_pending_on_or_conn(smartlist_t *out, or_connection_t *or_conn)
+circuit_get_all_pending_on_channel(smartlist_t *out, channel_t *chan)
{
tor_assert(out);
- tor_assert(or_conn);
+ tor_assert(chan);
- if (!circuits_pending_or_conns)
+ if (!circuits_pending_chans)
return;
- SMARTLIST_FOREACH_BEGIN(circuits_pending_or_conns, circuit_t *, circ) {
+ SMARTLIST_FOREACH_BEGIN(circuits_pending_chans, circuit_t *, circ) {
if (circ->marked_for_close)
continue;
if (!circ->n_hop)
continue;
- tor_assert(circ->state == CIRCUIT_STATE_OR_WAIT);
+ tor_assert(circ->state == CIRCUIT_STATE_CHAN_WAIT);
if (tor_digest_is_zero(circ->n_hop->identity_digest)) {
/* Look at addr/port. This is an unkeyed connection. */
- if (!tor_addr_eq(&circ->n_hop->addr, &or_conn->_base.addr) ||
- circ->n_hop->port != or_conn->_base.port)
+ if (!channel_matches_extend_info(chan, circ->n_hop))
continue;
} else {
/* We expected a key. See if it's the right one. */
- if (tor_memneq(or_conn->identity_digest,
- circ->n_hop->identity_digest, DIGEST_LEN))
+ if (tor_memneq(chan->identity_digest,
+ circ->n_hop->identity_digest, DIGEST_LEN))
continue;
}
smartlist_add(out, circ);
} SMARTLIST_FOREACH_END(circ);
}
-/** Return the number of circuits in state OR_WAIT, waiting for the given
- * connection. */
+/** Return the number of circuits in state CHAN_WAIT, waiting for the given
+ * channel. */
int
-circuit_count_pending_on_or_conn(or_connection_t *or_conn)
+circuit_count_pending_on_channel(channel_t *chan)
{
int cnt;
smartlist_t *sl = smartlist_new();
- circuit_get_all_pending_on_or_conn(sl, or_conn);
+
+ tor_assert(chan);
+
+ circuit_get_all_pending_on_channel(sl, chan);
cnt = smartlist_len(sl);
smartlist_free(sl);
log_debug(LD_CIRC,"or_conn to %s at %s, %d pending circs",
- or_conn->nickname ? or_conn->nickname : "NULL",
- or_conn->_base.address,
+ chan->nickname ? chan->nickname : "NULL",
+ channel_get_canonical_remote_descr(chan),
cnt);
return cnt;
}
@@ -310,7 +351,7 @@ circuit_close_all_marked(void)
/** Return the head of the global linked list of circuits. */
circuit_t *
-_circuit_get_global_list(void)
+circuit_get_global_list_(void)
{
return global_circuitlist;
}
@@ -323,7 +364,7 @@ circuit_state_to_string(int state)
switch (state) {
case CIRCUIT_STATE_BUILDING: return "doing handshakes";
case CIRCUIT_STATE_ONIONSKIN_PENDING: return "processing the onion";
- case CIRCUIT_STATE_OR_WAIT: return "connecting to server";
+ case CIRCUIT_STATE_CHAN_WAIT: return "connecting to server";
case CIRCUIT_STATE_OPEN: return "open";
default:
log_warn(LD_BUG, "Unknown circuit state %d", state);
@@ -514,15 +555,14 @@ init_circuit_base(circuit_t *circ)
{
tor_gettimeofday(&circ->timestamp_created);
+ // Gets reset when we send CREATE_FAST.
+ // circuit_expire_building() expects these to be equal
+ // until the orconn is built.
+ circ->timestamp_began = circ->timestamp_created;
+
circ->package_window = circuit_initial_package_window();
circ->deliver_window = CIRCWINDOW_START;
- /* Initialize the cell_ewma_t structure */
- circ->n_cell_ewma.last_adjusted_tick = cell_ewma_get_tick();
- circ->n_cell_ewma.cell_count = 0.0;
- circ->n_cell_ewma.heap_index = -1;
- circ->n_cell_ewma.is_for_p_conn = 0;
-
circuit_add(circ);
}
@@ -538,7 +578,7 @@ origin_circuit_new(void)
static uint32_t n_circuits_allocated = 1;
circ = tor_malloc_zero(sizeof(origin_circuit_t));
- circ->_base.magic = ORIGIN_CIRCUIT_MAGIC;
+ circ->base_.magic = ORIGIN_CIRCUIT_MAGIC;
circ->next_stream_id = crypto_rand_int(1<<16);
circ->global_identifier = n_circuits_allocated++;
@@ -555,31 +595,21 @@ origin_circuit_new(void)
/** Allocate a new or_circuit_t, connected to <b>p_conn</b> as
* <b>p_circ_id</b>. If <b>p_conn</b> is NULL, the circuit is unattached. */
or_circuit_t *
-or_circuit_new(circid_t p_circ_id, or_connection_t *p_conn)
+or_circuit_new(circid_t p_circ_id, channel_t *p_chan)
{
/* CircIDs */
or_circuit_t *circ;
circ = tor_malloc_zero(sizeof(or_circuit_t));
- circ->_base.magic = OR_CIRCUIT_MAGIC;
+ circ->base_.magic = OR_CIRCUIT_MAGIC;
- if (p_conn)
- circuit_set_p_circid_orconn(circ, p_circ_id, p_conn);
+ if (p_chan)
+ circuit_set_p_circid_chan(circ, p_circ_id, p_chan);
circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT;
init_circuit_base(TO_CIRCUIT(circ));
- /* Initialize the cell_ewma_t structure */
-
- /* Initialize the cell counts to 0 */
- circ->p_cell_ewma.cell_count = 0.0;
- circ->p_cell_ewma.last_adjusted_tick = cell_ewma_get_tick();
- circ->p_cell_ewma.is_for_p_conn = 1;
-
- /* It's not in any heap yet. */
- circ->p_cell_ewma.heap_index = -1;
-
return circ;
}
@@ -635,27 +665,27 @@ circuit_free(circuit_t *circ)
if (ocirc->rend_splice) {
or_circuit_t *other = ocirc->rend_splice;
- tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC);
+ tor_assert(other->base_.magic == OR_CIRCUIT_MAGIC);
other->rend_splice = NULL;
}
/* remove from map. */
- circuit_set_p_circid_orconn(ocirc, 0, NULL);
+ circuit_set_p_circid_chan(ocirc, 0, NULL);
/* Clear cell queue _after_ removing it from the map. Otherwise our
* "active" checks will be violated. */
- cell_queue_clear(&ocirc->p_conn_cells);
+ cell_queue_clear(&ocirc->p_chan_cells);
}
extend_info_free(circ->n_hop);
- tor_free(circ->n_conn_onionskin);
+ tor_free(circ->n_chan_onionskin);
/* Remove from map. */
- circuit_set_n_circid_orconn(circ, 0, NULL);
+ circuit_set_n_circid_chan(circ, 0, NULL);
/* Clear cell queue _after_ removing it from the map. Otherwise our
* "active" checks will be violated. */
- cell_queue_clear(&circ->n_conn_cells);
+ cell_queue_clear(&circ->n_chan_cells);
memwipe(mem, 0xAA, memlen); /* poison memory */
tor_free(mem);
@@ -701,10 +731,10 @@ circuit_free_all(void)
global_circuitlist = next;
}
- smartlist_free(circuits_pending_or_conns);
- circuits_pending_or_conns = NULL;
+ smartlist_free(circuits_pending_chans);
+ circuits_pending_chans = NULL;
- HT_CLEAR(orconn_circid_map, &orconn_circid_circuit_map);
+ HT_CLEAR(chan_circid_map, &chan_circid_map);
}
/** Deallocate space associated with the cpath node <b>victim</b>. */
@@ -741,14 +771,18 @@ cpath_ref_decref(crypt_path_reference_t *cpath_ref)
* of information about circuit <b>circ</b>.
*/
static void
-circuit_dump_details(int severity, circuit_t *circ, int conn_array_index,
- const char *type, int this_circid, int other_circid)
+circuit_dump_conn_details(int severity,
+ circuit_t *circ,
+ int conn_array_index,
+ const char *type,
+ int this_circid,
+ int other_circid)
{
log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
"state %d (%s), born %ld:",
conn_array_index, type, this_circid, other_circid, circ->state,
circuit_state_to_string(circ->state),
- (long)circ->timestamp_created.tv_sec);
+ (long)circ->timestamp_began.tv_sec);
if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
}
@@ -763,50 +797,101 @@ circuit_dump_by_conn(connection_t *conn, int severity)
circuit_t *circ;
edge_connection_t *tmpconn;
- for (circ=global_circuitlist;circ;circ = circ->next) {
+ for (circ = global_circuitlist; circ; circ = circ->next) {
circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
- if (circ->marked_for_close)
+
+ if (circ->marked_for_close) {
continue;
+ }
- if (! CIRCUIT_IS_ORIGIN(circ))
+ if (!CIRCUIT_IS_ORIGIN(circ)) {
p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
- if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn &&
- TO_CONN(TO_OR_CIRCUIT(circ)->p_conn) == conn)
- circuit_dump_details(severity, circ, conn->conn_array_index, "App-ward",
- p_circ_id, n_circ_id);
if (CIRCUIT_IS_ORIGIN(circ)) {
for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (TO_CONN(tmpconn) == conn) {
- circuit_dump_details(severity, circ, conn->conn_array_index,
- "App-ward", p_circ_id, n_circ_id);
+ circuit_dump_conn_details(severity, circ, conn->conn_array_index,
+ "App-ward", p_circ_id, n_circ_id);
}
}
}
- if (circ->n_conn && TO_CONN(circ->n_conn) == conn)
- circuit_dump_details(severity, circ, conn->conn_array_index, "Exit-ward",
- n_circ_id, p_circ_id);
+
if (! CIRCUIT_IS_ORIGIN(circ)) {
for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (TO_CONN(tmpconn) == conn) {
- circuit_dump_details(severity, circ, conn->conn_array_index,
- "Exit-ward", n_circ_id, p_circ_id);
+ circuit_dump_conn_details(severity, circ, conn->conn_array_index,
+ "Exit-ward", n_circ_id, p_circ_id);
}
}
}
- if (!circ->n_conn && circ->n_hop &&
- tor_addr_eq(&circ->n_hop->addr, &conn->addr) &&
- circ->n_hop->port == conn->port &&
- conn->type == CONN_TYPE_OR &&
- tor_memeq(TO_OR_CONN(conn)->identity_digest,
- circ->n_hop->identity_digest, DIGEST_LEN)) {
- circuit_dump_details(severity, circ, conn->conn_array_index,
- (circ->state == CIRCUIT_STATE_OPEN &&
- !CIRCUIT_IS_ORIGIN(circ)) ?
- "Endpoint" : "Pending",
- n_circ_id, p_circ_id);
+ }
+}
+
+/** A helper function for circuit_dump_by_chan() below. Log a bunch
+ * of information about circuit <b>circ</b>.
+ */
+static void
+circuit_dump_chan_details(int severity,
+ circuit_t *circ,
+ channel_t *chan,
+ const char *type,
+ int this_circid,
+ int other_circid)
+{
+ log(severity, LD_CIRC, "Conn %p has %s circuit: circID %d (other side %d), "
+ "state %d (%s), born %ld:",
+ chan, type, this_circid, other_circid, circ->state,
+ circuit_state_to_string(circ->state),
+ (long)circ->timestamp_began.tv_sec);
+ if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
+ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
+ }
+}
+
+/** Log, at severity <b>severity</b>, information about each circuit
+ * that is connected to <b>chan</b>.
+ */
+void
+circuit_dump_by_chan(channel_t *chan, int severity)
+{
+ circuit_t *circ;
+
+ tor_assert(chan);
+
+ for (circ = global_circuitlist; circ; circ = circ->next) {
+ circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
+
+ if (circ->marked_for_close) {
+ continue;
+ }
+
+ if (!CIRCUIT_IS_ORIGIN(circ)) {
+ p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
+
+ if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_chan &&
+ TO_OR_CIRCUIT(circ)->p_chan == chan) {
+ circuit_dump_chan_details(severity, circ, chan, "App-ward",
+ p_circ_id, n_circ_id);
+ }
+
+ if (circ->n_chan && circ->n_chan == chan) {
+ circuit_dump_chan_details(severity, circ, chan, "Exit-ward",
+ n_circ_id, p_circ_id);
+ }
+
+ if (!circ->n_chan && circ->n_hop &&
+ channel_matches_extend_info(chan, circ->n_hop) &&
+ tor_memeq(chan->identity_digest,
+ circ->n_hop->identity_digest, DIGEST_LEN)) {
+ circuit_dump_chan_details(severity, circ, chan,
+ (circ->state == CIRCUIT_STATE_OPEN &&
+ !CIRCUIT_IS_ORIGIN(circ)) ?
+ "Endpoint" : "Pending",
+ n_circ_id, p_circ_id);
}
}
}
@@ -831,27 +916,39 @@ circuit_get_by_global_id(uint32_t id)
/** Return a circ such that:
* - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
- * - circ is attached to <b>conn</b>, either as p_conn or n_conn.
+ * - circ is attached to <b>chan</b>, either as p_chan or n_chan.
* Return NULL if no such circuit exists.
*/
static INLINE circuit_t *
-circuit_get_by_circid_orconn_impl(circid_t circ_id, or_connection_t *conn)
+circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan)
{
- orconn_circid_circuit_map_t search;
- orconn_circid_circuit_map_t *found;
+ chan_circid_circuit_map_t search;
+ chan_circid_circuit_map_t *found;
- if (_last_circid_orconn_ent &&
- circ_id == _last_circid_orconn_ent->circ_id &&
- conn == _last_circid_orconn_ent->or_conn) {
- found = _last_circid_orconn_ent;
+ if (_last_circid_chan_ent &&
+ circ_id == _last_circid_chan_ent->circ_id &&
+ chan == _last_circid_chan_ent->chan) {
+ found = _last_circid_chan_ent;
} else {
search.circ_id = circ_id;
- search.or_conn = conn;
- found = HT_FIND(orconn_circid_map, &orconn_circid_circuit_map, &search);
- _last_circid_orconn_ent = found;
+ search.chan = chan;
+ found = HT_FIND(chan_circid_map, &chan_circid_map, &search);
+ _last_circid_chan_ent = found;
}
- if (found && found->circuit)
+ if (found && found->circuit) {
+ log_debug(LD_CIRC,
+ "circuit_get_by_circid_channel_impl() returning circuit %p for"
+ " circ_id %d, channel ID " U64_FORMAT " (%p)",
+ found->circuit, circ_id,
+ U64_PRINTF_ARG(chan->global_identifier), chan);
return found->circuit;
+ }
+
+ log_debug(LD_CIRC,
+ "circuit_get_by_circid_channel_impl() found nothing for"
+ " circ_id %d, channel ID " U64_FORMAT " (%p)",
+ circ_id,
+ U64_PRINTF_ARG(chan->global_identifier), chan);
return NULL;
/* The rest of this checks for bugs. Disabled by default. */
@@ -861,15 +958,15 @@ circuit_get_by_circid_orconn_impl(circid_t circ_id, or_connection_t *conn)
for (circ=global_circuitlist;circ;circ = circ->next) {
if (! CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
- if (or_circ->p_conn == conn && or_circ->p_circ_id == circ_id) {
+ if (or_circ->p_chan == chan && or_circ->p_circ_id == circ_id) {
log_warn(LD_BUG,
- "circuit matches p_conn, but not in hash table (Bug!)");
+ "circuit matches p_chan, but not in hash table (Bug!)");
return circ;
}
}
- if (circ->n_conn == conn && circ->n_circ_id == circ_id) {
+ if (circ->n_chan == chan && circ->n_circ_id == circ_id) {
log_warn(LD_BUG,
- "circuit matches n_conn, but not in hash table (Bug!)");
+ "circuit matches n_chan, but not in hash table (Bug!)");
return circ;
}
}
@@ -879,26 +976,38 @@ circuit_get_by_circid_orconn_impl(circid_t circ_id, or_connection_t *conn)
/** Return a circ such that:
* - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
- * - circ is attached to <b>conn</b>, either as p_conn or n_conn.
+ * - circ is attached to <b>chan</b>, either as p_chan or n_chan.
* - circ is not marked for close.
* Return NULL if no such circuit exists.
*/
circuit_t *
-circuit_get_by_circid_orconn(circid_t circ_id, or_connection_t *conn)
+circuit_get_by_circid_channel(circid_t circ_id, channel_t *chan)
{
- circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
+ circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan);
if (!circ || circ->marked_for_close)
return NULL;
else
return circ;
}
+/** Return a circ such that:
+ * - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
+ * - circ is attached to <b>chan</b>, either as p_chan or n_chan.
+ * Return NULL if no such circuit exists.
+ */
+circuit_t *
+circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
+ channel_t *chan)
+{
+ return circuit_get_by_circid_channel_impl(circ_id, chan);
+}
+
/** Return true iff the circuit ID <b>circ_id</b> is currently used by a
- * circuit, marked or not, on <b>conn</b>. */
+ * circuit, marked or not, on <b>chan</b>. */
int
-circuit_id_in_use_on_orconn(circid_t circ_id, or_connection_t *conn)
+circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan)
{
- return circuit_get_by_circid_orconn_impl(circ_id, conn) != NULL;
+ return circuit_get_by_circid_channel_impl(circ_id, chan) != NULL;
}
/** Return the circuit that a given edge connection is using. */
@@ -915,27 +1024,27 @@ circuit_get_by_edge_conn(edge_connection_t *conn)
return circ;
}
-/** For each circuit that has <b>conn</b> as n_conn or p_conn, unlink the
- * circuit from the orconn,circid map, and mark it for close if it hasn't
+/** For each circuit that has <b>chan</b> as n_chan or p_chan, unlink the
+ * circuit from the chan,circid map, and mark it for close if it hasn't
* been marked already.
*/
void
-circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason)
+circuit_unlink_all_from_channel(channel_t *chan, int reason)
{
circuit_t *circ;
- connection_or_unlink_all_active_circs(conn);
+ channel_unlink_all_circuits(chan);
for (circ = global_circuitlist; circ; circ = circ->next) {
int mark = 0;
- if (circ->n_conn == conn) {
- circuit_set_n_circid_orconn(circ, 0, NULL);
+ if (circ->n_chan == chan) {
+ circuit_set_n_circid_chan(circ, 0, NULL);
mark = 1;
}
if (! CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
- if (or_circ->p_conn == conn) {
- circuit_set_p_circid_orconn(or_circ, 0, NULL);
+ if (or_circ->p_chan == chan) {
+ circuit_set_p_circid_chan(or_circ, 0, NULL);
mark = 1;
}
}
@@ -1059,7 +1168,7 @@ origin_circuit_t *
circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
int flags)
{
- circuit_t *_circ;
+ circuit_t *circ_;
origin_circuit_t *best=NULL;
int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0;
int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0;
@@ -1075,13 +1184,13 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
"capacity %d, internal %d",
purpose, need_uptime, need_capacity, internal);
- for (_circ=global_circuitlist; _circ; _circ = _circ->next) {
- if (CIRCUIT_IS_ORIGIN(_circ) &&
- _circ->state == CIRCUIT_STATE_OPEN &&
- !_circ->marked_for_close &&
- _circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
- !_circ->timestamp_dirty) {
- origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ);
+ for (circ_=global_circuitlist; circ_; circ_ = circ_->next) {
+ if (CIRCUIT_IS_ORIGIN(circ_) &&
+ circ_->state == CIRCUIT_STATE_OPEN &&
+ !circ_->marked_for_close &&
+ circ_->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
+ !circ_->timestamp_dirty) {
+ origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(circ_);
if ((!need_uptime || circ->build_state->need_uptime) &&
(!need_capacity || circ->build_state->need_capacity) &&
(internal == circ->build_state->is_internal) &&
@@ -1215,7 +1324,7 @@ circuit_expire_all_dirty_circs(void)
* rendezvous stream), then mark the other circuit to close as well.
*/
void
-_circuit_mark_for_close(circuit_t *circ, int reason, int line,
+circuit_mark_for_close_(circuit_t *circ, int reason, int line,
const char *file)
{
int orig_reason = reason; /* Passed to the controller */
@@ -1246,7 +1355,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
if (reason & END_CIRC_REASON_FLAG_REMOTE)
reason &= ~END_CIRC_REASON_FLAG_REMOTE;
- if (reason < _END_CIRC_REASON_MIN || reason > _END_CIRC_REASON_MAX) {
+ if (reason < END_CIRC_REASON_MIN_ || reason > END_CIRC_REASON_MAX_) {
if (!(orig_reason & END_CIRC_REASON_FLAG_REMOTE))
log_warn(LD_BUG, "Reason %d out of range at %s:%d", reason, file, line);
reason = END_CIRC_REASON_NONE;
@@ -1266,9 +1375,9 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
circuit_rep_hist_note_result(ocirc);
}
}
- if (circ->state == CIRCUIT_STATE_OR_WAIT) {
- if (circuits_pending_or_conns)
- smartlist_remove(circuits_pending_or_conns, circ);
+ if (circ->state == CIRCUIT_STATE_CHAN_WAIT) {
+ if (circuits_pending_chans)
+ smartlist_remove(circuits_pending_chans, circ);
}
if (CIRCUIT_IS_ORIGIN(circ)) {
control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
@@ -1305,9 +1414,15 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
INTRO_POINT_FAILURE_UNREACHABLE);
}
}
- if (circ->n_conn) {
- circuit_clear_cell_queue(circ, circ->n_conn);
- connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
+ if (circ->n_chan) {
+ circuit_clear_cell_queue(circ, circ->n_chan);
+ /* Only send destroy if the channel isn't closing anyway */
+ if (!(circ->n_chan->state == CHANNEL_STATE_CLOSING ||
+ circ->n_chan->state == CHANNEL_STATE_CLOSED ||
+ circ->n_chan->state == CHANNEL_STATE_ERROR)) {
+ channel_send_destroy(circ->n_circ_id, circ->n_chan, reason);
+ }
+ circuitmux_detach_circuit(circ->n_chan->cmux, circ);
}
if (! CIRCUIT_IS_ORIGIN(circ)) {
@@ -1320,7 +1435,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
while (or_circ->resolving_streams) {
conn = or_circ->resolving_streams;
or_circ->resolving_streams = conn->next_stream;
- if (!conn->_base.marked_for_close) {
+ if (!conn->base_.marked_for_close) {
/* The client will see a DESTROY, and infer that the connections
* are closing because the circuit is getting torn down. No need
* to send an end cell. */
@@ -1332,9 +1447,15 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
conn->on_circuit = NULL;
}
- if (or_circ->p_conn) {
- circuit_clear_cell_queue(circ, or_circ->p_conn);
- connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason);
+ if (or_circ->p_chan) {
+ circuit_clear_cell_queue(circ, or_circ->p_chan);
+ /* Only send destroy if the channel isn't closing anyway */
+ if (!(or_circ->p_chan->state == CHANNEL_STATE_CLOSING ||
+ or_circ->p_chan->state == CHANNEL_STATE_CLOSED ||
+ or_circ->p_chan->state == CHANNEL_STATE_ERROR)) {
+ channel_send_destroy(or_circ->p_circ_id, or_circ->p_chan, reason);
+ }
+ circuitmux_detach_circuit(or_circ->p_chan->cmux, circ);
}
} else {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -1350,7 +1471,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
if (!CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
if (or_circ->rend_splice) {
- if (!or_circ->rend_splice->_base.marked_for_close) {
+ if (!or_circ->rend_splice->base_.marked_for_close) {
/* do this after marking this circuit, to avoid infinite recursion. */
circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason);
}
@@ -1424,8 +1545,8 @@ assert_circuit_ok(const circuit_t *c)
tor_assert(c);
tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC);
- tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
- c->purpose <= _CIRCUIT_PURPOSE_MAX);
+ tor_assert(c->purpose >= CIRCUIT_PURPOSE_MIN_ &&
+ c->purpose <= CIRCUIT_PURPOSE_MAX_);
{
/* Having a separate variable for this pleases GCC 4.2 in ways I hope I
@@ -1437,33 +1558,33 @@ assert_circuit_ok(const circuit_t *c)
or_circ = TO_OR_CIRCUIT(nonconst_circ);
}
- if (c->n_conn) {
+ if (c->n_chan) {
tor_assert(!c->n_hop);
if (c->n_circ_id) {
/* We use the _impl variant here to make sure we don't fail on marked
* circuits, which would not be returned by the regular function. */
- circuit_t *c2 = circuit_get_by_circid_orconn_impl(c->n_circ_id,
- c->n_conn);
+ circuit_t *c2 = circuit_get_by_circid_channel_impl(c->n_circ_id,
+ c->n_chan);
tor_assert(c == c2);
}
}
- if (or_circ && or_circ->p_conn) {
+ if (or_circ && or_circ->p_chan) {
if (or_circ->p_circ_id) {
/* ibid */
- circuit_t *c2 = circuit_get_by_circid_orconn_impl(or_circ->p_circ_id,
- or_circ->p_conn);
+ circuit_t *c2 = circuit_get_by_circid_channel_impl(or_circ->p_circ_id,
+ or_circ->p_chan);
tor_assert(c == c2);
}
}
if (or_circ)
for (conn = or_circ->n_streams; conn; conn = conn->next_stream)
- tor_assert(conn->_base.type == CONN_TYPE_EXIT);
+ tor_assert(conn->base_.type == CONN_TYPE_EXIT);
tor_assert(c->deliver_window >= 0);
tor_assert(c->package_window >= 0);
if (c->state == CIRCUIT_STATE_OPEN) {
- tor_assert(!c->n_conn_onionskin);
+ tor_assert(!c->n_chan_onionskin);
if (or_circ) {
tor_assert(or_circ->n_crypto);
tor_assert(or_circ->p_crypto);
@@ -1471,12 +1592,12 @@ assert_circuit_ok(const circuit_t *c)
tor_assert(or_circ->p_digest);
}
}
- if (c->state == CIRCUIT_STATE_OR_WAIT && !c->marked_for_close) {
- tor_assert(circuits_pending_or_conns &&
- smartlist_isin(circuits_pending_or_conns, c));
+ if (c->state == CIRCUIT_STATE_CHAN_WAIT && !c->marked_for_close) {
+ tor_assert(circuits_pending_chans &&
+ smartlist_isin(circuits_pending_chans, c));
} else {
- tor_assert(!circuits_pending_or_conns ||
- !smartlist_isin(circuits_pending_or_conns, c));
+ tor_assert(!circuits_pending_chans ||
+ !smartlist_isin(circuits_pending_chans, c));
}
if (origin_circ && origin_circ->cpath) {
assert_cpath_ok(origin_circ->cpath);
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index 6e7735476b..a885af2fa0 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -9,29 +9,33 @@
* \brief Header file for circuitlist.c.
**/
-#ifndef _TOR_CIRCUITLIST_H
-#define _TOR_CIRCUITLIST_H
+#ifndef TOR_CIRCUITLIST_H
+#define TOR_CIRCUITLIST_H
-circuit_t * _circuit_get_global_list(void);
+circuit_t * circuit_get_global_list_(void);
const char *circuit_state_to_string(int state);
const char *circuit_purpose_to_controller_string(uint8_t purpose);
const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);
const char *circuit_purpose_to_string(uint8_t purpose);
void circuit_dump_by_conn(connection_t *conn, int severity);
-void circuit_set_p_circid_orconn(or_circuit_t *circ, circid_t id,
- or_connection_t *conn);
-void circuit_set_n_circid_orconn(circuit_t *circ, circid_t id,
- or_connection_t *conn);
+void circuit_dump_by_chan(channel_t *chan, int severity);
+void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
+ channel_t *chan);
+void circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
+ channel_t *chan);
void circuit_set_state(circuit_t *circ, uint8_t state);
void circuit_close_all_marked(void);
int32_t circuit_initial_package_window(void);
origin_circuit_t *origin_circuit_new(void);
-or_circuit_t *or_circuit_new(circid_t p_circ_id, or_connection_t *p_conn);
-circuit_t *circuit_get_by_circid_orconn(circid_t circ_id,
- or_connection_t *conn);
-int circuit_id_in_use_on_orconn(circid_t circ_id, or_connection_t *conn);
+or_circuit_t *or_circuit_new(circid_t p_circ_id, channel_t *p_chan);
+circuit_t *circuit_get_by_circid_channel(circid_t circ_id,
+ channel_t *chan);
+circuit_t *
+circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
+ channel_t *chan);
+int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan);
circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn);
-void circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason);
+void circuit_unlink_all_from_channel(channel_t *chan, int reason);
origin_circuit_t *circuit_get_by_global_id(uint32_t id);
origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data(
const rend_data_t *rend_data);
@@ -43,16 +47,16 @@ origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
extend_info_t *info, int flags);
void circuit_mark_all_unused_circs(void);
void circuit_expire_all_dirty_circs(void);
-void _circuit_mark_for_close(circuit_t *circ, int reason,
+void circuit_mark_for_close_(circuit_t *circ, int reason,
int line, const char *file);
int circuit_get_cpath_len(origin_circuit_t *circ);
crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum);
-void circuit_get_all_pending_on_or_conn(smartlist_t *out,
- or_connection_t *or_conn);
-int circuit_count_pending_on_or_conn(or_connection_t *or_conn);
+void circuit_get_all_pending_on_channel(smartlist_t *out,
+ channel_t *chan);
+int circuit_count_pending_on_channel(channel_t *chan);
#define circuit_mark_for_close(c, reason) \
- _circuit_mark_for_close((c), (reason), __LINE__, _SHORT_FILE_)
+ circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__)
void assert_cpath_layer_ok(const crypt_path_t *cp);
void assert_circuit_ok(const circuit_t *c);
diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c
new file mode 100644
index 0000000000..f3b6b7cd7b
--- /dev/null
+++ b/src/or/circuitmux.c
@@ -0,0 +1,1745 @@
+/* * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitmux.c
+ * \brief Circuit mux/cell selection abstraction
+ **/
+
+#include "or.h"
+#include "channel.h"
+#include "circuitlist.h"
+#include "circuitmux.h"
+
+/*
+ * Private typedefs for circuitmux.c
+ */
+
+/*
+ * Map of muxinfos for circuitmux_t to use; struct is defined below (name
+ * of struct must match HT_HEAD line).
+ */
+typedef struct chanid_circid_muxinfo_map chanid_circid_muxinfo_map_t;
+
+/*
+ * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to
+ * break the hash table code).
+ */
+typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t;
+
+/*
+ * Anything the mux wants to store per-circuit in the map; right now just
+ * a count of queued cells.
+ */
+
+typedef struct circuit_muxinfo_s circuit_muxinfo_t;
+
+/*
+ * Structures for circuitmux.c
+ */
+
+/*
+ * A circuitmux is a collection of circuits; it tracks which subset
+ * of the attached circuits are 'active' (i.e., have cells available
+ * to transmit) and how many cells on each. It expoes three distinct
+ * interfaces to other components:
+ *
+ * To channels, which each have a circuitmux_t, the supported operations
+ * are:
+ *
+ * circuitmux_get_first_active_circuit():
+ *
+ * Pick one of the circuitmux's active circuits to send cells from.
+ *
+ * circuitmux_notify_xmit_cells():
+ *
+ * Notify the circuitmux that cells have been sent on a circuit.
+ *
+ * To circuits, the exposed operations are:
+ *
+ * circuitmux_attach_circuit():
+ *
+ * Attach a circuit to the circuitmux; this will allocate any policy-
+ * specific data wanted for this circuit and add it to the active
+ * circuits list if it has queued cells.
+ *
+ * circuitmux_detach_circuit():
+ *
+ * Detach a circuit from the circuitmux, freeing associated structures.
+ *
+ * circuitmux_clear_num_cells():
+ *
+ * Clear the circuitmux's cell counter for this circuit.
+ *
+ * circuitmux_set_num_cells():
+ *
+ * Set the circuitmux's cell counter for this circuit.
+ *
+ * See circuitmux.h for the circuitmux_policy_t data structure, which contains
+ * a table of function pointers implementing a circuit selection policy, and
+ * circuitmux_ewma.c for an example of a circuitmux policy. Circuitmux
+ * policies can be manipulated with:
+ *
+ * circuitmux_get_policy():
+ *
+ * Return the current policy for a circuitmux_t, if any.
+ *
+ * circuitmux_clear_policy():
+ *
+ * Remove a policy installed on a circuitmux_t, freeing all associated
+ * data. The circuitmux will revert to the built-in round-robin behavior.
+ *
+ * circuitmux_set_policy():
+ *
+ * Install a policy on a circuitmux_t; the appropriate callbacks will be
+ * made to attach all existing circuits to the new policy.
+ *
+ */
+
+struct circuitmux_s {
+ /* Keep count of attached, active circuits */
+ unsigned int n_circuits, n_active_circuits;
+
+ /* Total number of queued cells on all circuits */
+ unsigned int n_cells;
+
+ /*
+ * Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t
+ */
+ chanid_circid_muxinfo_map_t *chanid_circid_map;
+
+ /*
+ * Double-linked ring of circuits with queued cells waiting for room to
+ * free up on this connection's outbuf. Every time we pull cells from
+ * a circuit, we advance this pointer to the next circuit in the ring.
+ */
+ struct circuit_t *active_circuits_head, *active_circuits_tail;
+
+ /*
+ * Circuitmux policy; if this is non-NULL, it can override the built-
+ * in round-robin active circuits behavior. This is how EWMA works in
+ * the new circuitmux_t world.
+ */
+ const circuitmux_policy_t *policy;
+
+ /* Policy-specific data */
+ circuitmux_policy_data_t *policy_data;
+};
+
+/*
+ * This struct holds whatever we want to store per attached circuit on a
+ * circuitmux_t; right now, just the count of queued cells and the direction.
+ */
+
+struct circuit_muxinfo_s {
+ /* Count of cells on this circuit at last update */
+ unsigned int cell_count;
+ /* Direction of flow */
+ cell_direction_t direction;
+ /* Policy-specific data */
+ circuitmux_policy_circ_data_t *policy_data;
+ /* Mark bit for consistency checker */
+ unsigned int mark:1;
+};
+
+/*
+ * A map from channel ID and circuit ID to a circuit_muxinfo_t for that
+ * circuit.
+ */
+
+struct chanid_circid_muxinfo_t {
+ HT_ENTRY(chanid_circid_muxinfo_t) node;
+ uint64_t chan_id;
+ circid_t circ_id;
+ circuit_muxinfo_t muxinfo;
+};
+
+/*
+ * Internal-use #defines
+ */
+
+#ifdef CMUX_PARANOIA
+#define circuitmux_assert_okay_paranoid(cmux) \
+ circuitmux_assert_okay(cmux)
+#else
+#define circuitmux_assert_okay_paranoid(cmux)
+#endif
+
+/*
+ * Static function declarations
+ */
+
+static INLINE int
+chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
+ chanid_circid_muxinfo_t *b);
+static INLINE unsigned int
+chanid_circid_entry_hash(chanid_circid_muxinfo_t *a);
+static chanid_circid_muxinfo_t *
+circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
+static void
+circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+static void
+circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+static INLINE void
+circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+static INLINE circuit_t **
+circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
+static INLINE circuit_t **
+circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
+static void circuitmux_assert_okay_pass_one(circuitmux_t *cmux);
+static void circuitmux_assert_okay_pass_two(circuitmux_t *cmux);
+static void circuitmux_assert_okay_pass_three(circuitmux_t *cmux);
+
+/* Function definitions */
+
+/**
+ * Linked list helpers
+ */
+
+/**
+ * Move an active circuit to the tail of the cmux's active circuits list;
+ * used by circuitmux_notify_xmit_cells().
+ */
+
+static INLINE void
+circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ circuit_t **next_p = NULL, **prev_p = NULL;
+ circuit_t **next_prev = NULL, **prev_next = NULL;
+ circuit_t **tail_next = NULL;
+ or_circuit_t *or_circ = NULL;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ circuitmux_assert_okay_paranoid(cmux);
+
+ /* Figure out our next_p and prev_p for this cmux/direction */
+ if (direction) {
+ if (direction == CELL_DIRECTION_OUT) {
+ tor_assert(circ->n_mux == cmux);
+ next_p = &(circ->next_active_on_n_chan);
+ prev_p = &(circ->prev_active_on_n_chan);
+ } else {
+ or_circ = TO_OR_CIRCUIT(circ);
+ tor_assert(or_circ->p_mux == cmux);
+ next_p = &(or_circ->next_active_on_p_chan);
+ prev_p = &(or_circ->prev_active_on_p_chan);
+ }
+ } else {
+ if (circ->n_mux == cmux) {
+ next_p = &(circ->next_active_on_n_chan);
+ prev_p = &(circ->prev_active_on_n_chan);
+ direction = CELL_DIRECTION_OUT;
+ } else {
+ or_circ = TO_OR_CIRCUIT(circ);
+ tor_assert(or_circ->p_mux == cmux);
+ next_p = &(or_circ->next_active_on_p_chan);
+ prev_p = &(or_circ->prev_active_on_p_chan);
+ direction = CELL_DIRECTION_IN;
+ }
+ }
+ tor_assert(next_p);
+ tor_assert(prev_p);
+
+ /* Check if this really is an active circuit */
+ if ((*next_p == NULL && *prev_p == NULL) &&
+ !(circ == cmux->active_circuits_head ||
+ circ == cmux->active_circuits_tail)) {
+ /* Not active, no-op */
+ return;
+ }
+
+ /* Check if this is already the tail */
+ if (circ == cmux->active_circuits_tail) return;
+
+ /* Okay, we have to move it; figure out next_prev and prev_next */
+ if (*next_p) next_prev = circuitmux_prev_active_circ_p(cmux, *next_p);
+ if (*prev_p) prev_next = circuitmux_next_active_circ_p(cmux, *prev_p);
+ /* Adjust the previous node's next pointer, if any */
+ if (prev_next) *prev_next = *next_p;
+ /* Otherwise, we were the head */
+ else cmux->active_circuits_head = *next_p;
+ /* Adjust the next node's previous pointer, if any */
+ if (next_prev) *next_prev = *prev_p;
+ /* We're out of the list; now re-attach at the tail */
+ /* Adjust our next and prev pointers */
+ *next_p = NULL;
+ *prev_p = cmux->active_circuits_tail;
+ /* Set the next pointer of the tail, or the head if none */
+ if (cmux->active_circuits_tail) {
+ tail_next = circuitmux_next_active_circ_p(cmux,
+ cmux->active_circuits_tail);
+ *tail_next = circ;
+ } else {
+ cmux->active_circuits_head = circ;
+ }
+ /* Set the tail to this circuit */
+ cmux->active_circuits_tail = circ;
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+static INLINE circuit_t **
+circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
+{
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ if (circ->n_mux == cmux) return &(circ->next_active_on_n_chan);
+ else {
+ tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
+ return &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
+ }
+}
+
+static INLINE circuit_t **
+circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
+{
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ if (circ->n_mux == cmux) return &(circ->prev_active_on_n_chan);
+ else {
+ tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
+ return &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
+ }
+}
+
+/**
+ * Helper for chanid_circid_cell_count_map_t hash table: compare the channel
+ * ID and circuit ID for a and b, and return less than, equal to, or greater
+ * than zero appropriately.
+ */
+
+static INLINE int
+chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
+ chanid_circid_muxinfo_t *b)
+{
+ return a->chan_id == b->chan_id && a->circ_id == b->circ_id;
+}
+
+/**
+ * Helper: return a hash based on circuit ID and channel ID in a.
+ */
+
+static INLINE unsigned int
+chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
+{
+ return (((unsigned int)(a->circ_id) << 8) ^
+ ((unsigned int)((a->chan_id >> 32) & 0xffffffff)) ^
+ ((unsigned int)(a->chan_id & 0xffffffff)));
+}
+
+/* Declare the struct chanid_circid_muxinfo_map type */
+HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t);
+
+/* Emit a bunch of hash table stuff */
+HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
+ chanid_circid_entry_hash, chanid_circid_entries_eq);
+HT_GENERATE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
+ chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
+ malloc, realloc, free);
+
+/*
+ * Circuitmux alloc/free functions
+ */
+
+/**
+ * Allocate a new circuitmux_t
+ */
+
+circuitmux_t *
+circuitmux_alloc(void)
+{
+ circuitmux_t *rv = NULL;
+
+ rv = tor_malloc_zero(sizeof(*rv));
+ rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map)));
+ HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
+
+ return rv;
+}
+
+/**
+ * Detach all circuits from a circuitmux (use before circuitmux_free())
+ */
+
+void
+circuitmux_detach_all_circuits(circuitmux_t *cmux)
+{
+ chanid_circid_muxinfo_t **i = NULL, *to_remove;
+ channel_t *chan = NULL;
+ circuit_t *circ = NULL;
+
+ tor_assert(cmux);
+ /*
+ * Don't circuitmux_assert_okay_paranoid() here; this gets called when
+ * channels are being freed and have already been unregistered, so
+ * the channel ID lookups it does will fail.
+ */
+
+ i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+ while (i) {
+ to_remove = *i;
+ if (to_remove) {
+ /* Find a channel and circuit */
+ chan = channel_find_by_global_id(to_remove->chan_id);
+ if (chan) {
+ circ =
+ circuit_get_by_circid_channel_even_if_marked(to_remove->circ_id,
+ chan);
+ if (circ) {
+ /* Clear the circuit's mux for this direction */
+ if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) {
+ /*
+ * Update active_circuits et al.; this does policy notifies, so
+ * comes before freeing policy data
+ */
+
+ if (to_remove->muxinfo.cell_count > 0) {
+ circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_OUT);
+ }
+
+ /* Clear n_mux */
+ circ->n_mux = NULL;
+ } else if (circ->magic == OR_CIRCUIT_MAGIC) {
+ /*
+ * Update active_circuits et al.; this does policy notifies, so
+ * comes before freeing policy data
+ */
+
+ if (to_remove->muxinfo.cell_count > 0) {
+ circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_IN);
+ }
+
+ /*
+ * It has a sensible p_chan and direction == CELL_DIRECTION_IN,
+ * so clear p_mux.
+ */
+ TO_OR_CIRCUIT(circ)->p_mux = NULL;
+ } else {
+ /* Complain and move on */
+ log_warn(LD_CIRC,
+ "Circuit %d/channel " U64_FORMAT " had direction == "
+ "CELL_DIRECTION_IN, but isn't an or_circuit_t",
+ to_remove->circ_id,
+ U64_PRINTF_ARG(to_remove->chan_id));
+ }
+
+ /* Free policy-specific data if we have it */
+ if (to_remove->muxinfo.policy_data) {
+ /*
+ * If we have policy data, assert that we have the means to
+ * free it
+ */
+ tor_assert(cmux->policy);
+ tor_assert(cmux->policy->free_circ_data);
+ /* Call free_circ_data() */
+ cmux->policy->free_circ_data(cmux,
+ cmux->policy_data,
+ circ,
+ to_remove->muxinfo.policy_data);
+ to_remove->muxinfo.policy_data = NULL;
+ }
+ } else {
+ /* Complain and move on */
+ log_warn(LD_CIRC,
+ "Couldn't find circuit %d (for channel " U64_FORMAT ")",
+ to_remove->circ_id,
+ U64_PRINTF_ARG(to_remove->chan_id));
+ }
+ } else {
+ /* Complain and move on */
+ log_warn(LD_CIRC,
+ "Couldn't find channel " U64_FORMAT " (for circuit id %d)",
+ U64_PRINTF_ARG(to_remove->chan_id),
+ to_remove->circ_id);
+ }
+
+ /* Assert that we don't have un-freed policy data for this circuit */
+ tor_assert(to_remove->muxinfo.policy_data == NULL);
+ }
+
+ i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
+
+ /* Free it */
+ tor_free(to_remove);
+ }
+
+ cmux->n_circuits = 0;
+ cmux->n_active_circuits = 0;
+ cmux->n_cells = 0;
+}
+
+/**
+ * Free a circuitmux_t; the circuits must be detached first with
+ * circuitmux_detach_all_circuits().
+ */
+
+void
+circuitmux_free(circuitmux_t *cmux)
+{
+ if (!cmux) return;
+
+ tor_assert(cmux->n_circuits == 0);
+ tor_assert(cmux->n_active_circuits == 0);
+
+ /*
+ * Free policy-specific data if we have any; we don't
+ * need to do circuitmux_set_policy(cmux, NULL) to cover
+ * the circuits because they would have been handled in
+ * circuitmux_detach_all_circuits() before this was
+ * called.
+ */
+ if (cmux->policy && cmux->policy->free_cmux_data) {
+ if (cmux->policy_data) {
+ cmux->policy->free_cmux_data(cmux, cmux->policy_data);
+ cmux->policy_data = NULL;
+ }
+ } else tor_assert(cmux->policy_data == NULL);
+
+ if (cmux->chanid_circid_map) {
+ HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+ tor_free(cmux->chanid_circid_map);
+ }
+
+ tor_free(cmux);
+}
+
+/*
+ * Circuitmux policy control functions
+ */
+
+/**
+ * Remove any policy installed on cmux; all policy data will be freed and
+ * cmux behavior will revert to the built-in round-robin active_circuits
+ * mechanism.
+ */
+
+void
+circuitmux_clear_policy(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ /* Internally, this is just setting policy to NULL */
+ if (cmux->policy) {
+ circuitmux_set_policy(cmux, NULL);
+ }
+}
+
+/**
+ * Return the policy currently installed on a circuitmux_t
+ */
+
+const circuitmux_policy_t *
+circuitmux_get_policy(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ return cmux->policy;
+}
+
+/**
+ * Set policy; allocate for new policy, detach all circuits from old policy
+ * if any, attach them to new policy, and free old policy data.
+ */
+
+void
+circuitmux_set_policy(circuitmux_t *cmux,
+ const circuitmux_policy_t *pol)
+{
+ const circuitmux_policy_t *old_pol = NULL, *new_pol = NULL;
+ circuitmux_policy_data_t *old_pol_data = NULL, *new_pol_data = NULL;
+ chanid_circid_muxinfo_t **i = NULL;
+ channel_t *chan = NULL;
+ uint64_t last_chan_id_searched = 0;
+ circuit_t *circ = NULL;
+
+ tor_assert(cmux);
+
+ /* Set up variables */
+ old_pol = cmux->policy;
+ old_pol_data = cmux->policy_data;
+ new_pol = pol;
+
+ /* Check if this is the trivial case */
+ if (old_pol == new_pol) return;
+
+ /* Allocate data for new policy, if any */
+ if (new_pol && new_pol->alloc_cmux_data) {
+ /*
+ * If alloc_cmux_data is not null, then we expect to get some policy
+ * data. Assert that we also have free_cmux_data so we can free it
+ * when the time comes, and allocate it.
+ */
+ tor_assert(new_pol->free_cmux_data);
+ new_pol_data = new_pol->alloc_cmux_data(cmux);
+ tor_assert(new_pol_data);
+ }
+
+ /* Install new policy and new policy data on cmux */
+ cmux->policy = new_pol;
+ cmux->policy_data = new_pol_data;
+
+ /* Iterate over all circuits, attaching/detaching each one */
+ i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+ while (i) {
+ /* Assert that this entry isn't NULL */
+ tor_assert(*i);
+
+ /*
+ * Get the channel; since normal case is all circuits on the mux share a
+ * channel, we cache last_chan_id_searched
+ */
+ if (!chan || last_chan_id_searched != (*i)->chan_id) {
+ chan = channel_find_by_global_id((*i)->chan_id);
+ last_chan_id_searched = (*i)->chan_id;
+ }
+ tor_assert(chan);
+
+ /* Get the circuit */
+ circ = circuit_get_by_circid_channel_even_if_marked((*i)->circ_id, chan);
+ tor_assert(circ);
+
+ /* Need to tell old policy it becomes inactive (i.e., it is active) ? */
+ if (old_pol && old_pol->notify_circ_inactive &&
+ (*i)->muxinfo.cell_count > 0) {
+ old_pol->notify_circ_inactive(cmux, old_pol_data, circ,
+ (*i)->muxinfo.policy_data);
+ }
+
+ /* Need to free old policy data? */
+ if ((*i)->muxinfo.policy_data) {
+ /* Assert that we have the means to free it if we have policy data */
+ tor_assert(old_pol);
+ tor_assert(old_pol->free_circ_data);
+ /* Free it */
+ old_pol->free_circ_data(cmux, old_pol_data, circ,
+ (*i)->muxinfo.policy_data);
+ (*i)->muxinfo.policy_data = NULL;
+ }
+
+ /* Need to allocate new policy data? */
+ if (new_pol && new_pol->alloc_circ_data) {
+ /*
+ * If alloc_circ_data is not null, we expect to get some per-circuit
+ * policy data. Assert that we also have free_circ_data so we can
+ * free it when the time comes, and allocate it.
+ */
+ tor_assert(new_pol->free_circ_data);
+ (*i)->muxinfo.policy_data =
+ new_pol->alloc_circ_data(cmux, new_pol_data, circ,
+ (*i)->muxinfo.direction,
+ (*i)->muxinfo.cell_count);
+ }
+
+ /* Need to make active on new policy? */
+ if (new_pol && new_pol->notify_circ_active &&
+ (*i)->muxinfo.cell_count > 0) {
+ new_pol->notify_circ_active(cmux, new_pol_data, circ,
+ (*i)->muxinfo.policy_data);
+ }
+
+ /* Advance to next circuit map entry */
+ i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
+ }
+
+ /* Free data for old policy, if any */
+ if (old_pol_data) {
+ /*
+ * If we had old policy data, we should have an old policy and a free
+ * function for it.
+ */
+ tor_assert(old_pol);
+ tor_assert(old_pol->free_cmux_data);
+ old_pol->free_cmux_data(cmux, old_pol_data);
+ old_pol_data = NULL;
+ }
+}
+
+/*
+ * Circuitmux/circuit attachment status inquiry functions
+ */
+
+/**
+ * Query the direction of an attached circuit
+ */
+
+cell_direction_t
+circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+
+ /* Try to find a map entry */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+
+ /*
+ * This function should only be called on attached circuits; assert that
+ * we had a map entry.
+ */
+ tor_assert(hashent);
+
+ /* Return the direction from the map entry */
+ return hashent->muxinfo.direction;
+}
+
+/**
+ * Find an entry in the cmux's map for this circuit or return NULL if there
+ * is none.
+ */
+
+static chanid_circid_muxinfo_t *
+circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t search, *hashent = NULL;
+
+ /* Sanity-check parameters */
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+ tor_assert(circ);
+
+ /* Check if we have n_chan */
+ if (circ->n_chan) {
+ /* Okay, let's see if it's attached for n_chan/n_circ_id */
+ search.chan_id = circ->n_chan->global_identifier;
+ search.circ_id = circ->n_circ_id;
+
+ /* Query */
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+ }
+
+ /* Found something? */
+ if (hashent) {
+ /*
+ * Assert that the direction makes sense for a hashent we found by
+ * n_chan/n_circ_id before we return it.
+ */
+ tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_OUT);
+ } else {
+ /* Not there, have we got a p_chan/p_circ_id to try? */
+ if (circ->magic == OR_CIRCUIT_MAGIC) {
+ search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ /* Check for p_chan */
+ if (TO_OR_CIRCUIT(circ)->p_chan) {
+ search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
+ /* Okay, search for that */
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+ /* Find anything? */
+ if (hashent) {
+ /* Assert that the direction makes sense before we return it */
+ tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN);
+ }
+ }
+ }
+ }
+
+ /* Okay, hashent is it if it was there */
+ return hashent;
+}
+
+/**
+ * Query whether a circuit is attached to a circuitmux
+ */
+
+int
+circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+
+ /* Look if it's in the circuit map */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+
+ return (hashent != NULL);
+}
+
+/**
+ * Query whether a circuit is active on a circuitmux
+ */
+
+int
+circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+ int is_active = 0;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ /* Look if it's in the circuit map */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ if (hashent) {
+ /* Check the number of cells on this circuit */
+ is_active = (hashent->muxinfo.cell_count > 0);
+ }
+ /* else not attached, so not active */
+
+ return is_active;
+}
+
+/**
+ * Query number of available cells for a circuit on a circuitmux
+ */
+
+unsigned int
+circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+ unsigned int n_cells = 0;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ /* Look if it's in the circuit map */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ if (hashent) {
+ /* Just get the cell count for this circuit */
+ n_cells = hashent->muxinfo.cell_count;
+ }
+ /* else not attached, so 0 cells */
+
+ return n_cells;
+}
+
+/**
+ * Query total number of available cells on a circuitmux
+ */
+
+unsigned int
+circuitmux_num_cells(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ return cmux->n_cells;
+}
+
+/**
+ * Query total number of circuits active on a circuitmux
+ */
+
+unsigned int
+circuitmux_num_active_circuits(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ return cmux->n_active_circuits;
+}
+
+/**
+ * Query total number of circuits attached to a circuitmux
+ */
+
+unsigned int
+circuitmux_num_circuits(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ return cmux->n_circuits;
+}
+
+/*
+ * Functions for circuit code to call to update circuit status
+ */
+
+/**
+ * Attach a circuit to a circuitmux, for the specified direction.
+ */
+
+void
+circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ channel_t *chan = NULL;
+ uint64_t channel_id;
+ circid_t circ_id;
+ chanid_circid_muxinfo_t search, *hashent = NULL;
+ unsigned int cell_count;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ tor_assert(direction == CELL_DIRECTION_IN ||
+ direction == CELL_DIRECTION_OUT);
+ circuitmux_assert_okay_paranoid(cmux);
+
+ /*
+ * Figure out which channel we're using, and get the circuit's current
+ * cell count and circuit ID; assert that the circuit is not already
+ * attached to another mux.
+ */
+ if (direction == CELL_DIRECTION_OUT) {
+ /* It's n_chan */
+ chan = circ->n_chan;
+ cell_count = circ->n_chan_cells.n;
+ circ_id = circ->n_circ_id;
+ } else {
+ /* We want p_chan */
+ chan = TO_OR_CIRCUIT(circ)->p_chan;
+ cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n;
+ circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
+ /* Assert that we did get a channel */
+ tor_assert(chan);
+ /* Assert that the circuit ID is sensible */
+ tor_assert(circ_id != 0);
+
+ /* Get the channel ID */
+ channel_id = chan->global_identifier;
+
+ /* See if we already have this one */
+ search.chan_id = channel_id;
+ search.circ_id = circ_id;
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+
+ if (hashent) {
+ /*
+ * This circuit was already attached to this cmux; make sure the
+ * directions match and update the cell count and active circuit count.
+ */
+ log_info(LD_CIRC,
+ "Circuit %u on channel " U64_FORMAT " was already attached to "
+ "cmux %p (trying to attach to %p)",
+ circ_id, U64_PRINTF_ARG(channel_id),
+ ((direction == CELL_DIRECTION_OUT) ?
+ circ->n_mux : TO_OR_CIRCUIT(circ)->p_mux),
+ cmux);
+
+ /*
+ * The mux pointer on this circuit and the direction in result should
+ * match; otherwise assert.
+ */
+ if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == cmux);
+ else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
+ tor_assert(hashent->muxinfo.direction == direction);
+
+ /*
+ * Looks okay; just update the cell count and active circuits if we must
+ */
+ if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
+ --(cmux->n_active_circuits);
+ circuitmux_make_circuit_inactive(cmux, circ, direction);
+ } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
+ ++(cmux->n_active_circuits);
+ circuitmux_make_circuit_active(cmux, circ, direction);
+ }
+ cmux->n_cells -= hashent->muxinfo.cell_count;
+ cmux->n_cells += cell_count;
+ hashent->muxinfo.cell_count = cell_count;
+ } else {
+ /*
+ * New circuit; add an entry and update the circuit/active circuit
+ * counts.
+ */
+ log_debug(LD_CIRC,
+ "Attaching circuit %u on channel " U64_FORMAT " to cmux %p",
+ circ_id, U64_PRINTF_ARG(channel_id), cmux);
+
+ /*
+ * Assert that the circuit doesn't already have a mux for this
+ * direction.
+ */
+ if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == NULL);
+ else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == NULL);
+
+ /* Insert it in the map */
+ hashent = tor_malloc_zero(sizeof(*hashent));
+ hashent->chan_id = channel_id;
+ hashent->circ_id = circ_id;
+ hashent->muxinfo.cell_count = cell_count;
+ hashent->muxinfo.direction = direction;
+ /* Allocate policy specific circuit data if we need it */
+ if (cmux->policy && cmux->policy->alloc_circ_data) {
+ /* Assert that we have the means to free policy-specific data */
+ tor_assert(cmux->policy->free_circ_data);
+ /* Allocate it */
+ hashent->muxinfo.policy_data =
+ cmux->policy->alloc_circ_data(cmux,
+ cmux->policy_data,
+ circ,
+ direction,
+ cell_count);
+ /* If we wanted policy data, it's an error not to get any */
+ tor_assert(hashent->muxinfo.policy_data);
+ }
+ HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ hashent);
+
+ /* Set the circuit's mux for this direction */
+ if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux;
+ else TO_OR_CIRCUIT(circ)->p_mux = cmux;
+
+ /* Make sure the next/prev pointers are NULL */
+ if (direction == CELL_DIRECTION_OUT) {
+ circ->next_active_on_n_chan = NULL;
+ circ->prev_active_on_n_chan = NULL;
+ } else {
+ TO_OR_CIRCUIT(circ)->next_active_on_p_chan = NULL;
+ TO_OR_CIRCUIT(circ)->prev_active_on_p_chan = NULL;
+ }
+
+ /* Update counters */
+ ++(cmux->n_circuits);
+ if (cell_count > 0) {
+ ++(cmux->n_active_circuits);
+ circuitmux_make_circuit_active(cmux, circ, direction);
+ }
+ cmux->n_cells += cell_count;
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/**
+ * Detach a circuit from a circuitmux and update all counters as needed;
+ * no-op if not attached.
+ */
+
+void
+circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t search, *hashent = NULL;
+ /*
+ * Use this to keep track of whether we found it for n_chan or
+ * p_chan for consistency checking.
+ */
+ cell_direction_t last_searched_direction;
+
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+ tor_assert(circ);
+ circuitmux_assert_okay_paranoid(cmux);
+
+ /* See if we have it for n_chan/n_circ_id */
+ if (circ->n_chan) {
+ search.chan_id = circ->n_chan->global_identifier;
+ search.circ_id = circ->n_circ_id;
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+ last_searched_direction = CELL_DIRECTION_OUT;
+ }
+
+ /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */
+ if (!hashent) {
+ if (circ->magic == OR_CIRCUIT_MAGIC) {
+ search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ if (TO_OR_CIRCUIT(circ)->p_chan) {
+ search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
+ hashent = HT_FIND(chanid_circid_muxinfo_map,
+ cmux->chanid_circid_map,
+ &search);
+ last_searched_direction = CELL_DIRECTION_IN;
+ }
+ }
+ }
+
+ /*
+ * If hashent isn't NULL, we have a circuit to detach; don't remove it from
+ * the map until later of circuitmux_make_circuit_inactive() breaks.
+ */
+ if (hashent) {
+ /* Update counters */
+ --(cmux->n_circuits);
+ if (hashent->muxinfo.cell_count > 0) {
+ --(cmux->n_active_circuits);
+ /* This does policy notifies, so comes before freeing policy data */
+ circuitmux_make_circuit_inactive(cmux, circ, last_searched_direction);
+ }
+ cmux->n_cells -= hashent->muxinfo.cell_count;
+
+ /* Free policy-specific data if we have it */
+ if (hashent->muxinfo.policy_data) {
+ /* If we have policy data, assert that we have the means to free it */
+ tor_assert(cmux->policy);
+ tor_assert(cmux->policy->free_circ_data);
+ /* Call free_circ_data() */
+ cmux->policy->free_circ_data(cmux,
+ cmux->policy_data,
+ circ,
+ hashent->muxinfo.policy_data);
+ hashent->muxinfo.policy_data = NULL;
+ }
+
+ /* Consistency check: the direction must match the direction searched */
+ tor_assert(last_searched_direction == hashent->muxinfo.direction);
+ /* Clear the circuit's mux for this direction */
+ if (last_searched_direction == CELL_DIRECTION_OUT) circ->n_mux = NULL;
+ else TO_OR_CIRCUIT(circ)->p_mux = NULL;
+
+ /* Now remove it from the map */
+ HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent);
+
+ /* Free the hash entry */
+ tor_free(hashent);
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/**
+ * Make a circuit active; update active list and policy-specific info, but
+ * we don't mess with the counters or hash table here.
+ */
+
+static void
+circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ circuit_t **next_active = NULL, **prev_active = NULL, **next_prev = NULL;
+ circuitmux_t *circuit_cmux = NULL;
+ chanid_circid_muxinfo_t *hashent = NULL;
+ channel_t *chan = NULL;
+ circid_t circ_id;
+ int already_active;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ tor_assert(direction == CELL_DIRECTION_OUT ||
+ direction == CELL_DIRECTION_IN);
+ /*
+ * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
+ * already got changed and we have to update the list for it to be consistent
+ * again.
+ */
+
+ /* Get the right set of active list links for this direction */
+ if (direction == CELL_DIRECTION_OUT) {
+ next_active = &(circ->next_active_on_n_chan);
+ prev_active = &(circ->prev_active_on_n_chan);
+ circuit_cmux = circ->n_mux;
+ chan = circ->n_chan;
+ circ_id = circ->n_circ_id;
+ } else {
+ next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
+ prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
+ circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
+ chan = TO_OR_CIRCUIT(circ)->p_chan;
+ circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
+
+ /* Assert that it is attached to this mux and a channel */
+ tor_assert(cmux == circuit_cmux);
+ tor_assert(chan != NULL);
+
+ /*
+ * Check if the circuit really was inactive; if it's active, at least one
+ * of the next_active and prev_active pointers will not be NULL, or this
+ * circuit will be either the head or tail of the list for this cmux.
+ */
+ already_active = (*prev_active != NULL || *next_active != NULL ||
+ cmux->active_circuits_head == circ ||
+ cmux->active_circuits_tail == circ);
+
+ /* If we're already active, log a warning and finish */
+ if (already_active) {
+ log_warn(LD_CIRC,
+ "Circuit %d on channel " U64_FORMAT " was already active",
+ circ_id, U64_PRINTF_ARG(chan->global_identifier));
+ return;
+ }
+
+ /*
+ * This is going at the head of the list; if the old head is not NULL,
+ * then its prev pointer should point to this.
+ */
+ *next_active = cmux->active_circuits_head; /* Next is old head */
+ *prev_active = NULL; /* Prev is NULL (this will be the head) */
+ if (cmux->active_circuits_head) {
+ /* The list had an old head; update its prev pointer */
+ next_prev =
+ circuitmux_prev_active_circ_p(cmux, cmux->active_circuits_head);
+ tor_assert(next_prev);
+ *next_prev = circ;
+ } else {
+ /* The list was empty; this becomes the tail as well */
+ cmux->active_circuits_tail = circ;
+ }
+ /* This becomes the new head of the list */
+ cmux->active_circuits_head = circ;
+
+ /* Policy-specific notification */
+ if (cmux->policy &&
+ cmux->policy->notify_circ_active) {
+ /* Okay, we need to check the circuit for policy data now */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ /* We should have found something */
+ tor_assert(hashent);
+ /* Notify */
+ cmux->policy->notify_circ_active(cmux, cmux->policy_data,
+ circ, hashent->muxinfo.policy_data);
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/**
+ * Make a circuit inactive; update active list and policy-specific info, but
+ * we don't mess with the counters or hash table here.
+ */
+
+static void
+circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ circuit_t **next_active = NULL, **prev_active = NULL;
+ circuit_t **next_prev = NULL, **prev_next = NULL;
+ circuitmux_t *circuit_cmux = NULL;
+ chanid_circid_muxinfo_t *hashent = NULL;
+ channel_t *chan = NULL;
+ circid_t circ_id;
+ int already_inactive;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ tor_assert(direction == CELL_DIRECTION_OUT ||
+ direction == CELL_DIRECTION_IN);
+ /*
+ * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
+ * already got changed and we have to update the list for it to be consistent
+ * again.
+ */
+
+ /* Get the right set of active list links for this direction */
+ if (direction == CELL_DIRECTION_OUT) {
+ next_active = &(circ->next_active_on_n_chan);
+ prev_active = &(circ->prev_active_on_n_chan);
+ circuit_cmux = circ->n_mux;
+ chan = circ->n_chan;
+ circ_id = circ->n_circ_id;
+ } else {
+ next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
+ prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
+ circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
+ chan = TO_OR_CIRCUIT(circ)->p_chan;
+ circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
+
+ /* Assert that it is attached to this mux and a channel */
+ tor_assert(cmux == circuit_cmux);
+ tor_assert(chan != NULL);
+
+ /*
+ * Check if the circuit really was active; if it's inactive, the
+ * next_active and prev_active pointers will be NULL and this circuit
+ * will not be the head or tail of the list for this cmux.
+ */
+ already_inactive = (*prev_active == NULL && *next_active == NULL &&
+ cmux->active_circuits_head != circ &&
+ cmux->active_circuits_tail != circ);
+
+ /* If we're already inactive, log a warning and finish */
+ if (already_inactive) {
+ log_warn(LD_CIRC,
+ "Circuit %d on channel " U64_FORMAT " was already inactive",
+ circ_id, U64_PRINTF_ARG(chan->global_identifier));
+ return;
+ }
+
+ /* Remove from the list; first get next_prev and prev_next */
+ if (*next_active) {
+ /*
+ * If there's a next circuit, its previous circuit becomes this
+ * circuit's previous circuit.
+ */
+ next_prev = circuitmux_prev_active_circ_p(cmux, *next_active);
+ } else {
+ /* Else, the tail becomes this circuit's previous circuit */
+ next_prev = &(cmux->active_circuits_tail);
+ }
+
+ /* Got next_prev, now prev_next */
+ if (*prev_active) {
+ /*
+ * If there's a previous circuit, its next circuit becomes this circuit's
+ * next circuit.
+ */
+ prev_next = circuitmux_next_active_circ_p(cmux, *prev_active);
+ } else {
+ /* Else, the head becomes this circuit's next circuit */
+ prev_next = &(cmux->active_circuits_head);
+ }
+
+ /* Assert that we got sensible values for the next/prev pointers */
+ tor_assert(next_prev != NULL);
+ tor_assert(prev_next != NULL);
+
+ /* Update the next/prev pointers - this removes circ from the list */
+ *next_prev = *prev_active;
+ *prev_next = *next_active;
+
+ /* Now null out prev_active/next_active */
+ *prev_active = NULL;
+ *next_active = NULL;
+
+ /* Policy-specific notification */
+ if (cmux->policy &&
+ cmux->policy->notify_circ_inactive) {
+ /* Okay, we need to check the circuit for policy data now */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ /* We should have found something */
+ tor_assert(hashent);
+ /* Notify */
+ cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
+ circ, hashent->muxinfo.policy_data);
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/**
+ * Clear the cell counter for a circuit on a circuitmux
+ */
+
+void
+circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
+{
+ /* This is the same as setting the cell count to zero */
+ circuitmux_set_num_cells(cmux, circ, 0);
+}
+
+/**
+ * Set the cell counter for a circuit on a circuitmux
+ */
+
+void
+circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
+ unsigned int n_cells)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ circuitmux_assert_okay_paranoid(cmux);
+
+ /* Search for this circuit's entry */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ /* Assert that we found one */
+ tor_assert(hashent);
+
+ /* Update cmux cell counter */
+ cmux->n_cells -= hashent->muxinfo.cell_count;
+ cmux->n_cells += n_cells;
+
+ /* Do we need to notify a cmux policy? */
+ if (cmux->policy && cmux->policy->notify_set_n_cells) {
+ /* Call notify_set_n_cells */
+ cmux->policy->notify_set_n_cells(cmux,
+ cmux->policy_data,
+ circ,
+ hashent->muxinfo.policy_data,
+ n_cells);
+ }
+
+ /*
+ * Update cmux active circuit counter: is the old cell count > 0 and the
+ * new cell count == 0 ?
+ */
+ if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
+ --(cmux->n_active_circuits);
+ hashent->muxinfo.cell_count = n_cells;
+ circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
+ /* Is the old cell count == 0 and the new cell count > 0 ? */
+ } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
+ ++(cmux->n_active_circuits);
+ hashent->muxinfo.cell_count = n_cells;
+ circuitmux_make_circuit_active(cmux, circ, hashent->muxinfo.direction);
+ } else {
+ /*
+ * Update the entry cell count like this so we can put a
+ * circuitmux_assert_okay_paranoid inside make_circuit_(in)active() too.
+ */
+ hashent->muxinfo.cell_count = n_cells;
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/*
+ * Functions for channel code to call to get a circuit to transmit from or
+ * notify that cells have been transmitted.
+ */
+
+/**
+ * Pick a circuit to send from, using the active circuits list or a
+ * circuitmux policy if one is available. This is called from channel.c.
+ */
+
+circuit_t *
+circuitmux_get_first_active_circuit(circuitmux_t *cmux)
+{
+ circuit_t *circ = NULL;
+
+ tor_assert(cmux);
+
+ if (cmux->n_active_circuits > 0) {
+ /* We also must have a cell available for this to be the case */
+ tor_assert(cmux->n_cells > 0);
+ /* Do we have a policy-provided circuit selector? */
+ if (cmux->policy && cmux->policy->pick_active_circuit) {
+ circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
+ }
+ /* Fall back on the head of the active circuits list */
+ if (!circ) {
+ tor_assert(cmux->active_circuits_head);
+ circ = cmux->active_circuits_head;
+ }
+ } else tor_assert(cmux->n_cells == 0);
+
+ return circ;
+}
+
+/**
+ * Notify the circuitmux that cells have been sent on a circuit; this
+ * is called from channel.c.
+ */
+
+void
+circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
+ unsigned int n_cells)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+ int becomes_inactive = 0;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ circuitmux_assert_okay_paranoid(cmux);
+
+ if (n_cells == 0) return;
+
+ /*
+ * To handle this, we have to:
+ *
+ * 1.) Adjust the circuit's cell counter in the cmux hash table
+ * 2.) Move the circuit to the tail of the active_circuits linked list
+ * for this cmux, or make the circuit inactive if the cell count
+ * went to zero.
+ * 3.) Call cmux->policy->notify_xmit_cells(), if any
+ */
+
+ /* Find the hash entry */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ /* Assert that we found one */
+ tor_assert(hashent);
+
+ /* Adjust the cell counter and assert that we had that many cells to send */
+ tor_assert(n_cells <= hashent->muxinfo.cell_count);
+ hashent->muxinfo.cell_count -= n_cells;
+ /* Do we need to make the circuit inactive? */
+ if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1;
+ /* Adjust the mux cell counter */
+ cmux->n_cells -= n_cells;
+
+ /* If we aren't making it inactive later, move it to the tail of the list */
+ if (!becomes_inactive) {
+ circuitmux_move_active_circ_to_tail(cmux, circ,
+ hashent->muxinfo.direction);
+ }
+
+ /*
+ * We call notify_xmit_cells() before making the circuit inactive if needed,
+ * so the policy can always count on this coming in on an active circuit.
+ */
+ if (cmux->policy && cmux->policy->notify_xmit_cells) {
+ cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
+ hashent->muxinfo.policy_data,
+ n_cells);
+ }
+
+ /*
+ * Now make the circuit inactive if needed; this will call the policy's
+ * notify_circ_inactive() if present.
+ */
+ if (becomes_inactive) {
+ --(cmux->n_active_circuits);
+ circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/*
+ * Circuitmux consistency checking assertions
+ */
+
+/**
+ * Check that circuitmux data structures are consistent and fail with an
+ * assert if not.
+ */
+
+void
+circuitmux_assert_okay(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ /*
+ * Pass 1: iterate the hash table; for each entry:
+ * a) Check that the circuit has this cmux for n_mux or p_mux
+ * b) If the cell_count is > 0, set the mark bit; otherwise clear it
+ * c) Also check activeness (cell_count > 0 should be active)
+ * d) Count the number of circuits, active circuits and queued cells
+ * and at the end check that they match the counters in the cmux.
+ *
+ * Pass 2: iterate the active circuits list; for each entry,
+ * make sure the circuit is attached to this mux and appears
+ * in the hash table. Make sure the mark bit is 1, and clear
+ * it in the hash table entry. Consistency-check the linked
+ * list pointers.
+ *
+ * Pass 3: iterate the hash table again; assert if any active circuits
+ * (mark bit set to 1) are discovered that weren't cleared in pass 2
+ * (don't appear in the linked list).
+ */
+
+ circuitmux_assert_okay_pass_one(cmux);
+ circuitmux_assert_okay_pass_two(cmux);
+ circuitmux_assert_okay_pass_three(cmux);
+}
+
+/**
+ * Do the first pass of circuitmux_assert_okay(); see the comment in that
+ * function.
+ */
+
+static void
+circuitmux_assert_okay_pass_one(circuitmux_t *cmux)
+{
+ chanid_circid_muxinfo_t **i = NULL;
+ uint64_t chan_id;
+ channel_t *chan;
+ circid_t circ_id;
+ circuit_t *circ;
+ or_circuit_t *or_circ;
+ unsigned int circ_is_active;
+ circuit_t **next_p, **prev_p;
+ unsigned int n_circuits, n_active_circuits, n_cells;
+
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+
+ /* Reset the counters */
+ n_circuits = n_active_circuits = n_cells = 0;
+ /* Start iterating the hash table */
+ i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+ while (i) {
+ /* Assert that the hash table entry isn't null */
+ tor_assert(*i);
+
+ /* Get the channel and circuit id */
+ chan_id = (*i)->chan_id;
+ circ_id = (*i)->circ_id;
+
+ /* Find the channel and circuit, assert that they exist */
+ chan = channel_find_by_global_id(chan_id);
+ tor_assert(chan);
+ circ = circuit_get_by_circid_channel_even_if_marked(circ_id, chan);
+ tor_assert(circ);
+ /* Clear the circ_is_active bit to start */
+ circ_is_active = 0;
+
+ /* Assert that we know which direction this is going */
+ tor_assert((*i)->muxinfo.direction == CELL_DIRECTION_OUT ||
+ (*i)->muxinfo.direction == CELL_DIRECTION_IN);
+
+ if ((*i)->muxinfo.direction == CELL_DIRECTION_OUT) {
+ /* We should be n_mux on this circuit */
+ tor_assert(cmux == circ->n_mux);
+ tor_assert(chan == circ->n_chan);
+ /* Get next and prev for next test */
+ next_p = &(circ->next_active_on_n_chan);
+ prev_p = &(circ->prev_active_on_n_chan);
+ } else {
+ /* This should be an or_circuit_t and we should be p_mux */
+ or_circ = TO_OR_CIRCUIT(circ);
+ tor_assert(cmux == or_circ->p_mux);
+ tor_assert(chan == or_circ->p_chan);
+ /* Get next and prev for next test */
+ next_p = &(or_circ->next_active_on_p_chan);
+ prev_p = &(or_circ->prev_active_on_p_chan);
+ }
+
+ /*
+ * Should this circuit be active? I.e., does the mux know about > 0
+ * cells on it?
+ */
+ circ_is_active = ((*i)->muxinfo.cell_count > 0);
+
+ /* It should be in the linked list iff it's active */
+ if (circ_is_active) {
+ /* Either we have a next link or we are the tail */
+ tor_assert(*next_p || (circ == cmux->active_circuits_tail));
+ /* Either we have a prev link or we are the head */
+ tor_assert(*prev_p || (circ == cmux->active_circuits_head));
+ /* Increment the active circuits counter */
+ ++n_active_circuits;
+ } else {
+ /* Shouldn't be in list, so no next or prev link */
+ tor_assert(!(*next_p));
+ tor_assert(!(*prev_p));
+ /* And can't be head or tail */
+ tor_assert(circ != cmux->active_circuits_head);
+ tor_assert(circ != cmux->active_circuits_tail);
+ }
+
+ /* Increment the circuits counter */
+ ++n_circuits;
+ /* Adjust the cell counter */
+ n_cells += (*i)->muxinfo.cell_count;
+
+ /* Set the mark bit to circ_is_active */
+ (*i)->muxinfo.mark = circ_is_active;
+
+ /* Advance to the next entry */
+ i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
+ }
+
+ /* Now check the counters */
+ tor_assert(n_cells == cmux->n_cells);
+ tor_assert(n_circuits == cmux->n_circuits);
+ tor_assert(n_active_circuits == cmux->n_active_circuits);
+}
+
+/**
+ * Do the second pass of circuitmux_assert_okay(); see the comment in that
+ * function.
+ */
+
+static void
+circuitmux_assert_okay_pass_two(circuitmux_t *cmux)
+{
+ circuit_t *curr_circ, *prev_circ = NULL, *next_circ;
+ or_circuit_t *curr_or_circ;
+ uint64_t curr_chan_id;
+ circid_t curr_circ_id;
+ circuit_t **next_p, **prev_p;
+ channel_t *chan;
+ unsigned int n_active_circuits = 0;
+ cell_direction_t direction;
+ chanid_circid_muxinfo_t search, *hashent = NULL;
+
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+
+ /*
+ * Walk the linked list of active circuits in cmux; keep track of the
+ * previous circuit seen for consistency checking purposes. Count them
+ * to make sure the number in the linked list matches
+ * cmux->n_active_circuits.
+ */
+ curr_circ = cmux->active_circuits_head;
+ while (curr_circ) {
+ /* Reset some things */
+ chan = NULL;
+ curr_or_circ = NULL;
+ next_circ = NULL;
+ next_p = prev_p = NULL;
+ direction = 0;
+
+ /* Figure out if this is n_mux or p_mux */
+ if (cmux == curr_circ->n_mux) {
+ /* Get next_p and prev_p */
+ next_p = &(curr_circ->next_active_on_n_chan);
+ prev_p = &(curr_circ->prev_active_on_n_chan);
+ /* Get the channel */
+ chan = curr_circ->n_chan;
+ /* Get the circuit id */
+ curr_circ_id = curr_circ->n_circ_id;
+ /* Remember the direction */
+ direction = CELL_DIRECTION_OUT;
+ } else {
+ /* We must be p_mux and this must be an or_circuit_t */
+ curr_or_circ = TO_OR_CIRCUIT(curr_circ);
+ tor_assert(cmux == curr_or_circ->p_mux);
+ /* Get next_p and prev_p */
+ next_p = &(curr_or_circ->next_active_on_p_chan);
+ prev_p = &(curr_or_circ->prev_active_on_p_chan);
+ /* Get the channel */
+ chan = curr_or_circ->p_chan;
+ /* Get the circuit id */
+ curr_circ_id = curr_or_circ->p_circ_id;
+ /* Remember the direction */
+ direction = CELL_DIRECTION_IN;
+ }
+
+ /* Assert that we got a channel and get the channel ID */
+ tor_assert(chan);
+ curr_chan_id = chan->global_identifier;
+
+ /* Assert that prev_p points to last circuit we saw */
+ tor_assert(*prev_p == prev_circ);
+ /* If that's NULL, assert that we are the head */
+ if (!(*prev_p)) tor_assert(curr_circ == cmux->active_circuits_head);
+
+ /* Get the next circuit */
+ next_circ = *next_p;
+ /* If it's NULL, assert that we are the tail */
+ if (!(*next_p)) tor_assert(curr_circ == cmux->active_circuits_tail);
+
+ /* Now find the hash table entry for this circuit */
+ search.chan_id = curr_chan_id;
+ search.circ_id = curr_circ_id;
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+
+ /* Assert that we have one */
+ tor_assert(hashent);
+
+ /* Assert that the direction matches */
+ tor_assert(direction == hashent->muxinfo.direction);
+
+ /* Assert that the hash entry got marked in pass one */
+ tor_assert(hashent->muxinfo.mark);
+
+ /* Clear the mark */
+ hashent->muxinfo.mark = 0;
+
+ /* Increment the counter */
+ ++n_active_circuits;
+
+ /* Advance to the next active circuit and update prev_circ */
+ prev_circ = curr_circ;
+ curr_circ = next_circ;
+ }
+
+ /* Assert that the counter matches the cmux */
+ tor_assert(n_active_circuits == cmux->n_active_circuits);
+}
+
+/**
+ * Do the third pass of circuitmux_assert_okay(); see the comment in that
+ * function.
+ */
+
+static void
+circuitmux_assert_okay_pass_three(circuitmux_t *cmux)
+{
+ chanid_circid_muxinfo_t **i = NULL;
+
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+
+ /* Start iterating the hash table */
+ i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+
+ /* Advance through each entry */
+ while (i) {
+ /* Assert that it isn't null */
+ tor_assert(*i);
+
+ /*
+ * Assert that this entry is not marked - i.e., that either we didn't
+ * think it should be active in pass one or we saw it in the active
+ * circuits linked list.
+ */
+ tor_assert(!((*i)->muxinfo.mark));
+
+ /* Advance to the next entry */
+ i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
+ }
+}
+
diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h
new file mode 100644
index 0000000000..ebab1ba7d3
--- /dev/null
+++ b/src/or/circuitmux.h
@@ -0,0 +1,136 @@
+/* * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitmux.h
+ * \brief Header file for circuitmux.c
+ **/
+
+#ifndef TOR_CIRCUITMUX_H
+#define TOR_CIRCUITMUX_H
+
+#include "or.h"
+
+typedef struct circuitmux_policy_s circuitmux_policy_t;
+typedef struct circuitmux_policy_data_s circuitmux_policy_data_t;
+typedef struct circuitmux_policy_circ_data_s circuitmux_policy_circ_data_t;
+
+struct circuitmux_policy_s {
+ /* Allocate cmux-wide policy-specific data */
+ circuitmux_policy_data_t * (*alloc_cmux_data)(circuitmux_t *cmux);
+ /* Free cmux-wide policy-specific data */
+ void (*free_cmux_data)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data);
+ /* Allocate circuit policy-specific data for a newly attached circuit */
+ circuitmux_policy_circ_data_t *
+ (*alloc_circ_data)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ cell_direction_t direction,
+ unsigned int cell_count);
+ /* Free circuit policy-specific data */
+ void (*free_circ_data)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+ /* Notify that a circuit has become active/inactive */
+ void (*notify_circ_active)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+ void (*notify_circ_inactive)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+ /* Notify of arriving/transmitted cells on a circuit */
+ void (*notify_set_n_cells)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data,
+ unsigned int n_cells);
+ void (*notify_xmit_cells)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data,
+ unsigned int n_cells);
+ /* Choose a circuit */
+ circuit_t * (*pick_active_circuit)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data);
+};
+
+/*
+ * Circuitmux policy implementations can subclass this to store circuitmux-
+ * wide data; it just has the magic number in the base struct.
+ */
+
+struct circuitmux_policy_data_s {
+ uint32_t magic;
+};
+
+/*
+ * Circuitmux policy implementations can subclass this to store circuit-
+ * specific data; it just has the magic number in the base struct.
+ */
+
+struct circuitmux_policy_circ_data_s {
+ uint32_t magic;
+};
+
+/*
+ * Upcast #defines for the above types
+ */
+
+/**
+ * Convert a circuitmux_policy_data_t subtype to a circuitmux_policy_data_t.
+ */
+
+#define TO_CMUX_POL_DATA(x) (&((x)->base_))
+
+/**
+ * Convert a circuitmux_policy_circ_data_t subtype to a
+ * circuitmux_policy_circ_data_t.
+ */
+
+#define TO_CMUX_POL_CIRC_DATA(x) (&((x)->base_))
+
+/* Consistency check */
+void circuitmux_assert_okay(circuitmux_t *cmux);
+
+/* Create/destroy */
+circuitmux_t * circuitmux_alloc(void);
+void circuitmux_detach_all_circuits(circuitmux_t *cmux);
+void circuitmux_free(circuitmux_t *cmux);
+
+/* Policy control */
+void circuitmux_clear_policy(circuitmux_t *cmux);
+const circuitmux_policy_t * circuitmux_get_policy(circuitmux_t *cmux);
+void circuitmux_set_policy(circuitmux_t *cmux,
+ const circuitmux_policy_t *pol);
+
+/* Status inquiries */
+cell_direction_t circuitmux_attached_circuit_direction(
+ circuitmux_t *cmux,
+ circuit_t *circ);
+int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ);
+int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ);
+unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux,
+ circuit_t *circ);
+unsigned int circuitmux_num_cells(circuitmux_t *cmux);
+unsigned int circuitmux_num_circuits(circuitmux_t *cmux);
+unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux);
+
+/* Channel interface */
+circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux);
+void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
+ unsigned int n_cells);
+
+/* Circuit interface */
+void circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+void circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ);
+void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ);
+void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
+ unsigned int n_cells);
+
+#endif /* TOR_CIRCUITMUX_H */
+
diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c
new file mode 100644
index 0000000000..e1964d2383
--- /dev/null
+++ b/src/or/circuitmux_ewma.c
@@ -0,0 +1,684 @@
+/* * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitmux_ewma.c
+ * \brief EWMA circuit selection as a circuitmux_t policy
+ **/
+
+#define TOR_CIRCUITMUX_EWMA_C_
+
+#include <math.h>
+
+#include "or.h"
+#include "circuitmux.h"
+#include "circuitmux_ewma.h"
+#include "networkstatus.h"
+
+/*** EWMA parameter #defines ***/
+
+/** How long does a tick last (seconds)? */
+#define EWMA_TICK_LEN 10
+
+/** The default per-tick scale factor, if it hasn't been overridden by a
+ * consensus or a configuration setting. zero means "disabled". */
+#define EWMA_DEFAULT_HALFLIFE 0.0
+
+/*** Some useful constant #defines ***/
+
+/*DOCDOC*/
+#define EPSILON 0.00001
+/*DOCDOC*/
+#define LOG_ONEHALF -0.69314718055994529
+
+/*** EWMA structures ***/
+
+typedef struct cell_ewma_s cell_ewma_t;
+typedef struct ewma_policy_data_s ewma_policy_data_t;
+typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t;
+
+/**
+ * The cell_ewma_t structure keeps track of how many cells a circuit has
+ * transferred recently. It keeps an EWMA (exponentially weighted moving
+ * average) of the number of cells flushed from the circuit queue onto a
+ * connection in channel_flush_from_first_active_circuit().
+ */
+
+struct cell_ewma_s {
+ /** The last 'tick' at which we recalibrated cell_count.
+ *
+ * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
+ * since the start of this tick have weight greater than 1.0; ones sent
+ * earlier have less weight. */
+ unsigned int last_adjusted_tick;
+ /** The EWMA of the cell count. */
+ double cell_count;
+ /** True iff this is the cell count for a circuit's previous
+ * channel. */
+ unsigned int is_for_p_chan : 1;
+ /** The position of the circuit within the OR connection's priority
+ * queue. */
+ int heap_index;
+};
+
+struct ewma_policy_data_s {
+ circuitmux_policy_data_t base_;
+
+ /**
+ * Priority queue of cell_ewma_t for circuits with queued cells waiting
+ * for room to free up on the channel that owns this circuitmux. Kept
+ * in heap order according to EWMA. This was formerly in channel_t, and
+ * in or_connection_t before that.
+ */
+ smartlist_t *active_circuit_pqueue;
+
+ /**
+ * The tick on which the cell_ewma_ts in active_circuit_pqueue last had
+ * their ewma values rescaled. This was formerly in channel_t, and in
+ * or_connection_t before that.
+ */
+ unsigned int active_circuit_pqueue_last_recalibrated;
+};
+
+struct ewma_policy_circ_data_s {
+ circuitmux_policy_circ_data_t base_;
+
+ /**
+ * The EWMA count for the number of cells flushed from this circuit
+ * onto this circuitmux. Used to determine which circuit to flush
+ * from next. This was formerly in circuit_t and or_circuit_t.
+ */
+ cell_ewma_t cell_ewma;
+
+ /**
+ * Pointer back to the circuit_t this is for; since we're separating
+ * out circuit selection policy like this, we can't attach cell_ewma_t
+ * to the circuit_t any more, so we can't use SUBTYPE_P directly to a
+ * circuit_t like before; instead get it here.
+ */
+ circuit_t *circ;
+};
+
+#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
+#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U
+
+/*** Downcasts for the above types ***/
+
+static ewma_policy_data_t *
+TO_EWMA_POL_DATA(circuitmux_policy_data_t *);
+
+static ewma_policy_circ_data_t *
+TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *);
+
+/**
+ * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
+ * if the cast is impossible.
+ */
+
+static INLINE ewma_policy_data_t *
+TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol)
+{
+ if (!pol) return NULL;
+ else {
+ tor_assert(pol->magic == EWMA_POL_DATA_MAGIC);
+ return DOWNCAST(ewma_policy_data_t, pol);
+ }
+}
+
+/**
+ * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
+ * and assert if the cast is impossible.
+ */
+
+static INLINE ewma_policy_circ_data_t *
+TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol)
+{
+ if (!pol) return NULL;
+ else {
+ tor_assert(pol->magic == EWMA_POL_CIRC_DATA_MAGIC);
+ return DOWNCAST(ewma_policy_circ_data_t, pol);
+ }
+}
+
+/*** Static declarations for circuitmux_ewma.c ***/
+
+static void add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma);
+static int compare_cell_ewma_counts(const void *p1, const void *p2);
+static unsigned cell_ewma_tick_from_timeval(const struct timeval *now,
+ double *remainder_out);
+static circuit_t * cell_ewma_to_circuit(cell_ewma_t *ewma);
+static INLINE double get_scale_factor(unsigned from_tick, unsigned to_tick);
+static cell_ewma_t * pop_first_cell_ewma(ewma_policy_data_t *pol);
+static void remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma);
+static void scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick);
+static void scale_active_circuits(ewma_policy_data_t *pol,
+ unsigned cur_tick);
+
+/*** Circuitmux policy methods ***/
+
+static circuitmux_policy_data_t * ewma_alloc_cmux_data(circuitmux_t *cmux);
+static void ewma_free_cmux_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data);
+static circuitmux_policy_circ_data_t *
+ewma_alloc_circ_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data,
+ circuit_t *circ, cell_direction_t direction,
+ unsigned int cell_count);
+static void
+ewma_free_circ_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+static void
+ewma_notify_circ_active(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+static void
+ewma_notify_circ_inactive(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+static void
+ewma_notify_xmit_cells(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data,
+ unsigned int n_cells);
+static circuit_t *
+ewma_pick_active_circuit(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data);
+
+/*** EWMA global variables ***/
+
+/** The per-tick scale factor to be used when computing cell-count EWMA
+ * values. (A cell sent N ticks before the start of the current tick
+ * has value ewma_scale_factor ** N.)
+ */
+static double ewma_scale_factor = 0.1;
+/* DOCDOC ewma_enabled */
+static int ewma_enabled = 0;
+
+/*** EWMA circuitmux_policy_t method table ***/
+
+circuitmux_policy_t ewma_policy = {
+ /*.alloc_cmux_data =*/ ewma_alloc_cmux_data,
+ /*.free_cmux_data =*/ ewma_free_cmux_data,
+ /*.alloc_circ_data =*/ ewma_alloc_circ_data,
+ /*.free_circ_data =*/ ewma_free_circ_data,
+ /*.notify_circ_active =*/ ewma_notify_circ_active,
+ /*.notify_circ_inactive =*/ ewma_notify_circ_inactive,
+ /*.notify_set_n_cells =*/ NULL, /* EWMA doesn't need this */
+ /*.notify_xmit_cells =*/ ewma_notify_xmit_cells,
+ /*.pick_active_circuit =*/ ewma_pick_active_circuit
+};
+
+/*** EWMA method implementations using the below EWMA helper functions ***/
+
+/**
+ * Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t;
+ * this is called when setting the policy on a circuitmux_t to ewma_policy.
+ */
+
+static circuitmux_policy_data_t *
+ewma_alloc_cmux_data(circuitmux_t *cmux)
+{
+ ewma_policy_data_t *pol = NULL;
+
+ tor_assert(cmux);
+
+ pol = tor_malloc_zero(sizeof(*pol));
+ pol->base_.magic = EWMA_POL_DATA_MAGIC;
+ pol->active_circuit_pqueue = smartlist_new();
+ pol->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick();
+
+ return TO_CMUX_POL_DATA(pol);
+}
+
+/**
+ * Free an ewma_policy_data_t allocated with ewma_alloc_cmux_data()
+ */
+
+static void
+ewma_free_cmux_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data)
+{
+ ewma_policy_data_t *pol = NULL;
+
+ tor_assert(cmux);
+ if (!pol_data) return;
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+
+ smartlist_free(pol->active_circuit_pqueue);
+ tor_free(pol);
+}
+
+/**
+ * Allocate an ewma_policy_circ_data_t and upcast it to a
+ * circuitmux_policy_data_t; this is called when attaching a circuit to a
+ * circuitmux_t with ewma_policy.
+ */
+
+static circuitmux_policy_circ_data_t *
+ewma_alloc_circ_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ cell_direction_t direction,
+ unsigned int cell_count)
+{
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+ tor_assert(circ);
+ tor_assert(direction == CELL_DIRECTION_OUT ||
+ direction == CELL_DIRECTION_IN);
+ /* Shut the compiler up */
+ tor_assert(cell_count == cell_count);
+
+ cdata = tor_malloc_zero(sizeof(*cdata));
+ cdata->base_.magic = EWMA_POL_CIRC_DATA_MAGIC;
+ cdata->circ = circ;
+
+ /*
+ * Initialize the cell_ewma_t structure (formerly in
+ * init_circuit_base())
+ */
+ cdata->cell_ewma.last_adjusted_tick = cell_ewma_get_tick();
+ cdata->cell_ewma.cell_count = 0.0;
+ cdata->cell_ewma.heap_index = -1;
+ if (direction == CELL_DIRECTION_IN) {
+ cdata->cell_ewma.is_for_p_chan = 1;
+ } else {
+ cdata->cell_ewma.is_for_p_chan = 0;
+ }
+
+ return TO_CMUX_POL_CIRC_DATA(cdata);
+}
+
+/**
+ * Free an ewma_policy_circ_data_t allocated with ewma_alloc_circ_data()
+ */
+
+static void
+ewma_free_circ_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data)
+
+{
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ tor_assert(pol_data);
+
+ if (!pol_circ_data) return;
+
+ cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
+
+ tor_free(cdata);
+}
+
+/**
+ * Handle circuit activation; this inserts the circuit's cell_ewma into
+ * the active_circuits_pqueue.
+ */
+
+static void
+ewma_notify_circ_active(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data)
+{
+ ewma_policy_data_t *pol = NULL;
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+ tor_assert(circ);
+ tor_assert(pol_circ_data);
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+ cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
+
+ add_cell_ewma(pol, &(cdata->cell_ewma));
+}
+
+/**
+ * Handle circuit deactivation; this removes the circuit's cell_ewma from
+ * the active_circuits_pqueue.
+ */
+
+static void
+ewma_notify_circ_inactive(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data)
+{
+ ewma_policy_data_t *pol = NULL;
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+ tor_assert(circ);
+ tor_assert(pol_circ_data);
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+ cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
+
+ remove_cell_ewma(pol, &(cdata->cell_ewma));
+}
+
+/**
+ * Update cell_ewma for this circuit after we've sent some cells, and
+ * remove/reinsert it in the queue. This used to be done (brokenly,
+ * see bug 6816) in channel_flush_from_first_active_circuit().
+ */
+
+static void
+ewma_notify_xmit_cells(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data,
+ unsigned int n_cells)
+{
+ ewma_policy_data_t *pol = NULL;
+ ewma_policy_circ_data_t *cdata = NULL;
+ unsigned int tick;
+ double fractional_tick, ewma_increment;
+ /* The current (hi-res) time */
+ struct timeval now_hires;
+ cell_ewma_t *cell_ewma, *tmp;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+ tor_assert(circ);
+ tor_assert(pol_circ_data);
+ tor_assert(n_cells > 0);
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+ cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
+
+ /* Rescale the EWMAs if needed */
+ tor_gettimeofday_cached(&now_hires);
+ tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick);
+
+ if (tick != pol->active_circuit_pqueue_last_recalibrated) {
+ scale_active_circuits(pol, tick);
+ }
+
+ /* How much do we adjust the cell count in cell_ewma by? */
+ ewma_increment =
+ ((double)(n_cells)) * pow(ewma_scale_factor, -fractional_tick);
+
+ /* Do the adjustment */
+ cell_ewma = &(cdata->cell_ewma);
+ cell_ewma->cell_count += ewma_increment;
+
+ /*
+ * Since we just sent on this circuit, it should be at the head of
+ * the queue. Pop the head, assert that it matches, then re-add.
+ */
+ tmp = pop_first_cell_ewma(pol);
+ tor_assert(tmp == cell_ewma);
+ add_cell_ewma(pol, cell_ewma);
+}
+
+/**
+ * Pick the preferred circuit to send from; this will be the one with
+ * the lowest EWMA value in the priority queue. This used to be done
+ * in channel_flush_from_first_active_circuit().
+ */
+
+static circuit_t *
+ewma_pick_active_circuit(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data)
+{
+ ewma_policy_data_t *pol = NULL;
+ circuit_t *circ = NULL;
+ cell_ewma_t *cell_ewma = NULL;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+
+ if (smartlist_len(pol->active_circuit_pqueue) > 0) {
+ /* Get the head of the queue */
+ cell_ewma = smartlist_get(pol->active_circuit_pqueue, 0);
+ circ = cell_ewma_to_circuit(cell_ewma);
+ }
+
+ return circ;
+}
+
+/** Helper for sorting cell_ewma_t values in their priority queue. */
+static int
+compare_cell_ewma_counts(const void *p1, const void *p2)
+{
+ const cell_ewma_t *e1 = p1, *e2 = p2;
+
+ if (e1->cell_count < e2->cell_count)
+ return -1;
+ else if (e1->cell_count > e2->cell_count)
+ return 1;
+ else
+ return 0;
+}
+
+/** Given a cell_ewma_t, return a pointer to the circuit containing it. */
+static circuit_t *
+cell_ewma_to_circuit(cell_ewma_t *ewma)
+{
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(ewma);
+ cdata = SUBTYPE_P(ewma, ewma_policy_circ_data_t, cell_ewma);
+ tor_assert(cdata);
+
+ return cdata->circ;
+}
+
+/* ==== Functions for scaling cell_ewma_t ====
+
+ When choosing which cells to relay first, we favor circuits that have been
+ quiet recently. This gives better latency on connections that aren't
+ pushing lots of data, and makes the network feel more interactive.
+
+ Conceptually, we take an exponentially weighted mean average of the number
+ of cells a circuit has sent, and allow active circuits (those with cells to
+ relay) to send cells in reverse order of their exponentially-weighted mean
+ average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts'
+ F^N times as much as a cell sent now, for 0<F<1.0, and we favor the
+ circuit that has sent the fewest cells]
+
+ If 'double' had infinite precision, we could do this simply by counting a
+ cell sent at startup as having weight 1.0, and a cell sent N seconds later
+ as having weight F^-N. This way, we would never need to re-scale
+ any already-sent cells.
+
+ To prevent double from overflowing, we could count a cell sent now as
+ having weight 1.0 and a cell sent N seconds ago as having weight F^N.
+ This, however, would mean we'd need to re-scale *ALL* old circuits every
+ time we wanted to send a cell.
+
+ So as a compromise, we divide time into 'ticks' (currently, 10-second
+ increments) and say that a cell sent at the start of a current tick is
+ worth 1.0, a cell sent N seconds before the start of the current tick is
+ worth F^N, and a cell sent N seconds after the start of the current tick is
+ worth F^-N. This way we don't overflow, and we don't need to constantly
+ rescale.
+ */
+
+/** Given a timeval <b>now</b>, compute the cell_ewma tick in which it occurs
+ * and the fraction of the tick that has elapsed between the start of the tick
+ * and <b>now</b>. Return the former and store the latter in
+ * *<b>remainder_out</b>.
+ *
+ * These tick values are not meant to be shared between Tor instances, or used
+ * for other purposes. */
+
+static unsigned
+cell_ewma_tick_from_timeval(const struct timeval *now,
+ double *remainder_out)
+{
+ unsigned res = (unsigned) (now->tv_sec / EWMA_TICK_LEN);
+ /* rem */
+ double rem = (now->tv_sec % EWMA_TICK_LEN) +
+ ((double)(now->tv_usec)) / 1.0e6;
+ *remainder_out = rem / EWMA_TICK_LEN;
+ return res;
+}
+
+/** Tell the caller whether ewma_enabled is set */
+int
+cell_ewma_enabled(void)
+{
+ return ewma_enabled;
+}
+
+/** Compute and return the current cell_ewma tick. */
+unsigned int
+cell_ewma_get_tick(void)
+{
+ return ((unsigned)approx_time() / EWMA_TICK_LEN);
+}
+
+/** Adjust the global cell scale factor based on <b>options</b> */
+void
+cell_ewma_set_scale_factor(const or_options_t *options,
+ const networkstatus_t *consensus)
+{
+ int32_t halflife_ms;
+ double halflife;
+ const char *source;
+ if (options && options->CircuitPriorityHalflife >= -EPSILON) {
+ halflife = options->CircuitPriorityHalflife;
+ source = "CircuitPriorityHalflife in configuration";
+ } else if (consensus && (halflife_ms = networkstatus_get_param(
+ consensus, "CircuitPriorityHalflifeMsec",
+ -1, -1, INT32_MAX)) >= 0) {
+ halflife = ((double)halflife_ms)/1000.0;
+ source = "CircuitPriorityHalflifeMsec in consensus";
+ } else {
+ halflife = EWMA_DEFAULT_HALFLIFE;
+ source = "Default value";
+ }
+
+ if (halflife <= EPSILON) {
+ /* The cell EWMA algorithm is disabled. */
+ ewma_scale_factor = 0.1;
+ ewma_enabled = 0;
+ log_info(LD_OR,
+ "Disabled cell_ewma algorithm because of value in %s",
+ source);
+ } else {
+ /* convert halflife into halflife-per-tick. */
+ halflife /= EWMA_TICK_LEN;
+ /* compute per-tick scale factor. */
+ ewma_scale_factor = exp( LOG_ONEHALF / halflife );
+ ewma_enabled = 1;
+ log_info(LD_OR,
+ "Enabled cell_ewma algorithm because of value in %s; "
+ "scale factor is %f per %d seconds",
+ source, ewma_scale_factor, EWMA_TICK_LEN);
+ }
+}
+
+/** Return the multiplier necessary to convert the value of a cell sent in
+ * 'from_tick' to one sent in 'to_tick'. */
+static INLINE double
+get_scale_factor(unsigned from_tick, unsigned to_tick)
+{
+ /* This math can wrap around, but that's okay: unsigned overflow is
+ well-defined */
+ int diff = (int)(to_tick - from_tick);
+ return pow(ewma_scale_factor, diff);
+}
+
+/** Adjust the cell count of <b>ewma</b> so that it is scaled with respect to
+ * <b>cur_tick</b> */
+static void
+scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick)
+{
+ double factor = get_scale_factor(ewma->last_adjusted_tick, cur_tick);
+ ewma->cell_count *= factor;
+ ewma->last_adjusted_tick = cur_tick;
+}
+
+/** Adjust the cell count of every active circuit on <b>chan</b> so
+ * that they are scaled with respect to <b>cur_tick</b> */
+static void
+scale_active_circuits(ewma_policy_data_t *pol, unsigned cur_tick)
+{
+ double factor;
+
+ tor_assert(pol);
+ tor_assert(pol->active_circuit_pqueue);
+
+ factor =
+ get_scale_factor(
+ pol->active_circuit_pqueue_last_recalibrated,
+ cur_tick);
+ /** Ordinarily it isn't okay to change the value of an element in a heap,
+ * but it's okay here, since we are preserving the order. */
+ SMARTLIST_FOREACH_BEGIN(
+ pol->active_circuit_pqueue,
+ cell_ewma_t *, e) {
+ tor_assert(e->last_adjusted_tick ==
+ pol->active_circuit_pqueue_last_recalibrated);
+ e->cell_count *= factor;
+ e->last_adjusted_tick = cur_tick;
+ } SMARTLIST_FOREACH_END(e);
+ pol->active_circuit_pqueue_last_recalibrated = cur_tick;
+}
+
+/** Rescale <b>ewma</b> to the same scale as <b>pol</b>, and add it to
+ * <b>pol</b>'s priority queue of active circuits */
+static void
+add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma)
+{
+ tor_assert(pol);
+ tor_assert(pol->active_circuit_pqueue);
+ tor_assert(ewma);
+ tor_assert(ewma->heap_index == -1);
+
+ scale_single_cell_ewma(
+ ewma,
+ pol->active_circuit_pqueue_last_recalibrated);
+
+ smartlist_pqueue_add(pol->active_circuit_pqueue,
+ compare_cell_ewma_counts,
+ STRUCT_OFFSET(cell_ewma_t, heap_index),
+ ewma);
+}
+
+/** Remove <b>ewma</b> from <b>pol</b>'s priority queue of active circuits */
+static void
+remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma)
+{
+ tor_assert(pol);
+ tor_assert(pol->active_circuit_pqueue);
+ tor_assert(ewma);
+ tor_assert(ewma->heap_index != -1);
+
+ smartlist_pqueue_remove(pol->active_circuit_pqueue,
+ compare_cell_ewma_counts,
+ STRUCT_OFFSET(cell_ewma_t, heap_index),
+ ewma);
+}
+
+/** Remove and return the first cell_ewma_t from pol's priority queue of
+ * active circuits. Requires that the priority queue is nonempty. */
+static cell_ewma_t *
+pop_first_cell_ewma(ewma_policy_data_t *pol)
+{
+ tor_assert(pol);
+ tor_assert(pol->active_circuit_pqueue);
+
+ return smartlist_pqueue_pop(pol->active_circuit_pqueue,
+ compare_cell_ewma_counts,
+ STRUCT_OFFSET(cell_ewma_t, heap_index));
+}
+
diff --git a/src/or/circuitmux_ewma.h b/src/or/circuitmux_ewma.h
new file mode 100644
index 0000000000..5621acc936
--- /dev/null
+++ b/src/or/circuitmux_ewma.h
@@ -0,0 +1,29 @@
+/* * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitmux_ewma.h
+ * \brief Header file for circuitmux_ewma.c
+ **/
+
+#ifndef TOR_CIRCUITMUX_EWMA_H
+#define TOR_CIRCUITMUX_EWMA_H
+
+#include "or.h"
+#include "circuitmux.h"
+
+/* Everything but circuitmux_ewma.c should see this extern */
+#ifndef TOR_CIRCUITMUX_EWMA_C_
+
+extern circuitmux_policy_t ewma_policy;
+
+#endif /* !(TOR_CIRCUITMUX_EWMA_C_) */
+
+/* Externally visible EWMA functions */
+int cell_ewma_enabled(void);
+unsigned int cell_ewma_get_tick(void);
+void cell_ewma_set_scale_factor(const or_options_t *options,
+ const networkstatus_t *consensus);
+
+#endif /* TOR_CIRCUITMUX_EWMA_H */
+
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
new file mode 100644
index 0000000000..4f12a6fbcd
--- /dev/null
+++ b/src/or/circuitstats.c
@@ -0,0 +1,1569 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CIRCUITSTATS_PRIVATE
+
+#include "or.h"
+#include "circuitbuild.h"
+#include "circuitstats.h"
+#include "config.h"
+#include "confparse.h"
+#include "control.h"
+#include "networkstatus.h"
+#include "statefile.h"
+
+#undef log
+#include <math.h>
+
+#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2))
+
+/** Global list of circuit build times */
+// XXXX: Add this as a member for entry_guard_t instead of global?
+// Then we could do per-guard statistics, as guards are likely to
+// vary in their own latency. The downside of this is that guards
+// can change frequently, so we'd be building a lot more circuits
+// most likely.
+/* XXXX024 Make this static; add accessor functions. */
+circuit_build_times_t circ_times;
+
+/** If set, we're running the unit tests: we should avoid clobbering
+ * our state file or accessing get_options() or get_or_state() */
+static int unit_tests = 0;
+
+/**
+ * This function decides if CBT learning should be disabled. It returns
+ * true if one or more of the following four conditions are met:
+ *
+ * 1. If the cbtdisabled consensus parameter is set.
+ * 2. If the torrc option LearnCircuitBuildTimeout is false.
+ * 3. If we are a directory authority
+ * 4. If we fail to write circuit build time history to our state file.
+ */
+int
+circuit_build_times_disabled(void)
+{
+ if (unit_tests) {
+ return 0;
+ } else {
+ int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled",
+ 0, 0, 1);
+ int config_disabled = !get_options()->LearnCircuitBuildTimeout;
+ int dirauth_disabled = get_options()->AuthoritativeDir;
+ int state_disabled = did_last_state_file_write_fail() ? 1 : 0;
+
+ if (consensus_disabled || config_disabled || dirauth_disabled ||
+ state_disabled) {
+ log_debug(LD_CIRC,
+ "CircuitBuildTime learning is disabled. "
+ "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d",
+ consensus_disabled, config_disabled, dirauth_disabled,
+ state_disabled);
+ return 1;
+ } else {
+ log_debug(LD_CIRC,
+ "CircuitBuildTime learning is not disabled. "
+ "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d",
+ consensus_disabled, config_disabled, dirauth_disabled,
+ state_disabled);
+ return 0;
+ }
+ }
+}
+
+/**
+ * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter.
+ *
+ * Effect: When this many timeouts happen in the last 'cbtrecentcount'
+ * circuit attempts, the client should discard all of its history and
+ * begin learning a fresh timeout value.
+ */
+static int32_t
+circuit_build_times_max_timeouts(void)
+{
+ int32_t cbt_maxtimeouts;
+
+ cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts",
+ CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT,
+ CBT_MIN_MAX_RECENT_TIMEOUT_COUNT,
+ CBT_MAX_MAX_RECENT_TIMEOUT_COUNT);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is"
+ " %d",
+ cbt_maxtimeouts);
+ }
+
+ return cbt_maxtimeouts;
+}
+
+/**
+ * Retrieve and bounds-check the cbtnummodes consensus paramter.
+ *
+ * Effect: This value governs how many modes to use in the weighted
+ * average calculation of Pareto parameter Xm. A value of 3 introduces
+ * some bias (2-5% of CDF) under ideal conditions, but allows for better
+ * performance in the event that a client chooses guard nodes of radically
+ * different performance characteristics.
+ */
+static int32_t
+circuit_build_times_default_num_xm_modes(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbtnummodes",
+ CBT_DEFAULT_NUM_XM_MODES,
+ CBT_MIN_NUM_XM_MODES,
+ CBT_MAX_NUM_XM_MODES);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_default_num_xm_modes() called, cbtnummodes"
+ " is %d",
+ num);
+ }
+
+ return num;
+}
+
+/**
+ * Retrieve and bounds-check the cbtmincircs consensus paramter.
+ *
+ * Effect: This is the minimum number of circuits to build before
+ * computing a timeout.
+ */
+static int32_t
+circuit_build_times_min_circs_to_observe(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbtmincircs",
+ CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE,
+ CBT_MIN_MIN_CIRCUITS_TO_OBSERVE,
+ CBT_MAX_MIN_CIRCUITS_TO_OBSERVE);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_min_circs_to_observe() called, cbtmincircs"
+ " is %d",
+ num);
+ }
+
+ return num;
+}
+
+/** Return true iff <b>cbt</b> has recorded enough build times that we
+ * want to start acting on the timeout it implies. */
+int
+circuit_build_times_enough_to_compute(circuit_build_times_t *cbt)
+{
+ return cbt->total_build_times >= circuit_build_times_min_circs_to_observe();
+}
+
+/**
+ * Retrieve and bounds-check the cbtquantile consensus paramter.
+ *
+ * Effect: This is the position on the quantile curve to use to set the
+ * timeout value. It is a percent (10-99).
+ */
+double
+circuit_build_times_quantile_cutoff(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbtquantile",
+ CBT_DEFAULT_QUANTILE_CUTOFF,
+ CBT_MIN_QUANTILE_CUTOFF,
+ CBT_MAX_QUANTILE_CUTOFF);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_quantile_cutoff() called, cbtquantile"
+ " is %d",
+ num);
+ }
+
+ return num/100.0;
+}
+
+/* DOCDOC circuit_build_times_get_bw_scale */
+int
+circuit_build_times_get_bw_scale(networkstatus_t *ns)
+{
+ return networkstatus_get_param(ns, "bwweightscale",
+ BW_WEIGHT_SCALE,
+ BW_MIN_WEIGHT_SCALE,
+ BW_MAX_WEIGHT_SCALE);
+}
+
+/**
+ * Retrieve and bounds-check the cbtclosequantile consensus paramter.
+ *
+ * Effect: This is the position on the quantile curve to use to set the
+ * timeout value to use to actually close circuits. It is a percent
+ * (0-99).
+ */
+static double
+circuit_build_times_close_quantile(void)
+{
+ int32_t param;
+ /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */
+ int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff());
+ param = networkstatus_get_param(NULL, "cbtclosequantile",
+ CBT_DEFAULT_CLOSE_QUANTILE,
+ CBT_MIN_CLOSE_QUANTILE,
+ CBT_MAX_CLOSE_QUANTILE);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_close_quantile() called, cbtclosequantile"
+ " is %d", param);
+ }
+
+ if (param < min) {
+ log_warn(LD_DIR, "Consensus parameter cbtclosequantile is "
+ "too small, raising to %d", min);
+ param = min;
+ }
+ return param / 100.0;
+}
+
+/**
+ * Retrieve and bounds-check the cbttestfreq consensus paramter.
+ *
+ * Effect: Describes how often in seconds to build a test circuit to
+ * gather timeout values. Only applies if less than 'cbtmincircs'
+ * have been recorded.
+ */
+static int32_t
+circuit_build_times_test_frequency(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbttestfreq",
+ CBT_DEFAULT_TEST_FREQUENCY,
+ CBT_MIN_TEST_FREQUENCY,
+ CBT_MAX_TEST_FREQUENCY);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_test_frequency() called, cbttestfreq is %d",
+ num);
+ }
+
+ return num;
+}
+
+/**
+ * Retrieve and bounds-check the cbtmintimeout consensus parameter.
+ *
+ * Effect: This is the minimum allowed timeout value in milliseconds.
+ * The minimum is to prevent rounding to 0 (we only check once
+ * per second).
+ */
+static int32_t
+circuit_build_times_min_timeout(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbtmintimeout",
+ CBT_DEFAULT_TIMEOUT_MIN_VALUE,
+ CBT_MIN_TIMEOUT_MIN_VALUE,
+ CBT_MAX_TIMEOUT_MIN_VALUE);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_min_timeout() called, cbtmintimeout is %d",
+ num);
+ }
+
+ return num;
+}
+
+/**
+ * Retrieve and bounds-check the cbtinitialtimeout consensus paramter.
+ *
+ * Effect: This is the timeout value to use before computing a timeout,
+ * in milliseconds.
+ */
+int32_t
+circuit_build_times_initial_timeout(void)
+{
+ int32_t min = circuit_build_times_min_timeout();
+ int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout",
+ CBT_DEFAULT_TIMEOUT_INITIAL_VALUE,
+ CBT_MIN_TIMEOUT_INITIAL_VALUE,
+ CBT_MAX_TIMEOUT_INITIAL_VALUE);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_initial_timeout() called, "
+ "cbtinitialtimeout is %d",
+ param);
+ }
+
+ if (param < min) {
+ log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, "
+ "raising to %d", min);
+ param = min;
+ }
+ return param;
+}
+
+/**
+ * Retrieve and bounds-check the cbtrecentcount consensus paramter.
+ *
+ * Effect: This is the number of circuit build times to keep track of
+ * for deciding if we hit cbtmaxtimeouts and need to reset our state
+ * and learn a new timeout.
+ */
+static int32_t
+circuit_build_times_recent_circuit_count(networkstatus_t *ns)
+{
+ int32_t num;
+ num = networkstatus_get_param(ns, "cbtrecentcount",
+ CBT_DEFAULT_RECENT_CIRCUITS,
+ CBT_MIN_RECENT_CIRCUITS,
+ CBT_MAX_RECENT_CIRCUITS);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_recent_circuit_count() called, "
+ "cbtrecentcount is %d",
+ num);
+ }
+
+ return num;
+}
+
+/**
+ * This function is called when we get a consensus update.
+ *
+ * It checks to see if we have changed any consensus parameters
+ * that require reallocation or discard of previous stats.
+ */
+void
+circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
+ networkstatus_t *ns)
+{
+ int32_t num;
+
+ /*
+ * First check if we're doing adaptive timeouts at all; nothing to
+ * update if we aren't.
+ */
+
+ if (!circuit_build_times_disabled()) {
+ num = circuit_build_times_recent_circuit_count(ns);
+
+ if (num > 0) {
+ if (num != cbt->liveness.num_recent_circs) {
+ int8_t *recent_circs;
+ log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many "
+ "circuits we must track to detect network failures from %d "
+ "to %d.", cbt->liveness.num_recent_circs, num);
+
+ tor_assert(cbt->liveness.timeouts_after_firsthop ||
+ cbt->liveness.num_recent_circs == 0);
+
+ /*
+ * Technically this is a circular array that we are reallocating
+ * and memcopying. However, since it only consists of either 1s
+ * or 0s, and is only used in a statistical test to determine when
+ * we should discard our history after a sufficient number of 1's
+ * have been reached, it is fine if order is not preserved or
+ * elements are lost.
+ *
+ * cbtrecentcount should only be changing in cases of severe network
+ * distress anyway, so memory correctness here is paramount over
+ * doing acrobatics to preserve the array.
+ */
+ recent_circs = tor_malloc_zero(sizeof(int8_t)*num);
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop,
+ sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs));
+ }
+
+ // Adjust the index if it needs it.
+ if (num < cbt->liveness.num_recent_circs) {
+ cbt->liveness.after_firsthop_idx = MIN(num-1,
+ cbt->liveness.after_firsthop_idx);
+ }
+
+ tor_free(cbt->liveness.timeouts_after_firsthop);
+ cbt->liveness.timeouts_after_firsthop = recent_circs;
+ cbt->liveness.num_recent_circs = num;
+ }
+ /* else no change, nothing to do */
+ } else { /* num == 0 */
+ /*
+ * Weird. This probably shouldn't happen, so log a warning, but try
+ * to do something sensible anyway.
+ */
+
+ log_warn(LD_CIRC,
+ "The cbtrecentcircs consensus parameter came back zero! "
+ "This disables adaptive timeouts since we can't keep track of "
+ "any recent circuits.");
+
+ circuit_build_times_free_timeouts(cbt);
+ }
+ } else {
+ /*
+ * Adaptive timeouts are disabled; this might be because of the
+ * LearnCircuitBuildTimes config parameter, and hence permanent, or
+ * the cbtdisabled consensus parameter, so it may be a new condition.
+ * Treat it like getting num == 0 above and free the circuit history
+ * if we have any.
+ */
+
+ circuit_build_times_free_timeouts(cbt);
+ }
+}
+
+/**
+ * Return the initial default or configured timeout in milliseconds
+ */
+static double
+circuit_build_times_get_initial_timeout(void)
+{
+ double timeout;
+
+ /*
+ * Check if we have LearnCircuitBuildTimeout, and if we don't,
+ * always use CircuitBuildTimeout, no questions asked.
+ */
+ if (get_options()->LearnCircuitBuildTimeout) {
+ if (!unit_tests && get_options()->CircuitBuildTimeout) {
+ timeout = get_options()->CircuitBuildTimeout*1000;
+ if (timeout < circuit_build_times_min_timeout()) {
+ log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds",
+ circuit_build_times_min_timeout()/1000);
+ timeout = circuit_build_times_min_timeout();
+ }
+ } else {
+ timeout = circuit_build_times_initial_timeout();
+ }
+ } else {
+ timeout = get_options()->CircuitBuildTimeout*1000;
+ }
+
+ return timeout;
+}
+
+/**
+ * Reset the build time state.
+ *
+ * Leave estimated parameters, timeout and network liveness intact
+ * for future use.
+ */
+void
+circuit_build_times_reset(circuit_build_times_t *cbt)
+{
+ memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times));
+ cbt->total_build_times = 0;
+ cbt->build_times_idx = 0;
+ cbt->have_computed_timeout = 0;
+}
+
+/**
+ * Initialize the buildtimes structure for first use.
+ *
+ * Sets the initial timeout values based on either the config setting,
+ * the consensus param, or the default (CBT_DEFAULT_TIMEOUT_INITIAL_VALUE).
+ */
+void
+circuit_build_times_init(circuit_build_times_t *cbt)
+{
+ memset(cbt, 0, sizeof(*cbt));
+ /*
+ * Check if we really are using adaptive timeouts, and don't keep
+ * track of this stuff if not.
+ */
+ if (!circuit_build_times_disabled()) {
+ cbt->liveness.num_recent_circs =
+ circuit_build_times_recent_circuit_count(NULL);
+ cbt->liveness.timeouts_after_firsthop =
+ tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs);
+ } else {
+ cbt->liveness.num_recent_circs = 0;
+ cbt->liveness.timeouts_after_firsthop = NULL;
+ }
+ cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout();
+ control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
+}
+
+/**
+ * Free the saved timeouts, if the cbtdisabled consensus parameter got turned
+ * on or something.
+ */
+
+void
+circuit_build_times_free_timeouts(circuit_build_times_t *cbt)
+{
+ if (!cbt) return;
+
+ if (cbt->liveness.timeouts_after_firsthop) {
+ tor_free(cbt->liveness.timeouts_after_firsthop);
+ }
+
+ cbt->liveness.num_recent_circs = 0;
+}
+
+#if 0
+/**
+ * Rewind our build time history by n positions.
+ */
+static void
+circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
+{
+ int i = 0;
+
+ cbt->build_times_idx -= n;
+ cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE;
+
+ for (i = 0; i < n; i++) {
+ cbt->circuit_build_times[(i+cbt->build_times_idx)
+ %CBT_NCIRCUITS_TO_OBSERVE]=0;
+ }
+
+ if (cbt->total_build_times > n) {
+ cbt->total_build_times -= n;
+ } else {
+ cbt->total_build_times = 0;
+ }
+
+ log_info(LD_CIRC,
+ "Rewound history by %d places. Current index: %d. "
+ "Total: %d", n, cbt->build_times_idx, cbt->total_build_times);
+}
+#endif
+
+/**
+ * Add a new build time value <b>time</b> to the set of build times. Time
+ * units are milliseconds.
+ *
+ * circuit_build_times <b>cbt</b> is a circular array, so loop around when
+ * array is full.
+ */
+int
+circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
+{
+ if (time <= 0 || time > CBT_BUILD_TIME_MAX) {
+ log_warn(LD_BUG, "Circuit build time is too large (%u)."
+ "This is probably a bug.", time);
+ tor_fragile_assert();
+ return -1;
+ }
+
+ log_debug(LD_CIRC, "Adding circuit build time %u", time);
+
+ cbt->circuit_build_times[cbt->build_times_idx] = time;
+ cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE;
+ if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
+ cbt->total_build_times++;
+
+ if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) {
+ /* Save state every n circuit builds */
+ if (!unit_tests && !get_options()->AvoidDiskWrites)
+ or_state_mark_dirty(get_or_state(), 0);
+ }
+
+ return 0;
+}
+
+/**
+ * Return maximum circuit build time
+ */
+static build_time_t
+circuit_build_times_max(circuit_build_times_t *cbt)
+{
+ int i = 0;
+ build_time_t max_build_time = 0;
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] > max_build_time
+ && cbt->circuit_build_times[i] != CBT_BUILD_ABANDONED)
+ max_build_time = cbt->circuit_build_times[i];
+ }
+ return max_build_time;
+}
+
+#if 0
+/** Return minimum circuit build time */
+build_time_t
+circuit_build_times_min(circuit_build_times_t *cbt)
+{
+ int i = 0;
+ build_time_t min_build_time = CBT_BUILD_TIME_MAX;
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */
+ cbt->circuit_build_times[i] < min_build_time)
+ min_build_time = cbt->circuit_build_times[i];
+ }
+ if (min_build_time == CBT_BUILD_TIME_MAX) {
+ log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!");
+ }
+ return min_build_time;
+}
+#endif
+
+/**
+ * Calculate and return a histogram for the set of build times.
+ *
+ * Returns an allocated array of histrogram bins representing
+ * the frequency of index*CBT_BIN_WIDTH millisecond
+ * build times. Also outputs the number of bins in nbins.
+ *
+ * The return value must be freed by the caller.
+ */
+static uint32_t *
+circuit_build_times_create_histogram(circuit_build_times_t *cbt,
+ build_time_t *nbins)
+{
+ uint32_t *histogram;
+ build_time_t max_build_time = circuit_build_times_max(cbt);
+ int i, c;
+
+ *nbins = 1 + (max_build_time / CBT_BIN_WIDTH);
+ histogram = tor_malloc_zero(*nbins * sizeof(build_time_t));
+
+ // calculate histogram
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] == 0
+ || cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED)
+ continue; /* 0 <-> uninitialized */
+
+ c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH);
+ histogram[c]++;
+ }
+
+ return histogram;
+}
+
+/**
+ * Return the Pareto start-of-curve parameter Xm.
+ *
+ * Because we are not a true Pareto curve, we compute this as the
+ * weighted average of the N most frequent build time bins. N is either
+ * 1 if we don't have enough circuit build time data collected, or
+ * determined by the consensus parameter cbtnummodes (default 3).
+ */
+static build_time_t
+circuit_build_times_get_xm(circuit_build_times_t *cbt)
+{
+ build_time_t i, nbins;
+ build_time_t *nth_max_bin;
+ int32_t bin_counts=0;
+ build_time_t ret = 0;
+ uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins);
+ int n=0;
+ int num_modes = circuit_build_times_default_num_xm_modes();
+
+ tor_assert(nbins > 0);
+ tor_assert(num_modes > 0);
+
+ // Only use one mode if < 1000 buildtimes. Not enough data
+ // for multiple.
+ if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
+ num_modes = 1;
+
+ nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t));
+
+ /* Determine the N most common build times */
+ for (i = 0; i < nbins; i++) {
+ if (histogram[i] >= histogram[nth_max_bin[0]]) {
+ nth_max_bin[0] = i;
+ }
+
+ for (n = 1; n < num_modes; n++) {
+ if (histogram[i] >= histogram[nth_max_bin[n]] &&
+ (!histogram[nth_max_bin[n-1]]
+ || histogram[i] < histogram[nth_max_bin[n-1]])) {
+ nth_max_bin[n] = i;
+ }
+ }
+ }
+
+ for (n = 0; n < num_modes; n++) {
+ bin_counts += histogram[nth_max_bin[n]];
+ ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]];
+ log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]),
+ histogram[nth_max_bin[n]]);
+ }
+
+ /* The following assert is safe, because we don't get called when we
+ * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */
+ tor_assert(bin_counts > 0);
+
+ ret /= bin_counts;
+ tor_free(histogram);
+ tor_free(nth_max_bin);
+
+ return ret;
+}
+
+/**
+ * Output a histogram of current circuit build times to
+ * the or_state_t state structure.
+ */
+void
+circuit_build_times_update_state(circuit_build_times_t *cbt,
+ or_state_t *state)
+{
+ uint32_t *histogram;
+ build_time_t i = 0;
+ build_time_t nbins = 0;
+ config_line_t **next, *line;
+
+ histogram = circuit_build_times_create_histogram(cbt, &nbins);
+ // write to state
+ config_free_lines(state->BuildtimeHistogram);
+ next = &state->BuildtimeHistogram;
+ *next = NULL;
+
+ state->TotalBuildTimes = cbt->total_build_times;
+ state->CircuitBuildAbandonedCount = 0;
+
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED)
+ state->CircuitBuildAbandonedCount++;
+ }
+
+ for (i = 0; i < nbins; i++) {
+ // compress the histogram by skipping the blanks
+ if (histogram[i] == 0) continue;
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("CircuitBuildTimeBin");
+ tor_asprintf(&line->value, "%d %d",
+ CBT_BIN_TO_MS(i), histogram[i]);
+ next = &(line->next);
+ }
+
+ if (!unit_tests) {
+ if (!get_options()->AvoidDiskWrites)
+ or_state_mark_dirty(get_or_state(), 0);
+ }
+
+ tor_free(histogram);
+}
+
+/**
+ * Shuffle the build times array.
+ *
+ * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ */
+static void
+circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
+ build_time_t *raw_times,
+ uint32_t num_times)
+{
+ uint32_t n = num_times;
+ if (num_times > CBT_NCIRCUITS_TO_OBSERVE) {
+ log_notice(LD_CIRC, "The number of circuit times that this Tor version "
+ "uses to calculate build times is less than the number stored "
+ "in your state file. Decreasing the circuit time history from "
+ "%lu to %d.", (unsigned long)num_times,
+ CBT_NCIRCUITS_TO_OBSERVE);
+ }
+
+ if (n > INT_MAX-1) {
+ log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build "
+ "observations in your state file. That's far too many; probably "
+ "there's a bug here.", (unsigned long)n);
+ n = INT_MAX-1;
+ }
+
+ /* This code can only be run on a compact array */
+ while (n-- > 1) {
+ int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */
+ build_time_t tmp = raw_times[k];
+ raw_times[k] = raw_times[n];
+ raw_times[n] = tmp;
+ }
+
+ /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE
+ * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */
+ for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) {
+ circuit_build_times_add_time(cbt, raw_times[n]);
+ }
+}
+
+/**
+ * Filter old synthetic timeouts that were created before the
+ * new right-censored Pareto calculation was deployed.
+ *
+ * Once all clients before 0.2.1.13-alpha are gone, this code
+ * will be unused.
+ */
+static int
+circuit_build_times_filter_timeouts(circuit_build_times_t *cbt)
+{
+ int num_filtered=0, i=0;
+ double timeout_rate = 0;
+ build_time_t max_timeout = 0;
+
+ timeout_rate = circuit_build_times_timeout_rate(cbt);
+ max_timeout = (build_time_t)cbt->close_ms;
+
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] > max_timeout) {
+ build_time_t replaced = cbt->circuit_build_times[i];
+ num_filtered++;
+ cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED;
+
+ log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced,
+ cbt->circuit_build_times[i]);
+ }
+ }
+
+ log_info(LD_CIRC,
+ "We had %d timeouts out of %d build times, "
+ "and filtered %d above the max of %u",
+ (int)(cbt->total_build_times*timeout_rate),
+ cbt->total_build_times, num_filtered, max_timeout);
+
+ return num_filtered;
+}
+
+/**
+ * Load histogram from <b>state</b>, shuffling the resulting array
+ * after we do so. Use this result to estimate parameters and
+ * calculate the timeout.
+ *
+ * Return -1 on error.
+ */
+int
+circuit_build_times_parse_state(circuit_build_times_t *cbt,
+ or_state_t *state)
+{
+ int tot_values = 0;
+ uint32_t loaded_cnt = 0, N = 0;
+ config_line_t *line;
+ unsigned int i;
+ build_time_t *loaded_times;
+ int err = 0;
+ circuit_build_times_init(cbt);
+
+ if (circuit_build_times_disabled()) {
+ return 0;
+ }
+
+ /* build_time_t 0 means uninitialized */
+ loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes);
+
+ for (line = state->BuildtimeHistogram; line; line = line->next) {
+ smartlist_t *args = smartlist_new();
+ smartlist_split_string(args, line->value, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ if (smartlist_len(args) < 2) {
+ log_warn(LD_GENERAL, "Unable to parse circuit build times: "
+ "Too few arguments to CircuitBuildTime");
+ err = 1;
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ break;
+ } else {
+ const char *ms_str = smartlist_get(args,0);
+ const char *count_str = smartlist_get(args,1);
+ uint32_t count, k;
+ build_time_t ms;
+ int ok;
+ ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0,
+ CBT_BUILD_TIME_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_GENERAL, "Unable to parse circuit build times: "
+ "Unparsable bin number");
+ err = 1;
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ break;
+ }
+ count = (uint32_t)tor_parse_ulong(count_str, 0, 0,
+ UINT32_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_GENERAL, "Unable to parse circuit build times: "
+ "Unparsable bin count");
+ err = 1;
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ break;
+ }
+
+ if (loaded_cnt+count+state->CircuitBuildAbandonedCount
+ > state->TotalBuildTimes) {
+ log_warn(LD_CIRC,
+ "Too many build times in state file. "
+ "Stopping short before %d",
+ loaded_cnt+count);
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ break;
+ }
+
+ for (k = 0; k < count; k++) {
+ loaded_times[loaded_cnt++] = ms;
+ }
+ N++;
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ }
+ }
+
+ log_info(LD_CIRC,
+ "Adding %d timeouts.", state->CircuitBuildAbandonedCount);
+ for (i=0; i < state->CircuitBuildAbandonedCount; i++) {
+ loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED;
+ }
+
+ if (loaded_cnt != state->TotalBuildTimes) {
+ log_warn(LD_CIRC,
+ "Corrupt state file? Build times count mismatch. "
+ "Read %d times, but file says %d", loaded_cnt,
+ state->TotalBuildTimes);
+ err = 1;
+ circuit_build_times_reset(cbt);
+ goto done;
+ }
+
+ circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt);
+
+ /* Verify that we didn't overwrite any indexes */
+ for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (!cbt->circuit_build_times[i])
+ break;
+ tot_values++;
+ }
+ log_info(LD_CIRC,
+ "Loaded %d/%d values from %d lines in circuit time histogram",
+ tot_values, cbt->total_build_times, N);
+
+ if (cbt->total_build_times != tot_values
+ || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) {
+ log_warn(LD_CIRC,
+ "Corrupt state file? Shuffled build times mismatch. "
+ "Read %d times, but file says %d", tot_values,
+ state->TotalBuildTimes);
+ err = 1;
+ circuit_build_times_reset(cbt);
+ goto done;
+ }
+
+ circuit_build_times_set_timeout(cbt);
+
+ if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) {
+ circuit_build_times_filter_timeouts(cbt);
+ }
+
+ done:
+ tor_free(loaded_times);
+ return err ? -1 : 0;
+}
+
+/**
+ * Estimates the Xm and Alpha parameters using
+ * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation
+ *
+ * The notable difference is that we use mode instead of min to estimate Xm.
+ * This is because our distribution is frechet-like. We claim this is
+ * an acceptable approximation because we are only concerned with the
+ * accuracy of the CDF of the tail.
+ */
+int
+circuit_build_times_update_alpha(circuit_build_times_t *cbt)
+{
+ build_time_t *x=cbt->circuit_build_times;
+ double a = 0;
+ int n=0,i=0,abandoned_count=0;
+ build_time_t max_time=0;
+
+ /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
+ /* We sort of cheat here and make our samples slightly more pareto-like
+ * and less frechet-like. */
+ cbt->Xm = circuit_build_times_get_xm(cbt);
+
+ tor_assert(cbt->Xm > 0);
+
+ for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (!x[i]) {
+ continue;
+ }
+
+ if (x[i] < cbt->Xm) {
+ a += tor_mathlog(cbt->Xm);
+ } else if (x[i] == CBT_BUILD_ABANDONED) {
+ abandoned_count++;
+ } else {
+ a += tor_mathlog(x[i]);
+ if (x[i] > max_time)
+ max_time = x[i];
+ }
+ n++;
+ }
+
+ /*
+ * We are erring and asserting here because this can only happen
+ * in codepaths other than startup. The startup state parsing code
+ * performs this same check, and resets state if it hits it. If we
+ * hit it at runtime, something serious has gone wrong.
+ */
+ if (n!=cbt->total_build_times) {
+ log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n,
+ cbt->total_build_times);
+ }
+ tor_assert(n==cbt->total_build_times);
+
+ if (max_time <= 0) {
+ /* This can happen if Xm is actually the *maximum* value in the set.
+ * It can also happen if we've abandoned every single circuit somehow.
+ * In either case, tell the caller not to compute a new build timeout. */
+ log_warn(LD_BUG,
+ "Could not determine largest build time (%d). "
+ "Xm is %dms and we've abandoned %d out of %d circuits.", max_time,
+ cbt->Xm, abandoned_count, n);
+ return 0;
+ }
+
+ a += abandoned_count*tor_mathlog(max_time);
+
+ a -= n*tor_mathlog(cbt->Xm);
+ // Estimator comes from Eq #4 in:
+ // "Bayesian estimation based on trimmed samples from Pareto populations"
+ // by Arturo J. Fernández. We are right-censored only.
+ a = (n-abandoned_count)/a;
+
+ cbt->alpha = a;
+
+ return 1;
+}
+
+/**
+ * This is the Pareto Quantile Function. It calculates the point x
+ * in the distribution such that F(x) = quantile (ie quantile*100%
+ * of the mass of the density function is below x on the curve).
+ *
+ * We use it to calculate the timeout and also to generate synthetic
+ * values of time for circuits that timeout before completion.
+ *
+ * See http://en.wikipedia.org/wiki/Quantile_function,
+ * http://en.wikipedia.org/wiki/Inverse_transform_sampling and
+ * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_
+ * random_sample_from_Pareto_distribution
+ * That's right. I'll cite wikipedia all day long.
+ *
+ * Return value is in milliseconds.
+ */
+double
+circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
+ double quantile)
+{
+ double ret;
+ tor_assert(quantile >= 0);
+ tor_assert(1.0-quantile > 0);
+ tor_assert(cbt->Xm > 0);
+
+ ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha);
+ if (ret > INT32_MAX) {
+ ret = INT32_MAX;
+ }
+ tor_assert(ret > 0);
+ return ret;
+}
+
+/** Pareto CDF */
+double
+circuit_build_times_cdf(circuit_build_times_t *cbt, double x)
+{
+ double ret;
+ tor_assert(cbt->Xm > 0);
+ ret = 1.0-pow(cbt->Xm/x,cbt->alpha);
+ tor_assert(0 <= ret && ret <= 1.0);
+ return ret;
+}
+
+/**
+ * Generate a synthetic time using our distribution parameters.
+ *
+ * The return value will be within the [q_lo, q_hi) quantile points
+ * on the CDF.
+ */
+build_time_t
+circuit_build_times_generate_sample(circuit_build_times_t *cbt,
+ double q_lo, double q_hi)
+{
+ double randval = crypto_rand_double();
+ build_time_t ret;
+ double u;
+
+ /* Generate between [q_lo, q_hi) */
+ /*XXXX This is what nextafter is supposed to be for; we should use it on the
+ * platforms that support it. */
+ q_hi -= 1.0/(INT32_MAX);
+
+ tor_assert(q_lo >= 0);
+ tor_assert(q_hi < 1);
+ tor_assert(q_lo < q_hi);
+
+ u = q_lo + (q_hi-q_lo)*randval;
+
+ tor_assert(0 <= u && u < 1.0);
+ /* circuit_build_times_calculate_timeout returns <= INT32_MAX */
+ ret = (build_time_t)
+ tor_lround(circuit_build_times_calculate_timeout(cbt, u));
+ tor_assert(ret > 0);
+ return ret;
+}
+
+/**
+ * Estimate an initial alpha parameter by solving the quantile
+ * function with a quantile point and a specific timeout value.
+ */
+void
+circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
+ double quantile, double timeout_ms)
+{
+ // Q(u) = Xm/((1-u)^(1/a))
+ // Q(0.8) = Xm/((1-0.8))^(1/a)) = CircBuildTimeout
+ // CircBuildTimeout = Xm/((1-0.8))^(1/a))
+ // CircBuildTimeout = Xm*((1-0.8))^(-1/a))
+ // ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a)
+ // -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a
+ tor_assert(quantile >= 0);
+ tor_assert(cbt->Xm > 0);
+ cbt->alpha = tor_mathlog(1.0-quantile)/
+ (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms));
+ tor_assert(cbt->alpha > 0);
+}
+
+/**
+ * Returns true if we need circuits to be built
+ */
+int
+circuit_build_times_needs_circuits(circuit_build_times_t *cbt)
+{
+ /* Return true if < MIN_CIRCUITS_TO_OBSERVE */
+ return !circuit_build_times_enough_to_compute(cbt);
+}
+
+/**
+ * Returns true if we should build a timeout test circuit
+ * right now.
+ */
+int
+circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt)
+{
+ return circuit_build_times_needs_circuits(cbt) &&
+ approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency();
+}
+
+/**
+ * Called to indicate that the network showed some signs of liveness,
+ * i.e. we received a cell.
+ *
+ * This is used by circuit_build_times_network_check_live() to decide
+ * if we should record the circuit build timeout or not.
+ *
+ * This function is called every time we receive a cell. Avoid
+ * syscalls, events, and other high-intensity work.
+ */
+void
+circuit_build_times_network_is_live(circuit_build_times_t *cbt)
+{
+ time_t now = approx_time();
+ if (cbt->liveness.nonlive_timeouts > 0) {
+ log_notice(LD_CIRC,
+ "Tor now sees network activity. Restoring circuit build "
+ "timeout recording. Network was down for %d seconds "
+ "during %d circuit attempts.",
+ (int)(now - cbt->liveness.network_last_live),
+ cbt->liveness.nonlive_timeouts);
+ }
+ cbt->liveness.network_last_live = now;
+ cbt->liveness.nonlive_timeouts = 0;
+}
+
+/**
+ * Called to indicate that we completed a circuit. Because this circuit
+ * succeeded, it doesn't count as a timeout-after-the-first-hop.
+ *
+ * This is used by circuit_build_times_network_check_changed() to determine
+ * if we had too many recent timeouts and need to reset our learned timeout
+ * to something higher.
+ */
+void
+circuit_build_times_network_circ_success(circuit_build_times_t *cbt)
+{
+ /* Check for NULLness because we might not be using adaptive timeouts */
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]
+ = 0;
+ cbt->liveness.after_firsthop_idx++;
+ cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
+ }
+}
+
+/**
+ * A circuit just timed out. If it failed after the first hop, record it
+ * in our history for later deciding if the network speed has changed.
+ *
+ * This is used by circuit_build_times_network_check_changed() to determine
+ * if we had too many recent timeouts and need to reset our learned timeout
+ * to something higher.
+ */
+static void
+circuit_build_times_network_timeout(circuit_build_times_t *cbt,
+ int did_onehop)
+{
+ /* Check for NULLness because we might not be using adaptive timeouts */
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ if (did_onehop) {
+ cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]
+ = 1;
+ cbt->liveness.after_firsthop_idx++;
+ cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
+ }
+ }
+}
+
+/**
+ * A circuit was just forcibly closed. If there has been no recent network
+ * activity at all, but this circuit was launched back when we thought the
+ * network was live, increment the number of "nonlive" circuit timeouts.
+ *
+ * This is used by circuit_build_times_network_check_live() to decide
+ * if we should record the circuit build timeout or not.
+ */
+static void
+circuit_build_times_network_close(circuit_build_times_t *cbt,
+ int did_onehop, time_t start_time)
+{
+ time_t now = time(NULL);
+ /*
+ * Check if this is a timeout that was for a circuit that spent its
+ * entire existence during a time where we have had no network activity.
+ */
+ if (cbt->liveness.network_last_live < start_time) {
+ if (did_onehop) {
+ char last_live_buf[ISO_TIME_LEN+1];
+ char start_time_buf[ISO_TIME_LEN+1];
+ char now_buf[ISO_TIME_LEN+1];
+ format_local_iso_time(last_live_buf, cbt->liveness.network_last_live);
+ format_local_iso_time(start_time_buf, start_time);
+ format_local_iso_time(now_buf, now);
+ log_warn(LD_BUG,
+ "Circuit somehow completed a hop while the network was "
+ "not live. Network was last live at %s, but circuit launched "
+ "at %s. It's now %s.", last_live_buf, start_time_buf,
+ now_buf);
+ }
+ cbt->liveness.nonlive_timeouts++;
+ if (cbt->liveness.nonlive_timeouts == 1) {
+ log_notice(LD_CIRC,
+ "Tor has not observed any network activity for the past %d "
+ "seconds. Disabling circuit build timeout recording.",
+ (int)(now - cbt->liveness.network_last_live));
+ } else {
+ log_info(LD_CIRC,
+ "Got non-live timeout. Current count is: %d",
+ cbt->liveness.nonlive_timeouts);
+ }
+ }
+}
+
+/**
+ * When the network is not live, we do not record circuit build times.
+ *
+ * The network is considered not live if there has been at least one
+ * circuit build that began and ended (had its close_ms measurement
+ * period expire) since we last received a cell.
+ *
+ * Also has the side effect of rewinding the circuit time history
+ * in the case of recent liveness changes.
+ */
+int
+circuit_build_times_network_check_live(circuit_build_times_t *cbt)
+{
+ if (cbt->liveness.nonlive_timeouts > 0) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Returns true if we have seen more than MAX_RECENT_TIMEOUT_COUNT of
+ * the past RECENT_CIRCUITS time out after the first hop. Used to detect
+ * if the network connection has changed significantly, and if so,
+ * resets our circuit build timeout to the default.
+ *
+ * Also resets the entire timeout history in this case and causes us
+ * to restart the process of building test circuits and estimating a
+ * new timeout.
+ */
+int
+circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
+{
+ int total_build_times = cbt->total_build_times;
+ int timeout_count=0;
+ int i;
+
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ /* how many of our recent circuits made it to the first hop but then
+ * timed out? */
+ for (i = 0; i < cbt->liveness.num_recent_circs; i++) {
+ timeout_count += cbt->liveness.timeouts_after_firsthop[i];
+ }
+ }
+
+ /* If 80% of our recent circuits are timing out after the first hop,
+ * we need to re-estimate a new initial alpha and timeout. */
+ if (timeout_count < circuit_build_times_max_timeouts()) {
+ return 0;
+ }
+
+ circuit_build_times_reset(cbt);
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ memset(cbt->liveness.timeouts_after_firsthop, 0,
+ sizeof(*cbt->liveness.timeouts_after_firsthop)*
+ cbt->liveness.num_recent_circs);
+ }
+ cbt->liveness.after_firsthop_idx = 0;
+
+ /* Check to see if this has happened before. If so, double the timeout
+ * to give people on abysmally bad network connections a shot at access */
+ if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) {
+ if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) {
+ log_warn(LD_CIRC, "Insanely large circuit build timeout value. "
+ "(timeout = %fmsec, close = %fmsec)",
+ cbt->timeout_ms, cbt->close_ms);
+ } else {
+ cbt->timeout_ms *= 2;
+ cbt->close_ms *= 2;
+ }
+ } else {
+ cbt->close_ms = cbt->timeout_ms
+ = circuit_build_times_get_initial_timeout();
+ }
+
+ control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
+
+ log_notice(LD_CIRC,
+ "Your network connection speed appears to have changed. Resetting "
+ "timeout to %lds after %d timeouts and %d buildtimes.",
+ tor_lround(cbt->timeout_ms/1000), timeout_count,
+ total_build_times);
+
+ return 1;
+}
+
+/**
+ * Count the number of timeouts in a set of cbt data.
+ */
+double
+circuit_build_times_timeout_rate(const circuit_build_times_t *cbt)
+{
+ int i=0,timeouts=0;
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] >= cbt->timeout_ms) {
+ timeouts++;
+ }
+ }
+
+ if (!cbt->total_build_times)
+ return 0;
+
+ return ((double)timeouts)/cbt->total_build_times;
+}
+
+/**
+ * Count the number of closed circuits in a set of cbt data.
+ */
+double
+circuit_build_times_close_rate(const circuit_build_times_t *cbt)
+{
+ int i=0,closed=0;
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) {
+ closed++;
+ }
+ }
+
+ if (!cbt->total_build_times)
+ return 0;
+
+ return ((double)closed)/cbt->total_build_times;
+}
+
+/**
+ * Store a timeout as a synthetic value.
+ *
+ * Returns true if the store was successful and we should possibly
+ * update our timeout estimate.
+ */
+int
+circuit_build_times_count_close(circuit_build_times_t *cbt,
+ int did_onehop,
+ time_t start_time)
+{
+ if (circuit_build_times_disabled()) {
+ cbt->close_ms = cbt->timeout_ms
+ = circuit_build_times_get_initial_timeout();
+ return 0;
+ }
+
+ /* Record this force-close to help determine if the network is dead */
+ circuit_build_times_network_close(cbt, did_onehop, start_time);
+
+ /* Only count timeouts if network is live.. */
+ if (!circuit_build_times_network_check_live(cbt)) {
+ return 0;
+ }
+
+ circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED);
+ return 1;
+}
+
+/**
+ * Update timeout counts to determine if we need to expire
+ * our build time history due to excessive timeouts.
+ *
+ * We do not record any actual time values at this stage;
+ * we are only interested in recording the fact that a timeout
+ * happened. We record the time values via
+ * circuit_build_times_count_close() and circuit_build_times_add_time().
+ */
+void
+circuit_build_times_count_timeout(circuit_build_times_t *cbt,
+ int did_onehop)
+{
+ if (circuit_build_times_disabled()) {
+ cbt->close_ms = cbt->timeout_ms
+ = circuit_build_times_get_initial_timeout();
+ return;
+ }
+
+ /* Register the fact that a timeout just occurred. */
+ circuit_build_times_network_timeout(cbt, did_onehop);
+
+ /* If there are a ton of timeouts, we should reset
+ * the circuit build timeout. */
+ circuit_build_times_network_check_changed(cbt);
+}
+
+/**
+ * Estimate a new timeout based on history and set our timeout
+ * variable accordingly.
+ */
+static int
+circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt)
+{
+ build_time_t max_time;
+ if (!circuit_build_times_enough_to_compute(cbt))
+ return 0;
+
+ if (!circuit_build_times_update_alpha(cbt))
+ return 0;
+
+ cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt,
+ circuit_build_times_quantile_cutoff());
+
+ cbt->close_ms = circuit_build_times_calculate_timeout(cbt,
+ circuit_build_times_close_quantile());
+
+ max_time = circuit_build_times_max(cbt);
+
+ if (cbt->timeout_ms > max_time) {
+ log_info(LD_CIRC,
+ "Circuit build timeout of %dms is beyond the maximum build "
+ "time we have ever observed. Capping it to %dms.",
+ (int)cbt->timeout_ms, max_time);
+ cbt->timeout_ms = max_time;
+ }
+
+ if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) {
+ log_info(LD_CIRC,
+ "Circuit build measurement period of %dms is more than twice "
+ "the maximum build time we have ever observed. Capping it to "
+ "%dms.", (int)cbt->close_ms, 2*max_time);
+ cbt->close_ms = 2*max_time;
+ }
+
+ /* Sometimes really fast guard nodes give us such a steep curve
+ * that this ends up being not that much greater than timeout_ms.
+ * Make it be at least 1 min to handle this case. */
+ cbt->close_ms = MAX(cbt->close_ms, circuit_build_times_initial_timeout());
+
+ cbt->have_computed_timeout = 1;
+ return 1;
+}
+
+/**
+ * Exposed function to compute a new timeout. Dispatches events and
+ * also filters out extremely high timeout values.
+ */
+void
+circuit_build_times_set_timeout(circuit_build_times_t *cbt)
+{
+ long prev_timeout = tor_lround(cbt->timeout_ms/1000);
+ double timeout_rate;
+
+ /*
+ * Just return if we aren't using adaptive timeouts
+ */
+ if (circuit_build_times_disabled())
+ return;
+
+ if (!circuit_build_times_set_timeout_worker(cbt))
+ return;
+
+ if (cbt->timeout_ms < circuit_build_times_min_timeout()) {
+ log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms",
+ cbt->timeout_ms, circuit_build_times_min_timeout());
+ cbt->timeout_ms = circuit_build_times_min_timeout();
+ if (cbt->close_ms < cbt->timeout_ms) {
+ /* This shouldn't happen because of MAX() in timeout_worker above,
+ * but doing it just in case */
+ cbt->close_ms = circuit_build_times_initial_timeout();
+ }
+ }
+
+ control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED);
+
+ timeout_rate = circuit_build_times_timeout_rate(cbt);
+
+ if (prev_timeout > tor_lround(cbt->timeout_ms/1000)) {
+ log_info(LD_CIRC,
+ "Based on %d circuit times, it looks like we don't need to "
+ "wait so long for circuits to finish. We will now assume a "
+ "circuit is too slow to use after waiting %ld seconds.",
+ cbt->total_build_times,
+ tor_lround(cbt->timeout_ms/1000));
+ log_info(LD_CIRC,
+ "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
+ cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
+ timeout_rate);
+ } else if (prev_timeout < tor_lround(cbt->timeout_ms/1000)) {
+ log_info(LD_CIRC,
+ "Based on %d circuit times, it looks like we need to wait "
+ "longer for circuits to finish. We will now assume a "
+ "circuit is too slow to use after waiting %ld seconds.",
+ cbt->total_build_times,
+ tor_lround(cbt->timeout_ms/1000));
+ log_info(LD_CIRC,
+ "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
+ cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
+ timeout_rate);
+ } else {
+ log_info(LD_CIRC,
+ "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f,"
+ " r: %f) based on %d circuit times",
+ tor_lround(cbt->timeout_ms/1000),
+ cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate,
+ cbt->total_build_times);
+ }
+}
+/** Make a note that we're running unit tests (rather than running Tor
+ * itself), so we avoid clobbering our state file. */
+void
+circuitbuild_running_unit_tests(void)
+{
+ unit_tests = 1;
+}
+
diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h
new file mode 100644
index 0000000000..efe2799b0f
--- /dev/null
+++ b/src/or/circuitstats.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitstats.h
+ * \brief Header file for circuitstats.c
+ **/
+
+#ifndef TOR_CIRCUITSTATS_H
+#define TOR_CIRCUITSTATS_H
+
+extern circuit_build_times_t circ_times;
+
+int circuit_build_times_disabled(void);
+int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt);
+void circuit_build_times_update_state(circuit_build_times_t *cbt,
+ or_state_t *state);
+int circuit_build_times_parse_state(circuit_build_times_t *cbt,
+ or_state_t *state);
+void circuit_build_times_count_timeout(circuit_build_times_t *cbt,
+ int did_onehop);
+int circuit_build_times_count_close(circuit_build_times_t *cbt,
+ int did_onehop, time_t start_time);
+void circuit_build_times_set_timeout(circuit_build_times_t *cbt);
+int circuit_build_times_add_time(circuit_build_times_t *cbt,
+ build_time_t time);
+int circuit_build_times_needs_circuits(circuit_build_times_t *cbt);
+
+int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt);
+void circuit_build_times_init(circuit_build_times_t *cbt);
+void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
+void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
+ networkstatus_t *ns);
+double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
+double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
+
+#ifdef CIRCUITSTATS_PRIVATE
+double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
+ double quantile);
+build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt,
+ double q_lo, double q_hi);
+void circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
+ double quantile, double time_ms);
+int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
+double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
+void circuitbuild_running_unit_tests(void);
+void circuit_build_times_reset(circuit_build_times_t *cbt);
+
+/* Network liveness functions */
+int circuit_build_times_network_check_changed(circuit_build_times_t *cbt);
+#endif
+
+/* Network liveness functions */
+void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
+int circuit_build_times_network_check_live(circuit_build_times_t *cbt);
+void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
+
+/* DOCDOC circuit_build_times_get_bw_scale */
+int circuit_build_times_get_bw_scale(networkstatus_t *ns);
+
+#endif
+
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 20f124eb4e..e14f9d03ca 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -10,13 +10,17 @@
**/
#include "or.h"
+#include "addressmap.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitstats.h"
#include "circuituse.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "control.h"
+#include "entrynodes.h"
#include "nodelist.h"
#include "networkstatus.h"
#include "policies.h"
@@ -53,7 +57,7 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
tor_assert(conn);
tor_assert(conn->socks_request);
- if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_conn))
+ if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_chan))
return 0; /* ignore non-open circs */
if (circ->marked_for_close)
return 0;
@@ -172,6 +176,13 @@ circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
const uint8_t purpose = ENTRY_TO_CONN(conn)->purpose;
int a_bits, b_bits;
+ /* If one of the circuits was allowed to live due to relaxing its timeout,
+ * it is definitely worse (it's probably a much slower path). */
+ if (oa->relaxed_timeout && !ob->relaxed_timeout)
+ return 0; /* ob is better. It's not relaxed. */
+ if (!oa->relaxed_timeout && ob->relaxed_timeout)
+ return 1; /* oa is better. It's not relaxed. */
+
switch (purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
/* if it's used but less dirty it's best;
@@ -183,7 +194,7 @@ circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
return 1;
} else {
if (a->timestamp_dirty ||
- timercmp(&a->timestamp_created, &b->timestamp_created, >))
+ timercmp(&a->timestamp_began, &b->timestamp_began, >))
return 1;
if (ob->build_state->is_internal)
/* XXX023 what the heck is this internal thing doing here. I
@@ -275,7 +286,7 @@ circuit_get_best(const entry_connection_t *conn,
if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT &&
!must_be_open && circ->state != CIRCUIT_STATE_OPEN &&
- tv_mdiff(&now, &circ->timestamp_created) > circ_times.timeout_ms) {
+ tv_mdiff(&now, &circ->timestamp_began) > circ_times.timeout_ms) {
intro_going_on_but_too_old = 1;
continue;
}
@@ -361,8 +372,33 @@ circuit_expire_building(void)
const or_options_t *options = get_options();
struct timeval now;
cpath_build_state_t *build_state;
+ int any_opened_circs = 0;
tor_gettimeofday(&now);
+
+ /* Check to see if we have any opened circuits. If we don't,
+ * we want to be more lenient with timeouts, in case the
+ * user has relocated and/or changed network connections.
+ * See bug #3443. */
+ while (next_circ) {
+ if (!CIRCUIT_IS_ORIGIN(next_circ) || /* didn't originate here */
+ next_circ->marked_for_close) { /* don't mess with marked circs */
+ next_circ = next_circ->next;
+ continue;
+ }
+
+ if (TO_ORIGIN_CIRCUIT(next_circ)->has_opened &&
+ next_circ->state == CIRCUIT_STATE_OPEN &&
+ TO_ORIGIN_CIRCUIT(next_circ)->build_state &&
+ TO_ORIGIN_CIRCUIT(next_circ)->build_state->desired_path_len
+ == DEFAULT_ROUTE_LEN) {
+ any_opened_circs = 1;
+ break;
+ }
+ next_circ = next_circ->next;
+ }
+ next_circ = global_circuitlist;
+
#define SET_CUTOFF(target, msec) do { \
long ms = tor_lround(msec); \
struct timeval diff; \
@@ -387,8 +423,20 @@ circuit_expire_building(void)
victim = next_circ;
next_circ = next_circ->next;
if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */
- victim->marked_for_close) /* don't mess with marked circs */
+ victim->marked_for_close) /* don't mess with marked circs */
+ continue;
+
+ /* If we haven't yet started the first hop, it means we don't have
+ * any orconns available, and thus have not started counting time yet
+ * for this circuit. See circuit_deliver_create_cell() and uses of
+ * timestamp_began.
+ *
+ * Continue to wait in this case. The ORConn should timeout
+ * independently and kill us then.
+ */
+ if (TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_CLOSED) {
continue;
+ }
build_state = TO_ORIGIN_CIRCUIT(victim)->build_state;
if (build_state && build_state->onehop_tunnel)
@@ -406,9 +454,40 @@ circuit_expire_building(void)
if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)
cutoff = hs_extremely_old_cutoff;
- if (timercmp(&victim->timestamp_created, &cutoff, >))
+ if (timercmp(&victim->timestamp_began, &cutoff, >))
continue; /* it's still young, leave it alone */
+ if (!any_opened_circs) {
+ /* It's still young enough that we wouldn't close it, right? */
+ if (timercmp(&victim->timestamp_began, &close_cutoff, >)) {
+ if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
+ int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state
+ == CPATH_STATE_OPEN;
+ log_info(LD_CIRC,
+ "No circuits are opened. Relaxing timeout for "
+ "a circuit with channel state %s. %d guards are live.",
+ channel_state_to_string(victim->n_chan->state),
+ num_live_entry_guards());
+
+ /* We count the timeout here for CBT, because technically this
+ * was a timeout, and the timeout value needs to reset if we
+ * see enough of them. Note this means we also need to avoid
+ * double-counting below, too. */
+ circuit_build_times_count_timeout(&circ_times, first_hop_succeeded);
+ TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout = 1;
+ }
+ continue;
+ } else {
+ log_notice(LD_CIRC,
+ "No circuits are opened. Relaxed timeout for "
+ "a circuit with channel state %s to %ldms. "
+ "However, it appears the circuit has timed out anyway. "
+ "%d guards are live. ",
+ channel_state_to_string(victim->n_chan->state),
+ (long)circ_times.close_ms, num_live_entry_guards());
+ }
+ }
+
#if 0
/* some debug logs, to help track bugs */
if (victim->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING &&
@@ -485,9 +564,12 @@ circuit_expire_building(void)
/* Record this failure to check for too many timeouts
* in a row. This function does not record a time value yet
* (we do that later); it only counts the fact that we did
- * have a timeout. */
- circuit_build_times_count_timeout(&circ_times,
- first_hop_succeeded);
+ * have a timeout. We also want to avoid double-counting
+ * already "relaxed" circuits, which are counted above. */
+ if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
+ circuit_build_times_count_timeout(&circ_times,
+ first_hop_succeeded);
+ }
continue;
}
@@ -496,16 +578,16 @@ circuit_expire_building(void)
* it off at, we probably had a suspend event along this codepath,
* and we should discard the value.
*/
- if (timercmp(&victim->timestamp_created, &extremely_old_cutoff, <)) {
+ if (timercmp(&victim->timestamp_began, &extremely_old_cutoff, <)) {
log_notice(LD_CIRC,
"Extremely large value for circuit build timeout: %lds. "
"Assuming clock jump. Purpose %d (%s)",
- (long)(now.tv_sec - victim->timestamp_created.tv_sec),
+ (long)(now.tv_sec - victim->timestamp_began.tv_sec),
victim->purpose,
circuit_purpose_to_string(victim->purpose));
} else if (circuit_build_times_count_close(&circ_times,
first_hop_succeeded,
- victim->timestamp_created.tv_sec)) {
+ victim->timestamp_began.tv_sec)) {
circuit_build_times_set_timeout(&circ_times);
}
}
@@ -565,9 +647,9 @@ circuit_expire_building(void)
continue;
}
- if (victim->n_conn)
- log_info(LD_CIRC,"Abandoning circ %s:%d:%d (state %d:%s, purpose %d)",
- victim->n_conn->_base.address, victim->n_conn->_base.port,
+ if (victim->n_chan)
+ log_info(LD_CIRC,"Abandoning circ %s:%d (state %d:%s, purpose %d)",
+ channel_get_canonical_remote_descr(victim->n_chan),
victim->n_circ_id,
victim->state, circuit_state_to_string(victim->state),
victim->purpose);
@@ -787,7 +869,7 @@ circuit_build_needed_circs(time_t now)
circ = circuit_get_youngest_clean_open(CIRCUIT_PURPOSE_C_GENERAL);
if (get_options()->RunTesting &&
circ &&
- circ->timestamp_created.tv_sec + TESTING_CIRCUIT_INTERVAL < now) {
+ circ->timestamp_began.tv_sec + TESTING_CIRCUIT_INTERVAL < now) {
log_fn(LOG_INFO,"Creating a new testing circuit.");
circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, 0);
}
@@ -808,7 +890,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
tor_assert(circ);
tor_assert(conn);
- if (conn->_base.type == CONN_TYPE_AP) {
+ if (conn->base_.type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
entry_conn->may_use_optimistic_data = 0;
}
@@ -907,7 +989,7 @@ circuit_expire_old_circuits_clientside(void)
circ->purpose);
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) {
- if (timercmp(&circ->timestamp_created, &cutoff, <)) {
+ if (timercmp(&circ->timestamp_began, &cutoff, <)) {
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT ||
circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -917,7 +999,7 @@ circuit_expire_old_circuits_clientside(void)
circ->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) {
log_debug(LD_CIRC,
"Closing circuit that has been unused for %ld msec.",
- tv_mdiff(&circ->timestamp_created, &now));
+ tv_mdiff(&circ->timestamp_began, &now));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) {
/* Server-side rend joined circuits can end up really old, because
@@ -931,7 +1013,7 @@ circuit_expire_old_circuits_clientside(void)
"Ancient non-dirty circuit %d is still around after "
"%ld milliseconds. Purpose: %d (%s)",
TO_ORIGIN_CIRCUIT(circ)->global_identifier,
- tv_mdiff(&circ->timestamp_created, &now),
+ tv_mdiff(&circ->timestamp_began, &now),
circ->purpose,
circuit_purpose_to_string(circ->purpose));
TO_ORIGIN_CIRCUIT(circ)->is_ancient = 1;
@@ -977,13 +1059,13 @@ circuit_expire_old_circuits_serverside(time_t now)
/* If the circuit has been idle for too long, and there are no streams
* on it, and it ends here, and it used a create_fast, mark it for close.
*/
- if (or_circ->is_first_hop && !circ->n_conn &&
+ if (or_circ->is_first_hop && !circ->n_chan &&
!or_circ->n_streams && !or_circ->resolving_streams &&
- or_circ->p_conn &&
- or_circ->p_conn->timestamp_last_added_nonpadding <= cutoff) {
+ or_circ->p_chan &&
+ channel_when_last_xmit(or_circ->p_chan) <= cutoff) {
log_info(LD_CIRC, "Closing circ_id %d (empty %d secs ago)",
or_circ->p_circ_id,
- (int)(now - or_circ->p_conn->timestamp_last_added_nonpadding));
+ (int)(now - channel_when_last_xmit(or_circ->p_chan)));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
}
}
@@ -1125,7 +1207,7 @@ static int
circuit_try_clearing_isolation_state(origin_circuit_t *circ)
{
if (/* The circuit may have become non-open if it was cannibalized.*/
- circ->_base.state == CIRCUIT_STATE_OPEN &&
+ circ->base_.state == CIRCUIT_STATE_OPEN &&
/* If !isolation_values_set, there is nothing to clear. */
circ->isolation_values_set &&
/* It's not legal to clear a circuit's isolation info if it's ever had
@@ -1163,6 +1245,7 @@ circuit_try_attaching_streams(origin_circuit_t *circ)
void
circuit_build_failed(origin_circuit_t *circ)
{
+ channel_t *n_chan = NULL;
/* we should examine circ and see if it failed because of
* the last hop or an earlier hop. then use this info below.
*/
@@ -1179,11 +1262,12 @@ circuit_build_failed(origin_circuit_t *circ)
/* We failed at the first hop. If there's an OR connection
* to blame, blame it. Also, avoid this relay for a while, and
* fail any one-hop directory fetches destined for it. */
- const char *n_conn_id = circ->cpath->extend_info->identity_digest;
+ const char *n_chan_id = circ->cpath->extend_info->identity_digest;
int already_marked = 0;
- if (circ->_base.n_conn) {
- or_connection_t *n_conn = circ->_base.n_conn;
- if (n_conn->is_bad_for_new_circs) {
+ if (circ->base_.n_chan) {
+ n_chan = circ->base_.n_chan;
+
+ if (n_chan->is_bad_for_new_circs) {
/* We only want to blame this router when a fresh healthy
* connection fails. So don't mark this router as newly failed,
* since maybe this was just an old circuit attempt that's
@@ -1195,22 +1279,22 @@ circuit_build_failed(origin_circuit_t *circ)
}
log_info(LD_OR,
"Our circuit failed to get a response from the first hop "
- "(%s:%d). I'm going to try to rotate to a better connection.",
- n_conn->_base.address, n_conn->_base.port);
- n_conn->is_bad_for_new_circs = 1;
+ "(%s). I'm going to try to rotate to a better connection.",
+ channel_get_canonical_remote_descr(n_chan));
+ n_chan->is_bad_for_new_circs = 1;
} else {
log_info(LD_OR,
"Our circuit died before the first hop with no connection");
}
- if (n_conn_id && !already_marked) {
- entry_guard_register_connect_status(n_conn_id, 0, 1, time(NULL));
+ if (n_chan_id && !already_marked) {
+ entry_guard_register_connect_status(n_chan_id, 0, 1, time(NULL));
/* if there are any one-hop streams waiting on this circuit, fail
* them now so they can retry elsewhere. */
- connection_ap_fail_onehop(n_conn_id, circ->build_state);
+ connection_ap_fail_onehop(n_chan_id, circ->build_state);
}
}
- switch (circ->_base.purpose) {
+ switch (circ->base_.purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
/* If we never built the circuit, note it as a failure. */
circuit_increment_failure_count();
@@ -1225,7 +1309,7 @@ circuit_build_failed(origin_circuit_t *circ)
break;
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
/* at Bob, waiting for introductions */
- if (circ->_base.state != CIRCUIT_STATE_OPEN) {
+ if (circ->base_.state != CIRCUIT_STATE_OPEN) {
circuit_increment_failure_count();
}
/* no need to care here, because bob will rebuild intro
@@ -1309,21 +1393,25 @@ circuit_launch_by_extend_info(uint8_t purpose,
* internal circs rather than exit circs? -RD */
circ = circuit_find_to_cannibalize(purpose, extend_info, flags);
if (circ) {
- uint8_t old_purpose = circ->_base.purpose;
- struct timeval old_timestamp_created;
+ uint8_t old_purpose = circ->base_.purpose;
+ struct timeval old_timestamp_began;
log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d (%s)",
build_state_get_exit_nickname(circ->build_state), purpose,
circuit_purpose_to_string(purpose));
circuit_change_purpose(TO_CIRCUIT(circ), purpose);
- /* reset the birth date of this circ, else expire_building
+ /* Reset the start date of this circ, else expire_building
* will see it and think it's been trying to build since it
- * began. */
- tor_gettimeofday(&circ->_base.timestamp_created);
+ * began.
+ *
+ * Technically, the code should reset this when the
+ * create cell is finally sent, but we're close enough
+ * here. */
+ tor_gettimeofday(&circ->base_.timestamp_began);
control_event_circuit_cannibalized(circ, old_purpose,
- &old_timestamp_created);
+ &old_timestamp_began);
switch (purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
@@ -1513,8 +1601,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if ((m = rate_limit_log(&delay_limit, approx_time()))) {
log_notice(LD_APP, "We'd like to launch a circuit to handle a "
"connection, but we already have %d general-purpose client "
- "circuits pending. Waiting until some finish.",
- n_pending);
+ "circuits pending. Waiting until some finish.%s",
+ n_pending, m);
tor_free(m);
}
return 0;
@@ -1570,7 +1658,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
escaped_safe_str_client(conn->socks_request->address));
return -1;
}
- extend_info = extend_info_alloc(conn->chosen_exit_name+1,
+ extend_info = extend_info_new(conn->chosen_exit_name+1,
digest, NULL, &addr,
conn->socks_request->port);
} else {
@@ -1634,8 +1722,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if (circ) {
/* write the service_id into circ */
circ->rend_data = rend_data_dup(ENTRY_TO_EDGE_CONN(conn)->rend_data);
- if (circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
- circ->_base.state == CIRCUIT_STATE_OPEN)
+ if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
+ circ->base_.state == CIRCUIT_STATE_OPEN)
rend_client_rendcirc_has_opened(circ);
}
}
@@ -1698,7 +1786,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
/* add it into the linked list of streams on this circuit */
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
- circ->_base.n_circ_id);
+ circ->base_.n_circ_id);
/* reset it, so we can measure circ timeouts */
ENTRY_TO_CONN(apconn)->timestamp_lastread = time(NULL);
ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams;
@@ -1734,7 +1822,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
exitnode->rs) {
/* Okay; we know what exit node this is. */
if (optimistic_data_enabled() &&
- circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL &&
+ circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL &&
exitnode->rs->version_supports_optimistic_data)
apconn->may_use_optimistic_data = 1;
else
@@ -1820,12 +1908,12 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn,
base_conn->state == AP_CONN_STATE_CONTROLLER_WAIT);
tor_assert(conn->socks_request);
tor_assert(circ);
- tor_assert(circ->_base.state == CIRCUIT_STATE_OPEN);
+ tor_assert(circ->base_.state == CIRCUIT_STATE_OPEN);
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
- if (!circ->_base.timestamp_dirty)
- circ->_base.timestamp_dirty = time(NULL);
+ if (!circ->base_.timestamp_dirty)
+ circ->base_.timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, circ, cpath);
tor_assert(conn->socks_request);
@@ -1921,7 +2009,7 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
log_debug(LD_APP|LD_CIRC,
"Attaching apconn to circ %d (stream %d sec old).",
- circ->_base.n_circ_id, conn_age);
+ circ->base_.n_circ_id, conn_age);
/* print the circ's path, so people can figure out which circs are
* sucking. */
circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ);
@@ -1946,25 +2034,25 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
log_info(LD_REND,
"rend joined circ %d already here. attaching. "
"(stream %d sec old)",
- rendcirc->_base.n_circ_id, conn_age);
+ rendcirc->base_.n_circ_id, conn_age);
/* Mark rendezvous circuits as 'newly dirty' every time you use
* them, since the process of rebuilding a rendezvous circ is so
* expensive. There is a tradeoff between linkability and
* feasibility, at this point.
*/
- rendcirc->_base.timestamp_dirty = time(NULL);
+ rendcirc->base_.timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, rendcirc, NULL);
if (connection_ap_handshake_send_begin(conn) < 0)
return 0; /* already marked, let them fade away */
return 1;
}
- if (rendcirc && (rendcirc->_base.purpose ==
+ if (rendcirc && (rendcirc->base_.purpose ==
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) {
log_info(LD_REND,
"pending-join circ %d already here, with intro ack. "
"Stalling. (stream %d sec old)",
- rendcirc->_base.n_circ_id, conn_age);
+ rendcirc->base_.n_circ_id, conn_age);
return 0;
}
@@ -1979,8 +2067,8 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
tor_assert(introcirc);
log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). "
"Stalling. (stream %d sec old)",
- introcirc->_base.n_circ_id,
- rendcirc ? rendcirc->_base.n_circ_id : 0,
+ introcirc->base_.n_circ_id,
+ rendcirc ? rendcirc->base_.n_circ_id : 0,
conn_age);
/* abort parallel intro circs, if any */
for (c = global_circuitlist; c; c = c->next) {
@@ -2003,23 +2091,23 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
/* now rendcirc and introcirc are each either undefined or not finished */
if (rendcirc && introcirc &&
- rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
+ rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
log_info(LD_REND,
"ready rend circ %d already here (no intro-ack yet on "
"intro %d). (stream %d sec old)",
- rendcirc->_base.n_circ_id,
- introcirc->_base.n_circ_id, conn_age);
+ rendcirc->base_.n_circ_id,
+ introcirc->base_.n_circ_id, conn_age);
- tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- if (introcirc->_base.state == CIRCUIT_STATE_OPEN) {
+ tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ if (introcirc->base_.state == CIRCUIT_STATE_OPEN) {
log_info(LD_REND,"found open intro circ %d (rend %d); sending "
"introduction. (stream %d sec old)",
- introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id,
+ introcirc->base_.n_circ_id, rendcirc->base_.n_circ_id,
conn_age);
switch (rend_client_send_introduction(introcirc, rendcirc)) {
case 0: /* success */
- rendcirc->_base.timestamp_dirty = time(NULL);
- introcirc->_base.timestamp_dirty = time(NULL);
+ rendcirc->base_.timestamp_dirty = time(NULL);
+ introcirc->base_.timestamp_dirty = time(NULL);
assert_circuit_ok(TO_CIRCUIT(rendcirc));
assert_circuit_ok(TO_CIRCUIT(introcirc));
return 0;
@@ -2036,8 +2124,8 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. "
"Stalling conn. (%d sec old)",
- introcirc ? introcirc->_base.n_circ_id : 0,
- rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age);
+ introcirc ? introcirc->base_.n_circ_id : 0,
+ rendcirc ? rendcirc->base_.n_circ_id : 0, conn_age);
return 0;
}
}
diff --git a/src/or/circuituse.h b/src/or/circuituse.h
index be2bd7ec51..e8760c22d3 100644
--- a/src/or/circuituse.h
+++ b/src/or/circuituse.h
@@ -9,8 +9,8 @@
* \brief Header file for circuituse.c.
**/
-#ifndef _TOR_CIRCUITUSE_H
-#define _TOR_CIRCUITUSE_H
+#ifndef TOR_CIRCUITUSE_H
+#define TOR_CIRCUITUSE_H
void circuit_expire_building(void);
void circuit_remove_handled_ports(smartlist_t *needed_ports);
diff --git a/src/or/command.c b/src/or/command.c
index d935b5b18d..39eccdf82d 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -12,10 +12,13 @@
/* In-points to command.c:
*
* - command_process_cell(), called from
- * connection_or_process_cells_from_inbuf() in connection_or.c
+ * incoming cell handlers of channel_t instances;
+ * callbacks registered in command_setup_channel(),
+ * called when channels are created in circuitbuild.c
*/
#include "or.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "command.h"
@@ -31,8 +34,6 @@
#include "router.h"
#include "routerlist.h"
-/** How many CELL_PADDING cells have we received, ever? */
-uint64_t stats_n_padding_cells_processed = 0;
/** How many CELL_CREATE cells have we received, ever? */
uint64_t stats_n_create_cells_processed = 0;
/** How many CELL_CREATED cells have we received, ever? */
@@ -41,38 +42,16 @@ uint64_t stats_n_created_cells_processed = 0;
uint64_t stats_n_relay_cells_processed = 0;
/** How many CELL_DESTROY cells have we received, ever? */
uint64_t stats_n_destroy_cells_processed = 0;
-/** How many CELL_VERSIONS cells have we received, ever? */
-uint64_t stats_n_versions_cells_processed = 0;
-/** How many CELL_NETINFO cells have we received, ever? */
-uint64_t stats_n_netinfo_cells_processed = 0;
-/** How many CELL_VPADDING cells have we received, ever? */
-uint64_t stats_n_vpadding_cells_processed = 0;
-/** How many CELL_CERTS cells have we received, ever? */
-uint64_t stats_n_certs_cells_processed = 0;
-/** How many CELL_AUTH_CHALLENGE cells have we received, ever? */
-uint64_t stats_n_auth_challenge_cells_processed = 0;
-/** How many CELL_AUTHENTICATE cells have we received, ever? */
-uint64_t stats_n_authenticate_cells_processed = 0;
-/** How many CELL_AUTHORIZE cells have we received, ever? */
-uint64_t stats_n_authorize_cells_processed = 0;
+/* Handle an incoming channel */
+static void command_handle_incoming_channel(channel_listener_t *listener,
+ channel_t *chan);
/* These are the main functions for processing cells */
-static void command_process_create_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_created_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_relay_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_versions_cell(var_cell_t *cell,
- or_connection_t *conn);
-static void command_process_netinfo_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_certs_cell(var_cell_t *cell,
- or_connection_t *conn);
-static void command_process_auth_challenge_cell(var_cell_t *cell,
- or_connection_t *conn);
-static void command_process_authenticate_cell(var_cell_t *cell,
- or_connection_t *conn);
-static int enter_v3_handshake_with_cell(var_cell_t *cell,
- or_connection_t *conn);
+static void command_process_create_cell(cell_t *cell, channel_t *chan);
+static void command_process_created_cell(cell_t *cell, channel_t *chan);
+static void command_process_relay_cell(cell_t *cell, channel_t *chan);
+static void command_process_destroy_cell(cell_t *cell, channel_t *chan);
#ifdef KEEP_TIMING_STATS
/** This is a wrapper function around the actual function that processes the
@@ -80,15 +59,15 @@ static int enter_v3_handshake_with_cell(var_cell_t *cell,
* by the number of microseconds used by the call to <b>*func(cell, conn)</b>.
*/
static void
-command_time_process_cell(cell_t *cell, or_connection_t *conn, int *time,
- void (*func)(cell_t *, or_connection_t *))
+command_time_process_cell(cell_t *cell, channel_t *chan, int *time,
+ void (*func)(cell_t *, channel_t *))
{
struct timeval start, end;
long time_passed;
tor_gettimeofday(&start);
- (*func)(cell, conn);
+ (*func)(cell, chan);
tor_gettimeofday(&end);
time_passed = tv_udiff(&start, &end) ;
@@ -104,15 +83,14 @@ command_time_process_cell(cell_t *cell, or_connection_t *conn, int *time,
}
#endif
-/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal
+/** Process a <b>cell</b> that was just received on <b>chan</b>. Keep internal
* statistics about how many of each cell we've processed so far
* this second, and the total number of microseconds it took to
* process each type of cell.
*/
void
-command_process_cell(cell_t *cell, or_connection_t *conn)
+command_process_cell(channel_t *chan, cell_t *cell)
{
- int handshaking = (conn->_base.state != OR_CONN_STATE_OPEN);
#ifdef KEEP_TIMING_STATS
/* how many of each cell have we seen so far this second? needs better
* name. */
@@ -152,255 +130,115 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
#define PROCESS_CELL(tp, cl, cn) command_process_ ## tp ## _cell(cl, cn)
#endif
- if (conn->_base.marked_for_close)
- return;
-
- /* Reject all but VERSIONS and NETINFO when handshaking. */
- /* (VERSIONS should actually be impossible; it's variable-length.) */
- if (handshaking && cell->command != CELL_VERSIONS &&
- cell->command != CELL_NETINFO) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received unexpected cell command %d in state %s; closing the "
- "connection.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state));
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
-
- if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
- or_handshake_state_record_cell(conn->handshake_state, cell, 1);
-
switch (cell->command) {
- case CELL_PADDING:
- ++stats_n_padding_cells_processed;
- /* do nothing */
- break;
case CELL_CREATE:
case CELL_CREATE_FAST:
++stats_n_create_cells_processed;
- PROCESS_CELL(create, cell, conn);
+ PROCESS_CELL(create, cell, chan);
break;
case CELL_CREATED:
case CELL_CREATED_FAST:
++stats_n_created_cells_processed;
- PROCESS_CELL(created, cell, conn);
+ PROCESS_CELL(created, cell, chan);
break;
case CELL_RELAY:
case CELL_RELAY_EARLY:
++stats_n_relay_cells_processed;
- PROCESS_CELL(relay, cell, conn);
+ PROCESS_CELL(relay, cell, chan);
break;
case CELL_DESTROY:
++stats_n_destroy_cells_processed;
- PROCESS_CELL(destroy, cell, conn);
- break;
- case CELL_VERSIONS:
- tor_fragile_assert();
- break;
- case CELL_NETINFO:
- ++stats_n_netinfo_cells_processed;
- PROCESS_CELL(netinfo, cell, conn);
+ PROCESS_CELL(destroy, cell, chan);
break;
default:
log_fn(LOG_INFO, LD_PROTOCOL,
- "Cell of unknown type (%d) received. Dropping.", cell->command);
+ "Cell of unknown or unexpected type (%d) received. "
+ "Dropping.",
+ cell->command);
break;
}
}
-/** Return true if <b>command</b> is a cell command that's allowed to start a
- * V3 handshake. */
-static int
-command_allowed_before_handshake(uint8_t command)
-{
- switch (command) {
- case CELL_VERSIONS:
- case CELL_VPADDING:
- case CELL_AUTHORIZE:
- return 1;
- default:
- return 0;
- }
-}
-
-/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal
- * statistics about how many of each cell we've processed so far
- * this second, and the total number of microseconds it took to
- * process each type of cell.
+/** Process an incoming var_cell from a channel; in the current protocol all
+ * the var_cells are handshake-related and handled below the channel layer,
+ * so this just logs a warning and drops the cell.
*/
+
void
-command_process_var_cell(var_cell_t *cell, or_connection_t *conn)
+command_process_var_cell(channel_t *chan, var_cell_t *var_cell)
{
-#ifdef KEEP_TIMING_STATS
- /* how many of each cell have we seen so far this second? needs better
- * name. */
- static int num_versions=0, num_certs=0;
-
- time_t now = time(NULL);
-
- if (now > current_second) { /* the second has rolled over */
- /* print stats */
- log_info(LD_OR,
- "At end of second: %d versions (%d ms), %d certs (%d ms)",
- num_versions, versions_time/1000,
- num_certs, certs_time/1000);
-
- num_versions = num_certs = 0;
- versions_time = certs_time = 0;
+ tor_assert(chan);
+ tor_assert(var_cell);
- /* remember which second it is, for next time */
- current_second = now;
- }
-#endif
-
- if (conn->_base.marked_for_close)
- return;
-
- switch (conn->_base.state)
- {
- case OR_CONN_STATE_OR_HANDSHAKING_V2:
- if (cell->command != CELL_VERSIONS) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received a cell with command %d in state %s; "
- "closing the connection.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state));
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- break;
- case OR_CONN_STATE_TLS_HANDSHAKING:
- /* If we're using bufferevents, it's entirely possible for us to
- * notice "hey, data arrived!" before we notice "hey, the handshake
- * finished!" And we need to be accepting both at once to handle both
- * the v2 and v3 handshakes. */
-
- /* fall through */
- case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
- if (! command_allowed_before_handshake(cell->command)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received a cell with command %d in state %s; "
- "closing the connection.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state));
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else {
- if (enter_v3_handshake_with_cell(cell, conn)<0)
- return;
- }
- break;
- case OR_CONN_STATE_OR_HANDSHAKING_V3:
- if (cell->command != CELL_AUTHENTICATE)
- or_handshake_state_record_var_cell(conn->handshake_state, cell, 1);
- break; /* Everything is allowed */
- case OR_CONN_STATE_OPEN:
- if (conn->link_proto < 3) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received a variable-length cell with command %d in state %s "
- "with link protocol %d; ignoring it.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state),
- (int)conn->link_proto);
- return;
- }
- break;
- default:
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received var-length cell with command %d in unexpected state "
- "%s [%d]; ignoring it.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state),
- (int)conn->_base.state);
- return;
- }
-
- switch (cell->command) {
- case CELL_VERSIONS:
- ++stats_n_versions_cells_processed;
- PROCESS_CELL(versions, cell, conn);
- break;
- case CELL_VPADDING:
- ++stats_n_vpadding_cells_processed;
- /* Do nothing */
- break;
- case CELL_CERTS:
- ++stats_n_certs_cells_processed;
- PROCESS_CELL(certs, cell, conn);
- break;
- case CELL_AUTH_CHALLENGE:
- ++stats_n_auth_challenge_cells_processed;
- PROCESS_CELL(auth_challenge, cell, conn);
- break;
- case CELL_AUTHENTICATE:
- ++stats_n_authenticate_cells_processed;
- PROCESS_CELL(authenticate, cell, conn);
- break;
- case CELL_AUTHORIZE:
- ++stats_n_authorize_cells_processed;
- /* Ignored so far. */
- break;
- default:
- log_fn(LOG_INFO, LD_PROTOCOL,
- "Variable-length cell of unknown type (%d) received.",
- cell->command);
- break;
- }
+ log_info(LD_PROTOCOL,
+ "Received unexpected var_cell above the channel layer of type %d"
+ "; dropping it.",
+ var_cell->command);
}
-/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a
+/** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a
* new circuit with the p_circ_id specified in cell. Put the circuit in state
* onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
* picked up again when the cpuworker finishes decrypting it.
*/
static void
-command_process_create_cell(cell_t *cell, or_connection_t *conn)
+command_process_create_cell(cell_t *cell, channel_t *chan)
{
or_circuit_t *circ;
const or_options_t *options = get_options();
int id_is_high;
+ tor_assert(cell);
+ tor_assert(chan);
+
+ log_debug(LD_OR,
+ "Got a CREATE cell for circ_id %d on channel " U64_FORMAT
+ " (%p)",
+ cell->circ_id,
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+
if (we_are_hibernating()) {
log_info(LD_OR,
"Received create cell but we're shutting down. Sending back "
"destroy.");
- connection_or_send_destroy(cell->circ_id, conn,
+ channel_send_destroy(cell->circ_id, chan,
END_CIRC_REASON_HIBERNATING);
return;
}
if (!server_mode(options) ||
- (!public_server_mode(options) && conn->is_outgoing)) {
+ (!public_server_mode(options) && channel_is_outgoing(chan))) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received create cell (type %d) from %s:%d, but we're connected "
+ "Received create cell (type %d) from %s, but we're connected "
"to it as a client. "
"Sending back a destroy.",
- (int)cell->command, conn->_base.address, conn->_base.port);
- connection_or_send_destroy(cell->circ_id, conn,
- END_CIRC_REASON_TORPROTOCOL);
+ (int)cell->command, channel_get_canonical_remote_descr(chan));
+ channel_send_destroy(cell->circ_id, chan,
+ END_CIRC_REASON_TORPROTOCOL);
return;
}
/* If the high bit of the circuit ID is not as expected, close the
* circ. */
id_is_high = cell->circ_id & (1<<15);
- if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
- (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) {
+ if ((id_is_high &&
+ chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
+ (!id_is_high &&
+ chan->circ_id_type == CIRC_ID_TYPE_LOWER)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received create cell with unexpected circ_id %d. Closing.",
cell->circ_id);
- connection_or_send_destroy(cell->circ_id, conn,
- END_CIRC_REASON_TORPROTOCOL);
+ channel_send_destroy(cell->circ_id, chan,
+ END_CIRC_REASON_TORPROTOCOL);
return;
}
- if (circuit_id_in_use_on_orconn(cell->circ_id, conn)) {
- const node_t *node = node_get_by_id(conn->identity_digest);
+ if (circuit_id_in_use_on_channel(cell->circ_id, chan)) {
+ const node_t *node = node_get_by_id(chan->identity_digest);
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received CREATE cell (circID %d) for known circ. "
"Dropping (age %d).",
- cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created));
+ cell->circ_id, (int)(time(NULL) - channel_when_created(chan)));
if (node) {
char *p = esc_for_log(node_get_platform(node));
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -411,8 +249,8 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
return;
}
- circ = or_circuit_new(cell->circ_id, conn);
- circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+ circ = or_circuit_new(cell->circ_id, chan);
+ circ->base_.purpose = CIRCUIT_PURPOSE_OR;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
if (cell->command == CELL_CREATE) {
char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
@@ -420,14 +258,7 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
/* hand it off to the cpuworkers, and then return. */
if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) {
-#define WARN_HANDOFF_FAILURE_INTERVAL (6*60*60)
- static ratelim_t handoff_warning =
- RATELIM_INIT(WARN_HANDOFF_FAILURE_INTERVAL);
- char *m;
- if ((m = rate_limit_log(&handoff_warning, approx_time()))) {
- log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.%s",m);
- tor_free(m);
- }
+ log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return;
}
@@ -442,7 +273,7 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
/* Make sure we never try to use the OR connection on which we
* received this cell to satisfy an EXTEND request, */
- conn->is_connection_with_client = 1;
+ channel_mark_client(chan);
if (fast_server_handshake(cell->payload, (uint8_t*)reply,
(uint8_t*)keys, sizeof(keys))<0) {
@@ -458,7 +289,7 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
}
}
-/** Process a 'created' <b>cell</b> that just arrived from <b>conn</b>.
+/** Process a 'created' <b>cell</b> that just arrived from <b>chan</b>.
* Find the circuit
* that it's intended for. If we're not the origin of the circuit, package
* the 'created' cell in an 'extended' relay cell and pass it back. If we
@@ -467,11 +298,11 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
* extend to the next hop in the circuit if necessary.
*/
static void
-command_process_created_cell(cell_t *cell, or_connection_t *conn)
+command_process_created_cell(cell_t *cell, channel_t *chan)
{
circuit_t *circ;
- circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
+ circ = circuit_get_by_circid_channel(cell->circ_id, chan);
if (!circ) {
log_info(LD_OR,
@@ -518,17 +349,17 @@ command_process_created_cell(cell_t *cell, or_connection_t *conn)
* circuit_receive_relay_cell() for actual processing.
*/
static void
-command_process_relay_cell(cell_t *cell, or_connection_t *conn)
+command_process_relay_cell(cell_t *cell, channel_t *chan)
{
circuit_t *circ;
int reason, direction;
- circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
+ circ = circuit_get_by_circid_channel(cell->circ_id, chan);
if (!circ) {
log_debug(LD_OR,
- "unknown circuit %d on connection from %s:%d. Dropping.",
- cell->circ_id, conn->_base.address, conn->_base.port);
+ "unknown circuit %d on connection from %s. Dropping.",
+ cell->circ_id, channel_get_canonical_remote_descr(chan));
return;
}
@@ -541,7 +372,7 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn)
if (CIRCUIT_IS_ORIGIN(circ)) {
/* if we're a relay and treating connections with recent local
* traffic better, then this is one of them. */
- conn->client_used = time(NULL);
+ channel_timestamp_client(chan);
}
if (!CIRCUIT_IS_ORIGIN(circ) &&
@@ -562,10 +393,10 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn)
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
if (or_circ->remaining_relay_early_cells == 0) {
log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received too many RELAY_EARLY cells on circ %d from %s:%d."
+ "Received too many RELAY_EARLY cells on circ %d from %s."
" Closing circuit.",
- cell->circ_id, safe_str(conn->_base.address),
- conn->_base.port);
+ cell->circ_id,
+ safe_str(channel_get_canonical_remote_descr(chan)));
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
return;
}
@@ -582,7 +413,7 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn)
}
/** Process a 'destroy' <b>cell</b> that just arrived from
- * <b>conn</b>. Find the circ that it refers to (if any).
+ * <b>chan</b>. Find the circ that it refers to (if any).
*
* If the circ is in state
* onionskin_pending, then call onion_pending_remove() to remove it
@@ -595,15 +426,15 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn)
* and passes the destroy cell onward if necessary).
*/
static void
-command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
+command_process_destroy_cell(cell_t *cell, channel_t *chan)
{
circuit_t *circ;
int reason;
- circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
+ circ = circuit_get_by_circid_channel(cell->circ_id, chan);
if (!circ) {
- log_info(LD_OR,"unknown circuit %d on connection from %s:%d. Dropping.",
- cell->circ_id, conn->_base.address, conn->_base.port);
+ log_info(LD_OR,"unknown circuit %d on connection from %s. Dropping.",
+ cell->circ_id, channel_get_canonical_remote_descr(chan));
return;
}
log_debug(LD_OR,"Received for circID %d.",cell->circ_id);
@@ -613,10 +444,10 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
if (!CIRCUIT_IS_ORIGIN(circ) &&
cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
/* the destroy came from behind */
- circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL);
+ circuit_set_p_circid_chan(TO_OR_CIRCUIT(circ), 0, NULL);
circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE);
} else { /* the destroy came from ahead */
- circuit_set_n_circid_orconn(circ, 0, NULL);
+ circuit_set_n_circid_chan(circ, 0, NULL);
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE);
} else {
@@ -629,730 +460,43 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
}
}
-/** Called when we as a server receive an appropriate cell while waiting
- * either for a cell or a TLS handshake. Set the connection's state to
- * "handshaking_v3', initializes the or_handshake_state field as needed,
- * and add the cell to the hash of incoming cells.)
- *
- * Return 0 on success; return -1 and mark the connection on failure.
+/** Callback to handle a new channel; call command_setup_channel() to give
+ * it the right cell handlers.
*/
-static int
-enter_v3_handshake_with_cell(var_cell_t *cell, or_connection_t *conn)
-{
- const int started_here = connection_or_nonopen_was_started_here(conn);
-
- tor_assert(conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING ||
- conn->_base.state == OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
-
- if (started_here) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a cell while TLS-handshaking, not in "
- "OR_HANDSHAKING_V3, on a connection we originated.");
- }
- connection_or_block_renegotiation(conn);
- conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
- if (connection_init_or_handshake_state(conn, started_here) < 0) {
- connection_mark_for_close(TO_CONN(conn));
- return -1;
- }
- or_handshake_state_record_var_cell(conn->handshake_state, cell, 1);
- return 0;
-}
-
-/** Process a 'versions' cell. The current link protocol version must be 0
- * to indicate that no version has yet been negotiated. We compare the
- * versions in the cell to the list of versions we support, pick the
- * highest version we have in common, and continue the negotiation from
- * there.
- */
-static void
-command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
-{
- int highest_supported_version = 0;
- const uint8_t *cp, *end;
- const int started_here = connection_or_nonopen_was_started_here(conn);
- if (conn->link_proto != 0 ||
- (conn->handshake_state && conn->handshake_state->received_versions)) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a VERSIONS cell on a connection with its version "
- "already set to %d; dropping", (int) conn->link_proto);
- return;
- }
- switch (conn->_base.state)
- {
- case OR_CONN_STATE_OR_HANDSHAKING_V2:
- case OR_CONN_STATE_OR_HANDSHAKING_V3:
- break;
- case OR_CONN_STATE_TLS_HANDSHAKING:
- case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
- default:
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "VERSIONS cell while in unexpected state");
- return;
- }
-
- tor_assert(conn->handshake_state);
- end = cell->payload + cell->payload_len;
- for (cp = cell->payload; cp+1 < end; ++cp) {
- uint16_t v = ntohs(get_uint16(cp));
- if (is_or_protocol_version_known(v) && v > highest_supported_version)
- highest_supported_version = v;
- }
- if (!highest_supported_version) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Couldn't find a version in common between my version list and the "
- "list in the VERSIONS cell; closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else if (highest_supported_version == 1) {
- /* Negotiating version 1 makes no sense, since version 1 has no VERSIONS
- * cells. */
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Used version negotiation protocol to negotiate a v1 connection. "
- "That's crazily non-compliant. Closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else if (highest_supported_version < 3 &&
- conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Negotiated link protocol 2 or lower after doing a v3 TLS "
- "handshake. Closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else if (highest_supported_version != 2 &&
- conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V2) {
- /* XXXX This should eventually be a log_protocol_warn */
- log_fn(LOG_WARN, LD_OR,
- "Negotiated link with non-2 protocol after doing a v2 TLS "
- "handshake with %s. Closing connection.",
- fmt_addr(&conn->_base.addr));
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
-
- conn->link_proto = highest_supported_version;
- conn->handshake_state->received_versions = 1;
-
- if (conn->link_proto == 2) {
- log_info(LD_OR, "Negotiated version %d with %s:%d; sending NETINFO.",
- highest_supported_version,
- safe_str_client(conn->_base.address),
- conn->_base.port);
-
- if (connection_or_send_netinfo(conn) < 0) {
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- } else {
- const int send_versions = !started_here;
- /* If we want to authenticate, send a CERTS cell */
- const int send_certs = !started_here || public_server_mode(get_options());
- /* If we're a relay that got a connection, ask for authentication. */
- const int send_chall = !started_here && public_server_mode(get_options());
- /* If our certs cell will authenticate us, we can send a netinfo cell
- * right now. */
- const int send_netinfo = !started_here;
- const int send_any =
- send_versions || send_certs || send_chall || send_netinfo;
- tor_assert(conn->link_proto >= 3);
- log_info(LD_OR, "Negotiated version %d with %s:%d; %s%s%s%s%s",
- highest_supported_version,
- safe_str_client(conn->_base.address),
- conn->_base.port,
- send_any ? "Sending cells:" : "Waiting for CERTS cell",
- send_versions ? " VERSIONS" : "",
- send_certs ? " CERTS" : "",
- send_chall ? " AUTH_CHALLENGE" : "",
- send_netinfo ? " NETINFO" : "");
-
-#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
- if (1) {
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
-#endif
-
- if (send_versions) {
- if (connection_or_send_versions(conn, 1) < 0) {
- log_warn(LD_OR, "Couldn't send versions cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
- if (send_certs) {
- if (connection_or_send_certs_cell(conn) < 0) {
- log_warn(LD_OR, "Couldn't send certs cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
- if (send_chall) {
- if (connection_or_send_auth_challenge_cell(conn) < 0) {
- log_warn(LD_OR, "Couldn't send auth_challenge cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
- if (send_netinfo) {
- if (connection_or_send_netinfo(conn) < 0) {
- log_warn(LD_OR, "Couldn't send netinfo cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
- }
-}
-
-/** Process a 'netinfo' cell: read and act on its contents, and set the
- * connection state to "open". */
static void
-command_process_netinfo_cell(cell_t *cell, or_connection_t *conn)
+command_handle_incoming_channel(channel_listener_t *listener, channel_t *chan)
{
- time_t timestamp;
- uint8_t my_addr_type;
- uint8_t my_addr_len;
- const uint8_t *my_addr_ptr;
- const uint8_t *cp, *end;
- uint8_t n_other_addrs;
- time_t now = time(NULL);
+ tor_assert(listener);
+ tor_assert(chan);
- long apparent_skew = 0;
- uint32_t my_apparent_addr = 0;
-
- if (conn->link_proto < 2) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a NETINFO cell on %s connection; dropping.",
- conn->link_proto == 0 ? "non-versioned" : "a v1");
- return;
- }
- if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
- conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a NETINFO cell on non-handshaking connection; dropping.");
- return;
- }
- tor_assert(conn->handshake_state &&
- conn->handshake_state->received_versions);
-
- if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
- tor_assert(conn->link_proto >= 3);
- if (conn->handshake_state->started_here) {
- if (!conn->handshake_state->authenticated) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got a NETINFO cell from server, "
- "but no authentication. Closing the connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- } else {
- /* we're the server. If the client never authenticated, we have
- some housekeeping to do.*/
- if (!conn->handshake_state->authenticated) {
- tor_assert(tor_digest_is_zero(
- (const char*)conn->handshake_state->authenticated_peer_id));
- connection_or_set_circid_type(conn, NULL);
-
- connection_or_init_conn_from_address(conn,
- &conn->_base.addr,
- conn->_base.port,
- (const char*)conn->handshake_state->authenticated_peer_id,
- 0);
- }
- }
- }
-
- /* Decode the cell. */
- timestamp = ntohl(get_uint32(cell->payload));
- if (labs(now - conn->handshake_state->sent_versions_at) < 180) {
- apparent_skew = now - timestamp;
- }
-
- my_addr_type = (uint8_t) cell->payload[4];
- my_addr_len = (uint8_t) cell->payload[5];
- my_addr_ptr = (uint8_t*) cell->payload + 6;
- end = cell->payload + CELL_PAYLOAD_SIZE;
- cp = cell->payload + 6 + my_addr_len;
- if (cp >= end) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Addresses too long in netinfo cell; closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) {
- my_apparent_addr = ntohl(get_uint32(my_addr_ptr));
- }
-
- n_other_addrs = (uint8_t) *cp++;
- while (n_other_addrs && cp < end-2) {
- /* Consider all the other addresses; if any matches, this connection is
- * "canonical." */
- tor_addr_t addr;
- const uint8_t *next =
- decode_address_from_payload(&addr, cp, (int)(end-cp));
- if (next == NULL) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Bad address in netinfo cell; closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- if (tor_addr_eq(&addr, &conn->real_addr)) {
- conn->is_canonical = 1;
- break;
- }
- cp = next;
- --n_other_addrs;
- }
-
- /* Act on apparent skew. */
- /** Warn when we get a netinfo skew with at least this value. */
-#define NETINFO_NOTICE_SKEW 3600
- if (labs(apparent_skew) > NETINFO_NOTICE_SKEW &&
- router_get_by_id_digest(conn->identity_digest)) {
- char dbuf[64];
- int severity;
- /*XXXX be smarter about when everybody says we are skewed. */
- if (router_digest_is_trusted_dir(conn->identity_digest))
- severity = LOG_WARN;
- else
- severity = LOG_INFO;
- format_time_interval(dbuf, sizeof(dbuf), apparent_skew);
- log_fn(severity, LD_GENERAL, "Received NETINFO cell with skewed time from "
- "server at %s:%d. It seems that our clock is %s by %s, or "
- "that theirs is %s. Tor requires an accurate clock to work: "
- "please check your time and date settings.",
- conn->_base.address, (int)conn->_base.port,
- apparent_skew>0 ? "ahead" : "behind", dbuf,
- apparent_skew>0 ? "behind" : "ahead");
- if (severity == LOG_WARN) /* only tell the controller if an authority */
- control_event_general_status(LOG_WARN,
- "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d",
- apparent_skew,
- conn->_base.address, conn->_base.port);
- }
-
- /* XXX maybe act on my_apparent_addr, if the source is sufficiently
- * trustworthy. */
- (void)my_apparent_addr;
-
- if (connection_or_set_state_open(conn)<0) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got good NETINFO cell from %s:%d; but "
- "was unable to make the OR connection become open.",
- safe_str_client(conn->_base.address),
- conn->_base.port);
- connection_mark_for_close(TO_CONN(conn));
- } else {
- log_info(LD_OR, "Got good NETINFO cell from %s:%d; OR connection is now "
- "open, using protocol version %d. Its ID digest is %s",
- safe_str_client(conn->_base.address),
- conn->_base.port, (int)conn->link_proto,
- hex_str(conn->identity_digest, DIGEST_LEN));
- }
- assert_connection_ok(TO_CONN(conn),time(NULL));
+ command_setup_channel(chan);
}
-/** Process a CERTS cell from an OR connection.
- *
- * If the other side should not have sent us a CERTS cell, or the cell is
- * malformed, or it is supposed to authenticate the TLS key but it doesn't,
- * then mark the connection.
- *
- * If the cell has a good cert chain and we're doing a v3 handshake, then
- * store the certificates in or_handshake_state. If this is the client side
- * of the connection, we then authenticate the server or mark the connection.
- * If it's the server side, wait for an AUTHENTICATE cell.
+/** Given a channel, install the right handlers to process incoming
+ * cells on it.
*/
-static void
-command_process_certs_cell(var_cell_t *cell, or_connection_t *conn)
-{
-#define ERR(s) \
- do { \
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad CERTS cell from %s:%d: %s", \
- safe_str(conn->_base.address), conn->_base.port, (s)); \
- connection_mark_for_close(TO_CONN(conn)); \
- goto err; \
- } while (0)
-
- tor_cert_t *link_cert = NULL;
- tor_cert_t *id_cert = NULL;
- tor_cert_t *auth_cert = NULL;
-
- uint8_t *ptr;
- int n_certs, i;
- int send_netinfo = 0;
-
- if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
- ERR("We're not doing a v3 handshake!");
- if (conn->link_proto < 3)
- ERR("We're not using link protocol >= 3");
- if (conn->handshake_state->received_certs_cell)
- ERR("We already got one");
- if (conn->handshake_state->authenticated) {
- /* Should be unreachable, but let's make sure. */
- ERR("We're already authenticated!");
- }
- if (cell->payload_len < 1)
- ERR("It had no body");
- if (cell->circ_id)
- ERR("It had a nonzero circuit ID");
-
- n_certs = cell->payload[0];
- ptr = cell->payload + 1;
- for (i = 0; i < n_certs; ++i) {
- uint8_t cert_type;
- uint16_t cert_len;
- if (ptr + 3 > cell->payload + cell->payload_len) {
- goto truncated;
- }
- cert_type = *ptr;
- cert_len = ntohs(get_uint16(ptr+1));
- if (ptr + 3 + cert_len > cell->payload + cell->payload_len) {
- goto truncated;
- }
- if (cert_type == OR_CERT_TYPE_TLS_LINK ||
- cert_type == OR_CERT_TYPE_ID_1024 ||
- cert_type == OR_CERT_TYPE_AUTH_1024) {
- tor_cert_t *cert = tor_cert_decode(ptr + 3, cert_len);
- if (!cert) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received undecodable certificate in CERTS cell from %s:%d",
- safe_str(conn->_base.address), conn->_base.port);
- } else {
- if (cert_type == OR_CERT_TYPE_TLS_LINK) {
- if (link_cert) {
- tor_cert_free(cert);
- ERR("Too many TLS_LINK certificates");
- }
- link_cert = cert;
- } else if (cert_type == OR_CERT_TYPE_ID_1024) {
- if (id_cert) {
- tor_cert_free(cert);
- ERR("Too many ID_1024 certificates");
- }
- id_cert = cert;
- } else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
- if (auth_cert) {
- tor_cert_free(cert);
- ERR("Too many AUTH_1024 certificates");
- }
- auth_cert = cert;
- } else {
- tor_cert_free(cert);
- }
- }
- }
- ptr += 3 + cert_len;
- continue;
-
- truncated:
- ERR("It ends in the middle of a certificate");
- }
-
- if (conn->handshake_state->started_here) {
- int severity;
- if (! (id_cert && link_cert))
- ERR("The certs we wanted were missing");
- /* Okay. We should be able to check the certificates now. */
- if (! tor_tls_cert_matches_key(conn->tls, link_cert)) {
- ERR("The link certificate didn't match the TLS public key");
- }
- /* Note that this warns more loudly about time and validity if we were
- * _trying_ to connect to an authority, not necessarily if we _did_ connect
- * to one. */
- if (router_digest_is_trusted_dir(conn->identity_digest))
- severity = LOG_WARN;
- else
- severity = LOG_PROTOCOL_WARN;
-
- if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, 0))
- ERR("The link certificate was not valid");
- if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, 1))
- ERR("The ID certificate was not valid");
-
- conn->handshake_state->authenticated = 1;
- {
- const digests_t *id_digests = tor_cert_get_id_digests(id_cert);
- crypto_pk_t *identity_rcvd;
- if (!id_digests)
- ERR("Couldn't compute digests for key in ID cert");
-
- identity_rcvd = tor_tls_cert_get_key(id_cert);
- if (!identity_rcvd)
- ERR("Internal error: Couldn't get RSA key from ID cert.");
- memcpy(conn->handshake_state->authenticated_peer_id,
- id_digests->d[DIGEST_SHA1], DIGEST_LEN);
- connection_or_set_circid_type(conn, identity_rcvd);
- crypto_pk_free(identity_rcvd);
- }
-
- if (connection_or_client_learned_peer_id(conn,
- conn->handshake_state->authenticated_peer_id) < 0)
- ERR("Problem setting or checking peer id");
-
- log_info(LD_OR, "Got some good certificates from %s:%d: Authenticated it.",
- safe_str(conn->_base.address), conn->_base.port);
-
- conn->handshake_state->id_cert = id_cert;
- id_cert = NULL;
-
- if (!public_server_mode(get_options())) {
- /* If we initiated the connection and we are not a public server, we
- * aren't planning to authenticate at all. At this point we know who we
- * are talking to, so we can just send a netinfo now. */
- send_netinfo = 1;
- }
- } else {
- if (! (id_cert && auth_cert))
- ERR("The certs we wanted were missing");
-
- /* Remember these certificates so we can check an AUTHENTICATE cell */
- if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, 1))
- ERR("The authentication certificate was not valid");
- if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, 1))
- ERR("The ID certificate was not valid");
- log_info(LD_OR, "Got some good certificates from %s:%d: "
- "Waiting for AUTHENTICATE.",
- safe_str(conn->_base.address), conn->_base.port);
- /* XXXX check more stuff? */
-
- conn->handshake_state->id_cert = id_cert;
- conn->handshake_state->auth_cert = auth_cert;
- id_cert = auth_cert = NULL;
- }
-
- conn->handshake_state->received_certs_cell = 1;
-
- if (send_netinfo) {
- if (connection_or_send_netinfo(conn) < 0) {
- log_warn(LD_OR, "Couldn't send netinfo cell");
- connection_mark_for_close(TO_CONN(conn));
- goto err;
- }
- }
-
- err:
- tor_cert_free(id_cert);
- tor_cert_free(link_cert);
- tor_cert_free(auth_cert);
-#undef ERR
-}
-
-/** Process an AUTH_CHALLENGE cell from an OR connection.
- *
- * If we weren't supposed to get one (for example, because we're not the
- * originator of the connection), or it's ill-formed, or we aren't doing a v3
- * handshake, mark the connection. If the cell is well-formed but we don't
- * want to authenticate, just drop it. If the cell is well-formed *and* we
- * want to authenticate, send an AUTHENTICATE cell and then a NETINFO cell. */
-static void
-command_process_auth_challenge_cell(var_cell_t *cell, or_connection_t *conn)
+void
+command_setup_channel(channel_t *chan)
{
- int n_types, i, use_type = -1;
- uint8_t *cp;
-
-#define ERR(s) \
- do { \
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \
- safe_str(conn->_base.address), conn->_base.port, (s)); \
- connection_mark_for_close(TO_CONN(conn)); \
- return; \
- } while (0)
-
- if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
- ERR("We're not currently doing a v3 handshake");
- if (conn->link_proto < 3)
- ERR("We're not using link protocol >= 3");
- if (! conn->handshake_state->started_here)
- ERR("We didn't originate this connection");
- if (conn->handshake_state->received_auth_challenge)
- ERR("We already received one");
- if (! conn->handshake_state->received_certs_cell)
- ERR("We haven't gotten a CERTS cell yet");
- if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2)
- ERR("It was too short");
- if (cell->circ_id)
- ERR("It had a nonzero circuit ID");
-
- n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN));
- if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types)
- ERR("It looks truncated");
-
- /* Now see if there is an authentication type we can use */
- cp=cell->payload+OR_AUTH_CHALLENGE_LEN+2;
- for (i=0; i < n_types; ++i, cp += 2) {
- uint16_t authtype = ntohs(get_uint16(cp));
- if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET)
- use_type = authtype;
- }
-
- conn->handshake_state->received_auth_challenge = 1;
-
- if (! public_server_mode(get_options())) {
- /* If we're not a public server then we don't want to authenticate on a
- connection we originated, and we already sent a NETINFO cell when we
- got the CERTS cell. We have nothing more to do. */
- return;
- }
-
- if (use_type >= 0) {
- log_info(LD_OR, "Got an AUTH_CHALLENGE cell from %s:%d: Sending "
- "authentication",
- safe_str(conn->_base.address), conn->_base.port);
-
- if (connection_or_send_authenticate_cell(conn, use_type) < 0) {
- log_warn(LD_OR, "Couldn't send authenticate cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- } else {
- log_info(LD_OR, "Got an AUTH_CHALLENGE cell from %s:%d, but we don't "
- "know any of its authentication types. Not authenticating.",
- safe_str(conn->_base.address), conn->_base.port);
- }
-
- if (connection_or_send_netinfo(conn) < 0) {
- log_warn(LD_OR, "Couldn't send netinfo cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
+ tor_assert(chan);
-#undef ERR
+ channel_set_cell_handlers(chan,
+ command_process_cell,
+ command_process_var_cell);
}
-/** Process an AUTHENTICATE cell from an OR connection.
- *
- * If it's ill-formed or we weren't supposed to get one or we're not doing a
- * v3 handshake, then mark the connection. If it does not authenticate the
- * other side of the connection successfully (because it isn't signed right,
- * we didn't get a CERTS cell, etc) mark the connection. Otherwise, accept
- * the identity of the router on the other side of the connection.
+/** Given a listener, install the right handler to process incoming
+ * channels on it.
*/
-static void
-command_process_authenticate_cell(var_cell_t *cell, or_connection_t *conn)
-{
- uint8_t expected[V3_AUTH_FIXED_PART_LEN];
- const uint8_t *auth;
- int authlen;
-
-#define ERR(s) \
- do { \
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad AUTHENTICATE cell from %s:%d: %s", \
- safe_str(conn->_base.address), conn->_base.port, (s)); \
- connection_mark_for_close(TO_CONN(conn)); \
- return; \
- } while (0)
-
- if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
- ERR("We're not doing a v3 handshake");
- if (conn->link_proto < 3)
- ERR("We're not using link protocol >= 3");
- if (conn->handshake_state->started_here)
- ERR("We originated this connection");
- if (conn->handshake_state->received_authenticate)
- ERR("We already got one!");
- if (conn->handshake_state->authenticated) {
- /* Should be impossible given other checks */
- ERR("The peer is already authenticated");
- }
- if (! conn->handshake_state->received_certs_cell)
- ERR("We never got a certs cell");
- if (conn->handshake_state->auth_cert == NULL)
- ERR("We never got an authentication certificate");
- if (conn->handshake_state->id_cert == NULL)
- ERR("We never got an identity certificate");
- if (cell->payload_len < 4)
- ERR("Cell was way too short");
-
- auth = cell->payload;
- {
- uint16_t type = ntohs(get_uint16(auth));
- uint16_t len = ntohs(get_uint16(auth+2));
- if (4 + len > cell->payload_len)
- ERR("Authenticator was truncated");
-
- if (type != AUTHTYPE_RSA_SHA256_TLSSECRET)
- ERR("Authenticator type was not recognized");
-
- auth += 4;
- authlen = len;
- }
-
- if (authlen < V3_AUTH_BODY_LEN + 1)
- ERR("Authenticator was too short");
-
- if (connection_or_compute_authenticate_cell_body(
- conn, expected, sizeof(expected), NULL, 1) < 0)
- ERR("Couldn't compute expected AUTHENTICATE cell body");
-
- if (tor_memneq(expected, auth, sizeof(expected)))
- ERR("Some field in the AUTHENTICATE cell body was not as expected");
-
- {
- crypto_pk_t *pk = tor_tls_cert_get_key(
- conn->handshake_state->auth_cert);
- char d[DIGEST256_LEN];
- char *signed_data;
- size_t keysize;
- int signed_len;
- if (!pk)
- ERR("Internal error: couldn't get RSA key from AUTH cert.");
- crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256);
-
- keysize = crypto_pk_keysize(pk);
- signed_data = tor_malloc(keysize);
- signed_len = crypto_pk_public_checksig(pk, signed_data, keysize,
- (char*)auth + V3_AUTH_BODY_LEN,
- authlen - V3_AUTH_BODY_LEN);
- crypto_pk_free(pk);
- if (signed_len < 0) {
- tor_free(signed_data);
- ERR("Signature wasn't valid");
- }
- if (signed_len < DIGEST256_LEN) {
- tor_free(signed_data);
- ERR("Not enough data was signed");
- }
- /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here,
- * in case they're later used to hold a SHA3 digest or something. */
- if (tor_memneq(signed_data, d, DIGEST256_LEN)) {
- tor_free(signed_data);
- ERR("Signature did not match data to be signed.");
- }
- tor_free(signed_data);
- }
-
- /* Okay, we are authenticated. */
- conn->handshake_state->received_authenticate = 1;
- conn->handshake_state->authenticated = 1;
- conn->handshake_state->digest_received_data = 0;
- {
- crypto_pk_t *identity_rcvd =
- tor_tls_cert_get_key(conn->handshake_state->id_cert);
- const digests_t *id_digests =
- tor_cert_get_id_digests(conn->handshake_state->id_cert);
-
- /* This must exist; we checked key type when reading the cert. */
- tor_assert(id_digests);
-
- memcpy(conn->handshake_state->authenticated_peer_id,
- id_digests->d[DIGEST_SHA1], DIGEST_LEN);
-
- connection_or_set_circid_type(conn, identity_rcvd);
- crypto_pk_free(identity_rcvd);
-
- connection_or_init_conn_from_address(conn,
- &conn->_base.addr,
- conn->_base.port,
- (const char*)conn->handshake_state->authenticated_peer_id,
- 0);
-
- log_info(LD_OR, "Got an AUTHENTICATE cell from %s:%d: Looks good.",
- safe_str(conn->_base.address), conn->_base.port);
- }
+void
+command_setup_listener(channel_listener_t *listener)
+{
+ tor_assert(listener);
+ tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING);
-#undef ERR
+ channel_listener_set_listener_fn(listener, command_handle_incoming_channel);
}
diff --git a/src/or/command.h b/src/or/command.h
index 078ccc9f5d..375d704561 100644
--- a/src/or/command.h
+++ b/src/or/command.h
@@ -9,11 +9,15 @@
* \brief Header file for command.c.
**/
-#ifndef _TOR_COMMAND_H
-#define _TOR_COMMAND_H
+#ifndef TOR_COMMAND_H
+#define TOR_COMMAND_H
-void command_process_cell(cell_t *cell, or_connection_t *conn);
-void command_process_var_cell(var_cell_t *cell, or_connection_t *conn);
+#include "channel.h"
+
+void command_process_cell(channel_t *chan, cell_t *cell);
+void command_process_var_cell(channel_t *chan, var_cell_t *cell);
+void command_setup_channel(channel_t *chan);
+void command_setup_listener(channel_listener_t *chan_l);
extern uint64_t stats_n_padding_cells_processed;
extern uint64_t stats_n_create_cells_processed;
diff --git a/src/or/config.c b/src/or/config.c
index 90a5dfbda1..acfe2c4f83 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -12,21 +12,28 @@
#define CONFIG_PRIVATE
#include "or.h"
+#include "addressmap.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitmux.h"
+#include "circuitmux_ewma.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "confparse.h"
#include "cpuworker.h"
#include "dirserv.h"
#include "dirvote.h"
#include "dns.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
#include "networkstatus.h"
+#include "nodelist.h"
#include "policies.h"
#include "relay.h"
#include "rendclient.h"
@@ -35,6 +42,8 @@
#include "router.h"
#include "util.h"
#include "routerlist.h"
+#include "routerset.h"
+#include "statefile.h"
#include "transports.h"
#ifdef _WIN32
#include <shlobj.h>
@@ -45,51 +54,9 @@
/* From main.c */
extern int quiet_level;
-/** Enumeration of types which option values can take */
-typedef enum config_type_t {
- CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
- CONFIG_TYPE_FILENAME, /**< A filename: some prefixes get expanded. */
- CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */
- CONFIG_TYPE_INT, /**< Any integer. */
- CONFIG_TYPE_PORT, /**< A port from 1...65535, 0 for "not set", or
- * "auto". */
- CONFIG_TYPE_INTERVAL, /**< A number of seconds, with optional units*/
- CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional
- * units */
- CONFIG_TYPE_MEMUNIT, /**< A number of bytes, with optional units*/
- CONFIG_TYPE_DOUBLE, /**< A floating-point value */
- CONFIG_TYPE_BOOL, /**< A boolean value, expressed as 0 or 1. */
- CONFIG_TYPE_AUTOBOOL, /**< A boolean+auto value, expressed 0 for false,
- * 1 for true, and -1 for auto */
- CONFIG_TYPE_ISOTIME, /**< An ISO-formatted time relative to GMT. */
- CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and
- * optional whitespace. */
- CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
- CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines,
- * mixed with other keywords. */
- CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize
- * context-sensitive config lines when fetching.
- */
- CONFIG_TYPE_ROUTERSET, /**< A list of router names, addrs, and fps,
- * parsed into a routerset_t. */
- CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
-} config_type_t;
-
-/** An abbreviation for a configuration option allowed on the command line. */
-typedef struct config_abbrev_t {
- const char *abbreviated;
- const char *full;
- int commandline_only;
- int warn;
-} config_abbrev_t;
-
-/* Handy macro for declaring "In the config file or on the command line,
- * you can abbreviate <b>tok</b>s as <b>tok</b>". */
-#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
-
/** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */
-static config_abbrev_t _option_abbrevs[] = {
+static config_abbrev_t option_abbrevs_[] = {
PLURAL(AuthDirBadDirCC),
PLURAL(AuthDirBadExitCC),
PLURAL(AuthDirInvalidCC),
@@ -114,6 +81,7 @@ static config_abbrev_t _option_abbrevs[] = {
{ "BandwidthRateBytes", "BandwidthRate", 0, 0},
{ "BandwidthBurstBytes", "BandwidthBurst", 0, 0},
{ "DirFetchPostPeriod", "StatusFetchPeriod", 0, 0},
+ { "DirServer", "DirAuthority", 0, 0}, /* XXXX024 later, make this warn? */
{ "MaxConn", "ConnLimit", 0, 1},
{ "ORBindAddress", "ORListenAddress", 0, 0},
{ "DirBindAddress", "DirListenAddress", 0, 0},
@@ -130,31 +98,10 @@ static config_abbrev_t _option_abbrevs[] = {
{ "HashedControlPassword", "__HashedControlSessionPassword", 1, 0},
{ "StrictEntryNodes", "StrictNodes", 0, 1},
{ "StrictExitNodes", "StrictNodes", 0, 1},
+ { "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1},
{ NULL, NULL, 0, 0},
};
-/** A list of state-file "abbreviations," for compatibility. */
-static config_abbrev_t _state_abbrevs[] = {
- { "AccountingBytesReadInterval", "AccountingBytesReadInInterval", 0, 0 },
- { "HelperNode", "EntryGuard", 0, 0 },
- { "HelperNodeDownSince", "EntryGuardDownSince", 0, 0 },
- { "HelperNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
- { "EntryNode", "EntryGuard", 0, 0 },
- { "EntryNodeDownSince", "EntryGuardDownSince", 0, 0 },
- { "EntryNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
- { NULL, NULL, 0, 0},
-};
-#undef PLURAL
-
-/** A variable allowed in the configuration file or on the command line. */
-typedef struct config_var_t {
- const char *name; /**< The full keyword (case insensitive). */
- config_type_t type; /**< How to interpret the type and turn it into a
- * value. */
- off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
- const char *initvalue; /**< String (or null) describing initial value. */
-} config_var_t;
-
/** An entry for config_vars: "The option <b>name</b> has type
* CONFIG_TYPE_<b>conftype</b>, and corresponds to
* or_options_t.<b>member</b>"
@@ -175,7 +122,7 @@ typedef struct config_var_t {
* abbreviations, order is significant, since the first matching option will
* be chosen first.
*/
-static config_var_t _option_vars[] = {
+static config_var_t option_vars_[] = {
OBSOLETE("AccountingMaxKB"),
V(AccountingMax, MEMUNIT, "0 bytes"),
V(AccountingStart, STRING, NULL),
@@ -204,12 +151,13 @@ static config_var_t _option_vars[] = {
V(AuthDirListBadExits, BOOL, "0"),
V(AuthDirMaxServersPerAddr, UINT, "2"),
V(AuthDirMaxServersPerAuthAddr,UINT, "5"),
+ V(AuthDirHasIPv6Connectivity, BOOL, "0"),
VAR("AuthoritativeDirectory", BOOL, AuthoritativeDir, "0"),
V(AutomapHostsOnResolve, BOOL, "0"),
V(AutomapHostsSuffixes, CSV, ".onion,.exit"),
V(AvoidDiskWrites, BOOL, "0"),
- V(BandwidthBurst, MEMUNIT, "10 MB"),
- V(BandwidthRate, MEMUNIT, "5 MB"),
+ V(BandwidthBurst, MEMUNIT, "1 GB"),
+ V(BandwidthRate, MEMUNIT, "1 GB"),
V(BridgeAuthoritativeDir, BOOL, "0"),
VAR("Bridge", LINELIST, Bridges, NULL),
V(BridgePassword, STRING, NULL),
@@ -223,8 +171,10 @@ static config_var_t _option_vars[] = {
V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
V(ClientOnly, BOOL, "0"),
+ V(ClientPreferIPv6ORPort, BOOL, "0"),
V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientTransportPlugin, LINELIST, NULL),
+ V(ClientUseIPv6, BOOL, "0"),
V(ConsensusParams, STRING, NULL),
V(ConnLimit, UINT, "1000"),
V(ConnDirectionStatistics, BOOL, "0"),
@@ -257,7 +207,8 @@ static config_var_t _option_vars[] = {
OBSOLETE("DirRecordUsageRetainIPs"),
OBSOLETE("DirRecordUsageSaveInterval"),
V(DirReqStatistics, BOOL, "1"),
- VAR("DirServer", LINELIST, DirServers, NULL),
+ VAR("DirAuthority", LINELIST, DirAuthorities, NULL),
+ V(DirAuthorityFallbackRate, DOUBLE, "1.0"),
V(DisableAllSwap, BOOL, "0"),
V(DisableDebuggerAttachment, BOOL, "1"),
V(DisableIOCP, BOOL, "1"),
@@ -278,13 +229,9 @@ static config_var_t _option_vars[] = {
V(ExitPortStatistics, BOOL, "0"),
V(ExtendAllowPrivateAddresses, BOOL, "0"),
V(ExtraInfoStatistics, BOOL, "1"),
+ V(FallbackDir, LINELIST, NULL),
-#if defined (WINCE)
- V(FallbackNetworkstatusFile, FILENAME, "fallback-consensus"),
-#else
- V(FallbackNetworkstatusFile, FILENAME,
- SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "fallback-consensus"),
-#endif
+ OBSOLETE("FallbackNetworkstatusFile"),
V(FascistFirewall, BOOL, "0"),
V(FirewallPorts, CSV, ""),
V(FastFirstHopPK, BOOL, "1"),
@@ -296,9 +243,12 @@ static config_var_t _option_vars[] = {
V(FetchV2Networkstatus, BOOL, "0"),
#ifdef _WIN32
V(GeoIPFile, FILENAME, "<default>"),
+ V(GeoIPv6File, FILENAME, "<default>"),
#else
V(GeoIPFile, FILENAME,
SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip"),
+ V(GeoIPv6File, FILENAME,
+ SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip6"),
#endif
OBSOLETE("GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays"),
OBSOLETE("Group"),
@@ -324,7 +274,9 @@ static config_var_t _option_vars[] = {
V(HTTPProxyAuthenticator, STRING, NULL),
V(HTTPSProxy, STRING, NULL),
V(HTTPSProxyAuthenticator, STRING, NULL),
+ V(IPv6Exit, BOOL, "0"),
VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL),
+ V(ServerTransportListenAddr, LINELIST, NULL),
V(Socks4Proxy, STRING, NULL),
V(Socks5Proxy, STRING, NULL),
V(Socks5ProxyUsername, STRING, NULL),
@@ -358,7 +310,7 @@ static config_var_t _option_vars[] = {
V(NumEntryGuards, UINT, "3"),
V(ORListenAddress, LINELIST, NULL),
VPORT(ORPort, LINELIST, NULL),
- V(OutboundBindAddress, STRING, NULL),
+ V(OutboundBindAddress, LINELIST, NULL),
V(PathBiasCircThreshold, INT, "-1"),
V(PathBiasNoticeRate, DOUBLE, "-1"),
@@ -446,7 +398,7 @@ static config_var_t _option_vars[] = {
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
V(VirtualAddrNetwork, STRING, "127.192.0.0/10"),
V(WarnPlaintextPorts, CSV, "23,109,110,143"),
- V(_UseFilteringSSLBufferevents, BOOL, "0"),
+ V(UseFilteringSSLBufferevents, BOOL, "0"),
VAR("__ReloadTorrcOnSIGHUP", BOOL, ReloadTorrcOnSIGHUP, "1"),
VAR("__AllDirActionsPrivate", BOOL, AllDirActionsPrivate, "0"),
VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"),
@@ -456,7 +408,7 @@ static config_var_t _option_vars[] = {
VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL),
V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"),
V(VoteOnHidServDirectoriesV2, BOOL, "1"),
- V(_UsingTestNetworkDefaults, BOOL, "0"),
+ VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
@@ -484,65 +436,8 @@ static const config_var_t testing_tor_network_defaults[] = {
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"),
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"),
V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"),
- V(_UsingTestNetworkDefaults, BOOL, "1"),
-
- { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
-};
-#undef VAR
-
-#define VAR(name,conftype,member,initvalue) \
- { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_state_t, member), \
- initvalue }
+ VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
-/** Array of "state" variables saved to the ~/.tor/state file. */
-static config_var_t _state_vars[] = {
- /* Remember to document these in state-contents.txt ! */
-
- V(AccountingBytesReadInInterval, MEMUNIT, NULL),
- V(AccountingBytesWrittenInInterval, MEMUNIT, NULL),
- V(AccountingExpectedUsage, MEMUNIT, NULL),
- V(AccountingIntervalStart, ISOTIME, NULL),
- V(AccountingSecondsActive, INTERVAL, NULL),
- V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL),
- V(AccountingSoftLimitHitAt, ISOTIME, NULL),
- V(AccountingBytesAtSoftLimit, MEMUNIT, NULL),
-
- VAR("EntryGuard", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardUnlistedSince", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardPathBias", LINELIST_S, EntryGuards, NULL),
- V(EntryGuards, LINELIST_V, NULL),
-
- VAR("TransportProxy", LINELIST_S, TransportProxies, NULL),
- V(TransportProxies, LINELIST_V, NULL),
-
- V(BWHistoryReadEnds, ISOTIME, NULL),
- V(BWHistoryReadInterval, UINT, "900"),
- V(BWHistoryReadValues, CSV, ""),
- V(BWHistoryReadMaxima, CSV, ""),
- V(BWHistoryWriteEnds, ISOTIME, NULL),
- V(BWHistoryWriteInterval, UINT, "900"),
- V(BWHistoryWriteValues, CSV, ""),
- V(BWHistoryWriteMaxima, CSV, ""),
- V(BWHistoryDirReadEnds, ISOTIME, NULL),
- V(BWHistoryDirReadInterval, UINT, "900"),
- V(BWHistoryDirReadValues, CSV, ""),
- V(BWHistoryDirReadMaxima, CSV, ""),
- V(BWHistoryDirWriteEnds, ISOTIME, NULL),
- V(BWHistoryDirWriteInterval, UINT, "900"),
- V(BWHistoryDirWriteValues, CSV, ""),
- V(BWHistoryDirWriteMaxima, CSV, ""),
-
- V(TorVersion, STRING, NULL),
-
- V(LastRotatedOnionKey, ISOTIME, NULL),
- V(LastWritten, ISOTIME, NULL),
-
- V(TotalBuildTimes, UINT, NULL),
- V(CircuitBuildAbandonedCount, UINT, "0"),
- VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
- VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
@@ -550,61 +445,9 @@ static config_var_t _state_vars[] = {
#undef V
#undef OBSOLETE
-/** Represents an English description of a configuration variable; used when
- * generating configuration file comments. */
-typedef struct config_var_description_t {
- const char *name;
- const char *description;
-} config_var_description_t;
-
-/** Type of a callback to validate whether a given configuration is
- * well-formed and consistent. See options_trial_assign() for documentation
- * of arguments. */
-typedef int (*validate_fn_t)(void*,void*,int,char**);
-
-/** Information on the keys, value types, key-to-struct-member mappings,
- * variable descriptions, validation functions, and abbreviations for a
- * configuration or storage format. */
-typedef struct {
- size_t size; /**< Size of the struct that everything gets parsed into. */
- uint32_t magic; /**< Required 'magic value' to make sure we have a struct
- * of the right type. */
- off_t magic_offset; /**< Offset of the magic value within the struct. */
- config_abbrev_t *abbrevs; /**< List of abbreviations that we expand when
- * parsing this format. */
- config_var_t *vars; /**< List of variables we recognize, their default
- * values, and where we stick them in the structure. */
- validate_fn_t validate_fn; /**< Function to validate config. */
- /** If present, extra is a LINELIST variable for unrecognized
- * lines. Otherwise, unrecognized lines are an error. */
- config_var_t *extra;
-} config_format_t;
-
-/** Macro: assert that <b>cfg</b> has the right magic field for format
- * <b>fmt</b>. */
-#define CHECK(fmt, cfg) STMT_BEGIN \
- tor_assert(fmt && cfg); \
- tor_assert((fmt)->magic == \
- *(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset)); \
- STMT_END
-
#ifdef _WIN32
static char *get_windows_conf_root(void);
#endif
-static void config_line_append(config_line_t **lst,
- const char *key, const char *val);
-static void option_clear(const config_format_t *fmt, or_options_t *options,
- const config_var_t *var);
-static void option_reset(const config_format_t *fmt, or_options_t *options,
- const config_var_t *var, int use_defaults);
-static void config_free(const config_format_t *fmt, void *options);
-static int config_lines_eq(config_line_t *a, config_line_t *b);
-static int config_count_key(const config_line_t *a, const char *key);
-static int option_is_same(const config_format_t *fmt,
- const or_options_t *o1, const or_options_t *o2,
- const char *name);
-static or_options_t *options_dup(const config_format_t *fmt,
- const or_options_t *old);
static int options_validate(or_options_t *old_options,
or_options_t *options,
int from_setconf, char **msg);
@@ -623,9 +466,13 @@ static int parse_bridge_line(const char *line, int validate_only);
static int parse_client_transport_line(const char *line, int validate_only);
static int parse_server_transport_line(const char *line, int validate_only);
-static int parse_dir_server_line(const char *line,
+static char *get_bindaddr_from_transport_listen_line(const char *line,
+ const char *transport);
+static int parse_dir_authority_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
+static int parse_dir_fallback_line(const char *line,
+ int validate_only);
static void port_cfg_free(port_cfg_t *port);
static int parse_ports(or_options_t *options, int validate_only,
char **msg_out, int *n_ports_out);
@@ -635,20 +482,14 @@ static int check_server_ports(const smartlist_t *ports,
static int validate_data_directory(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
-static config_line_t *get_assigned_option(const config_format_t *fmt,
- const void *options, const char *key,
- int escape_val);
-static void config_init(const config_format_t *fmt, void *options);
-static int or_state_validate(or_state_t *old_options, or_state_t *options,
- int from_setconf, char **msg);
-static int or_state_load(void);
static int options_init_logs(or_options_t *options, int validate_only);
-static uint64_t config_parse_memunit(const char *s, int *ok);
-static int config_parse_msec_interval(const char *s, int *ok);
-static int config_parse_interval(const char *s, int *ok);
static void init_libevent(const or_options_t *options);
static int opt_streq(const char *s1, const char *s2);
+static int parse_outbound_addresses(or_options_t *options, int validate_only,
+ char **msg);
+static void config_maybe_load_geoip_files_(const or_options_t *options,
+ const or_options_t *old_options);
/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909
@@ -657,33 +498,13 @@ static int opt_streq(const char *s1, const char *s2);
static config_format_t options_format = {
sizeof(or_options_t),
OR_OPTIONS_MAGIC,
- STRUCT_OFFSET(or_options_t, _magic),
- _option_abbrevs,
- _option_vars,
+ STRUCT_OFFSET(or_options_t, magic_),
+ option_abbrevs_,
+ option_vars_,
(validate_fn_t)options_validate,
NULL
};
-/** Magic value for or_state_t. */
-#define OR_STATE_MAGIC 0x57A73f57
-
-/** "Extra" variable in the state that receives lines we can't parse. This
- * lets us preserve options from versions of Tor newer than us. */
-static config_var_t state_extra_var = {
- "__extra", CONFIG_TYPE_LINELIST, STRUCT_OFFSET(or_state_t, ExtraLines), NULL
-};
-
-/** Configuration format for or_state_t. */
-static const config_format_t state_format = {
- sizeof(or_state_t),
- OR_STATE_MAGIC,
- STRUCT_OFFSET(or_state_t, _magic),
- _state_abbrevs,
- _state_vars,
- (validate_fn_t)or_state_validate,
- &state_extra_var,
-};
-
/*
* Functions to read and write the global options pointer.
*/
@@ -697,8 +518,6 @@ static or_options_t *global_default_options = NULL;
static char *torrc_fname = NULL;
/** Name of the most recently read torrc-defaults file.*/
static char *torrc_defaults_fname;
-/** Persistent serialized state. */
-static or_state_t *global_state = NULL;
/** Configuration Options set by command line. */
static config_line_t *global_cmdline_options = NULL;
/** Contents of most recently read DirPortFrontPage file. */
@@ -713,16 +532,6 @@ get_dirportfrontpage(void)
return global_dirfrontpagecontents;
}
-/** Allocate an empty configuration object of a given format type. */
-static void *
-config_alloc(const config_format_t *fmt)
-{
- void *opts = tor_malloc_zero(fmt->size);
- *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
- CHECK(fmt, opts);
- return opts;
-}
-
/** Return the currently configured options. */
or_options_t *
get_options_mutable(void)
@@ -773,8 +582,9 @@ set_options(or_options_t *new_val, char **msg)
var->type == CONFIG_TYPE_OBSOLETE) {
continue;
}
- if (!option_is_same(&options_format, new_val, old_options, var_name)) {
- line = get_assigned_option(&options_format, new_val, var_name, 1);
+ if (!config_is_same(&options_format, new_val, old_options, var_name)) {
+ line = config_get_assigned_option(&options_format, new_val,
+ var_name, 1);
if (line) {
for (; line; line = line->next) {
@@ -843,13 +653,13 @@ or_options_free(or_options_t *options)
if (!options)
return;
- routerset_free(options->_ExcludeExitNodesUnion);
+ routerset_free(options->ExcludeExitNodesUnion_);
if (options->NodeFamilySets) {
SMARTLIST_FOREACH(options->NodeFamilySets, routerset_t *,
rs, routerset_free(rs));
smartlist_free(options->NodeFamilySets);
}
- tor_free(options->_BridgePassword_AuthDigest);
+ tor_free(options->BridgePassword_AuthDigest_);
config_free(&options_format, options);
}
@@ -863,9 +673,6 @@ config_free_all(void)
or_options_free(global_default_options);
global_default_options = NULL;
- config_free(&state_format, global_state);
- global_state = NULL;
-
config_free_lines(global_cmdline_options);
global_cmdline_options = NULL;
@@ -880,6 +687,9 @@ config_free_all(void)
tor_free(torrc_defaults_fname);
tor_free(the_tor_version);
tor_free(global_dirfrontpagecontents);
+
+ tor_free(the_short_tor_version);
+ tor_free(the_tor_version);
}
/** Make <b>address</b> -- a piece of information related to our operation as
@@ -892,7 +702,7 @@ const char *
safe_str_client(const char *address)
{
tor_assert(address);
- if (get_options()->_SafeLogging == SAFELOG_SCRUB_ALL)
+ if (get_options()->SafeLogging_ == SAFELOG_SCRUB_ALL)
return "[scrubbed]";
else
return address;
@@ -909,7 +719,7 @@ const char *
safe_str(const char *address)
{
tor_assert(address);
- if (get_options()->_SafeLogging != SAFELOG_SCRUB_NONE)
+ if (get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE)
return "[scrubbed]";
else
return address;
@@ -921,7 +731,7 @@ safe_str(const char *address)
const char *
escaped_safe_str_client(const char *address)
{
- if (get_options()->_SafeLogging == SAFELOG_SCRUB_ALL)
+ if (get_options()->SafeLogging_ == SAFELOG_SCRUB_ALL)
return "[scrubbed]";
else
return escaped(address);
@@ -933,7 +743,7 @@ escaped_safe_str_client(const char *address)
const char *
escaped_safe_str(const char *address)
{
- if (get_options()->_SafeLogging != SAFELOG_SCRUB_NONE)
+ if (get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE)
return "[scrubbed]";
else
return escaped(address);
@@ -945,7 +755,7 @@ static void
add_default_trusted_dir_authorities(dirinfo_type_t type)
{
int i;
- const char *dirservers[] = {
+ const char *authorities[] = {
"moria1 orport=9101 no-v2 "
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
@@ -974,10 +784,27 @@ add_default_trusted_dir_authorities(dirinfo_type_t type)
"154.35.32.5:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
NULL
};
- for (i=0; dirservers[i]; i++) {
- if (parse_dir_server_line(dirservers[i], type, 0)<0) {
- log_err(LD_BUG, "Couldn't parse internal dirserver line %s",
- dirservers[i]);
+ for (i=0; authorities[i]; i++) {
+ if (parse_dir_authority_line(authorities[i], type, 0)<0) {
+ log_err(LD_BUG, "Couldn't parse internal DirAuthority line %s",
+ authorities[i]);
+ }
+ }
+}
+
+/** Add the default fallback directory servers into the fallback directory
+ * server list. */
+static void
+add_default_fallback_dir_servers(void)
+{
+ int i;
+ const char *fallback[] = {
+ NULL
+ };
+ for (i=0; fallback[i]; i++) {
+ if (parse_dir_fallback_line(fallback[i], 0)<0) {
+ log_err(LD_BUG, "Couldn't parse internal FallbackDir line %s",
+ fallback[i]);
}
}
}
@@ -987,28 +814,29 @@ add_default_trusted_dir_authorities(dirinfo_type_t type)
* user if we changed any dangerous ones.
*/
static int
-validate_dir_authorities(or_options_t *options, or_options_t *old_options)
+validate_dir_servers(or_options_t *options, or_options_t *old_options)
{
config_line_t *cl;
- if (options->DirServers &&
+ if (options->DirAuthorities &&
(options->AlternateDirAuthority || options->AlternateBridgeAuthority ||
options->AlternateHSAuthority)) {
log_warn(LD_CONFIG,
- "You cannot set both DirServers and Alternate*Authority.");
+ "You cannot set both DirAuthority and Alternate*Authority.");
return -1;
}
/* do we want to complain to the user about being partitionable? */
- if ((options->DirServers &&
+ if ((options->DirAuthorities &&
(!old_options ||
- !config_lines_eq(options->DirServers, old_options->DirServers))) ||
+ !config_lines_eq(options->DirAuthorities,
+ old_options->DirAuthorities))) ||
(options->AlternateDirAuthority &&
(!old_options ||
!config_lines_eq(options->AlternateDirAuthority,
old_options->AlternateDirAuthority)))) {
log_warn(LD_CONFIG,
- "You have used DirServer or AlternateDirAuthority to "
+ "You have used DirAuthority or AlternateDirAuthority to "
"specify alternate directory authorities in "
"your configuration. This is potentially dangerous: it can "
"make you look different from all other Tor users, and hurt "
@@ -1019,17 +847,20 @@ validate_dir_authorities(or_options_t *options, or_options_t *old_options)
/* Now go through the four ways you can configure an alternate
* set of directory authorities, and make sure none are broken. */
- for (cl = options->DirServers; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
+ for (cl = options->DirAuthorities; cl; cl = cl->next)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
return -1;
for (cl = options->AlternateBridgeAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
return -1;
for (cl = options->AlternateDirAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
return -1;
for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
+ return -1;
+ for (cl = options->FallbackDir; cl; cl = cl->next)
+ if (parse_dir_fallback_line(cl->value, 1)<0)
return -1;
return 0;
}
@@ -1038,13 +869,15 @@ validate_dir_authorities(or_options_t *options, or_options_t *old_options)
* as appropriate.
*/
static int
-consider_adding_dir_authorities(const or_options_t *options,
- const or_options_t *old_options)
+consider_adding_dir_servers(const or_options_t *options,
+ const or_options_t *old_options)
{
config_line_t *cl;
int need_to_update =
- !smartlist_len(router_get_trusted_dir_servers()) || !old_options ||
- !config_lines_eq(options->DirServers, old_options->DirServers) ||
+ !smartlist_len(router_get_trusted_dir_servers()) ||
+ !smartlist_len(router_get_fallback_dir_servers()) || !old_options ||
+ !config_lines_eq(options->DirAuthorities, old_options->DirAuthorities) ||
+ !config_lines_eq(options->FallbackDir, old_options->FallbackDir) ||
!config_lines_eq(options->AlternateBridgeAuthority,
old_options->AlternateBridgeAuthority) ||
!config_lines_eq(options->AlternateDirAuthority,
@@ -1056,9 +889,9 @@ consider_adding_dir_authorities(const or_options_t *options,
return 0; /* all done */
/* Start from a clean slate. */
- clear_trusted_dir_servers();
+ clear_dir_servers();
- if (!options->DirServers) {
+ if (!options->DirAuthorities) {
/* then we may want some of the defaults */
dirinfo_type_t type = NO_DIRINFO;
if (!options->AlternateBridgeAuthority)
@@ -1070,18 +903,23 @@ consider_adding_dir_authorities(const or_options_t *options,
type |= HIDSERV_DIRINFO;
add_default_trusted_dir_authorities(type);
}
+ if (!options->FallbackDir)
+ add_default_fallback_dir_servers();
- for (cl = options->DirServers; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
+ for (cl = options->DirAuthorities; cl; cl = cl->next)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
return -1;
for (cl = options->AlternateBridgeAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
return -1;
for (cl = options->AlternateDirAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
return -1;
for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
+ return -1;
+ for (cl = options->FallbackDir; cl; cl = cl->next)
+ if (parse_dir_fallback_line(cl->value, 0)<0)
return -1;
return 0;
}
@@ -1130,7 +968,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int n_ports=0;
/* We need to set the connection limit before we can open the listeners. */
if (set_max_file_descriptors((unsigned)options->ConnLimit,
- &options->_ConnLimit) < 0) {
+ &options->ConnLimit_) < 0) {
*msg = tor_strdup("Problem with ConnLimit value. See logs for details.");
goto rollback;
}
@@ -1271,7 +1109,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
if (set_conn_limit && old_options)
set_max_file_descriptors((unsigned)old_options->ConnLimit,
- &options->_ConnLimit);
+ &options->ConnLimit_);
SMARTLIST_FOREACH(new_listeners, connection_t *, conn,
{
@@ -1371,9 +1209,10 @@ options_act(const or_options_t *old_options)
config_line_t *cl;
or_options_t *options = get_options_mutable();
int running_tor = options->command == CMD_RUN_TOR;
- char *msg;
+ char *msg=NULL;
const int transition_affects_workers =
old_options && options_transition_affects_workers(old_options, options);
+ int old_ewma_enabled;
/* disable ptrace and later, other basic debugging techniques */
{
@@ -1404,7 +1243,7 @@ options_act(const or_options_t *old_options)
return -1;
}
- if (consider_adding_dir_authorities(options, old_options) < 0)
+ if (consider_adding_dir_servers(options, old_options) < 0)
return -1;
#ifdef NON_ANONYMOUS_MODE_ENABLED
@@ -1454,7 +1293,7 @@ options_act(const or_options_t *old_options)
}
/* Load state */
- if (! global_state && running_tor) {
+ if (! or_state_loaded() && running_tor) {
if (or_state_load())
return -1;
rep_hist_load_mtbf_data(time(NULL));
@@ -1540,7 +1379,7 @@ options_act(const or_options_t *old_options)
/* Register addressmap directives */
config_register_addressmaps(options);
- parse_virtual_addr_network(options->VirtualAddrNetwork, 0, &msg);
+ parse_virtual_addr_network(options->VirtualAddrNetwork, 0, NULL);
/* Update address policies. */
if (policies_parse_from_options(options) < 0) {
@@ -1557,7 +1396,7 @@ options_act(const or_options_t *old_options)
monitor_owning_controller_process(options->OwningControllerProcess);
/* reload keys as needed for rendezvous services. */
- if (rend_service_load_keys()<0) {
+ if (rend_service_load_all_keys()<0) {
log_warn(LD_GENERAL,"Error loading rendezvous service keys");
return -1;
}
@@ -1581,8 +1420,16 @@ options_act(const or_options_t *old_options)
connection_bucket_init();
#endif
+ old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */
cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
+ /* If we just enabled ewma, set the cmux policy on all active channels */
+ if (cell_ewma_enabled() && !old_ewma_enabled) {
+ channel_set_cmux_policy_everywhere(&ewma_policy);
+ } else if (!cell_ewma_enabled() && old_ewma_enabled) {
+ /* Turn it off everywhere */
+ channel_set_cmux_policy_everywhere(NULL);
+ }
/* Update the BridgePassword's hashed version as needed. We store this as a
* digest so that we can do side-channel-proof comparisons on it.
@@ -1595,13 +1442,19 @@ options_act(const or_options_t *old_options)
"BridgePassword.");
return -1;
}
- options->_BridgePassword_AuthDigest = tor_malloc(DIGEST256_LEN);
- crypto_digest256(options->_BridgePassword_AuthDigest,
+ options->BridgePassword_AuthDigest_ = tor_malloc(DIGEST256_LEN);
+ crypto_digest256(options->BridgePassword_AuthDigest_,
http_authenticator, strlen(http_authenticator),
DIGEST_SHA256);
tor_free(http_authenticator);
}
+ if (parse_outbound_addresses(options, 0, &msg) < 0) {
+ log_warn(LD_BUG, "Failed parsing oubound bind addresses: %s", msg);
+ tor_free(msg);
+ return -1;
+ }
+
/* Check for transitions that need action. */
if (old_options) {
int revise_trackexithosts = 0;
@@ -1695,24 +1548,7 @@ options_act(const or_options_t *old_options)
connection_or_update_token_buckets(get_connection_array(), options);
}
- /* Maybe load geoip file */
- if (options->GeoIPFile &&
- ((!old_options || !opt_streq(old_options->GeoIPFile, options->GeoIPFile))
- || !geoip_is_loaded())) {
- /* XXXX Don't use this "<default>" junk; make our filename options
- * understand prefixes somehow. -NM */
- /* XXXX024 Reload GeoIPFile on SIGHUP. -NM */
- char *actual_fname = tor_strdup(options->GeoIPFile);
-#ifdef _WIN32
- if (!strcmp(actual_fname, "<default>")) {
- const char *conf_root = get_windows_conf_root();
- tor_free(actual_fname);
- tor_asprintf(&actual_fname, "%s\\geoip", conf_root);
- }
-#endif
- geoip_load_file(actual_fname, options);
- tor_free(actual_fname);
- }
+ config_maybe_load_geoip_files_(options, old_options);
if (options->CellStatistics || options->DirReqStatistics ||
options->EntryStatistics || options->ExitPortStatistics ||
@@ -1736,7 +1572,7 @@ options_act(const or_options_t *old_options)
}
if ((!old_options || !old_options->DirReqStatistics) &&
options->DirReqStatistics) {
- if (geoip_is_loaded()) {
+ if (geoip_is_loaded(AF_INET)) {
geoip_dirreq_stats_init(now);
print_notice = 1;
} else {
@@ -1751,7 +1587,7 @@ options_act(const or_options_t *old_options)
}
if ((!old_options || !old_options->EntryStatistics) &&
options->EntryStatistics && !should_record_bridge_info(options)) {
- if (geoip_is_loaded()) {
+ if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) {
geoip_entry_stats_init(now);
print_notice = 1;
} else {
@@ -1847,42 +1683,6 @@ options_act(const or_options_t *old_options)
return 0;
}
-/*
- * Functions to parse config options
- */
-
-/** If <b>option</b> is an official abbreviation for a longer option,
- * return the longer option. Otherwise return <b>option</b>.
- * If <b>command_line</b> is set, apply all abbreviations. Otherwise, only
- * apply abbreviations that work for the config file and the command line.
- * If <b>warn_obsolete</b> is set, warn about deprecated names. */
-static const char *
-expand_abbrev(const config_format_t *fmt, const char *option, int command_line,
- int warn_obsolete)
-{
- int i;
- if (! fmt->abbrevs)
- return option;
- for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
- /* Abbreviations are case insensitive. */
- if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
- (command_line || !fmt->abbrevs[i].commandline_only)) {
- if (warn_obsolete && fmt->abbrevs[i].warn) {
- log_warn(LD_CONFIG,
- "The configuration option '%s' is deprecated; "
- "use '%s' instead.",
- fmt->abbrevs[i].abbreviated,
- fmt->abbrevs[i].full);
- }
- /* Keep going through the list in case we want to rewrite it more.
- * (We could imagine recursing here, but I don't want to get the
- * user into an infinite loop if we craft our list wrong.) */
- option = fmt->abbrevs[i].full;
- }
- }
- return option;
-}
-
/** Helper: Read a list of configuration options from the command line.
* If successful, put them in *<b>result</b> and return 0, and return
* -1 and leave *<b>result</b> alone. */
@@ -1942,7 +1742,7 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
return -1;
}
- (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1, 1));
+ (*new)->key = tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
(*new)->value = want_arg ? tor_strdup(argv[i+1]) : tor_strdup("");
(*new)->command = command;
(*new)->next = NULL;
@@ -1956,444 +1756,6 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
return 0;
}
-/** Helper: allocate a new configuration option mapping 'key' to 'val',
- * append it to *<b>lst</b>. */
-static void
-config_line_append(config_line_t **lst,
- const char *key,
- const char *val)
-{
- config_line_t *newline;
-
- newline = tor_malloc_zero(sizeof(config_line_t));
- newline->key = tor_strdup(key);
- newline->value = tor_strdup(val);
- newline->next = NULL;
- while (*lst)
- lst = &((*lst)->next);
-
- (*lst) = newline;
-}
-
-/** Helper: parse the config string and strdup into key/value
- * strings. Set *result to the list, or NULL if parsing the string
- * failed. Return 0 on success, -1 on failure. Warn and ignore any
- * misformatted lines.
- *
- * If <b>extended</b> is set, then treat keys beginning with / and with + as
- * indicating "clear" and "append" respectively. */
-int
-config_get_lines(const char *string, config_line_t **result, int extended)
-{
- config_line_t *list = NULL, **next;
- char *k, *v;
-
- next = &list;
- do {
- k = v = NULL;
- string = parse_config_line_from_str(string, &k, &v);
- if (!string) {
- config_free_lines(list);
- tor_free(k);
- tor_free(v);
- return -1;
- }
- if (k && v) {
- unsigned command = CONFIG_LINE_NORMAL;
- if (extended) {
- if (k[0] == '+') {
- char *k_new = tor_strdup(k+1);
- tor_free(k);
- k = k_new;
- command = CONFIG_LINE_APPEND;
- } else if (k[0] == '/') {
- char *k_new = tor_strdup(k+1);
- tor_free(k);
- k = k_new;
- tor_free(v);
- v = tor_strdup("");
- command = CONFIG_LINE_CLEAR;
- }
- }
- /* This list can get long, so we keep a pointer to the end of it
- * rather than using config_line_append over and over and getting
- * n^2 performance. */
- *next = tor_malloc_zero(sizeof(config_line_t));
- (*next)->key = k;
- (*next)->value = v;
- (*next)->next = NULL;
- (*next)->command = command;
- next = &((*next)->next);
- } else {
- tor_free(k);
- tor_free(v);
- }
- } while (*string);
-
- *result = list;
- return 0;
-}
-
-/**
- * Free all the configuration lines on the linked list <b>front</b>.
- */
-void
-config_free_lines(config_line_t *front)
-{
- config_line_t *tmp;
-
- while (front) {
- tmp = front;
- front = tmp->next;
-
- tor_free(tmp->key);
- tor_free(tmp->value);
- tor_free(tmp);
- }
-}
-
-/** As config_find_option, but return a non-const pointer. */
-static config_var_t *
-config_find_option_mutable(config_format_t *fmt, const char *key)
-{
- int i;
- size_t keylen = strlen(key);
- if (!keylen)
- return NULL; /* if they say "--" on the command line, it's not an option */
- /* First, check for an exact (case-insensitive) match */
- for (i=0; fmt->vars[i].name; ++i) {
- if (!strcasecmp(key, fmt->vars[i].name)) {
- return &fmt->vars[i];
- }
- }
- /* If none, check for an abbreviated match */
- for (i=0; fmt->vars[i].name; ++i) {
- if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
- log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
- "Please use '%s' instead",
- key, fmt->vars[i].name);
- return &fmt->vars[i];
- }
- }
- /* Okay, unrecognized option */
- return NULL;
-}
-
-/** If <b>key</b> is a configuration option, return the corresponding const
- * config_var_t. Otherwise, if <b>key</b> is a non-standard abbreviation,
- * warn, and return the corresponding const config_var_t. Otherwise return
- * NULL.
- */
-static const config_var_t *
-config_find_option(const config_format_t *fmt, const char *key)
-{
- return config_find_option_mutable((config_format_t*)fmt, key);
-}
-
-/** Return the number of option entries in <b>fmt</b>. */
-static int
-config_count_options(const config_format_t *fmt)
-{
- int i;
- for (i=0; fmt->vars[i].name; ++i)
- ;
- return i;
-}
-
-/*
- * Functions to assign config options.
- */
-
-/** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
- * with <b>c</b>-\>value and return 0, or return -1 if bad value.
- *
- * Called from config_assign_line() and option_reset().
- */
-static int
-config_assign_value(const config_format_t *fmt, or_options_t *options,
- config_line_t *c, char **msg)
-{
- int i, ok;
- const config_var_t *var;
- void *lvalue;
-
- CHECK(fmt, options);
-
- var = config_find_option(fmt, c->key);
- tor_assert(var);
-
- lvalue = STRUCT_VAR_P(options, var->var_offset);
-
- switch (var->type) {
-
- case CONFIG_TYPE_PORT:
- if (!strcasecmp(c->value, "auto")) {
- *(int *)lvalue = CFG_AUTO_PORT;
- break;
- }
- /* fall through */
- case CONFIG_TYPE_INT:
- case CONFIG_TYPE_UINT:
- i = (int)tor_parse_long(c->value, 10,
- var->type==CONFIG_TYPE_INT ? INT_MIN : 0,
- var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX,
- &ok, NULL);
- if (!ok) {
- tor_asprintf(msg,
- "Int keyword '%s %s' is malformed or out of bounds.",
- c->key, c->value);
- return -1;
- }
- *(int *)lvalue = i;
- break;
-
- case CONFIG_TYPE_INTERVAL: {
- i = config_parse_interval(c->value, &ok);
- if (!ok) {
- tor_asprintf(msg,
- "Interval '%s %s' is malformed or out of bounds.",
- c->key, c->value);
- return -1;
- }
- *(int *)lvalue = i;
- break;
- }
-
- case CONFIG_TYPE_MSEC_INTERVAL: {
- i = config_parse_msec_interval(c->value, &ok);
- if (!ok) {
- tor_asprintf(msg,
- "Msec interval '%s %s' is malformed or out of bounds.",
- c->key, c->value);
- return -1;
- }
- *(int *)lvalue = i;
- break;
- }
-
- case CONFIG_TYPE_MEMUNIT: {
- uint64_t u64 = config_parse_memunit(c->value, &ok);
- if (!ok) {
- tor_asprintf(msg,
- "Value '%s %s' is malformed or out of bounds.",
- c->key, c->value);
- return -1;
- }
- *(uint64_t *)lvalue = u64;
- break;
- }
-
- case CONFIG_TYPE_BOOL:
- i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
- if (!ok) {
- tor_asprintf(msg,
- "Boolean '%s %s' expects 0 or 1.",
- c->key, c->value);
- return -1;
- }
- *(int *)lvalue = i;
- break;
-
- case CONFIG_TYPE_AUTOBOOL:
- if (!strcmp(c->value, "auto"))
- *(int *)lvalue = -1;
- else if (!strcmp(c->value, "0"))
- *(int *)lvalue = 0;
- else if (!strcmp(c->value, "1"))
- *(int *)lvalue = 1;
- else {
- tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.",
- c->key, c->value);
- return -1;
- }
- break;
-
- case CONFIG_TYPE_STRING:
- case CONFIG_TYPE_FILENAME:
- tor_free(*(char **)lvalue);
- *(char **)lvalue = tor_strdup(c->value);
- break;
-
- case CONFIG_TYPE_DOUBLE:
- *(double *)lvalue = atof(c->value);
- break;
-
- case CONFIG_TYPE_ISOTIME:
- if (parse_iso_time(c->value, (time_t *)lvalue)) {
- tor_asprintf(msg,
- "Invalid time '%s' for keyword '%s'", c->value, c->key);
- return -1;
- }
- break;
-
- case CONFIG_TYPE_ROUTERSET:
- if (*(routerset_t**)lvalue) {
- routerset_free(*(routerset_t**)lvalue);
- }
- *(routerset_t**)lvalue = routerset_new();
- if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) {
- tor_asprintf(msg, "Invalid exit list '%s' for option '%s'",
- c->value, c->key);
- return -1;
- }
- break;
-
- case CONFIG_TYPE_CSV:
- if (*(smartlist_t**)lvalue) {
- SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
- smartlist_clear(*(smartlist_t**)lvalue);
- } else {
- *(smartlist_t**)lvalue = smartlist_new();
- }
-
- smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- break;
-
- case CONFIG_TYPE_LINELIST:
- case CONFIG_TYPE_LINELIST_S:
- {
- config_line_t *lastval = *(config_line_t**)lvalue;
- if (lastval && lastval->fragile) {
- if (c->command != CONFIG_LINE_APPEND) {
- config_free_lines(lastval);
- *(config_line_t**)lvalue = NULL;
- } else {
- lastval->fragile = 0;
- }
- }
-
- config_line_append((config_line_t**)lvalue, c->key, c->value);
- }
- break;
- case CONFIG_TYPE_OBSOLETE:
- log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key);
- break;
- case CONFIG_TYPE_LINELIST_V:
- tor_asprintf(msg,
- "You may not provide a value for virtual option '%s'", c->key);
- return -1;
- default:
- tor_assert(0);
- break;
- }
- return 0;
-}
-
-/** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
- * to it will replace old ones. */
-static void
-config_mark_lists_fragile(const config_format_t *fmt, or_options_t *options)
-{
- int i;
- tor_assert(fmt);
- tor_assert(options);
-
- for (i = 0; fmt->vars[i].name; ++i) {
- const config_var_t *var = &fmt->vars[i];
- config_line_t *list;
- if (var->type != CONFIG_TYPE_LINELIST &&
- var->type != CONFIG_TYPE_LINELIST_V)
- continue;
-
- list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
- if (list)
- list->fragile = 1;
- }
-}
-
-/** If <b>c</b> is a syntactically valid configuration line, update
- * <b>options</b> with its value and return 0. Otherwise return -1 for bad
- * key, -2 for bad value.
- *
- * If <b>clear_first</b> is set, clear the value first. Then if
- * <b>use_defaults</b> is set, set the value to the default.
- *
- * Called from config_assign().
- */
-static int
-config_assign_line(const config_format_t *fmt, or_options_t *options,
- config_line_t *c, int use_defaults,
- int clear_first, bitarray_t *options_seen, char **msg)
-{
- const config_var_t *var;
-
- CHECK(fmt, options);
-
- var = config_find_option(fmt, c->key);
- if (!var) {
- if (fmt->extra) {
- void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset);
- log_info(LD_CONFIG,
- "Found unrecognized option '%s'; saving it.", c->key);
- config_line_append((config_line_t**)lvalue, c->key, c->value);
- return 0;
- } else {
- tor_asprintf(msg,
- "Unknown option '%s'. Failing.", c->key);
- return -1;
- }
- }
-
- /* Put keyword into canonical case. */
- if (strcmp(var->name, c->key)) {
- tor_free(c->key);
- c->key = tor_strdup(var->name);
- }
-
- if (!strlen(c->value)) {
- /* reset or clear it, then return */
- if (!clear_first) {
- if ((var->type == CONFIG_TYPE_LINELIST ||
- var->type == CONFIG_TYPE_LINELIST_S) &&
- c->command != CONFIG_LINE_CLEAR) {
- /* We got an empty linelist from the torrc or command line.
- As a special case, call this an error. Warn and ignore. */
- log_warn(LD_CONFIG,
- "Linelist option '%s' has no value. Skipping.", c->key);
- } else { /* not already cleared */
- option_reset(fmt, options, var, use_defaults);
- }
- }
- return 0;
- } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
- option_reset(fmt, options, var, use_defaults);
- }
-
- if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
- var->type != CONFIG_TYPE_LINELIST_S)) {
- /* We're tracking which options we've seen, and this option is not
- * supposed to occur more than once. */
- int var_index = (int)(var - fmt->vars);
- if (bitarray_is_set(options_seen, var_index)) {
- log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
- "value will be ignored.", var->name);
- }
- bitarray_set(options_seen, var_index);
- }
-
- if (config_assign_value(fmt, options, c, msg) < 0)
- return -2;
- return 0;
-}
-
-/** Restore the option named <b>key</b> in options to its default value.
- * Called from config_assign(). */
-static void
-config_reset_line(const config_format_t *fmt, or_options_t *options,
- const char *key, int use_defaults)
-{
- const config_var_t *var;
-
- CHECK(fmt, options);
-
- var = config_find_option(fmt, key);
- if (!var)
- return; /* give error on next pass. */
-
- option_reset(fmt, options, var, use_defaults);
-}
-
/** Return true iff key is a valid configuration option. */
int
option_is_recognized(const char *key)
@@ -2416,287 +1778,7 @@ option_get_canonical_name(const char *key)
config_line_t *
option_get_assignment(const or_options_t *options, const char *key)
{
- return get_assigned_option(&options_format, options, key, 1);
-}
-
-/** Return true iff value needs to be quoted and escaped to be used in
- * a configuration file. */
-static int
-config_value_needs_escape(const char *value)
-{
- if (*value == '\"')
- return 1;
- while (*value) {
- switch (*value)
- {
- case '\r':
- case '\n':
- case '#':
- /* Note: quotes and backspaces need special handling when we are using
- * quotes, not otherwise, so they don't trigger escaping on their
- * own. */
- return 1;
- default:
- if (!TOR_ISPRINT(*value))
- return 1;
- }
- ++value;
- }
- return 0;
-}
-
-/** Return a newly allocated deep copy of the lines in <b>inp</b>. */
-static config_line_t *
-config_lines_dup(const config_line_t *inp)
-{
- config_line_t *result = NULL;
- config_line_t **next_out = &result;
- while (inp) {
- *next_out = tor_malloc_zero(sizeof(config_line_t));
- (*next_out)->key = tor_strdup(inp->key);
- (*next_out)->value = tor_strdup(inp->value);
- inp = inp->next;
- next_out = &((*next_out)->next);
- }
- (*next_out) = NULL;
- return result;
-}
-
-/** Return newly allocated line or lines corresponding to <b>key</b> in the
- * configuration <b>options</b>. If <b>escape_val</b> is true and a
- * value needs to be quoted before it's put in a config file, quote and
- * escape that value. Return NULL if no such key exists. */
-static config_line_t *
-get_assigned_option(const config_format_t *fmt, const void *options,
- const char *key, int escape_val)
-{
- const config_var_t *var;
- const void *value;
- config_line_t *result;
- tor_assert(options && key);
-
- CHECK(fmt, options);
-
- var = config_find_option(fmt, key);
- if (!var) {
- log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
- return NULL;
- }
- value = STRUCT_VAR_P(options, var->var_offset);
-
- result = tor_malloc_zero(sizeof(config_line_t));
- result->key = tor_strdup(var->name);
- switch (var->type)
- {
- case CONFIG_TYPE_STRING:
- case CONFIG_TYPE_FILENAME:
- if (*(char**)value) {
- result->value = tor_strdup(*(char**)value);
- } else {
- tor_free(result->key);
- tor_free(result);
- return NULL;
- }
- break;
- case CONFIG_TYPE_ISOTIME:
- if (*(time_t*)value) {
- result->value = tor_malloc(ISO_TIME_LEN+1);
- format_iso_time(result->value, *(time_t*)value);
- } else {
- tor_free(result->key);
- tor_free(result);
- }
- escape_val = 0; /* Can't need escape. */
- break;
- case CONFIG_TYPE_PORT:
- if (*(int*)value == CFG_AUTO_PORT) {
- result->value = tor_strdup("auto");
- escape_val = 0;
- break;
- }
- /* fall through */
- case CONFIG_TYPE_INTERVAL:
- case CONFIG_TYPE_MSEC_INTERVAL:
- case CONFIG_TYPE_UINT:
- case CONFIG_TYPE_INT:
- /* This means every or_options_t uint or bool element
- * needs to be an int. Not, say, a uint16_t or char. */
- tor_asprintf(&result->value, "%d", *(int*)value);
- escape_val = 0; /* Can't need escape. */
- break;
- case CONFIG_TYPE_MEMUNIT:
- tor_asprintf(&result->value, U64_FORMAT,
- U64_PRINTF_ARG(*(uint64_t*)value));
- escape_val = 0; /* Can't need escape. */
- break;
- case CONFIG_TYPE_DOUBLE:
- tor_asprintf(&result->value, "%f", *(double*)value);
- escape_val = 0; /* Can't need escape. */
- break;
-
- case CONFIG_TYPE_AUTOBOOL:
- if (*(int*)value == -1) {
- result->value = tor_strdup("auto");
- escape_val = 0;
- break;
- }
- /* fall through */
- case CONFIG_TYPE_BOOL:
- result->value = tor_strdup(*(int*)value ? "1" : "0");
- escape_val = 0; /* Can't need escape. */
- break;
- case CONFIG_TYPE_ROUTERSET:
- result->value = routerset_to_string(*(routerset_t**)value);
- break;
- case CONFIG_TYPE_CSV:
- if (*(smartlist_t**)value)
- result->value =
- smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL);
- else
- result->value = tor_strdup("");
- break;
- case CONFIG_TYPE_OBSOLETE:
- log_fn(LOG_PROTOCOL_WARN, LD_CONFIG,
- "You asked me for the value of an obsolete config option '%s'.",
- key);
- tor_free(result->key);
- tor_free(result);
- return NULL;
- case CONFIG_TYPE_LINELIST_S:
- log_warn(LD_CONFIG,
- "Can't return context-sensitive '%s' on its own", key);
- tor_free(result->key);
- tor_free(result);
- return NULL;
- case CONFIG_TYPE_LINELIST:
- case CONFIG_TYPE_LINELIST_V:
- tor_free(result->key);
- tor_free(result);
- result = config_lines_dup(*(const config_line_t**)value);
- break;
- default:
- tor_free(result->key);
- tor_free(result);
- log_warn(LD_BUG,"Unknown type %d for known key '%s'",
- var->type, key);
- return NULL;
- }
-
- if (escape_val) {
- config_line_t *line;
- for (line = result; line; line = line->next) {
- if (line->value && config_value_needs_escape(line->value)) {
- char *newval = esc_for_log(line->value);
- tor_free(line->value);
- line->value = newval;
- }
- }
- }
-
- return result;
-}
-
-/** Iterate through the linked list of requested options <b>list</b>.
- * For each item, convert as appropriate and assign to <b>options</b>.
- * If an item is unrecognized, set *msg and return -1 immediately,
- * else return 0 for success.
- *
- * If <b>clear_first</b>, interpret config options as replacing (not
- * extending) their previous values. If <b>clear_first</b> is set,
- * then <b>use_defaults</b> to decide if you set to defaults after
- * clearing, or make the value 0 or NULL.
- *
- * Here are the use cases:
- * 1. A non-empty AllowInvalid line in your torrc. Appends to current
- * if linelist, replaces current if csv.
- * 2. An empty AllowInvalid line in your torrc. Should clear it.
- * 3. "RESETCONF AllowInvalid" sets it to default.
- * 4. "SETCONF AllowInvalid" makes it NULL.
- * 5. "SETCONF AllowInvalid=foo" clears it and sets it to "foo".
- *
- * Use_defaults Clear_first
- * 0 0 "append"
- * 1 0 undefined, don't use
- * 0 1 "set to null first"
- * 1 1 "set to defaults first"
- * Return 0 on success, -1 on bad key, -2 on bad value.
- *
- * As an additional special case, if a LINELIST config option has
- * no value and clear_first is 0, then warn and ignore it.
- */
-
-/*
-There are three call cases for config_assign() currently.
-
-Case one: Torrc entry
-options_init_from_torrc() calls config_assign(0, 0)
- calls config_assign_line(0, 0).
- if value is empty, calls option_reset(0) and returns.
- calls config_assign_value(), appends.
-
-Case two: setconf
-options_trial_assign() calls config_assign(0, 1)
- calls config_reset_line(0)
- calls option_reset(0)
- calls option_clear().
- calls config_assign_line(0, 1).
- if value is empty, returns.
- calls config_assign_value(), appends.
-
-Case three: resetconf
-options_trial_assign() calls config_assign(1, 1)
- calls config_reset_line(1)
- calls option_reset(1)
- calls option_clear().
- calls config_assign_value(default)
- calls config_assign_line(1, 1).
- returns.
-*/
-static int
-config_assign(const config_format_t *fmt, void *options, config_line_t *list,
- int use_defaults, int clear_first, char **msg)
-{
- config_line_t *p;
- bitarray_t *options_seen;
- const int n_options = config_count_options(fmt);
-
- CHECK(fmt, options);
-
- /* pass 1: normalize keys */
- for (p = list; p; p = p->next) {
- const char *full = expand_abbrev(fmt, p->key, 0, 1);
- if (strcmp(full,p->key)) {
- tor_free(p->key);
- p->key = tor_strdup(full);
- }
- }
-
- /* pass 2: if we're reading from a resetting source, clear all
- * mentioned config options, and maybe set to their defaults. */
- if (clear_first) {
- for (p = list; p; p = p->next)
- config_reset_line(fmt, options, p->key, use_defaults);
- }
-
- options_seen = bitarray_init_zero(n_options);
- /* pass 3: assign. */
- while (list) {
- int r;
- if ((r=config_assign_line(fmt, options, list, use_defaults,
- clear_first, options_seen, msg))) {
- bitarray_free(options_seen);
- return r;
- }
- list = list->next;
- }
- bitarray_free(options_seen);
-
- /** Now we're done assigning a group of options to the configuration.
- * Subsequent group assignments should _replace_ linelists, not extend
- * them. */
- config_mark_lists_fragile(fmt, options);
-
- return 0;
+ return config_get_assigned_option(&options_format, options, key, 1);
}
/** Try assigning <b>list</b> to the global options. You do this by duping
@@ -2713,7 +1795,7 @@ options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg)
{
int r;
- or_options_t *trial_options = options_dup(&options_format, get_options());
+ or_options_t *trial_options = config_dup(&options_format, get_options());
if ((r=config_assign(&options_format, trial_options,
list, use_defaults, clear_first, msg)) < 0) {
@@ -2740,90 +1822,6 @@ options_trial_assign(config_line_t *list, int use_defaults,
return SETOPT_OK;
}
-/** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
- * Called from option_reset() and config_free(). */
-static void
-option_clear(const config_format_t *fmt, or_options_t *options,
- const config_var_t *var)
-{
- void *lvalue = STRUCT_VAR_P(options, var->var_offset);
- (void)fmt; /* unused */
- switch (var->type) {
- case CONFIG_TYPE_STRING:
- case CONFIG_TYPE_FILENAME:
- tor_free(*(char**)lvalue);
- break;
- case CONFIG_TYPE_DOUBLE:
- *(double*)lvalue = 0.0;
- break;
- case CONFIG_TYPE_ISOTIME:
- *(time_t*)lvalue = 0;
- break;
- case CONFIG_TYPE_INTERVAL:
- case CONFIG_TYPE_MSEC_INTERVAL:
- case CONFIG_TYPE_UINT:
- case CONFIG_TYPE_INT:
- case CONFIG_TYPE_PORT:
- case CONFIG_TYPE_BOOL:
- *(int*)lvalue = 0;
- break;
- case CONFIG_TYPE_AUTOBOOL:
- *(int*)lvalue = -1;
- break;
- case CONFIG_TYPE_MEMUNIT:
- *(uint64_t*)lvalue = 0;
- break;
- case CONFIG_TYPE_ROUTERSET:
- if (*(routerset_t**)lvalue) {
- routerset_free(*(routerset_t**)lvalue);
- *(routerset_t**)lvalue = NULL;
- }
- break;
- case CONFIG_TYPE_CSV:
- if (*(smartlist_t**)lvalue) {
- SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
- smartlist_free(*(smartlist_t **)lvalue);
- *(smartlist_t **)lvalue = NULL;
- }
- break;
- case CONFIG_TYPE_LINELIST:
- case CONFIG_TYPE_LINELIST_S:
- config_free_lines(*(config_line_t **)lvalue);
- *(config_line_t **)lvalue = NULL;
- break;
- case CONFIG_TYPE_LINELIST_V:
- /* handled by linelist_s. */
- break;
- case CONFIG_TYPE_OBSOLETE:
- break;
- }
-}
-
-/** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
- * <b>use_defaults</b>, set it to its default value.
- * Called by config_init() and option_reset_line() and option_assign_line(). */
-static void
-option_reset(const config_format_t *fmt, or_options_t *options,
- const config_var_t *var, int use_defaults)
-{
- config_line_t *c;
- char *msg = NULL;
- CHECK(fmt, options);
- option_clear(fmt, options, var); /* clear it first */
- if (!use_defaults)
- return; /* all done */
- if (var->initvalue) {
- c = tor_malloc_zero(sizeof(config_line_t));
- c->key = tor_strdup(var->name);
- c->value = tor_strdup(var->initvalue);
- if (config_assign_value(fmt, options, c, &msg) < 0) {
- log_warn(LD_BUG, "Failed to assign default: %s", msg);
- tor_free(msg); /* if this happens it's a bug */
- }
- config_free_lines(c);
- }
-}
-
/** Print a usage message for tor. */
static void
print_usage(void)
@@ -2843,8 +1841,8 @@ list_torrc_options(void)
{
int i;
smartlist_t *lines = smartlist_new();
- for (i = 0; _option_vars[i].name; ++i) {
- const config_var_t *var = &_option_vars[i];
+ for (i = 0; option_vars_[i].name; ++i) {
+ const config_var_t *var = &option_vars_[i];
if (var->type == CONFIG_TYPE_OBSOLETE ||
var->type == CONFIG_TYPE_LINELIST_V)
continue;
@@ -2953,18 +1951,18 @@ resolve_my_address(int warn_severity, const or_options_t *options,
addr_string = tor_dup_ip(addr);
if (is_internal_IP(addr, 0)) {
/* make sure we're ok with publishing an internal IP */
- if (!options->DirServers && !options->AlternateDirAuthority) {
- /* if they are using the default dirservers, disallow internal IPs
+ if (!options->DirAuthorities && !options->AlternateDirAuthority) {
+ /* if they are using the default authorities, disallow internal IPs
* always. */
log_fn(warn_severity, LD_CONFIG,
"Address '%s' resolves to private IP address '%s'. "
- "Tor servers that use the default DirServers must have public "
- "IP addresses.", hostname, addr_string);
+ "Tor servers that use the default DirAuthorities must have "
+ "public IP addresses.", hostname, addr_string);
tor_free(addr_string);
return -1;
}
if (!explicit_ip) {
- /* even if they've set their own dirservers, require an explicit IP if
+ /* even if they've set their own authorities, require an explicit IP if
* they're using an internal address. */
log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
"IP address '%s'. Please set the Address config option to be "
@@ -3038,112 +2036,11 @@ is_local_addr(const tor_addr_t *addr)
return 0;
}
-/** Release storage held by <b>options</b>. */
-static void
-config_free(const config_format_t *fmt, void *options)
-{
- int i;
-
- if (!options)
- return;
-
- tor_assert(fmt);
-
- for (i=0; fmt->vars[i].name; ++i)
- option_clear(fmt, options, &(fmt->vars[i]));
- if (fmt->extra) {
- config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset);
- config_free_lines(*linep);
- *linep = NULL;
- }
- tor_free(options);
-}
-
-/** Return true iff a and b contain identical keys and values in identical
- * order. */
-static int
-config_lines_eq(config_line_t *a, config_line_t *b)
-{
- while (a && b) {
- if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
- return 0;
- a = a->next;
- b = b->next;
- }
- if (a || b)
- return 0;
- return 1;
-}
-
-/** Return the number of lines in <b>a</b> whose key is <b>key</b>. */
-static int
-config_count_key(const config_line_t *a, const char *key)
-{
- int n = 0;
- while (a) {
- if (!strcasecmp(a->key, key)) {
- ++n;
- }
- a = a->next;
- }
- return n;
-}
-
-/** Return true iff the option <b>name</b> has the same value in <b>o1</b>
- * and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
- */
-static int
-option_is_same(const config_format_t *fmt,
- const or_options_t *o1, const or_options_t *o2,
- const char *name)
-{
- config_line_t *c1, *c2;
- int r = 1;
- CHECK(fmt, o1);
- CHECK(fmt, o2);
-
- c1 = get_assigned_option(fmt, o1, name, 0);
- c2 = get_assigned_option(fmt, o2, name, 0);
- r = config_lines_eq(c1, c2);
- config_free_lines(c1);
- config_free_lines(c2);
- return r;
-}
-
-/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
-static or_options_t *
-options_dup(const config_format_t *fmt, const or_options_t *old)
-{
- or_options_t *newopts;
- int i;
- config_line_t *line;
-
- newopts = config_alloc(fmt);
- for (i=0; fmt->vars[i].name; ++i) {
- if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
- continue;
- if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
- continue;
- line = get_assigned_option(fmt, old, fmt->vars[i].name, 0);
- if (line) {
- char *msg = NULL;
- if (config_assign(fmt, newopts, line, 0, 0, &msg) < 0) {
- log_err(LD_BUG, "Config_get_assigned_option() generated "
- "something we couldn't config_assign(): %s", msg);
- tor_free(msg);
- tor_assert(0);
- }
- }
- config_free_lines(line);
- }
- return newopts;
-}
-
/** Return a new empty or_options_t. Used for testing. */
or_options_t *
options_new(void)
{
- return config_alloc(&options_format);
+ return config_new(&options_format);
}
/** Set <b>options</b> to hold reasonable defaults for most options.
@@ -3154,94 +2051,6 @@ options_init(or_options_t *options)
config_init(&options_format, options);
}
-/** Set all vars in the configuration object <b>options</b> to their default
- * values. */
-static void
-config_init(const config_format_t *fmt, void *options)
-{
- int i;
- const config_var_t *var;
- CHECK(fmt, options);
-
- for (i=0; fmt->vars[i].name; ++i) {
- var = &fmt->vars[i];
- if (!var->initvalue)
- continue; /* defaults to NULL or 0 */
- option_reset(fmt, options, var, 1);
- }
-}
-
-/** Allocate and return a new string holding the written-out values of the vars
- * in 'options'. If 'minimal', do not write out any default-valued vars.
- * Else, if comment_defaults, write default values as comments.
- */
-static char *
-config_dump(const config_format_t *fmt, const void *default_options,
- const void *options, int minimal,
- int comment_defaults)
-{
- smartlist_t *elements;
- const or_options_t *defaults = default_options;
- void *defaults_tmp = NULL;
- config_line_t *line, *assigned;
- char *result;
- int i;
- char *msg = NULL;
-
- if (defaults == NULL) {
- defaults = defaults_tmp = config_alloc(fmt);
- config_init(fmt, defaults_tmp);
- }
-
- /* XXX use a 1 here so we don't add a new log line while dumping */
- if (default_options == NULL) {
- if (fmt->validate_fn(NULL, defaults_tmp, 1, &msg) < 0) {
- log_err(LD_BUG, "Failed to validate default config.");
- tor_free(msg);
- tor_assert(0);
- }
- }
-
- elements = smartlist_new();
- for (i=0; fmt->vars[i].name; ++i) {
- int comment_option = 0;
- if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE ||
- fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
- continue;
- /* Don't save 'hidden' control variables. */
- if (!strcmpstart(fmt->vars[i].name, "__"))
- continue;
- if (minimal && option_is_same(fmt, options, defaults, fmt->vars[i].name))
- continue;
- else if (comment_defaults &&
- option_is_same(fmt, options, defaults, fmt->vars[i].name))
- comment_option = 1;
-
- line = assigned = get_assigned_option(fmt, options, fmt->vars[i].name, 1);
-
- for (; line; line = line->next) {
- smartlist_add_asprintf(elements, "%s%s %s\n",
- comment_option ? "# " : "",
- line->key, line->value);
- }
- config_free_lines(assigned);
- }
-
- if (fmt->extra) {
- line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset);
- for (; line; line = line->next) {
- smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
- }
- }
-
- result = smartlist_join_strings(elements, "", 0, NULL);
- SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
- smartlist_free(elements);
- if (defaults_tmp)
- config_free(fmt, defaults_tmp);
- return result;
-}
-
/** Return a string containing a possible configuration file that would give
* the configuration in <b>options</b>. If <b>minimal</b> is true, do not
* include options that are the same as Tor's defaults.
@@ -3298,16 +2107,16 @@ ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg)
}
/** Parse an authority type from <b>options</b>-\>PublishServerDescriptor
- * and write it to <b>options</b>-\>_PublishServerDescriptor. Treat "1"
+ * and write it to <b>options</b>-\>PublishServerDescriptor_. Treat "1"
* as "v2,v3" unless BridgeRelay is 1, in which case treat it as "bridge".
* Treat "0" as "".
* Return 0 on success or -1 if not a recognized authority type (in which
- * case the value of _PublishServerDescriptor is undefined). */
+ * case the value of PublishServerDescriptor_ is undefined). */
static int
compute_publishserverdescriptor(or_options_t *options)
{
smartlist_t *list = options->PublishServerDescriptor;
- dirinfo_type_t *auth = &options->_PublishServerDescriptor;
+ dirinfo_type_t *auth = &options->PublishServerDescriptor_;
*auth = NO_DIRINFO;
if (!list) /* empty list, answer is none */
return 0;
@@ -3403,6 +2212,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (parse_ports(options, 1, msg, &n_ports) < 0)
return -1;
+ if (parse_outbound_addresses(options, 1, msg) < 0)
+ return -1;
+
if (validate_data_directory(options)<0)
REJECT("Invalid DataDirectory");
@@ -3467,9 +2279,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->ExcludeExitNodes || options->ExcludeNodes) {
- options->_ExcludeExitNodesUnion = routerset_new();
- routerset_union(options->_ExcludeExitNodesUnion,options->ExcludeExitNodes);
- routerset_union(options->_ExcludeExitNodesUnion,options->ExcludeNodes);
+ options->ExcludeExitNodesUnion_ = routerset_new();
+ routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeExitNodes);
+ routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeNodes);
}
if (options->NodeFamilies) {
@@ -3668,19 +2480,19 @@ options_validate(or_options_t *old_options, or_options_t *options,
log_warn(LD_CONFIG, "EntryNodes is set, but UseEntryGuards is disabled. "
"EntryNodes will be ignored.");
- options->_AllowInvalid = 0;
+ options->AllowInvalid_ = 0;
if (options->AllowInvalidNodes) {
SMARTLIST_FOREACH_BEGIN(options->AllowInvalidNodes, const char *, cp) {
if (!strcasecmp(cp, "entry"))
- options->_AllowInvalid |= ALLOW_INVALID_ENTRY;
+ options->AllowInvalid_ |= ALLOW_INVALID_ENTRY;
else if (!strcasecmp(cp, "exit"))
- options->_AllowInvalid |= ALLOW_INVALID_EXIT;
+ options->AllowInvalid_ |= ALLOW_INVALID_EXIT;
else if (!strcasecmp(cp, "middle"))
- options->_AllowInvalid |= ALLOW_INVALID_MIDDLE;
+ options->AllowInvalid_ |= ALLOW_INVALID_MIDDLE;
else if (!strcasecmp(cp, "introduction"))
- options->_AllowInvalid |= ALLOW_INVALID_INTRODUCTION;
+ options->AllowInvalid_ |= ALLOW_INVALID_INTRODUCTION;
else if (!strcasecmp(cp, "rendezvous"))
- options->_AllowInvalid |= ALLOW_INVALID_RENDEZVOUS;
+ options->AllowInvalid_ |= ALLOW_INVALID_RENDEZVOUS;
else {
tor_asprintf(msg,
"Unrecognized value '%s' in AllowInvalidNodes", cp);
@@ -3691,11 +2503,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (!options->SafeLogging ||
!strcasecmp(options->SafeLogging, "0")) {
- options->_SafeLogging = SAFELOG_SCRUB_NONE;
+ options->SafeLogging_ = SAFELOG_SCRUB_NONE;
} else if (!strcasecmp(options->SafeLogging, "relay")) {
- options->_SafeLogging = SAFELOG_SCRUB_RELAY;
+ options->SafeLogging_ = SAFELOG_SCRUB_RELAY;
} else if (!strcasecmp(options->SafeLogging, "1")) {
- options->_SafeLogging = SAFELOG_SCRUB_ALL;
+ options->SafeLogging_ = SAFELOG_SCRUB_ALL;
} else {
tor_asprintf(msg,
"Unrecognized value '%s' in SafeLogging",
@@ -3709,8 +2521,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if ((options->BridgeRelay
- || options->_PublishServerDescriptor & BRIDGE_DIRINFO)
- && (options->_PublishServerDescriptor
+ || options->PublishServerDescriptor_ & BRIDGE_DIRINFO)
+ && (options->PublishServerDescriptor_
& (V1_DIRINFO|V2_DIRINFO|V3_DIRINFO))) {
REJECT("Bridges are not supposed to publish router descriptors to the "
"directory authorities. Please correct your "
@@ -3761,6 +2573,29 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->LearnCircuitBuildTimeout = 0;
}
+ if (options->Tor2webMode && options->UseEntryGuards) {
+ /* tor2web mode clients do not (and should not) use entry guards
+ * in any meaningful way. Further, tor2web mode causes the hidden
+ * service client code to do things which break the path bias
+ * detector, and it's far easier to turn off entry guards (and
+ * thus the path bias detector with it) than to figure out how to
+ * make a piece of code which cannot possibly help tor2web mode
+ * users compatible with tor2web mode.
+ */
+ log_notice(LD_CONFIG,
+ "Tor2WebMode is enabled; disabling UseEntryGuards.");
+ options->UseEntryGuards = 0;
+ }
+
+ if (!(options->UseEntryGuards) &&
+ (options->RendConfigLines != NULL)) {
+ log_warn(LD_CONFIG,
+ "UseEntryGuards is disabled, but you have configured one or more "
+ "hidden services on this Tor instance. Your hidden services "
+ "will be very easy to locate using a well-known attack -- see "
+ "http://freehaven.net/anonbib/#hs-attack06 for details.");
+ }
+
if (!(options->LearnCircuitBuildTimeout) &&
options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) {
log_warn(LD_CONFIG,
@@ -4035,8 +2870,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (validate_addr_policies(options, msg) < 0)
return -1;
- if (validate_dir_authorities(options, old_options) < 0)
- REJECT("Directory authority line did not parse. See logs for details.");
+ if (validate_dir_servers(options, old_options) < 0)
+ REJECT("Directory authority/fallback line did not parse. See logs "
+ "for details.");
if (options->UseBridges && !options->Bridges)
REJECT("If you set UseBridges, you must specify at least one bridge.");
@@ -4062,7 +2898,23 @@ options_validate(or_options_t *old_options, or_options_t *options,
log_notice(LD_GENERAL, "Tor is not configured as a relay but you specified"
" a ServerTransportPlugin line (%s). The ServerTransportPlugin "
"line will be ignored.",
- esc_for_log(options->ServerTransportPlugin->value));
+ escaped(options->ServerTransportPlugin->value));
+ }
+
+ for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+ /** If get_bindaddr_from_transport_listen_line() fails with
+ 'transport' being NULL, it means that something went wrong
+ while parsing the ServerTransportListenAddr line. */
+ char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL);
+ if (!bindaddr)
+ REJECT("ServerTransportListenAddr did not parse. See logs for details.");
+ tor_free(bindaddr);
+ }
+
+ if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) {
+ log_notice(LD_GENERAL, "You need at least a single managed-proxy to "
+ "specify a transport listen address. The "
+ "ServerTransportListenAddr line will be ignored.");
}
if (options->ConstrainedSockets) {
@@ -4138,7 +2990,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingTorNetwork &&
- !(options->DirServers ||
+ !(options->DirAuthorities ||
(options->AlternateDirAuthority &&
options->AlternateBridgeAuthority))) {
REJECT("TestingTorNetwork may only be configured in combination with "
@@ -4146,7 +2998,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
"and AlternateBridgeAuthority configured.");
}
- if (options->AllowSingleHopExits && !options->DirServers) {
+ if (options->AllowSingleHopExits && !options->DirAuthorities) {
COMPLAIN("You have set AllowSingleHopExits; now your relay will allow "
"others to make one-hop exits. However, since by default most "
"clients avoid relays that set this option, most clients will "
@@ -4158,7 +3010,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
/* Keep changes to hard-coded values synchronous to man page and default
* values table. */
if (options->TestingV3AuthInitialVotingInterval != 30*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingV3AuthInitialVotingInterval may only be changed in testing "
"Tor networks!");
} else if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) {
@@ -4169,7 +3021,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingV3AuthInitialVoteDelay != 5*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingV3AuthInitialVoteDelay may only be changed in testing "
"Tor networks!");
@@ -4178,7 +3030,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingV3AuthInitialDistDelay != 5*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingV3AuthInitialDistDelay may only be changed in testing "
"Tor networks!");
} else if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) {
@@ -4193,7 +3045,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingAuthDirTimeToLearnReachability != 30*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingAuthDirTimeToLearnReachability may only be changed in "
"testing Tor networks!");
} else if (options->TestingAuthDirTimeToLearnReachability < 0) {
@@ -4203,7 +3055,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingEstimatedDescriptorPropagationTime != 10*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingEstimatedDescriptorPropagationTime may only be changed in "
"testing Tor networks!");
} else if (options->TestingEstimatedDescriptorPropagationTime < 0) {
@@ -4339,7 +3191,7 @@ options_transition_affects_workers(const or_options_t *old_options,
!config_lines_eq(old_options->ORPort_lines, new_options->ORPort_lines) ||
old_options->ServerDNSSearchDomains !=
new_options->ServerDNSSearchDomains ||
- old_options->_SafeLogging != new_options->_SafeLogging ||
+ old_options->SafeLogging_ != new_options->SafeLogging_ ||
old_options->ClientOnly != new_options->ClientOnly ||
public_server_mode(old_options) != public_server_mode(new_options) ||
!config_lines_eq(old_options->Logs, new_options->Logs) ||
@@ -4366,14 +3218,15 @@ options_transition_affects_descriptor(const or_options_t *old_options,
!config_lines_eq(old_options->ExitPolicy,new_options->ExitPolicy) ||
old_options->ExitPolicyRejectPrivate !=
new_options->ExitPolicyRejectPrivate ||
+ old_options->IPv6Exit != new_options->IPv6Exit ||
!config_lines_eq(old_options->ORPort_lines,
new_options->ORPort_lines) ||
!config_lines_eq(old_options->DirPort_lines,
new_options->DirPort_lines) ||
old_options->ClientOnly != new_options->ClientOnly ||
old_options->DisableNetwork != new_options->DisableNetwork ||
- old_options->_PublishServerDescriptor !=
- new_options->_PublishServerDescriptor ||
+ old_options->PublishServerDescriptor_ !=
+ new_options->PublishServerDescriptor_ ||
get_effective_bwrate(old_options) != get_effective_bwrate(new_options) ||
get_effective_bwburst(old_options) !=
get_effective_bwburst(new_options) ||
@@ -4730,7 +3583,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
this is the first time we run*/
newoptions = tor_malloc_zero(sizeof(or_options_t));
- newoptions->_magic = OR_OPTIONS_MAGIC;
+ newoptions->magic_ = OR_OPTIONS_MAGIC;
options_init(newoptions);
newoptions->command = command;
newoptions->command_arg = command_arg;
@@ -4752,7 +3605,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
goto err;
}
if (i==0)
- newdefaultoptions = options_dup(&options_format, newoptions);
+ newdefaultoptions = config_dup(&options_format, newoptions);
}
/* Go through command-line variables too */
@@ -4790,7 +3643,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
config_free(&options_format, newdefaultoptions);
newdefaultoptions = NULL;
newoptions = tor_malloc_zero(sizeof(or_options_t));
- newoptions->_magic = OR_OPTIONS_MAGIC;
+ newoptions->magic_ = OR_OPTIONS_MAGIC;
options_init(newoptions);
newoptions->command = command;
newoptions->command_arg = command_arg;
@@ -4813,7 +3666,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
goto err;
}
if (i==0)
- newdefaultoptions = options_dup(&options_format, newoptions);
+ newdefaultoptions = config_dup(&options_format, newoptions);
}
/* Assign command-line variables a second time too */
retval = config_assign(&options_format, newoptions,
@@ -5147,8 +4000,8 @@ parse_bridge_line(const char *line, int validate_only)
}
if (!validate_only) {
- log_debug(LD_DIR, "Bridge at %s:%d (transport: %s) (%s)",
- fmt_addr(&addr), (int)port,
+ log_debug(LD_DIR, "Bridge at %s (transport: %s) (%s)",
+ fmt_addrport(&addr, port),
transport_name ? transport_name : "no transport",
fingerprint ? fingerprint : "no key listed");
bridge_add_from_config(&addr, port,
@@ -5281,8 +4134,8 @@ parse_client_transport_line(const char *line, int validate_only)
transport_add_from_config(&addr, port, smartlist_get(transport_list, 0),
socks_ver);
- log_info(LD_DIR, "Transport '%s' found at %s:%d",
- transports, fmt_addr(&addr), (int)port);
+ log_info(LD_DIR, "Transport '%s' found at %s",
+ transports, fmt_addrport(&addr, port));
}
}
@@ -5303,6 +4156,80 @@ parse_client_transport_line(const char *line, int validate_only)
return r;
}
+/** Given a ServerTransportListenAddr <b>line</b>, return its
+ * <address:port> string. Return NULL if the line was not
+ * well-formed.
+ *
+ * If <b>transport</b> is set, return NULL if the line is not
+ * referring to <b>transport</b>.
+ *
+ * The returned string is allocated on the heap and it's the
+ * responsibility of the caller to free it. */
+static char *
+get_bindaddr_from_transport_listen_line(const char *line,const char *transport)
+{
+ smartlist_t *items = NULL;
+ const char *parsed_transport = NULL;
+ char *addrport = NULL;
+ tor_addr_t addr;
+ uint16_t port = 0;
+
+ items = smartlist_new();
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(items) < 2) {
+ log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line.");
+ goto err;
+ }
+
+ parsed_transport = smartlist_get(items, 0);
+ addrport = tor_strdup(smartlist_get(items, 1));
+
+ /* If 'transport' is given, check if it matches the one on the line */
+ if (transport && strcmp(transport, parsed_transport))
+ goto err;
+
+ /* Validate addrport */
+ if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port)<0) {
+ log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
+ "address '%s'", addrport);
+ goto err;
+ }
+
+ goto done;
+
+ err:
+ tor_free(addrport);
+ addrport = NULL;
+
+ done:
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+
+ return addrport;
+}
+
+/** Given the name of a pluggable transport in <b>transport</b>, check
+ * the configuration file to see if the user has explicitly asked for
+ * it to listen on a specific port. Return a <address:port> string if
+ * so, otherwise NULL. */
+char *
+get_transport_bindaddr_from_config(const char *transport)
+{
+ config_line_t *cl;
+ const or_options_t *options = get_options();
+
+ for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+ char *bindaddr =
+ get_bindaddr_from_transport_listen_line(cl->value, transport);
+ if (bindaddr)
+ return bindaddr;
+ }
+
+ return NULL;
+}
+
/** Read the contents of a ServerTransportPlugin line from
* <b>line</b>. Return 0 if the line is well-formed, and -1 if it
* isn't.
@@ -5401,8 +4328,8 @@ parse_server_transport_line(const char *line, int validate_only)
}
if (!validate_only) {
- log_info(LD_DIR, "Server transport '%s' at %s:%d.",
- transports, fmt_addr(&addr), (int)port);
+ log_info(LD_DIR, "Server transport '%s' at %s.",
+ transports, fmt_addrport(&addr, port));
}
}
@@ -5423,15 +4350,15 @@ parse_server_transport_line(const char *line, int validate_only)
return r;
}
-/** Read the contents of a DirServer line from <b>line</b>. If
+/** Read the contents of a DirAuthority line from <b>line</b>. If
* <b>validate_only</b> is 0, and the line is well-formed, and it
* shares any bits with <b>required_type</b> or <b>required_type</b>
* is 0, then add the dirserver described in the line (minus whatever
* bits it's missing) as a valid authority. Return 0 on success,
* or -1 if the line isn't well-formed or if we can't add it. */
static int
-parse_dir_server_line(const char *line, dirinfo_type_t required_type,
- int validate_only)
+parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
+ int validate_only)
{
smartlist_t *items = NULL;
int r;
@@ -5441,6 +4368,7 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
char v3_digest[DIGEST_LEN];
dirinfo_type_t type = V2_DIRINFO;
int is_not_hidserv_authority = 0, is_not_v2_authority = 0;
+ double weight = 1.0;
items = smartlist_new();
smartlist_split_string(items, line, NULL,
@@ -5476,6 +4404,14 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
if (!ok)
log_warn(LD_CONFIG, "Invalid orport '%s' on DirServer line.",
portstring);
+ } else if (!strcmpstart(flag, "weight=")) {
+ int ok;
+ const char *wstring = flag + strlen("weight=");
+ weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_CONFIG, "Invalid weight '%s' on DirAuthority line.",flag);
+ weight=1.0;
+ }
} else if (!strcasecmpstart(flag, "v3ident=")) {
char *idstr = flag + strlen("v3ident=");
if (strlen(idstr) != HEX_DIGEST_LEN ||
@@ -5514,8 +4450,8 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
fingerprint = smartlist_join_strings(items, "", 0, NULL);
if (strlen(fingerprint) != HEX_DIGEST_LEN) {
- log_warn(LD_CONFIG, "Key digest for DirServer is wrong length %d.",
- (int)strlen(fingerprint));
+ log_warn(LD_CONFIG, "Key digest '%s' for DirServer is wrong length %d.",
+ fingerprint, (int)strlen(fingerprint));
goto err;
}
if (!strcmp(fingerprint, "E623F7625FBE0C87820F11EC5F6D5377ED816294")) {
@@ -5532,14 +4468,16 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
}
if (!validate_only && (!required_type || required_type & type)) {
+ dir_server_t *ds;
if (required_type)
type &= required_type; /* pare down what we think of them as an
* authority for. */
log_debug(LD_DIR, "Trusted %d dirserver at %s:%d (%s)", (int)type,
address, (int)dir_port, (char*)smartlist_get(items,0));
- if (!add_trusted_dir_server(nickname, address, dir_port, or_port,
- digest, v3_digest, type))
+ if (!(ds = trusted_dir_server_new(nickname, address, dir_port, or_port,
+ digest, v3_digest, type, weight)))
goto err;
+ dir_server_add(ds);
}
r = 0;
@@ -5558,6 +4496,99 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
return r;
}
+/** Read the contents of a FallbackDir line from <b>line</b>. If
+ * <b>validate_only</b> is 0, and the line is well-formed, then add the
+ * dirserver described in the line as a fallback directory. Return 0 on
+ * success, or -1 if the line isn't well-formed or if we can't add it. */
+static int
+parse_dir_fallback_line(const char *line,
+ int validate_only)
+{
+ int r = -1;
+ smartlist_t *items = smartlist_new(), *positional = smartlist_new();
+ int orport = -1;
+ uint16_t dirport;
+ tor_addr_t addr;
+ int ok;
+ char id[DIGEST_LEN];
+ char *address=NULL;
+ double weight=1.0;
+
+ memset(id, 0, sizeof(id));
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+ SMARTLIST_FOREACH_BEGIN(items, const char *, cp) {
+ const char *eq = strchr(cp, '=');
+ ok = 1;
+ if (! eq) {
+ smartlist_add(positional, (char*)cp);
+ continue;
+ }
+ if (!strcmpstart(cp, "orport=")) {
+ orport = (int)tor_parse_long(cp+strlen("orport="), 10,
+ 1, 65535, &ok, NULL);
+ } else if (!strcmpstart(cp, "id=")) {
+ ok = !base16_decode(id, DIGEST_LEN,
+ cp+strlen("id="), strlen(cp)-strlen("id="));
+ } else if (!strcmpstart(cp, "weight=")) {
+ int ok;
+ const char *wstring = cp + strlen("weight=");
+ weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_CONFIG, "Invalid weight '%s' on FallbackDir line.", cp);
+ weight=1.0;
+ }
+ }
+
+ if (!ok) {
+ log_warn(LD_CONFIG, "Bad FallbackDir option %s", escaped(cp));
+ goto end;
+ }
+ } SMARTLIST_FOREACH_END(cp);
+
+ if (smartlist_len(positional) != 1) {
+ log_warn(LD_CONFIG, "Couldn't parse FallbackDir line %s", escaped(line));
+ goto end;
+ }
+
+ if (tor_digest_is_zero(id)) {
+ log_warn(LD_CONFIG, "Missing identity on FallbackDir line");
+ goto end;
+ }
+
+ if (orport <= 0) {
+ log_warn(LD_CONFIG, "Missing orport on FallbackDir line");
+ goto end;
+ }
+
+ if (tor_addr_port_split(LOG_INFO, smartlist_get(positional, 0),
+ &address, &dirport) < 0 ||
+ tor_addr_parse(&addr, address)<0) {
+ log_warn(LD_CONFIG, "Couldn't parse address:port %s on FallbackDir line",
+ (const char*)smartlist_get(positional, 0));
+ goto end;
+ }
+
+ if (!validate_only) {
+ dir_server_t *ds;
+ ds = fallback_dir_server_new(&addr, dirport, orport, id, weight);
+ if (!ds) {
+ log_warn(LD_CONFIG, "Couldn't create FallbackDir %s", escaped(line));
+ goto end;
+ }
+ dir_server_add(ds);
+ }
+
+ r = 0;
+
+ end:
+ SMARTLIST_FOREACH(items, char *, cp, tor_free(cp));
+ smartlist_free(items);
+ smartlist_free(positional);
+ tor_free(address);
+ return r;
+}
+
/** Free all storage held in <b>port</b> */
static void
port_cfg_free(port_cfg_t *port)
@@ -5574,15 +4605,17 @@ warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname)
if (port->is_unix_addr) {
/* Unix sockets aren't accessible over a network. */
} else if (!tor_addr_is_internal(&port->addr, 1)) {
- log_warn(LD_CONFIG, "You specified a public address for %sPort. "
+ log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. "
"Other people on the Internet might find your computer and "
"use it as an open proxy. Please don't allow this unless you "
- "have a good reason.", portname);
+ "have a good reason.",
+ fmt_addrport(&port->addr, port->port), portname);
} else if (!tor_addr_is_loopback(&port->addr)) {
- log_notice(LD_CONFIG, "You configured a non-loopback address for "
- "%sPort. This allows everybody on your local network to use "
- "your machine as a proxy. Make sure this is what you wanted.",
- portname);
+ log_notice(LD_CONFIG, "You configured a non-loopback address '%s' "
+ "for %sPort. This allows everybody on your local network to "
+ "use your machine as a proxy. Make sure this is what you "
+ "wanted.",
+ fmt_addrport(&port->addr, port->port), portname);
}
} SMARTLIST_FOREACH_END(port);
}
@@ -5634,6 +4667,7 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
#define CL_PORT_ALLOW_EXTRA_LISTENADDR (1u<<2)
#define CL_PORT_SERVER_OPTIONS (1u<<3)
#define CL_PORT_FORBID_NONLOCAL (1u<<4)
+#define CL_PORT_TAKES_HOSTNAMES (1u<<5)
/**
* Parse port configuration for a single port type.
@@ -5666,6 +4700,9 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
* isolation options in the FooPort entries; instead allow the
* server-port option set.
*
+ * If CL_PORT_TAKES_HOSTNAMES is set in <b>flags</b>, allow the options
+ * {No,}IPv{4,6}Traffic.
+ *
* On success, if <b>out</b> is given, add a new port_cfg_t entry to
* <b>out</b> for every port that the client should listen on. Return 0
* on success, -1 on failure.
@@ -5689,6 +4726,7 @@ parse_port_config(smartlist_t *out,
const unsigned forbid_nonlocal = flags & CL_PORT_FORBID_NONLOCAL;
const unsigned allow_spurious_listenaddr =
flags & CL_PORT_ALLOW_EXTRA_LISTENADDR;
+ const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES;
int got_zero_port=0, got_nonzero_port=0;
/* FooListenAddress is deprecated; let's make it work like it used to work,
@@ -5730,7 +4768,8 @@ parse_port_config(smartlist_t *out,
cfg->port = mainport;
tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */
cfg->no_listen = 1;
- cfg->ipv4_only = 1;
+ cfg->bind_ipv4_only = 1;
+ cfg->ipv4_traffic = 1;
smartlist_add(out, cfg);
}
@@ -5750,6 +4789,7 @@ parse_port_config(smartlist_t *out,
cfg->session_group = SESSION_GROUP_UNSET;
cfg->isolation_flags = ISO_DEFAULT;
cfg->no_advertise = 1;
+ cfg->ipv4_traffic = 1;
smartlist_add(out, cfg);
}
}
@@ -5773,6 +4813,7 @@ parse_port_config(smartlist_t *out,
tor_addr_parse(&cfg->addr, defaultaddr);
cfg->session_group = SESSION_GROUP_UNSET;
cfg->isolation_flags = ISO_DEFAULT;
+ cfg->ipv4_traffic = 1;
smartlist_add(out, cfg);
}
return 0;
@@ -5792,7 +4833,8 @@ parse_port_config(smartlist_t *out,
uint16_t ptmp=0;
int ok;
int no_listen = 0, no_advertise = 0, all_addrs = 0,
- ipv4_only = 0, ipv6_only = 0;
+ bind_ipv4_only = 0, bind_ipv6_only = 0,
+ ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0;
smartlist_split_string(elts, ports->value, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
@@ -5857,9 +4899,9 @@ parse_port_config(smartlist_t *out,
all_addrs = 1;
#endif
} else if (!strcasecmp(elt, "IPv4Only")) {
- ipv4_only = 1;
+ bind_ipv4_only = 1;
} else if (!strcasecmp(elt, "IPv6Only")) {
- ipv6_only = 1;
+ bind_ipv6_only = 1;
} else {
log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'",
portname, escaped(elt));
@@ -5872,18 +4914,18 @@ parse_port_config(smartlist_t *out,
portname, escaped(ports->value));
goto err;
}
- if (ipv4_only && ipv6_only) {
+ if (bind_ipv4_only && bind_ipv6_only) {
log_warn(LD_CONFIG, "Tried to set both IPv4Only and IPv6Only "
"on %sPort line '%s'",
portname, escaped(ports->value));
goto err;
}
- if (ipv4_only && tor_addr_family(&addr) == AF_INET6) {
+ if (bind_ipv4_only && tor_addr_family(&addr) == AF_INET6) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
portname);
goto err;
}
- if (ipv6_only && tor_addr_family(&addr) == AF_INET) {
+ if (bind_ipv6_only && tor_addr_family(&addr) == AF_INET) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
portname);
goto err;
@@ -5916,6 +4958,20 @@ parse_port_config(smartlist_t *out,
no = 1;
elt += 2;
}
+
+ if (takes_hostnames) {
+ if (!strcasecmp(elt, "IPv4Traffic")) {
+ ipv4_traffic = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "IPv6Traffic")) {
+ ipv6_traffic = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "PreferIPv6")) {
+ prefer_ipv6 = ! no;
+ continue;
+ }
+ }
+
if (!strcasecmpend(elt, "s"))
elt[strlen(elt)-1] = '\0'; /* kill plurals. */
@@ -5947,6 +5003,12 @@ parse_port_config(smartlist_t *out,
else
got_zero_port = 1;
+ if (ipv4_traffic == 0 && ipv6_traffic == 0) {
+ log_warn(LD_CONFIG, "You have a %sPort entry with both IPv4 and "
+ "IPv6 disabled; that won't work.", portname);
+ goto err;
+ }
+
if (out && port) {
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
tor_addr_copy(&cfg->addr, &addr);
@@ -5957,8 +5019,11 @@ parse_port_config(smartlist_t *out,
cfg->no_advertise = no_advertise;
cfg->no_listen = no_listen;
cfg->all_addrs = all_addrs;
- cfg->ipv4_only = ipv4_only;
- cfg->ipv6_only = ipv6_only;
+ cfg->bind_ipv4_only = bind_ipv4_only;
+ cfg->bind_ipv6_only = bind_ipv6_only;
+ cfg->ipv4_traffic = ipv4_traffic;
+ cfg->ipv6_traffic = ipv6_traffic;
+ cfg->prefer_ipv6 = prefer_ipv6;
smartlist_add(out, cfg);
}
@@ -6051,7 +5116,8 @@ parse_ports(or_options_t *options, int validate_only,
options->SocksPort_lines, options->SocksListenAddress,
"Socks", CONN_TYPE_AP_LISTENER,
"127.0.0.1", 9050,
- CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR) < 0) {
+ CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR|
+ CL_PORT_TAKES_HOSTNAMES) < 0) {
*msg = tor_strdup("Invalid SocksPort/SocksListenAddress configuration");
goto err;
}
@@ -6191,7 +5257,8 @@ check_server_ports(const smartlist_t *ports,
if (! port->no_advertise) {
++n_orport_advertised;
if (tor_addr_family(&port->addr) == AF_INET ||
- (tor_addr_family(&port->addr) == AF_UNSPEC && !port->ipv6_only))
+ (tor_addr_family(&port->addr) == AF_UNSPEC &&
+ !port->bind_ipv6_only))
++n_orport_advertised_ipv4;
}
if (! port->no_listen)
@@ -6200,7 +5267,7 @@ check_server_ports(const smartlist_t *ports,
continue;
}
#ifndef _WIN32
- if (!port->no_advertise && port->port < 1024)
+ if (!port->no_listen && port->port < 1024)
++n_low_port;
#endif
} SMARTLIST_FOREACH_END(port);
@@ -6321,8 +5388,8 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family)
(tor_addr_family(&cfg->addr) == address_family ||
tor_addr_family(&cfg->addr) == AF_UNSPEC)) {
if (tor_addr_family(&cfg->addr) != AF_UNSPEC ||
- (address_family == AF_INET && !cfg->ipv6_only) ||
- (address_family == AF_INET6 && !cfg->ipv4_only)) {
+ (address_family == AF_INET && !cfg->bind_ipv6_only) ||
+ (address_family == AF_INET6 && !cfg->bind_ipv4_only)) {
return cfg->port;
}
}
@@ -6483,180 +5550,6 @@ options_save_current(void)
return write_configuration_file(get_torrc_fname(0), get_options());
}
-/** Mapping from a unit name to a multiplier for converting that unit into a
- * base unit. Used by config_parse_unit. */
-struct unit_table_t {
- const char *unit; /**< The name of the unit */
- uint64_t multiplier; /**< How many of the base unit appear in this unit */
-};
-
-/** Table to map the names of memory units to the number of bytes they
- * contain. */
-static struct unit_table_t memory_units[] = {
- { "", 1 },
- { "b", 1<< 0 },
- { "byte", 1<< 0 },
- { "bytes", 1<< 0 },
- { "kb", 1<<10 },
- { "kbyte", 1<<10 },
- { "kbytes", 1<<10 },
- { "kilobyte", 1<<10 },
- { "kilobytes", 1<<10 },
- { "m", 1<<20 },
- { "mb", 1<<20 },
- { "mbyte", 1<<20 },
- { "mbytes", 1<<20 },
- { "megabyte", 1<<20 },
- { "megabytes", 1<<20 },
- { "gb", 1<<30 },
- { "gbyte", 1<<30 },
- { "gbytes", 1<<30 },
- { "gigabyte", 1<<30 },
- { "gigabytes", 1<<30 },
- { "tb", U64_LITERAL(1)<<40 },
- { "terabyte", U64_LITERAL(1)<<40 },
- { "terabytes", U64_LITERAL(1)<<40 },
- { NULL, 0 },
-};
-
-/** Table to map the names of time units to the number of seconds they
- * contain. */
-static struct unit_table_t time_units[] = {
- { "", 1 },
- { "second", 1 },
- { "seconds", 1 },
- { "minute", 60 },
- { "minutes", 60 },
- { "hour", 60*60 },
- { "hours", 60*60 },
- { "day", 24*60*60 },
- { "days", 24*60*60 },
- { "week", 7*24*60*60 },
- { "weeks", 7*24*60*60 },
- { NULL, 0 },
-};
-
-/** Table to map the names of time units to the number of milliseconds
- * they contain. */
-static struct unit_table_t time_msec_units[] = {
- { "", 1 },
- { "msec", 1 },
- { "millisecond", 1 },
- { "milliseconds", 1 },
- { "second", 1000 },
- { "seconds", 1000 },
- { "minute", 60*1000 },
- { "minutes", 60*1000 },
- { "hour", 60*60*1000 },
- { "hours", 60*60*1000 },
- { "day", 24*60*60*1000 },
- { "days", 24*60*60*1000 },
- { "week", 7*24*60*60*1000 },
- { "weeks", 7*24*60*60*1000 },
- { NULL, 0 },
-};
-
-/** Parse a string <b>val</b> containing a number, zero or more
- * spaces, and an optional unit string. If the unit appears in the
- * table <b>u</b>, then multiply the number by the unit multiplier.
- * On success, set *<b>ok</b> to 1 and return this product.
- * Otherwise, set *<b>ok</b> to 0.
- */
-static uint64_t
-config_parse_units(const char *val, struct unit_table_t *u, int *ok)
-{
- uint64_t v = 0;
- double d = 0;
- int use_float = 0;
- char *cp;
-
- tor_assert(ok);
-
- v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp);
- if (!*ok || (cp && *cp == '.')) {
- d = tor_parse_double(val, 0, UINT64_MAX, ok, &cp);
- if (!*ok)
- goto done;
- use_float = 1;
- }
-
- if (!cp) {
- *ok = 1;
- v = use_float ? DBL_TO_U64(d) : v;
- goto done;
- }
-
- cp = (char*) eat_whitespace(cp);
-
- for ( ;u->unit;++u) {
- if (!strcasecmp(u->unit, cp)) {
- if (use_float)
- v = u->multiplier * d;
- else
- v *= u->multiplier;
- *ok = 1;
- goto done;
- }
- }
- log_warn(LD_CONFIG, "Unknown unit '%s'.", cp);
- *ok = 0;
- done:
-
- if (*ok)
- return v;
- else
- return 0;
-}
-
-/** Parse a string in the format "number unit", where unit is a unit of
- * information (byte, KB, M, etc). On success, set *<b>ok</b> to true
- * and return the number of bytes specified. Otherwise, set
- * *<b>ok</b> to false and return 0. */
-static uint64_t
-config_parse_memunit(const char *s, int *ok)
-{
- uint64_t u = config_parse_units(s, memory_units, ok);
- return u;
-}
-
-/** Parse a string in the format "number unit", where unit is a unit of
- * time in milliseconds. On success, set *<b>ok</b> to true and return
- * the number of milliseconds in the provided interval. Otherwise, set
- * *<b>ok</b> to 0 and return -1. */
-static int
-config_parse_msec_interval(const char *s, int *ok)
-{
- uint64_t r;
- r = config_parse_units(s, time_msec_units, ok);
- if (!ok)
- return -1;
- if (r > INT_MAX) {
- log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
- *ok = 0;
- return -1;
- }
- return (int)r;
-}
-
-/** Parse a string in the format "number unit", where unit is a unit of time.
- * On success, set *<b>ok</b> to true and return the number of seconds in
- * the provided interval. Otherwise, set *<b>ok</b> to 0 and return -1.
- */
-static int
-config_parse_interval(const char *s, int *ok)
-{
- uint64_t r;
- r = config_parse_units(s, time_units, ok);
- if (!ok)
- return -1;
- if (r > INT_MAX) {
- log_warn(LD_CONFIG, "Interval '%s' is too long", s);
- *ok = 0;
- return -1;
- }
- return (int)r;
-}
-
/** Return the number of cpus configured in <b>options</b>. If we are
* told to auto-detect the number of cpus, return the auto-detected number. */
int
@@ -6710,14 +5603,6 @@ init_libevent(const or_options_t *options)
}
}
-/** Return the persistent state struct for this Tor. */
-or_state_t *
-get_or_state(void)
-{
- tor_assert(global_state);
- return global_state;
-}
-
/** Return a newly allocated string holding a filename relative to the data
* directory. If <b>sub1</b> is present, it is the first path component after
* the data directory. If <b>sub2</b> is also present, it is the second path
@@ -6768,474 +5653,6 @@ options_get_datadir_fname2_suffix(const or_options_t *options,
return fname;
}
-/** Return true if <b>line</b> is a valid state TransportProxy line.
- * Return false otherwise. */
-static int
-state_transport_line_is_valid(const char *line)
-{
- smartlist_t *items = NULL;
- char *addrport=NULL;
- tor_addr_t addr;
- uint16_t port = 0;
- int r;
-
- items = smartlist_new();
- smartlist_split_string(items, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
-
- if (smartlist_len(items) != 2) {
- log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line.");
- goto err;
- }
-
- addrport = smartlist_get(items, 1);
- if (tor_addr_port_lookup(addrport, &addr, &port) < 0) {
- log_warn(LD_CONFIG, "state: Could not parse addrport.");
- goto err;
- }
-
- if (!port) {
- log_warn(LD_CONFIG, "state: Transport line did not contain port.");
- goto err;
- }
-
- r = 1;
- goto done;
-
- err:
- r = 0;
-
- done:
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- return r;
-}
-
-/** Return 0 if all TransportProxy lines in <b>state</b> are well
- * formed. Otherwise, return -1. */
-static int
-validate_transports_in_state(or_state_t *state)
-{
- int broken = 0;
- config_line_t *line;
-
- for (line = state->TransportProxies ; line ; line = line->next) {
- tor_assert(!strcmp(line->key, "TransportProxy"));
- if (!state_transport_line_is_valid(line->value))
- broken = 1;
- }
-
- if (broken)
- log_warn(LD_CONFIG, "state: State file seems to be broken.");
-
- return 0;
-}
-
-/** Return 0 if every setting in <b>state</b> is reasonable, and a
- * permissible transition from <b>old_state</b>. Else warn and return -1.
- * Should have no side effects, except for normalizing the contents of
- * <b>state</b>.
- */
-/* XXX from_setconf is here because of bug 238 */
-static int
-or_state_validate(or_state_t *old_state, or_state_t *state,
- int from_setconf, char **msg)
-{
- /* We don't use these; only options do. Still, we need to match that
- * signature. */
- (void) from_setconf;
- (void) old_state;
-
- if (entry_guards_parse_state(state, 0, msg)<0)
- return -1;
-
- if (validate_transports_in_state(state)<0)
- return -1;
-
- return 0;
-}
-
-/** Replace the current persistent state with <b>new_state</b> */
-static int
-or_state_set(or_state_t *new_state)
-{
- char *err = NULL;
- int ret = 0;
- tor_assert(new_state);
- config_free(&state_format, global_state);
- global_state = new_state;
- if (entry_guards_parse_state(global_state, 1, &err)<0) {
- log_warn(LD_GENERAL,"%s",err);
- tor_free(err);
- ret = -1;
- }
- if (rep_hist_load_state(global_state, &err)<0) {
- log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
- tor_free(err);
- ret = -1;
- }
- if (circuit_build_times_parse_state(&circ_times, global_state) < 0) {
- ret = -1;
- }
- return ret;
-}
-
-/**
- * Save a broken state file to a backup location.
- */
-static void
-or_state_save_broken(char *fname)
-{
- int i;
- file_status_t status;
- char *fname2 = NULL;
- for (i = 0; i < 100; ++i) {
- tor_asprintf(&fname2, "%s.%d", fname, i);
- status = file_status(fname2);
- if (status == FN_NOENT)
- break;
- tor_free(fname2);
- }
- if (i == 100) {
- log_warn(LD_BUG, "Unable to parse state in \"%s\"; too many saved bad "
- "state files to move aside. Discarding the old state file.",
- fname);
- unlink(fname);
- } else {
- log_warn(LD_BUG, "Unable to parse state in \"%s\". Moving it aside "
- "to \"%s\". This could be a bug in Tor; please tell "
- "the developers.", fname, fname2);
- if (rename(fname, fname2) < 0) {
- log_warn(LD_BUG, "Weirdly, I couldn't even move the state aside. The "
- "OS gave an error of %s", strerror(errno));
- }
- }
- tor_free(fname2);
-}
-
-/** Reload the persistent state from disk, generating a new state as needed.
- * Return 0 on success, less than 0 on failure.
- */
-static int
-or_state_load(void)
-{
- or_state_t *new_state = NULL;
- char *contents = NULL, *fname;
- char *errmsg = NULL;
- int r = -1, badstate = 0;
-
- fname = get_datadir_fname("state");
- switch (file_status(fname)) {
- case FN_FILE:
- if (!(contents = read_file_to_str(fname, 0, NULL))) {
- log_warn(LD_FS, "Unable to read state file \"%s\"", fname);
- goto done;
- }
- break;
- case FN_NOENT:
- break;
- case FN_ERROR:
- case FN_DIR:
- default:
- log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname);
- goto done;
- }
- new_state = tor_malloc_zero(sizeof(or_state_t));
- new_state->_magic = OR_STATE_MAGIC;
- config_init(&state_format, new_state);
- if (contents) {
- config_line_t *lines=NULL;
- int assign_retval;
- if (config_get_lines(contents, &lines, 0)<0)
- goto done;
- assign_retval = config_assign(&state_format, new_state,
- lines, 0, 0, &errmsg);
- config_free_lines(lines);
- if (assign_retval<0)
- badstate = 1;
- if (errmsg) {
- log_warn(LD_GENERAL, "%s", errmsg);
- tor_free(errmsg);
- }
- }
-
- if (!badstate && or_state_validate(NULL, new_state, 1, &errmsg) < 0)
- badstate = 1;
-
- if (errmsg) {
- log_warn(LD_GENERAL, "%s", errmsg);
- tor_free(errmsg);
- }
-
- if (badstate && !contents) {
- log_warn(LD_BUG, "Uh oh. We couldn't even validate our own default state."
- " This is a bug in Tor.");
- goto done;
- } else if (badstate && contents) {
- or_state_save_broken(fname);
-
- tor_free(contents);
- config_free(&state_format, new_state);
-
- new_state = tor_malloc_zero(sizeof(or_state_t));
- new_state->_magic = OR_STATE_MAGIC;
- config_init(&state_format, new_state);
- } else if (contents) {
- log_info(LD_GENERAL, "Loaded state from \"%s\"", fname);
- } else {
- log_info(LD_GENERAL, "Initialized state");
- }
- if (or_state_set(new_state) == -1) {
- or_state_save_broken(fname);
- }
- new_state = NULL;
- if (!contents) {
- global_state->next_write = 0;
- or_state_save(time(NULL));
- }
- r = 0;
-
- done:
- tor_free(fname);
- tor_free(contents);
- if (new_state)
- config_free(&state_format, new_state);
-
- return r;
-}
-
-/** Did the last time we tried to write the state file fail? If so, we
- * should consider disabling such features as preemptive circuit generation
- * to compute circuit-build-time. */
-static int last_state_file_write_failed = 0;
-
-/** Return whether the state file failed to write last time we tried. */
-int
-did_last_state_file_write_fail(void)
-{
- return last_state_file_write_failed;
-}
-
-/** If writing the state to disk fails, try again after this many seconds. */
-#define STATE_WRITE_RETRY_INTERVAL 3600
-
-/** If we're a relay, how often should we checkpoint our state file even
- * if nothing else dirties it? This will checkpoint ongoing stats like
- * bandwidth used, per-country user stats, etc. */
-#define STATE_RELAY_CHECKPOINT_INTERVAL (12*60*60)
-
-/** Write the persistent state to disk. Return 0 for success, <0 on failure. */
-int
-or_state_save(time_t now)
-{
- char *state, *contents;
- char tbuf[ISO_TIME_LEN+1];
- char *fname;
-
- tor_assert(global_state);
-
- if (global_state->next_write > now)
- return 0;
-
- /* Call everything else that might dirty the state even more, in order
- * to avoid redundant writes. */
- entry_guards_update_state(global_state);
- rep_hist_update_state(global_state);
- circuit_build_times_update_state(&circ_times, global_state);
- if (accounting_is_enabled(get_options()))
- accounting_run_housekeeping(now);
-
- global_state->LastWritten = now;
-
- tor_free(global_state->TorVersion);
- tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
-
- state = config_dump(&state_format, NULL, global_state, 1, 0);
- format_local_iso_time(tbuf, now);
- tor_asprintf(&contents,
- "# Tor state file last generated on %s local time\n"
- "# Other times below are in GMT\n"
- "# You *do not* need to edit this file.\n\n%s",
- tbuf, state);
- tor_free(state);
- fname = get_datadir_fname("state");
- if (write_str_to_file(fname, contents, 0)<0) {
- log_warn(LD_FS, "Unable to write state to file \"%s\"; "
- "will try again later", fname);
- last_state_file_write_failed = 1;
- tor_free(fname);
- tor_free(contents);
- /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state
- * changes sooner). */
- global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL;
- return -1;
- }
-
- last_state_file_write_failed = 0;
- log_info(LD_GENERAL, "Saved state to \"%s\"", fname);
- tor_free(fname);
- tor_free(contents);
-
- if (server_mode(get_options()))
- global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL;
- else
- global_state->next_write = TIME_MAX;
-
- return 0;
-}
-
-/** Return the config line for transport <b>transport</b> in the current state.
- * Return NULL if there is no config line for <b>transport</b>. */
-static config_line_t *
-get_transport_in_state_by_name(const char *transport)
-{
- or_state_t *or_state = get_or_state();
- config_line_t *line;
- config_line_t *ret = NULL;
- smartlist_t *items = NULL;
-
- for (line = or_state->TransportProxies ; line ; line = line->next) {
- tor_assert(!strcmp(line->key, "TransportProxy"));
-
- items = smartlist_new();
- smartlist_split_string(items, line->value, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
- if (smartlist_len(items) != 2) /* broken state */
- goto done;
-
- if (!strcmp(smartlist_get(items, 0), transport)) {
- ret = line;
- goto done;
- }
-
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- items = NULL;
- }
-
- done:
- if (items) {
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- }
- return ret;
-}
-
-/** Return string containing the address:port part of the
- * TransportProxy <b>line</b> for transport <b>transport</b>.
- * If the line is corrupted, return NULL. */
-static const char *
-get_transport_bindaddr(const char *line, const char *transport)
-{
- char *line_tmp = NULL;
-
- if (strlen(line) < strlen(transport) + 2) {
- goto broken_state;
- } else {
- /* line should start with the name of the transport and a space.
- (for example, "obfs2 127.0.0.1:47245") */
- tor_asprintf(&line_tmp, "%s ", transport);
- if (strcmpstart(line, line_tmp))
- goto broken_state;
-
- tor_free(line_tmp);
- return (line+strlen(transport)+1);
- }
-
- broken_state:
- tor_free(line_tmp);
- return NULL;
-}
-
-/** Return a string containing the address:port that a proxy transport
- * should bind on. The string is stored on the heap and must be freed
- * by the caller of this function. */
-char *
-get_stored_bindaddr_for_server_transport(const char *transport)
-{
- char *default_addrport = NULL;
- const char *stored_bindaddr = NULL;
-
- config_line_t *line = get_transport_in_state_by_name(transport);
- if (!line) /* Found no references in state for this transport. */
- goto no_bindaddr_found;
-
- stored_bindaddr = get_transport_bindaddr(line->value, transport);
- if (stored_bindaddr) /* found stored bindaddr in state file. */
- return tor_strdup(stored_bindaddr);
-
- no_bindaddr_found:
- /** If we didn't find references for this pluggable transport in the
- state file, we should instruct the pluggable transport proxy to
- listen on INADDR_ANY on a random ephemeral port. */
- tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0");
- return default_addrport;
-}
-
-/** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to
- state */
-void
-save_transport_to_state(const char *transport,
- const tor_addr_t *addr, uint16_t port)
-{
- or_state_t *state = get_or_state();
-
- char *transport_addrport=NULL;
-
- /** find where to write on the state */
- config_line_t **next, *line;
-
- /* see if this transport is already stored in state */
- config_line_t *transport_line =
- get_transport_in_state_by_name(transport);
-
- if (transport_line) { /* if transport already exists in state... */
- const char *prev_bindaddr = /* get its addrport... */
- get_transport_bindaddr(transport_line->value, transport);
- tor_asprintf(&transport_addrport, "%s:%d", fmt_addr(addr), (int)port);
-
- /* if transport in state has the same address as this one, life is good */
- if (!strcmp(prev_bindaddr, transport_addrport)) {
- log_info(LD_CONFIG, "Transport seems to have spawned on its usual "
- "address:port.");
- goto done;
- } else { /* if addrport in state is different than the one we got */
- log_info(LD_CONFIG, "Transport seems to have spawned on different "
- "address:port. Let's update the state file with the new "
- "address:port");
- tor_free(transport_line->value); /* free the old line */
- tor_asprintf(&transport_line->value, "%s %s:%d", transport,
- fmt_addr(addr),
- (int) port); /* replace old addrport line with new line */
- }
- } else { /* never seen this one before; save it in state for next time */
- log_info(LD_CONFIG, "It's the first time we see this transport. "
- "Let's save its address:port");
- next = &state->TransportProxies;
- /* find the last TransportProxy line in the state and point 'next'
- right after it */
- line = state->TransportProxies;
- while (line) {
- next = &(line->next);
- line = line->next;
- }
-
- /* allocate space for the new line and fill it in */
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("TransportProxy");
- tor_asprintf(&line->value, "%s %s:%d", transport,
- fmt_addr(addr), (int) port);
-
- next = &(line->next);
- }
-
- if (!get_options()->AvoidDiskWrites)
- or_state_mark_dirty(state, 0);
-
- done:
- tor_free(transport_addrport);
-}
-
/** Given a file name check to see whether the file exists but has not been
* modified for a very long time. If so, remove it. */
void
@@ -7253,6 +5670,43 @@ remove_file_if_very_old(const char *fname, time_t now)
}
}
+/** Return a smartlist of ports that must be forwarded by
+ * tor-fw-helper. The smartlist contains the ports in a string format
+ * that is understandable by tor-fw-helper. */
+smartlist_t *
+get_list_of_ports_to_forward(void)
+{
+ smartlist_t *ports_to_forward = smartlist_new();
+ int port = 0;
+
+ /** XXX TODO tor-fw-helper does not support forwarding ports to
+ other hosts than the local one. If the user is binding to a
+ different IP address, tor-fw-helper won't work. */
+ port = router_get_advertised_or_port(get_options()); /* Get ORPort */
+ if (port)
+ smartlist_add_asprintf(ports_to_forward, "%d:%d", port, port);
+
+ port = router_get_advertised_dir_port(get_options(), 0); /* Get DirPort */
+ if (port)
+ smartlist_add_asprintf(ports_to_forward, "%d:%d", port, port);
+
+ /* Get ports of transport proxies */
+ {
+ smartlist_t *transport_ports = get_transport_proxy_ports();
+ if (transport_ports) {
+ smartlist_add_all(ports_to_forward, transport_ports);
+ smartlist_free(transport_ports);
+ }
+ }
+
+ if (!smartlist_len(ports_to_forward)) {
+ smartlist_free(ports_to_forward);
+ ports_to_forward = NULL;
+ }
+
+ return ports_to_forward;
+}
+
/** Helper to implement GETINFO functions about configuration variables (not
* their values). Given a "config/names" question, set *<b>answer</b> to a
* new string describing the supported configuration variables and their
@@ -7267,9 +5721,12 @@ getinfo_helper_config(control_connection_t *conn,
if (!strcmp(question, "config/names")) {
smartlist_t *sl = smartlist_new();
int i;
- for (i = 0; _option_vars[i].name; ++i) {
- const config_var_t *var = &_option_vars[i];
+ for (i = 0; option_vars_[i].name; ++i) {
+ const config_var_t *var = &option_vars_[i];
const char *type;
+ /* don't tell controller about triple-underscore options */
+ if (!strncmp(option_vars_[i].name, "___", 3))
+ continue;
switch (var->type) {
case CONFIG_TYPE_STRING: type = "String"; break;
case CONFIG_TYPE_FILENAME: type = "Filename"; break;
@@ -7299,7 +5756,120 @@ getinfo_helper_config(control_connection_t *conn,
*answer = smartlist_join_strings(sl, "", 0, NULL);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
+ } else if (!strcmp(question, "config/defaults")) {
+ smartlist_t *sl = smartlist_new();
+ int i;
+ for (i = 0; option_vars_[i].name; ++i) {
+ const config_var_t *var = &option_vars_[i];
+ if (var->initvalue != NULL) {
+ char *val = esc_for_log(var->initvalue);
+ smartlist_add_asprintf(sl, "%s %s\n",var->name,val);
+ tor_free(val);
+ }
+ }
+ *answer = smartlist_join_strings(sl, "", 0, NULL);
+ SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
+ smartlist_free(sl);
}
return 0;
}
+/** Parse outbound bind address option lines. If <b>validate_only</b>
+ * is not 0 update OutboundBindAddressIPv4_ and
+ * OutboundBindAddressIPv6_ in <b>options</b>. On failure, set
+ * <b>msg</b> (if provided) to a newly allocated string containing a
+ * description of the problem and return -1. */
+static int
+parse_outbound_addresses(or_options_t *options, int validate_only, char **msg)
+{
+ const config_line_t *lines = options->OutboundBindAddress;
+ int found_v4 = 0, found_v6 = 0;
+
+ if (!validate_only) {
+ memset(&options->OutboundBindAddressIPv4_, 0,
+ sizeof(options->OutboundBindAddressIPv4_));
+ memset(&options->OutboundBindAddressIPv6_, 0,
+ sizeof(options->OutboundBindAddressIPv6_));
+ }
+ while (lines) {
+ tor_addr_t addr, *dst_addr = NULL;
+ int af = tor_addr_parse(&addr, lines->value);
+ switch (af) {
+ case AF_INET:
+ if (found_v4) {
+ if (msg)
+ tor_asprintf(msg, "Multiple IPv4 outbound bind addresses "
+ "configured: %s", lines->value);
+ return -1;
+ }
+ found_v4 = 1;
+ dst_addr = &options->OutboundBindAddressIPv4_;
+ break;
+ case AF_INET6:
+ if (found_v6) {
+ if (msg)
+ tor_asprintf(msg, "Multiple IPv6 outbound bind addresses "
+ "configured: %s", lines->value);
+ return -1;
+ }
+ found_v6 = 1;
+ dst_addr = &options->OutboundBindAddressIPv6_;
+ break;
+ default:
+ if (msg)
+ tor_asprintf(msg, "Outbound bind address '%s' didn't parse.",
+ lines->value);
+ return -1;
+ }
+ if (!validate_only)
+ tor_addr_copy(dst_addr, &addr);
+ lines = lines->next;
+ }
+ return 0;
+}
+
+/** Load one of the geoip files, <a>family</a> determining which
+ * one. <a>default_fname</a> is used if on Windows and
+ * <a>fname</a> equals "<default>". */
+static void
+config_load_geoip_file_(sa_family_t family,
+ const char *fname,
+ const char *default_fname)
+{
+#ifdef _WIN32
+ char *free_fname = NULL; /* Used to hold any temporary-allocated value */
+ /* XXXX Don't use this "<default>" junk; make our filename options
+ * understand prefixes somehow. -NM */
+ if (!strcmp(fname, "<default>")) {
+ const char *conf_root = get_windows_conf_root();
+ tor_asprintf(&free_fname, "%s\\%s", conf_root, default_fname);
+ fname = free_fname;
+ }
+ geoip_load_file(family, fname);
+ tor_free(free_fname);
+#else
+ (void)default_fname;
+ geoip_load_file(family, fname);
+#endif
+}
+
+/** Load geoip files for IPv4 and IPv6 if <a>options</a> and
+ * <a>old_options</a> indicate we should. */
+static void
+config_maybe_load_geoip_files_(const or_options_t *options,
+ const or_options_t *old_options)
+{
+ /* XXXX024 Reload GeoIPFile on SIGHUP. -NM */
+
+ if (options->GeoIPFile &&
+ ((!old_options || !opt_streq(old_options->GeoIPFile,
+ options->GeoIPFile))
+ || !geoip_is_loaded(AF_INET)))
+ config_load_geoip_file_(AF_INET, options->GeoIPFile, "geoip");
+ if (options->GeoIPv6File &&
+ ((!old_options || !opt_streq(old_options->GeoIPv6File,
+ options->GeoIPv6File))
+ || !geoip_is_loaded(AF_INET6)))
+ config_load_geoip_file_(AF_INET6, options->GeoIPv6File, "geoip6");
+}
+
diff --git a/src/or/config.h b/src/or/config.h
index dd76edcf1d..336685d075 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -9,8 +9,8 @@
* \brief Header file for config.c.
**/
-#ifndef _TOR_CONFIG_H
-#define _TOR_CONFIG_H
+#ifndef TOR_CONFIG_H
+#define TOR_CONFIG_H
const char *get_dirportfrontpage(void);
const or_options_t *get_options(void);
@@ -23,11 +23,9 @@ const char *escaped_safe_str_client(const char *address);
const char *escaped_safe_str(const char *address);
const char *get_version(void);
const char *get_short_version(void);
-
-int config_get_lines(const char *string, config_line_t **result, int extended);
-void config_free_lines(config_line_t *front);
setopt_err_t options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg);
+
int resolve_my_address(int warn_severity, const or_options_t *options,
uint32_t *addr, char **hostname_out);
int is_local_addr(const tor_addr_t *addr);
@@ -61,10 +59,6 @@ char *options_get_datadir_fname2_suffix(const or_options_t *options,
int get_num_cpus(const or_options_t *options);
-or_state_t *get_or_state(void);
-int did_last_state_file_write_fail(void);
-int or_state_save(time_t now);
-
const smartlist_t *get_configured_ports(void);
int get_first_advertised_port_by_type_af(int listener_type,
int address_family);
@@ -78,9 +72,7 @@ char *get_first_listener_addrport_string(int listener_type);
int options_need_geoip_info(const or_options_t *options,
const char **reason_out);
-void save_transport_to_state(const char *transport_name,
- const tor_addr_t *addr, uint16_t port);
-char *get_stored_bindaddr_for_server_transport(const char *transport);
+smartlist_t *get_list_of_ports_to_forward(void);
int getinfo_helper_config(control_connection_t *conn,
const char *question, char **answer,
@@ -90,6 +82,8 @@ const char *tor_get_digests(void);
uint32_t get_effective_bwrate(const or_options_t *options);
uint32_t get_effective_bwburst(const or_options_t *options);
+char *get_transport_bindaddr_from_config(const char *transport);
+
#ifdef CONFIG_PRIVATE
/* Used only by config.c and test.c */
or_options_t *options_new(void);
diff --git a/src/or/confparse.c b/src/or/confparse.c
new file mode 100644
index 0000000000..67cf43fe8c
--- /dev/null
+++ b/src/or/confparse.c
@@ -0,0 +1,1226 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "confparse.h"
+#include "routerset.h"
+
+static uint64_t config_parse_memunit(const char *s, int *ok);
+static int config_parse_msec_interval(const char *s, int *ok);
+static int config_parse_interval(const char *s, int *ok);
+static void config_reset(const config_format_t *fmt, void *options,
+ const config_var_t *var, int use_defaults);
+
+/** Allocate an empty configuration object of a given format type. */
+void *
+config_new(const config_format_t *fmt)
+{
+ void *opts = tor_malloc_zero(fmt->size);
+ *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
+ CONFIG_CHECK(fmt, opts);
+ return opts;
+}
+
+/*
+ * Functions to parse config options
+ */
+
+/** If <b>option</b> is an official abbreviation for a longer option,
+ * return the longer option. Otherwise return <b>option</b>.
+ * If <b>command_line</b> is set, apply all abbreviations. Otherwise, only
+ * apply abbreviations that work for the config file and the command line.
+ * If <b>warn_obsolete</b> is set, warn about deprecated names. */
+const char *
+config_expand_abbrev(const config_format_t *fmt, const char *option,
+ int command_line, int warn_obsolete)
+{
+ int i;
+ if (! fmt->abbrevs)
+ return option;
+ for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
+ /* Abbreviations are case insensitive. */
+ if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
+ (command_line || !fmt->abbrevs[i].commandline_only)) {
+ if (warn_obsolete && fmt->abbrevs[i].warn) {
+ log_warn(LD_CONFIG,
+ "The configuration option '%s' is deprecated; "
+ "use '%s' instead.",
+ fmt->abbrevs[i].abbreviated,
+ fmt->abbrevs[i].full);
+ }
+ /* Keep going through the list in case we want to rewrite it more.
+ * (We could imagine recursing here, but I don't want to get the
+ * user into an infinite loop if we craft our list wrong.) */
+ option = fmt->abbrevs[i].full;
+ }
+ }
+ return option;
+}
+
+/** Helper: allocate a new configuration option mapping 'key' to 'val',
+ * append it to *<b>lst</b>. */
+void
+config_line_append(config_line_t **lst,
+ const char *key,
+ const char *val)
+{
+ config_line_t *newline;
+
+ newline = tor_malloc_zero(sizeof(config_line_t));
+ newline->key = tor_strdup(key);
+ newline->value = tor_strdup(val);
+ newline->next = NULL;
+ while (*lst)
+ lst = &((*lst)->next);
+
+ (*lst) = newline;
+}
+
+/** Helper: parse the config string and strdup into key/value
+ * strings. Set *result to the list, or NULL if parsing the string
+ * failed. Return 0 on success, -1 on failure. Warn and ignore any
+ * misformatted lines.
+ *
+ * If <b>extended</b> is set, then treat keys beginning with / and with + as
+ * indicating "clear" and "append" respectively. */
+int
+config_get_lines(const char *string, config_line_t **result, int extended)
+{
+ config_line_t *list = NULL, **next;
+ char *k, *v;
+
+ next = &list;
+ do {
+ k = v = NULL;
+ string = parse_config_line_from_str(string, &k, &v);
+ if (!string) {
+ config_free_lines(list);
+ tor_free(k);
+ tor_free(v);
+ return -1;
+ }
+ if (k && v) {
+ unsigned command = CONFIG_LINE_NORMAL;
+ if (extended) {
+ if (k[0] == '+') {
+ char *k_new = tor_strdup(k+1);
+ tor_free(k);
+ k = k_new;
+ command = CONFIG_LINE_APPEND;
+ } else if (k[0] == '/') {
+ char *k_new = tor_strdup(k+1);
+ tor_free(k);
+ k = k_new;
+ tor_free(v);
+ v = tor_strdup("");
+ command = CONFIG_LINE_CLEAR;
+ }
+ }
+ /* This list can get long, so we keep a pointer to the end of it
+ * rather than using config_line_append over and over and getting
+ * n^2 performance. */
+ *next = tor_malloc_zero(sizeof(config_line_t));
+ (*next)->key = k;
+ (*next)->value = v;
+ (*next)->next = NULL;
+ (*next)->command = command;
+ next = &((*next)->next);
+ } else {
+ tor_free(k);
+ tor_free(v);
+ }
+ } while (*string);
+
+ *result = list;
+ return 0;
+}
+
+/**
+ * Free all the configuration lines on the linked list <b>front</b>.
+ */
+void
+config_free_lines(config_line_t *front)
+{
+ config_line_t *tmp;
+
+ while (front) {
+ tmp = front;
+ front = tmp->next;
+
+ tor_free(tmp->key);
+ tor_free(tmp->value);
+ tor_free(tmp);
+ }
+}
+
+/** As config_find_option, but return a non-const pointer. */
+config_var_t *
+config_find_option_mutable(config_format_t *fmt, const char *key)
+{
+ int i;
+ size_t keylen = strlen(key);
+ if (!keylen)
+ return NULL; /* if they say "--" on the command line, it's not an option */
+ /* First, check for an exact (case-insensitive) match */
+ for (i=0; fmt->vars[i].name; ++i) {
+ if (!strcasecmp(key, fmt->vars[i].name)) {
+ return &fmt->vars[i];
+ }
+ }
+ /* If none, check for an abbreviated match */
+ for (i=0; fmt->vars[i].name; ++i) {
+ if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
+ log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
+ "Please use '%s' instead",
+ key, fmt->vars[i].name);
+ return &fmt->vars[i];
+ }
+ }
+ /* Okay, unrecognized option */
+ return NULL;
+}
+
+/** If <b>key</b> is a configuration option, return the corresponding const
+ * config_var_t. Otherwise, if <b>key</b> is a non-standard abbreviation,
+ * warn, and return the corresponding const config_var_t. Otherwise return
+ * NULL.
+ */
+const config_var_t *
+config_find_option(const config_format_t *fmt, const char *key)
+{
+ return config_find_option_mutable((config_format_t*)fmt, key);
+}
+
+/** Return the number of option entries in <b>fmt</b>. */
+static int
+config_count_options(const config_format_t *fmt)
+{
+ int i;
+ for (i=0; fmt->vars[i].name; ++i)
+ ;
+ return i;
+}
+
+/*
+ * Functions to assign config options.
+ */
+
+/** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
+ * with <b>c</b>-\>value and return 0, or return -1 if bad value.
+ *
+ * Called from config_assign_line() and option_reset().
+ */
+static int
+config_assign_value(const config_format_t *fmt, void *options,
+ config_line_t *c, char **msg)
+{
+ int i, ok;
+ const config_var_t *var;
+ void *lvalue;
+
+ CONFIG_CHECK(fmt, options);
+
+ var = config_find_option(fmt, c->key);
+ tor_assert(var);
+
+ lvalue = STRUCT_VAR_P(options, var->var_offset);
+
+ switch (var->type) {
+
+ case CONFIG_TYPE_PORT:
+ if (!strcasecmp(c->value, "auto")) {
+ *(int *)lvalue = CFG_AUTO_PORT;
+ break;
+ }
+ /* fall through */
+ case CONFIG_TYPE_INT:
+ case CONFIG_TYPE_UINT:
+ i = (int)tor_parse_long(c->value, 10,
+ var->type==CONFIG_TYPE_INT ? INT_MIN : 0,
+ var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX,
+ &ok, NULL);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Int keyword '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ return -1;
+ }
+ *(int *)lvalue = i;
+ break;
+
+ case CONFIG_TYPE_INTERVAL: {
+ i = config_parse_interval(c->value, &ok);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Interval '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ return -1;
+ }
+ *(int *)lvalue = i;
+ break;
+ }
+
+ case CONFIG_TYPE_MSEC_INTERVAL: {
+ i = config_parse_msec_interval(c->value, &ok);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Msec interval '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ return -1;
+ }
+ *(int *)lvalue = i;
+ break;
+ }
+
+ case CONFIG_TYPE_MEMUNIT: {
+ uint64_t u64 = config_parse_memunit(c->value, &ok);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Value '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ return -1;
+ }
+ *(uint64_t *)lvalue = u64;
+ break;
+ }
+
+ case CONFIG_TYPE_BOOL:
+ i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Boolean '%s %s' expects 0 or 1.",
+ c->key, c->value);
+ return -1;
+ }
+ *(int *)lvalue = i;
+ break;
+
+ case CONFIG_TYPE_AUTOBOOL:
+ if (!strcmp(c->value, "auto"))
+ *(int *)lvalue = -1;
+ else if (!strcmp(c->value, "0"))
+ *(int *)lvalue = 0;
+ else if (!strcmp(c->value, "1"))
+ *(int *)lvalue = 1;
+ else {
+ tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.",
+ c->key, c->value);
+ return -1;
+ }
+ break;
+
+ case CONFIG_TYPE_STRING:
+ case CONFIG_TYPE_FILENAME:
+ tor_free(*(char **)lvalue);
+ *(char **)lvalue = tor_strdup(c->value);
+ break;
+
+ case CONFIG_TYPE_DOUBLE:
+ *(double *)lvalue = atof(c->value);
+ break;
+
+ case CONFIG_TYPE_ISOTIME:
+ if (parse_iso_time(c->value, (time_t *)lvalue)) {
+ tor_asprintf(msg,
+ "Invalid time '%s' for keyword '%s'", c->value, c->key);
+ return -1;
+ }
+ break;
+
+ case CONFIG_TYPE_ROUTERSET:
+ if (*(routerset_t**)lvalue) {
+ routerset_free(*(routerset_t**)lvalue);
+ }
+ *(routerset_t**)lvalue = routerset_new();
+ if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) {
+ tor_asprintf(msg, "Invalid exit list '%s' for option '%s'",
+ c->value, c->key);
+ return -1;
+ }
+ break;
+
+ case CONFIG_TYPE_CSV:
+ if (*(smartlist_t**)lvalue) {
+ SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
+ smartlist_clear(*(smartlist_t**)lvalue);
+ } else {
+ *(smartlist_t**)lvalue = smartlist_new();
+ }
+
+ smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ break;
+
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_S:
+ {
+ config_line_t *lastval = *(config_line_t**)lvalue;
+ if (lastval && lastval->fragile) {
+ if (c->command != CONFIG_LINE_APPEND) {
+ config_free_lines(lastval);
+ *(config_line_t**)lvalue = NULL;
+ } else {
+ lastval->fragile = 0;
+ }
+ }
+
+ config_line_append((config_line_t**)lvalue, c->key, c->value);
+ }
+ break;
+ case CONFIG_TYPE_OBSOLETE:
+ log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key);
+ break;
+ case CONFIG_TYPE_LINELIST_V:
+ tor_asprintf(msg,
+ "You may not provide a value for virtual option '%s'", c->key);
+ return -1;
+ default:
+ tor_assert(0);
+ break;
+ }
+ return 0;
+}
+
+/** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
+ * to it will replace old ones. */
+static void
+config_mark_lists_fragile(const config_format_t *fmt, void *options)
+{
+ int i;
+ tor_assert(fmt);
+ tor_assert(options);
+
+ for (i = 0; fmt->vars[i].name; ++i) {
+ const config_var_t *var = &fmt->vars[i];
+ config_line_t *list;
+ if (var->type != CONFIG_TYPE_LINELIST &&
+ var->type != CONFIG_TYPE_LINELIST_V)
+ continue;
+
+ list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
+ if (list)
+ list->fragile = 1;
+ }
+}
+
+/** If <b>c</b> is a syntactically valid configuration line, update
+ * <b>options</b> with its value and return 0. Otherwise return -1 for bad
+ * key, -2 for bad value.
+ *
+ * If <b>clear_first</b> is set, clear the value first. Then if
+ * <b>use_defaults</b> is set, set the value to the default.
+ *
+ * Called from config_assign().
+ */
+static int
+config_assign_line(const config_format_t *fmt, void *options,
+ config_line_t *c, int use_defaults,
+ int clear_first, bitarray_t *options_seen, char **msg)
+{
+ const config_var_t *var;
+
+ CONFIG_CHECK(fmt, options);
+
+ var = config_find_option(fmt, c->key);
+ if (!var) {
+ if (fmt->extra) {
+ void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset);
+ log_info(LD_CONFIG,
+ "Found unrecognized option '%s'; saving it.", c->key);
+ config_line_append((config_line_t**)lvalue, c->key, c->value);
+ return 0;
+ } else {
+ tor_asprintf(msg,
+ "Unknown option '%s'. Failing.", c->key);
+ return -1;
+ }
+ }
+
+ /* Put keyword into canonical case. */
+ if (strcmp(var->name, c->key)) {
+ tor_free(c->key);
+ c->key = tor_strdup(var->name);
+ }
+
+ if (!strlen(c->value)) {
+ /* reset or clear it, then return */
+ if (!clear_first) {
+ if ((var->type == CONFIG_TYPE_LINELIST ||
+ var->type == CONFIG_TYPE_LINELIST_S) &&
+ c->command != CONFIG_LINE_CLEAR) {
+ /* We got an empty linelist from the torrc or command line.
+ As a special case, call this an error. Warn and ignore. */
+ log_warn(LD_CONFIG,
+ "Linelist option '%s' has no value. Skipping.", c->key);
+ } else { /* not already cleared */
+ config_reset(fmt, options, var, use_defaults);
+ }
+ }
+ return 0;
+ } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
+ config_reset(fmt, options, var, use_defaults);
+ }
+
+ if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
+ var->type != CONFIG_TYPE_LINELIST_S)) {
+ /* We're tracking which options we've seen, and this option is not
+ * supposed to occur more than once. */
+ int var_index = (int)(var - fmt->vars);
+ if (bitarray_is_set(options_seen, var_index)) {
+ log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
+ "value will be ignored.", var->name);
+ }
+ bitarray_set(options_seen, var_index);
+ }
+
+ if (config_assign_value(fmt, options, c, msg) < 0)
+ return -2;
+ return 0;
+}
+
+/** Restore the option named <b>key</b> in options to its default value.
+ * Called from config_assign(). */
+static void
+config_reset_line(const config_format_t *fmt, void *options,
+ const char *key, int use_defaults)
+{
+ const config_var_t *var;
+
+ CONFIG_CHECK(fmt, options);
+
+ var = config_find_option(fmt, key);
+ if (!var)
+ return; /* give error on next pass. */
+
+ config_reset(fmt, options, var, use_defaults);
+}
+
+/** Return true iff value needs to be quoted and escaped to be used in
+ * a configuration file. */
+static int
+config_value_needs_escape(const char *value)
+{
+ if (*value == '\"')
+ return 1;
+ while (*value) {
+ switch (*value)
+ {
+ case '\r':
+ case '\n':
+ case '#':
+ /* Note: quotes and backspaces need special handling when we are using
+ * quotes, not otherwise, so they don't trigger escaping on their
+ * own. */
+ return 1;
+ default:
+ if (!TOR_ISPRINT(*value))
+ return 1;
+ }
+ ++value;
+ }
+ return 0;
+}
+
+/** Return a newly allocated deep copy of the lines in <b>inp</b>. */
+config_line_t *
+config_lines_dup(const config_line_t *inp)
+{
+ config_line_t *result = NULL;
+ config_line_t **next_out = &result;
+ while (inp) {
+ *next_out = tor_malloc_zero(sizeof(config_line_t));
+ (*next_out)->key = tor_strdup(inp->key);
+ (*next_out)->value = tor_strdup(inp->value);
+ inp = inp->next;
+ next_out = &((*next_out)->next);
+ }
+ (*next_out) = NULL;
+ return result;
+}
+
+/** Return newly allocated line or lines corresponding to <b>key</b> in the
+ * configuration <b>options</b>. If <b>escape_val</b> is true and a
+ * value needs to be quoted before it's put in a config file, quote and
+ * escape that value. Return NULL if no such key exists. */
+config_line_t *
+config_get_assigned_option(const config_format_t *fmt, const void *options,
+ const char *key, int escape_val)
+{
+ const config_var_t *var;
+ const void *value;
+ config_line_t *result;
+ tor_assert(options && key);
+
+ CONFIG_CHECK(fmt, options);
+
+ var = config_find_option(fmt, key);
+ if (!var) {
+ log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
+ return NULL;
+ }
+ value = STRUCT_VAR_P(options, var->var_offset);
+
+ result = tor_malloc_zero(sizeof(config_line_t));
+ result->key = tor_strdup(var->name);
+ switch (var->type)
+ {
+ case CONFIG_TYPE_STRING:
+ case CONFIG_TYPE_FILENAME:
+ if (*(char**)value) {
+ result->value = tor_strdup(*(char**)value);
+ } else {
+ tor_free(result->key);
+ tor_free(result);
+ return NULL;
+ }
+ break;
+ case CONFIG_TYPE_ISOTIME:
+ if (*(time_t*)value) {
+ result->value = tor_malloc(ISO_TIME_LEN+1);
+ format_iso_time(result->value, *(time_t*)value);
+ } else {
+ tor_free(result->key);
+ tor_free(result);
+ }
+ escape_val = 0; /* Can't need escape. */
+ break;
+ case CONFIG_TYPE_PORT:
+ if (*(int*)value == CFG_AUTO_PORT) {
+ result->value = tor_strdup("auto");
+ escape_val = 0;
+ break;
+ }
+ /* fall through */
+ case CONFIG_TYPE_INTERVAL:
+ case CONFIG_TYPE_MSEC_INTERVAL:
+ case CONFIG_TYPE_UINT:
+ case CONFIG_TYPE_INT:
+ /* This means every or_options_t uint or bool element
+ * needs to be an int. Not, say, a uint16_t or char. */
+ tor_asprintf(&result->value, "%d", *(int*)value);
+ escape_val = 0; /* Can't need escape. */
+ break;
+ case CONFIG_TYPE_MEMUNIT:
+ tor_asprintf(&result->value, U64_FORMAT,
+ U64_PRINTF_ARG(*(uint64_t*)value));
+ escape_val = 0; /* Can't need escape. */
+ break;
+ case CONFIG_TYPE_DOUBLE:
+ tor_asprintf(&result->value, "%f", *(double*)value);
+ escape_val = 0; /* Can't need escape. */
+ break;
+
+ case CONFIG_TYPE_AUTOBOOL:
+ if (*(int*)value == -1) {
+ result->value = tor_strdup("auto");
+ escape_val = 0;
+ break;
+ }
+ /* fall through */
+ case CONFIG_TYPE_BOOL:
+ result->value = tor_strdup(*(int*)value ? "1" : "0");
+ escape_val = 0; /* Can't need escape. */
+ break;
+ case CONFIG_TYPE_ROUTERSET:
+ result->value = routerset_to_string(*(routerset_t**)value);
+ break;
+ case CONFIG_TYPE_CSV:
+ if (*(smartlist_t**)value)
+ result->value =
+ smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL);
+ else
+ result->value = tor_strdup("");
+ break;
+ case CONFIG_TYPE_OBSOLETE:
+ log_fn(LOG_INFO, LD_CONFIG,
+ "You asked me for the value of an obsolete config option '%s'.",
+ key);
+ tor_free(result->key);
+ tor_free(result);
+ return NULL;
+ case CONFIG_TYPE_LINELIST_S:
+ log_warn(LD_CONFIG,
+ "Can't return context-sensitive '%s' on its own", key);
+ tor_free(result->key);
+ tor_free(result);
+ return NULL;
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_V:
+ tor_free(result->key);
+ tor_free(result);
+ result = config_lines_dup(*(const config_line_t**)value);
+ break;
+ default:
+ tor_free(result->key);
+ tor_free(result);
+ log_warn(LD_BUG,"Unknown type %d for known key '%s'",
+ var->type, key);
+ return NULL;
+ }
+
+ if (escape_val) {
+ config_line_t *line;
+ for (line = result; line; line = line->next) {
+ if (line->value && config_value_needs_escape(line->value)) {
+ char *newval = esc_for_log(line->value);
+ tor_free(line->value);
+ line->value = newval;
+ }
+ }
+ }
+
+ return result;
+}
+/** Iterate through the linked list of requested options <b>list</b>.
+ * For each item, convert as appropriate and assign to <b>options</b>.
+ * If an item is unrecognized, set *msg and return -1 immediately,
+ * else return 0 for success.
+ *
+ * If <b>clear_first</b>, interpret config options as replacing (not
+ * extending) their previous values. If <b>clear_first</b> is set,
+ * then <b>use_defaults</b> to decide if you set to defaults after
+ * clearing, or make the value 0 or NULL.
+ *
+ * Here are the use cases:
+ * 1. A non-empty AllowInvalid line in your torrc. Appends to current
+ * if linelist, replaces current if csv.
+ * 2. An empty AllowInvalid line in your torrc. Should clear it.
+ * 3. "RESETCONF AllowInvalid" sets it to default.
+ * 4. "SETCONF AllowInvalid" makes it NULL.
+ * 5. "SETCONF AllowInvalid=foo" clears it and sets it to "foo".
+ *
+ * Use_defaults Clear_first
+ * 0 0 "append"
+ * 1 0 undefined, don't use
+ * 0 1 "set to null first"
+ * 1 1 "set to defaults first"
+ * Return 0 on success, -1 on bad key, -2 on bad value.
+ *
+ * As an additional special case, if a LINELIST config option has
+ * no value and clear_first is 0, then warn and ignore it.
+ */
+
+/*
+There are three call cases for config_assign() currently.
+
+Case one: Torrc entry
+options_init_from_torrc() calls config_assign(0, 0)
+ calls config_assign_line(0, 0).
+ if value is empty, calls config_reset(0) and returns.
+ calls config_assign_value(), appends.
+
+Case two: setconf
+options_trial_assign() calls config_assign(0, 1)
+ calls config_reset_line(0)
+ calls config_reset(0)
+ calls option_clear().
+ calls config_assign_line(0, 1).
+ if value is empty, returns.
+ calls config_assign_value(), appends.
+
+Case three: resetconf
+options_trial_assign() calls config_assign(1, 1)
+ calls config_reset_line(1)
+ calls config_reset(1)
+ calls option_clear().
+ calls config_assign_value(default)
+ calls config_assign_line(1, 1).
+ returns.
+*/
+int
+config_assign(const config_format_t *fmt, void *options, config_line_t *list,
+ int use_defaults, int clear_first, char **msg)
+{
+ config_line_t *p;
+ bitarray_t *options_seen;
+ const int n_options = config_count_options(fmt);
+
+ CONFIG_CHECK(fmt, options);
+
+ /* pass 1: normalize keys */
+ for (p = list; p; p = p->next) {
+ const char *full = config_expand_abbrev(fmt, p->key, 0, 1);
+ if (strcmp(full,p->key)) {
+ tor_free(p->key);
+ p->key = tor_strdup(full);
+ }
+ }
+
+ /* pass 2: if we're reading from a resetting source, clear all
+ * mentioned config options, and maybe set to their defaults. */
+ if (clear_first) {
+ for (p = list; p; p = p->next)
+ config_reset_line(fmt, options, p->key, use_defaults);
+ }
+
+ options_seen = bitarray_init_zero(n_options);
+ /* pass 3: assign. */
+ while (list) {
+ int r;
+ if ((r=config_assign_line(fmt, options, list, use_defaults,
+ clear_first, options_seen, msg))) {
+ bitarray_free(options_seen);
+ return r;
+ }
+ list = list->next;
+ }
+ bitarray_free(options_seen);
+
+ /** Now we're done assigning a group of options to the configuration.
+ * Subsequent group assignments should _replace_ linelists, not extend
+ * them. */
+ config_mark_lists_fragile(fmt, options);
+
+ return 0;
+}
+
+/** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
+ * Called from config_reset() and config_free(). */
+static void
+config_clear(const config_format_t *fmt, void *options,
+ const config_var_t *var)
+{
+ void *lvalue = STRUCT_VAR_P(options, var->var_offset);
+ (void)fmt; /* unused */
+ switch (var->type) {
+ case CONFIG_TYPE_STRING:
+ case CONFIG_TYPE_FILENAME:
+ tor_free(*(char**)lvalue);
+ break;
+ case CONFIG_TYPE_DOUBLE:
+ *(double*)lvalue = 0.0;
+ break;
+ case CONFIG_TYPE_ISOTIME:
+ *(time_t*)lvalue = 0;
+ break;
+ case CONFIG_TYPE_INTERVAL:
+ case CONFIG_TYPE_MSEC_INTERVAL:
+ case CONFIG_TYPE_UINT:
+ case CONFIG_TYPE_INT:
+ case CONFIG_TYPE_PORT:
+ case CONFIG_TYPE_BOOL:
+ *(int*)lvalue = 0;
+ break;
+ case CONFIG_TYPE_AUTOBOOL:
+ *(int*)lvalue = -1;
+ break;
+ case CONFIG_TYPE_MEMUNIT:
+ *(uint64_t*)lvalue = 0;
+ break;
+ case CONFIG_TYPE_ROUTERSET:
+ if (*(routerset_t**)lvalue) {
+ routerset_free(*(routerset_t**)lvalue);
+ *(routerset_t**)lvalue = NULL;
+ }
+ break;
+ case CONFIG_TYPE_CSV:
+ if (*(smartlist_t**)lvalue) {
+ SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
+ smartlist_free(*(smartlist_t **)lvalue);
+ *(smartlist_t **)lvalue = NULL;
+ }
+ break;
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_S:
+ config_free_lines(*(config_line_t **)lvalue);
+ *(config_line_t **)lvalue = NULL;
+ break;
+ case CONFIG_TYPE_LINELIST_V:
+ /* handled by linelist_s. */
+ break;
+ case CONFIG_TYPE_OBSOLETE:
+ break;
+ }
+}
+
+/** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
+ * <b>use_defaults</b>, set it to its default value.
+ * Called by config_init() and option_reset_line() and option_assign_line(). */
+static void
+config_reset(const config_format_t *fmt, void *options,
+ const config_var_t *var, int use_defaults)
+{
+ config_line_t *c;
+ char *msg = NULL;
+ CONFIG_CHECK(fmt, options);
+ config_clear(fmt, options, var); /* clear it first */
+ if (!use_defaults)
+ return; /* all done */
+ if (var->initvalue) {
+ c = tor_malloc_zero(sizeof(config_line_t));
+ c->key = tor_strdup(var->name);
+ c->value = tor_strdup(var->initvalue);
+ if (config_assign_value(fmt, options, c, &msg) < 0) {
+ log_warn(LD_BUG, "Failed to assign default: %s", msg);
+ tor_free(msg); /* if this happens it's a bug */
+ }
+ config_free_lines(c);
+ }
+}
+
+/** Release storage held by <b>options</b>. */
+void
+config_free(const config_format_t *fmt, void *options)
+{
+ int i;
+
+ if (!options)
+ return;
+
+ tor_assert(fmt);
+
+ for (i=0; fmt->vars[i].name; ++i)
+ config_clear(fmt, options, &(fmt->vars[i]));
+ if (fmt->extra) {
+ config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset);
+ config_free_lines(*linep);
+ *linep = NULL;
+ }
+ tor_free(options);
+}
+
+/** Return true iff a and b contain identical keys and values in identical
+ * order. */
+int
+config_lines_eq(config_line_t *a, config_line_t *b)
+{
+ while (a && b) {
+ if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
+ return 0;
+ a = a->next;
+ b = b->next;
+ }
+ if (a || b)
+ return 0;
+ return 1;
+}
+
+/** Return the number of lines in <b>a</b> whose key is <b>key</b>. */
+int
+config_count_key(const config_line_t *a, const char *key)
+{
+ int n = 0;
+ while (a) {
+ if (!strcasecmp(a->key, key)) {
+ ++n;
+ }
+ a = a->next;
+ }
+ return n;
+}
+
+/** Return true iff the option <b>name</b> has the same value in <b>o1</b>
+ * and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
+ */
+int
+config_is_same(const config_format_t *fmt,
+ const void *o1, const void *o2,
+ const char *name)
+{
+ config_line_t *c1, *c2;
+ int r = 1;
+ CONFIG_CHECK(fmt, o1);
+ CONFIG_CHECK(fmt, o2);
+
+ c1 = config_get_assigned_option(fmt, o1, name, 0);
+ c2 = config_get_assigned_option(fmt, o2, name, 0);
+ r = config_lines_eq(c1, c2);
+ config_free_lines(c1);
+ config_free_lines(c2);
+ return r;
+}
+
+/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
+void *
+config_dup(const config_format_t *fmt, const void *old)
+{
+ void *newopts;
+ int i;
+ config_line_t *line;
+
+ newopts = config_new(fmt);
+ for (i=0; fmt->vars[i].name; ++i) {
+ if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
+ continue;
+ if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
+ continue;
+ line = config_get_assigned_option(fmt, old, fmt->vars[i].name, 0);
+ if (line) {
+ char *msg = NULL;
+ if (config_assign(fmt, newopts, line, 0, 0, &msg) < 0) {
+ log_err(LD_BUG, "config_get_assigned_option() generated "
+ "something we couldn't config_assign(): %s", msg);
+ tor_free(msg);
+ tor_assert(0);
+ }
+ }
+ config_free_lines(line);
+ }
+ return newopts;
+}
+/** Set all vars in the configuration object <b>options</b> to their default
+ * values. */
+void
+config_init(const config_format_t *fmt, void *options)
+{
+ int i;
+ const config_var_t *var;
+ CONFIG_CHECK(fmt, options);
+
+ for (i=0; fmt->vars[i].name; ++i) {
+ var = &fmt->vars[i];
+ if (!var->initvalue)
+ continue; /* defaults to NULL or 0 */
+ config_reset(fmt, options, var, 1);
+ }
+}
+
+/** Allocate and return a new string holding the written-out values of the vars
+ * in 'options'. If 'minimal', do not write out any default-valued vars.
+ * Else, if comment_defaults, write default values as comments.
+ */
+char *
+config_dump(const config_format_t *fmt, const void *default_options,
+ const void *options, int minimal,
+ int comment_defaults)
+{
+ smartlist_t *elements;
+ const void *defaults = default_options;
+ void *defaults_tmp = NULL;
+ config_line_t *line, *assigned;
+ char *result;
+ int i;
+ char *msg = NULL;
+
+ if (defaults == NULL) {
+ defaults = defaults_tmp = config_new(fmt);
+ config_init(fmt, defaults_tmp);
+ }
+
+ /* XXX use a 1 here so we don't add a new log line while dumping */
+ if (default_options == NULL) {
+ if (fmt->validate_fn(NULL, defaults_tmp, 1, &msg) < 0) {
+ log_err(LD_BUG, "Failed to validate default config.");
+ tor_free(msg);
+ tor_assert(0);
+ }
+ }
+
+ elements = smartlist_new();
+ for (i=0; fmt->vars[i].name; ++i) {
+ int comment_option = 0;
+ if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE ||
+ fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
+ continue;
+ /* Don't save 'hidden' control variables. */
+ if (!strcmpstart(fmt->vars[i].name, "__"))
+ continue;
+ if (minimal && config_is_same(fmt, options, defaults, fmt->vars[i].name))
+ continue;
+ else if (comment_defaults &&
+ config_is_same(fmt, options, defaults, fmt->vars[i].name))
+ comment_option = 1;
+
+ line = assigned =
+ config_get_assigned_option(fmt, options, fmt->vars[i].name, 1);
+
+ for (; line; line = line->next) {
+ smartlist_add_asprintf(elements, "%s%s %s\n",
+ comment_option ? "# " : "",
+ line->key, line->value);
+ }
+ config_free_lines(assigned);
+ }
+
+ if (fmt->extra) {
+ line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset);
+ for (; line; line = line->next) {
+ smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
+ }
+ }
+
+ result = smartlist_join_strings(elements, "", 0, NULL);
+ SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
+ smartlist_free(elements);
+ if (defaults_tmp)
+ config_free(fmt, defaults_tmp);
+ return result;
+}
+
+/** Mapping from a unit name to a multiplier for converting that unit into a
+ * base unit. Used by config_parse_unit. */
+struct unit_table_t {
+ const char *unit; /**< The name of the unit */
+ uint64_t multiplier; /**< How many of the base unit appear in this unit */
+};
+
+/** Table to map the names of memory units to the number of bytes they
+ * contain. */
+static struct unit_table_t memory_units[] = {
+ { "", 1 },
+ { "b", 1<< 0 },
+ { "byte", 1<< 0 },
+ { "bytes", 1<< 0 },
+ { "kb", 1<<10 },
+ { "kbyte", 1<<10 },
+ { "kbytes", 1<<10 },
+ { "kilobyte", 1<<10 },
+ { "kilobytes", 1<<10 },
+ { "m", 1<<20 },
+ { "mb", 1<<20 },
+ { "mbyte", 1<<20 },
+ { "mbytes", 1<<20 },
+ { "megabyte", 1<<20 },
+ { "megabytes", 1<<20 },
+ { "gb", 1<<30 },
+ { "gbyte", 1<<30 },
+ { "gbytes", 1<<30 },
+ { "gigabyte", 1<<30 },
+ { "gigabytes", 1<<30 },
+ { "tb", U64_LITERAL(1)<<40 },
+ { "terabyte", U64_LITERAL(1)<<40 },
+ { "terabytes", U64_LITERAL(1)<<40 },
+ { NULL, 0 },
+};
+
+/** Table to map the names of time units to the number of seconds they
+ * contain. */
+static struct unit_table_t time_units[] = {
+ { "", 1 },
+ { "second", 1 },
+ { "seconds", 1 },
+ { "minute", 60 },
+ { "minutes", 60 },
+ { "hour", 60*60 },
+ { "hours", 60*60 },
+ { "day", 24*60*60 },
+ { "days", 24*60*60 },
+ { "week", 7*24*60*60 },
+ { "weeks", 7*24*60*60 },
+ { NULL, 0 },
+};
+
+/** Table to map the names of time units to the number of milliseconds
+ * they contain. */
+static struct unit_table_t time_msec_units[] = {
+ { "", 1 },
+ { "msec", 1 },
+ { "millisecond", 1 },
+ { "milliseconds", 1 },
+ { "second", 1000 },
+ { "seconds", 1000 },
+ { "minute", 60*1000 },
+ { "minutes", 60*1000 },
+ { "hour", 60*60*1000 },
+ { "hours", 60*60*1000 },
+ { "day", 24*60*60*1000 },
+ { "days", 24*60*60*1000 },
+ { "week", 7*24*60*60*1000 },
+ { "weeks", 7*24*60*60*1000 },
+ { NULL, 0 },
+};
+
+/** Parse a string <b>val</b> containing a number, zero or more
+ * spaces, and an optional unit string. If the unit appears in the
+ * table <b>u</b>, then multiply the number by the unit multiplier.
+ * On success, set *<b>ok</b> to 1 and return this product.
+ * Otherwise, set *<b>ok</b> to 0.
+ */
+static uint64_t
+config_parse_units(const char *val, struct unit_table_t *u, int *ok)
+{
+ uint64_t v = 0;
+ double d = 0;
+ int use_float = 0;
+ char *cp;
+
+ tor_assert(ok);
+
+ v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp);
+ if (!*ok || (cp && *cp == '.')) {
+ d = tor_parse_double(val, 0, UINT64_MAX, ok, &cp);
+ if (!*ok)
+ goto done;
+ use_float = 1;
+ }
+
+ if (!cp) {
+ *ok = 1;
+ v = use_float ? DBL_TO_U64(d) : v;
+ goto done;
+ }
+
+ cp = (char*) eat_whitespace(cp);
+
+ for ( ;u->unit;++u) {
+ if (!strcasecmp(u->unit, cp)) {
+ if (use_float)
+ v = u->multiplier * d;
+ else
+ v *= u->multiplier;
+ *ok = 1;
+ goto done;
+ }
+ }
+ log_warn(LD_CONFIG, "Unknown unit '%s'.", cp);
+ *ok = 0;
+ done:
+
+ if (*ok)
+ return v;
+ else
+ return 0;
+}
+
+/** Parse a string in the format "number unit", where unit is a unit of
+ * information (byte, KB, M, etc). On success, set *<b>ok</b> to true
+ * and return the number of bytes specified. Otherwise, set
+ * *<b>ok</b> to false and return 0. */
+static uint64_t
+config_parse_memunit(const char *s, int *ok)
+{
+ uint64_t u = config_parse_units(s, memory_units, ok);
+ return u;
+}
+
+/** Parse a string in the format "number unit", where unit is a unit of
+ * time in milliseconds. On success, set *<b>ok</b> to true and return
+ * the number of milliseconds in the provided interval. Otherwise, set
+ * *<b>ok</b> to 0 and return -1. */
+static int
+config_parse_msec_interval(const char *s, int *ok)
+{
+ uint64_t r;
+ r = config_parse_units(s, time_msec_units, ok);
+ if (!ok)
+ return -1;
+ if (r > INT_MAX) {
+ log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
+ *ok = 0;
+ return -1;
+ }
+ return (int)r;
+}
+
+/** Parse a string in the format "number unit", where unit is a unit of time.
+ * On success, set *<b>ok</b> to true and return the number of seconds in
+ * the provided interval. Otherwise, set *<b>ok</b> to 0 and return -1.
+ */
+static int
+config_parse_interval(const char *s, int *ok)
+{
+ uint64_t r;
+ r = config_parse_units(s, time_units, ok);
+ if (!ok)
+ return -1;
+ if (r > INT_MAX) {
+ log_warn(LD_CONFIG, "Interval '%s' is too long", s);
+ *ok = 0;
+ return -1;
+ }
+ return (int)r;
+}
+
diff --git a/src/or/confparse.h b/src/or/confparse.h
new file mode 100644
index 0000000000..20616be925
--- /dev/null
+++ b/src/or/confparse.h
@@ -0,0 +1,132 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_CONFPARSE_H
+#define TOR_CONFPARSE_H
+
+/** Enumeration of types which option values can take */
+typedef enum config_type_t {
+ CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
+ CONFIG_TYPE_FILENAME, /**< A filename: some prefixes get expanded. */
+ CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */
+ CONFIG_TYPE_INT, /**< Any integer. */
+ CONFIG_TYPE_PORT, /**< A port from 1...65535, 0 for "not set", or
+ * "auto". */
+ CONFIG_TYPE_INTERVAL, /**< A number of seconds, with optional units*/
+ CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional
+ * units */
+ CONFIG_TYPE_MEMUNIT, /**< A number of bytes, with optional units*/
+ CONFIG_TYPE_DOUBLE, /**< A floating-point value */
+ CONFIG_TYPE_BOOL, /**< A boolean value, expressed as 0 or 1. */
+ CONFIG_TYPE_AUTOBOOL, /**< A boolean+auto value, expressed 0 for false,
+ * 1 for true, and -1 for auto */
+ CONFIG_TYPE_ISOTIME, /**< An ISO-formatted time relative to UTC. */
+ CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and
+ * optional whitespace. */
+ CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
+ CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines,
+ * mixed with other keywords. */
+ CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize
+ * context-sensitive config lines when fetching.
+ */
+ CONFIG_TYPE_ROUTERSET, /**< A list of router names, addrs, and fps,
+ * parsed into a routerset_t. */
+ CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
+} config_type_t;
+
+/** An abbreviation for a configuration option allowed on the command line. */
+typedef struct config_abbrev_t {
+ const char *abbreviated;
+ const char *full;
+ int commandline_only;
+ int warn;
+} config_abbrev_t;
+
+/* Handy macro for declaring "In the config file or on the command line,
+ * you can abbreviate <b>tok</b>s as <b>tok</b>". */
+#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
+
+/** A variable allowed in the configuration file or on the command line. */
+typedef struct config_var_t {
+ const char *name; /**< The full keyword (case insensitive). */
+ config_type_t type; /**< How to interpret the type and turn it into a
+ * value. */
+ off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
+ const char *initvalue; /**< String (or null) describing initial value. */
+} config_var_t;
+
+/** Represents an English description of a configuration variable; used when
+ * generating configuration file comments. */
+typedef struct config_var_description_t {
+ const char *name;
+ const char *description;
+} config_var_description_t;
+
+/** Type of a callback to validate whether a given configuration is
+ * well-formed and consistent. See options_trial_assign() for documentation
+ * of arguments. */
+typedef int (*validate_fn_t)(void*,void*,int,char**);
+
+/** Information on the keys, value types, key-to-struct-member mappings,
+ * variable descriptions, validation functions, and abbreviations for a
+ * configuration or storage format. */
+typedef struct {
+ size_t size; /**< Size of the struct that everything gets parsed into. */
+ uint32_t magic; /**< Required 'magic value' to make sure we have a struct
+ * of the right type. */
+ off_t magic_offset; /**< Offset of the magic value within the struct. */
+ config_abbrev_t *abbrevs; /**< List of abbreviations that we expand when
+ * parsing this format. */
+ config_var_t *vars; /**< List of variables we recognize, their default
+ * values, and where we stick them in the structure. */
+ validate_fn_t validate_fn; /**< Function to validate config. */
+ /** If present, extra is a LINELIST variable for unrecognized
+ * lines. Otherwise, unrecognized lines are an error. */
+ config_var_t *extra;
+} config_format_t;
+
+/** Macro: assert that <b>cfg</b> has the right magic field for format
+ * <b>fmt</b>. */
+#define CONFIG_CHECK(fmt, cfg) STMT_BEGIN \
+ tor_assert(fmt && cfg); \
+ tor_assert((fmt)->magic == \
+ *(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset)); \
+ STMT_END
+
+void *config_new(const config_format_t *fmt);
+void config_line_append(config_line_t **lst,
+ const char *key, const char *val);
+config_line_t *config_lines_dup(const config_line_t *inp);
+void config_free(const config_format_t *fmt, void *options);
+int config_lines_eq(config_line_t *a, config_line_t *b);
+int config_count_key(const config_line_t *a, const char *key);
+config_line_t *config_get_assigned_option(const config_format_t *fmt,
+ const void *options, const char *key,
+ int escape_val);
+int config_is_same(const config_format_t *fmt,
+ const void *o1, const void *o2,
+ const char *name);
+void config_init(const config_format_t *fmt, void *options);
+void *config_dup(const config_format_t *fmt, const void *old);
+char *config_dump(const config_format_t *fmt, const void *default_options,
+ const void *options, int minimal,
+ int comment_defaults);
+int config_assign(const config_format_t *fmt, void *options,
+ config_line_t *list,
+ int use_defaults, int clear_first, char **msg);
+config_var_t *config_find_option_mutable(config_format_t *fmt,
+ const char *key);
+const config_var_t *config_find_option(const config_format_t *fmt,
+ const char *key);
+
+int config_get_lines(const char *string, config_line_t **result, int extended);
+void config_free_lines(config_line_t *front);
+const char *config_expand_abbrev(const config_format_t *fmt,
+ const char *option,
+ int command_line, int warn_obsolete);
+
+#endif
+
diff --git a/src/or/connection.c b/src/or/connection.c
index eac9c4f32b..223bbd938f 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -12,6 +12,13 @@
#include "or.h"
#include "buffers.h"
+/*
+ * Define this so we get channel internal functions, since we're implementing
+ * part of a subclass (channel_tls_t).
+ */
+#define TOR_CHANNEL_INTERNAL_
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
@@ -25,6 +32,7 @@
#include "dirserv.h"
#include "dns.h"
#include "dnsserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "main.h"
#include "policies.h"
@@ -34,6 +42,7 @@
#include "rendcommon.h"
#include "rephist.h"
#include "router.h"
+#include "transports.h"
#include "routerparse.h"
#ifdef USE_BUFFEREVENTS
@@ -238,7 +247,16 @@ dir_connection_new(int socket_family)
}
/** Allocate and return a new or_connection_t, initialized as by
- * connection_init(). */
+ * connection_init().
+ *
+ * Set timestamp_last_added_nonpadding to now.
+ *
+ * Assign a pseudorandom next_circ_id between 0 and 2**15.
+ *
+ * Initialize active_circuit_pqueue.
+ *
+ * Set active_circuit_pqueue_last_recalibrated to current cell_ewma tick.
+ */
or_connection_t *
or_connection_new(int socket_family)
{
@@ -247,16 +265,15 @@ or_connection_new(int socket_family)
connection_init(now, TO_CONN(or_conn), CONN_TYPE_OR, socket_family);
or_conn->timestamp_last_added_nonpadding = time(NULL);
- or_conn->next_circ_id = crypto_rand_int(1<<15);
-
- or_conn->active_circuit_pqueue = smartlist_new();
- or_conn->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick();
return or_conn;
}
/** Allocate and return a new entry_connection_t, initialized as by
- * connection_init(). */
+ * connection_init().
+ *
+ * Allocate space to store the socks_request.
+ */
entry_connection_t *
entry_connection_new(int type, int socket_family)
{
@@ -264,6 +281,13 @@ entry_connection_new(int type, int socket_family)
tor_assert(type == CONN_TYPE_AP);
connection_init(time(NULL), ENTRY_TO_CONN(entry_conn), type, socket_family);
entry_conn->socks_request = socks_request_new();
+ /* If this is coming from a listener, we'll set it up based on the listener
+ * in a little while. Otherwise, we're doing this as a linked connection
+ * of some kind, and we should set it up here based on the socket family */
+ if (socket_family == AF_INET)
+ entry_conn->ipv4_traffic_ok = 1;
+ else if (socket_family == AF_INET6)
+ entry_conn->ipv6_traffic_ok = 1;
return entry_conn;
}
@@ -338,14 +362,11 @@ connection_new(int type, int socket_family)
/** Initializes conn. (you must call connection_add() to link it into the main
* array).
*
+ * Set conn-\>magic to the correct value.
+ *
* Set conn-\>type to <b>type</b>. Set conn-\>s and conn-\>conn_array_index to
* -1 to signify they are not yet assigned.
*
- * If conn is not a listener type, allocate buffers for it. If it's
- * an AP type, allocate space to store the socks_request.
- *
- * Assign a pseudorandom next_circ_id between 0 and 2**15.
- *
* Initialize conn's timestamps to now.
*/
static void
@@ -414,7 +435,7 @@ connection_link_connections(connection_t *conn_a, connection_t *conn_b)
* if <b>conn</b> is an OR or OP connection.
*/
static void
-_connection_free(connection_t *conn)
+connection_free_(connection_t *conn)
{
void *mem;
size_t memlen;
@@ -492,7 +513,6 @@ _connection_free(connection_t *conn)
or_conn->tls = NULL;
or_handshake_state_free(or_conn->handshake_state);
or_conn->handshake_state = NULL;
- smartlist_free(or_conn->active_circuit_pqueue);
tor_free(or_conn->nickname);
}
if (conn->type == CONN_TYPE_AP) {
@@ -592,7 +612,7 @@ connection_free(connection_t *conn)
connection_control_closed(TO_CONTROL_CONN(conn));
}
connection_unregister_events(conn);
- _connection_free(conn);
+ connection_free_(conn);
}
/**
@@ -668,7 +688,42 @@ connection_close_immediate(connection_t *conn)
/** Mark <b>conn</b> to be closed next time we loop through
* conn_close_if_marked() in main.c. */
void
-_connection_mark_for_close(connection_t *conn, int line, const char *file)
+connection_mark_for_close_(connection_t *conn, int line, const char *file)
+{
+ assert_connection_ok(conn,0);
+ tor_assert(line);
+ tor_assert(line < 1<<16); /* marked_for_close can only fit a uint16_t. */
+ tor_assert(file);
+
+ if (conn->type == CONN_TYPE_OR) {
+ /*
+ * An or_connection should have been closed through one of the channel-
+ * aware functions in connection_or.c. We'll assume this is an error
+ * close and do that, and log a bug warning.
+ */
+ log_warn(LD_CHANNEL | LD_BUG,
+ "Something tried to close an or_connection_t without going "
+ "through channels at %s:%d",
+ file, line);
+ connection_or_close_for_error(TO_OR_CONN(conn), 0);
+ } else {
+ /* Pass it down to the real function */
+ connection_mark_for_close_internal_(conn, line, file);
+ }
+}
+
+/** Mark <b>conn</b> to be closed next time we loop through
+ * conn_close_if_marked() in main.c; the _internal version bypasses the
+ * CONN_TYPE_OR checks; this should be called when you either are sure that
+ * if this is an or_connection_t the controlling channel has been notified
+ * (e.g. with connection_or_notify_error()), or you actually are the
+ * connection_or_close_for_error() or connection_or_close_normally function.
+ * For all other cases, use connection_mark_and_flush() instead, which
+ * checks for or_connection_t properly, instead. See below.
+ */
+void
+connection_mark_for_close_internal_(connection_t *conn,
+ int line, const char *file)
{
assert_connection_ok(conn,0);
tor_assert(line);
@@ -683,6 +738,17 @@ _connection_mark_for_close(connection_t *conn, int line, const char *file)
return;
}
+ if (conn->type == CONN_TYPE_OR) {
+ /*
+ * Bad news if this happens without telling the controlling channel; do
+ * this so we can find things that call this wrongly when the asserts hit.
+ */
+ log_debug(LD_CHANNEL,
+ "Calling connection_mark_for_close_internal_() on an OR conn "
+ "at %s:%d",
+ file, line);
+ }
+
conn->marked_for_close = line;
conn->marked_for_close_file = file;
add_connection_to_closeable_list(conn);
@@ -881,7 +947,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
static int global_next_session_group = SESSION_GROUP_FIRST_AUTO;
tor_addr_t addr;
- if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
+ if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
warn_too_many_conns();
return NULL;
}
@@ -894,8 +960,8 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
- log_notice(LD_NET, "Opening %s on %s:%d",
- conn_type_to_string(type), fmt_addr(&addr), usePort);
+ log_notice(LD_NET, "Opening %s on %s",
+ conn_type_to_string(type), fmt_addrport(&addr, usePort));
s = tor_open_socket(tor_addr_family(&addr),
is_tcp ? SOCK_STREAM : SOCK_DGRAM,
@@ -1056,6 +1122,14 @@ connection_listener_new(const struct sockaddr *listensockaddr,
lis_conn->session_group = global_next_session_group--;
}
}
+ if (type == CONN_TYPE_AP_LISTENER) {
+ lis_conn->socks_ipv4_traffic = port_cfg->ipv4_traffic;
+ lis_conn->socks_ipv6_traffic = port_cfg->ipv6_traffic;
+ lis_conn->socks_prefer_ipv6 = port_cfg->prefer_ipv6;
+ } else {
+ lis_conn->socks_ipv4_traffic = 1;
+ lis_conn->socks_ipv6_traffic = 1;
+ }
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
@@ -1089,7 +1163,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
* nmap does). We want to detect that, and not go on with the connection.
*/
static int
-check_sockaddr(struct sockaddr *sa, int len, int level)
+check_sockaddr(const struct sockaddr *sa, int len, int level)
{
int ok = 1;
@@ -1202,11 +1276,6 @@ connection_handle_listener_read(connection_t *conn, int new_type)
return 0;
}
- if (check_sockaddr_family_match(remote->sa_family, conn) < 0) {
- tor_close_socket(news);
- return 0;
- }
-
tor_addr_from_sockaddr(&addr, remote, &port);
/* process entrance policies here, before we even create the connection */
@@ -1215,7 +1284,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
if (socks_policy_permits_address(&addr) == 0) {
log_notice(LD_APP,
"Denying socks connection from untrusted address %s.",
- fmt_addr(&addr));
+ fmt_and_decorate_addr(&addr));
tor_close_socket(news);
return 0;
}
@@ -1224,7 +1293,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
/* check dirpolicy to see if we should accept it */
if (dir_policy_permits_address(&addr) == 0) {
log_notice(LD_DIRSERV,"Denying dir connection from address %s.",
- fmt_addr(&addr));
+ fmt_and_decorate_addr(&addr));
tor_close_socket(news);
return 0;
}
@@ -1276,17 +1345,27 @@ static int
connection_init_accepted_conn(connection_t *conn,
const listener_connection_t *listener)
{
+ int rv;
+
connection_start_reading(conn);
switch (conn->type) {
case CONN_TYPE_OR:
control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
- return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
+ rv = connection_tls_start_handshake(TO_OR_CONN(conn), 1);
+ if (rv < 0) {
+ connection_or_close_for_error(TO_OR_CONN(conn), 0);
+ }
+ return rv;
+ break;
case CONN_TYPE_AP:
TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags;
TO_ENTRY_CONN(conn)->session_group = listener->session_group;
TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch();
- TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->_base.type;
+ TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type;
+ TO_ENTRY_CONN(conn)->ipv4_traffic_ok = listener->socks_ipv4_traffic;
+ TO_ENTRY_CONN(conn)->ipv6_traffic_ok = listener->socks_ipv6_traffic;
+ TO_ENTRY_CONN(conn)->prefer_ipv6_traffic = listener->socks_prefer_ipv6;
switch (TO_CONN(listener)->type) {
case CONN_TYPE_AP_LISTENER:
conn->state = AP_CONN_STATE_SOCKS_WAIT;
@@ -1333,7 +1412,7 @@ connection_connect(connection_t *conn, const char *address,
const or_options_t *options = get_options();
int protocol_family;
- if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
+ if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
warn_too_many_conns();
*socket_error = SOCK_ERRNO(ENOBUFS);
return -1;
@@ -1372,23 +1451,34 @@ connection_connect(connection_t *conn, const char *address,
make_socket_reuseable(s);
- if (options->OutboundBindAddress && !tor_addr_is_loopback(addr)) {
- struct sockaddr_in ext_addr;
-
- memset(&ext_addr, 0, sizeof(ext_addr));
- ext_addr.sin_family = AF_INET;
- ext_addr.sin_port = 0;
- if (!tor_inet_aton(options->OutboundBindAddress, &ext_addr.sin_addr)) {
- log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
- options->OutboundBindAddress);
- } else {
- if (bind(s, (struct sockaddr*)&ext_addr,
- (socklen_t)sizeof(ext_addr)) < 0) {
- *socket_error = tor_socket_errno(s);
- log_warn(LD_NET,"Error binding network socket: %s",
- tor_socket_strerror(*socket_error));
- tor_close_socket(s);
- return -1;
+ if (!tor_addr_is_loopback(addr)) {
+ const tor_addr_t *ext_addr = NULL;
+ if (protocol_family == AF_INET &&
+ !tor_addr_is_null(&options->OutboundBindAddressIPv4_))
+ ext_addr = &options->OutboundBindAddressIPv4_;
+ else if (protocol_family == AF_INET6 &&
+ !tor_addr_is_null(&options->OutboundBindAddressIPv6_))
+ ext_addr = &options->OutboundBindAddressIPv6_;
+ if (ext_addr) {
+ struct sockaddr_storage ext_addr_sa;
+ socklen_t ext_addr_len = 0;
+ memset(&ext_addr_sa, 0, sizeof(ext_addr_sa));
+ ext_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
+ (struct sockaddr *) &ext_addr_sa,
+ sizeof(ext_addr_sa));
+ if (ext_addr_len == 0) {
+ log_warn(LD_NET,
+ "Error converting OutboundBindAddress %s into sockaddr. "
+ "Ignoring.", fmt_and_decorate_addr(ext_addr));
+ } else {
+ if (bind(s, (struct sockaddr *) &ext_addr_sa, ext_addr_len) < 0) {
+ *socket_error = tor_socket_errno(s);
+ log_warn(LD_NET,"Error binding network socket to %s: %s",
+ fmt_and_decorate_addr(ext_addr),
+ tor_socket_strerror(*socket_error));
+ tor_close_socket(s);
+ return -1;
+ }
}
}
}
@@ -1424,7 +1514,7 @@ connection_connect(connection_t *conn, const char *address,
/* it succeeded. we're connected. */
log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET,
- "Connection to %s:%u %s (sock %d).",
+ "Connection to %s:%u %s (sock "TOR_SOCKET_T_FORMAT").",
escaped_safe_str_client(address),
port, inprogress?"in progress":"established", s);
conn->s = s;
@@ -1495,17 +1585,17 @@ connection_proxy_connect(connection_t *conn, int type)
}
if (base64_authenticator) {
- const char *addr = fmt_addr(&conn->addr);
- tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n"
- "Host: %s:%d\r\n"
+ const char *addrport = fmt_addrport(&conn->addr, conn->port);
+ tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.1\r\n"
+ "Host: %s\r\n"
"Proxy-Authorization: Basic %s\r\n\r\n",
- addr, conn->port,
- addr, conn->port,
+ addrport,
+ addrport,
base64_authenticator);
tor_free(base64_authenticator);
} else {
- tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n\r\n",
- fmt_addr(&conn->addr), conn->port);
+ tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.0\r\n\r\n",
+ fmt_addrport(&conn->addr, conn->port));
}
connection_write_to_buf(buf, strlen(buf), conn);
@@ -2033,9 +2123,9 @@ connection_mark_all_noncontrol_connections(void)
/** Return 1 if we should apply rate limiting to <b>conn</b>, and 0
* otherwise.
* Right now this just checks if it's an internal IP address or an
- * internal connection. We also check if the connection uses pluggable
- * transports, since we should then limit it even if it comes from an
- * internal IP address. */
+ * internal connection. We also should, but don't, check if the connection
+ * uses pluggable transports, since we should then limit it even if it
+ * comes from an internal IP address. */
static int
connection_is_rate_limited(connection_t *conn)
{
@@ -2075,7 +2165,8 @@ static int
connection_counts_as_relayed_traffic(connection_t *conn, time_t now)
{
if (conn->type == CONN_TYPE_OR &&
- TO_OR_CONN(conn)->client_used + CLIENT_IDLE_TIME_FOR_PRIORITY < now)
+ connection_or_client_used(TO_OR_CONN(conn)) +
+ CLIENT_IDLE_TIME_FOR_PRIORITY < now)
return 1;
if (conn->type == CONN_TYPE_DIR && DIR_CONN_IS_SERVER(conn))
return 1;
@@ -2534,7 +2625,7 @@ connection_bucket_should_increase(int bucket, or_connection_t *conn)
{
tor_assert(conn);
- if (conn->_base.state != OR_CONN_STATE_OPEN)
+ if (conn->base_.state != OR_CONN_STATE_OPEN)
return 0; /* only open connections play the rate limiting game */
if (bucket >= conn->bandwidthburst)
return 0;
@@ -2672,11 +2763,14 @@ connection_handle_read_impl(connection_t *conn)
before = buf_datalen(conn->inbuf);
if (connection_read_to_buf(conn, &max_to_read, &socket_error) < 0) {
/* There's a read error; kill the connection.*/
- if (conn->type == CONN_TYPE_OR &&
- conn->state == OR_CONN_STATE_CONNECTING) {
- connection_or_connect_failed(TO_OR_CONN(conn),
- errno_to_orconn_end_reason(socket_error),
- tor_socket_strerror(socket_error));
+ if (conn->type == CONN_TYPE_OR) {
+ connection_or_notify_error(TO_OR_CONN(conn),
+ socket_error != 0 ?
+ errno_to_orconn_end_reason(socket_error) :
+ END_OR_CONN_REASON_CONNRESET,
+ socket_error != 0 ?
+ tor_socket_strerror(socket_error) :
+ "(unknown, errno was 0)");
}
if (CONN_IS_EDGE(conn)) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
@@ -2687,7 +2781,11 @@ connection_handle_read_impl(connection_t *conn)
}
}
connection_close_immediate(conn); /* Don't flush; connection is dead. */
- connection_mark_for_close(conn);
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
return -1;
}
n_read += buf_datalen(conn->inbuf) - before;
@@ -3198,12 +3296,16 @@ connection_handle_write_impl(connection_t *conn, int force)
if (CONN_IS_EDGE(conn))
connection_edge_end_errno(TO_EDGE_CONN(conn));
if (conn->type == CONN_TYPE_OR)
- connection_or_connect_failed(TO_OR_CONN(conn),
- errno_to_orconn_end_reason(e),
- tor_socket_strerror(e));
+ connection_or_notify_error(TO_OR_CONN(conn),
+ errno_to_orconn_end_reason(e),
+ tor_socket_strerror(e));
connection_close_immediate(conn);
- connection_mark_for_close(conn);
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
return -1;
} else {
return 0; /* no change, see if next time is better */
@@ -3225,8 +3327,16 @@ connection_handle_write_impl(connection_t *conn, int force)
connection_stop_writing(conn);
if (connection_tls_continue_handshake(or_conn) < 0) {
/* Don't flush; connection is dead. */
+ connection_or_notify_error(or_conn,
+ END_OR_CONN_REASON_MISC,
+ "TLS error in connection_tls_"
+ "continue_handshake()");
connection_close_immediate(conn);
- connection_mark_for_close(conn);
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
return -1;
}
return 0;
@@ -3238,21 +3348,29 @@ connection_handle_write_impl(connection_t *conn, int force)
result = flush_buf_tls(or_conn->tls, conn->outbuf,
max_to_write, &conn->outbuf_flushlen);
- /* If we just flushed the last bytes, check if this tunneled dir
- * request is done. */
+ /* If we just flushed the last bytes, tell the channel on the
+ * or_conn to check if it needs to geoip_change_dirreq_state() */
/* XXXX move this to flushed_some or finished_flushing -NM */
- if (buf_datalen(conn->outbuf) == 0 && conn->dirreq_id)
- geoip_change_dirreq_state(conn->dirreq_id, DIRREQ_TUNNELED,
- DIRREQ_OR_CONN_BUFFER_FLUSHED);
+ if (buf_datalen(conn->outbuf) == 0 && or_conn->chan)
+ channel_notify_flushed(TLS_CHAN_TO_BASE(or_conn->chan));
switch (result) {
CASE_TOR_TLS_ERROR_ANY:
case TOR_TLS_CLOSE:
- log_info(LD_NET,result!=TOR_TLS_CLOSE?
+ log_info(LD_NET, result != TOR_TLS_CLOSE ?
"tls error. breaking.":"TLS connection closed on flush");
/* Don't flush; connection is dead. */
+ connection_or_notify_error(or_conn,
+ END_OR_CONN_REASON_MISC,
+ result != TOR_TLS_CLOSE ?
+ "TLS error in during flush" :
+ "TLS closed during flush");
connection_close_immediate(conn);
- connection_mark_for_close(conn);
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
return -1;
case TOR_TLS_WANTWRITE:
log_debug(LD_NET,"wanted write.");
@@ -3309,8 +3427,20 @@ connection_handle_write_impl(connection_t *conn, int force)
if (result > 0) {
/* If we wrote any bytes from our buffer, then call the appropriate
* functions. */
- if (connection_flushed_some(conn) < 0)
- connection_mark_for_close(conn);
+ if (connection_flushed_some(conn) < 0) {
+ if (connection_speaks_cells(conn)) {
+ connection_or_notify_error(TO_OR_CONN(conn),
+ END_OR_CONN_REASON_MISC,
+ "Got error back from "
+ "connection_flushed_some()");
+ }
+
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
+ }
}
if (!connection_wants_to_flush(conn)) { /* it's done flushing */
@@ -3360,13 +3490,6 @@ connection_flush(connection_t *conn)
return connection_handle_write(conn, 1);
}
-/** OpenSSL TLS record size is 16383; this is close. The goal here is to
- * push data out as soon as we know there's enough for a TLS record, so
- * during periods of high load we won't read entire megabytes from
- * input before pushing any data out. It also has the feature of not
- * growing huge outbufs unless something is slow. */
-#define MIN_TLS_FLUSHLEN 15872
-
/** Append <b>len</b> bytes of <b>string</b> onto <b>conn</b>'s
* outbuf, and ask it to start writing.
*
@@ -3375,13 +3498,12 @@ connection_flush(connection_t *conn)
* negative, this is the last data to be compressed, and the connection's zlib
* state should be flushed.
*
- * If it's an OR conn and an entire TLS record is ready, then try to
- * flush the record now. Similarly, if it's a local control connection
- * and a 64k chunk is ready, try to flush it all, so we don't end up with
- * many megabytes of controller info queued at once.
+ * If it's a local control connection and a 64k chunk is ready, try to flush
+ * it all, so we don't end up with many megabytes of controller info queued at
+ * once.
*/
void
-_connection_write_to_buf_impl(const char *string, size_t len,
+connection_write_to_buf_impl_(const char *string, size_t len,
connection_t *conn, int zlib)
{
/* XXXX This function really needs to return -1 on failure. */
@@ -3446,7 +3568,6 @@ _connection_write_to_buf_impl(const char *string, size_t len,
if (zlib) {
conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen;
} else {
- ssize_t extra = 0;
conn->outbuf_flushlen += len;
/* Should we try flushing the outbuf now? */
@@ -3456,14 +3577,7 @@ _connection_write_to_buf_impl(const char *string, size_t len,
return;
}
- if (conn->type == CONN_TYPE_OR &&
- conn->outbuf_flushlen-len < MIN_TLS_FLUSHLEN &&
- conn->outbuf_flushlen >= MIN_TLS_FLUSHLEN) {
- /* We just pushed outbuf_flushlen to MIN_TLS_FLUSHLEN or above;
- * we can send out a full TLS frame now if we like. */
- extra = conn->outbuf_flushlen - MIN_TLS_FLUSHLEN;
- conn->outbuf_flushlen = MIN_TLS_FLUSHLEN;
- } else if (conn->type == CONN_TYPE_CONTROL &&
+ if (conn->type == CONN_TYPE_CONTROL &&
!connection_is_rate_limited(conn) &&
conn->outbuf_flushlen-len < 1<<16 &&
conn->outbuf_flushlen >= 1<<16) {
@@ -3483,10 +3597,6 @@ _connection_write_to_buf_impl(const char *string, size_t len,
}
return;
}
- if (extra) {
- conn->outbuf_flushlen += extra;
- connection_start_writing(conn);
- }
}
}
@@ -3960,9 +4070,9 @@ connection_reached_eof(connection_t *conn)
void
connection_dump_buffer_mem_stats(int severity)
{
- uint64_t used_by_type[_CONN_TYPE_MAX+1];
- uint64_t alloc_by_type[_CONN_TYPE_MAX+1];
- int n_conns_by_type[_CONN_TYPE_MAX+1];
+ uint64_t used_by_type[CONN_TYPE_MAX_+1];
+ uint64_t alloc_by_type[CONN_TYPE_MAX_+1];
+ int n_conns_by_type[CONN_TYPE_MAX_+1];
uint64_t total_alloc = 0;
uint64_t total_used = 0;
int i;
@@ -3984,7 +4094,7 @@ connection_dump_buffer_mem_stats(int severity)
alloc_by_type[tp] += buf_allocation(c->outbuf);
}
} SMARTLIST_FOREACH_END(c);
- for (i=0; i <= _CONN_TYPE_MAX; ++i) {
+ for (i=0; i <= CONN_TYPE_MAX_; ++i) {
total_used += used_by_type[i];
total_alloc += alloc_by_type[i];
}
@@ -3993,7 +4103,7 @@ connection_dump_buffer_mem_stats(int severity)
"In buffers for %d connections: "U64_FORMAT" used/"U64_FORMAT" allocated",
smartlist_len(conns),
U64_PRINTF_ARG(total_used), U64_PRINTF_ARG(total_alloc));
- for (i=_CONN_TYPE_MIN; i <= _CONN_TYPE_MAX; ++i) {
+ for (i=CONN_TYPE_MIN_; i <= CONN_TYPE_MAX_; ++i) {
if (!n_conns_by_type[i])
continue;
log(severity, LD_GENERAL,
@@ -4011,8 +4121,8 @@ assert_connection_ok(connection_t *conn, time_t now)
{
(void) now; /* XXXX unused. */
tor_assert(conn);
- tor_assert(conn->type >= _CONN_TYPE_MIN);
- tor_assert(conn->type <= _CONN_TYPE_MAX);
+ tor_assert(conn->type >= CONN_TYPE_MIN_);
+ tor_assert(conn->type <= CONN_TYPE_MAX_);
#ifdef USE_BUFFEREVENTS
if (conn->bufev) {
@@ -4127,34 +4237,33 @@ assert_connection_ok(connection_t *conn, time_t now)
tor_assert(conn->state == LISTENER_STATE_READY);
break;
case CONN_TYPE_OR:
- tor_assert(conn->state >= _OR_CONN_STATE_MIN);
- tor_assert(conn->state <= _OR_CONN_STATE_MAX);
- tor_assert(TO_OR_CONN(conn)->n_circuits >= 0);
+ tor_assert(conn->state >= OR_CONN_STATE_MIN_);
+ tor_assert(conn->state <= OR_CONN_STATE_MAX_);
break;
case CONN_TYPE_EXIT:
- tor_assert(conn->state >= _EXIT_CONN_STATE_MIN);
- tor_assert(conn->state <= _EXIT_CONN_STATE_MAX);
- tor_assert(conn->purpose >= _EXIT_PURPOSE_MIN);
- tor_assert(conn->purpose <= _EXIT_PURPOSE_MAX);
+ tor_assert(conn->state >= EXIT_CONN_STATE_MIN_);
+ tor_assert(conn->state <= EXIT_CONN_STATE_MAX_);
+ tor_assert(conn->purpose >= EXIT_PURPOSE_MIN_);
+ tor_assert(conn->purpose <= EXIT_PURPOSE_MAX_);
break;
case CONN_TYPE_AP:
- tor_assert(conn->state >= _AP_CONN_STATE_MIN);
- tor_assert(conn->state <= _AP_CONN_STATE_MAX);
+ tor_assert(conn->state >= AP_CONN_STATE_MIN_);
+ tor_assert(conn->state <= AP_CONN_STATE_MAX_);
tor_assert(TO_ENTRY_CONN(conn)->socks_request);
break;
case CONN_TYPE_DIR:
- tor_assert(conn->state >= _DIR_CONN_STATE_MIN);
- tor_assert(conn->state <= _DIR_CONN_STATE_MAX);
- tor_assert(conn->purpose >= _DIR_PURPOSE_MIN);
- tor_assert(conn->purpose <= _DIR_PURPOSE_MAX);
+ tor_assert(conn->state >= DIR_CONN_STATE_MIN_);
+ tor_assert(conn->state <= DIR_CONN_STATE_MAX_);
+ tor_assert(conn->purpose >= DIR_PURPOSE_MIN_);
+ tor_assert(conn->purpose <= DIR_PURPOSE_MAX_);
break;
case CONN_TYPE_CPUWORKER:
- tor_assert(conn->state >= _CPUWORKER_STATE_MIN);
- tor_assert(conn->state <= _CPUWORKER_STATE_MAX);
+ tor_assert(conn->state >= CPUWORKER_STATE_MIN_);
+ tor_assert(conn->state <= CPUWORKER_STATE_MAX_);
break;
case CONN_TYPE_CONTROL:
- tor_assert(conn->state >= _CONTROL_CONN_STATE_MIN);
- tor_assert(conn->state <= _CONTROL_CONN_STATE_MAX);
+ tor_assert(conn->state >= CONTROL_CONN_STATE_MIN_);
+ tor_assert(conn->state <= CONTROL_CONN_STATE_MAX_);
break;
default:
tor_assert(0);
@@ -4238,10 +4347,10 @@ log_failed_proxy_connection(connection_t *conn)
return; /* if we have no proxy set up, leave this function. */
log_warn(LD_NET,
- "The connection to the %s proxy server at %s:%u just failed. "
+ "The connection to the %s proxy server at %s just failed. "
"Make sure that the proxy server is up and running.",
- proxy_type_to_string(get_proxy_type()), fmt_addr(&proxy_addr),
- proxy_port);
+ proxy_type_to_string(get_proxy_type()),
+ fmt_addrport(&proxy_addr, proxy_port));
}
/** Return string representation of <b>proxy_type</b>. */
@@ -4259,7 +4368,7 @@ proxy_type_to_string(int proxy_type)
return NULL; /*Unreached*/
}
-/** Call _connection_free() on every connection in our array, and release all
+/** Call connection_free_() on every connection in our array, and release all
* storage held by connection.c. This is used by cpuworkers and dnsworkers
* when they fork, so they don't keep resources held open (especially
* sockets).
@@ -4285,7 +4394,7 @@ connection_free_all(void)
/* Clear out our list of broken connections */
clear_broken_connection_map(0);
- SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
+ SMARTLIST_FOREACH(conns, connection_t *, conn, connection_free_(conn));
if (outgoing_addrs) {
SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t *, addr, tor_free(addr));
@@ -4293,6 +4402,9 @@ connection_free_all(void)
outgoing_addrs = NULL;
}
+ tor_free(last_interface_ipv4);
+ tor_free(last_interface_ipv6);
+
#ifdef USE_BUFFEREVENTS
if (global_rate_limit)
bufferevent_rate_limit_group_free(global_rate_limit);
diff --git a/src/or/connection.h b/src/or/connection.h
index 785625e44b..b0c2a42838 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -9,8 +9,8 @@
* \brief Header file for connection.c.
**/
-#ifndef _TOR_CONNECTION_H
-#define _TOR_CONNECTION_H
+#ifndef TOR_CONNECTION_H
+#define TOR_CONNECTION_H
/* XXXX For buf_datalen in inline function */
#include "buffers.h"
@@ -31,25 +31,57 @@ void connection_free(connection_t *conn);
void connection_free_all(void);
void connection_about_to_close_connection(connection_t *conn);
void connection_close_immediate(connection_t *conn);
-void _connection_mark_for_close(connection_t *conn,int line, const char *file);
+void connection_mark_for_close_(connection_t *conn,
+ int line, const char *file);
+void connection_mark_for_close_internal_(connection_t *conn,
+ int line, const char *file);
#define connection_mark_for_close(c) \
- _connection_mark_for_close((c), __LINE__, _SHORT_FILE_)
+ connection_mark_for_close_((c), __LINE__, SHORT_FILE__)
+#define connection_mark_for_close_internal(c) \
+ connection_mark_for_close_internal_((c), __LINE__, SHORT_FILE__)
/**
* Mark 'c' for close, but try to hold it open until all the data is written.
+ * Use the _internal versions of connection_mark_for_close; this should be
+ * called when you either are sure that if this is an or_connection_t the
+ * controlling channel has been notified (e.g. with
+ * connection_or_notify_error()), or you actually are the
+ * connection_or_close_for_error() or connection_or_close_normally function.
+ * For all other cases, use connection_mark_and_flush() instead, which
+ * checks for or_connection_t properly, instead. See below.
*/
-#define _connection_mark_and_flush(c,line,file) \
- do { \
- connection_t *tmp_conn_ = (c); \
- _connection_mark_for_close(tmp_conn_, (line), (file)); \
- tmp_conn_->hold_open_until_flushed = 1; \
- IF_HAS_BUFFEREVENT(tmp_conn_, \
- connection_start_writing(tmp_conn_)); \
+#define connection_mark_and_flush_internal_(c,line,file) \
+ do { \
+ connection_t *tmp_conn_ = (c); \
+ connection_mark_for_close_internal_(tmp_conn_, (line), (file)); \
+ tmp_conn_->hold_open_until_flushed = 1; \
+ IF_HAS_BUFFEREVENT(tmp_conn_, \
+ connection_start_writing(tmp_conn_)); \
+ } while (0)
+
+#define connection_mark_and_flush_internal(c) \
+ connection_mark_and_flush_internal_((c), __LINE__, SHORT_FILE__)
+
+/**
+ * Mark 'c' for close, but try to hold it open until all the data is written.
+ */
+#define connection_mark_and_flush_(c,line,file) \
+ do { \
+ connection_t *tmp_conn_ = (c); \
+ if (tmp_conn_->type == CONN_TYPE_OR) { \
+ log_warn(LD_CHANNEL | LD_BUG, \
+ "Something tried to close (and flush) an or_connection_t" \
+ " without going through channels at %s:%d", \
+ file, line); \
+ connection_or_close_for_error(TO_OR_CONN(tmp_conn_), 1); \
+ } else { \
+ connection_mark_and_flush_internal_(c, line, file); \
+ } \
} while (0)
#define connection_mark_and_flush(c) \
- _connection_mark_and_flush((c), __LINE__, _SHORT_FILE_)
+ connection_mark_and_flush_((c), __LINE__, SHORT_FILE__)
void connection_expire_held_open(void);
@@ -90,7 +122,7 @@ int connection_outbuf_too_full(connection_t *conn);
int connection_handle_write(connection_t *conn, int force);
int connection_flush(connection_t *conn);
-void _connection_write_to_buf_impl(const char *string, size_t len,
+void connection_write_to_buf_impl_(const char *string, size_t len,
connection_t *conn, int zlib);
/* DOCDOC connection_write_to_buf */
static void connection_write_to_buf(const char *string, size_t len,
@@ -101,13 +133,13 @@ static void connection_write_to_buf_zlib(const char *string, size_t len,
static INLINE void
connection_write_to_buf(const char *string, size_t len, connection_t *conn)
{
- _connection_write_to_buf_impl(string, len, conn, 0);
+ connection_write_to_buf_impl_(string, len, conn, 0);
}
static INLINE void
connection_write_to_buf_zlib(const char *string, size_t len,
dir_connection_t *conn, int done)
{
- _connection_write_to_buf_impl(string, len, TO_CONN(conn), done ? -1 : 1);
+ connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1);
}
/* DOCDOC connection_get_inbuf_len */
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 9563ca6222..95088c7c17 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -8,9 +8,12 @@
* \file connection_edge.c
* \brief Handle edge streams.
**/
+#define CONNECTION_EDGE_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
+#include "channel.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
@@ -33,6 +36,7 @@
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
+#include "routerset.h"
#ifdef HAVE_LINUX_TYPES_H
#include <linux/types.h>
@@ -54,9 +58,7 @@
static int connection_ap_handshake_process_socks(entry_connection_t *conn);
static int connection_ap_process_natd(entry_connection_t *conn);
static int connection_exit_connect_dir(edge_connection_t *exitconn);
-static int address_is_in_virtual_range(const char *addr);
static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port);
-static void clear_trackexithost_mappings(const char *exitname);
static int connection_ap_supports_optimistic_data(const entry_connection_t *);
/** An AP stream has failed/finished. If it hasn't already sent back
@@ -64,7 +66,7 @@ static int connection_ap_supports_optimistic_data(const entry_connection_t *);
* has_sent_end to 1, and mark the conn.
*/
void
-_connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
+connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
int line, const char *file)
{
connection_t *base_conn = ENTRY_TO_CONN(conn);
@@ -87,7 +89,7 @@ _connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
if (base_conn->marked_for_close) {
/* This call will warn as appropriate. */
- _connection_mark_for_close(base_conn, line, file);
+ connection_mark_for_close_(base_conn, line, file);
return;
}
@@ -107,7 +109,7 @@ _connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
conn->socks_request->has_finished = 1;
}
- _connection_mark_and_flush(base_conn, line, file);
+ connection_mark_and_flush_(base_conn, line, file);
ENTRY_TO_EDGE_CONN(conn)->end_reason = endreason;
}
@@ -122,12 +124,13 @@ connection_edge_reached_eof(edge_connection_t *conn)
/* it still has stuff to process. don't let it die yet. */
return 0;
}
- log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->_base.s);
- if (!conn->_base.marked_for_close) {
+ log_info(LD_EDGE,"conn (fd "TOR_SOCKET_T_FORMAT") reached eof. Closing.",
+ conn->base_.s);
+ if (!conn->base_.marked_for_close) {
/* only mark it if not already marked. it's possible to
* get the 'end' right around when the client hangs up on us. */
connection_edge_end(conn, END_STREAM_REASON_DONE);
- if (conn->_base.type == CONN_TYPE_AP) {
+ if (conn->base_.type == CONN_TYPE_AP) {
/* eof, so don't send a socks reply back */
if (EDGE_TO_ENTRY_CONN(conn)->socks_request)
EDGE_TO_ENTRY_CONN(conn)->socks_request->has_finished = 1;
@@ -152,7 +155,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
{
tor_assert(conn);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case AP_CONN_STATE_SOCKS_WAIT:
if (connection_ap_handshake_process_socks(EDGE_TO_ENTRY_CONN(conn)) <0) {
/* already marked */
@@ -178,7 +181,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
log_info(LD_EDGE,
"data from edge while in '%s' state. Sending it anyway. "
"package_partial=%d, buflen=%ld",
- conn_state_to_string(conn->_base.type, conn->_base.state),
+ conn_state_to_string(conn->base_.type, conn->base_.state),
package_partial,
(long)connection_get_inbuf_len(TO_CONN(conn)));
if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) {
@@ -197,10 +200,10 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
case AP_CONN_STATE_CONTROLLER_WAIT:
log_info(LD_EDGE,
"data from edge while in '%s' state. Leaving it on buffer.",
- conn_state_to_string(conn->_base.type, conn->_base.state));
+ conn_state_to_string(conn->base_.type, conn->base_.state));
return 0;
}
- log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->_base.state);
+ log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->base_.state);
tor_fragile_assert();
connection_edge_end(conn, END_STREAM_REASON_INTERNAL);
connection_mark_for_close(TO_CONN(conn));
@@ -213,10 +216,10 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
int
connection_edge_destroy(circid_t circ_id, edge_connection_t *conn)
{
- if (!conn->_base.marked_for_close) {
+ if (!conn->base_.marked_for_close) {
log_info(LD_EDGE,
"CircID %d: At an edge. Marking connection for close.", circ_id);
- if (conn->_base.type == CONN_TYPE_AP) {
+ if (conn->base_.type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_DESTROY);
control_event_stream_bandwidth(conn);
@@ -280,10 +283,10 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason)
return -1;
}
- if (conn->_base.marked_for_close) {
+ if (conn->base_.marked_for_close) {
log_warn(LD_BUG,
"called on conn that's already marked for close at %s:%d.",
- conn->_base.marked_for_close_file, conn->_base.marked_for_close);
+ conn->base_.marked_for_close_file, conn->base_.marked_for_close);
return 0;
}
@@ -299,11 +302,11 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason)
if (reason == END_STREAM_REASON_EXITPOLICY &&
!connection_edge_is_rendezvous_stream(conn)) {
int addrlen;
- if (tor_addr_family(&conn->_base.addr) == AF_INET) {
- set_uint32(payload+1, tor_addr_to_ipv4n(&conn->_base.addr));
+ if (tor_addr_family(&conn->base_.addr) == AF_INET) {
+ set_uint32(payload+1, tor_addr_to_ipv4n(&conn->base_.addr));
addrlen = 4;
} else {
- memcpy(payload+1, tor_addr_to_in6_addr8(&conn->_base.addr), 16);
+ memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16);
addrlen = 16;
}
set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl)));
@@ -311,12 +314,14 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason)
}
if (circ && !circ->marked_for_close) {
- log_debug(LD_EDGE,"Sending end on conn (fd %d).",conn->_base.s);
+ log_debug(LD_EDGE,"Sending end on conn (fd "TOR_SOCKET_T_FORMAT").",
+ conn->base_.s);
connection_edge_send_command(conn, RELAY_COMMAND_END,
payload, payload_len);
} else {
- log_debug(LD_EDGE,"No circ to send end on conn (fd %d).",
- conn->_base.s);
+ log_debug(LD_EDGE,"No circ to send end on conn "
+ "(fd "TOR_SOCKET_T_FORMAT").",
+ conn->base_.s);
}
conn->edge_has_sent_end = 1;
@@ -333,7 +338,7 @@ connection_edge_end_errno(edge_connection_t *conn)
{
uint8_t reason;
tor_assert(conn);
- reason = errno_to_stream_end_reason(tor_socket_errno(conn->_base.s));
+ reason = errno_to_stream_end_reason(tor_socket_errno(conn->base_.s));
return connection_edge_end(conn, reason);
}
@@ -345,7 +350,7 @@ connection_edge_end_errno(edge_connection_t *conn)
int
connection_edge_flushed_some(edge_connection_t *conn)
{
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
connection_edge_consider_sending_sendme(conn);
@@ -369,7 +374,7 @@ connection_edge_finished_flushing(edge_connection_t *conn)
{
tor_assert(conn);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
connection_edge_consider_sending_sendme(conn);
@@ -383,13 +388,55 @@ connection_edge_finished_flushing(edge_connection_t *conn)
case AP_CONN_STATE_RESOLVE_WAIT:
return 0;
default:
- log_warn(LD_BUG, "Called in unexpected state %d.",conn->_base.state);
+ log_warn(LD_BUG, "Called in unexpected state %d.",conn->base_.state);
tor_fragile_assert();
return -1;
}
return 0;
}
+/** Longest size for the relay payload of a RELAY_CONNECTED cell that we're
+ * able to generate. */
+/* 4 zero bytes; 1 type byte; 16 byte IPv6 address; 4 byte TTL. */
+#define MAX_CONNECTED_CELL_PAYLOAD_LEN 25
+
+/** Set the buffer at <b>payload_out</b> -- which must have at least
+ * MAX_CONNECTED_CELL_PAYLOAD_LEN bytes available -- to the body of a
+ * RELAY_CONNECTED cell indicating that we have connected to <b>addr</b>, and
+ * that the name resolution that led us to <b>addr</b> will be valid for
+ * <b>ttl</b> seconds. Return -1 on error, or the number of bytes used on
+ * success. */
+/* private */int
+connected_cell_format_payload(uint8_t *payload_out,
+ const tor_addr_t *addr,
+ uint32_t ttl)
+{
+ const sa_family_t family = tor_addr_family(addr);
+ int connected_payload_len;
+
+ /* should be needless */
+ memset(payload_out, 0, MAX_CONNECTED_CELL_PAYLOAD_LEN);
+
+ if (family == AF_INET) {
+ set_uint32(payload_out, tor_addr_to_ipv4n(addr));
+ connected_payload_len = 4;
+ } else if (family == AF_INET6) {
+ set_uint32(payload_out, 0);
+ set_uint8(payload_out + 4, 6);
+ memcpy(payload_out + 5, tor_addr_to_in6_addr8(addr), 16);
+ connected_payload_len = 21;
+ } else {
+ return -1;
+ }
+
+ set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl)));
+ connected_payload_len += 4;
+
+ tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN);
+
+ return connected_payload_len;
+}
+
/** Connected handler for exit connections: start writing pending
* data, deliver 'CONNECTED' relay cells as appropriate, and check
* any pending data that may have been received. */
@@ -399,13 +446,13 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
connection_t *conn;
tor_assert(edge_conn);
- tor_assert(edge_conn->_base.type == CONN_TYPE_EXIT);
+ tor_assert(edge_conn->base_.type == CONN_TYPE_EXIT);
conn = TO_CONN(edge_conn);
tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING);
log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.",
escaped_safe_str(conn->address), conn->port,
- safe_str(fmt_addr(&conn->addr)));
+ safe_str(fmt_and_decorate_addr(&conn->addr)));
rep_hist_note_exit_stream_opened(conn->port);
@@ -421,22 +468,16 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
RELAY_COMMAND_CONNECTED, NULL, 0) < 0)
return 0; /* circuit is closed, don't continue */
} else {
- char connected_payload[20];
- int connected_payload_len;
- if (tor_addr_family(&conn->addr) == AF_INET) {
- set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
- set_uint32(connected_payload+4,
- htonl(dns_clip_ttl(edge_conn->address_ttl)));
- connected_payload_len = 8;
- } else {
- memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
- set_uint32(connected_payload+16,
- htonl(dns_clip_ttl(edge_conn->address_ttl)));
- connected_payload_len = 20;
- }
+ uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
+ int connected_payload_len =
+ connected_cell_format_payload(connected_payload, &conn->addr,
+ edge_conn->address_ttl);
+ if (connected_payload_len < 0)
+ return -1;
+
if (connection_edge_send_command(edge_conn,
- RELAY_COMMAND_CONNECTED,
- connected_payload, connected_payload_len) < 0)
+ RELAY_COMMAND_CONNECTED,
+ (char*)connected_payload, connected_payload_len) < 0)
return 0; /* circuit is closed, don't continue */
}
tor_assert(edge_conn->package_window > 0);
@@ -626,7 +667,7 @@ connection_ap_expire_beginning(void)
tor_assert(circ->timestamp_dirty);
circ->timestamp_dirty -= options->MaxCircuitDirtiness;
/* give our stream another 'cutoff' seconds to try */
- conn->_base.timestamp_lastread += cutoff;
+ conn->base_.timestamp_lastread += cutoff;
if (entry_conn->num_socks_retries < 250) /* avoid overflow */
entry_conn->num_socks_retries++;
/* move it back into 'pending' state, and try to attach. */
@@ -752,7 +793,7 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info)
/** The AP connection <b>conn</b> has just failed while attaching or
* sending a BEGIN or resolving on <b>circ</b>, but another circuit
* might work. Detach the circuit, and either reattach it, launch a
- * new circuit, tell the controller, or give up as a appropriate.
+ * new circuit, tell the controller, or give up as appropriate.
*
* Returns -1 on err, 1 on success, 0 on not-yet-sure.
*/
@@ -782,948 +823,6 @@ connection_ap_detach_retriable(entry_connection_t *conn,
}
}
-/** A client-side struct to remember requests to rewrite addresses
- * to new addresses. These structs are stored in the hash table
- * "addressmap" below.
- *
- * There are 5 ways to set an address mapping:
- * - A MapAddress command from the controller [permanent]
- * - An AddressMap directive in the torrc [permanent]
- * - When a TrackHostExits torrc directive is triggered [temporary]
- * - When a DNS resolve succeeds [temporary]
- * - When a DNS resolve fails [temporary]
- *
- * When an addressmap request is made but one is already registered,
- * the new one is replaced only if the currently registered one has
- * no "new_address" (that is, it's in the process of DNS resolve),
- * or if the new one is permanent (expires==0 or 1).
- *
- * (We overload the 'expires' field, using "0" for mappings set via
- * the configuration file, "1" for mappings set from the control
- * interface, and other values for DNS and TrackHostExit mappings that can
- * expire.)
- *
- * A mapping may be 'wildcarded'. If "src_wildcard" is true, then
- * any address that ends with a . followed by the key for this entry will
- * get remapped by it. If "dst_wildcard" is also true, then only the
- * matching suffix of such addresses will get replaced by new_address.
- */
-typedef struct {
- char *new_address;
- time_t expires;
- addressmap_entry_source_t source:3;
- unsigned src_wildcard:1;
- unsigned dst_wildcard:1;
- short num_resolve_failures;
-} addressmap_entry_t;
-
-/** Entry for mapping addresses to which virtual address we mapped them to. */
-typedef struct {
- char *ipv4_address;
- char *hostname_address;
-} virtaddress_entry_t;
-
-/** A hash table to store client-side address rewrite instructions. */
-static strmap_t *addressmap=NULL;
-/**
- * Table mapping addresses to which virtual address, if any, we
- * assigned them to.
- *
- * We maintain the following invariant: if [A,B] is in
- * virtaddress_reversemap, then B must be a virtual address, and [A,B]
- * must be in addressmap. We do not require that the converse hold:
- * if it fails, then we could end up mapping two virtual addresses to
- * the same address, which is no disaster.
- **/
-static strmap_t *virtaddress_reversemap=NULL;
-
-/** Initialize addressmap. */
-void
-addressmap_init(void)
-{
- addressmap = strmap_new();
- virtaddress_reversemap = strmap_new();
-}
-
-/** Free the memory associated with the addressmap entry <b>_ent</b>. */
-static void
-addressmap_ent_free(void *_ent)
-{
- addressmap_entry_t *ent;
- if (!_ent)
- return;
-
- ent = _ent;
- tor_free(ent->new_address);
- tor_free(ent);
-}
-
-/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
-static void
-addressmap_virtaddress_ent_free(void *_ent)
-{
- virtaddress_entry_t *ent;
- if (!_ent)
- return;
-
- ent = _ent;
- tor_free(ent->ipv4_address);
- tor_free(ent->hostname_address);
- tor_free(ent);
-}
-
-/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
-static void
-addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
-{
- if (ent && ent->new_address &&
- address_is_in_virtual_range(ent->new_address)) {
- virtaddress_entry_t *ve =
- strmap_get(virtaddress_reversemap, ent->new_address);
- /*log_fn(LOG_NOTICE,"remove reverse mapping for %s",ent->new_address);*/
- if (ve) {
- if (!strcmp(address, ve->ipv4_address))
- tor_free(ve->ipv4_address);
- if (!strcmp(address, ve->hostname_address))
- tor_free(ve->hostname_address);
- if (!ve->ipv4_address && !ve->hostname_address) {
- tor_free(ve);
- strmap_remove(virtaddress_reversemap, ent->new_address);
- }
- }
- }
-}
-
-/** Remove <b>ent</b> (which must be mapped to by <b>address</b>) from the
- * client address maps. */
-static void
-addressmap_ent_remove(const char *address, addressmap_entry_t *ent)
-{
- addressmap_virtaddress_remove(address, ent);
- addressmap_ent_free(ent);
-}
-
-/** Unregister all TrackHostExits mappings from any address to
- * *.exitname.exit. */
-static void
-clear_trackexithost_mappings(const char *exitname)
-{
- char *suffix = NULL;
- if (!addressmap || !exitname)
- return;
- tor_asprintf(&suffix, ".%s.exit", exitname);
- tor_strlower(suffix);
-
- STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
- if (ent->source == ADDRMAPSRC_TRACKEXIT &&
- !strcmpend(ent->new_address, suffix)) {
- addressmap_ent_remove(address, ent);
- MAP_DEL_CURRENT(address);
- }
- } STRMAP_FOREACH_END;
-
- tor_free(suffix);
-}
-
-/** Remove all TRACKEXIT mappings from the addressmap for which the target
- * host is unknown or no longer allowed, or for which the source address
- * is no longer in trackexithosts. */
-void
-addressmap_clear_excluded_trackexithosts(const or_options_t *options)
-{
- const routerset_t *allow_nodes = options->ExitNodes;
- const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion;
-
- if (!addressmap)
- return;
- if (routerset_is_empty(allow_nodes))
- allow_nodes = NULL;
- if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
- return;
-
- STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
- size_t len;
- const char *target = ent->new_address, *dot;
- char *nodename;
- const node_t *node;
-
- if (!target) {
- /* DNS resolving in progress */
- continue;
- } else if (strcmpend(target, ".exit")) {
- /* Not a .exit mapping */
- continue;
- } else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
- /* Not a trackexit mapping. */
- continue;
- }
- len = strlen(target);
- if (len < 6)
- continue; /* malformed. */
- dot = target + len - 6; /* dot now points to just before .exit */
- while (dot > target && *dot != '.')
- dot--;
- if (*dot == '.') dot++;
- nodename = tor_strndup(dot, len-5-(dot-target));;
- node = node_get_by_nickname(nodename, 0);
- tor_free(nodename);
- if (!node ||
- (allow_nodes && !routerset_contains_node(allow_nodes, node)) ||
- routerset_contains_node(exclude_nodes, node) ||
- !hostname_in_track_host_exits(options, address)) {
- /* We don't know this one, or we want to be rid of it. */
- addressmap_ent_remove(address, ent);
- MAP_DEL_CURRENT(address);
- }
- } STRMAP_FOREACH_END;
-}
-
-/** Remove all AUTOMAP mappings from the addressmap for which the
- * source address no longer matches AutomapHostsSuffixes, which is
- * no longer allowed by AutomapHostsOnResolve, or for which the
- * target address is no longer in the virtual network. */
-void
-addressmap_clear_invalid_automaps(const or_options_t *options)
-{
- int clear_all = !options->AutomapHostsOnResolve;
- const smartlist_t *suffixes = options->AutomapHostsSuffixes;
-
- if (!addressmap)
- return;
-
- if (!suffixes)
- clear_all = 1; /* This should be impossible, but let's be sure. */
-
- STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) {
- int remove = clear_all;
- if (ent->source != ADDRMAPSRC_AUTOMAP)
- continue; /* not an automap mapping. */
-
- if (!remove) {
- int suffix_found = 0;
- SMARTLIST_FOREACH(suffixes, const char *, suffix, {
- if (!strcasecmpend(src_address, suffix)) {
- suffix_found = 1;
- break;
- }
- });
- if (!suffix_found)
- remove = 1;
- }
-
- if (!remove && ! address_is_in_virtual_range(ent->new_address))
- remove = 1;
-
- if (remove) {
- addressmap_ent_remove(src_address, ent);
- MAP_DEL_CURRENT(src_address);
- }
- } STRMAP_FOREACH_END;
-}
-
-/** Remove all entries from the addressmap that were set via the
- * configuration file or the command line. */
-void
-addressmap_clear_configured(void)
-{
- addressmap_get_mappings(NULL, 0, 0, 0);
-}
-
-/** Remove all entries from the addressmap that are set to expire, ever. */
-void
-addressmap_clear_transient(void)
-{
- addressmap_get_mappings(NULL, 2, TIME_MAX, 0);
-}
-
-/** Clean out entries from the addressmap cache that were
- * added long enough ago that they are no longer valid.
- */
-void
-addressmap_clean(time_t now)
-{
- addressmap_get_mappings(NULL, 2, now, 0);
-}
-
-/** Free all the elements in the addressmap, and free the addressmap
- * itself. */
-void
-addressmap_free_all(void)
-{
- strmap_free(addressmap, addressmap_ent_free);
- addressmap = NULL;
-
- strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
- virtaddress_reversemap = NULL;
-}
-
-/** Try to find a match for AddressMap expressions that use
- * wildcard notation such as '*.c.d *.e.f' (so 'a.c.d' will map to 'a.e.f') or
- * '*.c.d a.b.c' (so 'a.c.d' will map to a.b.c).
- * Return the matching entry in AddressMap or NULL if no match is found.
- * For expressions such as '*.c.d *.e.f', truncate <b>address</b> 'a.c.d'
- * to 'a' before we return the matching AddressMap entry.
- *
- * This function does not handle the case where a pattern of the form "*.c.d"
- * matches the address c.d -- that's done by the main addressmap_rewrite
- * function.
- */
-static addressmap_entry_t *
-addressmap_match_superdomains(char *address)
-{
- addressmap_entry_t *val;
- char *cp;
-
- cp = address;
- while ((cp = strchr(cp, '.'))) {
- /* cp now points to a suffix of address that begins with a . */
- val = strmap_get_lc(addressmap, cp+1);
- if (val && val->src_wildcard) {
- if (val->dst_wildcard)
- *cp = '\0';
- return val;
- }
- ++cp;
- }
- return NULL;
-}
-
-/** Look at address, and rewrite it until it doesn't want any
- * more rewrites; but don't get into an infinite loop.
- * Don't write more than maxlen chars into address. Return true if the
- * address changed; false otherwise. Set *<b>expires_out</b> to the
- * expiry time of the result, or to <b>time_max</b> if the result does
- * not expire.
- *
- * If <b>exit_source_out</b> is non-null, we set it as follows. If we the
- * address starts out as a non-exit address, and we remap it to an .exit
- * address at any point, then set *<b>exit_source_out</b> to the
- * address_entry_source_t of the first such rule. Set *<b>exit_source_out</b>
- * to ADDRMAPSRC_NONE if there is no such rewrite, or if the original address
- * was a .exit.
- */
-int
-addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out,
- addressmap_entry_source_t *exit_source_out)
-{
- addressmap_entry_t *ent;
- int rewrites;
- time_t expires = TIME_MAX;
- addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE;
- char *addr_orig = tor_strdup(address);
- char *log_addr_orig = NULL;
-
- for (rewrites = 0; rewrites < 16; rewrites++) {
- int exact_match = 0;
- log_addr_orig = tor_strdup(escaped_safe_str_client(address));
-
- ent = strmap_get(addressmap, address);
-
- if (!ent || !ent->new_address) {
- ent = addressmap_match_superdomains(address);
- } else {
- if (ent->src_wildcard && !ent->dst_wildcard &&
- !strcasecmp(address, ent->new_address)) {
- /* This is a rule like *.example.com example.com, and we just got
- * "example.com" */
- goto done;
- }
-
- exact_match = 1;
- }
-
- if (!ent || !ent->new_address) {
- goto done;
- }
-
- if (ent->dst_wildcard && !exact_match) {
- strlcat(address, ".", maxlen);
- strlcat(address, ent->new_address, maxlen);
- } else {
- strlcpy(address, ent->new_address, maxlen);
- }
-
- if (!strcmpend(address, ".exit") &&
- strcmpend(addr_orig, ".exit") &&
- exit_source == ADDRMAPSRC_NONE) {
- exit_source = ent->source;
- }
-
- log_info(LD_APP, "Addressmap: rewriting %s to %s",
- log_addr_orig, escaped_safe_str_client(address));
- if (ent->expires > 1 && ent->expires < expires)
- expires = ent->expires;
-
- tor_free(log_addr_orig);
- }
- log_warn(LD_CONFIG,
- "Loop detected: we've rewritten %s 16 times! Using it as-is.",
- escaped_safe_str_client(address));
- /* it's fine to rewrite a rewrite, but don't loop forever */
-
- done:
- tor_free(addr_orig);
- tor_free(log_addr_orig);
- if (exit_source_out)
- *exit_source_out = exit_source;
- if (expires_out)
- *expires_out = TIME_MAX;
- return (rewrites > 0);
-}
-
-/** If we have a cached reverse DNS entry for the address stored in the
- * <b>maxlen</b>-byte buffer <b>address</b> (typically, a dotted quad) then
- * rewrite to the cached value and return 1. Otherwise return 0. Set
- * *<b>expires_out</b> to the expiry time of the result, or to <b>time_max</b>
- * if the result does not expire. */
-static int
-addressmap_rewrite_reverse(char *address, size_t maxlen, time_t *expires_out)
-{
- char *s, *cp;
- addressmap_entry_t *ent;
- int r = 0;
- tor_asprintf(&s, "REVERSE[%s]", address);
- ent = strmap_get(addressmap, s);
- if (ent) {
- cp = tor_strdup(escaped_safe_str_client(ent->new_address));
- log_info(LD_APP, "Rewrote reverse lookup %s -> %s",
- escaped_safe_str_client(s), cp);
- tor_free(cp);
- strlcpy(address, ent->new_address, maxlen);
- r = 1;
- }
-
- if (expires_out)
- *expires_out = (ent && ent->expires > 1) ? ent->expires : TIME_MAX;
-
- tor_free(s);
- return r;
-}
-
-/** Return 1 if <b>address</b> is already registered, else return 0. If address
- * is already registered, and <b>update_expires</b> is non-zero, then update
- * the expiry time on the mapping with update_expires if it is a
- * mapping created by TrackHostExits. */
-int
-addressmap_have_mapping(const char *address, int update_expiry)
-{
- addressmap_entry_t *ent;
- if (!(ent=strmap_get_lc(addressmap, address)))
- return 0;
- if (update_expiry && ent->source==ADDRMAPSRC_TRACKEXIT)
- ent->expires=time(NULL) + update_expiry;
- return 1;
-}
-
-/** Register a request to map <b>address</b> to <b>new_address</b>,
- * which will expire on <b>expires</b> (or 0 if never expires from
- * config file, 1 if never expires from controller, 2 if never expires
- * (virtual address mapping) from the controller.)
- *
- * <b>new_address</b> should be a newly dup'ed string, which we'll use or
- * free as appropriate. We will leave address alone.
- *
- * If <b>wildcard_addr</b> is true, then the mapping will match any address
- * equal to <b>address</b>, or any address ending with a period followed by
- * <b>address</b>. If <b>wildcard_addr</b> and <b>wildcard_new_addr</b> are
- * both true, the mapping will rewrite addresses that end with
- * ".<b>address</b>" into ones that end with ".<b>new_address</b>."
- *
- * If <b>new_address</b> is NULL, or <b>new_address</b> is equal to
- * <b>address</b> and <b>wildcard_addr</b> is equal to
- * <b>wildcard_new_addr</b>, remove any mappings that exist from
- * <b>address</b>.
- *
- *
- * It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is
- * not set. */
-void
-addressmap_register(const char *address, char *new_address, time_t expires,
- addressmap_entry_source_t source,
- const int wildcard_addr,
- const int wildcard_new_addr)
-{
- addressmap_entry_t *ent;
-
- if (wildcard_new_addr)
- tor_assert(wildcard_addr);
-
- ent = strmap_get(addressmap, address);
- if (!new_address || (!strcasecmp(address,new_address) &&
- wildcard_addr == wildcard_new_addr)) {
- /* Remove the mapping, if any. */
- tor_free(new_address);
- if (ent) {
- addressmap_ent_remove(address,ent);
- strmap_remove(addressmap, address);
- }
- return;
- }
- if (!ent) { /* make a new one and register it */
- ent = tor_malloc_zero(sizeof(addressmap_entry_t));
- strmap_set(addressmap, address, ent);
- } else if (ent->new_address) { /* we need to clean up the old mapping. */
- if (expires > 1) {
- log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
- "since it's already mapped to '%s'",
- safe_str_client(address),
- safe_str_client(new_address),
- safe_str_client(ent->new_address));
- tor_free(new_address);
- return;
- }
- if (address_is_in_virtual_range(ent->new_address) &&
- expires != 2) {
- /* XXX This isn't the perfect test; we want to avoid removing
- * mappings set from the control interface _as virtual mapping */
- addressmap_virtaddress_remove(address, ent);
- }
- tor_free(ent->new_address);
- } /* else { we have an in-progress resolve with no mapping. } */
-
- ent->new_address = new_address;
- ent->expires = expires==2 ? 1 : expires;
- ent->num_resolve_failures = 0;
- ent->source = source;
- ent->src_wildcard = wildcard_addr ? 1 : 0;
- ent->dst_wildcard = wildcard_new_addr ? 1 : 0;
-
- log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
- safe_str_client(address),
- safe_str_client(ent->new_address));
- control_event_address_mapped(address, ent->new_address, expires, NULL);
-}
-
-/** An attempt to resolve <b>address</b> failed at some OR.
- * Increment the number of resolve failures we have on record
- * for it, and then return that number.
- */
-int
-client_dns_incr_failures(const char *address)
-{
- addressmap_entry_t *ent = strmap_get(addressmap, address);
- if (!ent) {
- ent = tor_malloc_zero(sizeof(addressmap_entry_t));
- ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE;
- strmap_set(addressmap,address,ent);
- }
- if (ent->num_resolve_failures < SHORT_MAX)
- ++ent->num_resolve_failures; /* don't overflow */
- log_info(LD_APP, "Address %s now has %d resolve failures.",
- safe_str_client(address),
- ent->num_resolve_failures);
- return ent->num_resolve_failures;
-}
-
-/** If <b>address</b> is in the client DNS addressmap, reset
- * the number of resolve failures we have on record for it.
- * This is used when we fail a stream because it won't resolve:
- * otherwise future attempts on that address will only try once.
- */
-void
-client_dns_clear_failures(const char *address)
-{
- addressmap_entry_t *ent = strmap_get(addressmap, address);
- if (ent)
- ent->num_resolve_failures = 0;
-}
-
-/** Record the fact that <b>address</b> resolved to <b>name</b>.
- * We can now use this in subsequent streams via addressmap_rewrite()
- * so we can more correctly choose an exit that will allow <b>address</b>.
- *
- * If <b>exitname</b> is defined, then append the addresses with
- * ".exitname.exit" before registering the mapping.
- *
- * If <b>ttl</b> is nonnegative, the mapping will be valid for
- * <b>ttl</b>seconds; otherwise, we use the default.
- */
-static void
-client_dns_set_addressmap_impl(const char *address, const char *name,
- const char *exitname,
- int ttl)
-{
- /* <address>.<hex or nickname>.exit\0 or just <address>\0 */
- char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_VERBOSE_NICKNAME_LEN+10];
- /* 123.123.123.123.<hex or nickname>.exit\0 or just 123.123.123.123\0 */
- char extendedval[INET_NTOA_BUF_LEN+MAX_VERBOSE_NICKNAME_LEN+10];
-
- tor_assert(address);
- tor_assert(name);
-
- if (ttl<0)
- ttl = DEFAULT_DNS_TTL;
- else
- ttl = dns_clip_ttl(ttl);
-
- if (exitname) {
- /* XXXX fails to ever get attempts to get an exit address of
- * google.com.digest[=~]nickname.exit; we need a syntax for this that
- * won't make strict RFC952-compliant applications (like us) barf. */
- tor_snprintf(extendedaddress, sizeof(extendedaddress),
- "%s.%s.exit", address, exitname);
- tor_snprintf(extendedval, sizeof(extendedval),
- "%s.%s.exit", name, exitname);
- } else {
- tor_snprintf(extendedaddress, sizeof(extendedaddress),
- "%s", address);
- tor_snprintf(extendedval, sizeof(extendedval),
- "%s", name);
- }
- addressmap_register(extendedaddress, tor_strdup(extendedval),
- time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0);
-}
-
-/** Record the fact that <b>address</b> resolved to <b>val</b>.
- * We can now use this in subsequent streams via addressmap_rewrite()
- * so we can more correctly choose an exit that will allow <b>address</b>.
- *
- * If <b>exitname</b> is defined, then append the addresses with
- * ".exitname.exit" before registering the mapping.
- *
- * If <b>ttl</b> is nonnegative, the mapping will be valid for
- * <b>ttl</b>seconds; otherwise, we use the default.
- */
-void
-client_dns_set_addressmap(const char *address, uint32_t val,
- const char *exitname,
- int ttl)
-{
- struct in_addr in;
- char valbuf[INET_NTOA_BUF_LEN];
-
- tor_assert(address);
-
- if (tor_inet_aton(address, &in))
- return; /* If address was an IP address already, don't add a mapping. */
- in.s_addr = htonl(val);
- tor_inet_ntoa(&in,valbuf,sizeof(valbuf));
-
- client_dns_set_addressmap_impl(address, valbuf, exitname, ttl);
-}
-
-/** Add a cache entry noting that <b>address</b> (ordinarily a dotted quad)
- * resolved via a RESOLVE_PTR request to the hostname <b>v</b>.
- *
- * If <b>exitname</b> is defined, then append the addresses with
- * ".exitname.exit" before registering the mapping.
- *
- * If <b>ttl</b> is nonnegative, the mapping will be valid for
- * <b>ttl</b>seconds; otherwise, we use the default.
- */
-static void
-client_dns_set_reverse_addressmap(const char *address, const char *v,
- const char *exitname,
- int ttl)
-{
- char *s = NULL;
- tor_asprintf(&s, "REVERSE[%s]", address);
- client_dns_set_addressmap_impl(s, v, exitname, ttl);
- tor_free(s);
-}
-
-/* By default, we hand out 127.192.0.1 through 127.254.254.254.
- * These addresses should map to localhost, so even if the
- * application accidentally tried to connect to them directly (not
- * via Tor), it wouldn't get too far astray.
- *
- * These options are configured by parse_virtual_addr_network().
- */
-/** Which network should we use for virtual IPv4 addresses? Only the first
- * bits of this value are fixed. */
-static uint32_t virtual_addr_network = 0x7fc00000u;
-/** How many bits of <b>virtual_addr_network</b> are fixed? */
-static maskbits_t virtual_addr_netmask_bits = 10;
-/** What's the next virtual address we will hand out? */
-static uint32_t next_virtual_addr = 0x7fc00000u;
-
-/** Read a netmask of the form 127.192.0.0/10 from "val", and check whether
- * it's a valid set of virtual addresses to hand out in response to MAPADDRESS
- * requests. Return 0 on success; set *msg (if provided) to a newly allocated
- * string and return -1 on failure. If validate_only is false, sets the
- * actual virtual address range to the parsed value. */
-int
-parse_virtual_addr_network(const char *val, int validate_only,
- char **msg)
-{
- uint32_t addr;
- uint16_t port_min, port_max;
- maskbits_t bits;
-
- if (parse_addr_and_port_range(val, &addr, &bits, &port_min, &port_max)) {
- if (msg) *msg = tor_strdup("Error parsing VirtualAddressNetwork");
- return -1;
- }
-
- if (port_min != 1 || port_max != 65535) {
- if (msg) *msg = tor_strdup("Can't specify ports on VirtualAddressNetwork");
- return -1;
- }
-
- if (bits > 16) {
- if (msg) *msg = tor_strdup("VirtualAddressNetwork expects a /16 "
- "network or larger");
- return -1;
- }
-
- if (validate_only)
- return 0;
-
- virtual_addr_network = (uint32_t)( addr & (0xfffffffful << (32-bits)) );
- virtual_addr_netmask_bits = bits;
-
- if (addr_mask_cmp_bits(next_virtual_addr, addr, bits))
- next_virtual_addr = addr;
-
- return 0;
-}
-
-/**
- * Return true iff <b>addr</b> is likely to have been returned by
- * client_dns_get_unused_address.
- **/
-static int
-address_is_in_virtual_range(const char *address)
-{
- struct in_addr in;
- tor_assert(address);
- if (!strcasecmpend(address, ".virtual")) {
- return 1;
- } else if (tor_inet_aton(address, &in)) {
- uint32_t addr = ntohl(in.s_addr);
- if (!addr_mask_cmp_bits(addr, virtual_addr_network,
- virtual_addr_netmask_bits))
- return 1;
- }
- return 0;
-}
-
-/** Increment the value of next_virtual_addr; reset it to the start of the
- * virtual address range if it wraps around.
- */
-static INLINE void
-increment_virtual_addr(void)
-{
- ++next_virtual_addr;
- if (addr_mask_cmp_bits(next_virtual_addr, virtual_addr_network,
- virtual_addr_netmask_bits))
- next_virtual_addr = virtual_addr_network;
-}
-
-/** Return a newly allocated string holding an address of <b>type</b>
- * (one of RESOLVED_TYPE_{IPV4|HOSTNAME}) that has not yet been mapped,
- * and that is very unlikely to be the address of any real host.
- *
- * May return NULL if we have run out of virtual addresses.
- */
-static char *
-addressmap_get_virtual_address(int type)
-{
- char buf[64];
- tor_assert(addressmap);
-
- if (type == RESOLVED_TYPE_HOSTNAME) {
- char rand[10];
- do {
- crypto_rand(rand, sizeof(rand));
- base32_encode(buf,sizeof(buf),rand,sizeof(rand));
- strlcat(buf, ".virtual", sizeof(buf));
- } while (strmap_get(addressmap, buf));
- return tor_strdup(buf);
- } else if (type == RESOLVED_TYPE_IPV4) {
- // This is an imperfect estimate of how many addresses are available, but
- // that's ok.
- struct in_addr in;
- uint32_t available = 1u << (32-virtual_addr_netmask_bits);
- while (available) {
- /* Don't hand out any .0 or .255 address. */
- while ((next_virtual_addr & 0xff) == 0 ||
- (next_virtual_addr & 0xff) == 0xff) {
- increment_virtual_addr();
- if (! --available) {
- log_warn(LD_CONFIG, "Ran out of virtual addresses!");
- return NULL;
- }
- }
- in.s_addr = htonl(next_virtual_addr);
- tor_inet_ntoa(&in, buf, sizeof(buf));
- if (!strmap_get(addressmap, buf)) {
- increment_virtual_addr();
- break;
- }
-
- increment_virtual_addr();
- --available;
- // log_info(LD_CONFIG, "%d addrs available", (int)available);
- if (! available) {
- log_warn(LD_CONFIG, "Ran out of virtual addresses!");
- return NULL;
- }
- }
- return tor_strdup(buf);
- } else {
- log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
- return NULL;
- }
-}
-
-/** A controller has requested that we map some address of type
- * <b>type</b> to the address <b>new_address</b>. Choose an address
- * that is unlikely to be used, and map it, and return it in a newly
- * allocated string. If another address of the same type is already
- * mapped to <b>new_address</b>, try to return a copy of that address.
- *
- * The string in <b>new_address</b> may be freed or inserted into a map
- * as appropriate. May return NULL if are out of virtual addresses.
- **/
-const char *
-addressmap_register_virtual_address(int type, char *new_address)
-{
- char **addrp;
- virtaddress_entry_t *vent;
- int vent_needs_to_be_added = 0;
-
- tor_assert(new_address);
- tor_assert(addressmap);
- tor_assert(virtaddress_reversemap);
-
- vent = strmap_get(virtaddress_reversemap, new_address);
- if (!vent) {
- vent = tor_malloc_zero(sizeof(virtaddress_entry_t));
- vent_needs_to_be_added = 1;
- }
-
- addrp = (type == RESOLVED_TYPE_IPV4) ?
- &vent->ipv4_address : &vent->hostname_address;
- if (*addrp) {
- addressmap_entry_t *ent = strmap_get(addressmap, *addrp);
- if (ent && ent->new_address &&
- !strcasecmp(new_address, ent->new_address)) {
- tor_free(new_address);
- tor_assert(!vent_needs_to_be_added);
- return tor_strdup(*addrp);
- } else
- log_warn(LD_BUG,
- "Internal confusion: I thought that '%s' was mapped to by "
- "'%s', but '%s' really maps to '%s'. This is a harmless bug.",
- safe_str_client(new_address),
- safe_str_client(*addrp),
- safe_str_client(*addrp),
- ent?safe_str_client(ent->new_address):"(nothing)");
- }
-
- tor_free(*addrp);
- *addrp = addressmap_get_virtual_address(type);
- if (!*addrp) {
- tor_free(vent);
- tor_free(new_address);
- return NULL;
- }
- log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
- if (vent_needs_to_be_added)
- strmap_set(virtaddress_reversemap, new_address, vent);
- addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0);
-
-#if 0
- {
- /* Try to catch possible bugs */
- addressmap_entry_t *ent;
- ent = strmap_get(addressmap, *addrp);
- tor_assert(ent);
- tor_assert(!strcasecmp(ent->new_address,new_address));
- vent = strmap_get(virtaddress_reversemap, new_address);
- tor_assert(vent);
- tor_assert(!strcasecmp(*addrp,
- (type == RESOLVED_TYPE_IPV4) ?
- vent->ipv4_address : vent->hostname_address));
- log_info(LD_APP, "Map from %s to %s okay.",
- safe_str_client(*addrp),
- safe_str_client(new_address));
- }
-#endif
-
- return *addrp;
-}
-
-/** Return 1 if <b>address</b> has funny characters in it like colons. Return
- * 0 if it's fine, or if we're configured to allow it anyway. <b>client</b>
- * should be true if we're using this address as a client; false if we're
- * using it as a server.
- */
-int
-address_is_invalid_destination(const char *address, int client)
-{
- if (client) {
- if (get_options()->AllowNonRFC953Hostnames)
- return 0;
- } else {
- if (get_options()->ServerDNSAllowNonRFC953Hostnames)
- return 0;
- }
-
- while (*address) {
- if (TOR_ISALNUM(*address) ||
- *address == '-' ||
- *address == '.' ||
- *address == '_') /* Underscore is not allowed, but Windows does it
- * sometimes, just to thumb its nose at the IETF. */
- ++address;
- else
- return 1;
- }
- return 0;
-}
-
-/** Iterate over all address mappings which have expiry times between
- * min_expires and max_expires, inclusive. If sl is provided, add an
- * "old-addr new-addr expiry" string to sl for each mapping, omitting
- * the expiry time if want_expiry is false. If sl is NULL, remove the
- * mappings.
- */
-void
-addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
- time_t max_expires, int want_expiry)
-{
- strmap_iter_t *iter;
- const char *key;
- void *_val;
- addressmap_entry_t *val;
-
- if (!addressmap)
- addressmap_init();
-
- for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) {
- strmap_iter_get(iter, &key, &_val);
- val = _val;
- if (val->expires >= min_expires && val->expires <= max_expires) {
- if (!sl) {
- iter = strmap_iter_next_rmv(addressmap,iter);
- addressmap_ent_remove(key, val);
- continue;
- } else if (val->new_address) {
- const char *src_wc = val->src_wildcard ? "*." : "";
- const char *dst_wc = val->dst_wildcard ? "*." : "";
- if (want_expiry) {
- if (val->expires < 3 || val->expires == TIME_MAX)
- smartlist_add_asprintf(sl, "%s%s %s%s NEVER",
- src_wc, key, dst_wc, val->new_address);
- else {
- char time[ISO_TIME_LEN+1];
- format_iso_time(time, val->expires);
- smartlist_add_asprintf(sl, "%s%s %s%s \"%s\"",
- src_wc, key, dst_wc, val->new_address,
- time);
- }
- } else {
- smartlist_add_asprintf(sl, "%s%s %s%s",
- src_wc, key, dst_wc, val->new_address);
- }
- }
- }
- iter = strmap_iter_next(addressmap,iter);
- }
-}
-
/** Check if <b>conn</b> is using a dangerous port. Then warn and/or
* reject depending on our config options. */
static int
@@ -1923,7 +1022,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
/* If StrictNodes is not set, then .exit overrides ExcludeNodes. */
routerset_t *excludeset = options->StrictNodes ?
- options->_ExcludeExitNodesUnion : options->ExcludeExitNodes;
+ options->ExcludeExitNodesUnion_ : options->ExcludeExitNodes;
const node_t *node;
if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) {
@@ -2087,6 +1186,37 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
}
+ {
+ tor_addr_t addr;
+ /* XXX Duplicate call to tor_addr_parse. */
+ if (tor_addr_parse(&addr, socks->address) >= 0) {
+ sa_family_t family = tor_addr_family(&addr);
+ if ((family == AF_INET && ! conn->ipv4_traffic_ok) ||
+ (family == AF_INET6 && ! conn->ipv4_traffic_ok)) {
+ log_warn(LD_NET, "Rejecting SOCKS request for an IP address "
+ "family that this listener does not support.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
+ return -1;
+ } else if (family == AF_INET6 && socks->socks_version == 4) {
+ log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
+ return -1;
+ } else if (socks->socks_version == 4 && !conn->ipv4_traffic_ok) {
+ log_warn(LD_NET, "Rejecting SOCKS4 request on a listener with "
+ "no IPv4 traffic supported.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
+ return -1;
+ } else if (family == AF_INET6) {
+ conn->ipv4_traffic_ok = 0;
+ } else if (family == AF_INET) {
+ conn->ipv6_traffic_ok = 0;
+ }
+ }
+ }
+
+ if (socks->socks_version == 4)
+ conn->ipv6_traffic_ok = 0;
+
if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
/* see if we can find a suitable enclave exit */
const node_t *r =
@@ -2256,7 +1386,7 @@ connection_ap_get_original_destination(entry_connection_t *conn,
}
tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port);
- tor_addr_to_str(req->address, &addr, sizeof(req->address), 0);
+ tor_addr_to_str(req->address, &addr, sizeof(req->address), 1);
return 0;
#elif defined(TRANS_PF)
@@ -2317,7 +1447,7 @@ connection_ap_get_original_destination(entry_connection_t *conn,
return -1;
}
- tor_addr_to_str(req->address, &addr, sizeof(req->address), 0);
+ tor_addr_to_str(req->address, &addr, sizeof(req->address), 1);
req->port = ntohs(pnl.rdport);
return 0;
@@ -2555,6 +1685,65 @@ connection_ap_supports_optimistic_data(const entry_connection_t *conn)
return conn->may_use_optimistic_data;
}
+/** Return a bitmask of BEGIN_FLAG_* flags that we should transmit in the
+ * RELAY_BEGIN cell for <b>ap_conn</b>. */
+static uint32_t
+connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
+{
+ edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn);
+ const node_t *exitnode = NULL;
+ const crypt_path_t *cpath_layer = edge_conn->cpath_layer;
+ uint32_t flags = 0;
+
+ /* No flags for begindir */
+ if (ap_conn->use_begindir)
+ return 0;
+
+ /* No flags for hidden services. */
+ if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL)
+ return 0;
+
+ /* If only IPv4 is supported, no flags */
+ if (ap_conn->ipv4_traffic_ok && !ap_conn->ipv6_traffic_ok)
+ return 0;
+
+ if (! cpath_layer ||
+ ! cpath_layer->extend_info)
+ return 0;
+
+ if (!ap_conn->ipv4_traffic_ok)
+ flags |= BEGIN_FLAG_IPV4_NOT_OK;
+
+ exitnode = node_get_by_id(cpath_layer->extend_info->identity_digest);
+
+ if (ap_conn->ipv6_traffic_ok && exitnode) {
+ tor_addr_t a;
+ tor_addr_make_null(&a, AF_INET6);
+ if (compare_tor_addr_to_node_policy(&a, ap_conn->socks_request->port,
+ exitnode)
+ != ADDR_POLICY_REJECTED) {
+ /* Only say "IPv6 OK" if the exit node supports IPv6. Otherwise there's
+ * no point. */
+ flags |= BEGIN_FLAG_IPV6_OK;
+ }
+ }
+
+ if (flags == BEGIN_FLAG_IPV6_OK) {
+ /* When IPv4 and IPv6 are both allowed, consider whether to say we
+ * prefer IPv6. Otherwise there's no point in declaring a preference */
+ if (ap_conn->prefer_ipv6_traffic)
+ flags |= BEGIN_FLAG_IPV6_PREFERRED;
+ }
+
+ if (flags == BEGIN_FLAG_IPV4_NOT_OK) {
+ log_warn(LD_BUG, "Hey; I'm about to ask a node for a connection that I "
+ "am telling it to fulfil with neither IPv4 nor IPv6. That's "
+ "probably not going to work.");
+ }
+
+ return flags;
+}
+
/** Write a relay begin cell, using destaddr and destport from ap_conn's
* socks_request field, and send it down circ.
*
@@ -2585,16 +1774,23 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
/* Mark this circuit "unusable for new streams". */
/* XXXX024 this is a kludgy way to do this. */
- tor_assert(circ->_base.timestamp_dirty);
- circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ tor_assert(circ->base_.timestamp_dirty);
+ circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
return -1;
}
+ /* Set up begin cell flags. */
+ edge_conn->begincell_flags = connection_ap_get_begincell_flags(ap_conn);
+
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
- (circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
+ (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
ap_conn->socks_request->address : "",
ap_conn->socks_request->port);
payload_len = (int)strlen(payload)+1;
+ if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) {
+ set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags));
+ payload_len += 4;
+ }
log_info(LD_APP,
"Sending relay cell %d to begin stream %d.",
@@ -2617,8 +1813,9 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
edge_conn->package_window = STREAMWINDOW_START;
edge_conn->deliver_window = STREAMWINDOW_START;
base_conn->state = AP_CONN_STATE_CONNECT_WAIT;
- log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
- base_conn->s, circ->_base.n_circ_id);
+ log_info(LD_APP,"Address/port sent, ap socket "TOR_SOCKET_T_FORMAT
+ ", n_circ_id %d",
+ base_conn->s, circ->base_.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0);
/* If there's queued-up data, send it now */
@@ -2657,7 +1854,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
tor_assert(base_conn->type == CONN_TYPE_AP);
tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(ap_conn->socks_request);
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL);
command = ap_conn->socks_request->command;
tor_assert(SOCKS_COMMAND_IS_RESOLVE(command));
@@ -2670,8 +1867,8 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
/* Mark this circuit "unusable for new streams". */
/* XXXX024 this is a kludgy way to do this. */
- tor_assert(circ->_base.timestamp_dirty);
- circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ tor_assert(circ->base_.timestamp_dirty);
+ circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
return -1;
}
@@ -2686,7 +1883,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
/* We're doing a reverse lookup. The input could be an IP address, or
* could be an .in-addr.arpa or .ip6.arpa address */
- r = tor_addr_parse_PTR_name(&addr, a, AF_INET, 1);
+ r = tor_addr_parse_PTR_name(&addr, a, AF_UNSPEC, 1);
if (r <= 0) {
log_warn(LD_APP, "Rejecting ill-formed reverse lookup of %s",
safe_str_client(a));
@@ -2718,8 +1915,9 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
tor_free(base_conn->address); /* Maybe already set by dnsserv. */
base_conn->address = tor_strdup("(Tor_internal)");
base_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
- log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
- base_conn->s, circ->_base.n_circ_id);
+ log_info(LD_APP,"Address sent for resolve, ap socket "TOR_SOCKET_T_FORMAT
+ ", n_circ_id %d",
+ base_conn->s, circ->base_.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_NEW, 0);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0);
return 0;
@@ -2855,14 +2053,30 @@ connection_ap_handshake_socks_resolved(entry_connection_t *conn,
size_t replylen;
if (ttl >= 0) {
+ origin_circuit_t *origin_circ = NULL;
+ circuit_t *circ = ENTRY_TO_EDGE_CONN(conn)->on_circuit;
+ if (CIRCUIT_IS_ORIGIN(circ)) /* should always be true */
+ origin_circ = TO_ORIGIN_CIRCUIT(circ);
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
- uint32_t a = ntohl(get_uint32(answer));
- if (a)
- client_dns_set_addressmap(conn->socks_request->address, a,
+ tor_addr_t a;
+ tor_addr_from_ipv4n(&a, get_uint32(answer));
+ if (! tor_addr_is_null(&a)) {
+ client_dns_set_addressmap(origin_circ,
+ conn->socks_request->address, &a,
conn->chosen_exit_name, ttl);
+ }
+ } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
+ tor_addr_t a;
+ tor_addr_from_ipv6_bytes(&a, (char*)answer);
+ if (! tor_addr_is_null(&a)) {
+ client_dns_set_addressmap(origin_circ,
+ conn->socks_request->address, &a,
+ conn->chosen_exit_name, ttl);
+ }
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
char *cp = tor_strndup((char*)answer, answer_len);
- client_dns_set_reverse_addressmap(conn->socks_request->address,
+ client_dns_set_reverse_addressmap(origin_circ,
+ conn->socks_request->address,
cp,
conn->chosen_exit_name, ttl);
tor_free(cp);
@@ -2992,6 +2206,70 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
return;
}
+/** Read a RELAY_BEGIN or RELAY_BEGINDIR cell from <b>cell</b>, decode it, and
+ * place the result in <b>bcell</b>. On success return 0; on failure return
+ * <0 and set *<b>end_reason_out</b> to the end reason we should send back to
+ * the client.
+ *
+ * Return -1 in the case where want to send a RELAY_END cell, and < -1 when
+ * we don't.
+ **/
+/* static */ int
+begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
+ uint8_t *end_reason_out)
+{
+ relay_header_t rh;
+ const uint8_t *body, *nul;
+
+ memset(bcell, 0, sizeof(*bcell));
+ *end_reason_out = END_STREAM_REASON_MISC;
+
+ relay_header_unpack(&rh, cell->payload);
+ if (rh.length > RELAY_PAYLOAD_SIZE) {
+ return -2; /*XXXX why not TORPROTOCOL? */
+ }
+
+ bcell->stream_id = rh.stream_id;
+
+ if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
+ bcell->is_begindir = 1;
+ return 0;
+ } else if (rh.command != RELAY_COMMAND_BEGIN) {
+ log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command);
+ *end_reason_out = END_STREAM_REASON_INTERNAL;
+ return -1;
+ }
+
+ body = cell->payload + RELAY_HEADER_SIZE;
+ nul = memchr(body, 0, rh.length);
+ if (! nul) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Relay begin cell has no \\0. Closing.");
+ *end_reason_out = END_STREAM_REASON_TORPROTOCOL;
+ return -1;
+ }
+
+ if (tor_addr_port_split(LOG_PROTOCOL_WARN,
+ (char*)(body),
+ &bcell->address,&bcell->port)<0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Unable to parse addr:port in relay begin cell. Closing.");
+ *end_reason_out = END_STREAM_REASON_TORPROTOCOL;
+ return -1;
+ }
+ if (bcell->port == 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Missing port in relay begin cell. Closing.");
+ tor_free(bcell->address);
+ *end_reason_out = END_STREAM_REASON_TORPROTOCOL;
+ return -1;
+ }
+ if (body + rh.length >= nul + 4)
+ bcell->flags = ntohl(get_uint32(nul+1));
+
+ return 0;
+}
+
/** A relay 'begin' or 'begin_dir' cell has arrived, and either we are
* an exit hop for the circuit, or we are the origin and it is a
* rendezvous begin.
@@ -3015,10 +2293,13 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
{
edge_connection_t *n_stream;
relay_header_t rh;
- char *address=NULL;
- uint16_t port;
+ char *address = NULL;
+ uint16_t port = 0;
or_circuit_t *or_circ = NULL;
const or_options_t *options = get_options();
+ begin_cell_t bcell;
+ int r;
+ uint8_t end_reason=0;
assert_circuit_ok(circ);
if (!CIRCUIT_IS_ORIGIN(circ))
@@ -3042,52 +2323,43 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
return 0;
}
- if (rh.command == RELAY_COMMAND_BEGIN) {
- if (!memchr(cell->payload+RELAY_HEADER_SIZE, 0, rh.length)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Relay begin cell has no \\0. Closing.");
- relay_send_end_cell_from_edge(rh.stream_id, circ,
- END_STREAM_REASON_TORPROTOCOL, NULL);
- return 0;
- }
- if (tor_addr_port_split(LOG_PROTOCOL_WARN,
- (char*)(cell->payload+RELAY_HEADER_SIZE),
- &address,&port)<0) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Unable to parse addr:port in relay begin cell. Closing.");
- relay_send_end_cell_from_edge(rh.stream_id, circ,
- END_STREAM_REASON_TORPROTOCOL, NULL);
- return 0;
- }
- if (port==0) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Missing port in relay begin cell. Closing.");
- relay_send_end_cell_from_edge(rh.stream_id, circ,
- END_STREAM_REASON_TORPROTOCOL, NULL);
- tor_free(address);
- return 0;
- }
- if (or_circ && or_circ->p_conn && !options->AllowSingleHopExits &&
- (or_circ->is_first_hop ||
- (!connection_or_digest_is_known_relay(
- or_circ->p_conn->identity_digest) &&
+ r = begin_cell_parse(cell, &bcell, &end_reason);
+ if (r < -1) {
+ return -1;
+ } else if (r == -1) {
+ tor_free(bcell.address);
+ relay_send_end_cell_from_edge(rh.stream_id, circ, end_reason, NULL);
+ return 0;
+ }
+
+ if (! bcell.is_begindir) {
+ /* Steal reference */
+ address = bcell.address;
+ port = bcell.port;
+
+ if (or_circ && or_circ->p_chan) {
+ if (!options->AllowSingleHopExits &&
+ (or_circ->is_first_hop ||
+ (!connection_or_digest_is_known_relay(
+ or_circ->p_chan->identity_digest) &&
should_refuse_unknown_exits(options)))) {
- /* Don't let clients use us as a single-hop proxy, unless the user
- * has explicitly allowed that in the config. It attracts attackers
- * and users who'd be better off with, well, single-hop proxies.
- */
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Attempt by %s to open a stream %s. Closing.",
- safe_str(or_circ->p_conn->_base.address),
- or_circ->is_first_hop ? "on first hop of circuit" :
- "from unknown relay");
- relay_send_end_cell_from_edge(rh.stream_id, circ,
- or_circ->is_first_hop ?
- END_STREAM_REASON_TORPROTOCOL :
- END_STREAM_REASON_MISC,
- NULL);
- tor_free(address);
- return 0;
+ /* Don't let clients use us as a single-hop proxy, unless the user
+ * has explicitly allowed that in the config. It attracts attackers
+ * and users who'd be better off with, well, single-hop proxies.
+ */
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Attempt by %s to open a stream %s. Closing.",
+ safe_str(channel_get_canonical_remote_descr(or_circ->p_chan)),
+ or_circ->is_first_hop ? "on first hop of circuit" :
+ "from unknown relay");
+ relay_send_end_cell_from_edge(rh.stream_id, circ,
+ or_circ->is_first_hop ?
+ END_STREAM_REASON_TORPROTOCOL :
+ END_STREAM_REASON_MISC,
+ NULL);
+ tor_free(address);
+ return 0;
+ }
}
} else if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
if (!directory_permits_begindir_requests(options) ||
@@ -3098,10 +2370,10 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
}
/* Make sure to get the 'real' address of the previous hop: the
* caller might want to know whether his IP address has changed, and
- * we might already have corrected _base.addr[ess] for the relay's
+ * we might already have corrected base_.addr[ess] for the relay's
* canonical IP address. */
- if (or_circ && or_circ->p_conn)
- address = tor_dup_addr(&or_circ->p_conn->real_addr);
+ if (or_circ && or_circ->p_chan)
+ address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan));
else
address = tor_strdup("127.0.0.1");
port = 1; /* XXXX This value is never actually used anywhere, and there
@@ -3114,17 +2386,30 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
return 0;
}
+ if (! options->IPv6Exit) {
+ /* I don't care if you prefer IPv6; I can't give you any. */
+ bcell.flags &= ~BEGIN_FLAG_IPV6_PREFERRED;
+ /* If you don't want IPv4, I can't help. */
+ if (bcell.flags & BEGIN_FLAG_IPV4_NOT_OK) {
+ tor_free(address);
+ relay_send_end_cell_from_edge(rh.stream_id, circ,
+ END_STREAM_REASON_EXITPOLICY, NULL);
+ }
+ }
+
log_debug(LD_EXIT,"Creating new exit connection.");
+ /* The 'AF_INET' here is temporary; we might need to change it later in
+ * connection_exit_connect(). */
n_stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
/* Remember the tunneled request ID in the new edge connection, so that
* we can measure download times. */
- TO_CONN(n_stream)->dirreq_id = circ->dirreq_id;
-
- n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
+ n_stream->dirreq_id = circ->dirreq_id;
+ n_stream->base_.purpose = EXIT_PURPOSE_CONNECT;
+ n_stream->begincell_flags = bcell.flags;
n_stream->stream_id = rh.stream_id;
- n_stream->_base.port = port;
+ n_stream->base_.port = port;
/* leave n_stream->s at -1, because it's not yet valid */
n_stream->package_window = STREAMWINDOW_START;
n_stream->deliver_window = STREAMWINDOW_START;
@@ -3132,14 +2417,14 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_info(LD_REND,"begin is for rendezvous. configuring stream.");
- n_stream->_base.address = tor_strdup("(rendezvous)");
- n_stream->_base.state = EXIT_CONN_STATE_CONNECTING;
+ n_stream->base_.address = tor_strdup("(rendezvous)");
+ n_stream->base_.state = EXIT_CONN_STATE_CONNECTING;
n_stream->rend_data = rend_data_dup(origin_circ->rend_data);
tor_assert(connection_edge_is_rendezvous_stream(n_stream));
assert_circuit_ok(circ);
if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
- n_stream->_base.port);
+ n_stream->base_.port);
relay_send_end_cell_from_edge(rh.stream_id, circ,
END_STREAM_REASON_EXITPOLICY,
origin_circ->cpath->prev);
@@ -3162,8 +2447,8 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
return 0;
}
tor_strlower(address);
- n_stream->_base.address = address;
- n_stream->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ n_stream->base_.address = address;
+ n_stream->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
/* default to failed, change in dns_resolve if it turns out not to fail */
if (we_are_hibernating()) {
@@ -3176,9 +2461,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
n_stream->on_circuit = circ;
if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
+ tor_addr_t tmp_addr;
tor_assert(or_circ);
- if (or_circ->p_conn && !tor_addr_is_null(&or_circ->p_conn->real_addr))
- tor_addr_copy(&n_stream->_base.addr, &or_circ->p_conn->real_addr);
+ if (or_circ->p_chan &&
+ channel_get_addr_if_possible(or_circ->p_chan, &tmp_addr)) {
+ tor_addr_copy(&n_stream->base_.addr, &tmp_addr);
+ }
return connection_exit_connect_dir(n_stream);
}
@@ -3228,12 +2516,12 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
*/
dummy_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
dummy_conn->stream_id = rh.stream_id;
- dummy_conn->_base.address = tor_strndup(
+ dummy_conn->base_.address = tor_strndup(
(char*)cell->payload+RELAY_HEADER_SIZE,
rh.length);
- dummy_conn->_base.port = 0;
- dummy_conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
- dummy_conn->_base.purpose = EXIT_PURPOSE_RESOLVE;
+ dummy_conn->base_.port = 0;
+ dummy_conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ dummy_conn->base_.purpose = EXIT_PURPOSE_RESOLVE;
dummy_conn->on_circuit = TO_CIRCUIT(circ);
@@ -3243,7 +2531,7 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
/* Connection freed; don't touch it. */
return 0;
case 1: /* The result was cached; a resolved cell was sent. */
- if (!dummy_conn->_base.marked_for_close)
+ if (!dummy_conn->base_.marked_for_close)
connection_free(TO_CONN(dummy_conn));
return 0;
case 0: /* resolve added to pending list */
@@ -3268,8 +2556,11 @@ connection_exit_connect(edge_connection_t *edge_conn)
connection_t *conn = TO_CONN(edge_conn);
int socket_error = 0;
- if (!connection_edge_is_rendezvous_stream(edge_conn) &&
- router_compare_to_my_exit_policy(edge_conn)) {
+ if ( (!connection_edge_is_rendezvous_stream(edge_conn) &&
+ router_compare_to_my_exit_policy(&edge_conn->base_.addr,
+ edge_conn->base_.port)) ||
+ (tor_addr_family(&conn->addr) == AF_INET6 &&
+ ! get_options()->IPv6Exit)) {
log_info(LD_EXIT,"%s:%d failed exit policy. Closing.",
escaped_safe_str_client(conn->address), conn->port);
connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY);
@@ -3281,6 +2572,9 @@ connection_exit_connect(edge_connection_t *edge_conn)
addr = &conn->addr;
port = conn->port;
+ if (tor_addr_family(addr) == AF_INET6)
+ conn->socket_family = AF_INET6;
+
log_debug(LD_EXIT,"about to try connecting");
switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
case -1: {
@@ -3317,21 +2611,21 @@ connection_exit_connect(edge_connection_t *edge_conn)
RELAY_COMMAND_CONNECTED,
NULL, 0);
} else { /* normal stream */
- char connected_payload[20];
- int connected_payload_len;
- if (tor_addr_family(&conn->addr) == AF_INET) {
- set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
- connected_payload_len = 4;
- } else {
- memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
- connected_payload_len = 16;
+ uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
+ int connected_payload_len =
+ connected_cell_format_payload(connected_payload, &conn->addr,
+ edge_conn->address_ttl);
+ if (connected_payload_len < 0) {
+ connection_edge_end(edge_conn, END_STREAM_REASON_INTERNAL);
+ circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
+ connection_free(conn);
+ return;
}
- set_uint32(connected_payload+connected_payload_len,
- htonl(dns_clip_ttl(edge_conn->address_ttl)));
- connected_payload_len += 4;
+
connection_edge_send_command(edge_conn,
RELAY_COMMAND_CONNECTED,
- connected_payload, connected_payload_len);
+ (char*)connected_payload,
+ connected_payload_len);
}
}
@@ -3350,20 +2644,20 @@ connection_exit_connect_dir(edge_connection_t *exitconn)
log_info(LD_EXIT, "Opening local connection for anonymized directory exit");
- exitconn->_base.state = EXIT_CONN_STATE_OPEN;
+ exitconn->base_.state = EXIT_CONN_STATE_OPEN;
- dirconn = dir_connection_new(tor_addr_family(&exitconn->_base.addr));
+ dirconn = dir_connection_new(tor_addr_family(&exitconn->base_.addr));
- tor_addr_copy(&dirconn->_base.addr, &exitconn->_base.addr);
- dirconn->_base.port = 0;
- dirconn->_base.address = tor_strdup(exitconn->_base.address);
- dirconn->_base.type = CONN_TYPE_DIR;
- dirconn->_base.purpose = DIR_PURPOSE_SERVER;
- dirconn->_base.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
+ tor_addr_copy(&dirconn->base_.addr, &exitconn->base_.addr);
+ dirconn->base_.port = 0;
+ dirconn->base_.address = tor_strdup(exitconn->base_.address);
+ dirconn->base_.type = CONN_TYPE_DIR;
+ dirconn->base_.purpose = DIR_PURPOSE_SERVER;
+ dirconn->base_.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
/* Note that the new dir conn belongs to the same tunneled request as
* the edge conn, so that we can measure download times. */
- TO_CONN(dirconn)->dirreq_id = TO_CONN(exitconn)->dirreq_id;
+ dirconn->dirreq_id = exitconn->dirreq_id;
connection_link_connections(TO_CONN(dirconn), TO_CONN(exitconn));
@@ -3446,11 +2740,15 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit)
}
if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
- struct in_addr in;
tor_addr_t addr, *addrp = NULL;
addr_policy_result_t r;
- if (tor_inet_aton(conn->socks_request->address, &in)) {
- tor_addr_from_in(&addr, &in);
+ if (0 == tor_addr_parse(&addr, conn->socks_request->address)) {
+ addrp = &addr;
+ } else if (!conn->ipv4_traffic_ok && conn->ipv6_traffic_ok) {
+ tor_addr_make_null(&addr, AF_INET6);
+ addrp = &addr;
+ } else if (conn->ipv4_traffic_ok && !conn->ipv6_traffic_ok) {
+ tor_addr_make_null(&addr, AF_INET);
addrp = &addr;
}
r = compare_tor_addr_to_node_policy(addrp, conn->socks_request->port,exit);
@@ -3465,7 +2763,7 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit)
if (!conn->chosen_exit_name && node_exit_policy_rejects_all(exit))
return 0;
}
- if (routerset_contains_node(options->_ExcludeExitNodesUnion, exit)) {
+ if (routerset_contains_node(options->ExcludeExitNodesUnion_, exit)) {
/* Not a suitable exit. Refuse it. */
return 0;
}
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index c320d6ba49..9f38951f40 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -9,13 +9,13 @@
* \brief Header file for connection_edge.c.
**/
-#ifndef _TOR_CONNECTION_EDGE_H
-#define _TOR_CONNECTION_EDGE_H
+#ifndef TOR_CONNECTION_EDGE_H
+#define TOR_CONNECTION_EDGE_H
#define connection_mark_unattached_ap(conn, endreason) \
- _connection_mark_unattached_ap((conn), (endreason), __LINE__, _SHORT_FILE_)
+ connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__)
-void _connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
+void connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
int line, const char *file);
int connection_edge_reached_eof(edge_connection_t *conn);
int connection_edge_process_inbuf(edge_connection_t *conn,
@@ -67,30 +67,6 @@ int connection_ap_process_transparent(entry_connection_t *conn);
int address_is_invalid_destination(const char *address, int client);
-void addressmap_init(void);
-void addressmap_clear_excluded_trackexithosts(const or_options_t *options);
-void addressmap_clear_invalid_automaps(const or_options_t *options);
-void addressmap_clean(time_t now);
-void addressmap_clear_configured(void);
-void addressmap_clear_transient(void);
-void addressmap_free_all(void);
-int addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out,
- addressmap_entry_source_t *exit_source_out);
-int addressmap_have_mapping(const char *address, int update_timeout);
-
-void addressmap_register(const char *address, char *new_address,
- time_t expires, addressmap_entry_source_t source,
- const int address_wildcard,
- const int new_address_wildcard);
-int parse_virtual_addr_network(const char *val, int validate_only,
- char **msg);
-int client_dns_incr_failures(const char *address);
-void client_dns_clear_failures(const char *address);
-void client_dns_set_addressmap(const char *address, uint32_t val,
- const char *exitname, int ttl);
-const char *addressmap_register_virtual_address(int type, char *new_address);
-void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
- time_t max_expires, int want_expiry);
int connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn,
origin_circuit_t *circ,
crypt_path_t *cpath);
@@ -115,5 +91,50 @@ int connection_edge_update_circuit_isolation(const entry_connection_t *conn,
int dry_run);
void circuit_clear_isolation(origin_circuit_t *circ);
+/** @name Begin-cell flags
+ *
+ * These flags are used in RELAY_BEGIN cells to change the default behavior
+ * of the cell.
+ *
+ * @{
+ **/
+/** When this flag is set, the client is willing to get connected to IPv6
+ * addresses */
+#define BEGIN_FLAG_IPV6_OK (1u<<0)
+/** When this flag is set, the client DOES NOT support connecting to IPv4
+ * addresses. (The sense of this flag is inverted from IPV6_OK, so that the
+ * old default behavior of Tor is equivalent to having all flags set to 0.)
+ **/
+#define BEGIN_FLAG_IPV4_NOT_OK (1u<<1)
+/** When this flag is set, if we find both an IPv4 and an IPv6 address,
+ * we use the IPv6 address. Otherwise we use the IPv4 address. */
+#define BEGIN_FLAG_IPV6_PREFERRED (1u<<2)
+/**@}*/
+
+#ifdef CONNECTION_EDGE_PRIVATE
+
+/** A parsed BEGIN or BEGIN_DIR cell */
+typedef struct begin_cell_t {
+ /** The address the client has asked us to connect to, or NULL if this is
+ * a BEGIN_DIR cell*/
+ char *address;
+ /** The flags specified in the BEGIN cell's body. One or more of
+ * BEGIN_FLAG_*. */
+ uint32_t flags;
+ /** The client's requested port. */
+ uint16_t port;
+ /** The client's requested Stream ID */
+ uint16_t stream_id;
+ /** True iff this is a BEGIN_DIR cell. */
+ unsigned is_begindir : 1;
+} begin_cell_t;
+
+int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
+ uint8_t *end_reason_out);
+int connected_cell_format_payload(uint8_t *payload_out,
+ const tor_addr_t *addr,
+ uint32_t ttl);
+#endif
+
#endif
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 5eecee0740..7ac4d1ee95 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -12,14 +12,23 @@
#include "or.h"
#include "buffers.h"
+/*
+ * Define this so we get channel internal functions, since we're implementing
+ * part of a subclass (channel_tls_t).
+ */
+#define TOR_CHANNEL_INTERNAL_
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitstats.h"
#include "command.h"
#include "config.h"
#include "connection.h"
#include "connection_or.h"
#include "control.h"
#include "dirserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "main.h"
#include "networkstatus.h"
@@ -43,6 +52,17 @@ static int connection_or_check_valid_tls_handshake(or_connection_t *conn,
static void connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn);
+static unsigned int
+connection_or_is_bad_for_new_circs(or_connection_t *or_conn);
+static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn);
+
+/*
+ * Call this when changing connection state, so notifications to the owning
+ * channel can be handled.
+ */
+
+static void connection_or_change_state(or_connection_t *conn, uint8_t state);
+
#ifdef USE_BUFFEREVENTS
static void connection_or_handle_event_cb(struct bufferevent *bufev,
short event, void *arg);
@@ -127,8 +147,11 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
return;
/* If the identity was set previously, remove the old mapping. */
- if (! tor_digest_is_zero(conn->identity_digest))
+ if (! tor_digest_is_zero(conn->identity_digest)) {
connection_or_remove_from_identity_map(conn);
+ if (conn->chan)
+ channel_clear_identity_digest(TLS_CHAN_TO_BASE(conn->chan));
+ }
memcpy(conn->identity_digest, digest, DIGEST_LEN);
@@ -139,6 +162,10 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
tmp = digestmap_set(orconn_identity_map, digest, conn);
conn->next_with_same_id = tmp;
+ /* Deal with channels */
+ if (conn->chan)
+ channel_set_identity_digest(TLS_CHAN_TO_BASE(conn->chan), digest);
+
#if 1
/* Testing code to check for bugs in representation. */
for (; tmp; tmp = tmp->next_with_same_id) {
@@ -282,6 +309,39 @@ connection_or_report_broken_states(int severity, int domain)
smartlist_free(items);
}
+/** Call this to change or_connection_t states, so the owning channel_tls_t can
+ * be notified.
+ */
+
+static void
+connection_or_change_state(or_connection_t *conn, uint8_t state)
+{
+ uint8_t old_state;
+
+ tor_assert(conn);
+
+ old_state = conn->base_.state;
+ conn->base_.state = state;
+
+ if (conn->chan)
+ channel_tls_handle_state_change_on_orconn(conn->chan, conn,
+ old_state, state);
+}
+
+/** Return the number of circuits using an or_connection_t; this used to
+ * be an or_connection_t field, but it got moved to channel_t and we
+ * shouldn't maintain two copies. */
+
+int
+connection_or_get_num_circuits(or_connection_t *conn)
+{
+ tor_assert(conn);
+
+ if (conn->chan) {
+ return channel_num_circuits(TLS_CHAN_TO_BASE(conn->chan));
+ } else return 0;
+}
+
/**************************************************************/
/** Pack the cell_t host-order structure <b>src</b> into network-order
@@ -296,7 +356,7 @@ cell_pack(packed_cell_t *dst, const cell_t *src)
{
char *dest = dst->body;
set_uint16(dest, htons(src->circ_id));
- *(uint8_t*)(dest+2) = src->command;
+ set_uint8(dest+2, src->command);
memcpy(dest+3, src->payload, CELL_PAYLOAD_SIZE);
}
@@ -307,7 +367,7 @@ static void
cell_unpack(cell_t *dest, const char *src)
{
dest->circ_id = ntohs(get_uint16(src));
- dest->command = *(uint8_t*)(src+2);
+ dest->command = get_uint8(src+2);
memcpy(dest->payload, src+3, CELL_PAYLOAD_SIZE);
}
@@ -327,7 +387,7 @@ var_cell_t *
var_cell_new(uint16_t payload_len)
{
size_t size = STRUCT_OFFSET(var_cell_t, payload) + payload_len;
- var_cell_t *cell = tor_malloc(size);
+ var_cell_t *cell = tor_malloc_zero(size);
cell->payload_len = payload_len;
cell->command = 0;
cell->circ_id = 0;
@@ -345,8 +405,11 @@ var_cell_free(var_cell_t *cell)
int
connection_or_reached_eof(or_connection_t *conn)
{
+ tor_assert(conn);
+
log_info(LD_OR,"OR connection reached EOF. Closing.");
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_normally(conn, 1);
+
return 0;
}
@@ -366,7 +429,7 @@ connection_or_process_inbuf(or_connection_t *conn)
int ret = 0;
tor_assert(conn);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case OR_CONN_STATE_PROXY_HANDSHAKING:
ret = connection_read_proxy_handshake(TO_CONN(conn));
@@ -375,9 +438,12 @@ connection_or_process_inbuf(or_connection_t *conn)
tor_assert(TO_CONN(conn)->proxy_state == PROXY_CONNECTED);
if (connection_tls_start_handshake(conn, 0) < 0)
ret = -1;
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
}
if (ret < 0) {
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
}
return ret;
@@ -385,7 +451,7 @@ connection_or_process_inbuf(or_connection_t *conn)
#ifdef USE_BUFFEREVENTS
if (tor_tls_server_got_renegotiate(conn->tls))
connection_or_tls_renegotiated_cb(conn->tls, conn);
- if (conn->_base.marked_for_close)
+ if (conn->base_.marked_for_close)
return 0;
/* fall through. */
#endif
@@ -403,14 +469,14 @@ connection_or_process_inbuf(or_connection_t *conn)
*
* XXX024 Remove this check once we verify that the above paragraph is
* 100% true. */
- if (buf_datalen(conn->_base.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) {
+ if (buf_datalen(conn->base_.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) {
log_fn(LOG_PROTOCOL_WARN, LD_NET, "Accumulated too much data (%d bytes) "
"on nonopen OR connection %s %s:%u in state %s; closing.",
- (int)buf_datalen(conn->_base.inbuf),
+ (int)buf_datalen(conn->base_.inbuf),
connection_or_nonopen_was_started_here(conn) ? "to" : "from",
- conn->_base.address, conn->_base.port,
- conn_state_to_string(conn->_base.type, conn->_base.state));
- connection_mark_for_close(TO_CONN(conn));
+ conn->base_.address, conn->base_.port,
+ conn_state_to_string(conn->base_.type, conn->base_.state));
+ connection_or_close_for_error(conn, 0);
ret = -1;
}
@@ -430,18 +496,31 @@ connection_or_process_inbuf(or_connection_t *conn)
int
connection_or_flushed_some(or_connection_t *conn)
{
- size_t datalen = connection_get_outbuf_len(TO_CONN(conn));
+ size_t datalen, temp;
+ ssize_t n, flushed;
+
/* If we're under the low water mark, add cells until we're just over the
* high water mark. */
+ datalen = connection_get_outbuf_len(TO_CONN(conn));
if (datalen < OR_CONN_LOWWATER) {
- ssize_t n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, CELL_NETWORK_SIZE);
- time_t now = approx_time();
- while (conn->active_circuits && n > 0) {
- int flushed;
- flushed = connection_or_flush_from_first_active_circuit(conn, 1, now);
- n -= flushed;
+ while ((conn->chan) && channel_tls_more_to_flush(conn->chan)) {
+ /* Compute how many more cells we want at most */
+ n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, CELL_NETWORK_SIZE);
+ /* Bail out if we don't want any more */
+ if (n <= 0) break;
+ /* We're still here; try to flush some more cells */
+ flushed = channel_tls_flush_some_cells(conn->chan, n);
+ /* Bail out if it says it didn't flush anything */
+ if (flushed <= 0) break;
+ /* How much in the outbuf now? */
+ temp = connection_get_outbuf_len(TO_CONN(conn));
+ /* Bail out if we didn't actually increase the outbuf size */
+ if (temp <= datalen) break;
+ /* Update datalen for the next iteration */
+ datalen = temp;
}
}
+
return 0;
}
@@ -459,14 +538,14 @@ connection_or_finished_flushing(or_connection_t *conn)
tor_assert(conn);
assert_connection_ok(TO_CONN(conn),0);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case OR_CONN_STATE_PROXY_HANDSHAKING:
case OR_CONN_STATE_OPEN:
case OR_CONN_STATE_OR_HANDSHAKING_V2:
case OR_CONN_STATE_OR_HANDSHAKING_V3:
break;
default:
- log_err(LD_BUG,"Called in unexpected state %d.", conn->_base.state);
+ log_err(LD_BUG,"Called in unexpected state %d.", conn->base_.state);
tor_fragile_assert();
return -1;
}
@@ -480,6 +559,7 @@ connection_or_finished_connecting(or_connection_t *or_conn)
{
const int proxy_type = or_conn->proxy_type;
connection_t *conn;
+
tor_assert(or_conn);
conn = TO_CONN(or_conn);
tor_assert(conn->state == OR_CONN_STATE_CONNECTING);
@@ -491,18 +571,18 @@ connection_or_finished_connecting(or_connection_t *or_conn)
if (proxy_type != PROXY_NONE) {
/* start proxy handshake */
if (connection_proxy_connect(conn, proxy_type) < 0) {
- connection_mark_for_close(conn);
+ connection_or_close_for_error(or_conn, 0);
return -1;
}
connection_start_reading(conn);
- conn->state = OR_CONN_STATE_PROXY_HANDSHAKING;
+ connection_or_change_state(or_conn, OR_CONN_STATE_PROXY_HANDSHAKING);
return 0;
}
if (connection_tls_start_handshake(or_conn, 0) < 0) {
/* TLS handshaking error of some kind. */
- connection_mark_for_close(conn);
+ connection_or_close_for_error(or_conn, 0);
return -1;
}
return 0;
@@ -516,11 +596,14 @@ connection_or_about_to_close(or_connection_t *or_conn)
time_t now = time(NULL);
connection_t *conn = TO_CONN(or_conn);
+ /* Tell the controlling channel we're closed */
+ if (or_conn->chan) {
+ channel_closed(TLS_CHAN_TO_BASE(or_conn->chan));
+ or_conn->chan = NULL;
+ }
+
/* Remember why we're closing this connection. */
if (conn->state != OR_CONN_STATE_OPEN) {
- /* Inform any pending (not attached) circs that they should
- * give up. */
- circuit_n_conn_done(TO_OR_CONN(conn), 0);
/* now mark things down as needed */
if (connection_or_nonopen_was_started_here(or_conn)) {
const or_options_t *options = get_options();
@@ -548,9 +631,6 @@ connection_or_about_to_close(or_connection_t *or_conn)
control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED,
tls_error_to_orconn_end_reason(or_conn->tls_error));
}
- /* Now close all the attached circuits on it. */
- circuit_unlink_all_from_or_conn(TO_OR_CONN(conn),
- END_CIRC_REASON_OR_CONN_CLOSED);
}
/** Return 1 if identity digest <b>id_digest</b> is known to be a
@@ -613,8 +693,8 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset,
cfg = ev_token_bucket_cfg_new(rate_per_tick, burst, rate_per_tick,
burst, tick);
old_cfg = conn->bucket_cfg;
- if (conn->_base.bufev)
- tor_set_bufferevent_rate_limit(conn->_base.bufev, cfg);
+ if (conn->base_.bufev)
+ tor_set_bufferevent_rate_limit(conn->base_.bufev, cfg);
if (old_cfg)
ev_token_bucket_cfg_free(old_cfg);
conn->bucket_cfg = cfg;
@@ -663,15 +743,15 @@ connection_or_init_conn_from_address(or_connection_t *conn,
connection_or_set_identity_digest(conn, id_digest);
connection_or_update_token_buckets_helper(conn, 1, get_options());
- conn->_base.port = port;
- tor_addr_copy(&conn->_base.addr, addr);
+ conn->base_.port = port;
+ tor_addr_copy(&conn->base_.addr, addr);
tor_addr_copy(&conn->real_addr, addr);
if (r) {
tor_addr_port_t node_ap;
node_get_pref_orport(r, &node_ap);
/* XXXX proposal 186 is making this more complex. For now, a conn
is canonical when it uses the _preferred_ address. */
- if (tor_addr_eq(&conn->_base.addr, &node_ap.addr))
+ if (tor_addr_eq(&conn->base_.addr, &node_ap.addr))
conn->is_canonical = 1;
if (!started_here) {
/* Override the addr/port, so our log messages will make sense.
@@ -684,12 +764,12 @@ connection_or_init_conn_from_address(or_connection_t *conn,
* right IP address and port 56244, that wouldn't be as helpful. now we
* log the "right" port too, so we know if it's moria1 or moria2.
*/
- tor_addr_copy(&conn->_base.addr, &node_ap.addr);
- conn->_base.port = node_ap.port;
+ tor_addr_copy(&conn->base_.addr, &node_ap.addr);
+ conn->base_.port = node_ap.port;
}
conn->nickname = tor_strdup(node_get_nickname(r));
- tor_free(conn->_base.address);
- conn->_base.address = tor_dup_addr(&node_ap.addr);
+ tor_free(conn->base_.address);
+ conn->base_.address = tor_dup_addr(&node_ap.addr);
} else {
const char *n;
/* If we're an authoritative directory server, we may know a
@@ -703,157 +783,31 @@ connection_or_init_conn_from_address(or_connection_t *conn,
base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
conn->identity_digest, DIGEST_LEN);
}
- tor_free(conn->_base.address);
- conn->_base.address = tor_dup_addr(addr);
+ tor_free(conn->base_.address);
+ conn->base_.address = tor_dup_addr(addr);
}
}
-/** Return true iff <b>a</b> is "better" than <b>b</b> for new circuits.
- *
- * A more canonical connection is always better than a less canonical
- * connection. That aside, a connection is better if it has circuits and the
- * other does not, or if it was created more recently.
- *
- * Requires that both input connections are open; not is_bad_for_new_circs,
- * and not impossibly non-canonical.
- *
- * If <b>forgive_new_connections</b> is true, then we do not call
- * <b>a</b>better than <b>b</b> simply because b has no circuits,
- * unless b is also relatively old.
- */
-static int
-connection_or_is_better(time_t now,
- const or_connection_t *a,
- const or_connection_t *b,
- int forgive_new_connections)
-{
- int newer;
-/** Do not definitively deprecate a new connection with no circuits on it
- * until this much time has passed. */
-#define NEW_CONN_GRACE_PERIOD (15*60)
-
- if (b->is_canonical && !a->is_canonical)
- return 0; /* A canonical connection is better than a non-canonical
- * one, no matter how new it is or which has circuits. */
-
- newer = b->_base.timestamp_created < a->_base.timestamp_created;
-
- if (
- /* We prefer canonical connections regardless of newness. */
- (!b->is_canonical && a->is_canonical) ||
- /* If both have circuits we prefer the newer: */
- (b->n_circuits && a->n_circuits && newer) ||
- /* If neither has circuits we prefer the newer: */
- (!b->n_circuits && !a->n_circuits && newer))
- return 1;
+/** These just pass all the is_bad_for_new_circs manipulation on to
+ * channel_t */
- /* If one has no circuits and the other does... */
- if (!b->n_circuits && a->n_circuits) {
- /* Then it's bad, unless it's in its grace period and we're forgiving. */
- if (forgive_new_connections &&
- now < b->_base.timestamp_created + NEW_CONN_GRACE_PERIOD)
- return 0;
- else
- return 1;
- }
+static unsigned int
+connection_or_is_bad_for_new_circs(or_connection_t *or_conn)
+{
+ tor_assert(or_conn);
- return 0;
+ if (or_conn->chan)
+ return channel_is_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan));
+ else return 0;
}
-/** Return the OR connection we should use to extend a circuit to the router
- * whose identity is <b>digest</b>, and whose address we believe (or have been
- * told in an extend cell) is <b>target_addr</b>. If there is no good
- * connection, set *<b>msg_out</b> to a message describing the connection's
- * state and our next action, and set <b>launch_out</b> to a boolean for
- * whether we should launch a new connection or not.
- */
-or_connection_t *
-connection_or_get_for_extend(const char *digest,
- const tor_addr_t *target_addr,
- const char **msg_out,
- int *launch_out)
+static void
+connection_or_mark_bad_for_new_circs(or_connection_t *or_conn)
{
- or_connection_t *conn, *best=NULL;
- int n_inprogress_goodaddr = 0, n_old = 0, n_noncanonical = 0, n_possible = 0;
- time_t now = approx_time();
-
- tor_assert(msg_out);
- tor_assert(launch_out);
-
- if (!orconn_identity_map) {
- *msg_out = "Router not connected (nothing is). Connecting.";
- *launch_out = 1;
- return NULL;
- }
-
- conn = digestmap_get(orconn_identity_map, digest);
-
- for (; conn; conn = conn->next_with_same_id) {
- tor_assert(conn->_base.magic == OR_CONNECTION_MAGIC);
- tor_assert(conn->_base.type == CONN_TYPE_OR);
- tor_assert(tor_memeq(conn->identity_digest, digest, DIGEST_LEN));
- if (conn->_base.marked_for_close)
- continue;
- /* Never return a connection on which the other end appears to be
- * a client. */
- if (conn->is_connection_with_client) {
- continue;
- }
- /* Never return a non-open connection. */
- if (conn->_base.state != OR_CONN_STATE_OPEN) {
- /* If the address matches, don't launch a new connection for this
- * circuit. */
- if (!tor_addr_compare(&conn->real_addr, target_addr, CMP_EXACT))
- ++n_inprogress_goodaddr;
- continue;
- }
- /* Never return a connection that shouldn't be used for circs. */
- if (conn->is_bad_for_new_circs) {
- ++n_old;
- continue;
- }
- /* Never return a non-canonical connection using a recent link protocol
- * if the address is not what we wanted.
- *
- * (For old link protocols, we can't rely on is_canonical getting
- * set properly if we're talking to the right address, since we might
- * have an out-of-date descriptor, and we will get no NETINFO cell to
- * tell us about the right address.) */
- if (!conn->is_canonical && conn->link_proto >= 2 &&
- tor_addr_compare(&conn->real_addr, target_addr, CMP_EXACT)) {
- ++n_noncanonical;
- continue;
- }
-
- ++n_possible;
-
- if (!best) {
- best = conn; /* If we have no 'best' so far, this one is good enough. */
- continue;
- }
-
- if (connection_or_is_better(now, conn, best, 0))
- best = conn;
- }
+ tor_assert(or_conn);
- if (best) {
- *msg_out = "Connection is fine; using it.";
- *launch_out = 0;
- return best;
- } else if (n_inprogress_goodaddr) {
- *msg_out = "Connection in progress; waiting.";
- *launch_out = 0;
- return NULL;
- } else if (n_old || n_noncanonical) {
- *msg_out = "Connections all too old, or too non-canonical. "
- " Launching a new one.";
- *launch_out = 1;
- return NULL;
- } else {
- *msg_out = "Not connected. Connecting.";
- *launch_out = 1;
- return NULL;
- }
+ if (or_conn->chan)
+ channel_mark_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan));
}
/** How old do we let a connection to an OR get before deciding it's
@@ -874,8 +828,8 @@ connection_or_get_for_extend(const char *digest,
* - all open non-canonical connections for which a 'better' non-canonical
* connection exists to the same router at the same address.
*
- * See connection_or_is_better() for our idea of what makes one OR connection
- * better than another.
+ * See channel_is_better() in channel.c for our idea of what makes one OR
+ * connection better than another.
*/
static void
connection_or_group_set_badness(or_connection_t *head, int force)
@@ -887,23 +841,23 @@ connection_or_group_set_badness(or_connection_t *head, int force)
/* Pass 1: expire everything that's old, and see what the status of
* everything else is. */
for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) {
- if (or_conn->_base.marked_for_close ||
- or_conn->is_bad_for_new_circs)
+ if (or_conn->base_.marked_for_close ||
+ connection_or_is_bad_for_new_circs(or_conn))
continue;
if (force ||
- or_conn->_base.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
+ or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
< now) {
log_info(LD_OR,
"Marking OR conn to %s:%d as too old for new circuits "
- "(fd %d, %d secs old).",
- or_conn->_base.address, or_conn->_base.port, or_conn->_base.s,
- (int)(now - or_conn->_base.timestamp_created));
- or_conn->is_bad_for_new_circs = 1;
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old).",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
}
- if (or_conn->is_bad_for_new_circs) {
+ if (connection_or_is_bad_for_new_circs(or_conn)) {
++n_old;
- } else if (or_conn->_base.state != OR_CONN_STATE_OPEN) {
+ } else if (or_conn->base_.state != OR_CONN_STATE_OPEN) {
++n_inprogress;
} else if (or_conn->is_canonical) {
++n_canonical;
@@ -915,10 +869,10 @@ connection_or_group_set_badness(or_connection_t *head, int force)
/* Pass 2: We know how about how good the best connection is.
* expire everything that's worse, and find the very best if we can. */
for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) {
- if (or_conn->_base.marked_for_close ||
- or_conn->is_bad_for_new_circs)
+ if (or_conn->base_.marked_for_close ||
+ connection_or_is_bad_for_new_circs(or_conn))
continue; /* This one doesn't need to be marked bad. */
- if (or_conn->_base.state != OR_CONN_STATE_OPEN)
+ if (or_conn->base_.state != OR_CONN_STATE_OPEN)
continue; /* Don't mark anything bad until we have seen what happens
* when the connection finishes. */
if (n_canonical && !or_conn->is_canonical) {
@@ -926,16 +880,21 @@ connection_or_group_set_badness(or_connection_t *head, int force)
* and this one is open but not canonical. Mark it bad. */
log_info(LD_OR,
"Marking OR conn to %s:%d as unsuitable for new circuits: "
- "(fd %d, %d secs old). It is not canonical, and we have "
- "another connection to that OR that is.",
- or_conn->_base.address, or_conn->_base.port, or_conn->_base.s,
- (int)(now - or_conn->_base.timestamp_created));
- or_conn->is_bad_for_new_circs = 1;
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old). It is not "
+ "canonical, and we have another connection to that OR that is.",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
continue;
}
- if (!best || connection_or_is_better(now, or_conn, best, 0))
+ if (!best ||
+ channel_is_better(now,
+ TLS_CHAN_TO_BASE(or_conn->chan),
+ TLS_CHAN_TO_BASE(best->chan),
+ 0)) {
best = or_conn;
+ }
}
if (!best)
@@ -956,32 +915,37 @@ connection_or_group_set_badness(or_connection_t *head, int force)
* "mostly harmless", so a fix can wait until somebody is bored.
*/
for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) {
- if (or_conn->_base.marked_for_close ||
- or_conn->is_bad_for_new_circs ||
- or_conn->_base.state != OR_CONN_STATE_OPEN)
+ if (or_conn->base_.marked_for_close ||
+ connection_or_is_bad_for_new_circs(or_conn) ||
+ or_conn->base_.state != OR_CONN_STATE_OPEN)
continue;
- if (or_conn != best && connection_or_is_better(now, best, or_conn, 1)) {
+ if (or_conn != best &&
+ channel_is_better(now,
+ TLS_CHAN_TO_BASE(best->chan),
+ TLS_CHAN_TO_BASE(or_conn->chan), 1)) {
/* This isn't the best conn, _and_ the best conn is better than it,
even when we're being forgiving. */
if (best->is_canonical) {
log_info(LD_OR,
"Marking OR conn to %s:%d as unsuitable for new circuits: "
- "(fd %d, %d secs old). We have a better canonical one "
- "(fd %d; %d secs old).",
- or_conn->_base.address, or_conn->_base.port, or_conn->_base.s,
- (int)(now - or_conn->_base.timestamp_created),
- best->_base.s, (int)(now - best->_base.timestamp_created));
- or_conn->is_bad_for_new_circs = 1;
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old). "
+ "We have a better canonical one "
+ "(fd "TOR_SOCKET_T_FORMAT"; %d secs old).",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created),
+ best->base_.s, (int)(now - best->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
} else if (!tor_addr_compare(&or_conn->real_addr,
&best->real_addr, CMP_EXACT)) {
log_info(LD_OR,
"Marking OR conn to %s:%d as unsuitable for new circuits: "
- "(fd %d, %d secs old). We have a better one with the "
- "same address (fd %d; %d secs old).",
- or_conn->_base.address, or_conn->_base.port, or_conn->_base.s,
- (int)(now - or_conn->_base.timestamp_created),
- best->_base.s, (int)(now - best->_base.timestamp_created));
- or_conn->is_bad_for_new_circs = 1;
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old). We have a better "
+ "one with the "
+ "same address (fd "TOR_SOCKET_T_FORMAT"; %d secs old).",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created),
+ best->base_.s, (int)(now - best->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
}
}
}
@@ -1019,8 +983,41 @@ connection_or_connect_failed(or_connection_t *conn,
control_event_bootstrap_problem(msg, reason);
}
+/** <b>conn</b> got an error in connection_handle_read_impl() or
+ * connection_handle_write_impl() and is going to die soon.
+ *
+ * <b>reason</b> specifies the or_conn_end_reason for the failure;
+ * <b>msg</b> specifies the strerror-style error message.
+ */
+void
+connection_or_notify_error(or_connection_t *conn,
+ int reason, const char *msg)
+{
+ channel_t *chan;
+
+ tor_assert(conn);
+
+ /* If we're connecting, call connect_failed() too */
+ if (TO_CONN(conn)->state == OR_CONN_STATE_CONNECTING)
+ connection_or_connect_failed(conn, reason, msg);
+
+ /* Tell the controlling channel if we have one */
+ if (conn->chan) {
+ chan = TLS_CHAN_TO_BASE(conn->chan);
+ /* Don't transition if we're already in closing, closed or error */
+ if (!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ channel_close_for_error(chan);
+ }
+ }
+
+ /* No need to mark for error because connection.c is about to do that */
+}
+
/** Launch a new OR connection to <b>addr</b>:<b>port</b> and expect to
- * handshake with an OR with identity digest <b>id_digest</b>.
+ * handshake with an OR with identity digest <b>id_digest</b>. Optionally,
+ * pass in a pointer to a channel using this connection.
*
* If <b>id_digest</b> is me, do nothing. If we're already connected to it,
* return that connection. If the connect() is in progress, set the
@@ -1035,7 +1032,8 @@ connection_or_connect_failed(or_connection_t *conn,
*/
or_connection_t *
connection_or_connect(const tor_addr_t *_addr, uint16_t port,
- const char *id_digest)
+ const char *id_digest,
+ channel_tls_t *chan)
{
or_connection_t *conn;
const or_options_t *options = get_options();
@@ -1058,9 +1056,17 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
conn = or_connection_new(tor_addr_family(&addr));
- /* set up conn so it's got all the data we need to remember */
+ /*
+ * Set up conn so it's got all the data we need to remember for channels
+ *
+ * This stuff needs to happen before connection_or_init_conn_from_address()
+ * so connection_or_set_identity_digest() and such know where to look to
+ * keep the channel up to date.
+ */
+ conn->chan = chan;
+ chan->conn = conn;
connection_or_init_conn_from_address(conn, &addr, port, id_digest, 1);
- conn->_base.state = OR_CONN_STATE_CONNECTING;
+ connection_or_change_state(conn, OR_CONN_STATE_CONNECTING);
control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0);
conn->is_outgoing = 1;
@@ -1072,7 +1078,7 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
if (proxy_type != PROXY_NONE) {
tor_addr_copy(&addr, &proxy_addr);
port = proxy_port;
- conn->_base.proxy_state = PROXY_INFANT;
+ conn->base_.proxy_state = PROXY_INFANT;
}
} else {
/* get_proxy_addrport() might fail if we have a Bridge line that
@@ -1084,29 +1090,29 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
TO_CONN(conn)->port);
if (transport_name) {
- log_warn(LD_GENERAL, "We were supposed to connect to bridge '%s:%u' "
+ log_warn(LD_GENERAL, "We were supposed to connect to bridge '%s' "
"using pluggable transport '%s', but we can't find a pluggable "
"transport proxy supporting '%s'. This can happen if you "
"haven't provided a ClientTransportPlugin line, or if "
"your pluggable transport proxy stopped running.",
- fmt_addr(&TO_CONN(conn)->addr), TO_CONN(conn)->port,
+ fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port),
transport_name, transport_name);
} else {
- log_warn(LD_GENERAL, "Tried to connect to '%s:%u' through a proxy, but "
+ log_warn(LD_GENERAL, "Tried to connect to '%s' through a proxy, but "
"the proxy address could not be found.",
- fmt_addr(&TO_CONN(conn)->addr), TO_CONN(conn)->port);
+ fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port));
}
connection_free(TO_CONN(conn));
return NULL;
}
- switch (connection_connect(TO_CONN(conn), conn->_base.address,
+ switch (connection_connect(TO_CONN(conn), conn->base_.address,
&addr, port, &socket_error)) {
case -1:
/* If the connection failed immediately, and we're using
* a proxy, our proxy is down. Don't blame the Tor server. */
- if (conn->_base.proxy_state == PROXY_INFANT)
+ if (conn->base_.proxy_state == PROXY_INFANT)
entry_guard_register_connect_status(conn->identity_digest,
0, 1, time(NULL));
connection_or_connect_failed(conn,
@@ -1129,6 +1135,52 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
return conn;
}
+/** Mark orconn for close and transition the associated channel, if any, to
+ * the closing state.
+ */
+
+void
+connection_or_close_normally(or_connection_t *orconn, int flush)
+{
+ channel_t *chan = NULL;
+
+ tor_assert(orconn);
+ if (flush) connection_mark_and_flush_internal(TO_CONN(orconn));
+ else connection_mark_for_close_internal(TO_CONN(orconn));
+ if (orconn->chan) {
+ chan = TLS_CHAN_TO_BASE(orconn->chan);
+ /* Don't transition if we're already in closing, closed or error */
+ if (!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ channel_close_from_lower_layer(chan);
+ }
+ }
+}
+
+/** Mark orconn for close and transition the associated channel, if any, to
+ * the error state.
+ */
+
+void
+connection_or_close_for_error(or_connection_t *orconn, int flush)
+{
+ channel_t *chan = NULL;
+
+ tor_assert(orconn);
+ if (flush) connection_mark_and_flush_internal(TO_CONN(orconn));
+ else connection_mark_for_close_internal(TO_CONN(orconn));
+ if (orconn->chan) {
+ chan = TLS_CHAN_TO_BASE(orconn->chan);
+ /* Don't transition if we're already in closing, closed or error */
+ if (!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ channel_close_for_error(chan);
+ }
+ }
+}
+
/** Begin the tls handshake with <b>conn</b>. <b>receiving</b> is 0 if
* we initiated the connection, else it's 1.
*
@@ -1140,29 +1192,46 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
int
connection_tls_start_handshake(or_connection_t *conn, int receiving)
{
- conn->_base.state = OR_CONN_STATE_TLS_HANDSHAKING;
+ channel_listener_t *chan_listener;
+ channel_t *chan;
+
+ /* Incoming connections will need a new channel passed to the
+ * channel_tls_listener */
+ if (receiving) {
+ /* It shouldn't already be set */
+ tor_assert(!(conn->chan));
+ chan_listener = channel_tls_get_listener();
+ if (!chan_listener) {
+ chan_listener = channel_tls_start_listener();
+ command_setup_listener(chan_listener);
+ }
+ chan = channel_tls_handle_incoming(conn);
+ channel_listener_queue_incoming(chan_listener, chan);
+ }
+
+ connection_or_change_state(conn, OR_CONN_STATE_TLS_HANDSHAKING);
tor_assert(!conn->tls);
- conn->tls = tor_tls_new(conn->_base.s, receiving);
+ conn->tls = tor_tls_new(conn->base_.s, receiving);
if (!conn->tls) {
log_warn(LD_BUG,"tor_tls_new failed. Closing.");
return -1;
}
tor_tls_set_logged_address(conn->tls, // XXX client and relay?
- escaped_safe_str(conn->_base.address));
+ escaped_safe_str(conn->base_.address));
#ifdef USE_BUFFEREVENTS
if (connection_type_uses_bufferevent(TO_CONN(conn))) {
- const int filtering = get_options()->_UseFilteringSSLBufferevents;
+ const int filtering = get_options()->UseFilteringSSLBufferevents;
struct bufferevent *b =
- tor_tls_init_bufferevent(conn->tls, conn->_base.bufev, conn->_base.s,
+ tor_tls_init_bufferevent(conn->tls, conn->base_.bufev, conn->base_.s,
receiving, filtering);
if (!b) {
log_warn(LD_BUG,"tor_tls_init_bufferevent failed. Closing.");
return -1;
}
- conn->_base.bufev = b;
+ conn->base_.bufev = b;
if (conn->bucket_cfg)
- tor_set_bufferevent_rate_limit(conn->_base.bufev, conn->bucket_cfg);
+ tor_set_bufferevent_rate_limit(conn->base_.bufev, conn->bucket_cfg);
connection_enable_rate_limiting(TO_CONN(conn));
connection_configure_bufferevent_callbacks(TO_CONN(conn));
@@ -1174,7 +1243,8 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving)
}
#endif
connection_start_reading(TO_CONN(conn));
- log_debug(LD_HANDSHAKE,"starting TLS handshake on fd %d", conn->_base.s);
+ log_debug(LD_HANDSHAKE,"starting TLS handshake on fd "TOR_SOCKET_T_FORMAT,
+ conn->base_.s);
note_crypto_pk_op(receiving ? TLS_HANDSHAKE_S : TLS_HANDSHAKE_C);
IF_HAS_BUFFEREVENT(TO_CONN(conn), {
@@ -1211,7 +1281,7 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn)
if (connection_tls_finish_handshake(conn) < 0) {
/* XXXX_TLS double-check that it's ok to do this from inside read. */
/* XXXX_TLS double-check that this verifies certificates. */
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
}
}
@@ -1226,12 +1296,12 @@ connection_tls_continue_handshake(or_connection_t *conn)
int result;
check_no_tls_errors();
again:
- if (conn->_base.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) {
+ if (conn->base_.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) {
// log_notice(LD_OR, "Renegotiate with %p", conn->tls);
result = tor_tls_renegotiate(conn->tls);
// log_notice(LD_OR, "Result: %d", result);
} else {
- tor_assert(conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING);
+ tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING);
// log_notice(LD_OR, "Continue handshake with %p", conn->tls);
result = tor_tls_handshake(conn->tls);
// log_notice(LD_OR, "Result: %d", result);
@@ -1244,7 +1314,7 @@ connection_tls_continue_handshake(or_connection_t *conn)
case TOR_TLS_DONE:
if (! tor_tls_used_v1_handshake(conn->tls)) {
if (!tor_tls_is_server(conn->tls)) {
- if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) {
+ if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_received_v3_certificate(conn->tls)) {
log_info(LD_OR, "Client got a v3 cert! Moving on to v3 "
"handshake.");
@@ -1252,11 +1322,12 @@ connection_tls_continue_handshake(or_connection_t *conn)
} else {
log_debug(LD_OR, "Done with initial SSL handshake (client-side)."
" Requesting renegotiation.");
- conn->_base.state = OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING;
+ connection_or_change_state(conn,
+ OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
goto again;
}
}
- // log_notice(LD_OR,"Done. state was %d.", conn->_base.state);
+ // log_notice(LD_OR,"Done. state was %d.", conn->base_.state);
} else {
/* v2/v3 handshake, but not a client. */
log_debug(LD_OR, "Done with initial SSL handshake (server-side). "
@@ -1264,7 +1335,8 @@ connection_tls_continue_handshake(or_connection_t *conn)
tor_tls_set_renegotiate_callback(conn->tls,
connection_or_tls_renegotiated_cb,
conn);
- conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING;
+ connection_or_change_state(conn,
+ OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
connection_stop_writing(TO_CONN(conn));
connection_start_reading(TO_CONN(conn));
return 0;
@@ -1294,28 +1366,29 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
/* XXXX cut-and-paste code; should become a function. */
if (event & BEV_EVENT_CONNECTED) {
- if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) {
+ if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_finish_handshake(conn->tls) < 0) {
log_warn(LD_OR, "Problem finishing handshake");
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
return;
}
}
if (! tor_tls_used_v1_handshake(conn->tls)) {
if (!tor_tls_is_server(conn->tls)) {
- if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) {
+ if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_received_v3_certificate(conn->tls)) {
log_info(LD_OR, "Client got a v3 cert!");
if (connection_or_launch_v3_or_handshake(conn) < 0)
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
return;
} else {
- conn->_base.state = OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING;
+ connection_or_change_state(conn,
+ OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
tor_tls_unblock_renegotiation(conn->tls);
- if (bufferevent_ssl_renegotiate(conn->_base.bufev)<0) {
+ if (bufferevent_ssl_renegotiate(conn->base_.bufev)<0) {
log_warn(LD_OR, "Start_renegotiating went badly.");
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
}
tor_tls_unblock_renegotiation(conn->tls);
return; /* ???? */
@@ -1330,7 +1403,8 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
tor_tls_set_renegotiate_callback(conn->tls,
connection_or_tls_renegotiated_cb,
conn);
- conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING;
+ connection_or_change_state(conn,
+ OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
} else if (handshakes == 2) {
/* v2 handshake, as a server. Two handshakes happened already,
* so we treat renegotiation as done.
@@ -1339,18 +1413,18 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
} else if (handshakes > 2) {
log_warn(LD_OR, "More than two handshakes done on connection. "
"Closing.");
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
} else {
log_warn(LD_BUG, "We were unexpectedly told that a connection "
"got %d handshakes. Closing.", handshakes);
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
}
return;
}
}
connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT);
if (connection_tls_finish_handshake(conn) < 0)
- connection_mark_for_close(TO_CONN(conn)); /* ???? */
+ connection_or_close_for_error(conn, 0); /* ???? */
return;
}
@@ -1372,7 +1446,7 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
int
connection_or_nonopen_was_started_here(or_connection_t *conn)
{
- tor_assert(conn->_base.type == CONN_TYPE_OR);
+ tor_assert(conn->base_.type == CONN_TYPE_OR);
if (!conn->tls)
return 1; /* it's still in proxy states or something */
if (conn->handshake_state)
@@ -1380,29 +1454,6 @@ connection_or_nonopen_was_started_here(or_connection_t *conn)
return !tor_tls_is_server(conn->tls);
}
-/** Set the circid_type field of <b>conn</b> (which determines which part of
- * the circuit ID space we're willing to use) based on comparing our ID to
- * <b>identity_rcvd</b> */
-void
-connection_or_set_circid_type(or_connection_t *conn,
- crypto_pk_t *identity_rcvd)
-{
- const int started_here = connection_or_nonopen_was_started_here(conn);
- crypto_pk_t *our_identity =
- started_here ? get_tlsclient_identity_key() :
- get_server_identity_key();
-
- if (identity_rcvd) {
- if (crypto_pk_cmp_keys(our_identity, identity_rcvd)<0) {
- conn->circ_id_type = CIRC_ID_TYPE_LOWER;
- } else {
- conn->circ_id_type = CIRC_ID_TYPE_HIGHER;
- }
- } else {
- conn->circ_id_type = CIRC_ID_TYPE_NEITHER;
- }
-}
-
/** <b>Conn</b> just completed its handshake. Return 0 if all is well, and
* return -1 if he is lying, broken, or otherwise something is wrong.
*
@@ -1437,8 +1488,8 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
const or_options_t *options = get_options();
int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN;
const char *safe_address =
- started_here ? conn->_base.address :
- safe_str_client(conn->_base.address);
+ started_here ? conn->base_.address :
+ safe_str_client(conn->base_.address);
const char *conn_type = started_here ? "outgoing" : "incoming";
int has_cert = 0;
@@ -1447,7 +1498,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
if (started_here && !has_cert) {
log_info(LD_HANDSHAKE,"Tried connecting to router at %s:%d, but it didn't "
"send a cert! Closing.",
- safe_address, conn->_base.port);
+ safe_address, conn->base_.port);
return -1;
} else if (!has_cert) {
log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. "
@@ -1461,7 +1512,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
if (started_here && v<0) {
log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s:%d: It"
" has a cert but it's invalid. Closing.",
- safe_address, conn->_base.port);
+ safe_address, conn->base_.port);
return -1;
} else if (v<0) {
log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert "
@@ -1469,7 +1520,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
} else {
log_debug(LD_HANDSHAKE,
"The certificate seems to be valid on %s connection "
- "with %s:%d", conn_type, safe_address, conn->_base.port);
+ "with %s:%d", conn_type, safe_address, conn->base_.port);
}
check_no_tls_errors();
}
@@ -1480,7 +1531,8 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
memset(digest_rcvd_out, 0, DIGEST_LEN);
}
- connection_or_set_circid_type(conn, identity_rcvd);
+ tor_assert(conn->chan);
+ channel_set_circid_type(TLS_CHAN_TO_BASE(conn->chan), identity_rcvd);
crypto_pk_free(identity_rcvd);
if (started_here)
@@ -1521,10 +1573,10 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
conn->identity_digest, DIGEST_LEN);
log_info(LD_HANDSHAKE, "Connected to router %s at %s:%d without knowing "
"its key. Hoping for the best.",
- conn->nickname, conn->_base.address, conn->_base.port);
+ conn->nickname, conn->base_.address, conn->base_.port);
/* if it's a bridge and we didn't know its identity fingerprint, now
* we do -- remember it for future attempts. */
- learned_router_identity(&conn->_base.addr, conn->_base.port,
+ learned_router_identity(&conn->base_.addr, conn->base_.port,
(const char*)peer_id);
}
@@ -1538,7 +1590,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
log_fn(severity, LD_HANDSHAKE,
"Tried connecting to router at %s:%d, but identity key was not "
"as expected: wanted %s but got %s.",
- conn->_base.address, conn->_base.port, expected, seen);
+ conn->base_.address, conn->base_.port, expected, seen);
entry_guard_register_connect_status(conn->identity_digest, 0, 1,
time(NULL));
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED,
@@ -1550,13 +1602,26 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
return -1;
}
if (authdir_mode_tests_reachability(options)) {
- dirserv_orconn_tls_done(conn->_base.address, conn->_base.port,
+ dirserv_orconn_tls_done(&conn->base_.addr, conn->base_.port,
(const char*)peer_id);
}
return 0;
}
+/** Return when a client used this, for connection.c, since client_used
+ * is now one of the timestamps of channel_t */
+
+time_t
+connection_or_client_used(or_connection_t *conn)
+{
+ tor_assert(conn);
+
+ if (conn->chan) {
+ return channel_when_last_client(TLS_CHAN_TO_BASE(conn->chan));
+ } else return 0;
+}
+
/** The v1/v2 TLS handshake is finished.
*
* Make sure we are happy with the person we just handshaked with.
@@ -1579,7 +1644,7 @@ connection_tls_finish_handshake(or_connection_t *conn)
log_debug(LD_HANDSHAKE,"%s tls handshake on %p with %s done. verifying.",
started_here?"outgoing":"incoming",
conn,
- safe_str_client(conn->_base.address));
+ safe_str_client(conn->base_.address));
directory_set_dirty();
@@ -1592,18 +1657,18 @@ connection_tls_finish_handshake(or_connection_t *conn)
if (tor_tls_used_v1_handshake(conn->tls)) {
conn->link_proto = 1;
if (!started_here) {
- connection_or_init_conn_from_address(conn, &conn->_base.addr,
- conn->_base.port, digest_rcvd, 0);
+ connection_or_init_conn_from_address(conn, &conn->base_.addr,
+ conn->base_.port, digest_rcvd, 0);
}
tor_tls_block_renegotiation(conn->tls);
return connection_or_set_state_open(conn);
} else {
- conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V2;
+ connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2);
if (connection_init_or_handshake_state(conn, started_here) < 0)
return -1;
if (!started_here) {
- connection_or_init_conn_from_address(conn, &conn->_base.addr,
- conn->_base.port, digest_rcvd, 0);
+ connection_or_init_conn_from_address(conn, &conn->base_.addr,
+ conn->base_.port, digest_rcvd, 0);
}
return connection_or_send_versions(conn, 0);
}
@@ -1623,7 +1688,7 @@ connection_or_launch_v3_or_handshake(or_connection_t *conn)
circuit_build_times_network_is_live(&circ_times);
- conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
if (connection_init_or_handshake_state(conn, 1) < 0)
return -1;
@@ -1742,35 +1807,9 @@ or_handshake_state_record_var_cell(or_handshake_state_t *state,
int
connection_or_set_state_open(or_connection_t *conn)
{
- int started_here = connection_or_nonopen_was_started_here(conn);
- time_t now = time(NULL);
- conn->_base.state = OR_CONN_STATE_OPEN;
+ connection_or_change_state(conn, OR_CONN_STATE_OPEN);
control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED, 0);
- if (started_here) {
- circuit_build_times_network_is_live(&circ_times);
- rep_hist_note_connect_succeeded(conn->identity_digest, now);
- if (entry_guard_register_connect_status(conn->identity_digest,
- 1, 0, now) < 0) {
- /* Close any circuits pending on this conn. We leave it in state
- * 'open' though, because it didn't actually *fail* -- we just
- * chose not to use it. (Otherwise
- * connection_about_to_close_connection() will call a big pile of
- * functions to indicate we shouldn't try it again.) */
- log_debug(LD_OR, "New entry guard was reachable, but closing this "
- "connection so we can retry the earlier entry guards.");
- circuit_n_conn_done(conn, 0);
- return -1;
- }
- router_set_status(conn->identity_digest, 1);
- } else {
- /* only report it to the geoip module if it's not a known router */
- if (!router_get_by_id_digest(conn->identity_digest)) {
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(conn)->addr,
- now);
- }
- }
-
or_handshake_state_free(conn->handshake_state);
conn->handshake_state = NULL;
IF_HAS_BUFFEREVENT(TO_CONN(conn), {
@@ -1779,8 +1818,6 @@ connection_or_set_state_open(or_connection_t *conn)
connection_start_reading(TO_CONN(conn));
}
- circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
-
return 0;
}
@@ -1800,7 +1837,11 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
connection_write_to_buf(networkcell.body, CELL_NETWORK_SIZE, TO_CONN(conn));
- if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
+
+ if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
or_handshake_state_record_cell(conn->handshake_state, cell, 0);
if (cell->command != CELL_PADDING)
@@ -1822,10 +1863,14 @@ connection_or_write_var_cell_to_buf(const var_cell_t *cell,
connection_write_to_buf(hdr, sizeof(hdr), TO_CONN(conn));
connection_write_to_buf((char*)cell->payload,
cell->payload_len, TO_CONN(conn));
- if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
+ if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
or_handshake_state_record_var_cell(conn->handshake_state, cell, 0);
if (cell->command != CELL_PADDING)
conn->timestamp_last_added_nonpadding = approx_time();
+
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
}
/** See whether there's a variable-length cell waiting on <b>or_conn</b>'s
@@ -1856,14 +1901,20 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn)
while (1) {
log_debug(LD_OR,
- "%d: starting, inbuf_datalen %d (%d pending in tls object).",
- conn->_base.s,(int)connection_get_inbuf_len(TO_CONN(conn)),
+ TOR_SOCKET_T_FORMAT": starting, inbuf_datalen %d "
+ "(%d pending in tls object).",
+ conn->base_.s,(int)connection_get_inbuf_len(TO_CONN(conn)),
tor_tls_get_pending_bytes(conn->tls));
if (connection_fetch_var_cell_from_buf(conn, &var_cell)) {
if (!var_cell)
return 0; /* not yet. */
+
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
+
circuit_build_times_network_is_live(&circ_times);
- command_process_var_cell(var_cell, conn);
+ channel_tls_handle_var_cell(var_cell, conn);
var_cell_free(var_cell);
} else {
char buf[CELL_NETWORK_SIZE];
@@ -1872,6 +1923,10 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn)
< CELL_NETWORK_SIZE) /* whole response available? */
return 0; /* not yet */
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
+
circuit_build_times_network_is_live(&circ_times);
connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
@@ -1879,34 +1934,11 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn)
* network-order string) */
cell_unpack(&cell, buf);
- command_process_cell(&cell, conn);
+ channel_tls_handle_cell(&cell, conn);
}
}
}
-/** Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
- * onto OR connection <b>conn</b>. Don't perform range-checking on reason:
- * we may want to propagate reasons from other cells.
- *
- * Return 0.
- */
-int
-connection_or_send_destroy(circid_t circ_id, or_connection_t *conn, int reason)
-{
- cell_t cell;
-
- tor_assert(conn);
-
- memset(&cell, 0, sizeof(cell_t));
- cell.circ_id = circ_id;
- cell.command = CELL_DESTROY;
- cell.payload[0] = (uint8_t) reason;
- log_debug(LD_OR,"Sending destroy (circID %d).", circ_id);
-
- connection_or_write_cell_to_buf(&cell, conn);
- return 0;
-}
-
/** Array of recognized link protocol versions. */
static const uint16_t or_protocol_versions[] = { 1, 2, 3 };
/** Number of versions in <b>or_protocol_versions</b>. */
@@ -1984,10 +2016,10 @@ connection_or_send_netinfo(or_connection_t *conn)
/* Their address. */
out = cell.payload + 4;
/* We use &conn->real_addr below, unless it hasn't yet been set. If it
- * hasn't yet been set, we know that _base.addr hasn't been tampered with
+ * hasn't yet been set, we know that base_.addr hasn't been tampered with
* yet either. */
len = append_address_to_payload(out, !tor_addr_is_null(&conn->real_addr)
- ? &conn->real_addr : &conn->_base.addr);
+ ? &conn->real_addr : &conn->base_.addr);
if (len<0)
return -1;
out += len;
@@ -1998,12 +2030,19 @@ connection_or_send_netinfo(or_connection_t *conn)
if ((public_server_mode(get_options()) || !conn->is_outgoing) &&
(me = router_get_my_routerinfo())) {
tor_addr_t my_addr;
- *out++ = 1; /* only one address is supported. */
+ *out++ = 1 + !tor_addr_is_null(&me->ipv6_addr);
tor_addr_from_ipv4h(&my_addr, me->addr);
len = append_address_to_payload(out, &my_addr);
if (len < 0)
return -1;
+ out += len;
+
+ if (!tor_addr_is_null(&me->ipv6_addr)) {
+ len = append_address_to_payload(out, &me->ipv6_addr);
+ if (len < 0)
+ return -1;
+ }
} else {
*out = 0;
}
@@ -2027,7 +2066,7 @@ connection_or_send_certs_cell(or_connection_t *conn)
ssize_t pos;
int server_mode;
- tor_assert(conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
+ tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
if (! conn->handshake_state)
return -1;
@@ -2074,7 +2113,7 @@ connection_or_send_auth_challenge_cell(or_connection_t *conn)
var_cell_t *cell;
uint8_t *cp;
uint8_t challenge[OR_AUTH_CHALLENGE_LEN];
- tor_assert(conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
+ tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
if (! conn->handshake_state)
return -1;
diff --git a/src/or/connection_or.h b/src/or/connection_or.h
index b78c444921..727de211b0 100644
--- a/src/or/connection_or.h
+++ b/src/or/connection_or.h
@@ -9,8 +9,8 @@
* \brief Header file for connection_or.c.
**/
-#ifndef _TOR_CONNECTION_OR_H
-#define _TOR_CONNECTION_OR_H
+#ifndef TOR_CONNECTION_OR_H
+#define TOR_CONNECTION_OR_H
void connection_or_remove_from_identity_map(or_connection_t *conn);
void connection_or_clear_identity_map(void);
@@ -34,8 +34,14 @@ void connection_or_update_token_buckets(smartlist_t *conns,
void connection_or_connect_failed(or_connection_t *conn,
int reason, const char *msg);
+void connection_or_notify_error(or_connection_t *conn,
+ int reason, const char *msg);
or_connection_t *connection_or_connect(const tor_addr_t *addr, uint16_t port,
- const char *id_digest);
+ const char *id_digest,
+ channel_tls_t *chan);
+
+void connection_or_close_normally(or_connection_t *orconn, int flush);
+void connection_or_close_for_error(or_connection_t *orconn, int flush);
void connection_or_report_broken_states(int severity, int domain);
@@ -51,8 +57,8 @@ void connection_or_init_conn_from_address(or_connection_t *conn,
int started_here);
int connection_or_client_learned_peer_id(or_connection_t *conn,
const uint8_t *peer_id);
-void connection_or_set_circid_type(or_connection_t *conn,
- crypto_pk_t *identity_rcvd);
+time_t connection_or_client_used(or_connection_t *conn);
+int connection_or_get_num_circuits(or_connection_t *conn);
void or_handshake_state_free(or_handshake_state_t *state);
void or_handshake_state_record_cell(or_handshake_state_t *state,
const cell_t *cell,
@@ -66,8 +72,6 @@ void connection_or_write_cell_to_buf(const cell_t *cell,
or_connection_t *conn);
void connection_or_write_var_cell_to_buf(const var_cell_t *cell,
or_connection_t *conn);
-int connection_or_send_destroy(circid_t circ_id, or_connection_t *conn,
- int reason);
int connection_or_send_versions(or_connection_t *conn, int v3_plus);
int connection_or_send_netinfo(or_connection_t *conn);
int connection_or_send_certs_cell(or_connection_t *conn);
diff --git a/src/or/control.c b/src/or/control.c
index 913d18a7fc..75c9af6f7b 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -11,11 +11,16 @@
#define CONTROL_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitstats.h"
#include "circuituse.h"
#include "config.h"
+#include "confparse.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
@@ -23,6 +28,7 @@
#include "directory.h"
#include "dirserv.h"
#include "dnsserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
@@ -50,7 +56,7 @@
* because it is used both as a list of v0 event types, and as indices
* into the bitfield to determine which controllers want which events.
*/
-#define _EVENT_MIN 0x0001
+#define EVENT_MIN_ 0x0001
#define EVENT_CIRCUIT_STATUS 0x0001
#define EVENT_STREAM_STATUS 0x0002
#define EVENT_OR_CONN_STATUS 0x0003
@@ -76,8 +82,8 @@
#define EVENT_BUILDTIMEOUT_SET 0x0017
#define EVENT_SIGNAL 0x0018
#define EVENT_CONF_CHANGED 0x0019
-#define _EVENT_MAX 0x0019
-/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */
+#define EVENT_MAX_ 0x0019
+/* If EVENT_MAX_ ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1&lt;&lt;e is set if <b>any</b> open control
* connection is interested in events of type <b>e</b>. We use this
@@ -592,7 +598,7 @@ send_control_event_string(uint16_t event, event_format_t which,
{
smartlist_t *conns = get_connection_array();
(void)which;
- tor_assert(event >= _EVENT_MIN && event <= _EVENT_MAX);
+ tor_assert(event >= EVENT_MIN_ && event <= EVENT_MAX_);
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
if (conn->type == CONN_TYPE_CONTROL &&
@@ -1215,9 +1221,10 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
connection_mark_for_close(TO_CONN(conn));
return 0;
ok:
- log_info(LD_CONTROL, "Authenticated control connection (%d)", conn->_base.s);
+ log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT
+ ")", conn->base_.s);
send_control_done(conn);
- conn->_base.state = CONTROL_CONN_STATE_OPEN;
+ conn->base_.state = CONTROL_CONN_STATE_OPEN;
tor_free(password);
if (sl) { /* clean up */
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
@@ -1243,6 +1250,27 @@ handle_control_saveconf(control_connection_t *conn, uint32_t len,
return 0;
}
+struct signal_t {
+ int sig;
+ const char *signal_name;
+};
+
+static const struct signal_t signal_table[] = {
+ { SIGHUP, "RELOAD" },
+ { SIGHUP, "HUP" },
+ { SIGINT, "SHUTDOWN" },
+ { SIGUSR1, "DUMP" },
+ { SIGUSR1, "USR1" },
+ { SIGUSR2, "DEBUG" },
+ { SIGUSR2, "USR2" },
+ { SIGTERM, "HALT" },
+ { SIGTERM, "TERM" },
+ { SIGTERM, "INT" },
+ { SIGNEWNYM, "NEWNYM" },
+ { SIGCLEARDNSCACHE, "CLEARDNSCACHE"},
+ { 0, NULL },
+};
+
/** Called when we get a SIGNAL command. React to the provided signal, and
* report success or failure. (If the signal results in a shutdown, success
* may not be reported.) */
@@ -1250,7 +1278,8 @@ static int
handle_control_signal(control_connection_t *conn, uint32_t len,
const char *body)
{
- int sig;
+ int sig = -1;
+ int i;
int n = 0;
char *s;
@@ -1259,27 +1288,19 @@ handle_control_signal(control_connection_t *conn, uint32_t len,
while (body[n] && ! TOR_ISSPACE(body[n]))
++n;
s = tor_strndup(body, n);
- if (!strcasecmp(s, "RELOAD") || !strcasecmp(s, "HUP"))
- sig = SIGHUP;
- else if (!strcasecmp(s, "SHUTDOWN") || !strcasecmp(s, "INT"))
- sig = SIGINT;
- else if (!strcasecmp(s, "DUMP") || !strcasecmp(s, "USR1"))
- sig = SIGUSR1;
- else if (!strcasecmp(s, "DEBUG") || !strcasecmp(s, "USR2"))
- sig = SIGUSR2;
- else if (!strcasecmp(s, "HALT") || !strcasecmp(s, "TERM"))
- sig = SIGTERM;
- else if (!strcasecmp(s, "NEWNYM"))
- sig = SIGNEWNYM;
- else if (!strcasecmp(s, "CLEARDNSCACHE"))
- sig = SIGCLEARDNSCACHE;
- else {
+
+ for (i = 0; signal_table[i].signal_name != NULL; ++i) {
+ if (!strcasecmp(s, signal_table[i].signal_name)) {
+ sig = signal_table[i].sig;
+ break;
+ }
+ }
+
+ if (sig < 0)
connection_printf_to_buf(conn, "552 Unrecognized signal code \"%s\"\r\n",
s);
- sig = -1;
- }
tor_free(s);
- if (sig<0)
+ if (sig < 0)
return 0;
send_control_done(conn);
@@ -1306,7 +1327,7 @@ handle_control_takeownership(control_connection_t *conn, uint32_t len,
log_info(LD_CONTROL, "Control connection %d has taken ownership of this "
"Tor instance.",
- (int)(conn->_base.s));
+ (int)(conn->base_.s));
send_control_done(conn);
return 0;
@@ -1440,6 +1461,16 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
*answer = smartlist_join_strings(event_names, " ", 0, NULL);
smartlist_free(event_names);
+ } else if (!strcmp(question, "signal/names")) {
+ smartlist_t *signal_names = smartlist_new();
+ int j;
+ for (j = 0; signal_table[j].signal_name != NULL; ++j) {
+ smartlist_add(signal_names, (char*)signal_table[j].signal_name);
+ }
+
+ *answer = smartlist_join_strings(signal_names, " ", 0, NULL);
+
+ smartlist_free(signal_names);
} else if (!strcmp(question, "features/names")) {
*answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS");
} else if (!strcmp(question, "address")) {
@@ -1614,10 +1645,13 @@ getinfo_helper_dir(control_connection_t *control_conn,
const char *question, char **answer,
const char **errmsg)
{
- const routerinfo_t *ri;
+ const node_t *node;
+ const routerinfo_t *ri = NULL;
(void) control_conn;
if (!strcmpstart(question, "desc/id/")) {
- ri = router_get_by_hexdigest(question+strlen("desc/id/"));
+ node = node_get_by_hex_id(question+strlen("desc/id/"));
+ if (node)
+ ri = node->ri;
if (ri) {
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
@@ -1626,7 +1660,9 @@ getinfo_helper_dir(control_connection_t *control_conn,
} else if (!strcmpstart(question, "desc/name/")) {
/* XXX023 Setting 'warn_if_unnamed' here is a bit silly -- the
* warning goes to the user, not to the controller. */
- ri = router_get_by_nickname(question+strlen("desc/name/"),1);
+ node = node_get_by_nickname(question+strlen("desc/name/"), 1);
+ if (node)
+ ri = node->ri;
if (ri) {
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
@@ -1688,8 +1724,9 @@ getinfo_helper_dir(control_connection_t *control_conn,
*answer = tor_strndup(md->body, md->bodylen);
}
} else if (!strcmpstart(question, "desc-annotations/id/")) {
- ri = router_get_by_hexdigest(question+
- strlen("desc-annotations/id/"));
+ node = node_get_by_hex_id(question+strlen("desc-annotations/id/"));
+ if (node)
+ ri = node->ri;
if (ri) {
const char *annotations =
signed_descriptor_get_annotations(&ri->cache_info);
@@ -1847,11 +1884,11 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
}
smartlist_add_asprintf(descparts, "PURPOSE=%s",
- circuit_purpose_to_controller_string(circ->_base.purpose));
+ circuit_purpose_to_controller_string(circ->base_.purpose));
{
const char *hs_state =
- circuit_purpose_to_controller_hs_state_string(circ->_base.purpose);
+ circuit_purpose_to_controller_hs_state_string(circ->base_.purpose);
if (hs_state != NULL) {
smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state);
@@ -1865,7 +1902,7 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
{
char tbuf[ISO_TIME_USEC_LEN+1];
- format_iso_time_nospace_usec(tbuf, &circ->_base.timestamp_created);
+ format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created);
smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf);
}
@@ -1889,7 +1926,7 @@ getinfo_helper_events(control_connection_t *control_conn,
if (!strcmp(question, "circuit-status")) {
circuit_t *circ_;
smartlist_t *status = smartlist_new();
- for (circ_ = _circuit_get_global_list(); circ_; circ_ = circ_->next) {
+ for (circ_ = circuit_get_global_list_(); circ_; circ_ = circ_->next) {
origin_circuit_t *circ;
char *circdesc;
const char *state;
@@ -1897,7 +1934,7 @@ getinfo_helper_events(control_connection_t *control_conn,
continue;
circ = TO_ORIGIN_CIRCUIT(circ_);
- if (circ->_base.state == CIRCUIT_STATE_OPEN)
+ if (circ->base_.state == CIRCUIT_STATE_OPEN)
state = "BUILT";
else if (circ->cpath)
state = "EXTENDED";
@@ -1974,7 +2011,7 @@ getinfo_helper_events(control_connection_t *control_conn,
if (base_conn->type != CONN_TYPE_OR || base_conn->marked_for_close)
continue;
conn = TO_OR_CONN(base_conn);
- if (conn->_base.state == OR_CONN_STATE_OPEN)
+ if (conn->base_.state == OR_CONN_STATE_OPEN)
state = "CONNECTED";
else if (conn->nickname)
state = "LAUNCHED";
@@ -2130,10 +2167,14 @@ static const getinfo_item_t getinfo_items[] = {
PREFIX("config/", config, "Current configuration values."),
DOC("config/names",
"List of configuration options, types, and documentation."),
+ DOC("config/defaults",
+ "List of default values for configuration options. "
+ "See also config/names"),
ITEM("info/names", misc,
"List of GETINFO options, types, and documentation."),
ITEM("events/names", misc,
"Events that the controller can ask for with SETEVENTS."),
+ ITEM("signal/names", misc, "Signal names recognized by the SIGNAL command"),
ITEM("features/names", misc, "What arguments can USEFEATURE take?"),
PREFIX("desc/id/", dir, "Router descriptors by ID."),
PREFIX("desc/name/", dir, "Router descriptors by nickname."),
@@ -2497,7 +2538,7 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
goto done;
}
} else {
- if (circ->_base.state == CIRCUIT_STATE_OPEN) {
+ if (circ->base_.state == CIRCUIT_STATE_OPEN) {
int err_reason = 0;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
@@ -2630,7 +2671,7 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len,
TO_CONN(edge_conn)->state = AP_CONN_STATE_CONTROLLER_WAIT;
}
- if (circ && (circ->_base.state != CIRCUIT_STATE_OPEN)) {
+ if (circ && (circ->base_.state != CIRCUIT_STATE_OPEN)) {
connection_write_str_to_buf(
"551 Can't attach stream to non-open origin circuit\r\n",
conn);
@@ -2903,7 +2944,7 @@ handle_control_resolve(control_connection_t *conn, uint32_t len,
send_control_done(conn);
SMARTLIST_FOREACH(failed, const char *, arg, {
control_event_address_mapped(arg, arg, time(NULL),
- "Unable to launch resolve request");
+ "internal");
});
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
@@ -3198,7 +3239,7 @@ connection_control_closed(control_connection_t *conn)
static int
is_valid_initial_command(control_connection_t *conn, const char *cmd)
{
- if (conn->_base.state == CONTROL_CONN_STATE_OPEN)
+ if (conn->base_.state == CONTROL_CONN_STATE_OPEN)
return 1;
if (!strcasecmp(cmd, "PROTOCOLINFO"))
return (!conn->have_sent_protocolinfo &&
@@ -3243,8 +3284,8 @@ connection_control_process_inbuf(control_connection_t *conn)
char *args;
tor_assert(conn);
- tor_assert(conn->_base.state == CONTROL_CONN_STATE_OPEN ||
- conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH);
+ tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN ||
+ conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH);
if (!conn->incoming_cmd) {
conn->incoming_cmd = tor_malloc(1024);
@@ -3252,7 +3293,7 @@ connection_control_process_inbuf(control_connection_t *conn)
conn->incoming_cmd_cur_len = 0;
}
- if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH &&
+ if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
peek_connection_has_control0_command(TO_CONN(conn))) {
/* Detect v0 commands and send a "no more v0" message. */
size_t body_len;
@@ -3351,7 +3392,7 @@ connection_control_process_inbuf(control_connection_t *conn)
return 0;
}
- if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH &&
+ if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
!is_valid_initial_command(conn, conn->incoming_cmd)) {
connection_write_str_to_buf("514 Authentication required.\r\n", conn);
connection_mark_for_close(TO_CONN(conn));
@@ -3538,9 +3579,9 @@ control_event_circuit_status_minor(origin_circuit_t *circ,
/* event_tail can currently be up to 130 chars long */
const char *hs_state_str =
circuit_purpose_to_controller_hs_state_string(purpose);
- const struct timeval *old_timestamp_created = tv;
+ const struct timeval *old_timestamp_began = tv;
char tbuf[ISO_TIME_USEC_LEN+1];
- format_iso_time_nospace_usec(tbuf, old_timestamp_created);
+ format_iso_time_nospace_usec(tbuf, old_timestamp_began);
tor_snprintf(event_tail, sizeof(event_tail),
" OLD_PURPOSE=%s%s%s OLD_TIME_CREATED=%s",
@@ -3755,7 +3796,7 @@ orconn_target_get_name(char *name, size_t len, or_connection_t *conn)
DIGEST_LEN);
} else {
tor_snprintf(name, len, "%s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
}
}
@@ -3787,8 +3828,12 @@ control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp,
log_warn(LD_BUG, "Unrecognized status code %d", (int)tp);
return 0;
}
- ncircs = circuit_count_pending_on_or_conn(conn);
- ncircs += conn->n_circuits;
+ if (conn->chan) {
+ ncircs = circuit_count_pending_on_channel(TLS_CHAN_TO_BASE(conn->chan));
+ } else {
+ ncircs = 0;
+ }
+ ncircs += connection_or_get_num_circuits(conn);
if (ncircs && (tp == OR_CONN_EVENT_FAILED || tp == OR_CONN_EVENT_CLOSED)) {
tor_snprintf(ncircs_buf, sizeof(ncircs_buf), "%sNCIRCS=%d",
reason ? " " : "", ncircs);
@@ -3817,7 +3862,7 @@ control_event_stream_bandwidth(edge_connection_t *edge_conn)
send_control_event(EVENT_STREAM_BANDWIDTH_USED, ALL_FORMATS,
"650 STREAM_BW "U64_FORMAT" %lu %lu\r\n",
- U64_PRINTF_ARG(edge_conn->_base.global_identifier),
+ U64_PRINTF_ARG(edge_conn->base_.global_identifier),
(unsigned long)edge_conn->n_read,
(unsigned long)edge_conn->n_written);
@@ -3846,7 +3891,7 @@ control_event_stream_bandwidth_used(void)
send_control_event(EVENT_STREAM_BANDWIDTH_USED, ALL_FORMATS,
"650 STREAM_BW "U64_FORMAT" %lu %lu\r\n",
- U64_PRINTF_ARG(edge_conn->_base.global_identifier),
+ U64_PRINTF_ARG(edge_conn->base_.global_identifier),
(unsigned long)edge_conn->n_read,
(unsigned long)edge_conn->n_written);
diff --git a/src/or/control.h b/src/or/control.h
index f301ce91be..eea3af724c 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -9,8 +9,8 @@
* \brief Header file for control.c.
**/
-#ifndef _TOR_CONTROL_H
-#define _TOR_CONTROL_H
+#ifndef TOR_CONTROL_H
+#define TOR_CONTROL_H
void control_update_global_event_mask(void);
void control_adjust_event_log_severity(void);
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 0255227e7b..2164e52a41 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -14,6 +14,8 @@
#include "or.h"
#include "buffers.h"
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "config.h"
@@ -68,19 +70,20 @@ connection_cpu_finished_flushing(connection_t *conn)
/** Pack global_id and circ_id; set *tag to the result. (See note on
* cpuworker_main for wire format.) */
static void
-tag_pack(char *tag, uint64_t conn_id, circid_t circ_id)
+tag_pack(char *tag, uint64_t chan_id, circid_t circ_id)
{
/*XXXX RETHINK THIS WHOLE MESS !!!! !NM NM NM NM*/
- set_uint64(tag, conn_id);
+ /*XXXX DOUBLEPLUSTHIS!!!! AS AS AS AS*/
+ set_uint64(tag, chan_id);
set_uint16(tag+8, circ_id);
}
/** Unpack <b>tag</b> into addr, port, and circ_id.
*/
static void
-tag_unpack(const char *tag, uint64_t *conn_id, circid_t *circ_id)
+tag_unpack(const char *tag, uint64_t *chan_id, circid_t *circ_id)
{
- *conn_id = get_uint64(tag);
+ *chan_id = get_uint64(tag);
*circ_id = get_uint16(tag+8);
}
@@ -131,10 +134,9 @@ connection_cpu_process_inbuf(connection_t *conn)
{
char success;
char buf[LEN_ONION_RESPONSE];
- uint64_t conn_id;
+ uint64_t chan_id;
circid_t circ_id;
- connection_t *tmp_conn;
- or_connection_t *p_conn = NULL;
+ channel_t *p_chan = NULL;
circuit_t *circ;
tor_assert(conn);
@@ -152,15 +154,16 @@ connection_cpu_process_inbuf(connection_t *conn)
connection_fetch_from_buf(buf,LEN_ONION_RESPONSE-1,conn);
/* parse out the circ it was talking about */
- tag_unpack(buf, &conn_id, &circ_id);
+ tag_unpack(buf, &chan_id, &circ_id);
circ = NULL;
- tmp_conn = connection_get_by_global_id(conn_id);
- if (tmp_conn && !tmp_conn->marked_for_close &&
- tmp_conn->type == CONN_TYPE_OR)
- p_conn = TO_OR_CONN(tmp_conn);
+ log_debug(LD_OR,
+ "Unpacking cpuworker reply, chan_id is " U64_FORMAT
+ ", circ_id is %d",
+ U64_PRINTF_ARG(chan_id), circ_id);
+ p_chan = channel_find_by_global_id(chan_id);
- if (p_conn)
- circ = circuit_get_by_circid_orconn(circ_id, p_conn);
+ if (p_chan)
+ circ = circuit_get_by_circid_channel(circ_id, p_chan);
if (success == 0) {
log_debug(LD_OR,
@@ -259,7 +262,7 @@ cpuworker_main(void *data)
log_info(LD_OR,
"CPU worker exiting because of error on connection to Tor "
"process.");
- log_info(LD_OR,"(Error on %d was %s)",
+ log_info(LD_OR,"(Error on "TOR_SOCKET_T_FORMAT" was %s)",
fd, tor_socket_strerror(tor_socket_errno(fd)));
}
goto end;
@@ -475,12 +478,12 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker,
tor_assert(cpuworker);
- if (!circ->p_conn) {
- log_info(LD_OR,"circ->p_conn gone. Failing circ.");
+ if (!circ->p_chan) {
+ log_info(LD_OR,"circ->p_chan gone. Failing circ.");
tor_free(onionskin);
return -1;
}
- tag_pack(tag, circ->p_conn->_base.global_identifier,
+ tag_pack(tag, circ->p_chan->global_identifier,
circ->p_circ_id);
cpuworker->state = CPUWORKER_STATE_BUSY_ONION;
diff --git a/src/or/cpuworker.h b/src/or/cpuworker.h
index 91172caa56..73c7eefd4c 100644
--- a/src/or/cpuworker.h
+++ b/src/or/cpuworker.h
@@ -9,8 +9,8 @@
* \brief Header file for cpuworker.c.
**/
-#ifndef _TOR_CPUWORKER_H
-#define _TOR_CPUWORKER_H
+#ifndef TOR_CPUWORKER_H
+#define TOR_CPUWORKER_H
void cpu_init(void);
void cpuworkers_rotate(void);
diff --git a/src/or/directory.c b/src/or/directory.c
index f235bf3b41..198fb6d40f 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -13,6 +13,7 @@
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "main.h"
#include "microdesc.h"
@@ -25,6 +26,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
#if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
#ifndef OPENBSD
@@ -58,7 +60,6 @@
static void directory_send_command(dir_connection_t *conn,
int purpose, int direct, const char *resource,
const char *payload, size_t payload_len,
- int supports_conditional_consensus,
time_t if_modified_since);
static int directory_handle_command(dir_connection_t *conn);
static int body_is_plausible(const char *body, size_t body_len, int purpose);
@@ -89,12 +90,10 @@ static void directory_initiate_command_rend(const char *address,
const tor_addr_t *addr,
uint16_t or_port,
uint16_t dir_port,
- int supports_conditional_consensus,
- int supports_begindir,
const char *digest,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -227,16 +226,9 @@ router_supports_extrainfo(const char *identity_digest, int is_authority)
if (node && node->ri) {
if (node->ri->caches_extra_info)
return 1;
- if (is_authority && node->ri->platform &&
- tor_version_as_new_as(node->ri->platform,
- "Tor 0.2.0.0-alpha-dev (r10070)"))
- return 1;
}
if (is_authority) {
- const routerstatus_t *rs =
- router_get_consensus_status_by_id(identity_digest);
- if (rs && rs->version_supports_extrainfo_upload)
- return 1;
+ return 1;
}
return 0;
}
@@ -252,10 +244,10 @@ router_supports_extrainfo(const char *identity_digest, int is_authority)
int
directories_have_accepted_server_descriptor(void)
{
- smartlist_t *servers = router_get_trusted_dir_servers();
+ const smartlist_t *servers = router_get_trusted_dir_servers();
const or_options_t *options = get_options();
- SMARTLIST_FOREACH(servers, trusted_dir_server_t *, d, {
- if ((d->type & options->_PublishServerDescriptor) &&
+ SMARTLIST_FOREACH(servers, dir_server_t *, d, {
+ if ((d->type & options->PublishServerDescriptor_) &&
d->has_accepted_serverdesc) {
return 1;
}
@@ -288,7 +280,7 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
{
const or_options_t *options = get_options();
int post_via_tor;
- smartlist_t *dirservers = router_get_trusted_dir_servers();
+ const smartlist_t *dirservers = router_get_trusted_dir_servers();
int found = 0;
const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE ||
dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES);
@@ -296,7 +288,7 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
/* This tries dirservers which we believe to be down, but ultimately, that's
* harmless, and we may as well err on the side of getting things uploaded.
*/
- SMARTLIST_FOREACH_BEGIN(dirservers, trusted_dir_server_t *, ds) {
+ SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) {
routerstatus_t *rs = &(ds->fake_status);
size_t upload_len = payload_len;
tor_addr_t ds_addr;
@@ -431,8 +423,6 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
* the behavior supported by our oldest bridge; see for example
* any_bridges_dont_support_microdescriptors().
*/
- /* XXX024 Not all bridges handle conditional consensus downloading,
- * so, for now, never assume the server supports that. -PP */
const node_t *node = choose_random_entry(NULL);
if (node && node->ri) {
/* every bridge has a routerinfo. */
@@ -440,12 +430,12 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
routerinfo_t *ri = node->ri;
node_get_addr(node, &addr);
directory_initiate_command(ri->address, &addr,
- ri->or_port, 0,
- 0, /* don't use conditional consensus url */
- 1, ri->cache_info.identity_digest,
+ ri->or_port, 0/*no dirport*/,
+ ri->cache_info.identity_digest,
dir_purpose,
router_purpose,
- 0, resource, NULL, 0, if_modified_since);
+ DIRIND_ONEHOP,
+ resource, NULL, 0, if_modified_since);
} else
log_notice(LD_DIR, "Ignoring directory request, since no bridge "
"nodes are available yet.");
@@ -484,7 +474,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
if (!rs) {
log_info(LD_DIR, "No router found for %s; falling back to "
"dirserver list.", dir_conn_purpose_to_string(dir_purpose));
- rs = router_pick_trusteddirserver(type, pds_flags);
+ rs = router_pick_fallback_dirserver(type, pds_flags);
if (!rs)
get_via_tor = 1; /* last resort: try routing it via Tor */
}
@@ -506,13 +496,15 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
}
}
- if (rs)
+ if (rs) {
+ const dir_indirection_t indirection =
+ get_via_tor ? DIRIND_ANONYMOUS : DIRIND_ONEHOP;
directory_initiate_command_routerstatus(rs, dir_purpose,
router_purpose,
- get_via_tor,
+ indirection,
resource, NULL, 0,
if_modified_since);
- else {
+ } else {
log_notice(LD_DIR,
"While fetching directory info, "
"no running dirservers known. Will try again later. "
@@ -536,7 +528,7 @@ directory_get_from_all_authorities(uint8_t dir_purpose,
dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES);
SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds) {
+ dir_server_t *, ds) {
routerstatus_t *rs;
if (router_digest_is_me(ds->digest))
continue;
@@ -544,17 +536,25 @@ directory_get_from_all_authorities(uint8_t dir_purpose,
continue;
rs = &ds->fake_status;
directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
- 0, resource, NULL, 0, 0);
+ DIRIND_ONEHOP, resource, NULL,
+ 0, 0);
} SMARTLIST_FOREACH_END(ds);
}
+/** Return true iff <b>ind</b> requires a multihop circuit. */
+static int
+dirind_is_anon(dir_indirection_t ind)
+{
+ return ind == DIRIND_ANON_DIRPORT || ind == DIRIND_ANONYMOUS;
+}
+
/** Same as directory_initiate_command_routerstatus(), but accepts
* rendezvous data to fetch a hidden service descriptor. */
void
directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -567,6 +567,7 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
struct in_addr in;
const char *address;
tor_addr_t addr;
+ const int anonymized_connection = dirind_is_anon(indirection);
node = node_get_by_id(status->identity_digest);
if (!node && anonymized_connection) {
@@ -596,11 +597,9 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
directory_initiate_command_rend(address, &addr,
status->or_port, status->dir_port,
- status->version_supports_conditional_consensus,
- status->version_supports_begindir,
status->identity_digest,
dir_purpose, router_purpose,
- anonymized_connection, resource,
+ indirection, resource,
payload, payload_len, if_modified_since,
rend_query);
}
@@ -623,7 +622,7 @@ void
directory_initiate_command_routerstatus(const routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -631,7 +630,7 @@ directory_initiate_command_routerstatus(const routerstatus_t *status,
{
directory_initiate_command_routerstatus_rend(status, dir_purpose,
router_purpose,
- anonymized_connection, resource,
+ indirection, resource,
payload, payload_len,
if_modified_since, NULL);
}
@@ -647,8 +646,8 @@ directory_conn_is_self_reachability_test(dir_connection_t *conn)
const routerinfo_t *me = router_get_my_routerinfo();
if (me &&
router_digest_is_me(conn->identity_digest) &&
- tor_addr_eq_ipv4h(&conn->_base.addr, me->addr) && /*XXXX prop 118*/
- me->dir_port == conn->_base.port)
+ tor_addr_eq_ipv4h(&conn->base_.addr, me->addr) && /*XXXX prop 118*/
+ me->dir_port == conn->base_.port)
return 1;
}
return 0;
@@ -666,35 +665,35 @@ connection_dir_request_failed(dir_connection_t *conn)
}
if (!entry_list_is_constrained(get_options()))
router_set_status(conn->identity_digest, 0); /* don't try him again */
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
- conn->_base.address);
+ conn->base_.address);
connection_dir_download_v2_networkstatus_failed(conn, -1);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from "
"directory server at '%s'; retrying",
- conn->_base.address);
+ conn->base_.address);
if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE)
connection_dir_bridge_routerdesc_failed(conn);
connection_dir_download_routerdesc_failed(conn);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
if (conn->requested_resource)
networkstatus_consensus_download_failed(0, conn->requested_resource);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
log_info(LD_DIR, "Giving up on certificate fetch from directory server "
"at '%s'; retrying",
- conn->_base.address);
+ conn->base_.address);
connection_dir_download_cert_failed(conn, 0);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
log_info(LD_DIR, "Giving up downloading detached signatures from '%s'",
- conn->_base.address);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
+ conn->base_.address);
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
log_info(LD_DIR, "Giving up downloading votes from '%s'",
- conn->_base.address);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+ conn->base_.address);
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
log_info(LD_DIR, "Giving up on downloading microdescriptors from "
- " directory server at '%s'; will retry", conn->_base.address);
+ " directory server at '%s'; will retry", conn->base_.address);
connection_dir_download_routerdesc_failed(conn);
}
}
@@ -717,10 +716,10 @@ connection_dir_download_v2_networkstatus_failed(dir_connection_t *conn,
/* We're a non-authoritative directory cache; try again. Ignore status
* code, since we don't want to keep trying forever in a tight loop
* if all the authorities are shutting us out. */
- smartlist_t *trusted_dirs = router_get_trusted_dir_servers();
- SMARTLIST_FOREACH(trusted_dirs, trusted_dir_server_t *, ds,
+ const smartlist_t *trusted_dirs = router_get_trusted_dir_servers();
+ SMARTLIST_FOREACH(trusted_dirs, dir_server_t *, ds,
download_status_failed(&ds->v2_ns_dl_status, 0));
- directory_get_from_dirserver(conn->_base.purpose, conn->router_purpose,
+ directory_get_from_dirserver(conn->base_.purpose, conn->router_purpose,
"all.z", 0 /* don't retry_if_no_servers */);
} else if (!strcmpstart(conn->requested_resource, "fp/")) {
/* We were trying to download by fingerprint; mark them all as having
@@ -765,9 +764,9 @@ connection_dir_download_routerdesc_failed(dir_connection_t *conn)
/* No need to relaunch descriptor downloads here: we already do it
* every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
- tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC);
+ tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
(void) conn;
}
@@ -791,7 +790,7 @@ connection_dir_bridge_routerdesc_failed(dir_connection_t *conn)
+ strlen("fp/"),
which, NULL, 0);
- tor_assert(conn->_base.purpose != DIR_PURPOSE_FETCH_EXTRAINFO);
+ tor_assert(conn->base_.purpose != DIR_PURPOSE_FETCH_EXTRAINFO);
if (smartlist_len(which)) {
connection_dir_retry_bridges(which);
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
@@ -804,7 +803,7 @@ static void
connection_dir_download_cert_failed(dir_connection_t *conn, int status)
{
smartlist_t *failed;
- tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
+ tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
if (!conn->requested_resource)
return;
@@ -833,11 +832,13 @@ static int
directory_command_should_use_begindir(const or_options_t *options,
const tor_addr_t *addr,
int or_port, uint8_t router_purpose,
- int anonymized_connection)
+ dir_indirection_t indirection)
{
if (!or_port)
return 0; /* We don't know an ORPort -- no chance. */
- if (!anonymized_connection)
+ if (indirection == DIRIND_DIRECT_CONN || indirection == DIRIND_ANON_DIRPORT)
+ return 0;
+ if (indirection == DIRIND_ONEHOP)
if (!fascist_firewall_allows_address_or(addr, or_port) ||
directory_fetches_from_authorities(options))
return 0; /* We're firewalled or are acting like a relay -- also no. */
@@ -855,17 +856,15 @@ directory_command_should_use_begindir(const or_options_t *options,
void
directory_initiate_command(const char *address, const tor_addr_t *_addr,
uint16_t or_port, uint16_t dir_port,
- int supports_conditional_consensus,
- int supports_begindir, const char *digest,
+ const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
- int anonymized_connection, const char *resource,
+ dir_indirection_t indirection, const char *resource,
const char *payload, size_t payload_len,
time_t if_modified_since)
{
directory_initiate_command_rend(address, _addr, or_port, dir_port,
- supports_conditional_consensus,
- supports_begindir, digest, dir_purpose,
- router_purpose, anonymized_connection,
+ digest, dir_purpose,
+ router_purpose, indirection,
resource, payload, payload_len,
if_modified_since, NULL);
}
@@ -889,10 +888,9 @@ is_sensitive_dir_purpose(uint8_t dir_purpose)
static void
directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
uint16_t or_port, uint16_t dir_port,
- int supports_conditional_consensus,
- int supports_begindir, const char *digest,
+ const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload, size_t payload_len,
time_t if_modified_since,
@@ -901,9 +899,9 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
dir_connection_t *conn;
const or_options_t *options = get_options();
int socket_error = 0;
- int use_begindir = supports_begindir &&
- directory_command_should_use_begindir(options, _addr,
- or_port, router_purpose, anonymized_connection);
+ int use_begindir = directory_command_should_use_begindir(options, _addr,
+ or_port, router_purpose, indirection);
+ const int anonymized_connection = dirind_is_anon(indirection);
tor_addr_t addr;
tor_assert(address);
@@ -937,18 +935,19 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
conn = dir_connection_new(tor_addr_family(&addr));
/* set up conn so it's got all the data we need to remember */
- tor_addr_copy(&conn->_base.addr, &addr);
- conn->_base.port = use_begindir ? or_port : dir_port;
- conn->_base.address = tor_strdup(address);
+ tor_addr_copy(&conn->base_.addr, &addr);
+ conn->base_.port = use_begindir ? or_port : dir_port;
+ conn->base_.address = tor_strdup(address);
memcpy(conn->identity_digest, digest, DIGEST_LEN);
- conn->_base.purpose = dir_purpose;
+ conn->base_.purpose = dir_purpose;
conn->router_purpose = router_purpose;
/* give it an initial state */
- conn->_base.state = DIR_CONN_STATE_CONNECTING;
+ conn->base_.state = DIR_CONN_STATE_CONNECTING;
/* decide whether we can learn our IP address from this conn */
+ /* XXXX This is a bad name for this field now. */
conn->dirconn_direct = !anonymized_connection;
/* copy rendezvous data, if any */
@@ -963,7 +962,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
dir_port = options->HTTPProxyPort;
}
- switch (connection_connect(TO_CONN(conn), conn->_base.address, &addr,
+ switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr,
dir_port, &socket_error)) {
case -1:
connection_dir_request_failed(conn); /* retry if we want */
@@ -973,13 +972,12 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
return;
case 1:
/* start flushing conn */
- conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
+ conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
/* fall through */
case 0:
/* queue the command on the outbuf */
directory_send_command(conn, dir_purpose, 1, resource,
payload, payload_len,
- supports_conditional_consensus,
if_modified_since);
connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT);
/* writable indicates finish, readable indicates broken link,
@@ -997,7 +995,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
if (anonymized_connection && use_begindir)
rep_hist_note_used_internal(time(NULL), 0, 1);
else if (anonymized_connection && !use_begindir)
- rep_hist_note_used_port(time(NULL), conn->_base.port);
+ rep_hist_note_used_port(time(NULL), conn->base_.port);
/* make an AP connection
* populate it and add it at the right state
@@ -1005,7 +1003,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
*/
linked_conn =
connection_ap_make_link(TO_CONN(conn),
- conn->_base.address, conn->_base.port,
+ conn->base_.address, conn->base_.port,
digest,
SESSION_GROUP_DIRCONN, iso_flags,
use_begindir, conn->dirconn_direct);
@@ -1020,11 +1018,10 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
connection_mark_for_close(TO_CONN(conn));
return;
}
- conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
+ conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
/* queue the command on the outbuf */
directory_send_command(conn, dir_purpose, 0, resource,
payload, payload_len,
- supports_conditional_consensus,
if_modified_since);
connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT);
@@ -1054,7 +1051,7 @@ connection_dir_is_encrypted(dir_connection_t *conn)
* sort strings alphabetically
*/
static int
-_compare_strs(const void **a, const void **b)
+compare_strs_(const void **a, const void **b)
{
const char *s1 = *a, *s2 = *b;
return strcmp(s1, s2);
@@ -1074,8 +1071,7 @@ _compare_strs(const void **a, const void **b)
* If 'resource' is provided, it is the name of a consensus flavor to request.
*/
static char *
-directory_get_consensus_url(int supports_conditional_consensus,
- const char *resource)
+directory_get_consensus_url(const char *resource)
{
char *url = NULL;
const char *hyphen, *flavor;
@@ -1087,12 +1083,12 @@ directory_get_consensus_url(int supports_conditional_consensus,
hyphen = "-";
}
- if (supports_conditional_consensus) {
+ {
char *authority_id_list;
smartlist_t *authority_digests = smartlist_new();
SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds) {
+ dir_server_t *, ds) {
char *hex;
if (!(ds->type & V3_DIRINFO))
continue;
@@ -1102,7 +1098,7 @@ directory_get_consensus_url(int supports_conditional_consensus,
ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN);
smartlist_add(authority_digests, hex);
} SMARTLIST_FOREACH_END(ds);
- smartlist_sort(authority_digests, _compare_strs);
+ smartlist_sort(authority_digests, compare_strs_);
authority_id_list = smartlist_join_strings(authority_digests,
"+", 0, NULL);
@@ -1112,9 +1108,6 @@ directory_get_consensus_url(int supports_conditional_consensus,
SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp));
smartlist_free(authority_digests);
tor_free(authority_id_list);
- } else {
- tor_asprintf(&url, "/tor/status-vote/current/consensus%s%s.z",
- hyphen, flavor);
}
return url;
}
@@ -1126,7 +1119,6 @@ static void
directory_send_command(dir_connection_t *conn,
int purpose, int direct, const char *resource,
const char *payload, size_t payload_len,
- int supports_conditional_consensus,
time_t if_modified_since)
{
char proxystring[256];
@@ -1137,18 +1129,18 @@ directory_send_command(dir_connection_t *conn,
const char *httpcommand = NULL;
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
tor_free(conn->requested_resource);
if (resource)
conn->requested_resource = tor_strdup(resource);
/* come up with a string for which Host: we want */
- if (conn->_base.port == 80) {
- strlcpy(hoststring, conn->_base.address, sizeof(hoststring));
+ if (conn->base_.port == 80) {
+ strlcpy(hoststring, conn->base_.address, sizeof(hoststring));
} else {
tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
}
/* Format if-modified-since */
@@ -1189,8 +1181,7 @@ directory_send_command(dir_connection_t *conn,
/* resource is optional. If present, it's a flavor name */
tor_assert(!payload);
httpcommand = "GET";
- url = directory_get_consensus_url(supports_conditional_consensus,
- resource);
+ url = directory_get_consensus_url(resource);
log_info(LD_DIR, "Downloading consensus from %s using %s",
hoststring, url);
break;
@@ -1584,9 +1575,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
compress_method_t compression;
int plausible;
int skewed=0;
- int allow_partial = (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC);
+ int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
int was_compressed=0;
time_t now = time(NULL);
@@ -1597,7 +1588,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
case -1: /* overflow */
log_warn(LD_PROTOCOL,
"'fetch' response too large (server '%s:%d'). Closing.",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
return -1;
case 0:
log_info(LD_HTTP,
@@ -1610,7 +1601,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (parse_http_response(headers, &status_code, &date_header,
&compression, &reason) < 0) {
log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
tor_free(body); tor_free(headers);
return -1;
}
@@ -1619,9 +1610,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_debug(LD_DIR,
"Received response from directory server '%s:%d': %d %s "
"(purpose: %d)",
- conn->_base.address, conn->_base.port, status_code,
+ conn->base_.address, conn->base_.port, status_code,
escaped(reason),
- conn->_base.purpose);
+ conn->base_.purpose);
/* now check if it's got any hints for us about our IP address. */
if (conn->dirconn_direct) {
@@ -1638,7 +1629,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
* and the date header. (We used to check now-date_header, but that's
* inaccurate if we spend a lot of time downloading.)
*/
- delta = conn->_base.timestamp_lastwritten - date_header;
+ delta = conn->base_.timestamp_lastwritten - date_header;
if (labs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
char dbuf[64];
int trusted = router_digest_is_trusted_dir(conn->identity_digest);
@@ -1649,14 +1640,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"It seems that our clock is %s by %s, or that theirs is %s. "
"Tor requires an accurate clock to work: please check your time, "
"timezone, and date settings.",
- conn->_base.address, conn->_base.port,
+ conn->base_.address, conn->base_.port,
delta>0 ? "ahead" : "behind", dbuf,
delta>0 ? "behind" : "ahead");
skewed = 1; /* don't check the recommended-versions line */
if (trusted)
control_event_general_status(LOG_WARN,
"CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d",
- delta, conn->_base.address, conn->_base.port);
+ delta, conn->base_.address, conn->base_.port);
} else {
log_debug(LD_HTTP, "Time on received directory is within tolerance; "
"we are %ld seconds skewed. (That's okay.)", delta);
@@ -1666,22 +1657,22 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (status_code == 503) {
routerstatus_t *rs;
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
const char *id_digest = conn->identity_digest;
log_info(LD_DIR,"Received http status code %d (%s) from server "
"'%s:%d'. I'll try again soon.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
if ((rs = router_get_mutable_consensus_status_by_id(id_digest)))
rs->last_dir_503_at = now;
- if ((ds = router_get_trusteddirserver_by_digest(id_digest)))
+ if ((ds = router_get_fallback_dirserver_by_digest(id_digest)))
ds->fake_status.last_dir_503_at = now;
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
- plausible = body_is_plausible(body, body_len, conn->_base.purpose);
+ plausible = body_is_plausible(body, body_len, conn->base_.purpose);
if (compression != NO_METHOD || !plausible) {
char *new_body = NULL;
size_t new_len = 0;
@@ -1708,7 +1699,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, "
"but it seems to be %s.%s",
- conn->_base.address, conn->_base.port, description1,
+ conn->base_.address, conn->base_.port, description1,
description2,
(compression>0 && guessed>0)?" Trying both.":"");
}
@@ -1728,7 +1719,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (!plausible && !new_body) {
log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
"Unable to decompress HTTP body (server '%s:%d').",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
@@ -1740,12 +1731,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
smartlist_t *which = NULL;
v2_networkstatus_source_t source;
char *cp;
log_info(LD_DIR,"Received networkstatus objects (size %d) from server "
- "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
+ "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
if (status_code != 200) {
static ratelim_t warning_limit = RATELIM_INIT(3600);
char *m;
@@ -1754,8 +1745,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/status/%s\". "
"I'll try again soon.%s",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port, conn->requested_resource, m);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port, conn->requested_resource, m);
tor_free(m);
}
tor_free(body); tor_free(headers); tor_free(reason);
@@ -1773,7 +1764,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
source = NS_FROM_DIR_ALL;
which = smartlist_new();
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
{
char *hex = tor_malloc(HEX_DIGEST_LEN+1);
base16_encode(hex, HEX_DIGEST_LEN+1, ds->digest, DIGEST_LEN);
@@ -1811,7 +1802,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
int r;
const char *flavname = conn->requested_resource;
if (status_code != 200) {
@@ -1819,19 +1810,19 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log(severity, LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching consensus directory.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
tor_free(body); tor_free(headers); tor_free(reason);
networkstatus_consensus_download_failed(status_code, flavname);
return -1;
}
log_info(LD_DIR,"Received consensus directory (size %d) from server "
- "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
+ "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
if ((r=networkstatus_set_current_consensus(body, flavname, 0))<0) {
log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
"Unable to load %s consensus directory downloaded from "
"server '%s:%d'. I'll try again soon.",
- flavname, conn->_base.address, conn->_base.port);
+ flavname, conn->base_.address, conn->base_.port);
tor_free(body); tor_free(headers); tor_free(reason);
networkstatus_consensus_download_failed(0, flavname);
return -1;
@@ -1844,19 +1835,19 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Successfully loaded consensus.");
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/keys/%s\".",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port, conn->requested_resource);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port, conn->requested_resource);
connection_dir_download_cert_failed(conn, status_code);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
log_info(LD_DIR,"Received authority certificates (size %d) from server "
- "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
+ "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
if (trusted_dirs_load_certs_from_string(body, 0, 1)<0) {
log_warn(LD_DIR, "Unable to parse fetched certificates");
/* if we fetched more than one and only some failed, the successful
@@ -1867,17 +1858,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Successfully loaded certificates from fetch.");
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
const char *msg;
int st;
log_info(LD_DIR,"Got votes (size %d) from server %s:%d",
- (int)body_len, conn->_base.address, conn->_base.port);
+ (int)body_len, conn->base_.address, conn->base_.port);
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port, conn->requested_resource);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port, conn->requested_resource);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
@@ -1888,35 +1879,35 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg);
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
const char *msg = NULL;
log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d",
- (int)body_len, conn->_base.address, conn->_base.port);
+ (int)body_len, conn->base_.address, conn->base_.port);
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server '%s:%d' while fetching "
"\"/tor/status-vote/next/consensus-signatures.z\".",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
- if (dirvote_add_signatures(body, conn->_base.address, &msg)<0) {
+ if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) {
log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s",
- conn->_base.address, conn->_base.port, msg?msg:"???");
+ conn->base_.address, conn->base_.port, msg?msg:"???");
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
- int was_ei = conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO;
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
+ int was_ei = conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO;
smartlist_t *which = NULL;
int n_asked_for = 0;
int descriptor_digests = conn->requested_resource &&
!strcmpstart(conn->requested_resource,"d/");
log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'",
was_ei ? "extra server info" : "server info",
- (int)body_len, conn->_base.address, conn->_base.port);
+ (int)body_len, conn->base_.address, conn->base_.port);
if (conn->requested_resource &&
(!strcmpstart(conn->requested_resource,"d/") ||
!strcmpstart(conn->requested_resource,"fp/"))) {
@@ -1934,8 +1925,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR,
"Received http status code %d (%s) from server '%s:%d' "
"while fetching \"/tor/server/%s\". I'll try again soon.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port, conn->requested_resource);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port, conn->requested_resource);
if (!which) {
connection_dir_download_routerdesc_failed(conn);
} else {
@@ -1969,7 +1960,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
// descriptor_digests, conn->router_purpose);
if (load_downloaded_routers(body, which, descriptor_digests,
conn->router_purpose,
- conn->_base.address))
+ conn->base_.address))
directory_info_has_arrived(now, 0);
}
}
@@ -1977,7 +1968,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Received %d/%d %s requested from %s:%d",
n_asked_for-smartlist_len(which), n_asked_for,
was_ei ? "extra-info documents" : "router descriptors",
- conn->_base.address, (int)conn->_base.port);
+ conn->base_.address, (int)conn->base_.port);
if (smartlist_len(which)) {
dir_routerdesc_download_failed(which, status_code,
conn->router_purpose,
@@ -1989,12 +1980,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (directory_conn_is_self_reachability_test(conn))
router_dirport_found_reachable();
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
smartlist_t *which = NULL;
log_info(LD_DIR,"Received answer to microdescriptor request (status %d, "
"size %d) from server '%s:%d'",
- status_code, (int)body_len, conn->_base.address,
- conn->_base.port);
+ status_code, (int)body_len, conn->base_.address,
+ conn->base_.port);
tor_assert(conn->requested_resource &&
!strcmpstart(conn->requested_resource, "d/"));
which = smartlist_new();
@@ -2005,8 +1996,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Received status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/micro/%s\". I'll try again "
"soon.",
- status_code, escaped(reason), conn->_base.address,
- (int)conn->_base.port, conn->requested_resource);
+ status_code, escaped(reason), conn->base_.address,
+ (int)conn->base_.port, conn->requested_resource);
dir_microdesc_download_failed(which, status_code);
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
smartlist_free(which);
@@ -2027,10 +2018,10 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
}
- if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
+ if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_DIR) {
switch (status_code) {
case 200: {
- trusted_dir_server_t *ds =
+ dir_server_t *ds =
router_get_trusteddirserver_by_digest(conn->identity_digest);
char *rejected_hdr = http_get_header(headers,
"X-Descriptor-Not-New: ");
@@ -2053,7 +2044,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"descriptor: finished.");
control_event_server_status(
LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
ds->has_accepted_serverdesc = 1;
if (directories_have_accepted_server_descriptor())
@@ -2063,72 +2054,72 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
case 400:
log_warn(LD_GENERAL,"http status 400 (%s) response from "
"dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->_base.address, conn->_base.port);
+ escaped(reason), conn->base_.address, conn->base_.port);
control_event_server_status(LOG_WARN,
"BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"",
- conn->_base.address, conn->_base.port, escaped(reason));
+ conn->base_.address, conn->base_.port, escaped(reason));
break;
default:
log_warn(LD_GENERAL,
"http status %d (%s) reason unexpected while uploading "
"descriptor to server '%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
/* return 0 in all cases, since we don't want to mark any
* dirservers down just because they don't like us. */
}
- if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
+ if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
switch (status_code) {
case 200: {
log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
}
break;
case 400:
log_warn(LD_DIR,"http status 400 (%s) response after uploading "
"vote to dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->_base.address, conn->_base.port);
+ escaped(reason), conn->base_.address, conn->base_.port);
break;
default:
log_warn(LD_GENERAL,
"http status %d (%s) reason unexpected while uploading "
"vote to server '%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
/* return 0 in all cases, since we don't want to mark any
* dirservers down just because they don't like us. */
}
- if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) {
+ if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) {
switch (status_code) {
case 200: {
log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
}
break;
case 400:
log_warn(LD_DIR,"http status 400 (%s) response after uploading "
"signatures to dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->_base.address, conn->_base.port);
+ escaped(reason), conn->base_.address, conn->base_.port);
break;
default:
log_warn(LD_GENERAL,
"http status %d (%s) reason unexpected while uploading "
"signatures to server '%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
/* return 0 in all cases, since we don't want to mark any
* dirservers down just because they don't like us. */
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
tor_assert(conn->rend_data);
log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
"(%s))",
@@ -2146,7 +2137,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
} else {
/* Success, or at least there's a v2 descriptor already
* present. Notify pending connections about this. */
- conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+ conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
rend_client_desc_trynow(conn->rend_data->onion_address);
}
break;
@@ -2162,13 +2153,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
default:
log_warn(LD_REND,"http status %d (%s) response unexpected while "
"fetching hidden service descriptor (server '%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
tor_assert(conn->rend_data);
log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
"(%s))",
@@ -2187,13 +2178,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
* and _not_ performing another request. */
log_info(LD_REND, "Successfully fetched v2 rendezvous "
"descriptor, but we already have a v0 descriptor.");
- conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+ conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
break;
default:
/* success. notify pending connections about this. */
log_info(LD_REND, "Successfully fetched v2 rendezvous "
"descriptor.");
- conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+ conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
rend_client_desc_trynow(conn->rend_data->onion_address);
break;
}
@@ -2215,14 +2206,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"http status %d (%s) response unexpected while "
"fetching v2 hidden service descriptor (server '%s:%d'). "
"Retrying at another directory.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
}
- if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC ||
- conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
+ if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC ||
+ conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
"(%s))",
status_code, escaped(reason));
@@ -2235,17 +2226,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
case 400:
log_warn(LD_REND,"http status 400 (%s) response from dirserver "
"'%s:%d'. Malformed rendezvous descriptor?",
- escaped(reason), conn->_base.address, conn->_base.port);
+ escaped(reason), conn->base_.address, conn->base_.port);
break;
default:
log_warn(LD_REND,"http status %d (%s) response unexpected (server "
"'%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
}
- note_client_request(conn->_base.purpose, was_compressed, orig_len);
+ note_client_request(conn->base_.purpose, was_compressed, orig_len);
tor_free(body); tor_free(headers); tor_free(reason);
return 0;
}
@@ -2255,9 +2246,9 @@ int
connection_dir_reached_eof(dir_connection_t *conn)
{
int retval;
- if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
+ if (conn->base_.state != DIR_CONN_STATE_CLIENT_READING) {
log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.",
- conn->_base.state);
+ conn->base_.state);
connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
connection_mark_for_close(TO_CONN(conn));
return -1;
@@ -2265,7 +2256,7 @@ connection_dir_reached_eof(dir_connection_t *conn)
retval = connection_dir_client_reached_eof(conn);
if (retval == 0) /* success */
- conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED;
+ conn->base_.state = DIR_CONN_STATE_CLIENT_FINISHED;
connection_mark_for_close(TO_CONN(conn));
return retval;
}
@@ -2283,7 +2274,7 @@ int
connection_dir_process_inbuf(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
/* Directory clients write, then read data until they receive EOF;
* directory servers read data until they get an HTTP command, then
@@ -2292,7 +2283,7 @@ connection_dir_process_inbuf(dir_connection_t *conn)
*/
/* If we're on the dirserver side, look for a command. */
- if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
+ if (conn->base_.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
if (directory_handle_command(conn) < 0) {
connection_mark_for_close(TO_CONN(conn));
return -1;
@@ -2307,7 +2298,7 @@ connection_dir_process_inbuf(dir_connection_t *conn)
return -1;
}
- if (!conn->_base.inbuf_reached_eof)
+ if (!conn->base_.inbuf_reached_eof)
log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
return 0;
}
@@ -2380,12 +2371,12 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type);
cp += strlen(cp);
}
- if (!is_local_addr(&conn->_base.addr)) {
+ if (!is_local_addr(&conn->base_.addr)) {
/* Don't report the source address for a nearby/private connection.
* Otherwise we tend to mis-report in cases where incoming ports are
* being forwarded to a Tor server running behind the firewall. */
tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
- X_ADDRESS_HEADER "%s\r\n", conn->_base.address);
+ X_ADDRESS_HEADER "%s\r\n", conn->base_.address);
cp += strlen(cp);
}
if (encoding) {
@@ -2637,7 +2628,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
log_debug(LD_DIRSERV,"Received GET command.");
- conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
+ conn->base_.state = DIR_CONN_STATE_SERVER_WRITING;
if (parse_http_url(headers, &url) < 0) {
write_http_status_line(conn, 400, "Bad request");
@@ -2865,8 +2856,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
geoip_note_ns_response(act, GEOIP_SUCCESS);
/* Note that a request for a network status has started, so that we
* can measure the download time later on. */
- if (TO_CONN(conn)->dirreq_id)
- geoip_start_dirreq(TO_CONN(conn)->dirreq_id, dlen, act,
+ if (conn->dirreq_id)
+ geoip_start_dirreq(conn->dirreq_id, dlen, act,
DIRREQ_TUNNELED);
else
geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen, act,
@@ -3231,7 +3222,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
}
if (options->BridgeAuthoritativeDir &&
- options->_BridgePassword_AuthDigest &&
+ options->BridgePassword_AuthDigest_ &&
connection_dir_is_encrypted(conn) &&
!strcmp(url,"/tor/networkstatus-bridges")) {
char *status;
@@ -3244,7 +3235,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
/* now make sure the password is there and right */
if (!header ||
tor_memneq(digest,
- options->_BridgePassword_AuthDigest, DIGEST256_LEN)) {
+ options->BridgePassword_AuthDigest_, DIGEST256_LEN)) {
write_http_status_line(conn, 404, "Not found");
tor_free(header);
goto done;
@@ -3300,7 +3291,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
}while(0);
if (!strcmp(url,"/tor/mallinfo.txt") &&
- (tor_addr_eq_ipv4h(&conn->_base.addr, 0x7f000001ul))) {
+ (tor_addr_eq_ipv4h(&conn->base_.addr, 0x7f000001ul))) {
char *result;
size_t len;
struct mallinfo mi;
@@ -3355,7 +3346,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
log_debug(LD_DIRSERV,"Received POST command.");
- conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
+ conn->base_.state = DIR_CONN_STATE_SERVER_WRITING;
if (parse_http_url(headers, &url) < 0) {
write_http_status_line(conn, 400, "Bad request");
@@ -3371,13 +3362,13 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
case -2:
log_info(LD_REND, "Rejected v2 rend descriptor (length %d) from %s "
"since we're not currently a hidden service directory.",
- (int)body_len, conn->_base.address);
+ (int)body_len, conn->base_.address);
write_http_status_line(conn, 503, "Currently not acting as v2 "
"hidden service directory");
break;
case -1:
log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.",
- (int)body_len, conn->_base.address);
+ (int)body_len, conn->base_.address);
write_http_status_line(conn, 400,
"Invalid v2 service descriptor rejected");
break;
@@ -3402,7 +3393,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
uint8_t purpose = authdir_mode_bridge(options) ?
ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose,
- conn->_base.address, &msg);
+ conn->base_.address, &msg);
tor_assert(msg);
if (WRA_WAS_ADDED(r))
dirserv_get_directory(); /* rebuild and write to disk */
@@ -3412,7 +3403,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
log_info(LD_DIRSERV,
"Problematic router descriptor or extra-info from %s "
"(\"%s\").",
- conn->_base.address, msg);
+ conn->base_.address, msg);
write_http_status_line(conn, 400, msg);
} else if (r == ROUTER_ADDED_SUCCESSFULLY) {
write_http_status_line(conn, 200, msg);
@@ -3423,7 +3414,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
log_info(LD_DIRSERV,
"Rejected router descriptor or extra-info from %s "
"(\"%s\").",
- conn->_base.address, msg);
+ conn->base_.address, msg);
write_http_status_line(conn, 400, msg);
}
goto done;
@@ -3436,7 +3427,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
if (rend_cache_store(body, body_len, 1, NULL) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV,
"Rejected rend descriptor (length %d) from %s.",
- (int)body_len, conn->_base.address);
+ (int)body_len, conn->base_.address);
write_http_status_line(conn, 400,
"Invalid v0 service descriptor rejected");
} else {
@@ -3454,7 +3445,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
} else {
tor_assert(msg);
log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").",
- conn->_base.address, msg);
+ conn->base_.address, msg);
write_http_status_line(conn, status, msg);
}
goto done;
@@ -3463,11 +3454,11 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
if (authdir_mode_v3(options) &&
!strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */
const char *msg = NULL;
- if (dirvote_add_signatures(body, conn->_base.address, &msg)>=0) {
+ if (dirvote_add_signatures(body, conn->base_.address, &msg)>=0) {
write_http_status_line(conn, 200, msg?msg:"Signatures stored");
} else {
log_warn(LD_DIR, "Unable to store signatures posted by %s: %s",
- conn->_base.address, msg?msg:"???");
+ conn->base_.address, msg?msg:"???");
write_http_status_line(conn, 400, msg?msg:"Unable to store signatures");
}
goto done;
@@ -3494,7 +3485,7 @@ directory_handle_command(dir_connection_t *conn)
int r;
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
switch (connection_fetch_from_buf_http(TO_CONN(conn),
&headers, MAX_HEADERS_SIZE,
@@ -3502,7 +3493,7 @@ directory_handle_command(dir_connection_t *conn)
case -1: /* overflow */
log_warn(LD_DIRSERV,
"Request too large from address '%s' to DirPort. Closing.",
- safe_str(conn->_base.address));
+ safe_str(conn->base_.address));
return -1;
case 0:
log_debug(LD_DIRSERV,"command not all here yet.");
@@ -3536,23 +3527,23 @@ int
connection_dir_finished_flushing(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
/* Note that we have finished writing the directory response. For direct
* connections this means we're done, for tunneled connections its only
* an intermediate step. */
- if (TO_CONN(conn)->dirreq_id)
- geoip_change_dirreq_state(TO_CONN(conn)->dirreq_id, DIRREQ_TUNNELED,
+ if (conn->dirreq_id)
+ geoip_change_dirreq_state(conn->dirreq_id, DIRREQ_TUNNELED,
DIRREQ_FLUSHING_DIR_CONN_FINISHED);
else
geoip_change_dirreq_state(TO_CONN(conn)->global_identifier,
DIRREQ_DIRECT,
DIRREQ_FLUSHING_DIR_CONN_FINISHED);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case DIR_CONN_STATE_CONNECTING:
case DIR_CONN_STATE_CLIENT_SENDING:
log_debug(LD_DIR,"client finished sending command.");
- conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
+ conn->base_.state = DIR_CONN_STATE_CLIENT_READING;
return 0;
case DIR_CONN_STATE_SERVER_WRITING:
if (conn->dir_spool_src != DIR_SPOOL_NONE) {
@@ -3573,7 +3564,7 @@ connection_dir_finished_flushing(dir_connection_t *conn)
return 0;
default:
log_warn(LD_BUG,"called in unexpected state %d.",
- conn->_base.state);
+ conn->base_.state);
tor_fragile_assert();
return -1;
}
@@ -3586,13 +3577,13 @@ int
connection_dir_finished_connecting(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
- tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING);
log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
- conn->_base.address,conn->_base.port);
+ conn->base_.address,conn->base_.port);
- conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
+ conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
return 0;
}
@@ -3606,13 +3597,13 @@ dir_networkstatus_download_failed(smartlist_t *failed, int status_code)
return;
SMARTLIST_FOREACH_BEGIN(failed, const char *, fp) {
char digest[DIGEST_LEN];
- trusted_dir_server_t *dir;
+ dir_server_t *dir;
if (base16_decode(digest, DIGEST_LEN, fp, strlen(fp))<0) {
log_warn(LD_BUG, "Called with bad fingerprint in list: %s",
escaped(fp));
continue;
}
- dir = router_get_trusteddirserver_by_digest(digest);
+ dir = router_get_fallback_dirserver_by_digest(digest);
if (dir)
download_status_failed(&dir->v2_ns_dl_status, status_code);
@@ -3829,7 +3820,7 @@ dir_microdesc_download_failed(smartlist_t *failed,
/** Helper. Compare two fp_pair_t objects, and return negative, 0, or
* positive as appropriate. */
static int
-_compare_pairs(const void **a, const void **b)
+compare_pairs_(const void **a, const void **b)
{
const fp_pair_t *fp1 = *a, *fp2 = *b;
int r;
@@ -3880,8 +3871,8 @@ dir_split_resource_into_fingerprint_pairs(const char *res,
smartlist_free(pairs_tmp);
/* Uniq-and-sort */
- smartlist_sort(pairs_result, _compare_pairs);
- smartlist_uniq(pairs_result, _compare_pairs, _tor_free);
+ smartlist_sort(pairs_result, compare_pairs_);
+ smartlist_uniq(pairs_result, compare_pairs_, tor_free_);
smartlist_add_all(pairs_out, pairs_result);
smartlist_free(pairs_result);
diff --git a/src/or/directory.h b/src/or/directory.h
index 1ca1c5a6e0..9ff78d12c4 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -9,8 +9,8 @@
* \brief Header file for directory.c.
**/
-#ifndef _TOR_DIRECTORY_H
-#define _TOR_DIRECTORY_H
+#ifndef TOR_DIRECTORY_H
+#define TOR_DIRECTORY_H
int directories_have_accepted_server_descriptor(void);
void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
@@ -22,10 +22,24 @@ void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
void directory_get_from_all_authorities(uint8_t dir_purpose,
uint8_t router_purpose,
const char *resource);
+
+/** Enumeration of ways to connect to a directory server */
+typedef enum {
+ /** Default: connect over a one-hop Tor circuit but fall back to direct
+ * connection */
+ DIRIND_ONEHOP=0,
+ /** Connect over a multi-hop anonymizing Tor circuit */
+ DIRIND_ANONYMOUS=1,
+ /** Conncet to the DirPort directly */
+ DIRIND_DIRECT_CONN,
+ /** Connect over a multi-hop anonymizing Tor circuit to our dirport */
+ DIRIND_ANON_DIRPORT,
+} dir_indirection_t;
+
void directory_initiate_command_routerstatus(const routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -33,7 +47,7 @@ void directory_initiate_command_routerstatus(const routerstatus_t *status,
void directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -51,10 +65,9 @@ int connection_dir_finished_connecting(dir_connection_t *conn);
void connection_dir_about_to_close(dir_connection_t *dir_conn);
void directory_initiate_command(const char *address, const tor_addr_t *addr,
uint16_t or_port, uint16_t dir_port,
- int supports_conditional_consensus,
- int supports_begindir, const char *digest,
+ const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload, size_t payload_len,
time_t if_modified_since);
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index f1c9c6232d..0eb1fb3c62 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -7,6 +7,10 @@
#include "or.h"
#include "buffers.h"
#include "config.h"
+#include "confparse.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "command.h"
#include "connection.h"
#include "connection_or.h"
#include "control.h"
@@ -62,6 +66,18 @@ static cached_dir_t *the_directory = NULL;
/** For authoritative directories: the current (v1) network status. */
static cached_dir_t the_runningrouters;
+/** Array of start and end of consensus methods used for supported
+ microdescriptor formats. */
+static const struct consensus_method_range_t {
+ int low;
+ int high;
+} microdesc_consensus_methods[] = {
+ {MIN_METHOD_FOR_MICRODESC, MIN_METHOD_FOR_A_LINES - 1},
+ {MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1},
+ {MIN_METHOD_FOR_P6_LINES, MAX_SUPPORTED_CONSENSUS_METHOD},
+ {-1, -1}
+};
+
static void directory_remove_invalid(void);
static cached_dir_t *dirserv_regenerate_directory(void);
static char *format_versions_list(config_line_t *ln);
@@ -79,7 +95,8 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp(
const char *fp,
int extrainfo,
time_t publish_cutoff);
-static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg);
+static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
+ const char **msg);
/************** Measured Bandwidth parsing code ******/
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
@@ -388,18 +405,18 @@ 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));
- /* Versions before Tor 0.2.1.30 have known security issues that
+ /* Versions before Tor 0.2.2.35 have known security issues that
* make them unsuitable for the current network. */
- if (platform && !tor_version_as_new_as(platform,"0.2.1.30")) {
+ if (platform && !tor_version_as_new_as(platform,"0.2.2.35")) {
if (msg)
- *msg = "Tor version is insecure. Please upgrade!";
+ *msg = "Tor version is insecure or unsupported. Please upgrade!";
return FP_REJECT;
- } else if (platform && tor_version_as_new_as(platform,"0.2.2.1-alpha")) {
- /* Versions from 0.2.2.1-alpha...0.2.2.20-alpha have known security
+ } else if (platform && tor_version_as_new_as(platform,"0.2.3.0-alpha")) {
+ /* Versions from 0.2.3-alpha...0.2.3.9-alpha have known security
* issues that make them unusable for the current network */
- if (!tor_version_as_new_as(platform, "0.2.2.21-alpha")) {
+ if (!tor_version_as_new_as(platform, "0.2.3.10-alpha")) {
if (msg)
- *msg = "Tor version is insecure. Please upgrade!";
+ *msg = "Tor version is insecure or unsupported. Please upgrade!";
return FP_REJECT;
}
}
@@ -501,8 +518,8 @@ dirserv_free_fingerprint_list(void)
if (!fingerprint_list)
return;
- strmap_free(fingerprint_list->fp_by_name, _tor_free);
- digestmap_free(fingerprint_list->status_by_digest, _tor_free);
+ strmap_free(fingerprint_list->fp_by_name, tor_free_);
+ digestmap_free(fingerprint_list->status_by_digest, tor_free_);
tor_free(fingerprint_list);
}
@@ -717,7 +734,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
"MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.",
ri->nickname, source, (int)ri->cache_info.signed_descriptor_len,
MAX_DESCRIPTOR_UPLOAD_SIZE);
- *msg = "Router descriptor was too large";
+ *msg = "Router descriptor was too large.";
control_event_or_authdir_new_descriptor("REJECTED",
ri->cache_info.signed_descriptor_body,
ri->cache_info.signed_descriptor_len, *msg);
@@ -980,6 +997,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
unreachable.
*/
int answer;
+ const or_options_t *options = get_options();
node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest);
tor_assert(node);
@@ -988,17 +1006,27 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
answer = ! we_are_hibernating();
} else if (router->is_hibernating &&
(router->cache_info.published_on +
- HIBERNATION_PUBLICATION_SKEW) > router->last_reachable) {
+ HIBERNATION_PUBLICATION_SKEW) > node->last_reachable) {
/* A hibernating router is down unless we (somehow) had contact with it
* since it declared itself to be hibernating. */
answer = 0;
- } else if (get_options()->AssumeReachable) {
+ } else if (options->AssumeReachable) {
/* If AssumeReachable, everybody is up unless they say they are down! */
answer = 1;
} else {
- /* Otherwise, a router counts as up if we found it reachable in the last
- REACHABLE_TIMEOUT seconds. */
- answer = (now < router->last_reachable + REACHABLE_TIMEOUT);
+ /* Otherwise, a router counts as up if we found all announced OR
+ ports reachable in the last REACHABLE_TIMEOUT seconds.
+
+ XXX prop186 For now there's always one IPv4 and at most one
+ IPv6 OR port.
+
+ If we're not on IPv6, don't consider reachability of potential
+ IPv6 OR port since that'd kill all dual stack relays until a
+ majority of the dir auths have IPv6 connectivity. */
+ answer = (now < node->last_reachable + REACHABLE_TIMEOUT &&
+ (options->AuthDirHasIPv6Connectivity != 1 ||
+ tor_addr_is_null(&router->ipv6_addr) ||
+ now < node->last_reachable6 + REACHABLE_TIMEOUT));
}
if (!answer && running_long_enough_to_decide_unreachable()) {
@@ -1008,11 +1036,13 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
REACHABILITY_TEST_CYCLE_PERIOD seconds, then the router has probably
been down since at least that time after we last successfully reached
it.
+
+ XXX ipv6
*/
time_t when = now;
- if (router->last_reachable &&
- router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
- when = router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
+ if (node->last_reachable &&
+ node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
+ when = node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
rep_hist_note_router_unreachable(router->cache_info.identity_digest, when);
}
@@ -1117,6 +1147,8 @@ int
dirserv_dump_directory_to_string(char **dir_out,
crypto_pk_t *private_key)
{
+ /* XXXX 024 Get rid of this function if we can confirm that nobody's
+ * fetching these any longer */
char *cp;
char *identity_pkey; /* Identity key, DER64-encoded. */
char *recommended_versions;
@@ -1399,7 +1431,7 @@ clear_cached_dir(cached_dir_t *d)
/** Free all storage held by the cached_dir_t in <b>d</b>. */
static void
-_free_cached_dir(void *_d)
+free_cached_dir_(void *_d)
{
cached_dir_t *d;
if (!_d)
@@ -1417,21 +1449,12 @@ _free_cached_dir(void *_d)
* If <b>is_running_routers</b>, this is really a v1 running_routers
* document rather than a v1 directory.
*/
-void
-dirserv_set_cached_directory(const char *directory, time_t published,
- int is_running_routers)
+static void
+dirserv_set_cached_directory(const char *directory, time_t published)
{
- time_t now = time(NULL);
- if (is_running_routers) {
- if (published >= now - MAX_V1_RR_AGE)
- set_cached_dir(&cached_runningrouters, tor_strdup(directory), published);
- } else {
- if (published >= now - MAX_V1_DIRECTORY_AGE) {
- cached_dir_decref(cached_directory);
- cached_directory = new_cached_dir(tor_strdup(directory), published);
- }
- }
+ cached_dir_decref(cached_directory);
+ cached_directory = new_cached_dir(tor_strdup(directory), published);
}
/** If <b>networkstatus</b> is non-NULL, we've just received a v2
@@ -1448,7 +1471,6 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
time_t published)
{
cached_dir_t *d, *old_d;
- smartlist_t *trusted_dirs;
if (!cached_v2_networkstatus)
cached_v2_networkstatus = digestmap_new();
@@ -1471,9 +1493,9 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
}
/* Now purge old entries. */
- trusted_dirs = router_get_trusted_dir_servers();
+
if (digestmap_size(cached_v2_networkstatus) >
- smartlist_len(trusted_dirs) + MAX_UNTRUSTED_NETWORKSTATUSES) {
+ get_n_authorities(V2_DIRINFO) + MAX_UNTRUSTED_NETWORKSTATUSES) {
/* We need to remove the oldest untrusted networkstatus. */
const char *oldest = NULL;
time_t oldest_published = TIME_MAX;
@@ -1613,6 +1635,8 @@ dirserv_get_directory(void)
static cached_dir_t *
dirserv_regenerate_directory(void)
{
+ /* XXXX 024 Get rid of this function if we can confirm that nobody's
+ * fetching these any longer */
char *new_directory=NULL;
if (dirserv_dump_directory_to_string(&new_directory,
@@ -1632,7 +1656,7 @@ dirserv_regenerate_directory(void)
/* Save the directory to disk so we re-load it quickly on startup.
*/
- dirserv_set_cached_directory(the_directory->dir, time(NULL), 0);
+ dirserv_set_cached_directory(the_directory->dir, time(NULL));
return the_directory;
}
@@ -2040,7 +2064,7 @@ version_from_platform(const char *platform)
* non-NULL, add a "v" line for the platform. Return 0 on success, -1 on
* failure.
*
- * The format argument has three possible values:
+ * The format argument has one of the following values:
* NS_V2 - Output an entry suitable for a V2 NS opinion document
* NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
* NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
@@ -2079,15 +2103,32 @@ routerstatus_format_entry(char *buf, size_t buf_len,
log_warn(LD_BUG, "Not enough space in buffer.");
return -1;
}
+ cp = buf + strlen(buf);
/* TODO: Maybe we want to pass in what we need to build the rest of
* this here, instead of in the caller. Then we could use the
* networkstatus_type_t values, with an additional control port value
* added -MP */
- if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
+
+ /* V3 microdesc consensuses don't have "a" lines. */
+ if (format == NS_V3_CONSENSUS_MICRODESC)
+ return 0;
+
+ /* Possible "a" line. At most one for now. */
+ if (!tor_addr_is_null(&rs->ipv6_addr)) {
+ r = tor_snprintf(cp, buf_len - (cp-buf),
+ "a %s\n",
+ fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
+ if (r<0) {
+ log_warn(LD_BUG, "Not enough space in buffer.");
+ return -1;
+ }
+ cp += strlen(cp);
+ }
+
+ if (format == NS_V3_CONSENSUS)
return 0;
- cp = buf + strlen(buf);
/* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
r = tor_snprintf(cp, buf_len - (cp-buf),
"s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
@@ -2114,7 +2155,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
/* length of "opt v \n" */
#define V_LINE_OVERHEAD 7
if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
- if (tor_snprintf(cp, buf_len - (cp-buf), "opt v %s\n", version)<0) {
+ if (tor_snprintf(cp, buf_len - (cp-buf), "v %s\n", version)<0) {
log_warn(LD_BUG, "Unable to print router version.");
return -1;
}
@@ -2192,7 +2233,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
}
if (desc) {
- summary = policy_summarize(desc->exit_policy);
+ summary = policy_summarize(desc->exit_policy, AF_INET);
r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
if (r<0) {
log_warn(LD_BUG, "Not enough space in buffer.");
@@ -2213,7 +2254,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
* and a router with more bandwidth is more useful than one with less.)
**/
static int
-_compare_routerinfo_by_ip_and_bw(const void **a, const void **b)
+compare_routerinfo_by_ip_and_bw_(const void **a, const void **b)
{
routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b;
int first_is_auth, second_is_auth;
@@ -2288,7 +2329,7 @@ get_possible_sybil_list(const smartlist_t *routers)
max_with_same_addr_on_authority = INT_MAX;
smartlist_add_all(routers_by_ip, routers);
- smartlist_sort(routers_by_ip, _compare_routerinfo_by_ip_and_bw);
+ smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_);
omit_as_sybil = digestmap_new();
last_addr = 0;
@@ -2393,8 +2434,6 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
int listbaddirs, int vote_on_hsdirs)
{
const or_options_t *options = get_options();
- int unstable_version =
- !tor_version_as_new_as(ri->platform,"0.1.1.16-rc-cvs");
uint32_t routerbw = router_get_advertised_bandwidth(ri);
memset(rs, 0, sizeof(routerstatus_t));
@@ -2406,8 +2445,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->is_exit = node->is_exit;
rs->is_stable = node->is_stable =
router_is_active(ri, node, now) &&
- !dirserv_thinks_router_is_unreliable(now, ri, 1, 0) &&
- !unstable_version;
+ !dirserv_thinks_router_is_unreliable(now, ri, 1, 0);
rs->is_fast = node->is_fast =
router_is_active(ri, node, now) &&
!dirserv_thinks_router_is_unreliable(now, ri, 0, 1);
@@ -2453,6 +2491,14 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname));
rs->or_port = ri->or_port;
rs->dir_port = ri->dir_port;
+ if (options->AuthDirHasIPv6Connectivity == 1 &&
+ !tor_addr_is_null(&ri->ipv6_addr) &&
+ node->last_reachable6 >= now - REACHABLE_TIMEOUT) {
+ /* We're configured as having IPv6 connectivity. There's an IPv6
+ OR port and it's reachable so copy it to the routerstatus. */
+ tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr);
+ rs->ipv6_orport = ri->ipv6_orport;
+ }
}
/** Routerstatus <b>rs</b> is part of a group of routers that are on
@@ -2715,6 +2761,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
microdescriptors = smartlist_new();
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
+ const struct consensus_method_range_t *cmr = NULL;
if (ri->cache_info.published_on >= cutoff) {
routerstatus_t *rs;
vote_routerstatus_t *vrs;
@@ -2736,17 +2783,22 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
rs->is_flagged_running = 0;
vrs->version = version_from_platform(ri->platform);
- md = dirvote_create_microdescriptor(ri);
- if (md) {
- char buf[128];
- vote_microdesc_hash_t *h;
- dirvote_format_microdesc_vote_line(buf, sizeof(buf), md);
- h = tor_malloc(sizeof(vote_microdesc_hash_t));
- h->microdesc_hash_line = tor_strdup(buf);
- h->next = NULL;
- vrs->microdesc = h;
- md->last_listed = now;
- smartlist_add(microdescriptors, md);
+ for (cmr = microdesc_consensus_methods;
+ cmr->low != -1 && cmr->high != -1;
+ cmr++) {
+ md = dirvote_create_microdescriptor(ri, cmr->low);
+ if (md) {
+ char buf[128];
+ vote_microdesc_hash_t *h;
+ dirvote_format_microdesc_vote_line(buf, sizeof(buf), md,
+ cmr->low, cmr->high);
+ h = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
+ h->microdesc_hash_line = tor_strdup(buf);
+ h->next = vrs->microdesc;
+ vrs->microdesc = h;
+ md->last_listed = now;
+ smartlist_add(microdescriptors, md);
+ }
}
smartlist_add(routerstatuses, vrs);
@@ -3074,7 +3126,7 @@ dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result,
}
} else {
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
if (ds->type & V2_DIRINFO)
smartlist_add(result, tor_memdup(ds->digest, DIGEST_LEN)));
}
@@ -3273,36 +3325,42 @@ dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
* Inform the reachability checker that we could get to this guy.
*/
void
-dirserv_orconn_tls_done(const char *address,
+dirserv_orconn_tls_done(const tor_addr_t *addr,
uint16_t or_port,
const char *digest_rcvd)
{
- routerinfo_t *ri;
+ node_t *node = NULL;
+ tor_addr_port_t orport;
+ routerinfo_t *ri = NULL;
time_t now = time(NULL);
- tor_assert(address);
+ tor_assert(addr);
tor_assert(digest_rcvd);
- ri = router_get_mutable_by_digest(digest_rcvd);
-
- if (ri == NULL)
+ node = node_get_mutable_by_id(digest_rcvd);
+ if (node == NULL || node->ri == NULL)
return;
+ ri = node->ri;
- if (!strcasecmp(address, ri->address) && or_port == ri->or_port) {
+ tor_addr_copy(&orport.addr, addr);
+ orport.port = or_port;
+ if (router_has_orport(ri, &orport)) {
/* Found the right router. */
if (!authdir_mode_bridge(get_options()) ||
ri->purpose == ROUTER_PURPOSE_BRIDGE) {
+ char addrstr[TOR_ADDR_BUF_LEN];
/* This is a bridge or we're not a bridge authorititative --
mark it as reachable. */
- tor_addr_t addr, *addrp=NULL;
log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.",
router_describe(ri),
- address, ri->or_port);
- if (tor_addr_parse(&addr, ri->address) != -1)
- addrp = &addr;
- else
- log_warn(LD_BUG, "Couldn't parse IP address \"%s\"", ri->address);
- rep_hist_note_router_reachable(digest_rcvd, addrp, or_port, now);
- ri->last_reachable = now;
+ tor_addr_to_str(addrstr, addr, sizeof(addrstr), 1),
+ ri->or_port);
+ if (tor_addr_family(addr) == AF_INET) {
+ rep_hist_note_router_reachable(digest_rcvd, addr, or_port, now);
+ node->last_reachable = now;
+ } else if (tor_addr_family(addr) == AF_INET6) {
+ /* No rephist for IPv6. */
+ node->last_reachable6 = now;
+ }
}
}
}
@@ -3325,7 +3383,7 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
/* It just came out of hibernation; launch a reachability test */
return 1;
}
- if (! routers_have_same_or_addr(ri, ri_old)) {
+ if (! routers_have_same_or_addrs(ri, ri_old)) {
/* Address or port changed; launch a reachability test */
return 1;
}
@@ -3338,15 +3396,35 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
void
dirserv_single_reachability_test(time_t now, routerinfo_t *router)
{
+ channel_t *chan = NULL;
+ node_t *node = NULL;
tor_addr_t router_addr;
+ (void) now;
+
+ tor_assert(router);
+ node = node_get_mutable_by_id(router->cache_info.identity_digest);
+ tor_assert(node);
+
+ /* IPv4. */
log_debug(LD_OR,"Testing reachability of %s at %s:%u.",
router->nickname, router->address, router->or_port);
- /* Remember when we started trying to determine reachability */
- if (!router->testing_since)
- router->testing_since = now;
tor_addr_from_ipv4h(&router_addr, router->addr);
- connection_or_connect(&router_addr, router->or_port,
- router->cache_info.identity_digest);
+ chan = channel_tls_connect(&router_addr, router->or_port,
+ router->cache_info.identity_digest);
+ if (chan) command_setup_channel(chan);
+
+ /* Possible IPv6. */
+ if (get_options()->AuthDirHasIPv6Connectivity == 1 &&
+ !tor_addr_is_null(&router->ipv6_addr)) {
+ char addrstr[TOR_ADDR_BUF_LEN];
+ log_debug(LD_OR, "Testing reachability of %s at %s:%u.",
+ router->nickname,
+ tor_addr_to_str(addrstr, &router->ipv6_addr, sizeof(addrstr), 1),
+ router->ipv6_orport);
+ chan = channel_tls_connect(&router->ipv6_addr, router->ipv6_orport,
+ router->cache_info.identity_digest);
+ if (chan) command_setup_channel(chan);
+ }
}
/** Auth dir server only: load balance such that we only
@@ -3767,7 +3845,7 @@ connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn)
int
connection_dirserv_flushed_some(dir_connection_t *conn)
{
- tor_assert(conn->_base.state == DIR_CONN_STATE_SERVER_WRITING);
+ tor_assert(conn->base_.state == DIR_CONN_STATE_SERVER_WRITING);
if (connection_get_outbuf_len(TO_CONN(conn)) >= DIRSERV_BUFFER_MIN)
return 0;
@@ -3802,9 +3880,9 @@ dirserv_free_all(void)
cached_dir_decref(cached_directory);
clear_cached_dir(&cached_runningrouters);
- digestmap_free(cached_v2_networkstatus, _free_cached_dir);
+ digestmap_free(cached_v2_networkstatus, free_cached_dir_);
cached_v2_networkstatus = NULL;
- strmap_free(cached_consensuses, _free_cached_dir);
+ strmap_free(cached_consensuses, free_cached_dir_);
cached_consensuses = NULL;
}
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index 22269b2009..0140cfb4d8 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -9,8 +9,8 @@
* \brief Header file for dirserv.c.
**/
-#ifndef _TOR_DIRSERV_H
-#define _TOR_DIRSERV_H
+#ifndef TOR_DIRSERV_H
+#define TOR_DIRSERV_H
/** What fraction (1 over this number) of the relay ID space do we
* (as a directory authority) launch connections to at each reachability
@@ -87,8 +87,6 @@ void directory_set_dirty(void);
cached_dir_t *dirserv_get_directory(void);
cached_dir_t *dirserv_get_runningrouters(void);
cached_dir_t *dirserv_get_consensus(const char *flavor_name);
-void dirserv_set_cached_directory(const char *directory, time_t when,
- int is_running_routers);
void dirserv_set_cached_networkstatus_v2(const char *directory,
const char *identity,
time_t published);
@@ -107,7 +105,7 @@ int dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key,
int is_extrainfo);
int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
const char **msg);
-void dirserv_orconn_tls_done(const char *address,
+void dirserv_orconn_tls_done(const tor_addr_t *addr,
uint16_t or_port,
const char *digest_rcvd);
int dirserv_should_launch_reachability_test(const routerinfo_t *ri,
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 144859ae04..1b9af0f731 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -53,29 +53,6 @@ static int dirvote_compute_consensuses(void);
static int dirvote_publish_consensus(void);
static char *make_consensus_method_list(int low, int high, const char *sep);
-/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 13
-
-/** Lowest consensus method that contains a 'directory-footer' marker */
-#define MIN_METHOD_FOR_FOOTER 9
-
-/** Lowest consensus method that contains bandwidth weights */
-#define MIN_METHOD_FOR_BW_WEIGHTS 9
-
-/** Lowest consensus method that contains consensus params */
-#define MIN_METHOD_FOR_PARAMS 7
-
-/** Lowest consensus method that generates microdescriptors */
-#define MIN_METHOD_FOR_MICRODESC 8
-
-/** Lowest consensus method that ensures a majority of authorities voted
- * for a param. */
-#define MIN_METHOD_FOR_MAJORITY_PARAMS 12
-
-/** Lowest consensus method where microdesc consensuses omit any entry
- * with no microdesc. */
-#define MIN_METHOD_FOR_MANDATORY_MICRODESC 13
-
/* =====
* Voting
* =====*/
@@ -346,7 +323,7 @@ typedef struct dir_src_ent_t {
/** Helper for sorting networkstatus_t votes (not consensuses) by the
* hash of their voters' identity digests. */
static int
-_compare_votes_by_authority_id(const void **_a, const void **_b)
+compare_votes_by_authority_id_(const void **_a, const void **_b)
{
const networkstatus_t *a = *_a, *b = *_b;
return fast_memcmp(get_voter(a)->identity_digest,
@@ -357,7 +334,7 @@ _compare_votes_by_authority_id(const void **_a, const void **_b)
* their identity digests, and return -1, 0, or 1 depending on their
* ordering */
static int
-_compare_dir_src_ents_by_authority_id(const void **_a, const void **_b)
+compare_dir_src_ents_by_authority_id_(const void **_a, const void **_b)
{
const dir_src_ent_t *a = *_a, *b = *_b;
const networkstatus_voter_info_t *a_v = get_voter(a->v),
@@ -424,12 +401,27 @@ compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
/** Helper for sorting routerlists based on compare_vote_rs. */
static int
-_compare_vote_rs(const void **_a, const void **_b)
+compare_vote_rs_(const void **_a, const void **_b)
{
const vote_routerstatus_t *a = *_a, *b = *_b;
return compare_vote_rs(a,b);
}
+/** Helper for sorting OR ports. */
+static int
+compare_orports_(const void **_a, const void **_b)
+{
+ const tor_addr_port_t *a = *_a, *b = *_b;
+ int r;
+
+ if ((r = tor_addr_compare(&a->addr, &b->addr, CMP_EXACT)))
+ return r;
+ if ((r = (((int) b->port) - ((int) a->port))))
+ return r;
+
+ return 0;
+}
+
/** Given a list of vote_routerstatus_t, all for the same router identity,
* return whichever is most frequent, breaking ties in favor of more
* recently published vote_routerstatus_t and in case of ties there,
@@ -437,17 +429,18 @@ _compare_vote_rs(const void **_a, const void **_b)
*/
static vote_routerstatus_t *
compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
- char *microdesc_digest256_out)
+ char *microdesc_digest256_out,
+ tor_addr_port_t *best_alt_orport_out)
{
vote_routerstatus_t *most = NULL, *cur = NULL;
int most_n = 0, cur_n = 0;
time_t most_published = 0;
- /* _compare_vote_rs() sorts the items by identity digest (all the same),
+ /* compare_vote_rs_() sorts the items by identity digest (all the same),
* then by SD digest. That way, if we have a tie that the published_on
* date cannot tie, we use the descriptor with the smaller digest.
*/
- smartlist_sort(votes, _compare_vote_rs);
+ smartlist_sort(votes, compare_vote_rs_);
SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
if (cur && !compare_vote_rs(cur, rs)) {
++cur_n;
@@ -473,6 +466,38 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
tor_assert(most);
+ /* If we're producing "a" lines, vote on potential alternative (sets
+ * of) OR port(s) in the winning routerstatuses.
+ *
+ * XXX prop186 There's at most one alternative OR port (_the_ IPv6
+ * port) for now. */
+ if (consensus_method >= MIN_METHOD_FOR_A_LINES && best_alt_orport_out) {
+ smartlist_t *alt_orports = smartlist_new();
+ const tor_addr_port_t *most_alt_orport = NULL;
+
+ SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
+ if (compare_vote_rs(most, rs) == 0 &&
+ !tor_addr_is_null(&rs->status.ipv6_addr)
+ && rs->status.ipv6_orport) {
+ smartlist_add(alt_orports, tor_addr_port_new(&rs->status.ipv6_addr,
+ rs->status.ipv6_orport));
+ }
+ } SMARTLIST_FOREACH_END(rs);
+
+ smartlist_sort(alt_orports, compare_orports_);
+ most_alt_orport = smartlist_get_most_frequent(alt_orports,
+ compare_orports_);
+ if (most_alt_orport) {
+ memcpy(best_alt_orport_out, most_alt_orport, sizeof(tor_addr_port_t));
+ log_debug(LD_DIR, "\"a\" line winner for %s is %s",
+ most->status.nickname,
+ fmt_addrport(&most_alt_orport->addr, most_alt_orport->port));
+ }
+
+ SMARTLIST_FOREACH(alt_orports, tor_addr_port_t *, ap, tor_free(ap));
+ smartlist_free(alt_orports);
+ }
+
if (consensus_method >= MIN_METHOD_FOR_MICRODESC &&
microdesc_digest256_out) {
smartlist_t *digests = smartlist_new();
@@ -518,7 +543,7 @@ hash_list_members(char *digest_out, size_t len_out,
* positive integers. (Non-integers are treated as prior to all integers, and
* compared lexically.) */
static int
-_cmp_int_strings(const void **_a, const void **_b)
+cmp_int_strings_(const void **_a, const void **_b)
{
const char *a = *_a, *b = *_b;
int ai = (int)tor_parse_long(a, 10, 1, INT_MAX, NULL, NULL);
@@ -549,13 +574,13 @@ compute_consensus_method(smartlist_t *votes)
{
tor_assert(vote->supported_methods);
smartlist_add_all(tmp, vote->supported_methods);
- smartlist_sort(tmp, _cmp_int_strings);
- smartlist_uniq(tmp, _cmp_int_strings, NULL);
+ smartlist_sort(tmp, cmp_int_strings_);
+ smartlist_uniq(tmp, cmp_int_strings_, NULL);
smartlist_add_all(all_methods, tmp);
smartlist_clear(tmp);
});
- smartlist_sort(all_methods, _cmp_int_strings);
+ smartlist_sort(all_methods, cmp_int_strings_);
get_frequent_members(acceptable_methods, all_methods, min);
n_ok = smartlist_len(acceptable_methods);
if (n_ok) {
@@ -1504,7 +1529,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
/* Sort the votes. */
- smartlist_sort(votes, _compare_votes_by_authority_id);
+ smartlist_sort(votes, compare_votes_by_authority_id_);
/* Add the authority sections. */
{
smartlist_t *dir_sources = smartlist_new();
@@ -1523,7 +1548,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add(dir_sources, e_legacy);
}
} SMARTLIST_FOREACH_END(v);
- smartlist_sort(dir_sources, _compare_dir_src_ents_by_authority_id);
+ smartlist_sort(dir_sources, compare_dir_src_ents_by_authority_id_);
SMARTLIST_FOREACH_BEGIN(dir_sources, const dir_src_ent_t *, e) {
char fingerprint[HEX_DIGEST_LEN+1];
@@ -1685,6 +1710,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
int n_listing = 0;
int i;
char microdesc_digest[DIGEST256_LEN];
+ tor_addr_port_t alt_orport = {TOR_ADDR_NULL, 0};
/* Of the next-to-be-considered digest in each voter, which is first? */
SMARTLIST_FOREACH(votes, networkstatus_t *, v, {
@@ -1754,7 +1780,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
* routerinfo and its contents are. */
memset(microdesc_digest, 0, sizeof(microdesc_digest));
rs = compute_routerstatus_consensus(matching_descs, consensus_method,
- microdesc_digest);
+ microdesc_digest, &alt_orport);
/* Copy bits of that into rs_out. */
memset(&rs_out, 0, sizeof(rs_out));
tor_assert(fast_memeq(lowest_id, rs->status.identity_digest,DIGEST_LEN));
@@ -1765,6 +1791,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
rs_out.published_on = rs->status.published_on;
rs_out.dir_port = rs->status.dir_port;
rs_out.or_port = rs->status.or_port;
+ if (consensus_method >= MIN_METHOD_FOR_A_LINES) {
+ tor_addr_copy(&rs_out.ipv6_addr, &alt_orport.addr);
+ rs_out.ipv6_orport = alt_orport.port;
+ }
rs_out.has_bandwidth = 0;
rs_out.has_exitsummary = 0;
@@ -1862,7 +1892,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
* listed that descriptor will have the same summary. If not then
* something is fishy and we'll use the most common one (breaking
* ties in favor of lexicographically larger one (only because it
- * lets me reuse more existing code.
+ * lets me reuse more existing code)).
*
* The other case that can happen is that no authority that voted
* for that descriptor has an exit policy summary. That's
@@ -2457,7 +2487,7 @@ ns_detached_signatures_free(ns_detached_signatures_t *s)
smartlist_free(sigs);
} STRMAP_FOREACH_END;
strmap_free(s->signatures, NULL);
- strmap_free(s->digests, _tor_free);
+ strmap_free(s->digests, tor_free_);
}
tor_free(s);
@@ -2757,7 +2787,7 @@ dirvote_fetch_missing_votes(void)
char *resource;
SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds) {
+ dir_server_t *, ds) {
if (!(ds->type & V3_DIRINFO))
continue;
if (!dirvote_get_vote(ds->v3_identity_digest,
@@ -2875,7 +2905,7 @@ list_v3_auth_ids(void)
smartlist_t *known_v3_keys = smartlist_new();
char *keys;
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
if ((ds->type & V3_DIRINFO) &&
!tor_digest_is_zero(ds->v3_identity_digest))
smartlist_add(known_v3_keys,
@@ -2896,7 +2926,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
{
networkstatus_t *vote;
networkstatus_voter_info_t *vi;
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
pending_vote_t *pending_vote = NULL;
const char *end_of_vote = NULL;
int any_failed = 0;
@@ -3504,15 +3534,11 @@ dirvote_get_vote(const char *fp, int flags)
return NULL;
}
-/** Construct and return a new microdescriptor from a routerinfo <b>ri</b>.
- *
- * XXX Right now, there is only one way to generate microdescriptors from
- * router descriptors. This may change in future consensus methods. If so,
- * we'll need an internal way to remember which method we used, and ask for a
- * particular method.
+/** Construct and return a new microdescriptor from a routerinfo <b>ri</b>
+ * according to <b>consensus_method</b>.
**/
microdesc_t *
-dirvote_create_microdescriptor(const routerinfo_t *ri)
+dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
{
microdesc_t *result = NULL;
char *key = NULL, *summary = NULL, *family = NULL;
@@ -3522,18 +3548,34 @@ dirvote_create_microdescriptor(const routerinfo_t *ri)
if (crypto_pk_write_public_key_to_string(ri->onion_pkey, &key, &keylen)<0)
goto done;
- summary = policy_summarize(ri->exit_policy);
+ summary = policy_summarize(ri->exit_policy, AF_INET);
if (ri->declared_family)
family = smartlist_join_strings(ri->declared_family, " ", 0, NULL);
smartlist_add_asprintf(chunks, "onion-key\n%s", key);
+ if (consensus_method >= MIN_METHOD_FOR_A_LINES &&
+ !tor_addr_is_null(&ri->ipv6_addr) && ri->ipv6_orport)
+ smartlist_add_asprintf(chunks, "a %s\n",
+ fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport));
+
if (family)
smartlist_add_asprintf(chunks, "family %s\n", family);
if (summary && strcmp(summary, "reject 1-65535"))
smartlist_add_asprintf(chunks, "p %s\n", summary);
+ if (consensus_method >= MIN_METHOD_FOR_P6_LINES &&
+ ri->ipv6_exit_policy) {
+ /* XXXX024 This doesn't match proposal 208, which says these should
+ * be taken unchanged from the routerinfo. That's bogosity, IMO:
+ * the proposal should have said to do this instead.*/
+ char *p6 = write_short_policy(ri->ipv6_exit_policy);
+ if (p6 && strcmp(p6, "reject 1-65535"))
+ smartlist_add_asprintf(chunks, "p6 %s\n", p6);
+ tor_free(p6);
+ }
+
output = smartlist_join_strings(chunks, "", 0, NULL);
{
@@ -3561,33 +3603,36 @@ dirvote_create_microdescriptor(const routerinfo_t *ri)
return result;
}
-/** Cached space-separated string to hold */
-static char *microdesc_consensus_methods = NULL;
-
/** Format the appropriate vote line to describe the microdescriptor <b>md</b>
* in a consensus vote document. Write it into the <b>out_len</b>-byte buffer
* in <b>out</b>. Return -1 on failure and the number of characters written
* on success. */
ssize_t
-dirvote_format_microdesc_vote_line(char *out, size_t out_len,
- const microdesc_t *md)
+dirvote_format_microdesc_vote_line(char *out_buf, size_t out_buf_len,
+ const microdesc_t *md,
+ int consensus_method_low,
+ int consensus_method_high)
{
+ ssize_t ret = -1;
char d64[BASE64_DIGEST256_LEN+1];
- if (!microdesc_consensus_methods) {
- microdesc_consensus_methods =
- make_consensus_method_list(MIN_METHOD_FOR_MICRODESC,
- MAX_SUPPORTED_CONSENSUS_METHOD,
- ",");
- tor_assert(microdesc_consensus_methods);
- }
+ char *microdesc_consensus_methods =
+ make_consensus_method_list(consensus_method_low,
+ consensus_method_high,
+ ",");
+ tor_assert(microdesc_consensus_methods);
+
if (digest256_to_base64(d64, md->digest)<0)
- return -1;
+ goto out;
- if (tor_snprintf(out, out_len, "m %s sha256=%s\n",
+ if (tor_snprintf(out_buf, out_buf_len, "m %s sha256=%s\n",
microdesc_consensus_methods, d64)<0)
- return -1;
+ goto out;
- return strlen(out);
+ ret = strlen(out_buf);
+
+ out:
+ tor_free(microdesc_consensus_methods);
+ return ret;
}
/** If <b>vrs</b> has a hash made for the consensus method <b>method</b> with
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index e6f9700614..d14a375161 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -9,8 +9,8 @@
* \brief Header file for dirvote.c.
**/
-#ifndef _TOR_DIRVOTE_H
-#define _TOR_DIRVOTE_H
+#ifndef TOR_DIRVOTE_H
+#define TOR_DIRVOTE_H
/** Lowest allowable value for VoteSeconds. */
#define MIN_VOTE_SECONDS 20
@@ -19,6 +19,35 @@
/** Smallest allowable voting interval. */
#define MIN_VOTE_INTERVAL 300
+/** The highest consensus method that we currently support. */
+#define MAX_SUPPORTED_CONSENSUS_METHOD 15
+
+/** Lowest consensus method that contains a 'directory-footer' marker */
+#define MIN_METHOD_FOR_FOOTER 9
+
+/** Lowest consensus method that contains bandwidth weights */
+#define MIN_METHOD_FOR_BW_WEIGHTS 9
+
+/** Lowest consensus method that contains consensus params */
+#define MIN_METHOD_FOR_PARAMS 7
+
+/** Lowest consensus method that generates microdescriptors */
+#define MIN_METHOD_FOR_MICRODESC 8
+
+/** Lowest consensus method that ensures a majority of authorities voted
+ * for a param. */
+#define MIN_METHOD_FOR_MAJORITY_PARAMS 12
+
+/** Lowest consensus method where microdesc consensuses omit any entry
+ * with no microdesc. */
+#define MIN_METHOD_FOR_MANDATORY_MICRODESC 13
+
+/** Lowest consensus method that contains "a" lines. */
+#define MIN_METHOD_FOR_A_LINES 14
+
+/** Lowest consensus method where microdescs may include a "p6" line. */
+#define MIN_METHOD_FOR_P6_LINES 15
+
void dirvote_free_all(void);
/* vote manipulation */
@@ -70,10 +99,12 @@ networkstatus_t *
dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
authority_cert_t *cert);
-microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri);
+microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri,
+ int consensus_method);
ssize_t dirvote_format_microdesc_vote_line(char *out, size_t out_len,
- const microdesc_t *md);
-
+ const microdesc_t *md,
+ int consensus_method_low,
+ int consensus_method_high);
int vote_routerstatus_find_microdesc_hash(char *digest256_out,
const vote_routerstatus_t *vrs,
int method,
diff --git a/src/or/dns.c b/src/or/dns.c
index 78893bfbed..c81948a601 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -61,6 +61,9 @@ struct evdns_request;
#define evdns_base_resolve_ipv4(base, addr, options, cb, ptr) \
((evdns_resolve_ipv4((addr), (options), (cb), (ptr))!=0) \
? NULL : ((void*)1))
+#define evdns_base_resolve_ipv6(base, addr, options, cb, ptr) \
+ ((evdns_resolve_ipv6((addr), (options), (cb), (ptr))!=0) \
+ ? NULL : ((void*)1))
#define evdns_base_resolve_reverse(base, addr, options, cb, ptr) \
((evdns_resolve_reverse((addr), (options), (cb), (ptr))!=0) \
? NULL : ((void*)1))
@@ -84,12 +87,6 @@ struct evdns_request;
* that the resolver is wedged? */
#define RESOLVE_MAX_TIMEOUT 300
-/** Possible outcomes from hostname lookup: permanent failure,
- * transient (retryable) failure, and success. */
-#define DNS_RESOLVE_FAILED_TRANSIENT 1
-#define DNS_RESOLVE_FAILED_PERMANENT 2
-#define DNS_RESOLVE_SUCCEEDED 3
-
/** Our evdns_base; this structure handles all our name lookups. */
static struct evdns_base *the_evdns_base = NULL;
@@ -117,7 +114,7 @@ typedef struct pending_connection_t {
/* Possible states for a cached resolve_t */
/** We are waiting for the resolver system to tell us an answer here.
* When we get one, or when we time out, the state of this cached_resolve_t
- * will become "DONE" and we'll possibly add a CACHED_VALID or a CACHED_FAILED
+ * will become "DONE" and we'll possibly add a CACHED
* entry. This cached_resolve_t will be in the hash table so that we will
* know not to launch more requests for this addr, but rather to add more
* connections to the pending list for the addr. */
@@ -128,10 +125,18 @@ typedef struct pending_connection_t {
#define CACHE_STATE_DONE 1
/** We are caching an answer for this address. This should have no pending
* connections, and should appear in the hash table. */
-#define CACHE_STATE_CACHED_VALID 2
-/** We are caching a failure for this address. This should have no pending
- * connections, and should appear in the hash table */
-#define CACHE_STATE_CACHED_FAILED 3
+#define CACHE_STATE_CACHED 2
+
+/** @name status values for a single DNS request.
+ *
+ * @{ */
+/** The DNS request is in progress. */
+#define RES_STATUS_INFLIGHT 1
+/** The DNS request finished and gave an answer */
+#define RES_STATUS_DONE_OK 2
+/** The DNS request finished and gave an error */
+#define RES_STATUS_DONE_ERR 3
+/**@}*/
/** A DNS request: possibly completed, possibly pending; cached_resolve
* structs are stored at the OR side in a hash table, and as a linked
@@ -139,19 +144,39 @@ typedef struct pending_connection_t {
*/
typedef struct cached_resolve_t {
HT_ENTRY(cached_resolve_t) node;
- uint32_t magic;
+ uint32_t magic; /**< Must be CACHED_RESOLVE_MAGIC */
char address[MAX_ADDRESSLEN]; /**< The hostname to be resolved. */
+
+ union {
+ uint32_t addr_ipv4; /**< IPv4 addr for <b>address</b>, if successful.
+ * (In host order.) */
+ int err_ipv4; /**< One of DNS_ERR_*, if IPv4 lookup failed. */
+ } result_ipv4; /**< Outcome of IPv4 lookup */
+ union {
+ struct in6_addr addr_ipv6; /**< IPv6 addr for <b>address</b>, if
+ * successful */
+ int err_ipv6; /**< One of DNS_ERR_*, if IPv6 lookup failed. */
+ } result_ipv6; /**< Outcome of IPv6 lookup, if any */
union {
- struct {
- struct in6_addr addr6; /**< IPv6 addr for <b>address</b>. */
- uint32_t addr; /**< IPv4 addr for <b>address</b>. */
- } a;
- char *hostname; /**< Hostname for <b>address</b> (if a reverse lookup) */
- } result;
- uint8_t state; /**< Is this cached entry pending/done/valid/failed? */
- uint8_t is_reverse; /**< Is this a reverse (addr-to-hostname) lookup? */
+ char *hostname; /** A hostname, if PTR lookup happened successfully*/
+ int err_hostname; /** One of DNS_ERR_*, if PTR lookup failed. */
+ } result_ptr;
+ /** @name Status fields
+ *
+ * These take one of the RES_STATUS_* values, depending on the state
+ * of the corresponding lookup.
+ *
+ * @{ */
+ unsigned int res_status_ipv4 : 2;
+ unsigned int res_status_ipv6 : 2;
+ unsigned int res_status_hostname : 2;
+ /**@}*/
+ uint8_t state; /**< Is this cached entry pending/done/informative? */
+
time_t expire; /**< Remove items from cache after this time. */
- uint32_t ttl; /**< What TTL did the nameserver tell us? */
+ uint32_t ttl_ipv4; /**< What TTL did the nameserver tell us? */
+ uint32_t ttl_ipv6; /**< What TTL did the nameserver tell us? */
+ uint32_t ttl_hostname; /**< What TTL did the nameserver tell us? */
/** Connections that want to know when we get an answer for this resolve. */
pending_connection_t *pending_connections;
/** Position of this element in the heap*/
@@ -159,20 +184,31 @@ typedef struct cached_resolve_t {
} cached_resolve_t;
static void purge_expired_resolves(time_t now);
-static void dns_found_answer(const char *address, uint8_t is_reverse,
- uint32_t addr, const char *hostname, char outcome,
+static void dns_found_answer(const char *address, uint8_t query_type,
+ int dns_answer,
+ const tor_addr_t *addr,
+ const char *hostname,
uint32_t ttl);
-static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type);
-static int launch_resolve(edge_connection_t *exitconn);
+static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
+ const cached_resolve_t *resolve);
+static int launch_resolve(cached_resolve_t *resolve);
static void add_wildcarded_test_address(const char *address);
static int configure_nameservers(int force);
static int answer_is_wildcarded(const char *ip);
static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
or_circuit_t *oncirc, char **resolved_to_hostname,
- int *made_connection_pending_out);
+ int *made_connection_pending_out,
+ cached_resolve_t **resolve_out);
+static int set_exitconn_info_from_resolve(edge_connection_t *exitconn,
+ const cached_resolve_t *resolve,
+ char **hostname_out);
+static int evdns_err_is_transient(int err);
+static void inform_pending_connections(cached_resolve_t *resolve);
+static void make_pending_resolve_cached(cached_resolve_t *cached);
+
#ifdef DEBUG_DNS_CACHE
-static void _assert_cache_ok(void);
-#define assert_cache_ok() _assert_cache_ok()
+static void assert_cache_ok_(void);
+#define assert_cache_ok() assert_cache_ok_()
#else
#define assert_cache_ok() STMT_NIL
#endif
@@ -181,6 +217,13 @@ static void assert_resolve_ok(cached_resolve_t *resolve);
/** Hash table of cached_resolve objects. */
static HT_HEAD(cache_map, cached_resolve_t) cache_root;
+/** Global: how many IPv6 requests have we made in all? */
+static uint64_t n_ipv6_requests_made = 0;
+/** Global: how many IPv6 requests have timed out? */
+static uint64_t n_ipv6_timeouts = 0;
+/** Global: Do we think that IPv6 DNS is broken? */
+static int dns_is_broken_for_ipv6 = 0;
+
/** Function to compare hashed resolves on their addresses; used to
* implement hash tables. */
static INLINE int
@@ -254,7 +297,7 @@ evdns_log_cb(int warn, const char *msg)
/** Helper: passed to eventdns.c as a callback so it can generate random
* numbers for transaction IDs and 0x20-hack coding. */
static void
-_dns_randfn(char *b, size_t n)
+dns_randfn_(char *b, size_t n)
{
crypto_rand(b,n);
}
@@ -264,7 +307,7 @@ int
dns_init(void)
{
init_cache_map();
- evdns_set_random_bytes_fn(_dns_randfn);
+ evdns_set_random_bytes_fn(dns_randfn_);
if (server_mode(get_options())) {
int r = configure_nameservers(1);
return r;
@@ -336,7 +379,7 @@ dns_get_expiry_ttl(uint32_t ttl)
/** Helper: free storage held by an entry in the DNS cache. */
static void
-_free_cached_resolve(cached_resolve_t *r)
+free_cached_resolve_(cached_resolve_t *r)
{
if (!r)
return;
@@ -345,8 +388,8 @@ _free_cached_resolve(cached_resolve_t *r)
r->pending_connections = victim->next;
tor_free(victim);
}
- if (r->is_reverse)
- tor_free(r->result.hostname);
+ if (r->res_status_hostname == RES_STATUS_DONE_OK)
+ tor_free(r->result_ptr.hostname);
r->magic = 0xFF00FF00;
tor_free(r);
}
@@ -355,7 +398,7 @@ _free_cached_resolve(cached_resolve_t *r)
* less-than-zero, zero, or greater-than-zero as appropriate. Used for
* the priority queue implementation. */
static int
-_compare_cached_resolves_by_expiry(const void *_a, const void *_b)
+compare_cached_resolves_by_expiry_(const void *_a, const void *_b)
{
const cached_resolve_t *a = _a, *b = _b;
if (a->expire < b->expire)
@@ -370,6 +413,65 @@ _compare_cached_resolves_by_expiry(const void *_a, const void *_b)
* will expire. */
static smartlist_t *cached_resolve_pqueue = NULL;
+static void
+cached_resolve_add_answer(cached_resolve_t *resolve,
+ int query_type,
+ int dns_result,
+ const tor_addr_t *answer_addr,
+ const char *answer_hostname,
+ uint32_t ttl)
+{
+ if (query_type == DNS_PTR) {
+ if (resolve->res_status_hostname != RES_STATUS_INFLIGHT)
+ return;
+
+ if (dns_result == DNS_ERR_NONE && answer_hostname) {
+ resolve->result_ptr.hostname = tor_strdup(answer_hostname);
+ resolve->res_status_hostname = RES_STATUS_DONE_OK;
+ } else {
+ resolve->result_ptr.err_hostname = dns_result;
+ resolve->res_status_hostname = RES_STATUS_DONE_ERR;
+ }
+ resolve->ttl_hostname = ttl;
+ } else if (query_type == DNS_IPv4_A) {
+ if (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT)
+ return;
+
+ if (dns_result == DNS_ERR_NONE && answer_addr) {
+ tor_assert(tor_addr_family(answer_addr) == AF_INET);
+ resolve->result_ipv4.addr_ipv4 = tor_addr_to_ipv4h(answer_addr);
+ resolve->res_status_ipv4 = RES_STATUS_DONE_OK;
+ } else {
+ resolve->result_ipv4.err_ipv4 = dns_result;
+ resolve->res_status_ipv4 = RES_STATUS_DONE_ERR;
+ }
+
+ } else if (query_type == DNS_IPv6_AAAA) {
+ if (resolve->res_status_ipv6 != RES_STATUS_INFLIGHT)
+ return;
+
+ if (dns_result == DNS_ERR_NONE && answer_addr) {
+ tor_assert(tor_addr_family(answer_addr) == AF_INET6);
+ memcpy(&resolve->result_ipv6.addr_ipv6,
+ tor_addr_to_in6(answer_addr),
+ sizeof(struct in6_addr));
+ resolve->res_status_ipv6 = RES_STATUS_DONE_OK;
+ } else {
+ resolve->result_ipv6.err_ipv6 = dns_result;
+ resolve->res_status_ipv6 = RES_STATUS_DONE_ERR;
+ }
+ }
+}
+
+/** Return true iff there are no in-flight requests for <b>resolve</b>. */
+static int
+cached_resolve_have_all_answers(const cached_resolve_t *resolve)
+{
+ return (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT &&
+ resolve->res_status_ipv6 != RES_STATUS_INFLIGHT &&
+ resolve->res_status_hostname != RES_STATUS_INFLIGHT);
+}
+
/** Set an expiry time for a cached_resolve_t, and add it to the expiry
* priority queue */
static void
@@ -380,7 +482,7 @@ set_expiry(cached_resolve_t *resolve, time_t expires)
cached_resolve_pqueue = smartlist_new();
resolve->expire = expires;
smartlist_pqueue_add(cached_resolve_pqueue,
- _compare_cached_resolves_by_expiry,
+ compare_cached_resolves_by_expiry_,
STRUCT_OFFSET(cached_resolve_t, minheap_idx),
resolve);
}
@@ -395,13 +497,13 @@ dns_free_all(void)
SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res,
{
if (res->state == CACHE_STATE_DONE)
- _free_cached_resolve(res);
+ free_cached_resolve_(res);
});
}
for (ptr = HT_START(cache_map, &cache_root); ptr != NULL; ptr = next) {
item = *ptr;
next = HT_NEXT_RMV(cache_map, &cache_root, ptr);
- _free_cached_resolve(item);
+ free_cached_resolve_(item);
}
HT_CLEAR(cache_map, &cache_root);
smartlist_free(cached_resolve_pqueue);
@@ -427,7 +529,7 @@ purge_expired_resolves(time_t now)
if (resolve->expire > now)
break;
smartlist_pqueue_pop(cached_resolve_pqueue,
- _compare_cached_resolves_by_expiry,
+ compare_cached_resolves_by_expiry_,
STRUCT_OFFSET(cached_resolve_t, minheap_idx));
if (resolve->state == CACHE_STATE_PENDING) {
@@ -435,8 +537,7 @@ purge_expired_resolves(time_t now)
"Expiring a dns resolve %s that's still pending. Forgot to "
"cull it? DNS resolve didn't tell us about the timeout?",
escaped_safe_str(resolve->address));
- } else if (resolve->state == CACHE_STATE_CACHED_VALID ||
- resolve->state == CACHE_STATE_CACHED_FAILED) {
+ } else if (resolve->state == CACHE_STATE_CACHED) {
log_debug(LD_EXIT,
"Forgetting old cached resolve (address %s, expires %lu)",
escaped_safe_str(resolve->address),
@@ -454,9 +555,9 @@ purge_expired_resolves(time_t now)
pend = resolve->pending_connections;
resolve->pending_connections = pend->next;
/* Connections should only be pending if they have no socket. */
- tor_assert(!SOCKET_OK(pend->conn->_base.s));
+ tor_assert(!SOCKET_OK(pend->conn->base_.s));
pendconn = pend->conn;
- if (!pendconn->_base.marked_for_close) {
+ if (!pendconn->base_.marked_for_close) {
connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT);
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
connection_free(TO_CONN(pendconn));
@@ -465,8 +566,7 @@ purge_expired_resolves(time_t now)
}
}
- if (resolve->state == CACHE_STATE_CACHED_VALID ||
- resolve->state == CACHE_STATE_CACHED_FAILED ||
+ if (resolve->state == CACHE_STATE_CACHED ||
resolve->state == CACHE_STATE_PENDING) {
removed = HT_REMOVE(cache_map, &cache_root, resolve);
if (removed != resolve) {
@@ -481,8 +581,8 @@ purge_expired_resolves(time_t now)
cached_resolve_t *tmp = HT_FIND(cache_map, &cache_root, resolve);
tor_assert(tmp != resolve);
}
- if (resolve->is_reverse)
- tor_free(resolve->result.hostname);
+ if (resolve->res_status_hostname == RES_STATUS_DONE_OK)
+ tor_free(resolve->result_ptr.hostname);
resolve->magic = 0xF0BBF0BB;
tor_free(resolve);
}
@@ -490,19 +590,24 @@ purge_expired_resolves(time_t now)
assert_cache_ok();
}
+/* argument for send_resolved_cell only, meaning "let the answer type be ipv4
+ * or ipv6 depending on the connection's address". */
+#define RESOLVED_TYPE_AUTO 0xff
+
/** Send a response to the RESOLVE request of a connection.
* <b>answer_type</b> must be one of
- * RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT).
+ * RESOLVED_TYPE_(AUTO|ERROR|ERROR_TRANSIENT|).
*
* If <b>circ</b> is provided, and we have a cached answer, send the
* answer back along circ; otherwise, send the answer back along
* <b>conn</b>'s attached circuit.
*/
static void
-send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
+send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
+ const cached_resolve_t *resolved)
{
- char buf[RELAY_PAYLOAD_SIZE];
- size_t buflen;
+ char buf[RELAY_PAYLOAD_SIZE], *cp = buf;
+ size_t buflen = 0;
uint32_t ttl;
buf[0] = answer_type;
@@ -510,19 +615,36 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
switch (answer_type)
{
- case RESOLVED_TYPE_IPV4:
- buf[1] = 4;
- set_uint32(buf+2, tor_addr_to_ipv4n(&conn->_base.addr));
- set_uint32(buf+6, htonl(ttl));
- buflen = 10;
- break;
- /*XXXX IP6 need ipv6 implementation */
+ case RESOLVED_TYPE_AUTO:
+ if (resolved && resolved->res_status_ipv4 == RES_STATUS_DONE_OK) {
+ cp[0] = RESOLVED_TYPE_IPV4;
+ cp[1] = 4;
+ set_uint32(cp+2, htonl(resolved->result_ipv4.addr_ipv4));
+ set_uint32(cp+6, htonl(ttl));
+ cp += 10;
+ }
+ if (resolved && resolved->res_status_ipv6 == RES_STATUS_DONE_OK) {
+ const uint8_t *bytes = resolved->result_ipv6.addr_ipv6.s6_addr;
+ cp[0] = RESOLVED_TYPE_IPV6;
+ cp[1] = 16;
+ memcpy(cp+2, bytes, 16);
+ set_uint32(cp+18, htonl(ttl));
+ cp += 22;
+ }
+ if (cp != buf) {
+ buflen = cp - buf;
+ break;
+ } else {
+ answer_type = RESOLVED_TYPE_ERROR;
+ /* fall through. */
+ }
case RESOLVED_TYPE_ERROR_TRANSIENT:
case RESOLVED_TYPE_ERROR:
{
const char *errmsg = "Error resolving hostname";
size_t msglen = strlen(errmsg);
+ buf[0] = answer_type;
buf[1] = msglen;
strlcpy(buf+2, errmsg, sizeof(buf)-2);
set_uint32(buf+2+msglen, htonl(ttl));
@@ -600,10 +722,11 @@ dns_resolve(edge_connection_t *exitconn)
int is_resolve, r;
int made_connection_pending = 0;
char *hostname = NULL;
- is_resolve = exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE;
+ cached_resolve_t *resolve = NULL;
+ is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE;
r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname,
- &made_connection_pending);
+ &made_connection_pending, &resolve);
switch (r) {
case 1:
@@ -614,7 +737,7 @@ dns_resolve(edge_connection_t *exitconn)
if (hostname)
send_resolved_hostname_cell(exitconn, hostname);
else
- send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_AUTO, resolve);
exitconn->on_circuit = NULL;
} else {
/* Add to the n_streams list; the calling function will send back a
@@ -626,7 +749,7 @@ dns_resolve(edge_connection_t *exitconn)
case 0:
/* The request is pending: add the connection into the linked list of
* resolving_streams on this circuit. */
- exitconn->_base.state = EXIT_CONN_STATE_RESOLVING;
+ exitconn->base_.state = EXIT_CONN_STATE_RESOLVING;
exitconn->next_stream = oncirc->resolving_streams;
oncirc->resolving_streams = exitconn;
break;
@@ -636,14 +759,15 @@ dns_resolve(edge_connection_t *exitconn)
* and stop everybody waiting for the same connection. */
if (is_resolve) {
send_resolved_cell(exitconn,
- (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
+ (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT,
+ NULL);
}
exitconn->on_circuit = NULL;
- dns_cancel_pending_resolve(exitconn->_base.address);
+ dns_cancel_pending_resolve(exitconn->base_.address);
- if (!made_connection_pending && !exitconn->_base.marked_for_close) {
+ if (!made_connection_pending && !exitconn->base_.marked_for_close) {
/* If we made the connection pending, then we freed it already in
* dns_cancel_pending_resolve(). If we marked it for close, it'll
* get freed from the main loop. Otherwise, can free it now. */
@@ -670,48 +794,50 @@ dns_resolve(edge_connection_t *exitconn)
* Set *<b>made_connection_pending_out</b> to true if we have placed
* <b>exitconn</b> on the list of pending connections for some resolve; set it
* to false otherwise.
+ *
+ * Set *<b>resolve_out</b> to a cached resolve, if we found one.
*/
static int
dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
or_circuit_t *oncirc, char **hostname_out,
- int *made_connection_pending_out)
+ int *made_connection_pending_out,
+ cached_resolve_t **resolve_out)
{
cached_resolve_t *resolve;
cached_resolve_t search;
pending_connection_t *pending_connection;
- const routerinfo_t *me;
+ int is_reverse = 0;
tor_addr_t addr;
time_t now = time(NULL);
- uint8_t is_reverse = 0;
int r;
assert_connection_ok(TO_CONN(exitconn), 0);
- tor_assert(!SOCKET_OK(exitconn->_base.s));
+ tor_assert(!SOCKET_OK(exitconn->base_.s));
assert_cache_ok();
tor_assert(oncirc);
*made_connection_pending_out = 0;
- /* first check if exitconn->_base.address is an IP. If so, we already
+ /* first check if exitconn->base_.address is an IP. If so, we already
* know the answer. */
- if (tor_addr_parse(&addr, exitconn->_base.address) >= 0) {
- if (tor_addr_family(&addr) == AF_INET) {
- tor_addr_copy(&exitconn->_base.addr, &addr);
+ if (tor_addr_parse(&addr, exitconn->base_.address) >= 0) {
+ if (tor_addr_family(&addr) == AF_INET ||
+ tor_addr_family(&addr) == AF_INET6) {
+ tor_addr_copy(&exitconn->base_.addr, &addr);
exitconn->address_ttl = DEFAULT_DNS_TTL;
return 1;
} else {
- /* XXXX IPv6 */
+ /* XXXX unspec? Bogus? */
return -1;
}
}
/* If we're a non-exit, don't even do DNS lookups. */
- if (!(me = router_get_my_routerinfo()) ||
- policy_is_reject_star(me->exit_policy)) {
+ if (router_my_exit_policy_is_reject_star())
return -1;
- }
- if (address_is_invalid_destination(exitconn->_base.address, 0)) {
+
+ if (address_is_invalid_destination(exitconn->base_.address, 0)) {
log(LOG_PROTOCOL_WARN, LD_EXIT,
"Rejecting invalid destination address %s",
- escaped_safe_str(exitconn->_base.address));
+ escaped_safe_str(exitconn->base_.address));
return -1;
}
@@ -719,14 +845,14 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
* resolves in the hash table. */
purge_expired_resolves(now);
- /* lower-case exitconn->_base.address, so it's in canonical form */
- tor_strlower(exitconn->_base.address);
+ /* lower-case exitconn->base_.address, so it's in canonical form */
+ tor_strlower(exitconn->base_.address);
/* Check whether this is a reverse lookup. If it's malformed, or it's a
* .in-addr.arpa address but this isn't a resolve request, kill the
* connection.
*/
- if ((r = tor_addr_parse_PTR_name(&addr, exitconn->_base.address,
+ if ((r = tor_addr_parse_PTR_name(&addr, exitconn->base_.address,
AF_UNSPEC, 0)) != 0) {
if (r == 1) {
is_reverse = 1;
@@ -737,21 +863,22 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
if (!is_reverse || !is_resolve) {
if (!is_reverse)
log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.",
- escaped_safe_str(exitconn->_base.address));
+ escaped_safe_str(exitconn->base_.address));
else if (!is_resolve)
log_info(LD_EXIT,
"Attempt to connect to a .in-addr.arpa address \"%s\"; "
"sending error.",
- escaped_safe_str(exitconn->_base.address));
+ escaped_safe_str(exitconn->base_.address));
return -1;
}
//log_notice(LD_EXIT, "Looks like an address %s",
- //exitconn->_base.address);
+ //exitconn->base_.address);
}
+ exitconn->is_reverse_dns_lookup = is_reverse;
/* now check the hash table to see if 'address' is already there. */
- strlcpy(search.address, exitconn->_base.address, sizeof(search.address));
+ strlcpy(search.address, exitconn->base_.address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (resolve && resolve->expire > now) { /* already there */
switch (resolve->state) {
@@ -763,27 +890,19 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
pending_connection->next = resolve->pending_connections;
resolve->pending_connections = pending_connection;
*made_connection_pending_out = 1;
- log_debug(LD_EXIT,"Connection (fd %d) waiting for pending DNS "
- "resolve of %s", exitconn->_base.s,
- escaped_safe_str(exitconn->_base.address));
+ log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") waiting "
+ "for pending DNS resolve of %s", exitconn->base_.s,
+ escaped_safe_str(exitconn->base_.address));
return 0;
- case CACHE_STATE_CACHED_VALID:
- log_debug(LD_EXIT,"Connection (fd %d) found cached answer for %s",
- exitconn->_base.s,
+ case CACHE_STATE_CACHED:
+ log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") found "
+ "cached answer for %s",
+ exitconn->base_.s,
escaped_safe_str(resolve->address));
- exitconn->address_ttl = resolve->ttl;
- if (resolve->is_reverse) {
- tor_assert(is_resolve);
- *hostname_out = tor_strdup(resolve->result.hostname);
- } else {
- tor_addr_from_ipv4h(&exitconn->_base.addr, resolve->result.a.addr);
- }
- return 1;
- case CACHE_STATE_CACHED_FAILED:
- log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s",
- exitconn->_base.s,
- escaped_safe_str(exitconn->_base.address));
- return -1;
+
+ *resolve_out = resolve;
+
+ return set_exitconn_info_from_resolve(exitconn, resolve, hostname_out);
case CACHE_STATE_DONE:
log_err(LD_BUG, "Found a 'DONE' dns resolve still in the cache.");
tor_fragile_assert();
@@ -796,8 +915,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
resolve->magic = CACHED_RESOLVE_MAGIC;
resolve->state = CACHE_STATE_PENDING;
resolve->minheap_idx = -1;
- resolve->is_reverse = is_reverse;
- strlcpy(resolve->address, exitconn->_base.address, sizeof(resolve->address));
+ strlcpy(resolve->address, exitconn->base_.address, sizeof(resolve->address));
/* add this connection to the pending list */
pending_connection = tor_malloc_zero(sizeof(pending_connection_t));
@@ -810,10 +928,115 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
set_expiry(resolve, now + RESOLVE_MAX_TIMEOUT);
log_debug(LD_EXIT,"Launching %s.",
- escaped_safe_str(exitconn->_base.address));
+ escaped_safe_str(exitconn->base_.address));
assert_cache_ok();
- return launch_resolve(exitconn);
+ return launch_resolve(resolve);
+}
+
+/** Given an exit connection <b>exitconn</b>, and a cached_resolve_t
+ * <b>resolve</b> whose DNS lookups have all succeeded or failed, update the
+ * appropriate fields (address_ttl and addr) of <b>exitconn</b>.
+ *
+ * If this is a reverse lookup, set *<b>hostname_out</b> to a newly allocated
+ * copy of the name resulting hostname.
+ *
+ * Return -2 on a transient error, -1 on a permenent error, and 1 on
+ * a successful lookup.
+ */
+static int
+set_exitconn_info_from_resolve(edge_connection_t *exitconn,
+ const cached_resolve_t *resolve,
+ char **hostname_out)
+{
+ int ipv4_ok, ipv6_ok, answer_with_ipv4, r;
+ uint32_t begincell_flags;
+ const int is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE;
+ tor_assert(exitconn);
+ tor_assert(resolve);
+
+ if (exitconn->is_reverse_dns_lookup) {
+ exitconn->address_ttl = resolve->ttl_hostname;
+ if (resolve->res_status_hostname == RES_STATUS_DONE_OK) {
+ *hostname_out = tor_strdup(resolve->result_ptr.hostname);
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ /* If we're here then the connection wants one or either of ipv4, ipv6, and
+ * we can give it one or both. */
+ if (is_resolve) {
+ begincell_flags = BEGIN_FLAG_IPV6_OK;
+ } else {
+ begincell_flags = exitconn->begincell_flags;
+ }
+
+ ipv4_ok = (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) &&
+ ! (begincell_flags & BEGIN_FLAG_IPV4_NOT_OK);
+ ipv6_ok = (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) &&
+ (begincell_flags & BEGIN_FLAG_IPV6_OK) &&
+ get_options()->IPv6Exit;
+
+ /* Now decide which one to actually give. */
+ if (ipv4_ok && ipv6_ok && is_resolve) {
+ answer_with_ipv4 = 1;
+ } else if (ipv4_ok && ipv6_ok) {
+ /* If we have both, see if our exit policy has an opinion. */
+ const uint16_t port = exitconn->base_.port;
+ int ipv4_allowed, ipv6_allowed;
+ tor_addr_t a4, a6;
+ tor_addr_from_ipv4h(&a4, resolve->result_ipv4.addr_ipv4);
+ tor_addr_from_in6(&a6, &resolve->result_ipv6.addr_ipv6);
+ ipv4_allowed = !router_compare_to_my_exit_policy(&a4, port);
+ ipv6_allowed = !router_compare_to_my_exit_policy(&a6, port);
+ if (ipv4_allowed && !ipv6_allowed) {
+ answer_with_ipv4 = 1;
+ } else if (ipv6_allowed && !ipv4_allowed) {
+ answer_with_ipv4 = 0;
+ } else {
+ /* Our exit policy would permit both. Answer with whichever the user
+ * prefers */
+ answer_with_ipv4 = !(begincell_flags &
+ BEGIN_FLAG_IPV6_PREFERRED);
+ }
+ } else {
+ /* Otherwise if one is okay, send it back. */
+ if (ipv4_ok) {
+ answer_with_ipv4 = 1;
+ } else if (ipv6_ok) {
+ answer_with_ipv4 = 0;
+ } else {
+ /* Neither one was okay. Choose based on user preference. */
+ answer_with_ipv4 = !(begincell_flags &
+ BEGIN_FLAG_IPV6_PREFERRED);
+ }
+ }
+
+ /* Finally, we write the answer back. */
+ r = 1;
+ if (answer_with_ipv4) {
+ if (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) {
+ tor_addr_from_ipv4h(&exitconn->base_.addr,
+ resolve->result_ipv4.addr_ipv4);
+ } else {
+ r = evdns_err_is_transient(resolve->result_ipv4.err_ipv4) ? -2 : -1;
+ }
+
+ exitconn->address_ttl = resolve->ttl_ipv4;
+ } else {
+ if (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) {
+ tor_addr_from_in6(&exitconn->base_.addr,
+ &resolve->result_ipv6.addr_ipv6);
+ } else {
+ r = evdns_err_is_transient(resolve->result_ipv6.err_ipv6) ? -2 : -1;
+ }
+
+ exitconn->address_ttl = resolve->ttl_ipv6;
+ }
+
+ return r;
}
/** Log an error and abort if conn is waiting for a DNS resolve.
@@ -826,7 +1049,7 @@ assert_connection_edge_not_dns_pending(edge_connection_t *conn)
#if 1
cached_resolve_t *resolve;
- strlcpy(search.address, conn->_base.address, sizeof(search.address));
+ strlcpy(search.address, conn->base_.address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (!resolve)
return;
@@ -856,7 +1079,7 @@ assert_all_pending_dns_resolves_ok(void)
pend;
pend = pend->next) {
assert_connection_ok(TO_CONN(pend->conn), 0);
- tor_assert(!SOCKET_OK(pend->conn->_base.s));
+ tor_assert(!SOCKET_OK(pend->conn->base_.s));
tor_assert(!connection_in_array(TO_CONN(pend->conn)));
}
}
@@ -871,15 +1094,15 @@ connection_dns_remove(edge_connection_t *conn)
cached_resolve_t search;
cached_resolve_t *resolve;
- tor_assert(conn->_base.type == CONN_TYPE_EXIT);
- tor_assert(conn->_base.state == EXIT_CONN_STATE_RESOLVING);
+ tor_assert(conn->base_.type == CONN_TYPE_EXIT);
+ tor_assert(conn->base_.state == EXIT_CONN_STATE_RESOLVING);
- strlcpy(search.address, conn->_base.address, sizeof(search.address));
+ strlcpy(search.address, conn->base_.address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (!resolve) {
log_notice(LD_BUG, "Address %s is not pending. Dropping.",
- escaped_safe_str(conn->_base.address));
+ escaped_safe_str(conn->base_.address));
return;
}
@@ -891,10 +1114,10 @@ connection_dns_remove(edge_connection_t *conn)
if (pend->conn == conn) {
resolve->pending_connections = pend->next;
tor_free(pend);
- log_debug(LD_EXIT, "First connection (fd %d) no longer waiting "
- "for resolve of %s",
- conn->_base.s,
- escaped_safe_str(conn->_base.address));
+ log_debug(LD_EXIT, "First connection (fd "TOR_SOCKET_T_FORMAT") no "
+ "longer waiting for resolve of %s",
+ conn->base_.s,
+ escaped_safe_str(conn->base_.address));
return;
} else {
for ( ; pend->next; pend = pend->next) {
@@ -903,8 +1126,9 @@ connection_dns_remove(edge_connection_t *conn)
pend->next = victim->next;
tor_free(victim);
log_debug(LD_EXIT,
- "Connection (fd %d) no longer waiting for resolve of %s",
- conn->_base.s, escaped_safe_str(conn->_base.address));
+ "Connection (fd "TOR_SOCKET_T_FORMAT") no longer waiting "
+ "for resolve of %s",
+ conn->base_.s, escaped_safe_str(conn->base_.address));
return; /* more are pending */
}
}
@@ -959,17 +1183,17 @@ dns_cancel_pending_resolve(const char *address)
escaped_safe_str(address));
while (resolve->pending_connections) {
pend = resolve->pending_connections;
- pend->conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ pend->conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
pendconn = pend->conn;
assert_connection_ok(TO_CONN(pendconn), 0);
- tor_assert(!SOCKET_OK(pendconn->_base.s));
- if (!pendconn->_base.marked_for_close) {
+ tor_assert(!SOCKET_OK(pendconn->base_.s));
+ if (!pendconn->base_.marked_for_close) {
connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED);
}
circ = circuit_get_by_edge_conn(pendconn);
if (circ)
circuit_detach_stream(circ, pendconn);
- if (!pendconn->_base.marked_for_close)
+ if (!pendconn->base_.marked_for_close)
connection_free(TO_CONN(pendconn));
resolve->pending_connections = pend->next;
tor_free(pend);
@@ -987,47 +1211,6 @@ dns_cancel_pending_resolve(const char *address)
resolve->state = CACHE_STATE_DONE;
}
-/** Helper: adds an entry to the DNS cache mapping <b>address</b> to the ipv4
- * address <b>addr</b> (if is_reverse is 0) or the hostname <b>hostname</b> (if
- * is_reverse is 1). <b>ttl</b> is a cache ttl; <b>outcome</b> is one of
- * DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
- **/
-static void
-add_answer_to_cache(const char *address, uint8_t is_reverse, uint32_t addr,
- const char *hostname, char outcome, uint32_t ttl)
-{
- cached_resolve_t *resolve;
- if (outcome == DNS_RESOLVE_FAILED_TRANSIENT)
- return;
-
- //log_notice(LD_EXIT, "Adding to cache: %s -> %s (%lx, %s), %d",
- // address, is_reverse?"(reverse)":"", (unsigned long)addr,
- // hostname?hostname:"NULL",(int)outcome);
-
- resolve = tor_malloc_zero(sizeof(cached_resolve_t));
- resolve->magic = CACHED_RESOLVE_MAGIC;
- resolve->state = (outcome == DNS_RESOLVE_SUCCEEDED) ?
- CACHE_STATE_CACHED_VALID : CACHE_STATE_CACHED_FAILED;
- strlcpy(resolve->address, address, sizeof(resolve->address));
- resolve->is_reverse = is_reverse;
- if (is_reverse) {
- if (outcome == DNS_RESOLVE_SUCCEEDED) {
- tor_assert(hostname);
- resolve->result.hostname = tor_strdup(hostname);
- } else {
- tor_assert(! hostname);
- resolve->result.hostname = NULL;
- }
- } else {
- tor_assert(!hostname);
- resolve->result.a.addr = addr;
- }
- resolve->ttl = ttl;
- assert_resolve_ok(resolve);
- HT_INSERT(cache_map, &cache_root, resolve);
- set_expiry(resolve, time(NULL) + dns_get_expiry_ttl(ttl));
-}
-
/** Return true iff <b>address</b> is one of the addresses we use to verify
* that well-known sites aren't being hijacked by our DNS servers. */
static INLINE int
@@ -1038,22 +1221,23 @@ is_test_address(const char *address)
smartlist_string_isin_case(options->ServerDNSTestAddresses, address);
}
-/** Called on the OR side when a DNS worker or the eventdns library tells us
- * the outcome of a DNS resolve: tell all pending connections about the result
- * of the lookup, and cache the value. (<b>address</b> is a NUL-terminated
- * string containing the address to look up; <b>addr</b> is an IPv4 address in
- * host order; <b>outcome</b> is one of
- * DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
+/** Called on the OR side when the eventdns library tells us the outcome of a
+ * single DNS resolve: remember the answer, and tell all pending connections
+ * about the result of the lookup if the lookup is now done. (<b>address</b>
+ * is a NUL-terminated string containing the address to look up;
+ * <b>query_type</b> is one of DNS_{IPv4_A,IPv6_AAAA,PTR}; <b>dns_answer</b>
+ * is DNS_OK or one of DNS_ERR_*, <b>addr</b> is an IPv4 or IPv6 address if we
+ * got one; <b>hostname</b> is a hostname fora PTR request if we got one, and
+ * <b>ttl</b> is the time-to-live of this answer, in seconds.)
*/
static void
-dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
- const char *hostname, char outcome, uint32_t ttl)
+dns_found_answer(const char *address, uint8_t query_type,
+ int dns_answer,
+ const tor_addr_t *addr,
+ const char *hostname, uint32_t ttl)
{
- pending_connection_t *pend;
cached_resolve_t search;
- cached_resolve_t *resolve, *removed;
- edge_connection_t *pendconn;
- circuit_t *circ;
+ cached_resolve_t *resolve;
assert_cache_ok();
@@ -1063,9 +1247,8 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
if (!resolve) {
int is_test_addr = is_test_address(address);
if (!is_test_addr)
- log_info(LD_EXIT,"Resolved unasked address %s; caching anyway.",
+ log_info(LD_EXIT,"Resolved unasked address %s; ignoring.",
escaped_safe_str(address));
- add_answer_to_cache(address, is_reverse, addr, hostname, outcome, ttl);
return;
}
assert_resolve_ok(resolve);
@@ -1081,46 +1264,66 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
tor_assert(resolve->pending_connections == NULL);
return;
}
- /* Removed this assertion: in fact, we'll sometimes get a double answer
- * to the same question. This can happen when we ask one worker to resolve
- * X.Y.Z., then we cancel the request, and then we ask another worker to
- * resolve X.Y.Z. */
- /* tor_assert(resolve->state == CACHE_STATE_PENDING); */
+
+ cached_resolve_add_answer(resolve, query_type, dns_answer,
+ addr, hostname, ttl);
+
+ if (cached_resolve_have_all_answers(resolve)) {
+ inform_pending_connections(resolve);
+
+ make_pending_resolve_cached(resolve);
+ }
+}
+
+/** Given a pending cached_resolve_t that we just finished resolving,
+ * inform every connection that was waiting for the outcome of that
+ * resolution. */
+static void
+inform_pending_connections(cached_resolve_t *resolve)
+{
+ pending_connection_t *pend;
+ edge_connection_t *pendconn;
+ int r;
while (resolve->pending_connections) {
+ char *hostname = NULL;
pend = resolve->pending_connections;
pendconn = pend->conn; /* don't pass complex things to the
connection_mark_for_close macro */
assert_connection_ok(TO_CONN(pendconn),time(NULL));
- if (pendconn->_base.marked_for_close) {
+
+ if (pendconn->base_.marked_for_close) {
/* prevent double-remove. */
- pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
resolve->pending_connections = pend->next;
tor_free(pend);
continue;
}
- tor_addr_from_ipv4h(&pendconn->_base.addr, addr);
- pendconn->address_ttl = ttl;
- if (outcome != DNS_RESOLVE_SUCCEEDED) {
+ r = set_exitconn_info_from_resolve(pendconn,
+ resolve,
+ &hostname);
+
+ if (r < 0) {
/* prevent double-remove. */
- pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
- if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
+ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) {
connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED);
/* This detach must happen after we send the end cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
} else {
- send_resolved_cell(pendconn, outcome == DNS_RESOLVE_FAILED_PERMANENT ?
- RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
+ send_resolved_cell(pendconn, r == -1 ?
+ RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT,
+ NULL);
/* This detach must happen after we send the resolved cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
}
connection_free(TO_CONN(pendconn));
} else {
- if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
- tor_assert(!is_reverse);
+ circuit_t *circ;
+ if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) {
/* prevent double-remove. */
- pend->conn->_base.state = EXIT_CONN_STATE_CONNECTING;
+ pend->conn->base_.state = EXIT_CONN_STATE_CONNECTING;
circ = circuit_get_by_edge_conn(pend->conn);
tor_assert(circ);
@@ -1136,11 +1339,11 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
} else {
/* prevent double-remove. This isn't really an accurate state,
* but it does the right thing. */
- pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
- if (is_reverse)
+ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ if (pendconn->is_reverse_dns_lookup)
send_resolved_hostname_cell(pendconn, hostname);
else
- send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4);
+ send_resolved_cell(pendconn, RESOLVED_TYPE_AUTO, resolve);
circ = circuit_get_by_edge_conn(pendconn);
tor_assert(circ);
circuit_detach_stream(circ, pendconn);
@@ -1150,9 +1353,21 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
resolve->pending_connections = pend->next;
tor_free(pend);
}
+}
+
+/** Remove a pending cached_resolve_t from the hashtable, and add a
+ * corresponding cached cached_resolve_t.
+ *
+ * This function is only necessary because of the perversity of our
+ * cache timeout code; see inline comment for ideas on eliminating it.
+ **/
+static void
+make_pending_resolve_cached(cached_resolve_t *resolve)
+{
+ cached_resolve_t *removed;
resolve->state = CACHE_STATE_DONE;
- removed = HT_REMOVE(cache_map, &cache_root, &search);
+ removed = HT_REMOVE(cache_map, &cache_root, resolve);
if (removed != resolve) {
log_err(LD_BUG, "The pending resolve we found wasn't removable from"
" the cache. Tried to purge %s (%p); instead got %s (%p).",
@@ -1161,8 +1376,42 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
}
assert_resolve_ok(resolve);
assert_cache_ok();
+ /* The resolve will eventually just hit the time-out in the expiry queue and
+ * expire. See fd0bafb0dedc7e2 for a brief explanation of how this got that
+ * way. XXXXX we could do better!*/
+
+ {
+ cached_resolve_t *new_resolve = tor_memdup(resolve,
+ sizeof(cached_resolve_t));
+ uint32_t ttl = UINT32_MAX;
+ new_resolve->expire = 0; /* So that set_expiry won't croak. */
+ if (resolve->res_status_hostname == RES_STATUS_DONE_OK)
+ new_resolve->result_ptr.hostname =
+ tor_strdup(resolve->result_ptr.hostname);
+
+ new_resolve->state = CACHE_STATE_CACHED;
+
+ assert_resolve_ok(new_resolve);
+ HT_INSERT(cache_map, &cache_root, new_resolve);
+
+ if ((resolve->res_status_ipv4 == RES_STATUS_DONE_OK ||
+ resolve->res_status_ipv4 == RES_STATUS_DONE_ERR) &&
+ resolve->ttl_ipv4 < ttl)
+ ttl = resolve->ttl_ipv4;
+
+ if ((resolve->res_status_ipv6 == RES_STATUS_DONE_OK ||
+ resolve->res_status_ipv6 == RES_STATUS_DONE_ERR) &&
+ resolve->ttl_ipv6 < ttl)
+ ttl = resolve->ttl_ipv6;
+
+ if ((resolve->res_status_hostname == RES_STATUS_DONE_OK ||
+ resolve->res_status_hostname == RES_STATUS_DONE_ERR) &&
+ resolve->ttl_hostname < ttl)
+ ttl = resolve->ttl_hostname;
+
+ set_expiry(new_resolve, time(NULL) + dns_get_expiry_ttl(ttl));
+ }
- add_answer_to_cache(address, is_reverse, addr, hostname, outcome, ttl);
assert_cache_ok();
}
@@ -1210,24 +1459,18 @@ configure_nameservers(int force)
}
#ifdef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS
- if (options->OutboundBindAddress) {
- tor_addr_t addr;
- if (tor_addr_parse(&addr, options->OutboundBindAddress) < 0) {
- log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
- options->OutboundBindAddress);
+ if (! tor_addr_is_null(&options->OutboundBindAddressIPv4_)) {
+ int socklen;
+ struct sockaddr_storage ss;
+ socklen = tor_addr_to_sockaddr(&options->OutboundBindAddressIPv4_, 0,
+ (struct sockaddr *)&ss, sizeof(ss));
+ if (socklen <= 0) {
+ log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr."
+ " Ignoring.");
} else {
- int socklen;
- struct sockaddr_storage ss;
- socklen = tor_addr_to_sockaddr(&addr, 0,
- (struct sockaddr *)&ss, sizeof(ss));
- if (socklen <= 0) {
- log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr."
- " Ignoring.");
- } else {
- evdns_base_set_default_outgoing_bind_address(the_evdns_base,
- (struct sockaddr *)&ss,
- socklen);
- }
+ evdns_base_set_default_outgoing_bind_address(the_evdns_base,
+ (struct sockaddr *)&ss,
+ socklen);
}
}
#endif
@@ -1331,23 +1574,40 @@ static void
evdns_callback(int result, char type, int count, int ttl, void *addresses,
void *arg)
{
- char *string_address = arg;
- uint8_t is_reverse = 0;
- int status = DNS_RESOLVE_FAILED_PERMANENT;
- uint32_t addr = 0;
+ char *arg_ = arg;
+ uint8_t orig_query_type = arg_[0];
+ char *string_address = arg_ + 1;
+ tor_addr_t addr;
const char *hostname = NULL;
int was_wildcarded = 0;
+ tor_addr_make_unspec(&addr);
+
+ /* Keep track of whether IPv6 is working */
+ if (type == DNS_IPv6_AAAA) {
+ if (result == DNS_ERR_TIMEOUT) {
+ ++n_ipv6_timeouts;
+ }
+
+ if (n_ipv6_timeouts > 10 &&
+ n_ipv6_timeouts > n_ipv6_requests_made / 2) {
+ if (! dns_is_broken_for_ipv6) {
+ log_notice(LD_EXIT, "More than half of our IPv6 requests seem to "
+ "have timed out. I'm going to assume I can't get AAAA "
+ "responses.");
+ dns_is_broken_for_ipv6 = 1;
+ }
+ }
+ }
+
if (result == DNS_ERR_NONE) {
if (type == DNS_IPv4_A && count) {
char answer_buf[INET_NTOA_BUF_LEN+1];
- struct in_addr in;
char *escaped_address;
uint32_t *addrs = addresses;
- in.s_addr = addrs[0];
- addr = ntohl(addrs[0]);
- status = DNS_RESOLVE_SUCCEEDED;
- tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
+ tor_addr_from_ipv4n(&addr, addrs[0]);
+
+ tor_addr_to_str(answer_buf, &addr, sizeof(answer_buf), 0);
escaped_address = esc_for_log(string_address);
if (answer_is_wildcarded(answer_buf)) {
@@ -1356,8 +1616,30 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
safe_str(escaped_address),
escaped_safe_str(answer_buf));
was_wildcarded = 1;
- addr = 0;
- status = DNS_RESOLVE_FAILED_PERMANENT;
+ tor_addr_make_unspec(&addr);
+ result = DNS_ERR_NOTEXIST;
+ } else {
+ log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
+ safe_str(escaped_address),
+ escaped_safe_str(answer_buf));
+ }
+ tor_free(escaped_address);
+ } else if (type == DNS_IPv6_AAAA && count) {
+ char answer_buf[TOR_ADDR_BUF_LEN];
+ char *escaped_address;
+ struct in6_addr *addrs = addresses;
+ tor_addr_from_in6(&addr, &addrs[0]);
+ tor_inet_ntop(AF_INET6, &addrs[0], answer_buf, sizeof(answer_buf));
+ escaped_address = esc_for_log(string_address);
+
+ if (answer_is_wildcarded(answer_buf)) {
+ log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked "
+ "address %s; treating as a failure.",
+ safe_str(escaped_address),
+ escaped_safe_str(answer_buf));
+ was_wildcarded = 1;
+ tor_addr_make_unspec(&addr);
+ result = DNS_ERR_NOTEXIST;
} else {
log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
safe_str(escaped_address),
@@ -1366,9 +1648,7 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
tor_free(escaped_address);
} else if (type == DNS_PTR && count) {
char *escaped_address;
- is_reverse = 1;
hostname = ((char**)addresses)[0];
- status = DNS_RESOLVE_SUCCEEDED;
escaped_address = esc_for_log(string_address);
log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
safe_str(escaped_address),
@@ -1381,9 +1661,6 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
log_warn(LD_BUG, "eventdns returned no addresses or error for %s!",
escaped_safe_str(string_address));
}
- } else {
- if (evdns_err_is_transient(result))
- status = DNS_RESOLVE_FAILED_TRANSIENT;
}
if (was_wildcarded) {
if (is_test_address(string_address)) {
@@ -1392,23 +1669,78 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
add_wildcarded_test_address(string_address);
}
}
+
+ if (orig_query_type && type && orig_query_type != type) {
+ log_warn(LD_BUG, "Weird; orig_query_type == %d but type == %d",
+ (int)orig_query_type, (int)type);
+ }
if (result != DNS_ERR_SHUTDOWN)
- dns_found_answer(string_address, is_reverse, addr, hostname, status, ttl);
- tor_free(string_address);
+ dns_found_answer(string_address, orig_query_type,
+ result, &addr, hostname, ttl);
+
+ tor_free(arg_);
+}
+
+/** Start a single DNS resolve for <b>address</b> (if <b>query_type</b> is
+ * DNS_IPv4_A or DNS_IPv6_AAAA) <b>ptr_address</b> (if <b>query_type</b> is
+ * DNS_PTR). Return 0 if we launched the request, -1 otherwise. */
+static int
+launch_one_resolve(const char *address, uint8_t query_type,
+ const tor_addr_t *ptr_address)
+{
+ const int options = get_options()->ServerDNSSearchDomains ? 0
+ : DNS_QUERY_NO_SEARCH;
+ const size_t addr_len = strlen(address);
+ struct evdns_request *req = 0;
+ char *addr = tor_malloc(addr_len + 2);
+ addr[0] = (char) query_type;
+ memcpy(addr+1, address, addr_len + 1);
+
+ switch (query_type) {
+ case DNS_IPv4_A:
+ req = evdns_base_resolve_ipv4(the_evdns_base,
+ address, options, evdns_callback, addr);
+ break;
+ case DNS_IPv6_AAAA:
+ req = evdns_base_resolve_ipv6(the_evdns_base,
+ address, options, evdns_callback, addr);
+ ++n_ipv6_requests_made;
+ break;
+ case DNS_PTR:
+ if (tor_addr_family(ptr_address) == AF_INET)
+ req = evdns_base_resolve_reverse(the_evdns_base,
+ tor_addr_to_in(ptr_address),
+ DNS_QUERY_NO_SEARCH,
+ evdns_callback, addr);
+ else if (tor_addr_family(ptr_address) == AF_INET6)
+ req = evdns_base_resolve_reverse_ipv6(the_evdns_base,
+ tor_addr_to_in6(ptr_address),
+ DNS_QUERY_NO_SEARCH,
+ evdns_callback, addr);
+ else
+ log_warn(LD_BUG, "Called with PTR query and unexpected address family");
+ break;
+ default:
+ log_warn(LD_BUG, "Called with unexpectd query type %d", (int)query_type);
+ break;
+ }
+
+ if (req) {
+ return 0;
+ } else {
+ tor_free(addr);
+ return -1;
+ }
}
/** For eventdns: start resolving as necessary to find the target for
* <b>exitconn</b>. Returns -1 on error, -2 on transient error,
* 0 on "resolve launched." */
static int
-launch_resolve(edge_connection_t *exitconn)
+launch_resolve(cached_resolve_t *resolve)
{
- char *addr;
- struct evdns_request *req = NULL;
tor_addr_t a;
int r;
- int options = get_options()->ServerDNSSearchDomains ? 0
- : DNS_QUERY_NO_SEARCH;
if (get_options()->DisableNetwork)
return -1;
@@ -1422,40 +1754,45 @@ launch_resolve(edge_connection_t *exitconn)
}
}
- addr = tor_strdup(exitconn->_base.address);
-
r = tor_addr_parse_PTR_name(
- &a, exitconn->_base.address, AF_UNSPEC, 0);
+ &a, resolve->address, AF_UNSPEC, 0);
tor_assert(the_evdns_base);
if (r == 0) {
log_info(LD_EXIT, "Launching eventdns request for %s",
- escaped_safe_str(exitconn->_base.address));
- req = evdns_base_resolve_ipv4(the_evdns_base,
- exitconn->_base.address, options,
- evdns_callback, addr);
+ escaped_safe_str(resolve->address));
+ resolve->res_status_ipv4 = RES_STATUS_INFLIGHT;
+ if (get_options()->IPv6Exit)
+ resolve->res_status_ipv6 = RES_STATUS_INFLIGHT;
+
+ if (launch_one_resolve(resolve->address, DNS_IPv4_A, NULL) < 0) {
+ resolve->res_status_ipv4 = 0;
+ r = -1;
+ }
+
+ if (r==0 && get_options()->IPv6Exit) {
+ /* We ask for an IPv6 address for *everything*. */
+ if (launch_one_resolve(resolve->address, DNS_IPv6_AAAA, NULL) < 0) {
+ resolve->res_status_ipv6 = 0;
+ r = -1;
+ }
+ }
} else if (r == 1) {
+ r = 0;
log_info(LD_EXIT, "Launching eventdns reverse request for %s",
- escaped_safe_str(exitconn->_base.address));
- if (tor_addr_family(&a) == AF_INET)
- req = evdns_base_resolve_reverse(the_evdns_base,
- tor_addr_to_in(&a), DNS_QUERY_NO_SEARCH,
- evdns_callback, addr);
- else
- req = evdns_base_resolve_reverse_ipv6(the_evdns_base,
- tor_addr_to_in6(&a), DNS_QUERY_NO_SEARCH,
- evdns_callback, addr);
+ escaped_safe_str(resolve->address));
+ resolve->res_status_hostname = RES_STATUS_INFLIGHT;
+ if (launch_one_resolve(resolve->address, DNS_PTR, &a) < 0) {
+ resolve->res_status_hostname = 0;
+ r = -1;
+ }
} else if (r == -1) {
log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here.");
}
- r = 0;
- if (!req) {
+ if (r < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_EXIT, "eventdns rejected address %s.",
- escaped_safe_str(addr));
- r = -1;
- tor_free(addr); /* There is no evdns request in progress; stop
- * addr from getting leaked. */
+ escaped_safe_str(resolve->address));
}
return r;
}
@@ -1488,8 +1825,8 @@ static int dns_wildcarded_test_address_notice_given = 0;
/** True iff all addresses seem to be getting wildcarded. */
static int dns_is_completely_invalid = 0;
-/** Called when we see <b>id</b> (a dotted quad) in response to a request for
- * a hopefully bogus address. */
+/** Called when we see <b>id</b> (a dotted quad or IPv6 address) in response
+ * to a request for a hopefully bogus address. */
static void
wildcard_increment_answer(const char *id)
{
@@ -1561,17 +1898,27 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl,
{
(void)ttl;
++n_wildcard_requests;
- if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) {
- uint32_t *addrs = addresses;
- int i;
+ if (result == DNS_ERR_NONE && count) {
char *string_address = arg;
- for (i = 0; i < count; ++i) {
- char answer_buf[INET_NTOA_BUF_LEN+1];
- struct in_addr in;
- in.s_addr = addrs[i];
- tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
- wildcard_increment_answer(answer_buf);
+ int i;
+ if (type == DNS_IPv4_A) {
+ const uint32_t *addrs = addresses;
+ for (i = 0; i < count; ++i) {
+ char answer_buf[INET_NTOA_BUF_LEN+1];
+ struct in_addr in;
+ in.s_addr = addrs[i];
+ tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
+ wildcard_increment_answer(answer_buf);
+ }
+ } else if (type == DNS_IPv6_AAAA) {
+ const struct in6_addr *addrs = addresses;
+ for (i = 0; i < count; ++i) {
+ char answer_buf[TOR_ADDR_BUF_LEN+1];
+ tor_inet_ntop(AF_INET6, &addrs[i], answer_buf, sizeof(answer_buf));
+ wildcard_increment_answer(answer_buf);
+ }
}
+
log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
"Your DNS provider gave an answer for \"%s\", which "
"is not supposed to exist. Apparently they are hijacking "
@@ -1588,7 +1935,8 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl,
* <b>min_len</b> and <b>max_len</b> random (plausible) characters followed by
* <b>suffix</b> */
static void
-launch_wildcard_check(int min_len, int max_len, const char *suffix)
+launch_wildcard_check(int min_len, int max_len, int is_ipv6,
+ const char *suffix)
{
char *addr;
struct evdns_request *req;
@@ -1598,7 +1946,15 @@ launch_wildcard_check(int min_len, int max_len, const char *suffix)
"domains with request for bogus hostname \"%s\"", addr);
tor_assert(the_evdns_base);
- req = evdns_base_resolve_ipv4(
+ if (is_ipv6)
+ req = evdns_base_resolve_ipv6(
+ the_evdns_base,
+ /* This "addr" tells us which address to resolve */
+ addr,
+ DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback,
+ /* This "addr" is an argument to the callback*/ addr);
+ else
+ req = evdns_base_resolve_ipv4(
the_evdns_base,
/* This "addr" tells us which address to resolve */
addr,
@@ -1613,10 +1969,9 @@ launch_wildcard_check(int min_len, int max_len, const char *suffix)
/** Launch attempts to resolve a bunch of known-good addresses (configured in
* ServerDNSTestAddresses). [Callback for a libevent timer] */
static void
-launch_test_addresses(int fd, short event, void *args)
+launch_test_addresses(evutil_socket_t fd, short event, void *args)
{
const or_options_t *options = get_options();
- struct evdns_request *req;
(void)fd;
(void)event;
(void)args;
@@ -1629,21 +1984,22 @@ launch_test_addresses(int fd, short event, void *args)
/* This situation is worse than the failure-hijacking situation. When this
* happens, we're no good for DNS requests at all, and we shouldn't really
* be an exit server.*/
- if (!options->ServerDNSTestAddresses)
- return;
- tor_assert(the_evdns_base);
- SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses,
- const char *, address) {
- char *a = tor_strdup(address);
- req = evdns_base_resolve_ipv4(the_evdns_base,
- address, DNS_QUERY_NO_SEARCH, evdns_callback, a);
+ if (options->ServerDNSTestAddresses) {
- if (!req) {
- log_info(LD_EXIT, "eventdns rejected test address %s",
- escaped_safe_str(address));
- tor_free(a);
- }
- } SMARTLIST_FOREACH_END(address);
+ tor_assert(the_evdns_base);
+ SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses,
+ const char *, address) {
+ if (launch_one_resolve(address, DNS_IPv4_A, NULL) < 0) {
+ log_info(LD_EXIT, "eventdns rejected test address %s",
+ escaped_safe_str(address));
+ }
+
+ if (launch_one_resolve(address, DNS_IPv6_AAAA, NULL) < 0) {
+ log_info(LD_EXIT, "eventdns rejected test address %s",
+ escaped_safe_str(address));
+ }
+ } SMARTLIST_FOREACH_END(address);
+ }
}
#define N_WILDCARD_CHECKS 2
@@ -1655,27 +2011,29 @@ launch_test_addresses(int fd, short event, void *args)
static void
dns_launch_wildcard_checks(void)
{
- int i;
+ int i, ipv6;
log_info(LD_EXIT, "Launching checks to see whether our nameservers like "
"to hijack DNS failures.");
- for (i = 0; i < N_WILDCARD_CHECKS; ++i) {
- /* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly attempt
- * to 'comply' with rfc2606, refrain from giving A records for these.
- * This is the standards-compliance equivalent of making sure that your
- * crackhouse's elevator inspection certificate is up to date.
- */
- launch_wildcard_check(2, 16, ".invalid");
- launch_wildcard_check(2, 16, ".test");
-
- /* These will break specs if there are ever any number of
- * 8+-character top-level domains. */
- launch_wildcard_check(8, 16, "");
-
- /* Try some random .com/org/net domains. This will work fine so long as
- * not too many resolve to the same place. */
- launch_wildcard_check(8, 16, ".com");
- launch_wildcard_check(8, 16, ".org");
- launch_wildcard_check(8, 16, ".net");
+ for (ipv6 = 0; ipv6 <= 1; ++ipv6) {
+ for (i = 0; i < N_WILDCARD_CHECKS; ++i) {
+ /* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly
+ * attempt to 'comply' with rfc2606, refrain from giving A records for
+ * these. This is the standards-compliance equivalent of making sure
+ * that your crackhouse's elevator inspection certificate is up to date.
+ */
+ launch_wildcard_check(2, 16, ipv6, ".invalid");
+ launch_wildcard_check(2, 16, ipv6, ".test");
+
+ /* These will break specs if there are ever any number of
+ * 8+-character top-level domains. */
+ launch_wildcard_check(8, 16, ipv6, "");
+
+ /* Try some random .com/org/net domains. This will work fine so long as
+ * not too many resolve to the same place. */
+ launch_wildcard_check(8, 16, ipv6, ".com");
+ launch_wildcard_check(8, 16, ipv6, ".org");
+ launch_wildcard_check(8, 16, ipv6, ".net");
+ }
}
}
@@ -1709,15 +2067,24 @@ dns_seems_to_be_broken(void)
return dns_is_completely_invalid;
}
+/** Return true iff we think that IPv6 hostname lookup is broken */
+int
+dns_seems_to_be_broken_for_ipv6(void)
+{
+ return dns_is_broken_for_ipv6;
+}
+
/** Forget what we've previously learned about our DNS servers' correctness. */
void
dns_reset_correctness_checks(void)
{
- strmap_free(dns_wildcard_response_count, _tor_free);
+ strmap_free(dns_wildcard_response_count, tor_free_);
dns_wildcard_response_count = NULL;
n_wildcard_requests = 0;
+ n_ipv6_requests_made = n_ipv6_timeouts = 0;
+
if (dns_wildcard_list) {
SMARTLIST_FOREACH(dns_wildcard_list, char *, cp, tor_free(cp));
smartlist_clear(dns_wildcard_list);
@@ -1728,7 +2095,8 @@ dns_reset_correctness_checks(void)
smartlist_clear(dns_wildcarded_test_address_list);
}
dns_wildcard_one_notice_given = dns_wildcard_notice_given =
- dns_wildcarded_test_address_notice_given = dns_is_completely_invalid = 0;
+ dns_wildcarded_test_address_notice_given = dns_is_completely_invalid =
+ dns_is_broken_for_ipv6 = 0;
}
/** Return true iff we have noticed that the dotted-quad <b>ip</b> has been
@@ -1752,11 +2120,14 @@ assert_resolve_ok(cached_resolve_t *resolve)
}
if (resolve->state == CACHE_STATE_PENDING ||
resolve->state == CACHE_STATE_DONE) {
+#if 0
tor_assert(!resolve->ttl);
if (resolve->is_reverse)
- tor_assert(!resolve->result.hostname);
+ tor_assert(!resolve->hostname);
else
- tor_assert(!resolve->result.a.addr);
+ tor_assert(!resolve->result_ipv4.addr_ipv4);
+#endif
+ /*XXXXX ADD MORE */
}
}
@@ -1787,7 +2158,7 @@ dump_dns_mem_usage(int severity)
#ifdef DEBUG_DNS_CACHE
/** Exit with an assertion if the DNS cache is corrupt. */
static void
-_assert_cache_ok(void)
+assert_cache_ok_(void)
{
cached_resolve_t **resolve;
int bad_rep = _cache_map_HT_REP_IS_BAD(&cache_root);
@@ -1804,7 +2175,7 @@ _assert_cache_ok(void)
return;
smartlist_pqueue_assert_ok(cached_resolve_pqueue,
- _compare_cached_resolves_by_expiry,
+ compare_cached_resolves_by_expiry_,
STRUCT_OFFSET(cached_resolve_t, minheap_idx));
SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res,
diff --git a/src/or/dns.h b/src/or/dns.h
index 8c8b476ac8..d2f6614e64 100644
--- a/src/or/dns.h
+++ b/src/or/dns.h
@@ -9,8 +9,8 @@
* \brief Header file for dns.c.
**/
-#ifndef _TOR_DNS_H
-#define _TOR_DNS_H
+#ifndef TOR_DNS_H
+#define TOR_DNS_H
int dns_init(void);
int has_dns_init_failed(void);
@@ -24,6 +24,7 @@ void dns_cancel_pending_resolve(const char *question);
int dns_resolve(edge_connection_t *exitconn);
void dns_launch_correctness_checks(void);
int dns_seems_to_be_broken(void);
+int dns_seems_to_be_broken_for_ipv6(void);
void dns_reset_correctness_checks(void);
void dump_dns_mem_usage(int severity);
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 69adcef9ea..a211899073 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -89,6 +89,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
continue;
switch (req->questions[i]->type) {
case EVDNS_TYPE_A:
+ case EVDNS_TYPE_AAAA:
case EVDNS_TYPE_PTR:
q = req->questions[i];
default:
@@ -101,7 +102,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
evdns_server_request_respond(req, DNS_ERR_NOTIMPL);
return;
}
- if (q->type != EVDNS_TYPE_A) {
+ if (q->type != EVDNS_TYPE_A && q->type != EVDNS_TYPE_AAAA) {
tor_assert(q->type == EVDNS_TYPE_PTR);
}
@@ -125,7 +126,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
TO_CONN(conn)->port = port;
TO_CONN(conn)->address = tor_dup_addr(&tor_addr);
- if (q->type == EVDNS_TYPE_A)
+ if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA)
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE;
else
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
@@ -133,7 +134,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
strlcpy(entry_conn->socks_request->address, q->name,
sizeof(entry_conn->socks_request->address));
- entry_conn->socks_request->listener_type = listener->_base.type;
+ entry_conn->socks_request->listener_type = listener->base_.type;
entry_conn->dns_server_request = req;
entry_conn->isolation_flags = listener->isolation_flags;
entry_conn->session_group = listener->session_group;
@@ -178,7 +179,7 @@ dnsserv_launch_request(const char *name, int reverse)
/* Make a new dummy AP connection, and attach the request to it. */
entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET);
conn = ENTRY_TO_EDGE_CONN(entry_conn);
- conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
+ conn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
if (reverse)
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
@@ -289,8 +290,9 @@ dnsserv_resolved(entry_connection_t *conn,
* or more of the questions in the request); then, call
* evdns_server_request_respond. */
if (answer_type == RESOLVED_TYPE_IPV6) {
- log_info(LD_APP, "Got an IPv6 answer; that's not implemented.");
- err = DNS_ERR_NOTIMPL;
+ evdns_server_request_add_aaaa_reply(req,
+ name,
+ 1, answer, ttl);
} else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4 &&
conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
evdns_server_request_add_a_reply(req,
diff --git a/src/or/dnsserv.h b/src/or/dnsserv.h
index 3aaa038d2b..39bd1d33b2 100644
--- a/src/or/dnsserv.h
+++ b/src/or/dnsserv.h
@@ -9,8 +9,8 @@
* \brief Header file for dnsserv.c.
**/
-#ifndef _TOR_DNSSERV_H
-#define _TOR_DNSSERV_H
+#ifndef TOR_DNSSERV_H
+#define TOR_DNSSERV_H
void dnsserv_configure_listener(connection_t *conn);
void dnsserv_close_listener(connection_t *conn);
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
new file mode 100644
index 0000000000..8712241f62
--- /dev/null
+++ b/src/or/entrynodes.c
@@ -0,0 +1,1948 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file entrynodes.c
+ * \brief Code to manage our fixed first nodes for various functions.
+ *
+ * Entry nodes can be guards (for general use) or bridges (for censorship
+ * circumvention).
+ **/
+
+#include "or.h"
+#include "circuitbuild.h"
+#include "circuitstats.h"
+#include "config.h"
+#include "confparse.h"
+#include "connection.h"
+#include "connection_or.h"
+#include "control.h"
+#include "directory.h"
+#include "entrynodes.h"
+#include "main.h"
+#include "nodelist.h"
+#include "policies.h"
+#include "router.h"
+#include "routerlist.h"
+#include "routerparse.h"
+#include "routerset.h"
+#include "transports.h"
+#include "statefile.h"
+
+/** Information about a configured bridge. Currently this just matches the
+ * ones in the torrc file, but one day we may be able to learn about new
+ * bridges on our own, and remember them in the state file. */
+typedef struct {
+ /** Address of the bridge. */
+ tor_addr_t addr;
+ /** TLS port for the bridge. */
+ uint16_t port;
+ /** Boolean: We are re-parsing our bridge list, and we are going to remove
+ * this one if we don't find it in the list of configured bridges. */
+ unsigned marked_for_removal : 1;
+ /** Expected identity digest, or all zero bytes if we don't know what the
+ * digest should be. */
+ char identity[DIGEST_LEN];
+
+ /** Name of pluggable transport protocol taken from its config line. */
+ char *transport_name;
+
+ /** When should we next try to fetch a descriptor for this bridge? */
+ download_status_t fetch_status;
+} bridge_info_t;
+
+/** A list of our chosen entry guards. */
+static smartlist_t *entry_guards = NULL;
+/** A value of 1 means that the entry_guards list has changed
+ * and those changes need to be flushed to disk. */
+static int entry_guards_dirty = 0;
+
+static void bridge_free(bridge_info_t *bridge);
+
+/** Return the list of entry guards, creating it if necessary. */
+const smartlist_t *
+get_entry_guards(void)
+{
+ if (! entry_guards)
+ entry_guards = smartlist_new();
+ return entry_guards;
+}
+
+/** Check whether the entry guard <b>e</b> is usable, given the directory
+ * authorities' opinion about the router (stored in <b>ri</b>) and the user's
+ * configuration (in <b>options</b>). Set <b>e</b>-&gt;bad_since
+ * accordingly. Return true iff the entry guard's status changes.
+ *
+ * If it's not usable, set *<b>reason</b> to a static string explaining why.
+ */
+static int
+entry_guard_set_status(entry_guard_t *e, const node_t *node,
+ time_t now, const or_options_t *options,
+ const char **reason)
+{
+ char buf[HEX_DIGEST_LEN+1];
+ int changed = 0;
+
+ *reason = NULL;
+
+ /* Do we want to mark this guard as bad? */
+ if (!node)
+ *reason = "unlisted";
+ else if (!node->is_running)
+ *reason = "down";
+ else if (options->UseBridges && (!node->ri ||
+ node->ri->purpose != ROUTER_PURPOSE_BRIDGE))
+ *reason = "not a bridge";
+ else if (options->UseBridges && !node_is_a_configured_bridge(node))
+ *reason = "not a configured bridge";
+ else if (!options->UseBridges && !node->is_possible_guard &&
+ !routerset_contains_node(options->EntryNodes,node))
+ *reason = "not recommended as a guard";
+ else if (routerset_contains_node(options->ExcludeNodes, node))
+ *reason = "excluded";
+ else if (e->path_bias_disabled)
+ *reason = "path-biased";
+
+ if (*reason && ! e->bad_since) {
+ /* Router is newly bad. */
+ base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
+ log_info(LD_CIRC, "Entry guard %s (%s) is %s: marking as unusable.",
+ e->nickname, buf, *reason);
+
+ e->bad_since = now;
+ control_event_guard(e->nickname, e->identity, "BAD");
+ changed = 1;
+ } else if (!*reason && e->bad_since) {
+ /* There's nothing wrong with the router any more. */
+ base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
+ log_info(LD_CIRC, "Entry guard %s (%s) is no longer unusable: "
+ "marking as ok.", e->nickname, buf);
+
+ e->bad_since = 0;
+ control_event_guard(e->nickname, e->identity, "GOOD");
+ changed = 1;
+ }
+ return changed;
+}
+
+/** Return true iff enough time has passed since we last tried to connect
+ * to the unreachable guard <b>e</b> that we're willing to try again. */
+static int
+entry_is_time_to_retry(entry_guard_t *e, time_t now)
+{
+ long diff;
+ if (e->last_attempted < e->unreachable_since)
+ return 1;
+ diff = now - e->unreachable_since;
+ if (diff < 6*60*60)
+ return now > (e->last_attempted + 60*60);
+ else if (diff < 3*24*60*60)
+ return now > (e->last_attempted + 4*60*60);
+ else if (diff < 7*24*60*60)
+ return now > (e->last_attempted + 18*60*60);
+ else
+ return now > (e->last_attempted + 36*60*60);
+}
+
+/** Return the node corresponding to <b>e</b>, if <b>e</b> is
+ * working well enough that we are willing to use it as an entry
+ * right now. (Else return NULL.) In particular, it must be
+ * - Listed as either up or never yet contacted;
+ * - Present in the routerlist;
+ * - Listed as 'stable' or 'fast' by the current dirserver consensus,
+ * if demanded by <b>need_uptime</b> or <b>need_capacity</b>
+ * (unless it's a configured EntryNode);
+ * - Allowed by our current ReachableORAddresses config option; and
+ * - Currently thought to be reachable by us (unless <b>assume_reachable</b>
+ * is true).
+ *
+ * If the answer is no, set *<b>msg</b> to an explanation of why.
+ */
+static INLINE const node_t *
+entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
+ int assume_reachable, const char **msg)
+{
+ const node_t *node;
+ const or_options_t *options = get_options();
+ tor_assert(msg);
+
+ if (e->path_bias_disabled) {
+ *msg = "path-biased";
+ return NULL;
+ }
+ if (e->bad_since) {
+ *msg = "bad";
+ return NULL;
+ }
+ /* no good if it's unreachable, unless assume_unreachable or can_retry. */
+ if (!assume_reachable && !e->can_retry &&
+ e->unreachable_since && !entry_is_time_to_retry(e, time(NULL))) {
+ *msg = "unreachable";
+ return NULL;
+ }
+ node = node_get_by_id(e->identity);
+ if (!node || !node_has_descriptor(node)) {
+ *msg = "no descriptor";
+ return NULL;
+ }
+ if (get_options()->UseBridges) {
+ if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) {
+ *msg = "not a bridge";
+ return NULL;
+ }
+ if (!node_is_a_configured_bridge(node)) {
+ *msg = "not a configured bridge";
+ return NULL;
+ }
+ } else { /* !get_options()->UseBridges */
+ if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
+ *msg = "not general-purpose";
+ return NULL;
+ }
+ }
+ if (routerset_contains_node(options->EntryNodes, node)) {
+ /* they asked for it, they get it */
+ need_uptime = need_capacity = 0;
+ }
+ if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
+ *msg = "not fast/stable";
+ return NULL;
+ }
+ if (!fascist_firewall_allows_node(node)) {
+ *msg = "unreachable by config";
+ return NULL;
+ }
+ return node;
+}
+
+/** Return the number of entry guards that we think are usable. */
+int
+num_live_entry_guards(void)
+{
+ int n = 0;
+ const char *msg;
+ if (! entry_guards)
+ return 0;
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
+ {
+ if (entry_is_live(entry, 0, 1, 0, &msg))
+ ++n;
+ });
+ return n;
+}
+
+/** If <b>digest</b> matches the identity of any node in the
+ * entry_guards list, return that node. Else return NULL. */
+entry_guard_t *
+entry_guard_get_by_id_digest(const char *digest)
+{
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
+ if (tor_memeq(digest, entry->identity, DIGEST_LEN))
+ return entry;
+ );
+ return NULL;
+}
+
+/** Dump a description of our list of entry guards to the log at level
+ * <b>severity</b>. */
+static void
+log_entry_guards(int severity)
+{
+ smartlist_t *elements = smartlist_new();
+ char *s;
+
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e)
+ {
+ const char *msg = NULL;
+ if (entry_is_live(e, 0, 1, 0, &msg))
+ smartlist_add_asprintf(elements, "%s [%s] (up %s)",
+ e->nickname,
+ hex_str(e->identity, DIGEST_LEN),
+ e->made_contact ? "made-contact" : "never-contacted");
+ else
+ smartlist_add_asprintf(elements, "%s [%s] (%s, %s)",
+ e->nickname,
+ hex_str(e->identity, DIGEST_LEN),
+ msg,
+ e->made_contact ? "made-contact" : "never-contacted");
+ }
+ SMARTLIST_FOREACH_END(e);
+
+ s = smartlist_join_strings(elements, ",", 0, NULL);
+ SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp));
+ smartlist_free(elements);
+ log_fn(severity,LD_CIRC,"%s",s);
+ tor_free(s);
+}
+
+/** Called when one or more guards that we would previously have used for some
+ * purpose are no longer in use because a higher-priority guard has become
+ * usable again. */
+static void
+control_event_guard_deferred(void)
+{
+ /* XXXX We don't actually have a good way to figure out _how many_ entries
+ * are live for some purpose. We need an entry_is_even_slightly_live()
+ * function for this to work right. NumEntryGuards isn't reliable: if we
+ * need guards with weird properties, we can have more than that number
+ * live.
+ **/
+#if 0
+ int n = 0;
+ const char *msg;
+ const or_options_t *options = get_options();
+ if (!entry_guards)
+ return;
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
+ {
+ if (entry_is_live(entry, 0, 1, 0, &msg)) {
+ if (n++ == options->NumEntryGuards) {
+ control_event_guard(entry->nickname, entry->identity, "DEFERRED");
+ return;
+ }
+ }
+ });
+#endif
+}
+
+/** Add a new (preferably stable and fast) router to our
+ * entry_guards list. Return a pointer to the router if we succeed,
+ * or NULL if we can't find any more suitable entries.
+ *
+ * If <b>chosen</b> is defined, use that one, and if it's not
+ * already in our entry_guards list, put it at the *beginning*.
+ * Else, put the one we pick at the end of the list. */
+static const node_t *
+add_an_entry_guard(const node_t *chosen, int reset_status, int prepend)
+{
+ const node_t *node;
+ entry_guard_t *entry;
+
+ if (chosen) {
+ node = chosen;
+ entry = entry_guard_get_by_id_digest(node->identity);
+ if (entry) {
+ if (reset_status) {
+ entry->bad_since = 0;
+ entry->can_retry = 1;
+ }
+ return NULL;
+ }
+ } else {
+ node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL);
+ if (!node)
+ return NULL;
+ }
+ entry = tor_malloc_zero(sizeof(entry_guard_t));
+ log_info(LD_CIRC, "Chose %s as new entry guard.",
+ node_describe(node));
+ strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname));
+ memcpy(entry->identity, node->identity, DIGEST_LEN);
+ /* Choose expiry time smudged over the past month. The goal here
+ * is to a) spread out when Tor clients rotate their guards, so they
+ * don't all select them on the same day, and b) avoid leaving a
+ * precise timestamp in the state file about when we first picked
+ * this guard. For details, see the Jan 2010 or-dev thread. */
+ entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
+ entry->chosen_by_version = tor_strdup(VERSION);
+ if (prepend)
+ smartlist_insert(entry_guards, 0, entry);
+ else
+ smartlist_add(entry_guards, entry);
+ control_event_guard(entry->nickname, entry->identity, "NEW");
+ control_event_guard_deferred();
+ log_entry_guards(LOG_INFO);
+ return node;
+}
+
+/** If the use of entry guards is configured, choose more entry guards
+ * until we have enough in the list. */
+static void
+pick_entry_guards(const or_options_t *options)
+{
+ int changed = 0;
+
+ tor_assert(entry_guards);
+
+ while (num_live_entry_guards() < options->NumEntryGuards) {
+ if (!add_an_entry_guard(NULL, 0, 0))
+ break;
+ changed = 1;
+ }
+ if (changed)
+ entry_guards_changed();
+}
+
+/** How long (in seconds) do we allow an entry guard to be nonfunctional,
+ * unlisted, excluded, or otherwise nonusable before we give up on it? */
+#define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60)
+
+/** Release all storage held by <b>e</b>. */
+static void
+entry_guard_free(entry_guard_t *e)
+{
+ if (!e)
+ return;
+ tor_free(e->chosen_by_version);
+ tor_free(e);
+}
+
+/** Remove any entry guard which was selected by an unknown version of Tor,
+ * or which was selected by a version of Tor that's known to select
+ * entry guards badly, or which was selected more 2 months ago. */
+/* XXXX The "obsolete guards" and "chosen long ago guards" things should
+ * probably be different functions. */
+static int
+remove_obsolete_entry_guards(time_t now)
+{
+ int changed = 0, i;
+
+ for (i = 0; i < smartlist_len(entry_guards); ++i) {
+ entry_guard_t *entry = smartlist_get(entry_guards, i);
+ const char *ver = entry->chosen_by_version;
+ const char *msg = NULL;
+ tor_version_t v;
+ int version_is_bad = 0, date_is_bad = 0;
+ if (!ver) {
+ msg = "does not say what version of Tor it was selected by";
+ version_is_bad = 1;
+ } else if (tor_version_parse(ver, &v)) {
+ msg = "does not seem to be from any recognized version of Tor";
+ version_is_bad = 1;
+ } else {
+ char *tor_ver = NULL;
+ tor_asprintf(&tor_ver, "Tor %s", ver);
+ if ((tor_version_as_new_as(tor_ver, "0.1.0.10-alpha") &&
+ !tor_version_as_new_as(tor_ver, "0.1.2.16-dev")) ||
+ (tor_version_as_new_as(tor_ver, "0.2.0.0-alpha") &&
+ !tor_version_as_new_as(tor_ver, "0.2.0.6-alpha")) ||
+ /* above are bug 440; below are bug 1217 */
+ (tor_version_as_new_as(tor_ver, "0.2.1.3-alpha") &&
+ !tor_version_as_new_as(tor_ver, "0.2.1.23")) ||
+ (tor_version_as_new_as(tor_ver, "0.2.2.0-alpha") &&
+ !tor_version_as_new_as(tor_ver, "0.2.2.7-alpha"))) {
+ msg = "was selected without regard for guard bandwidth";
+ version_is_bad = 1;
+ }
+ tor_free(tor_ver);
+ }
+ if (!version_is_bad && entry->chosen_on_date + 3600*24*60 < now) {
+ /* It's been 2 months since the date listed in our state file. */
+ msg = "was selected several months ago";
+ date_is_bad = 1;
+ }
+
+ if (version_is_bad || date_is_bad) { /* we need to drop it */
+ char dbuf[HEX_DIGEST_LEN+1];
+ tor_assert(msg);
+ base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
+ log_fn(version_is_bad ? LOG_NOTICE : LOG_INFO, LD_CIRC,
+ "Entry guard '%s' (%s) %s. (Version=%s.) Replacing it.",
+ entry->nickname, dbuf, msg, ver?escaped(ver):"none");
+ control_event_guard(entry->nickname, entry->identity, "DROPPED");
+ entry_guard_free(entry);
+ smartlist_del_keeporder(entry_guards, i--);
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ }
+ }
+
+ return changed ? 1 : 0;
+}
+
+/** Remove all entry guards that have been down or unlisted for so
+ * long that we don't think they'll come up again. Return 1 if we
+ * removed any, or 0 if we did nothing. */
+static int
+remove_dead_entry_guards(time_t now)
+{
+ char dbuf[HEX_DIGEST_LEN+1];
+ char tbuf[ISO_TIME_LEN+1];
+ int i;
+ int changed = 0;
+
+ for (i = 0; i < smartlist_len(entry_guards); ) {
+ entry_guard_t *entry = smartlist_get(entry_guards, i);
+ if (entry->bad_since &&
+ ! entry->path_bias_disabled &&
+ entry->bad_since + ENTRY_GUARD_REMOVE_AFTER < now) {
+
+ base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
+ format_local_iso_time(tbuf, entry->bad_since);
+ log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted "
+ "since %s local time; removing.",
+ entry->nickname, dbuf, tbuf);
+ control_event_guard(entry->nickname, entry->identity, "DROPPED");
+ entry_guard_free(entry);
+ smartlist_del_keeporder(entry_guards, i);
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ } else
+ ++i;
+ }
+ return changed ? 1 : 0;
+}
+
+/** A new directory or router-status has arrived; update the down/listed
+ * status of the entry guards.
+ *
+ * An entry is 'down' if the directory lists it as nonrunning.
+ * An entry is 'unlisted' if the directory doesn't include it.
+ *
+ * Don't call this on startup; only on a fresh download. Otherwise we'll
+ * think that things are unlisted.
+ */
+void
+entry_guards_compute_status(const or_options_t *options, time_t now)
+{
+ int changed = 0;
+ digestmap_t *reasons;
+
+ if (! entry_guards)
+ return;
+
+ if (options->EntryNodes) /* reshuffle the entry guard list if needed */
+ entry_nodes_should_be_added();
+
+ reasons = digestmap_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry)
+ {
+ const node_t *r = node_get_by_id(entry->identity);
+ const char *reason = NULL;
+ if (entry_guard_set_status(entry, r, now, options, &reason))
+ changed = 1;
+
+ if (entry->bad_since)
+ tor_assert(reason);
+ if (reason)
+ digestmap_set(reasons, entry->identity, (char*)reason);
+ }
+ SMARTLIST_FOREACH_END(entry);
+
+ if (remove_dead_entry_guards(now))
+ changed = 1;
+ if (remove_obsolete_entry_guards(now))
+ changed = 1;
+
+ if (changed) {
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
+ const char *reason = digestmap_get(reasons, entry->identity);
+ const char *live_msg = "";
+ const node_t *r = entry_is_live(entry, 0, 1, 0, &live_msg);
+ log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.",
+ entry->nickname,
+ hex_str(entry->identity, DIGEST_LEN),
+ entry->unreachable_since ? "unreachable" : "reachable",
+ entry->bad_since ? "unusable" : "usable",
+ reason ? ", ": "",
+ reason ? reason : "",
+ r ? "live" : "not live / ",
+ r ? "" : live_msg);
+ } SMARTLIST_FOREACH_END(entry);
+ log_info(LD_CIRC, " (%d/%d entry guards are usable/new)",
+ num_live_entry_guards(), smartlist_len(entry_guards));
+ log_entry_guards(LOG_INFO);
+ entry_guards_changed();
+ }
+
+ digestmap_free(reasons, NULL);
+}
+
+/** Called when a connection to an OR with the identity digest <b>digest</b>
+ * is established (<b>succeeded</b>==1) or has failed (<b>succeeded</b>==0).
+ * If the OR is an entry, change that entry's up/down status.
+ * Return 0 normally, or -1 if we want to tear down the new connection.
+ *
+ * If <b>mark_relay_status</b>, also call router_set_status() on this
+ * relay.
+ *
+ * XXX024 change succeeded and mark_relay_status into 'int flags'.
+ */
+int
+entry_guard_register_connect_status(const char *digest, int succeeded,
+ int mark_relay_status, time_t now)
+{
+ int changed = 0;
+ int refuse_conn = 0;
+ int first_contact = 0;
+ entry_guard_t *entry = NULL;
+ int idx = -1;
+ char buf[HEX_DIGEST_LEN+1];
+
+ if (! entry_guards)
+ return 0;
+
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ tor_assert(e);
+ if (tor_memeq(e->identity, digest, DIGEST_LEN)) {
+ entry = e;
+ idx = e_sl_idx;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(e);
+
+ if (!entry)
+ return 0;
+
+ base16_encode(buf, sizeof(buf), entry->identity, DIGEST_LEN);
+
+ if (succeeded) {
+ if (entry->unreachable_since) {
+ log_info(LD_CIRC, "Entry guard '%s' (%s) is now reachable again. Good.",
+ entry->nickname, buf);
+ entry->can_retry = 0;
+ entry->unreachable_since = 0;
+ entry->last_attempted = now;
+ control_event_guard(entry->nickname, entry->identity, "UP");
+ changed = 1;
+ }
+ if (!entry->made_contact) {
+ entry->made_contact = 1;
+ first_contact = changed = 1;
+ }
+ } else { /* ! succeeded */
+ if (!entry->made_contact) {
+ /* We've never connected to this one. */
+ log_info(LD_CIRC,
+ "Connection to never-contacted entry guard '%s' (%s) failed. "
+ "Removing from the list. %d/%d entry guards usable/new.",
+ entry->nickname, buf,
+ num_live_entry_guards()-1, smartlist_len(entry_guards)-1);
+ control_event_guard(entry->nickname, entry->identity, "DROPPED");
+ entry_guard_free(entry);
+ smartlist_del_keeporder(entry_guards, idx);
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ } else if (!entry->unreachable_since) {
+ log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). "
+ "Marking as unreachable.", entry->nickname, buf);
+ entry->unreachable_since = entry->last_attempted = now;
+ control_event_guard(entry->nickname, entry->identity, "DOWN");
+ changed = 1;
+ entry->can_retry = 0; /* We gave it an early chance; no good. */
+ } else {
+ char tbuf[ISO_TIME_LEN+1];
+ format_iso_time(tbuf, entry->unreachable_since);
+ log_debug(LD_CIRC, "Failed to connect to unreachable entry guard "
+ "'%s' (%s). It has been unreachable since %s.",
+ entry->nickname, buf, tbuf);
+ entry->last_attempted = now;
+ entry->can_retry = 0; /* We gave it an early chance; no good. */
+ }
+ }
+
+ /* if the caller asked us to, also update the is_running flags for this
+ * relay */
+ if (mark_relay_status)
+ router_set_status(digest, succeeded);
+
+ if (first_contact) {
+ /* We've just added a new long-term entry guard. Perhaps the network just
+ * came back? We should give our earlier entries another try too,
+ * and close this connection so we don't use it before we've given
+ * the others a shot. */
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ if (e == entry)
+ break;
+ if (e->made_contact) {
+ const char *msg;
+ const node_t *r = entry_is_live(e, 0, 1, 1, &msg);
+ if (r && e->unreachable_since) {
+ refuse_conn = 1;
+ e->can_retry = 1;
+ }
+ }
+ } SMARTLIST_FOREACH_END(e);
+ if (refuse_conn) {
+ log_info(LD_CIRC,
+ "Connected to new entry guard '%s' (%s). Marking earlier "
+ "entry guards up. %d/%d entry guards usable/new.",
+ entry->nickname, buf,
+ num_live_entry_guards(), smartlist_len(entry_guards));
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ }
+ }
+
+ if (changed)
+ entry_guards_changed();
+ return refuse_conn ? -1 : 0;
+}
+
+/** When we try to choose an entry guard, should we parse and add
+ * config's EntryNodes first? */
+static int should_add_entry_nodes = 0;
+
+/** Called when the value of EntryNodes changes in our configuration. */
+void
+entry_nodes_should_be_added(void)
+{
+ log_info(LD_CIRC, "EntryNodes config option set. Putting configured "
+ "relays at the front of the entry guard list.");
+ should_add_entry_nodes = 1;
+}
+
+/** Adjust the entry guards list so that it only contains entries from
+ * EntryNodes, adding new entries from EntryNodes to the list as needed. */
+static void
+entry_guards_set_from_config(const or_options_t *options)
+{
+ smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps;
+ smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list;
+ tor_assert(entry_guards);
+
+ should_add_entry_nodes = 0;
+
+ if (!options->EntryNodes) {
+ /* It's possible that a controller set EntryNodes, thus making
+ * should_add_entry_nodes set, then cleared it again, all before the
+ * call to choose_random_entry() that triggered us. If so, just return.
+ */
+ return;
+ }
+
+ {
+ char *string = routerset_to_string(options->EntryNodes);
+ log_info(LD_CIRC,"Adding configured EntryNodes '%s'.", string);
+ tor_free(string);
+ }
+
+ entry_nodes = smartlist_new();
+ worse_entry_nodes = smartlist_new();
+ entry_fps = smartlist_new();
+ old_entry_guards_on_list = smartlist_new();
+ old_entry_guards_not_on_list = smartlist_new();
+
+ /* Split entry guards into those on the list and those not. */
+
+ routerset_get_all_nodes(entry_nodes, options->EntryNodes,
+ options->ExcludeNodes, 0);
+ SMARTLIST_FOREACH(entry_nodes, const node_t *,node,
+ smartlist_add(entry_fps, (void*)node->identity));
+
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, {
+ if (smartlist_digest_isin(entry_fps, e->identity))
+ smartlist_add(old_entry_guards_on_list, e);
+ else
+ smartlist_add(old_entry_guards_not_on_list, e);
+ });
+
+ /* Remove all currently configured guard nodes, excluded nodes, unreachable
+ * nodes, or non-Guard nodes from entry_nodes. */
+ SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
+ if (entry_guard_get_by_id_digest(node->identity)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (routerset_contains_node(options->ExcludeNodes, node)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (!fascist_firewall_allows_node(node)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (! node->is_possible_guard) {
+ smartlist_add(worse_entry_nodes, (node_t*)node);
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ }
+ } SMARTLIST_FOREACH_END(node);
+
+ /* Now build the new entry_guards list. */
+ smartlist_clear(entry_guards);
+ /* First, the previously configured guards that are in EntryNodes. */
+ smartlist_add_all(entry_guards, old_entry_guards_on_list);
+ /* Next, scramble the rest of EntryNodes, putting the guards first. */
+ smartlist_shuffle(entry_nodes);
+ smartlist_shuffle(worse_entry_nodes);
+ smartlist_add_all(entry_nodes, worse_entry_nodes);
+
+ /* Next, the rest of EntryNodes */
+ SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
+ add_an_entry_guard(node, 0, 0);
+ if (smartlist_len(entry_guards) > options->NumEntryGuards * 10)
+ break;
+ } SMARTLIST_FOREACH_END(node);
+ log_notice(LD_GENERAL, "%d entries in guards", smartlist_len(entry_guards));
+ /* Finally, free the remaining previously configured guards that are not in
+ * EntryNodes. */
+ SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
+ entry_guard_free(e));
+
+ smartlist_free(entry_nodes);
+ smartlist_free(worse_entry_nodes);
+ smartlist_free(entry_fps);
+ smartlist_free(old_entry_guards_on_list);
+ smartlist_free(old_entry_guards_not_on_list);
+ entry_guards_changed();
+}
+
+/** Return 0 if we're fine adding arbitrary routers out of the
+ * directory to our entry guard list, or return 1 if we have a
+ * list already and we must stick to it.
+ */
+int
+entry_list_is_constrained(const or_options_t *options)
+{
+ if (options->EntryNodes)
+ return 1;
+ if (options->UseBridges)
+ return 1;
+ return 0;
+}
+
+/** Pick a live (up and listed) entry guard from entry_guards. If
+ * <b>state</b> is non-NULL, this is for a specific circuit --
+ * make sure not to pick this circuit's exit or any node in the
+ * exit's family. If <b>state</b> is NULL, we're looking for a random
+ * guard (likely a bridge). */
+const node_t *
+choose_random_entry(cpath_build_state_t *state)
+{
+ const or_options_t *options = get_options();
+ smartlist_t *live_entry_guards = smartlist_new();
+ smartlist_t *exit_family = smartlist_new();
+ const node_t *chosen_exit =
+ state?build_state_get_exit_node(state) : NULL;
+ const node_t *node = NULL;
+ int need_uptime = state ? state->need_uptime : 0;
+ int need_capacity = state ? state->need_capacity : 0;
+ int preferred_min, consider_exit_family = 0;
+
+ if (chosen_exit) {
+ nodelist_add_node_and_family(exit_family, chosen_exit);
+ consider_exit_family = 1;
+ }
+
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+
+ if (should_add_entry_nodes)
+ entry_guards_set_from_config(options);
+
+ if (!entry_list_is_constrained(options) &&
+ smartlist_len(entry_guards) < options->NumEntryGuards)
+ pick_entry_guards(options);
+
+ retry:
+ smartlist_clear(live_entry_guards);
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
+ const char *msg;
+ node = entry_is_live(entry, need_uptime, need_capacity, 0, &msg);
+ if (!node)
+ continue; /* down, no point */
+ if (node == chosen_exit)
+ continue; /* don't pick the same node for entry and exit */
+ if (consider_exit_family && smartlist_isin(exit_family, node))
+ continue; /* avoid relays that are family members of our exit */
+#if 0 /* since EntryNodes is always strict now, this clause is moot */
+ if (options->EntryNodes &&
+ !routerset_contains_node(options->EntryNodes, node)) {
+ /* We've come to the end of our preferred entry nodes. */
+ if (smartlist_len(live_entry_guards))
+ goto choose_and_finish; /* only choose from the ones we like */
+ if (options->StrictNodes) {
+ /* in theory this case should never happen, since
+ * entry_guards_set_from_config() drops unwanted relays */
+ tor_fragile_assert();
+ } else {
+ log_info(LD_CIRC,
+ "No relays from EntryNodes available. Using others.");
+ }
+ }
+#endif
+ smartlist_add(live_entry_guards, (void*)node);
+ if (!entry->made_contact) {
+ /* Always start with the first not-yet-contacted entry
+ * guard. Otherwise we might add several new ones, pick
+ * the second new one, and now we've expanded our entry
+ * guard list without needing to. */
+ goto choose_and_finish;
+ }
+ if (smartlist_len(live_entry_guards) >= options->NumEntryGuards)
+ goto choose_and_finish; /* we have enough */
+ } SMARTLIST_FOREACH_END(entry);
+
+ if (entry_list_is_constrained(options)) {
+ /* If we prefer the entry nodes we've got, and we have at least
+ * one choice, that's great. Use it. */
+ preferred_min = 1;
+ } else {
+ /* Try to have at least 2 choices available. This way we don't
+ * get stuck with a single live-but-crummy entry and just keep
+ * using him.
+ * (We might get 2 live-but-crummy entry guards, but so be it.) */
+ preferred_min = 2;
+ }
+
+ if (smartlist_len(live_entry_guards) < preferred_min) {
+ if (!entry_list_is_constrained(options)) {
+ /* still no? try adding a new entry then */
+ /* XXX if guard doesn't imply fast and stable, then we need
+ * to tell add_an_entry_guard below what we want, or it might
+ * be a long time til we get it. -RD */
+ node = add_an_entry_guard(NULL, 0, 0);
+ if (node) {
+ entry_guards_changed();
+ /* XXX we start over here in case the new node we added shares
+ * a family with our exit node. There's a chance that we'll just
+ * load up on entry guards here, if the network we're using is
+ * one big family. Perhaps we should teach add_an_entry_guard()
+ * to understand nodes-to-avoid-if-possible? -RD */
+ goto retry;
+ }
+ }
+ if (!node && need_uptime) {
+ need_uptime = 0; /* try without that requirement */
+ goto retry;
+ }
+ if (!node && need_capacity) {
+ /* still no? last attempt, try without requiring capacity */
+ need_capacity = 0;
+ goto retry;
+ }
+#if 0
+ /* Removing this retry logic: if we only allow one exit, and it is in the
+ same family as all our entries, then we are just plain not going to win
+ here. */
+ if (!node && entry_list_is_constrained(options) && consider_exit_family) {
+ /* still no? if we're using bridges or have strictentrynodes
+ * set, and our chosen exit is in the same family as all our
+ * bridges/entry guards, then be flexible about families. */
+ consider_exit_family = 0;
+ goto retry;
+ }
+#endif
+ /* live_entry_guards may be empty below. Oh well, we tried. */
+ }
+
+ choose_and_finish:
+ if (entry_list_is_constrained(options)) {
+ /* We need to weight by bandwidth, because our bridges or entryguards
+ * were not already selected proportional to their bandwidth. */
+ node = node_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD);
+ } else {
+ /* We choose uniformly at random here, because choose_good_entry_server()
+ * already weights its choices by bandwidth, so we don't want to
+ * *double*-weight our guard selection. */
+ node = smartlist_choose(live_entry_guards);
+ }
+ smartlist_free(live_entry_guards);
+ smartlist_free(exit_family);
+ return node;
+}
+
+/** Parse <b>state</b> and learn about the entry guards it describes.
+ * If <b>set</b> is true, and there are no errors, replace the global
+ * entry_list with what we find.
+ * On success, return 0. On failure, alloc into *<b>msg</b> a string
+ * describing the error, and return -1.
+ */
+int
+entry_guards_parse_state(or_state_t *state, int set, char **msg)
+{
+ entry_guard_t *node = NULL;
+ smartlist_t *new_entry_guards = smartlist_new();
+ config_line_t *line;
+ time_t now = time(NULL);
+ const char *state_version = state->TorVersion;
+ digestmap_t *added_by = digestmap_new();
+
+ *msg = NULL;
+ for (line = state->EntryGuards; line; line = line->next) {
+ if (!strcasecmp(line->key, "EntryGuard")) {
+ smartlist_t *args = smartlist_new();
+ node = tor_malloc_zero(sizeof(entry_guard_t));
+ /* all entry guards on disk have been contacted */
+ node->made_contact = 1;
+ smartlist_add(new_entry_guards, node);
+ smartlist_split_string(args, line->value, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ if (smartlist_len(args)<2) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "Too few arguments to EntryGuard");
+ } else if (!is_legal_nickname(smartlist_get(args,0))) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "Bad nickname for EntryGuard");
+ } else {
+ strlcpy(node->nickname, smartlist_get(args,0), MAX_NICKNAME_LEN+1);
+ if (base16_decode(node->identity, DIGEST_LEN, smartlist_get(args,1),
+ strlen(smartlist_get(args,1)))<0) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "Bad hex digest for EntryGuard");
+ }
+ }
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ if (*msg)
+ break;
+ } else if (!strcasecmp(line->key, "EntryGuardDownSince") ||
+ !strcasecmp(line->key, "EntryGuardUnlistedSince")) {
+ time_t when;
+ time_t last_try = 0;
+ if (!node) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "EntryGuardDownSince/UnlistedSince without EntryGuard");
+ break;
+ }
+ if (parse_iso_time(line->value, &when)<0) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "Bad time in EntryGuardDownSince/UnlistedSince");
+ break;
+ }
+ if (when > now) {
+ /* It's a bad idea to believe info in the future: you can wind
+ * up with timeouts that aren't allowed to happen for years. */
+ continue;
+ }
+ if (strlen(line->value) >= ISO_TIME_LEN+ISO_TIME_LEN+1) {
+ /* ignore failure */
+ (void) parse_iso_time(line->value+ISO_TIME_LEN+1, &last_try);
+ }
+ if (!strcasecmp(line->key, "EntryGuardDownSince")) {
+ node->unreachable_since = when;
+ node->last_attempted = last_try;
+ } else {
+ node->bad_since = when;
+ }
+ } else if (!strcasecmp(line->key, "EntryGuardAddedBy")) {
+ char d[DIGEST_LEN];
+ /* format is digest version date */
+ if (strlen(line->value) < HEX_DIGEST_LEN+1+1+1+ISO_TIME_LEN) {
+ log_warn(LD_BUG, "EntryGuardAddedBy line is not long enough.");
+ continue;
+ }
+ if (base16_decode(d, sizeof(d), line->value, HEX_DIGEST_LEN)<0 ||
+ line->value[HEX_DIGEST_LEN] != ' ') {
+ log_warn(LD_BUG, "EntryGuardAddedBy line %s does not begin with "
+ "hex digest", escaped(line->value));
+ continue;
+ }
+ digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1));
+ } else if (!strcasecmp(line->key, "EntryGuardPathBias")) {
+ const or_options_t *options = get_options();
+ unsigned hop_cnt, success_cnt;
+
+ if (!node) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "EntryGuardPathBias without EntryGuard");
+ break;
+ }
+
+ if (tor_sscanf(line->value, "%u %u", &success_cnt, &hop_cnt) != 2) {
+ log_warn(LD_GENERAL, "Unable to parse guard path bias info: "
+ "Misformated EntryGuardPathBias %s", escaped(line->value));
+ continue;
+ }
+
+ node->first_hops = hop_cnt;
+ node->circuit_successes = success_cnt;
+ log_info(LD_GENERAL, "Read %u/%u path bias for node %s",
+ node->circuit_successes, node->first_hops, node->nickname);
+ /* Note: We rely on the < comparison here to allow us to set a 0
+ * rate and disable the feature entirely. If refactoring, don't
+ * change to <= */
+ if (node->circuit_successes/((double)node->first_hops)
+ < pathbias_get_disable_rate(options)) {
+ node->path_bias_disabled = 1;
+ log_info(LD_GENERAL,
+ "Path bias is too high (%u/%u); disabling node %s",
+ node->circuit_successes, node->first_hops, node->nickname);
+ }
+
+ } else {
+ log_warn(LD_BUG, "Unexpected key %s", line->key);
+ }
+ }
+
+ SMARTLIST_FOREACH_BEGIN(new_entry_guards, entry_guard_t *, e) {
+ char *sp;
+ char *val = digestmap_get(added_by, e->identity);
+ if (val && (sp = strchr(val, ' '))) {
+ time_t when;
+ *sp++ = '\0';
+ if (parse_iso_time(sp, &when)<0) {
+ log_warn(LD_BUG, "Can't read time %s in EntryGuardAddedBy", sp);
+ } else {
+ e->chosen_by_version = tor_strdup(val);
+ e->chosen_on_date = when;
+ }
+ } else {
+ if (state_version) {
+ e->chosen_by_version = tor_strdup(state_version);
+ e->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
+ }
+ }
+ if (e->path_bias_disabled && !e->bad_since)
+ e->bad_since = time(NULL);
+ }
+ SMARTLIST_FOREACH_END(e);
+
+ if (*msg || !set) {
+ SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e,
+ entry_guard_free(e));
+ smartlist_free(new_entry_guards);
+ } else { /* !err && set */
+ if (entry_guards) {
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
+ entry_guard_free(e));
+ smartlist_free(entry_guards);
+ }
+ entry_guards = new_entry_guards;
+ entry_guards_dirty = 0;
+ /* XXX024 hand new_entry_guards to this func, and move it up a
+ * few lines, so we don't have to re-dirty it */
+ if (remove_obsolete_entry_guards(now))
+ entry_guards_dirty = 1;
+ }
+ digestmap_free(added_by, tor_free_);
+ return *msg ? -1 : 0;
+}
+
+/** Our list of entry guards has changed, or some element of one
+ * of our entry guards has changed. Write the changes to disk within
+ * the next few minutes.
+ */
+void
+entry_guards_changed(void)
+{
+ time_t when;
+ entry_guards_dirty = 1;
+
+ /* or_state_save() will call entry_guards_update_state(). */
+ when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600;
+ or_state_mark_dirty(get_or_state(), when);
+}
+
+/** If the entry guard info has not changed, do nothing and return.
+ * Otherwise, free the EntryGuards piece of <b>state</b> and create
+ * a new one out of the global entry_guards list, and then mark
+ * <b>state</b> dirty so it will get saved to disk.
+ */
+void
+entry_guards_update_state(or_state_t *state)
+{
+ config_line_t **next, *line;
+ if (! entry_guards_dirty)
+ return;
+
+ config_free_lines(state->EntryGuards);
+ next = &state->EntryGuards;
+ *next = NULL;
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ char dbuf[HEX_DIGEST_LEN+1];
+ if (!e->made_contact)
+ continue; /* don't write this one to disk */
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuard");
+ base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN);
+ tor_asprintf(&line->value, "%s %s", e->nickname, dbuf);
+ next = &(line->next);
+ if (e->unreachable_since) {
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardDownSince");
+ line->value = tor_malloc(ISO_TIME_LEN+1+ISO_TIME_LEN+1);
+ format_iso_time(line->value, e->unreachable_since);
+ if (e->last_attempted) {
+ line->value[ISO_TIME_LEN] = ' ';
+ format_iso_time(line->value+ISO_TIME_LEN+1, e->last_attempted);
+ }
+ next = &(line->next);
+ }
+ if (e->bad_since) {
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardUnlistedSince");
+ line->value = tor_malloc(ISO_TIME_LEN+1);
+ format_iso_time(line->value, e->bad_since);
+ next = &(line->next);
+ }
+ if (e->chosen_on_date && e->chosen_by_version &&
+ !strchr(e->chosen_by_version, ' ')) {
+ char d[HEX_DIGEST_LEN+1];
+ char t[ISO_TIME_LEN+1];
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardAddedBy");
+ base16_encode(d, sizeof(d), e->identity, DIGEST_LEN);
+ format_iso_time(t, e->chosen_on_date);
+ tor_asprintf(&line->value, "%s %s %s",
+ d, e->chosen_by_version, t);
+ next = &(line->next);
+ }
+ if (e->first_hops) {
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardPathBias");
+ tor_asprintf(&line->value, "%u %u",
+ e->circuit_successes, e->first_hops);
+ next = &(line->next);
+ }
+
+ } SMARTLIST_FOREACH_END(e);
+ if (!get_options()->AvoidDiskWrites)
+ or_state_mark_dirty(get_or_state(), 0);
+ entry_guards_dirty = 0;
+}
+
+/** If <b>question</b> is the string "entry-guards", then dump
+ * to *<b>answer</b> a newly allocated string describing all of
+ * the nodes in the global entry_guards list. See control-spec.txt
+ * for details.
+ * For backward compatibility, we also handle the string "helper-nodes".
+ * */
+int
+getinfo_helper_entry_guards(control_connection_t *conn,
+ const char *question, char **answer,
+ const char **errmsg)
+{
+ (void) conn;
+ (void) errmsg;
+
+ if (!strcmp(question,"entry-guards") ||
+ !strcmp(question,"helper-nodes")) {
+ smartlist_t *sl = smartlist_new();
+ char tbuf[ISO_TIME_LEN+1];
+ char nbuf[MAX_VERBOSE_NICKNAME_LEN+1];
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ const char *status = NULL;
+ time_t when = 0;
+ const node_t *node;
+
+ if (!e->made_contact) {
+ status = "never-connected";
+ } else if (e->bad_since) {
+ when = e->bad_since;
+ status = "unusable";
+ } else {
+ status = "up";
+ }
+
+ node = node_get_by_id(e->identity);
+ if (node) {
+ node_get_verbose_nickname(node, nbuf);
+ } else {
+ nbuf[0] = '$';
+ base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN);
+ /* e->nickname field is not very reliable if we don't know about
+ * this router any longer; don't include it. */
+ }
+
+ if (when) {
+ format_iso_time(tbuf, when);
+ smartlist_add_asprintf(sl, "%s %s %s\n", nbuf, status, tbuf);
+ } else {
+ smartlist_add_asprintf(sl, "%s %s\n", nbuf, status);
+ }
+ } SMARTLIST_FOREACH_END(e);
+ *answer = smartlist_join_strings(sl, "", 0, NULL);
+ SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
+ smartlist_free(sl);
+ }
+ return 0;
+}
+
+/** A list of configured bridges. Whenever we actually get a descriptor
+ * for one, we add it as an entry guard. Note that the order of bridges
+ * in this list does not necessarily correspond to the order of bridges
+ * in the torrc. */
+static smartlist_t *bridge_list = NULL;
+
+/** Mark every entry of the bridge list to be removed on our next call to
+ * sweep_bridge_list unless it has first been un-marked. */
+void
+mark_bridge_list(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+ SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b,
+ b->marked_for_removal = 1);
+}
+
+/** Remove every entry of the bridge list that was marked with
+ * mark_bridge_list if it has not subsequently been un-marked. */
+void
+sweep_bridge_list(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
+ if (b->marked_for_removal) {
+ SMARTLIST_DEL_CURRENT(bridge_list, b);
+ bridge_free(b);
+ }
+ } SMARTLIST_FOREACH_END(b);
+}
+
+/** Initialize the bridge list to empty, creating it if needed. */
+static void
+clear_bridge_list(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+ SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b));
+ smartlist_clear(bridge_list);
+}
+
+/** Free the bridge <b>bridge</b>. */
+static void
+bridge_free(bridge_info_t *bridge)
+{
+ if (!bridge)
+ return;
+
+ tor_free(bridge->transport_name);
+ tor_free(bridge);
+}
+
+/** If we have a bridge configured whose digest matches <b>digest</b>, or a
+ * bridge with no known digest whose address matches any of the
+ * tor_addr_port_t's in <b>orports</b>, return that bridge. Else return
+ * NULL. */
+static bridge_info_t *
+get_configured_bridge_by_orports_digest(const char *digest,
+ const smartlist_t *orports)
+{
+ if (!bridge_list)
+ return NULL;
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
+ {
+ if (tor_digest_is_zero(bridge->identity)) {
+ SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, ap)
+ {
+ if (tor_addr_compare(&bridge->addr, &ap->addr, CMP_EXACT) == 0 &&
+ bridge->port == ap->port)
+ return bridge;
+ }
+ SMARTLIST_FOREACH_END(ap);
+ }
+ if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN))
+ return bridge;
+ }
+ SMARTLIST_FOREACH_END(bridge);
+ return NULL;
+}
+
+/** If we have a bridge configured whose digest matches <b>digest</b>, or a
+ * bridge with no known digest whose address matches <b>addr</b>:<b>/port</b>,
+ * return that bridge. Else return NULL. */
+static bridge_info_t *
+get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr,
+ uint16_t port,
+ const char *digest)
+{
+ if (!bridge_list)
+ return NULL;
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
+ {
+ if (tor_digest_is_zero(bridge->identity) &&
+ !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) &&
+ bridge->port == port)
+ return bridge;
+ if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN))
+ return bridge;
+ }
+ SMARTLIST_FOREACH_END(bridge);
+ return NULL;
+}
+
+/** Wrapper around get_configured_bridge_by_addr_port_digest() to look
+ * it up via router descriptor <b>ri</b>. */
+static bridge_info_t *
+get_configured_bridge_by_routerinfo(const routerinfo_t *ri)
+{
+ bridge_info_t *bi = NULL;
+ smartlist_t *orports = router_get_all_orports(ri);
+ bi = get_configured_bridge_by_orports_digest(ri->cache_info.identity_digest,
+ orports);
+ SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p));
+ smartlist_free(orports);
+ return bi;
+}
+
+/** Return 1 if <b>ri</b> is one of our known bridges, else 0. */
+int
+routerinfo_is_a_configured_bridge(const routerinfo_t *ri)
+{
+ return get_configured_bridge_by_routerinfo(ri) ? 1 : 0;
+}
+
+/** Return 1 if <b>node</b> is one of our configured bridges, else 0. */
+int
+node_is_a_configured_bridge(const node_t *node)
+{
+ int retval = 0;
+ smartlist_t *orports = node_get_all_orports(node);
+ retval = get_configured_bridge_by_orports_digest(node->identity,
+ orports) != NULL;
+ SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p));
+ smartlist_free(orports);
+ return retval;
+}
+
+/** We made a connection to a router at <b>addr</b>:<b>port</b>
+ * without knowing its digest. Its digest turned out to be <b>digest</b>.
+ * If it was a bridge, and we still don't know its digest, record it.
+ */
+void
+learned_router_identity(const tor_addr_t *addr, uint16_t port,
+ const char *digest)
+{
+ bridge_info_t *bridge =
+ get_configured_bridge_by_addr_port_digest(addr, port, digest);
+ if (bridge && tor_digest_is_zero(bridge->identity)) {
+ memcpy(bridge->identity, digest, DIGEST_LEN);
+ log_notice(LD_DIR, "Learned fingerprint %s for bridge %s",
+ hex_str(digest, DIGEST_LEN), fmt_addrport(addr, port));
+ }
+}
+
+/** Return true if <b>bridge</b> has the same identity digest as
+ * <b>digest</b>. If <b>digest</b> is NULL, it matches
+ * bridges with unspecified identity digests. */
+static int
+bridge_has_digest(const bridge_info_t *bridge, const char *digest)
+{
+ if (digest)
+ return tor_memeq(digest, bridge->identity, DIGEST_LEN);
+ else
+ return tor_digest_is_zero(bridge->identity);
+}
+
+/** We are about to add a new bridge at <b>addr</b>:<b>port</b>, with optional
+ * <b>digest</b> and <b>transport_name</b>. Mark for removal any previously
+ * existing bridge with the same address and port, and warn the user as
+ * appropriate.
+ */
+static void
+bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
+ const char *digest, const char *transport_name)
+{
+ /* Iterate the already-registered bridge list:
+
+ If you find a bridge with the same adress and port, mark it for
+ removal. It doesn't make sense to have two active bridges with
+ the same IP:PORT. If the bridge in question has a different
+ digest or transport than <b>digest</b>/<b>transport_name</b>,
+ it's probably a misconfiguration and we should warn the user.
+ */
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) {
+ if (bridge->marked_for_removal)
+ continue;
+
+ if (tor_addr_eq(&bridge->addr, addr) && (bridge->port == port)) {
+
+ bridge->marked_for_removal = 1;
+
+ if (!bridge_has_digest(bridge, digest) ||
+ strcmp_opt(bridge->transport_name, transport_name)) {
+ /* warn the user */
+ char *bridge_description_new, *bridge_description_old;
+ tor_asprintf(&bridge_description_new, "%s:%s:%s",
+ fmt_addrport(addr, port),
+ digest ? hex_str(digest, DIGEST_LEN) : "",
+ transport_name ? transport_name : "");
+ tor_asprintf(&bridge_description_old, "%s:%s:%s",
+ fmt_addrport(&bridge->addr, bridge->port),
+ tor_digest_is_zero(bridge->identity) ?
+ "" : hex_str(bridge->identity,DIGEST_LEN),
+ bridge->transport_name ? bridge->transport_name : "");
+
+ log_warn(LD_GENERAL,"Tried to add bridge '%s', but we found a conflict"
+ " with the already registered bridge '%s'. We will discard"
+ " the old bridge and keep '%s'. If this is not what you"
+ " wanted, please change your configuration file accordingly.",
+ bridge_description_new, bridge_description_old,
+ bridge_description_new);
+
+ tor_free(bridge_description_new);
+ tor_free(bridge_description_old);
+ }
+ }
+ } SMARTLIST_FOREACH_END(bridge);
+}
+
+/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
+ * is set, it tells us the identity key too. If we already had the
+ * bridge in our list, unmark it, and don't actually add anything new.
+ * If <b>transport_name</b> is non-NULL - the bridge is associated with a
+ * pluggable transport - we assign the transport to the bridge. */
+void
+bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *digest, const char *transport_name)
+{
+ bridge_info_t *b;
+
+ bridge_resolve_conflicts(addr, port, digest, transport_name);
+
+ b = tor_malloc_zero(sizeof(bridge_info_t));
+ tor_addr_copy(&b->addr, addr);
+ b->port = port;
+ if (digest)
+ memcpy(b->identity, digest, DIGEST_LEN);
+ if (transport_name)
+ b->transport_name = tor_strdup(transport_name);
+ b->fetch_status.schedule = DL_SCHED_BRIDGE;
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+
+ smartlist_add(bridge_list, b);
+}
+
+/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */
+static int
+routerset_contains_bridge(const routerset_t *routerset,
+ const bridge_info_t *bridge)
+{
+ int result;
+ extend_info_t *extinfo;
+ tor_assert(bridge);
+ if (!routerset)
+ return 0;
+
+ extinfo = extend_info_new(
+ NULL, bridge->identity, NULL, &bridge->addr, bridge->port);
+ result = routerset_contains_extendinfo(routerset, extinfo);
+ extend_info_free(extinfo);
+ return result;
+}
+
+/** If <b>digest</b> is one of our known bridges, return it. */
+static bridge_info_t *
+find_bridge_by_digest(const char *digest)
+{
+ SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge,
+ {
+ if (tor_memeq(bridge->identity, digest, DIGEST_LEN))
+ return bridge;
+ });
+ return NULL;
+}
+
+/* DOCDOC find_transport_name_by_bridge_addrport */
+const char *
+find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
+{
+ if (!bridge_list)
+ return NULL;
+
+ SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
+ if (tor_addr_eq(&bridge->addr, addr) &&
+ (bridge->port == port))
+ return bridge->transport_name;
+ } SMARTLIST_FOREACH_END(bridge);
+
+ return NULL;
+}
+
+/** If <b>addr</b> and <b>port</b> match the address and port of a
+ * bridge of ours that uses pluggable transports, place its transport
+ * in <b>transport</b>.
+ *
+ * Return 0 on success (found a transport, or found a bridge with no
+ * transport, or found no bridge); return -1 if we should be using a
+ * transport, but the transport could not be found.
+ */
+int
+find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
+ const transport_t **transport)
+{
+ *transport = NULL;
+ if (!bridge_list)
+ return 0;
+
+ SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
+ if (tor_addr_eq(&bridge->addr, addr) &&
+ (bridge->port == port)) { /* bridge matched */
+ if (bridge->transport_name) { /* it also uses pluggable transports */
+ *transport = transport_get_by_name(bridge->transport_name);
+ if (*transport == NULL) { /* it uses pluggable transports, but
+ the transport could not be found! */
+ return -1;
+ }
+ return 0;
+ } else { /* bridge matched, but it doesn't use transports. */
+ break;
+ }
+ }
+ } SMARTLIST_FOREACH_END(bridge);
+
+ *transport = NULL;
+ return 0;
+}
+
+/** We need to ask <b>bridge</b> for its server descriptor. */
+static void
+launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
+{
+ char *address;
+ const or_options_t *options = get_options();
+
+ if (connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR, &bridge->addr, bridge->port,
+ DIR_PURPOSE_FETCH_SERVERDESC))
+ return; /* it's already on the way */
+
+ if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
+ download_status_mark_impossible(&bridge->fetch_status);
+ log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
+ safe_str_client(fmt_and_decorate_addr(&bridge->addr)));
+ return;
+ }
+
+ address = tor_dup_addr(&bridge->addr);
+
+ directory_initiate_command(address, &bridge->addr,
+ bridge->port, 0/*no dirport*/,
+ bridge->identity,
+ DIR_PURPOSE_FETCH_SERVERDESC,
+ ROUTER_PURPOSE_BRIDGE,
+ DIRIND_ONEHOP, "authority.z", NULL, 0, 0);
+ tor_free(address);
+}
+
+/** Fetching the bridge descriptor from the bridge authority returned a
+ * "not found". Fall back to trying a direct fetch. */
+void
+retry_bridge_descriptor_fetch_directly(const char *digest)
+{
+ bridge_info_t *bridge = find_bridge_by_digest(digest);
+ if (!bridge)
+ return; /* not found? oh well. */
+
+ launch_direct_bridge_descriptor_fetch(bridge);
+}
+
+/** For each bridge in our list for which we don't currently have a
+ * descriptor, fetch a new copy of its descriptor -- either directly
+ * from the bridge or via a bridge authority. */
+void
+fetch_bridge_descriptors(const or_options_t *options, time_t now)
+{
+ int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO);
+ int ask_bridge_directly;
+ int can_use_bridge_authority;
+
+ if (!bridge_list)
+ return;
+
+ /* If we still have unconfigured managed proxies, don't go and
+ connect to a bridge. */
+ if (pt_proxies_configuration_pending())
+ return;
+
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
+ {
+ if (!download_status_is_ready(&bridge->fetch_status, now,
+ IMPOSSIBLE_TO_DOWNLOAD))
+ continue; /* don't bother, no need to retry yet */
+ if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
+ download_status_mark_impossible(&bridge->fetch_status);
+ log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
+ safe_str_client(fmt_and_decorate_addr(&bridge->addr)));
+ continue;
+ }
+
+ /* schedule another fetch as if this one will fail, in case it does */
+ download_status_failed(&bridge->fetch_status, 0);
+
+ can_use_bridge_authority = !tor_digest_is_zero(bridge->identity) &&
+ num_bridge_auths;
+ ask_bridge_directly = !can_use_bridge_authority ||
+ !options->UpdateBridgesFromAuthority;
+ log_debug(LD_DIR, "ask_bridge_directly=%d (%d, %d, %d)",
+ ask_bridge_directly, tor_digest_is_zero(bridge->identity),
+ !options->UpdateBridgesFromAuthority, !num_bridge_auths);
+
+ if (ask_bridge_directly &&
+ !fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) {
+ log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our "
+ "firewall policy. %s.",
+ fmt_addrport(&bridge->addr, bridge->port),
+ can_use_bridge_authority ?
+ "Asking bridge authority instead" : "Skipping");
+ if (can_use_bridge_authority)
+ ask_bridge_directly = 0;
+ else
+ continue;
+ }
+
+ if (ask_bridge_directly) {
+ /* we need to ask the bridge itself for its descriptor. */
+ launch_direct_bridge_descriptor_fetch(bridge);
+ } else {
+ /* We have a digest and we want to ask an authority. We could
+ * combine all the requests into one, but that may give more
+ * hints to the bridge authority than we want to give. */
+ char resource[10 + HEX_DIGEST_LEN];
+ memcpy(resource, "fp/", 3);
+ base16_encode(resource+3, HEX_DIGEST_LEN+1,
+ bridge->identity, DIGEST_LEN);
+ memcpy(resource+3+HEX_DIGEST_LEN, ".z", 3);
+ log_info(LD_DIR, "Fetching bridge info '%s' from bridge authority.",
+ resource);
+ directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,
+ ROUTER_PURPOSE_BRIDGE, resource, 0);
+ }
+ }
+ SMARTLIST_FOREACH_END(bridge);
+}
+
+/** If our <b>bridge</b> is configured to be a different address than
+ * the bridge gives in <b>node</b>, rewrite the routerinfo
+ * we received to use the address we meant to use. Now we handle
+ * multihomed bridges better.
+ */
+static void
+rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
+{
+ /* XXXX move this function. */
+ /* XXXX overridden addresses should really live in the node_t, so that the
+ * routerinfo_t and the microdesc_t can be immutable. But we can only
+ * do that safely if we know that no function that connects to an OR
+ * does so through an address from any source other than node_get_addr().
+ */
+ tor_addr_t addr;
+
+ if (node->ri) {
+ routerinfo_t *ri = node->ri;
+ tor_addr_from_ipv4h(&addr, ri->addr);
+
+ if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
+ bridge->port == ri->or_port) ||
+ (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) &&
+ bridge->port == ri->ipv6_orport)) {
+ /* they match, so no need to do anything */
+ } else {
+ if (tor_addr_family(&bridge->addr) == AF_INET) {
+ ri->addr = tor_addr_to_ipv4h(&bridge->addr);
+ tor_free(ri->address);
+ ri->address = tor_dup_ip(ri->addr);
+ ri->or_port = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerinfo for '%s' to match configured "
+ "address %s:%d.",
+ ri->nickname, ri->address, ri->or_port);
+ } else if (tor_addr_family(&bridge->addr) == AF_INET6) {
+ tor_addr_copy(&ri->ipv6_addr, &bridge->addr);
+ ri->ipv6_orport = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerinfo for '%s' to match configured "
+ "address %s.",
+ ri->nickname, fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport));
+ } else {
+ log_err(LD_BUG, "Address family not supported: %d.",
+ tor_addr_family(&bridge->addr));
+ return;
+ }
+ }
+
+ /* Mark which address to use based on which bridge_t we got. */
+ node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 &&
+ !tor_addr_is_null(&node->ri->ipv6_addr));
+
+ /* XXXipv6 we lack support for falling back to another address for
+ the same relay, warn the user */
+ if (!tor_addr_is_null(&ri->ipv6_addr)) {
+ tor_addr_port_t ap;
+ node_get_pref_orport(node, &ap);
+ log_notice(LD_CONFIG,
+ "Bridge '%s' has both an IPv4 and an IPv6 address. "
+ "Will prefer using its %s address (%s).",
+ ri->nickname,
+ tor_addr_family(&ap.addr) == AF_INET6 ? "IPv6" : "IPv4",
+ fmt_addrport(&ap.addr, ap.port));
+ }
+ }
+ if (node->rs) {
+ routerstatus_t *rs = node->rs;
+ tor_addr_from_ipv4h(&addr, rs->addr);
+
+ if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
+ bridge->port == rs->or_port) {
+ /* they match, so no need to do anything */
+ } else {
+ rs->addr = tor_addr_to_ipv4h(&bridge->addr);
+ rs->or_port = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerstatus for '%s' to match "
+ "configured address %s.",
+ rs->nickname, fmt_addrport(&bridge->addr, rs->or_port));
+ }
+ }
+}
+
+/** We just learned a descriptor for a bridge. See if that
+ * digest is in our entry guard list, and add it if not. */
+void
+learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
+{
+ tor_assert(ri);
+ tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
+ if (get_options()->UseBridges) {
+ int first = !any_bridge_descriptors_known();
+ bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri);
+ time_t now = time(NULL);
+ router_set_status(ri->cache_info.identity_digest, 1);
+
+ if (bridge) { /* if we actually want to use this one */
+ node_t *node;
+ /* it's here; schedule its re-fetch for a long time from now. */
+ if (!from_cache)
+ download_status_reset(&bridge->fetch_status);
+
+ node = node_get_mutable_by_id(ri->cache_info.identity_digest);
+ tor_assert(node);
+ rewrite_node_address_for_bridge(bridge, node);
+ add_an_entry_guard(node, 1, 1);
+
+ log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
+ from_cache ? "cached" : "fresh", router_describe(ri));
+ /* set entry->made_contact so if it goes down we don't drop it from
+ * our entry node list */
+ entry_guard_register_connect_status(ri->cache_info.identity_digest,
+ 1, 0, now);
+ if (first)
+ routerlist_retry_directory_downloads(now);
+ }
+ }
+}
+
+/** Return 1 if any of our entry guards have descriptors that
+ * are marked with purpose 'bridge' and are running. Else return 0.
+ *
+ * We use this function to decide if we're ready to start building
+ * circuits through our bridges, or if we need to wait until the
+ * directory "server/authority" requests finish. */
+int
+any_bridge_descriptors_known(void)
+{
+ tor_assert(get_options()->UseBridges);
+ return choose_random_entry(NULL)!=NULL ? 1 : 0;
+}
+
+/** Return 1 if there are any directory conns fetching bridge descriptors
+ * that aren't marked for close. We use this to guess if we should tell
+ * the controller that we have a problem. */
+int
+any_pending_bridge_descriptor_fetches(void)
+{
+ smartlist_t *conns = get_connection_array();
+ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
+ if (conn->type == CONN_TYPE_DIR &&
+ conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
+ TO_DIR_CONN(conn)->router_purpose == ROUTER_PURPOSE_BRIDGE &&
+ !conn->marked_for_close &&
+ conn->linked &&
+ conn->linked_conn && !conn->linked_conn->marked_for_close) {
+ log_debug(LD_DIR, "found one: %s", conn->address);
+ return 1;
+ }
+ } SMARTLIST_FOREACH_END(conn);
+ return 0;
+}
+
+/** Return 1 if we have at least one descriptor for an entry guard
+ * (bridge or member of EntryNodes) and all descriptors we know are
+ * down. Else return 0. If <b>act</b> is 1, then mark the down guards
+ * up; else just observe and report. */
+static int
+entries_retry_helper(const or_options_t *options, int act)
+{
+ const node_t *node;
+ int any_known = 0;
+ int any_running = 0;
+ int need_bridges = options->UseBridges != 0;
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ node = node_get_by_id(e->identity);
+ if (node && node_has_descriptor(node) &&
+ node_is_bridge(node) == need_bridges) {
+ any_known = 1;
+ if (node->is_running)
+ any_running = 1; /* some entry is both known and running */
+ else if (act) {
+ /* Mark all current connections to this OR as unhealthy, since
+ * otherwise there could be one that started 30 seconds
+ * ago, and in 30 seconds it will time out, causing us to mark
+ * the node down and undermine the retry attempt. We mark even
+ * the established conns, since if the network just came back
+ * we'll want to attach circuits to fresh conns. */
+ connection_or_set_bad_connections(node->identity, 1);
+
+ /* mark this entry node for retry */
+ router_set_status(node->identity, 1);
+ e->can_retry = 1;
+ e->bad_since = 0;
+ }
+ }
+ } SMARTLIST_FOREACH_END(e);
+ log_debug(LD_DIR, "%d: any_known %d, any_running %d",
+ act, any_known, any_running);
+ return any_known && !any_running;
+}
+
+/** Do we know any descriptors for our bridges / entrynodes, and are
+ * all the ones we have descriptors for down? */
+int
+entries_known_but_down(const or_options_t *options)
+{
+ tor_assert(entry_list_is_constrained(options));
+ return entries_retry_helper(options, 0);
+}
+
+/** Mark all down known bridges / entrynodes up. */
+void
+entries_retry_all(const or_options_t *options)
+{
+ tor_assert(entry_list_is_constrained(options));
+ entries_retry_helper(options, 1);
+}
+
+/** Return true if we've ever had a bridge running a Tor version that can't
+ * provide microdescriptors to us. In that case fall back to asking for
+ * full descriptors. Eventually all bridges will support microdescriptors
+ * and we can take this check out; see bug 4013. */
+int
+any_bridges_dont_support_microdescriptors(void)
+{
+ const node_t *node;
+ static int ever_answered_yes = 0;
+ if (!get_options()->UseBridges || !entry_guards)
+ return 0;
+ if (ever_answered_yes)
+ return 1; /* if we ever answer 'yes', always answer 'yes' */
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ node = node_get_by_id(e->identity);
+ if (node && node->ri &&
+ node_is_bridge(node) && node_is_a_configured_bridge(node) &&
+ !tor_version_supports_microdescriptors(node->ri->platform)) {
+ /* This is one of our current bridges, and we know enough about
+ * it to know that it won't be able to answer our microdescriptor
+ * questions. */
+ ever_answered_yes = 1;
+ return 1;
+ }
+ } SMARTLIST_FOREACH_END(e);
+ return 0;
+}
+
+/** Release all storage held by the list of entry guards and related
+ * memory structs. */
+void
+entry_guards_free_all(void)
+{
+ if (entry_guards) {
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
+ entry_guard_free(e));
+ smartlist_free(entry_guards);
+ entry_guards = NULL;
+ }
+ clear_bridge_list();
+ smartlist_free(bridge_list);
+ bridge_list = NULL;
+ circuit_build_times_free_timeouts(&circ_times);
+}
+
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
new file mode 100644
index 0000000000..4d031c3593
--- /dev/null
+++ b/src/or/entrynodes.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file guardnodes.h
+ * \brief Header file for circuitbuild.c.
+ **/
+
+#ifndef TOR_ENTRYNODES_H
+#define TOR_ENTRYNODES_H
+
+#if 1
+/* XXXX NM I would prefer that all of this stuff be private to
+ * entrynodes.c. */
+
+/** An entry_guard_t represents our information about a chosen long-term
+ * first hop, known as a "helper" node in the literature. We can't just
+ * use a node_t, since we want to remember these even when we
+ * don't have any directory info. */
+typedef struct entry_guard_t {
+ char nickname[MAX_NICKNAME_LEN+1];
+ char identity[DIGEST_LEN];
+ time_t chosen_on_date; /**< Approximately when was this guard added?
+ * "0" if we don't know. */
+ char *chosen_by_version; /**< What tor version added this guard? NULL
+ * if we don't know. */
+ unsigned int made_contact : 1; /**< 0 if we have never connected to this
+ * router, 1 if we have. */
+ unsigned int can_retry : 1; /**< Should we retry connecting to this entry,
+ * in spite of having it marked as unreachable?*/
+ unsigned int path_bias_notice : 1; /**< Did we alert the user about path bias
+ * for this node already? */
+ unsigned int path_bias_disabled : 1; /**< Have we disabled this node because
+ * of path bias issues? */
+ time_t bad_since; /**< 0 if this guard is currently usable, or the time at
+ * which it was observed to become (according to the
+ * directory or the user configuration) unusable. */
+ time_t unreachable_since; /**< 0 if we can connect to this guard, or the
+ * time at which we first noticed we couldn't
+ * connect to it. */
+ time_t last_attempted; /**< 0 if we can connect to this guard, or the time
+ * at which we last failed to connect to it. */
+
+ unsigned first_hops; /**< Number of first hops this guard has completed */
+ unsigned circuit_successes; /**< Number of successfully built circuits using
+ * this guard as first hop. */
+} entry_guard_t;
+
+entry_guard_t *entry_guard_get_by_id_digest(const char *digest);
+void entry_guards_changed(void);
+const smartlist_t *get_entry_guards(void);
+int num_live_entry_guards(void);
+
+#endif
+
+void entry_guards_compute_status(const or_options_t *options, time_t now);
+int entry_guard_register_connect_status(const char *digest, int succeeded,
+ int mark_relay_status, time_t now);
+void entry_nodes_should_be_added(void);
+int entry_list_is_constrained(const or_options_t *options);
+const node_t *choose_random_entry(cpath_build_state_t *state);
+int entry_guards_parse_state(or_state_t *state, int set, char **msg);
+void entry_guards_update_state(or_state_t *state);
+int getinfo_helper_entry_guards(control_connection_t *conn,
+ const char *question, char **answer,
+ const char **errmsg);
+
+void mark_bridge_list(void);
+void sweep_bridge_list(void);
+
+int routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
+int node_is_a_configured_bridge(const node_t *node);
+void learned_router_identity(const tor_addr_t *addr, uint16_t port,
+ const char *digest);
+void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *digest,
+ const char *transport_name);
+void retry_bridge_descriptor_fetch_directly(const char *digest);
+void fetch_bridge_descriptors(const or_options_t *options, time_t now);
+void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
+int any_bridge_descriptors_known(void);
+int any_pending_bridge_descriptor_fetches(void);
+int entries_known_but_down(const or_options_t *options);
+void entries_retry_all(const or_options_t *options);
+
+int any_bridges_dont_support_microdescriptors(void);
+
+void entry_guards_free_all(void);
+
+const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr,
+ uint16_t port);
+struct transport_t;
+int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
+ const struct transport_t **transport);
+
+int validate_pluggable_transports_config(void);
+
+#endif
+
diff --git a/src/or/eventdns_tor.h b/src/or/eventdns_tor.h
index 4c40b3524b..0775643b5c 100644
--- a/src/or/eventdns_tor.h
+++ b/src/or/eventdns_tor.h
@@ -1,6 +1,9 @@
/* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#ifndef TOR_EVENTDNS_TOR_H
+#define TOR_EVENTDNS_TOR_H
+
#include "orconfig.h"
#define DNS_USE_OPENSSL_FOR_ID
#ifndef HAVE_UINT
@@ -18,3 +21,5 @@ typedef unsigned char u_char;
#include "util.h"
#include "compat.h"
+#endif
+
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 6b7cc82b82..2fd77d8b97 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -21,12 +21,19 @@
static void clear_geoip_db(void);
static void init_geoip_countries(void);
-/** An entry from the GeoIP file: maps an IP range to a country. */
-typedef struct geoip_entry_t {
+/** An entry from the GeoIP IPv4 file: maps an IPv4 range to a country. */
+typedef struct geoip_ipv4_entry_t {
uint32_t ip_low; /**< The lowest IP in the range, in host order */
uint32_t ip_high; /**< The highest IP in the range, in host order */
intptr_t country; /**< An index into geoip_countries */
-} geoip_entry_t;
+} geoip_ipv4_entry_t;
+
+/** An entry from the GeoIP IPv6 file: maps an IPv6 range to a country. */
+typedef struct geoip_ipv6_entry_t {
+ struct in6_addr ip_low; /**< The lowest IP in the range, in host order */
+ struct in6_addr ip_high; /**< The highest IP in the range, in host order */
+ intptr_t country; /**< An index into geoip_countries */
+} geoip_ipv6_entry_t;
/** A per-country record for GeoIP request history. */
typedef struct geoip_country_t {
@@ -41,45 +48,48 @@ static smartlist_t *geoip_countries = NULL;
* The index is encoded in the pointer, and 1 is added so that NULL can mean
* not found. */
static strmap_t *country_idxplus1_by_lc_code = NULL;
-/** A list of all known geoip_entry_t, sorted by ip_low. */
-static smartlist_t *geoip_entries = NULL;
+/** Lists of all known geoip_ipv4_entry_t and geoip_ipv6_entry_t, sorted
+ * by their respective ip_low. */
+static smartlist_t *geoip_ipv4_entries = NULL, *geoip_ipv6_entries = NULL;
-/** SHA1 digest of the GeoIP file to include in extra-info descriptors. */
+/** SHA1 digest of the GeoIP files to include in extra-info descriptors. */
static char geoip_digest[DIGEST_LEN];
+static char geoip6_digest[DIGEST_LEN];
-/** Return the index of the <b>country</b>'s entry in the GeoIP DB
- * if it is a valid 2-letter country code, otherwise return -1.
- */
+/** Return the index of the <b>country</b>'s entry in the GeoIP
+ * country list if it is a valid 2-letter country code, otherwise
+ * return -1. */
country_t
geoip_get_country(const char *country)
{
- void *_idxplus1;
+ void *idxplus1_;
intptr_t idx;
- _idxplus1 = strmap_get_lc(country_idxplus1_by_lc_code, country);
- if (!_idxplus1)
+ idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country);
+ if (!idxplus1_)
return -1;
- idx = ((uintptr_t)_idxplus1)-1;
+ idx = ((uintptr_t)idxplus1_)-1;
return (country_t)idx;
}
-/** Add an entry to the GeoIP table, mapping all IPs between <b>low</b> and
- * <b>high</b>, inclusive, to the 2-letter country code <b>country</b>.
- */
+/** Add an entry to a GeoIP table, mapping all IP addresses between <b>low</b>
+ * and <b>high</b>, inclusive, to the 2-letter country code <b>country</b>. */
static void
-geoip_add_entry(uint32_t low, uint32_t high, const char *country)
+geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high,
+ const char *country)
{
intptr_t idx;
- geoip_entry_t *ent;
- void *_idxplus1;
+ void *idxplus1_;
- if (high < low)
+ if (tor_addr_family(low) != tor_addr_family(high))
+ return;
+ if (tor_addr_compare(high, low, CMP_EXACT) < 0)
return;
- _idxplus1 = strmap_get_lc(country_idxplus1_by_lc_code, country);
+ idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country);
- if (!_idxplus1) {
+ if (!idxplus1_) {
geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t));
strlcpy(c->countrycode, country, sizeof(c->countrycode));
tor_strlower(c->countrycode);
@@ -87,54 +97,103 @@ geoip_add_entry(uint32_t low, uint32_t high, const char *country)
idx = smartlist_len(geoip_countries) - 1;
strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1));
} else {
- idx = ((uintptr_t)_idxplus1)-1;
+ idx = ((uintptr_t)idxplus1_)-1;
}
{
geoip_country_t *c = smartlist_get(geoip_countries, idx);
tor_assert(!strcasecmp(c->countrycode, country));
}
- ent = tor_malloc_zero(sizeof(geoip_entry_t));
- ent->ip_low = low;
- ent->ip_high = high;
- ent->country = idx;
- smartlist_add(geoip_entries, ent);
+
+ if (tor_addr_family(low) == AF_INET) {
+ geoip_ipv4_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv4_entry_t));
+ ent->ip_low = tor_addr_to_ipv4h(low);
+ ent->ip_high = tor_addr_to_ipv4h(high);
+ ent->country = idx;
+ smartlist_add(geoip_ipv4_entries, ent);
+ } else if (tor_addr_family(low) == AF_INET6) {
+ geoip_ipv6_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv6_entry_t));
+ ent->ip_low = *tor_addr_to_in6(low);
+ ent->ip_high = *tor_addr_to_in6(high);
+ ent->country = idx;
+ smartlist_add(geoip_ipv6_entries, ent);
+ }
}
-/** Add an entry to the GeoIP table, parsing it from <b>line</b>. The
- * format is as for geoip_load_file(). */
+/** Add an entry to the GeoIP table indicated by <b>family</b>,
+ * parsing it from <b>line</b>. The format is as for geoip_load_file(). */
/*private*/ int
-geoip_parse_entry(const char *line)
+geoip_parse_entry(const char *line, sa_family_t family)
{
- unsigned int low, high;
- char b[3];
+ tor_addr_t low_addr, high_addr;
+ char c[3];
+ char *country = NULL;
+
if (!geoip_countries)
init_geoip_countries();
- if (!geoip_entries)
- geoip_entries = smartlist_new();
+ if (family == AF_INET) {
+ if (!geoip_ipv4_entries)
+ geoip_ipv4_entries = smartlist_new();
+ } else if (family == AF_INET6) {
+ if (!geoip_ipv6_entries)
+ geoip_ipv6_entries = smartlist_new();
+ } else {
+ log_warn(LD_GENERAL, "Unsupported family: %d", family);
+ return -1;
+ }
while (TOR_ISSPACE(*line))
++line;
if (*line == '#')
return 0;
- if (tor_sscanf(line,"%u,%u,%2s", &low, &high, b) == 3) {
- geoip_add_entry(low, high, b);
- return 0;
- } else if (tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, b) == 3) {
- geoip_add_entry(low, high, b);
- return 0;
- } else {
- log_warn(LD_GENERAL, "Unable to parse line from GEOIP file: %s",
- escaped(line));
- return -1;
+
+ if (family == AF_INET) {
+ unsigned int low, high;
+ if (tor_sscanf(line,"%u,%u,%2s", &low, &high, c) == 3 ||
+ tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, c) == 3) {
+ tor_addr_from_ipv4h(&low_addr, low);
+ tor_addr_from_ipv4h(&high_addr, high);
+ } else
+ goto fail;
+ country = c;
+ } else { /* AF_INET6 */
+ char buf[512];
+ char *low_str, *high_str;
+ struct in6_addr low, high;
+ char *strtok_state;
+ strlcpy(buf, line, sizeof(buf));
+ low_str = tor_strtok_r(buf, ",", &strtok_state);
+ if (!low_str)
+ goto fail;
+ high_str = tor_strtok_r(NULL, ",", &strtok_state);
+ if (!high_str)
+ goto fail;
+ country = tor_strtok_r(NULL, "\n", &strtok_state);
+ if (!country)
+ goto fail;
+ if (strlen(country) != 2)
+ goto fail;
+ if (tor_inet_pton(AF_INET6, low_str, &low) <= 0)
+ goto fail;
+ tor_addr_from_in6(&low_addr, &low);
+ if (tor_inet_pton(AF_INET6, high_str, &high) <= 0)
+ goto fail;
+ tor_addr_from_in6(&high_addr, &high);
}
+ geoip_add_entry(&low_addr, &high_addr, country);
+ return 0;
+
+ fail:
+ log_warn(LD_GENERAL, "Unable to parse line from GEOIP %s file: %s",
+ family == AF_INET ? "IPv4" : "IPv6", escaped(line));
+ return -1;
}
/** Sorting helper: return -1, 1, or 0 based on comparison of two
- * geoip_entry_t */
+ * geoip_ipv4_entry_t */
static int
-_geoip_compare_entries(const void **_a, const void **_b)
+geoip_ipv4_compare_entries_(const void **_a, const void **_b)
{
- const geoip_entry_t *a = *_a, *b = *_b;
+ const geoip_ipv4_entry_t *a = *_a, *b = *_b;
if (a->ip_low < b->ip_low)
return -1;
else if (a->ip_low > b->ip_low)
@@ -144,13 +203,13 @@ _geoip_compare_entries(const void **_a, const void **_b)
}
/** bsearch helper: return -1, 1, or 0 based on comparison of an IP (a pointer
- * to a uint32_t in host order) to a geoip_entry_t */
+ * to a uint32_t in host order) to a geoip_ipv4_entry_t */
static int
-_geoip_compare_key_to_entry(const void *_key, const void **_member)
+geoip_ipv4_compare_key_to_entry_(const void *_key, const void **_member)
{
/* No alignment issue here, since _key really is a pointer to uint32_t */
const uint32_t addr = *(uint32_t *)_key;
- const geoip_entry_t *entry = *_member;
+ const geoip_ipv4_entry_t *entry = *_member;
if (addr < entry->ip_low)
return -1;
else if (addr > entry->ip_high)
@@ -159,6 +218,33 @@ _geoip_compare_key_to_entry(const void *_key, const void **_member)
return 0;
}
+/** Sorting helper: return -1, 1, or 0 based on comparison of two
+ * geoip_ipv6_entry_t */
+static int
+geoip_ipv6_compare_entries_(const void **_a, const void **_b)
+{
+ const geoip_ipv6_entry_t *a = *_a, *b = *_b;
+ return memcmp(a->ip_low.s6_addr, b->ip_low.s6_addr, sizeof(struct in6_addr));
+}
+
+/** bsearch helper: return -1, 1, or 0 based on comparison of an IPv6
+ * (a pointer to a in6_addr) to a geoip_ipv6_entry_t */
+static int
+geoip_ipv6_compare_key_to_entry_(const void *_key, const void **_member)
+{
+ const struct in6_addr *addr = (struct in6_addr *)_key;
+ const geoip_ipv6_entry_t *entry = *_member;
+
+ if (memcmp(addr->s6_addr, entry->ip_low.s6_addr,
+ sizeof(struct in6_addr)) < 0)
+ return -1;
+ else if (memcmp(addr->s6_addr, entry->ip_high.s6_addr,
+ sizeof(struct in6_addr)) > 0)
+ return 1;
+ else
+ return 0;
+}
+
/** Return 1 if we should collect geoip stats on bridge users, and
* include them in our extrainfo descriptor. Else return 0. */
int
@@ -185,27 +271,35 @@ init_geoip_countries(void)
strmap_set_lc(country_idxplus1_by_lc_code, "??", (void*)(1));
}
-/** Clear the GeoIP database and reload it from the file
- * <b>filename</b>. Return 0 on success, -1 on failure.
+/** Clear appropriate GeoIP database, based on <b>family</b>, and
+ * reload it from the file <b>filename</b>. Return 0 on success, -1 on
+ * failure.
*
- * Recognized line formats are:
+ * Recognized line formats for IPv4 are:
* INTIPLOW,INTIPHIGH,CC
* and
* "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME"
* where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as 4-byte unsigned
* integers, and CC is a country code.
*
+ * Recognized line format for IPv6 is:
+ * IPV6LOW,IPV6HIGH,CC
+ * where IPV6LOW and IPV6HIGH are IPv6 addresses and CC is a country code.
+ *
* It also recognizes, and skips over, blank lines and lines that start
* with '#' (comments).
*/
int
-geoip_load_file(const char *filename, const or_options_t *options)
+geoip_load_file(sa_family_t family, const char *filename)
{
FILE *f;
const char *msg = "";
+ const or_options_t *options = get_options();
int severity = options_need_geoip_info(options, &msg) ? LOG_WARN : LOG_INFO;
crypto_digest_t *geoip_digest_env = NULL;
- clear_geoip_db();
+
+ tor_assert(family == AF_INET || family == AF_INET6);
+
if (!(f = tor_fopen_cloexec(filename, "r"))) {
log_fn(severity, LD_GENERAL, "Failed to open GEOIP file %s. %s",
filename, msg);
@@ -213,33 +307,51 @@ geoip_load_file(const char *filename, const or_options_t *options)
}
if (!geoip_countries)
init_geoip_countries();
- if (geoip_entries) {
- SMARTLIST_FOREACH(geoip_entries, geoip_entry_t *, e, tor_free(e));
- smartlist_free(geoip_entries);
+
+ if (family == AF_INET) {
+ if (geoip_ipv4_entries) {
+ SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, e,
+ tor_free(e));
+ smartlist_free(geoip_ipv4_entries);
+ }
+ geoip_ipv4_entries = smartlist_new();
+ } else { /* AF_INET6 */
+ if (geoip_ipv6_entries) {
+ SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, e,
+ tor_free(e));
+ smartlist_free(geoip_ipv6_entries);
+ }
+ geoip_ipv6_entries = smartlist_new();
}
- geoip_entries = smartlist_new();
geoip_digest_env = crypto_digest_new();
- log_notice(LD_GENERAL, "Parsing GEOIP file %s.", filename);
+
+ log_notice(LD_GENERAL, "Parsing GEOIP %s file %s.",
+ (family == AF_INET) ? "IPv4" : "IPv6", filename);
while (!feof(f)) {
char buf[512];
if (fgets(buf, (int)sizeof(buf), f) == NULL)
break;
crypto_digest_add_bytes(geoip_digest_env, buf, strlen(buf));
/* FFFF track full country name. */
- geoip_parse_entry(buf);
+ geoip_parse_entry(buf, family);
}
/*XXXX abort and return -1 if no entries/illformed?*/
fclose(f);
- smartlist_sort(geoip_entries, _geoip_compare_entries);
-
- /* Okay, now we need to maybe change our mind about what is in which
- * country. */
- refresh_all_country_info();
-
- /* Remember file digest so that we can include it in our extra-info
- * descriptors. */
- crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN);
+ /* Sort list and remember file digests so that we can include it in
+ * our extra-info descriptors. */
+ if (family == AF_INET) {
+ smartlist_sort(geoip_ipv4_entries, geoip_ipv4_compare_entries_);
+ /* Okay, now we need to maybe change our mind about what is in
+ * which country. We do this for IPv4 only since that's what we
+ * store in node->country. */
+ refresh_all_country_info();
+ crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN);
+ } else {
+ /* AF_INET6 */
+ smartlist_sort(geoip_ipv6_entries, geoip_ipv6_compare_entries_);
+ crypto_digest_get_digest(geoip_digest_env, geoip6_digest, DIGEST_LEN);
+ }
crypto_digest_free(geoip_digest_env);
return 0;
@@ -252,12 +364,30 @@ geoip_load_file(const char *filename, const or_options_t *options)
* geoip_get_country_name().
*/
int
-geoip_get_country_by_ip(uint32_t ipaddr)
+geoip_get_country_by_ipv4(uint32_t ipaddr)
+{
+ geoip_ipv4_entry_t *ent;
+ if (!geoip_ipv4_entries)
+ return -1;
+ ent = smartlist_bsearch(geoip_ipv4_entries, &ipaddr,
+ geoip_ipv4_compare_key_to_entry_);
+ return ent ? (int)ent->country : 0;
+}
+
+/** Given an IPv6 address, return a number representing the country to
+ * which that address belongs, -1 for "No geoip information available", or
+ * 0 for the 'unknown country'. The return value will always be less than
+ * geoip_get_n_countries(). To decode it, call geoip_get_country_name().
+ */
+int
+geoip_get_country_by_ipv6(const struct in6_addr *addr)
{
- geoip_entry_t *ent;
- if (!geoip_entries)
+ geoip_ipv6_entry_t *ent;
+
+ if (!geoip_ipv6_entries)
return -1;
- ent = smartlist_bsearch(geoip_entries, &ipaddr, _geoip_compare_key_to_entry);
+ ent = smartlist_bsearch(geoip_ipv6_entries, addr,
+ geoip_ipv6_compare_key_to_entry_);
return ent ? (int)ent->country : 0;
}
@@ -269,14 +399,16 @@ geoip_get_country_by_ip(uint32_t ipaddr)
int
geoip_get_country_by_addr(const tor_addr_t *addr)
{
- if (tor_addr_family(addr) != AF_INET) {
- /*XXXX IP6 support ipv6 geoip.*/
+ if (tor_addr_family(addr) == AF_INET) {
+ return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr));
+ } else if (tor_addr_family(addr) == AF_INET6) {
+ return geoip_get_country_by_ipv6(tor_addr_to_in6(addr));
+ } else {
return -1;
}
- return geoip_get_country_by_ip(tor_addr_to_ipv4h(addr));
}
-/** Return the number of countries recognized by the GeoIP database. */
+/** Return the number of countries recognized by the GeoIP country list. */
int
geoip_get_n_countries(void)
{
@@ -299,18 +431,28 @@ geoip_get_country_name(country_t num)
/** Return true iff we have loaded a GeoIP database.*/
int
-geoip_is_loaded(void)
+geoip_is_loaded(sa_family_t family)
{
- return geoip_countries != NULL && geoip_entries != NULL;
+ tor_assert(family == AF_INET || family == AF_INET6);
+ if (geoip_countries == NULL)
+ return 0;
+ if (family == AF_INET)
+ return geoip_ipv4_entries != NULL;
+ else /* AF_INET6 */
+ return geoip_ipv6_entries != NULL;
}
/** Return the hex-encoded SHA1 digest of the loaded GeoIP file. The
* result does not need to be deallocated, but will be overwritten by the
* next call of hex_str(). */
const char *
-geoip_db_digest(void)
+geoip_db_digest(sa_family_t family)
{
- return hex_str(geoip_digest, DIGEST_LEN);
+ tor_assert(family == AF_INET || family == AF_INET6);
+ if (family == AF_INET)
+ return hex_str(geoip_digest, DIGEST_LEN);
+ else /* AF_INET6 */
+ return hex_str(geoip6_digest, DIGEST_LEN);
}
/** Entry in a map from IP address to the last time we've seen an incoming
@@ -489,7 +631,7 @@ geoip_note_client_seen(geoip_client_action_t action,
/** HT_FOREACH helper: remove a clientmap_entry_t from the hashtable if it's
* older than a certain time. */
static int
-_remove_old_client_helper(struct clientmap_entry_t *ent, void *_cutoff)
+remove_old_client_helper_(struct clientmap_entry_t *ent, void *_cutoff)
{
time_t cutoff = *(time_t*)_cutoff / 60;
if (ent->last_seen_in_minutes < cutoff) {
@@ -505,7 +647,7 @@ void
geoip_remove_old_clients(time_t cutoff)
{
clientmap_HT_FOREACH_FN(&client_history,
- _remove_old_client_helper,
+ remove_old_client_helper_,
&cutoff);
}
@@ -559,10 +701,10 @@ typedef struct c_hist_t {
} c_hist_t;
/** Sorting helper: return -1, 1, or 0 based on comparison of two
- * geoip_entry_t. Sort in descending order of total, and then by country
+ * geoip_ipv4_entry_t. Sort in descending order of total, and then by country
* code. */
static int
-_c_hist_compare(const void **_a, const void **_b)
+c_hist_compare_(const void **_a, const void **_b)
{
const c_hist_t *a = *_a, *b = *_b;
if (a->total > b->total)
@@ -578,7 +720,7 @@ _c_hist_compare(const void **_a, const void **_b)
* failed, the others as still running. */
#define DIRREQ_TIMEOUT (10*60)
-/** Entry in a map from either conn->global_identifier for direct requests
+/** Entry in a map from either chan->global_identifier for direct requests
* or a unique circuit identifier for tunneled requests to request time,
* response size, and completion time of a network status request. Used to
* measure download times of requests to derive average client
@@ -586,7 +728,7 @@ _c_hist_compare(const void **_a, const void **_b)
typedef struct dirreq_map_entry_t {
HT_ENTRY(dirreq_map_entry_t) node;
/** Unique identifier for this network status request; this is either the
- * conn->global_identifier of the dir conn (direct request) or a new
+ * chan->global_identifier of the dir channel (direct request) or a new
* locally unique identifier of a circuit (tunneled request). This ID is
* only unique among other direct or tunneled requests, respectively. */
uint64_t dirreq_id;
@@ -631,7 +773,7 @@ HT_GENERATE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
* <b>type</b> and <b>dirreq_id</b> as key parts. If there is
* already an entry for that key, print out a BUG warning and return. */
static void
-_dirreq_map_put(dirreq_map_entry_t *entry, dirreq_type_t type,
+dirreq_map_put_(dirreq_map_entry_t *entry, dirreq_type_t type,
uint64_t dirreq_id)
{
dirreq_map_entry_t *old_ent;
@@ -653,7 +795,7 @@ _dirreq_map_put(dirreq_map_entry_t *entry, dirreq_type_t type,
* using <b>type</b> and <b>dirreq_id</b> as key parts. If there
* is no such entry, return NULL. */
static dirreq_map_entry_t *
-_dirreq_map_get(dirreq_type_t type, uint64_t dirreq_id)
+dirreq_map_get_(dirreq_type_t type, uint64_t dirreq_id)
{
dirreq_map_entry_t lookup;
lookup.type = type;
@@ -678,7 +820,7 @@ geoip_start_dirreq(uint64_t dirreq_id, size_t response_size,
ent->response_size = response_size;
ent->action = action;
ent->type = type;
- _dirreq_map_put(ent, type, dirreq_id);
+ dirreq_map_put_(ent, type, dirreq_id);
}
/** Change the state of the either direct or tunneled (see <b>type</b>)
@@ -694,7 +836,7 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
dirreq_map_entry_t *ent;
if (!get_options()->DirReqStatistics)
return;
- ent = _dirreq_map_get(type, dirreq_id);
+ ent = dirreq_map_get_(type, dirreq_id);
if (!ent)
return;
if (new_state == DIRREQ_IS_FOR_NETWORK_STATUS)
@@ -705,7 +847,7 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
if ((type == DIRREQ_DIRECT &&
new_state == DIRREQ_FLUSHING_DIR_CONN_FINISHED) ||
(type == DIRREQ_TUNNELED &&
- new_state == DIRREQ_OR_CONN_BUFFER_FLUSHED)) {
+ new_state == DIRREQ_CHANNEL_BUFFER_FLUSHED)) {
tor_gettimeofday(&ent->completion_time);
ent->completed = 1;
}
@@ -813,27 +955,35 @@ geoip_get_dirreq_history(geoip_client_action_t action,
return result;
}
-/** Return a newly allocated comma-separated string containing entries for
- * all the countries from which we've seen enough clients connect as a
- * bridge, directory server, or entry guard. The entry format is cc=num
- * where num is the number of IPs we've seen connecting from that country,
- * and cc is a lowercased country code. Returns NULL if we don't want
- * to export geoip data yet. */
-char *
-geoip_get_client_history(geoip_client_action_t action)
+/** Store a newly allocated comma-separated string in
+ * *<a>country_str</a> containing entries for all the countries from
+ * which we've seen enough clients connect as a bridge, directory
+ * server, or entry guard. The entry format is cc=num where num is the
+ * number of IPs we've seen connecting from that country, and cc is a
+ * lowercased country code. *<a>country_str</a> is set to NULL if
+ * we're not ready to export per country data yet.
+ *
+ * Store a newly allocated comma-separated string in <a>ipver_str</a>
+ * containing entries for clients connecting over IPv4 and IPv6. The
+ * format is family=num where num is the nubmer of IPs we've seen
+ * connecting over that protocol family, and family is 'v4' or 'v6'.
+ *
+ * Return 0 on success and -1 if we're missing geoip data. */
+int
+geoip_get_client_history(geoip_client_action_t action,
+ char **country_str, char **ipver_str)
{
- char *result = NULL;
unsigned granularity = IP_GRANULARITY;
- smartlist_t *chunks = NULL;
smartlist_t *entries = NULL;
int n_countries = geoip_get_n_countries();
int i;
clientmap_entry_t **ent;
unsigned *counts = NULL;
unsigned total = 0;
+ unsigned ipv4_count = 0, ipv6_count = 0;
- if (!geoip_is_loaded())
- return NULL;
+ if (!geoip_is_loaded(AF_INET) && !geoip_is_loaded(AF_INET6))
+ return -1;
counts = tor_malloc_zero(sizeof(unsigned)*n_countries);
HT_FOREACH(ent, clientmap, &client_history) {
@@ -846,10 +996,34 @@ geoip_get_client_history(geoip_client_action_t action)
tor_assert(0 <= country && country < n_countries);
++counts[country];
++total;
+ switch (tor_addr_family(&(*ent)->addr)) {
+ case AF_INET:
+ ipv4_count++;
+ break;
+ case AF_INET6:
+ ipv6_count++;
+ break;
+ }
}
- /* Don't record anything if we haven't seen enough IPs. */
- if (total < MIN_IPS_TO_NOTE_ANYTHING)
- goto done;
+ if (ipver_str) {
+ smartlist_t *chunks = smartlist_new();
+ smartlist_add_asprintf(chunks, "v4=%u",
+ round_to_next_multiple_of(ipv4_count, granularity));
+ smartlist_add_asprintf(chunks, "v6=%u",
+ round_to_next_multiple_of(ipv6_count, granularity));
+ *ipver_str = smartlist_join_strings(chunks, ",", 0, NULL);
+ SMARTLIST_FOREACH(chunks, char *, c, tor_free(c));
+ smartlist_free(chunks);
+ }
+
+ /* Don't record per country data if we haven't seen enough IPs. */
+ if (total < MIN_IPS_TO_NOTE_ANYTHING) {
+ tor_free(counts);
+ if (country_str)
+ *country_str = NULL;
+ return 0;
+ }
+
/* Make a list of c_hist_t */
entries = smartlist_new();
for (i = 0; i < n_countries; ++i) {
@@ -868,25 +1042,23 @@ geoip_get_client_history(geoip_client_action_t action)
}
/* Sort entries. Note that we must do this _AFTER_ rounding, or else
* the sort order could leak info. */
- smartlist_sort(entries, _c_hist_compare);
-
- /* Build the result. */
- chunks = smartlist_new();
- SMARTLIST_FOREACH(entries, c_hist_t *, ch, {
- smartlist_add_asprintf(chunks, "%s=%u", ch->country, ch->total);
- });
- result = smartlist_join_strings(chunks, ",", 0, NULL);
- done:
- tor_free(counts);
- if (chunks) {
+ smartlist_sort(entries, c_hist_compare_);
+
+ if (country_str) {
+ smartlist_t *chunks = smartlist_new();
+ SMARTLIST_FOREACH(entries, c_hist_t *, ch, {
+ smartlist_add_asprintf(chunks, "%s=%u", ch->country, ch->total);
+ });
+ *country_str = smartlist_join_strings(chunks, ",", 0, NULL);
SMARTLIST_FOREACH(chunks, char *, c, tor_free(c));
smartlist_free(chunks);
}
- if (entries) {
- SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c));
- smartlist_free(entries);
- }
- return result;
+
+ SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c));
+ smartlist_free(entries);
+ tor_free(counts);
+
+ return 0;
}
/** Return a newly allocated string holding the per-country request history
@@ -918,7 +1090,7 @@ geoip_get_request_history(geoip_client_action_t action)
ent->total = round_to_next_multiple_of(tot, granularity);
smartlist_add(entries, ent);
} SMARTLIST_FOREACH_END(c);
- smartlist_sort(entries, _c_hist_compare);
+ smartlist_sort(entries, c_hist_compare_);
strings = smartlist_new();
SMARTLIST_FOREACH(entries, c_hist_t *, ent, {
@@ -1009,8 +1181,9 @@ geoip_format_dirreq_stats(time_t now)
tor_assert(now >= start_of_dirreq_stats_interval);
format_iso_time(t, now);
- v2_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
- v3_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
+ geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2, &v2_ips_string,
+ NULL);
+ geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS, &v3_ips_string, NULL);
v2_reqs_string = geoip_get_request_history(
GEOIP_CLIENT_NETWORKSTATUS_V2);
v3_reqs_string = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);
@@ -1216,7 +1389,7 @@ static char *bridge_stats_extrainfo = NULL;
char *
geoip_format_bridge_stats(time_t now)
{
- char *out = NULL, *data = NULL;
+ char *out = NULL, *country_data = NULL, *ipver_data = NULL;
long duration = now - start_of_bridge_stats_interval;
char written[ISO_TIME_LEN+1];
@@ -1226,14 +1399,17 @@ geoip_format_bridge_stats(time_t now)
return NULL; /* Not initialized. */
format_iso_time(written, now);
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data);
tor_asprintf(&out,
"bridge-stats-end %s (%ld s)\n"
- "bridge-ips %s\n",
+ "bridge-ips %s\n"
+ "bridge-ip-versions %s\n",
written, duration,
- data ? data : "");
- tor_free(data);
+ country_data ? country_data : "",
+ ipver_data ? ipver_data : "");
+ tor_free(country_data);
+ tor_free(ipver_data);
return out;
}
@@ -1244,17 +1420,20 @@ geoip_format_bridge_stats(time_t now)
static char *
format_bridge_stats_controller(time_t now)
{
- char *out = NULL, *data = NULL;
+ char *out = NULL, *country_data = NULL, *ipver_data = NULL;
char started[ISO_TIME_LEN+1];
(void) now;
format_iso_time(started, start_of_bridge_stats_interval);
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data);
tor_asprintf(&out,
- "TimeStarted=\"%s\" CountrySummary=%s",
- started, data ? data : "");
- tor_free(data);
+ "TimeStarted=\"%s\" CountrySummary=%s IPVersions=%s",
+ started,
+ country_data ? country_data : "",
+ ipver_data ? ipver_data : "");
+ tor_free(country_data);
+ tor_free(ipver_data);
return out;
}
@@ -1381,11 +1560,13 @@ geoip_format_entry_stats(time_t now)
tor_assert(now >= start_of_entry_stats_interval);
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &data, NULL);
format_iso_time(t, now);
- tor_asprintf(&result, "entry-stats-end %s (%u s)\nentry-ips %s\n",
- t, (unsigned) (now - start_of_entry_stats_interval),
- data ? data : "");
+ tor_asprintf(&result,
+ "entry-stats-end %s (%u s)\n"
+ "entry-ips %s\n",
+ t, (unsigned) (now - start_of_entry_stats_interval),
+ data ? data : "");
tor_free(data);
return result;
}
@@ -1437,25 +1618,30 @@ getinfo_helper_geoip(control_connection_t *control_conn,
const char **errmsg)
{
(void)control_conn;
- if (!geoip_is_loaded()) {
- *errmsg = "GeoIP data not loaded";
- return -1;
- }
if (!strcmpstart(question, "ip-to-country/")) {
int c;
- uint32_t ip;
- struct in_addr in;
+ sa_family_t family;
+ tor_addr_t addr;
question += strlen("ip-to-country/");
- if (tor_inet_aton(question, &in) != 0) {
- ip = ntohl(in.s_addr);
- c = geoip_get_country_by_ip(ip);
- *answer = tor_strdup(geoip_get_country_name(c));
+ family = tor_addr_parse(&addr, question);
+ if (family != AF_INET && family != AF_INET6) {
+ *errmsg = "Invalid address family";
+ return -1;
}
+ if (!geoip_is_loaded(family)) {
+ *errmsg = "GeoIP data not loaded";
+ return -1;
+ }
+ if (family == AF_INET)
+ c = geoip_get_country_by_ipv4(tor_addr_to_ipv4h(&addr));
+ else /* AF_INET6 */
+ c = geoip_get_country_by_ipv6(tor_addr_to_in6(&addr));
+ *answer = tor_strdup(geoip_get_country_name(c));
}
return 0;
}
-/** Release all storage held by the GeoIP database. */
+/** Release all storage held by the GeoIP databases and country list. */
static void
clear_geoip_db(void)
{
@@ -1465,13 +1651,20 @@ clear_geoip_db(void)
}
strmap_free(country_idxplus1_by_lc_code, NULL);
- if (geoip_entries) {
- SMARTLIST_FOREACH(geoip_entries, geoip_entry_t *, ent, tor_free(ent));
- smartlist_free(geoip_entries);
+ if (geoip_ipv4_entries) {
+ SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, ent,
+ tor_free(ent));
+ smartlist_free(geoip_ipv4_entries);
+ }
+ if (geoip_ipv6_entries) {
+ SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, ent,
+ tor_free(ent));
+ smartlist_free(geoip_ipv6_entries);
}
geoip_countries = NULL;
country_idxplus1_by_lc_code = NULL;
- geoip_entries = NULL;
+ geoip_ipv4_entries = NULL;
+ geoip_ipv6_entries = NULL;
}
/** Release all storage held in this file. */
diff --git a/src/or/geoip.h b/src/or/geoip.h
index 4aed4e07bb..2272486477 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -9,20 +9,21 @@
* \brief Header file for geoip.c.
**/
-#ifndef _TOR_GEOIP_H
-#define _TOR_GEOIP_H
+#ifndef TOR_GEOIP_H
+#define TOR_GEOIP_H
#ifdef GEOIP_PRIVATE
-int geoip_parse_entry(const char *line);
+int geoip_parse_entry(const char *line, sa_family_t family);
+int geoip_get_country_by_ipv4(uint32_t ipaddr);
+int geoip_get_country_by_ipv6(const struct in6_addr *addr);
#endif
int should_record_bridge_info(const or_options_t *options);
-int geoip_load_file(const char *filename, const or_options_t *options);
-int geoip_get_country_by_ip(uint32_t ipaddr);
+int geoip_load_file(sa_family_t family, const char *filename);
int geoip_get_country_by_addr(const tor_addr_t *addr);
int geoip_get_n_countries(void);
const char *geoip_get_country_name(country_t num);
-int geoip_is_loaded(void);
-const char *geoip_db_digest(void);
+int geoip_is_loaded(sa_family_t family);
+const char *geoip_db_digest(sa_family_t family);
country_t geoip_get_country(const char *countrycode);
void geoip_note_client_seen(geoip_client_action_t action,
@@ -31,7 +32,8 @@ void geoip_remove_old_clients(time_t cutoff);
void geoip_note_ns_response(geoip_client_action_t action,
geoip_ns_response_t response);
-char *geoip_get_client_history(geoip_client_action_t action);
+int geoip_get_client_history(geoip_client_action_t action,
+ char **country_str, char **ipver_str);
char *geoip_get_request_history(geoip_client_action_t action);
int getinfo_helper_geoip(control_connection_t *control_conn,
const char *question, char **answer,
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 3a9c1e4224..72089962ae 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -23,12 +23,15 @@ hibernating, phase 2:
#define HIBERNATE_PRIVATE
#include "or.h"
+#include "channel.h"
+#include "channeltls.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "hibernate.h"
#include "main.h"
#include "router.h"
+#include "statefile.h"
extern long stats_n_seconds_working; /* published uptime */
@@ -845,7 +848,13 @@ hibernate_go_dormant(time_t now)
if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */
connection_mark_unattached_ap(TO_ENTRY_CONN(conn),
END_STREAM_REASON_HIBERNATING);
- else
+ else if (conn->type == CONN_TYPE_OR) {
+ if (TO_OR_CONN(conn)->chan) {
+ channel_mark_for_close(TLS_CHAN_TO_BASE(TO_OR_CONN(conn)->chan));
+ } else {
+ connection_mark_for_close(conn);
+ }
+ } else
connection_mark_for_close(conn);
}
@@ -881,12 +890,12 @@ hibernate_end_time_elapsed(time_t now)
/* We weren't sleeping before; we should sleep now. */
log_notice(LD_ACCT,
"Accounting period ended. Commencing hibernation until "
- "%s GMT", buf);
+ "%s UTC", buf);
hibernate_go_dormant(now);
} else {
log_notice(LD_ACCT,
"Accounting period ended. This period, we will hibernate"
- " until %s GMT",buf);
+ " until %s UTC",buf);
}
}
}
diff --git a/src/or/hibernate.h b/src/or/hibernate.h
index 9aa026b7b0..5f99cde015 100644
--- a/src/or/hibernate.h
+++ b/src/or/hibernate.h
@@ -9,8 +9,8 @@
* \brief Header file for hibernate.c.
**/
-#ifndef _TOR_HIBERNATE_H
-#define _TOR_HIBERNATE_H
+#ifndef TOR_HIBERNATE_H
+#define TOR_HIBERNATE_H
int accounting_parse_options(const or_options_t *options, int validate_only);
int accounting_is_enabled(const or_options_t *options);
diff --git a/src/or/include.am b/src/or/include.am
new file mode 100644
index 0000000000..405cbd071f
--- /dev/null
+++ b/src/or/include.am
@@ -0,0 +1,180 @@
+bin_PROGRAMS+= src/or/tor
+noinst_LIBRARIES+= src/or/libtor.a
+
+if BUILD_NT_SERVICES
+tor_platform_source=src/or/ntmain.c
+else
+tor_platform_source=
+endif
+
+EXTRA_DIST+= src/or/ntmain.c src/or/or_sha1.i src/or/Makefile.nmake
+
+if USE_EXTERNAL_EVDNS
+evdns_source=
+else
+evdns_source=src/ext/eventdns.c
+endif
+
+src_or_libtor_a_SOURCES = \
+ src/or/addressmap.c \
+ src/or/buffers.c \
+ src/or/channel.c \
+ src/or/channeltls.c \
+ src/or/circuitbuild.c \
+ src/or/circuitlist.c \
+ src/or/circuitmux.c \
+ src/or/circuitmux_ewma.c \
+ src/or/circuitstats.c \
+ src/or/circuituse.c \
+ src/or/command.c \
+ src/or/config.c \
+ src/or/confparse.c \
+ src/or/connection.c \
+ src/or/connection_edge.c \
+ src/or/connection_or.c \
+ src/or/control.c \
+ src/or/cpuworker.c \
+ src/or/directory.c \
+ src/or/dirserv.c \
+ src/or/dirvote.c \
+ src/or/dns.c \
+ src/or/dnsserv.c \
+ src/or/geoip.c \
+ src/or/entrynodes.c \
+ src/or/hibernate.c \
+ src/or/main.c \
+ src/or/microdesc.c \
+ src/or/networkstatus.c \
+ src/or/nodelist.c \
+ src/or/onion.c \
+ src/or/transports.c \
+ src/or/policies.c \
+ src/or/reasons.c \
+ src/or/relay.c \
+ src/or/rendclient.c \
+ src/or/rendcommon.c \
+ src/or/rendmid.c \
+ src/or/rendservice.c \
+ src/or/rephist.c \
+ src/or/replaycache.c \
+ src/or/router.c \
+ src/or/routerlist.c \
+ src/or/routerparse.c \
+ src/or/routerset.c \
+ src/or/statefile.c \
+ src/or/status.c \
+ $(evdns_source) \
+ $(tor_platform_source) \
+ src/or/config_codedigest.c
+
+#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
+# ../common/libor-event.a
+
+
+src_or_tor_SOURCES = src/or/tor_main.c
+AM_CPPFLAGS += -I$(srcdir)/src/or -Isrc/or
+
+src/or/tor_main.o: micro-revision.i
+
+AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \
+ -DLOCALSTATEDIR="\"$(localstatedir)\"" \
+ -DBINDIR="\"$(bindir)\""
+
+# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
+# This seems to matter nowhere but on windows, but I assure you that it
+# matters a lot there, and is quite hard to debug if you forget to do it.
+
+
+src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
+src_or_tor_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypto.a \
+ src/common/libor-event.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+
+ORHEADERS = \
+ src/or/addressmap.h \
+ src/or/buffers.h \
+ src/or/channel.h \
+ src/or/channeltls.h \
+ src/or/circuitbuild.h \
+ src/or/circuitlist.h \
+ src/or/circuitmux.h \
+ src/or/circuitmux_ewma.h \
+ src/or/circuitstats.h \
+ src/or/circuituse.h \
+ src/or/command.h \
+ src/or/config.h \
+ src/or/confparse.h \
+ src/or/connection.h \
+ src/or/connection_edge.h \
+ src/or/connection_or.h \
+ src/or/control.h \
+ src/or/cpuworker.h \
+ src/or/directory.h \
+ src/or/dirserv.h \
+ src/or/dirvote.h \
+ src/or/dns.h \
+ src/or/dnsserv.h \
+ src/or/eventdns_tor.h \
+ src/or/geoip.h \
+ src/or/entrynodes.h \
+ src/or/hibernate.h \
+ src/or/main.h \
+ src/or/microdesc.h \
+ src/or/networkstatus.h \
+ src/or/nodelist.h \
+ src/or/ntmain.h \
+ src/or/onion.h \
+ src/or/or.h \
+ src/or/transports.h \
+ src/or/policies.h \
+ src/or/reasons.h \
+ src/or/relay.h \
+ src/or/rendclient.h \
+ src/or/rendcommon.h \
+ src/or/rendmid.h \
+ src/or/rendservice.h \
+ src/or/rephist.h \
+ src/or/replaycache.h \
+ src/or/router.h \
+ src/or/routerlist.h \
+ src/or/routerset.h \
+ src/or/routerparse.h \
+ src/or/statefile.h \
+ src/or/status.h
+
+noinst_HEADERS+= $(ORHEADERS) micro-revision.i
+
+src/or/config_codedigest.o: src/or/or_sha1.i
+
+micro-revision.i: FORCE
+ @rm -f micro-revision.tmp; \
+ if test -d "$(top_srcdir)/.git" && \
+ test -x "`which git 2>&1;true`"; then \
+ HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \
+ echo \"$$HASH\" > micro-revision.tmp; \
+ fi; \
+ if test ! -f micro-revision.tmp ; then \
+ if test ! -f micro-revision.i ; then \
+ echo '""' > micro-revision.i; \
+ fi; \
+ elif test ! -f micro-revision.i || \
+ test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \
+ mv micro-revision.tmp micro-revision.i; \
+ fi; true
+
+src/or/or_sha1.i: $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS)
+ $(AM_V_GEN)if test "@SHA1SUM@" != none; then \
+ (cd "$(srcdir)" && "@SHA1SUM@" $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS) ) | \
+ "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > src/or/or_sha1.i; \
+ elif test "@OPENSSL@" != none; then \
+ (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS)) | \
+ "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > src/or/or_sha1.i; \
+ else \
+ rm src/or/or_sha1.i; \
+ touch src/or/or_sha1.i; \
+ fi
+
+CLEANFILES+= micro-revision.i
+
+FORCE:
diff --git a/src/or/main.c b/src/or/main.c
index 34bf3e50f5..abb1e34fcd 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -12,7 +12,10 @@
#define MAIN_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
@@ -28,6 +31,7 @@
#include "dirvote.h"
#include "dns.h"
#include "dnsserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
@@ -46,6 +50,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "statefile.h"
#include "status.h"
#ifdef USE_DMALLOC
#include <dmalloc.h>
@@ -397,6 +402,18 @@ connection_unlink(connection_t *conn)
if (conn->type == CONN_TYPE_OR) {
if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest))
connection_or_remove_from_identity_map(TO_OR_CONN(conn));
+ /* connection_unlink() can only get called if the connection
+ * was already on the closeable list, and it got there by
+ * connection_mark_for_close(), which was called from
+ * connection_or_close_normally() or
+ * connection_or_close_for_error(), so the channel should
+ * already be in CHANNEL_STATE_CLOSING, and then the
+ * connection_about_to_close_connection() goes to
+ * connection_or_about_to_close(), which calls channel_closed()
+ * to notify the channel_t layer, and closed the channel, so
+ * nothing more to do here to deal with the channel associated
+ * with an orconn.
+ */
}
connection_free(conn);
}
@@ -796,7 +813,8 @@ conn_close_if_marked(int i)
}
#endif
- log_debug(LD_NET,"Cleaning up connection (fd %d).",conn->s);
+ log_debug(LD_NET,"Cleaning up connection (fd "TOR_SOCKET_T_FORMAT").",
+ conn->s);
/* If the connection we are about to close was trying to connect to
a proxy server and failed, the client won't be able to use that
@@ -953,7 +971,8 @@ directory_info_has_arrived(time_t now, int from_cache)
const or_options_t *options = get_options();
if (!router_have_minimum_dir_info()) {
- int quiet = directory_too_idle_to_fetch_descriptors(options, now);
+ int quiet = from_cache ||
+ directory_too_idle_to_fetch_descriptors(options, now);
log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
"I learned some more directory information, but not enough to "
"build a circuit: %s", get_dir_info_status_string());
@@ -1044,7 +1063,8 @@ run_connection_housekeeping(int i, time_t now)
tor_assert(conn->outbuf);
#endif
- if (or_conn->is_bad_for_new_circs && !or_conn->n_circuits) {
+ if (channel_is_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan)) &&
+ !connection_or_get_num_circuits(or_conn)) {
/* It's bad for new circuits, and has no unmarked circuits on it:
* mark it now. */
log_info(LD_OR,
@@ -1054,28 +1074,29 @@ run_connection_housekeeping(int i, time_t now)
connection_or_connect_failed(TO_OR_CONN(conn),
END_OR_CONN_REASON_TIMEOUT,
"Tor gave up on the connection");
- connection_mark_and_flush(conn);
+ connection_or_close_normally(TO_OR_CONN(conn), 1);
} else if (!connection_state_is_open(conn)) {
if (past_keepalive) {
/* We never managed to actually get this connection open and happy. */
log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).",
(int)conn->s,conn->address, conn->port);
- connection_mark_for_close(conn);
+ connection_or_close_normally(TO_OR_CONN(conn), 0);
}
- } else if (we_are_hibernating() && !or_conn->n_circuits &&
+ } else if (we_are_hibernating() &&
+ !connection_or_get_num_circuits(or_conn) &&
!connection_get_outbuf_len(conn)) {
/* We're hibernating, there's no circuits, and nothing to flush.*/
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
"[Hibernating or exiting].",
(int)conn->s,conn->address, conn->port);
- connection_mark_and_flush(conn);
- } else if (!or_conn->n_circuits &&
+ connection_or_close_normally(TO_OR_CONN(conn), 1);
+ } else if (!connection_or_get_num_circuits(or_conn) &&
now >= or_conn->timestamp_last_added_nonpadding +
IDLE_OR_CONN_TIMEOUT) {
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
"[idle %d].", (int)conn->s,conn->address, conn->port,
(int)(now - or_conn->timestamp_last_added_nonpadding));
- connection_mark_for_close(conn);
+ connection_or_close_normally(TO_OR_CONN(conn), 0);
} else if (
now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 &&
now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) {
@@ -1085,7 +1106,7 @@ run_connection_housekeeping(int i, time_t now)
(int)conn->s, conn->address, conn->port,
(int)connection_get_outbuf_len(conn),
(int)(now-conn->timestamp_lastwritten));
- connection_mark_for_close(conn);
+ connection_or_close_normally(TO_OR_CONN(conn), 0);
} else if (past_keepalive && !connection_get_outbuf_len(conn)) {
/* send a padding cell */
log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)",
@@ -1519,6 +1540,10 @@ run_scheduled_events(time_t now)
* flush it. */
or_state_save(now);
+ /** 8c. Do channel cleanup just like for connections */
+ channel_run_cleanup();
+ channel_listener_run_cleanup();
+
/** 9. and if we're a server, check whether our DNS is telling stories to
* us. */
if (!net_is_disabled() &&
@@ -1546,11 +1571,15 @@ run_scheduled_events(time_t now)
options->PortForwarding &&
is_server) {
#define PORT_FORWARDING_CHECK_INTERVAL 5
- /* XXXXX this should take a list of ports, not just two! */
- tor_check_port_forwarding(options->PortForwardingHelper,
- get_primary_dir_port(),
- get_primary_or_port(),
- now);
+ smartlist_t *ports_to_forward = get_list_of_ports_to_forward();
+ if (ports_to_forward) {
+ tor_check_port_forwarding(options->PortForwardingHelper,
+ ports_to_forward,
+ now);
+
+ SMARTLIST_FOREACH(ports_to_forward, char *, cp, tor_free(cp));
+ smartlist_free(ports_to_forward);
+ }
time_to_check_port_forwarding = now+PORT_FORWARDING_CHECK_INTERVAL;
}
@@ -1561,7 +1590,8 @@ run_scheduled_events(time_t now)
/** 12. write the heartbeat message */
if (options->HeartbeatPeriod &&
time_to_next_heartbeat <= now) {
- log_heartbeat(now);
+ if (time_to_next_heartbeat) /* don't log the first heartbeat */
+ log_heartbeat(now);
time_to_next_heartbeat = now+options->HeartbeatPeriod;
}
}
@@ -2144,6 +2174,10 @@ dumpstats(int severity)
circuit_dump_by_conn(conn, severity); /* dump info about all the circuits
* using this conn */
} SMARTLIST_FOREACH_END(conn);
+
+ channel_dumpstats(severity);
+ channel_listener_dumpstats(severity);
+
log(severity, LD_NET,
"Cells processed: "U64_FORMAT" padding\n"
" "U64_FORMAT" create\n"
@@ -2286,6 +2320,9 @@ tor_init(int argc, char *argv[])
quiet = 1;
if (!strcmp(argv[i], "--quiet"))
quiet = 2;
+ /* --version implies --quiet */
+ if (!strcmp(argv[i], "--version"))
+ quiet = 2;
}
/* give it somewhere to log to initially */
switch (quiet) {
@@ -2302,12 +2339,17 @@ tor_init(int argc, char *argv[])
{
const char *version = get_version();
+ const char *bev_str =
#ifdef USE_BUFFEREVENTS
- log_notice(LD_GENERAL, "Tor v%s (with bufferevents) running on %s.",
- version, get_uname());
+ "(with bufferevents) ";
#else
- log_notice(LD_GENERAL, "Tor v%s running on %s.", version, get_uname());
+ "";
#endif
+ log_notice(LD_GENERAL, "Tor v%s %srunning on %s with Libevent %s "
+ "and OpenSSL %s.", version, bev_str,
+ get_uname(),
+ tor_libevent_get_version_str(),
+ crypto_openssl_get_version_str());
log_notice(LD_GENERAL, "Tor can't help you if you use it wrong! "
"Learn how to be safe at "
@@ -2441,6 +2483,8 @@ tor_free_all(int postfork)
circuit_free_all();
entry_guards_free_all();
pt_free_all();
+ channel_tls_free_all();
+ channel_free_all();
connection_free_all();
buf_shrink_freelists(1);
memarea_clear_freelist();
@@ -2448,6 +2492,7 @@ tor_free_all(int postfork)
microdesc_free_all();
if (!postfork) {
config_free_all();
+ or_state_free_all();
router_free_all();
policies_free_all();
}
@@ -2461,6 +2506,10 @@ tor_free_all(int postfork)
smartlist_free(closeable_connection_lst);
smartlist_free(active_linked_connection_lst);
periodic_timer_free(second_timer);
+#ifndef USE_BUFFEREVENTS
+ periodic_timer_free(refill_timer);
+#endif
+
if (!postfork) {
release_lockfile();
}
@@ -2631,7 +2680,7 @@ tor_main(int argc, char *argv[])
{
/* Instruct OpenSSL to use our internal wrappers for malloc,
realloc and free. */
- int r = CRYPTO_set_mem_ex_functions(_tor_malloc, _tor_realloc, _tor_free);
+ int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
tor_assert(r);
}
#endif
diff --git a/src/or/main.h b/src/or/main.h
index f843b6f9fc..da2bcfd493 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -9,8 +9,8 @@
* \brief Header file for main.c.
**/
-#ifndef _TOR_MAIN_H
-#define _TOR_MAIN_H
+#ifndef TOR_MAIN_H
+#define TOR_MAIN_H
extern int can_complete_circuit;
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index b4d22c1c62..7602a93457 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -6,6 +6,7 @@
#include "config.h"
#include "directory.h"
#include "dirserv.h"
+#include "entrynodes.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
@@ -42,7 +43,7 @@ struct microdesc_cache_t {
/** Helper: computes a hash of <b>md</b> to place it in a hash table. */
static INLINE unsigned int
-_microdesc_hash(microdesc_t *md)
+microdesc_hash_(microdesc_t *md)
{
unsigned *d = (unsigned*)md->digest;
#if SIZEOF_INT == 4
@@ -54,15 +55,15 @@ _microdesc_hash(microdesc_t *md)
/** Helper: compares <b>a</b> and </b> for equality for hash-table purposes. */
static INLINE int
-_microdesc_eq(microdesc_t *a, microdesc_t *b)
+microdesc_eq_(microdesc_t *a, microdesc_t *b)
{
return tor_memeq(a->digest, b->digest, DIGEST256_LEN);
}
HT_PROTOTYPE(microdesc_map, microdesc_t, node,
- _microdesc_hash, _microdesc_eq);
+ microdesc_hash_, microdesc_eq_);
HT_GENERATE(microdesc_map, microdesc_t, node,
- _microdesc_hash, _microdesc_eq, 0.6,
+ microdesc_hash_, microdesc_eq_, 0.6,
malloc, realloc, free);
/** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
@@ -74,7 +75,7 @@ dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
{
ssize_t r = 0;
size_t written;
- /* XXXX drops unkown annotations. */
+ /* XXXX drops unknown annotations. */
if (md->last_listed) {
char buf[ISO_TIME_LEN+1];
char annotation[ISO_TIME_LEN+32];
@@ -131,7 +132,7 @@ get_microdesc_cache(void)
*/
/** Decode the microdescriptors from the string starting at <b>s</b> and
- * ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no-save</b>,
+ * ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no_save</b>,
* mark them as non-writable to disk. If <b>where</b> is SAVED_IN_CACHE,
* leave their bodies as pointers to the mmap'd cache. If where is
* <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is positive,
@@ -159,7 +160,7 @@ microdescs_add_to_cache(microdesc_cache_t *cache,
md->last_listed = listed_at);
}
if (requested_digests256) {
- digestmap_t *requested; /* XXXX actuqlly we should just use a
+ digestmap_t *requested; /* XXXX actually we should just use a
digest256map */
requested = digestmap_new();
SMARTLIST_FOREACH(requested_digests256, const char *, cp,
@@ -168,7 +169,7 @@ microdescs_add_to_cache(microdesc_cache_t *cache,
if (digestmap_get(requested, md->digest)) {
digestmap_set(requested, md->digest, (void*)2);
} else {
- log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Received non-requested microcdesc");
+ log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Received non-requested microdesc");
microdesc_free(md);
SMARTLIST_DEL_CURRENT(descriptors, md);
}
@@ -187,7 +188,7 @@ microdescs_add_to_cache(microdesc_cache_t *cache,
return added;
}
-/** As microdescs_add_to_cache, but takes a list of micrdescriptors instead of
+/** As microdescs_add_to_cache, but takes a list of microdescriptors instead of
* a string to decode. Frees any members of <b>descriptors</b> that it does
* not add. */
smartlist_t *
@@ -231,7 +232,7 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
size_t annotation_len;
size = dump_microdescriptor(f, md, &annotation_len);
if (size < 0) {
- /* we already warned in dump_microdescriptor; */
+ /* we already warned in dump_microdescriptor */
abort_writing_to_file(open_file);
smartlist_clear(added);
return added;
@@ -323,8 +324,8 @@ microdesc_cache_reload(microdesc_cache_t *cache)
}
tor_free(journal_content);
}
- log_notice(LD_DIR, "Reloaded microdescriptor cache. Found %d descriptors.",
- total);
+ log_info(LD_DIR, "Reloaded microdescriptor cache. Found %d descriptors.",
+ total);
microdesc_cache_rebuild(cache, 0 /* don't force */);
@@ -582,6 +583,7 @@ microdesc_free(microdesc_t *md)
smartlist_free(md->family);
}
short_policy_free(md->exit_policy);
+ short_policy_free(md->ipv6_exit_policy);
tor_free(md);
}
diff --git a/src/or/microdesc.h b/src/or/microdesc.h
index 5646fc7a85..4b18caaae0 100644
--- a/src/or/microdesc.h
+++ b/src/or/microdesc.h
@@ -9,8 +9,8 @@
* \brief Header file for microdesc.c.
**/
-#ifndef _TOR_MICRODESC_H
-#define _TOR_MICRODESC_H
+#ifndef TOR_MICRODESC_H
+#define TOR_MICRODESC_H
microdesc_cache_t *get_microdesc_cache(void);
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 2553a74e50..9d402403c0 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -11,7 +11,10 @@
*/
#include "or.h"
-#include "circuitbuild.h"
+#include "channel.h"
+#include "circuitmux.h"
+#include "circuitmux_ewma.h"
+#include "circuitstats.h"
#include "config.h"
#include "connection.h"
#include "connection_or.h"
@@ -19,6 +22,7 @@
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
+#include "entrynodes.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@@ -215,8 +219,6 @@ router_reload_consensus_networkstatus(void)
{
char *filename;
char *s;
- struct stat st;
- const or_options_t *options = get_options();
const unsigned int flags = NSSET_FROM_CACHE | NSSET_DONT_DOWNLOAD_CERTS;
int flav;
@@ -259,25 +261,6 @@ router_reload_consensus_networkstatus(void)
tor_free(filename);
}
- if (!current_consensus ||
- (stat(options->FallbackNetworkstatusFile, &st)==0 &&
- st.st_mtime > current_consensus->valid_after)) {
- s = read_file_to_str(options->FallbackNetworkstatusFile,
- RFTS_IGNORE_MISSING, NULL);
- if (s) {
- if (networkstatus_set_current_consensus(s, "ns",
- flags|NSSET_ACCEPT_OBSOLETE)) {
- log_info(LD_FS, "Couldn't load consensus networkstatus from \"%s\"",
- options->FallbackNetworkstatusFile);
- } else {
- log_notice(LD_FS,
- "Loaded fallback consensus networkstatus from \"%s\"",
- options->FallbackNetworkstatusFile);
- }
- tor_free(s);
- }
- }
-
if (!current_consensus) {
if (!named_server_map)
named_server_map = strmap_new();
@@ -561,7 +544,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
/* Now see whether we're missing any voters entirely. */
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
{
if ((ds->type & V3_DIRINFO) &&
!networkstatus_get_voter_by_id(consensus, ds->v3_identity_digest))
@@ -593,7 +576,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
voter->contact?voter->contact:"n/a",
hex_str(voter->identity_digest, DIGEST_LEN));
});
- SMARTLIST_FOREACH(missing_authorities, trusted_dir_server_t *, ds,
+ SMARTLIST_FOREACH(missing_authorities, dir_server_t *, ds,
{
log(severity, LD_DIR, "Consensus does not include configured "
"authority '%s' at %s:%d (identity %s)",
@@ -667,7 +650,7 @@ networkstatus_get_cache_filename(const char *identity_digest)
/** Helper for smartlist_sort: Compare two networkstatus objects by
* publication date. */
static int
-_compare_networkstatus_v2_published_on(const void **_a, const void **_b)
+compare_networkstatus_v2_published_on_(const void **_a, const void **_b)
{
const networkstatus_v2_t *a = *_a, *b = *_b;
if (a->published_on < b->published_on)
@@ -735,7 +718,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at,
int i, found;
time_t now;
int skewed = 0;
- trusted_dir_server_t *trusted_dir = NULL;
+ dir_server_t *trusted_dir = NULL;
const char *source_desc = NULL;
char fp[HEX_DIGEST_LEN+1];
char published[ISO_TIME_LEN+1];
@@ -771,7 +754,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at,
long delta = now - ns->published_on;
format_time_interval(dbuf, sizeof(dbuf), delta);
log_warn(LD_GENERAL, "Network status from %s was published %s in the "
- "future (%s GMT). Check your time and date settings! "
+ "future (%s UTC). Check your time and date settings! "
"Not caching.",
source_desc, dbuf, published);
control_event_general_status(LOG_WARN,
@@ -901,7 +884,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at,
networkstatus_v2_list_has_changed = 1;
smartlist_sort(networkstatus_v2_list,
- _compare_networkstatus_v2_published_on);
+ compare_networkstatus_v2_published_on_);
if (!skewed)
add_networkstatus_to_cache(s, source, ns);
@@ -1140,7 +1123,7 @@ update_v2_networkstatus_cache_downloads(time_t now)
if (authority) {
/* An authority launches a separate connection for everybody. */
- SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, ds)
+ SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ds)
{
char resource[HEX_DIGEST_LEN+6]; /* fp/hexdigit.z\0 */
tor_addr_t addr;
@@ -1168,7 +1151,7 @@ update_v2_networkstatus_cache_downloads(time_t now)
directory_initiate_command_routerstatus(
&ds->fake_status, DIR_PURPOSE_FETCH_V2_NETWORKSTATUS,
ROUTER_PURPOSE_GENERAL,
- 0, /* Not private */
+ DIRIND_ONEHOP,
resource,
NULL, 0 /* No payload. */,
0 /* No I-M-S. */);
@@ -1530,13 +1513,7 @@ routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b)
a->is_bad_exit != b->is_bad_exit ||
a->is_bad_directory != b->is_bad_directory ||
a->is_hs_dir != b->is_hs_dir ||
- a->version_known != b->version_known ||
- a->version_supports_begindir != b->version_supports_begindir ||
- a->version_supports_extrainfo_upload !=
- b->version_supports_extrainfo_upload ||
- a->version_supports_conditional_consensus !=
- b->version_supports_conditional_consensus ||
- a->version_supports_v3_dir != b->version_supports_v3_dir;
+ a->version_known != b->version_known;
}
/** Notify controllers of any router status entries that changed between
@@ -1640,6 +1617,7 @@ networkstatus_set_current_consensus(const char *consensus,
consensus_waiting_for_certs_t *waiting = NULL;
time_t current_valid_after = 0;
int free_consensus = 1; /* Free 'c' at the end of the function */
+ int old_ewma_enabled;
if (flav < 0) {
/* XXXX we don't handle unrecognized flavors yet. */
@@ -1675,9 +1653,6 @@ networkstatus_set_current_consensus(const char *consensus,
if (from_cache && !accept_obsolete &&
c->valid_until < now-OLD_ROUTER_DESC_MAX_AGE) {
- /* XXXX If we try to make fallbackconsensus work again, we should
- * consider taking this out. Until then, believing obsolete consensuses
- * is causing more harm than good. See also bug 887. */
log_info(LD_DIR, "Loaded an expired consensus. Discarding.");
goto done;
}
@@ -1833,7 +1808,18 @@ networkstatus_set_current_consensus(const char *consensus,
dirvote_recalculate_timing(options, now);
routerstatus_list_update_named_server_map();
- cell_ewma_set_scale_factor(options, current_consensus);
+
+ /* Update ewma and adjust policy if needed; first cache the old value */
+ old_ewma_enabled = cell_ewma_enabled();
+ /* Change the cell EWMA settings */
+ cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
+ /* If we just enabled ewma, set the cmux policy on all active channels */
+ if (cell_ewma_enabled() && !old_ewma_enabled) {
+ channel_set_cmux_policy_everywhere(&ewma_policy);
+ } else if (!cell_ewma_enabled() && old_ewma_enabled) {
+ /* Turn it off everywhere */
+ channel_set_cmux_policy_everywhere(NULL);
+ }
/* XXXX024 this call might be unnecessary here: can changing the
* current consensus really alter our view of any OR's rate limits? */
@@ -1864,7 +1850,7 @@ networkstatus_set_current_consensus(const char *consensus,
format_iso_time(tbuf, c->valid_after);
format_time_interval(dbuf, sizeof(dbuf), delta);
log_warn(LD_GENERAL, "Our clock is %s behind the time published in the "
- "consensus network status document (%s GMT). Tor needs an "
+ "consensus network status document (%s UTC). Tor needs an "
"accurate clock to work correctly. Please check your time and "
"date settings!", dbuf, tbuf);
control_event_general_status(LOG_WARN,
@@ -1996,7 +1982,7 @@ download_status_map_update_from_v2_networkstatus(void)
digestmap_set(dl_status, d, s);
} SMARTLIST_FOREACH_END(rs);
} SMARTLIST_FOREACH_END(ns);
- digestmap_free(v2_download_status_map, _tor_free);
+ digestmap_free(v2_download_status_map, tor_free_);
v2_download_status_map = dl_status;
networkstatus_v2_list_has_changed = 0;
}
@@ -2009,7 +1995,7 @@ routerstatus_list_update_named_server_map(void)
if (!current_consensus)
return;
- strmap_free(named_server_map, _tor_free);
+ strmap_free(named_server_map, tor_free_);
named_server_map = strmap_new();
strmap_free(unnamed_server_map, NULL);
unnamed_server_map = strmap_new();
@@ -2032,7 +2018,7 @@ void
routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
int reset_failures)
{
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
const or_options_t *options = get_options();
int authdir = authdir_mode_v2(options) || authdir_mode_v3(options);
networkstatus_t *ns = current_consensus;
@@ -2052,7 +2038,7 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
/* We have a routerstatus for this router. */
const char *digest = router->cache_info.identity_digest;
- ds = router_get_trusteddirserver_by_digest(digest);
+ ds = router_get_fallback_dirserver_by_digest(digest);
/* Is it the same descriptor, or only the same identity? */
if (tor_memeq(router->cache_info.signed_descriptor_digest,
@@ -2310,6 +2296,30 @@ networkstatus_parse_flavor_name(const char *flavname)
return -1;
}
+/** Return 0 if this routerstatus is obsolete, too new, isn't
+ * running, or otherwise not a descriptor that we would make any
+ * use of even if we had it. Else return 1. */
+int
+client_would_use_router(const routerstatus_t *rs, time_t now,
+ const or_options_t *options)
+{
+ if (!rs->is_flagged_running && !options->FetchUselessDescriptors) {
+ /* If we had this router descriptor, we wouldn't even bother using it.
+ * But, if we want to have a complete list, fetch it anyway. */
+ return 0;
+ }
+ if (rs->published_on + options->TestingEstimatedDescriptorPropagationTime
+ > now) {
+ /* Most caches probably don't have this descriptor yet. */
+ return 0;
+ }
+ if (rs->published_on + OLD_ROUTER_DESC_MAX_AGE < now) {
+ /* We'd drop it immediately for being too old. */
+ return 0;
+ }
+ return 1;
+}
+
/** If <b>question</b> is a string beginning with "ns/" in a format the
* control interface expects for a GETINFO question, set *<b>answer</b> to a
* newly-allocated string containing networkstatus lines for the appropriate
@@ -2340,8 +2350,11 @@ getinfo_helper_networkstatus(control_connection_t *conn,
return 0;
} else if (!strcmpstart(question, "ns/id/")) {
char d[DIGEST_LEN];
+ const char *q = question + 6;
+ if (*q == '$')
+ ++q;
- if (base16_decode(d, DIGEST_LEN, question+6, strlen(question+6))) {
+ if (base16_decode(d, DIGEST_LEN, q, strlen(q))) {
*errmsg = "Data not decodeable as hex";
return -1;
}
@@ -2372,7 +2385,7 @@ networkstatus_free_all(void)
networkstatus_v2_list = NULL;
}
- digestmap_free(v2_download_status_map, _tor_free);
+ digestmap_free(v2_download_status_map, tor_free_);
v2_download_status_map = NULL;
networkstatus_vote_free(current_ns_consensus);
networkstatus_vote_free(current_md_consensus);
@@ -2387,7 +2400,7 @@ networkstatus_free_all(void)
tor_free(waiting->body);
}
- strmap_free(named_server_map, _tor_free);
+ strmap_free(named_server_map, tor_free_);
strmap_free(unnamed_server_map, NULL);
}
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index 0af17512dd..fe16f33918 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -9,8 +9,8 @@
* \brief Header file for networkstatus.c.
**/
-#ifndef _TOR_NETWORKSTATUS_H
-#define _TOR_NETWORKSTATUS_H
+#ifndef TOR_NETWORKSTATUS_H
+#define TOR_NETWORKSTATUS_H
/** How old do we allow a v2 network-status to get before removing it
* completely? */
@@ -71,6 +71,8 @@ int should_delay_dir_fetches(const or_options_t *options);
void update_networkstatus_downloads(time_t now);
void update_certificate_downloads(time_t now);
int consensus_is_waiting_for_certs(void);
+int client_would_use_router(const routerstatus_t *rs, time_t now,
+ const or_options_t *options);
networkstatus_v2_t *networkstatus_v2_get_by_digest(const char *digest);
networkstatus_t *networkstatus_get_latest_consensus(void);
networkstatus_t *networkstatus_get_latest_consensus_by_flavor(
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index d17850888d..4f1e95064d 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -5,19 +5,26 @@
/* See LICENSE for licensing information */
#include "or.h"
+#include "address.h"
#include "config.h"
+#include "control.h"
#include "dirserv.h"
+#include "geoip.h"
+#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
+#include "rendservice.h"
#include "router.h"
#include "routerlist.h"
+#include "routerset.h"
#include <string.h>
static void nodelist_drop_node(node_t *node, int remove_from_ht);
static void node_free(node_t *node);
+static void update_router_have_minimum_dir_info(void);
/** A nodelist_t holds a node_t object for every router we're "willing to use
* for something". Specifically, it should hold a node_t for every node that
@@ -115,19 +122,47 @@ node_get_or_create(const char *identity_digest)
return node;
}
-/** Add <b>ri</b> to the nodelist. */
+/** Called when a node's address changes. */
+static void
+node_addrs_changed(node_t *node)
+{
+ node->last_reachable = node->last_reachable6 = 0;
+ node->country = -1;
+}
+
+/** Add <b>ri</b> to an appropriate node in the nodelist. If we replace an
+ * old routerinfo, and <b>ri_old_out</b> is not NULL, set *<b>ri_old_out</b>
+ * to the previous routerinfo.
+ */
node_t *
-nodelist_add_routerinfo(routerinfo_t *ri)
+nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out)
{
node_t *node;
+ const char *id_digest;
+ int had_router = 0;
+ tor_assert(ri);
+
init_nodelist();
- node = node_get_or_create(ri->cache_info.identity_digest);
+ id_digest = ri->cache_info.identity_digest;
+ node = node_get_or_create(id_digest);
+
+ if (node->ri) {
+ if (!routers_have_same_or_addrs(node->ri, ri)) {
+ node_addrs_changed(node);
+ }
+ had_router = 1;
+ if (ri_old_out)
+ *ri_old_out = node->ri;
+ } else {
+ if (ri_old_out)
+ *ri_old_out = NULL;
+ }
node->ri = ri;
if (node->country == -1)
node_set_country(node);
- if (authdir_mode(get_options())) {
+ if (authdir_mode(get_options()) && !had_router) {
const char *discard=NULL;
uint32_t status = dirserv_router_get_status(ri, &discard);
dirserv_set_node_flags_from_authoritative_status(node, status);
@@ -167,7 +202,7 @@ nodelist_add_microdesc(microdesc_t *md)
return node;
}
-/** Tell the nodelist that the current usable consensus to <b>ns</b>.
+/** Tell the nodelist that the current usable consensus is <b>ns</b>.
* This makes the nodelist change all of the routerstatus entries for
* the nodes, drop nodes that no longer have enough info to get used,
* and grab microdescriptors into nodes as appropriate.
@@ -177,6 +212,7 @@ nodelist_set_consensus(networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v2(options) || authdir_mode_v3(options);
+ int client = !server_mode(options);
init_nodelist();
if (ns->flavor == FLAV_MICRODESC)
@@ -213,6 +249,11 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_bad_directory = rs->is_bad_directory;
node->is_bad_exit = rs->is_bad_exit;
node->is_hs_dir = rs->is_hs_dir;
+ node->ipv6_preferred = 0;
+ if (client && options->ClientPreferIPv6ORPort == 1 &&
+ (tor_addr_is_null(&rs->ipv6_addr) == 0 ||
+ (node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
+ node->ipv6_preferred = 1;
}
} SMARTLIST_FOREACH_END(rs);
@@ -231,7 +272,8 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_valid = node->is_running = node->is_hs_dir =
node->is_fast = node->is_stable =
node->is_possible_guard = node->is_exit =
- node->is_bad_exit = node->is_bad_directory = 0;
+ node->is_bad_exit = node->is_bad_directory =
+ node->ipv6_preferred = 0;
}
}
} SMARTLIST_FOREACH_END(node);
@@ -582,7 +624,7 @@ node_is_dir(const node_t *node)
}
/** Return true iff <b>node</b> has either kind of usable descriptor -- that
- * is, a routerdecriptor or a microdescriptor. */
+ * is, a routerdescriptor or a microdescriptor. */
int
node_has_descriptor(const node_t *node)
{
@@ -682,19 +724,6 @@ node_get_all_orports(const node_t *node)
return sl;
}
-/** Copy the primary (IPv4) OR port (IP address and TCP port) for
- * <b>node</b> into *<b>ap_out</b>. */
-void
-node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
-{
- if (node->ri) {
- router_get_prim_orport(node->ri, ap_out);
- } else if (node->rs) {
- tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
- ap_out->port = node->rs->or_port;
- }
-}
-
/** Wrapper around node_get_prim_orport for backward
compatibility. */
void
@@ -718,36 +747,6 @@ node_get_prim_addr_ipv4h(const node_t *node)
return 0;
}
-/** Copy the preferred OR port (IP address and TCP port) for
- * <b>node</b> into <b>ap_out</b>. */
-void
-node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out)
-{
- if (node->ri) {
- router_get_pref_orport(node->ri, ap_out);
- } else if (node->rs) {
- /* No IPv6 in routerstatus_t yet. XXXprop186 ok for private
- bridges but needs fixing */
- tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
- ap_out->port = node->rs->or_port;
- }
-}
-
-/** Copy the preferred IPv6 OR port (address and TCP port) for
- * <b>node</b> into *<b>ap_out</b>. */
-void
-node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
-{
- if (node->ri) {
- router_get_pref_ipv6_orport(node->ri, ap_out);
- } else if (node->rs) {
- /* No IPv6 in routerstatus_t yet. XXXprop186 ok for private
- bridges but needs fixing */
- tor_addr_make_unspec(&ap_out->addr);
- ap_out->port = 0;
- }
-}
-
/** Copy a string representation of an IP address for <b>node</b> into
* the <b>len</b>-byte buffer at <b>buf</b>. */
void
@@ -818,3 +817,604 @@ node_get_declared_family(const node_t *node)
return NULL;
}
+/** Return 1 if we prefer the IPv6 address and OR TCP port of
+ * <b>node</b>, else 0.
+ *
+ * We prefer the IPv6 address if the router has an IPv6 address and
+ * i) the node_t says that it prefers IPv6
+ * or
+ * ii) the router has no IPv4 address. */
+int
+node_ipv6_preferred(const node_t *node)
+{
+ tor_addr_port_t ipv4_addr;
+ node_assert_ok(node);
+
+ if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) {
+ if (node->ri)
+ return !tor_addr_is_null(&node->ri->ipv6_addr);
+ if (node->md)
+ return !tor_addr_is_null(&node->md->ipv6_addr);
+ if (node->rs)
+ return !tor_addr_is_null(&node->rs->ipv6_addr);
+ }
+ return 0;
+}
+
+/** Copy the primary (IPv4) OR port (IP address and TCP port) for
+ * <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
+ * port was copied, else return non-zero.*/
+int
+node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
+{
+ node_assert_ok(node);
+ tor_assert(ap_out);
+
+ if (node->ri) {
+ if (node->ri->addr == 0 || node->ri->or_port == 0)
+ return -1;
+ tor_addr_from_ipv4h(&ap_out->addr, node->ri->addr);
+ ap_out->port = node->ri->or_port;
+ return 0;
+ }
+ if (node->rs) {
+ if (node->rs->addr == 0 || node->rs->or_port == 0)
+ return -1;
+ tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
+ ap_out->port = node->rs->or_port;
+ return 0;
+ }
+ return -1;
+}
+
+/** Copy the preferred OR port (IP address and TCP port) for
+ * <b>node</b> into *<b>ap_out</b>. */
+void
+node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out)
+{
+ const or_options_t *options = get_options();
+ tor_assert(ap_out);
+
+ /* Cheap implementation of config option ClientUseIPv6 -- simply
+ don't prefer IPv6 when ClientUseIPv6 is not set and we're not a
+ client running with bridges. See #4455 for more on this subject.
+
+ Note that this filter is too strict since we're hindering not
+ only clients! Erring on the safe side shouldn't be a problem
+ though. XXX move this check to where outgoing connections are
+ made? -LN */
+ if ((options->ClientUseIPv6 || options->UseBridges) &&
+ node_ipv6_preferred(node)) {
+ node_get_pref_ipv6_orport(node, ap_out);
+ } else {
+ node_get_prim_orport(node, ap_out);
+ }
+}
+
+/** Copy the preferred IPv6 OR port (IP address and TCP port) for
+ * <b>node</b> into *<b>ap_out</b>. */
+void
+node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
+{
+ node_assert_ok(node);
+ tor_assert(ap_out);
+
+ /* We prefer the microdesc over a potential routerstatus here. They
+ are not being synchronised atm so there might be a chance that
+ they differ at some point, f.ex. when flipping
+ UseMicrodescriptors? -LN */
+
+ if (node->ri) {
+ tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
+ ap_out->port = node->ri->ipv6_orport;
+ } else if (node->md) {
+ tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr);
+ ap_out->port = node->md->ipv6_orport;
+ } else if (node->rs) {
+ tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
+ ap_out->port = node->rs->ipv6_orport;
+ }
+}
+
+/** Refresh the country code of <b>ri</b>. This function MUST be called on
+ * each router when the GeoIP database is reloaded, and on all new routers. */
+void
+node_set_country(node_t *node)
+{
+ tor_addr_t addr = TOR_ADDR_NULL;
+
+ /* XXXXipv6 */
+ if (node->rs)
+ tor_addr_from_ipv4h(&addr, node->rs->addr);
+ else if (node->ri)
+ tor_addr_from_ipv4h(&addr, node->ri->addr);
+
+ node->country = geoip_get_country_by_addr(&addr);
+}
+
+/** Set the country code of all routers in the routerlist. */
+void
+nodelist_refresh_countries(void)
+{
+ smartlist_t *nodes = nodelist_get_list();
+ SMARTLIST_FOREACH(nodes, node_t *, node,
+ node_set_country(node));
+}
+
+/** Return true iff router1 and router2 have similar enough network addresses
+ * that we should treat them as being in the same family */
+static INLINE int
+addrs_in_same_network_family(const tor_addr_t *a1,
+ const tor_addr_t *a2)
+{
+ return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC);
+}
+
+/** Return true if <b>node</b>'s nickname matches <b>nickname</b>
+ * (case-insensitive), or if <b>node's</b> identity key digest
+ * matches a hexadecimal value stored in <b>nickname</b>. Return
+ * false otherwise. */
+static int
+node_nickname_matches(const node_t *node, const char *nickname)
+{
+ const char *n = node_get_nickname(node);
+ if (n && nickname[0]!='$' && !strcasecmp(n, nickname))
+ return 1;
+ return hex_digest_nickname_matches(nickname,
+ node->identity,
+ n,
+ node_is_named(node));
+}
+
+/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */
+static INLINE int
+node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
+{
+ if (!lst) return 0;
+ SMARTLIST_FOREACH(lst, const char *, name, {
+ if (node_nickname_matches(node, name))
+ return 1;
+ });
+ return 0;
+}
+
+/** Return true iff r1 and r2 are in the same family, but not the same
+ * router. */
+int
+nodes_in_same_family(const node_t *node1, const node_t *node2)
+{
+ const or_options_t *options = get_options();
+
+ /* Are they in the same family because of their addresses? */
+ if (options->EnforceDistinctSubnets) {
+ tor_addr_t a1, a2;
+ node_get_addr(node1, &a1);
+ node_get_addr(node2, &a2);
+ if (addrs_in_same_network_family(&a1, &a2))
+ return 1;
+ }
+
+ /* Are they in the same family because the agree they are? */
+ {
+ const smartlist_t *f1, *f2;
+ f1 = node_get_declared_family(node1);
+ f2 = node_get_declared_family(node2);
+ if (f1 && f2 &&
+ node_in_nickname_smartlist(f1, node2) &&
+ node_in_nickname_smartlist(f2, node1))
+ return 1;
+ }
+
+ /* Are they in the same option because the user says they are? */
+ if (options->NodeFamilySets) {
+ SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
+ if (routerset_contains_node(rs, node1) &&
+ routerset_contains_node(rs, node2))
+ return 1;
+ });
+ }
+
+ return 0;
+}
+
+/**
+ * Add all the family of <b>node</b>, including <b>node</b> itself, to
+ * the smartlist <b>sl</b>.
+ *
+ * This is used to make sure we don't pick siblings in a single path, or
+ * pick more than one relay from a family for our entry guard list.
+ * Note that a node may be added to <b>sl</b> more than once if it is
+ * part of <b>node</b>'s family for more than one reason.
+ */
+void
+nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
+{
+ const smartlist_t *all_nodes = nodelist_get_list();
+ const smartlist_t *declared_family;
+ const or_options_t *options = get_options();
+
+ tor_assert(node);
+
+ declared_family = node_get_declared_family(node);
+
+ /* Let's make sure that we have the node itself, if it's a real node. */
+ {
+ const node_t *real_node = node_get_by_id(node->identity);
+ if (real_node)
+ smartlist_add(sl, (node_t*)real_node);
+ }
+
+ /* First, add any nodes with similar network addresses. */
+ if (options->EnforceDistinctSubnets) {
+ tor_addr_t node_addr;
+ node_get_addr(node, &node_addr);
+
+ SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) {
+ tor_addr_t a;
+ node_get_addr(node2, &a);
+ if (addrs_in_same_network_family(&a, &node_addr))
+ smartlist_add(sl, (void*)node2);
+ } SMARTLIST_FOREACH_END(node2);
+ }
+
+ /* Now, add all nodes in the declared_family of this node, if they
+ * also declare this node to be in their family. */
+ if (declared_family) {
+ /* Add every r such that router declares familyness with node, and node
+ * declares familyhood with router. */
+ SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) {
+ const node_t *node2;
+ const smartlist_t *family2;
+ if (!(node2 = node_get_by_nickname(name, 0)))
+ continue;
+ if (!(family2 = node_get_declared_family(node2)))
+ continue;
+ SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) {
+ if (node_nickname_matches(node, name2)) {
+ smartlist_add(sl, (void*)node2);
+ break;
+ }
+ } SMARTLIST_FOREACH_END(name2);
+ } SMARTLIST_FOREACH_END(name);
+ }
+
+ /* If the user declared any families locally, honor those too. */
+ if (options->NodeFamilySets) {
+ SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
+ if (routerset_contains_node(rs, node)) {
+ routerset_get_all_nodes(sl, rs, NULL, 0);
+ }
+ });
+ }
+}
+
+/** Find a router that's up, that has this IP address, and
+ * that allows exit to this address:port, or return NULL if there
+ * isn't a good one.
+ * Don't exit enclave to excluded relays -- it wouldn't actually
+ * hurt anything, but this way there are fewer confused users.
+ */
+const node_t *
+router_find_exact_exit_enclave(const char *address, uint16_t port)
+{/*XXXX MOVE*/
+ uint32_t addr;
+ struct in_addr in;
+ tor_addr_t a;
+ const or_options_t *options = get_options();
+
+ if (!tor_inet_aton(address, &in))
+ return NULL; /* it's not an IP already */
+ addr = ntohl(in.s_addr);
+
+ tor_addr_from_ipv4h(&a, addr);
+
+ SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
+ if (node_get_addr_ipv4h(node) == addr &&
+ node->is_running &&
+ compare_tor_addr_to_node_policy(&a, port, node) ==
+ ADDR_POLICY_ACCEPTED &&
+ !routerset_contains_node(options->ExcludeExitNodesUnion_, node))
+ return node;
+ });
+ return NULL;
+}
+
+/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
+ * If <b>need_uptime</b> is non-zero, we require a minimum uptime.
+ * If <b>need_capacity</b> is non-zero, we require a minimum advertised
+ * bandwidth.
+ * If <b>need_guard</b>, we require that the router is a possible entry guard.
+ */
+int
+node_is_unreliable(const node_t *node, int need_uptime,
+ int need_capacity, int need_guard)
+{
+ if (need_uptime && !node->is_stable)
+ return 1;
+ if (need_capacity && !node->is_fast)
+ return 1;
+ if (need_guard && !node->is_possible_guard)
+ return 1;
+ return 0;
+}
+
+/** Return 1 if all running sufficiently-stable routers we can use will reject
+ * addr:port. Return 0 if any might accept it. */
+int
+router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
+ int need_uptime)
+{
+ addr_policy_result_t r;
+
+ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
+ if (node->is_running &&
+ !node_is_unreliable(node, need_uptime, 0, 0)) {
+
+ r = compare_tor_addr_to_node_policy(addr, port, node);
+
+ if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
+ return 0; /* this one could be ok. good enough. */
+ }
+ } SMARTLIST_FOREACH_END(node);
+ return 1; /* all will reject. */
+}
+
+/** Mark the router with ID <b>digest</b> as running or non-running
+ * in our routerlist. */
+void
+router_set_status(const char *digest, int up)
+{
+ node_t *node;
+ tor_assert(digest);
+
+ SMARTLIST_FOREACH(router_get_fallback_dir_servers(),
+ dir_server_t *, d,
+ if (tor_memeq(d->digest, digest, DIGEST_LEN))
+ d->is_running = up);
+
+ SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
+ dir_server_t *, d,
+ if (tor_memeq(d->digest, digest, DIGEST_LEN))
+ d->is_running = up);
+
+ node = node_get_mutable_by_id(digest);
+ if (node) {
+#if 0
+ log_debug(LD_DIR,"Marking router %s as %s.",
+ node_describe(node), up ? "up" : "down");
+#endif
+ if (!up && node_is_me(node) && !net_is_disabled())
+ log_warn(LD_NET, "We just marked ourself as down. Are your external "
+ "addresses reachable?");
+ node->is_running = up;
+ }
+
+ router_dir_info_changed();
+}
+
+/** True iff, the last time we checked whether we had enough directory info
+ * to build circuits, the answer was "yes". */
+static int have_min_dir_info = 0;
+/** True iff enough has changed since the last time we checked whether we had
+ * enough directory info to build circuits that our old answer can no longer
+ * be trusted. */
+static int need_to_update_have_min_dir_info = 1;
+/** String describing what we're missing before we have enough directory
+ * info. */
+static char dir_info_status[128] = "";
+
+/** Return true iff we have enough networkstatus and router information to
+ * start building circuits. Right now, this means "more than half the
+ * networkstatus documents, and at least 1/4 of expected routers." */
+//XXX should consider whether we have enough exiting nodes here.
+int
+router_have_minimum_dir_info(void)
+{
+ if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) {
+ update_router_have_minimum_dir_info();
+ need_to_update_have_min_dir_info = 0;
+ }
+ return have_min_dir_info;
+}
+
+/** Called when our internal view of the directory has changed. This can be
+ * when the authorities change, networkstatuses change, the list of routerdescs
+ * changes, or number of running routers changes.
+ */
+void
+router_dir_info_changed(void)
+{
+ need_to_update_have_min_dir_info = 1;
+ rend_hsdir_routers_changed();
+}
+
+/** Return a string describing what we're missing before we have enough
+ * directory info. */
+const char *
+get_dir_info_status_string(void)
+{
+ return dir_info_status;
+}
+
+/** Iterate over the servers listed in <b>consensus</b>, and count how many of
+ * them seem like ones we'd use, and how many of <em>those</em> we have
+ * descriptors for. Store the former in *<b>num_usable</b> and the latter in
+ * *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those
+ * routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes
+ * with the Exit flag.
+ */
+static void
+count_usable_descriptors(int *num_present, int *num_usable,
+ const networkstatus_t *consensus,
+ const or_options_t *options, time_t now,
+ routerset_t *in_set, int exit_only)
+{
+ const int md = (consensus->flavor == FLAV_MICRODESC);
+ *num_present = 0, *num_usable=0;
+
+ SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
+ {
+ if (exit_only && ! rs->is_exit)
+ continue;
+ if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
+ continue;
+ if (client_would_use_router(rs, now, options)) {
+ const char * const digest = rs->descriptor_digest;
+ int present;
+ ++*num_usable; /* the consensus says we want it. */
+ if (md)
+ present = NULL != microdesc_cache_lookup_by_digest256(NULL, digest);
+ else
+ present = NULL != router_get_by_descriptor_digest(digest);
+ if (present) {
+ /* we have the descriptor listed in the consensus. */
+ ++*num_present;
+ }
+ }
+ }
+ SMARTLIST_FOREACH_END(rs);
+
+ log_debug(LD_DIR, "%d usable, %d present (%s%s).",
+ *num_usable, *num_present,
+ md ? "microdesc" : "desc", exit_only ? " exits" : "s");
+}
+
+/** We just fetched a new set of descriptors. Compute how far through
+ * the "loading descriptors" bootstrapping phase we are, so we can inform
+ * the controller of our progress. */
+int
+count_loading_descriptors_progress(void)
+{
+ int num_present = 0, num_usable=0;
+ time_t now = time(NULL);
+ const networkstatus_t *consensus =
+ networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
+ double fraction;
+
+ if (!consensus)
+ return 0; /* can't count descriptors if we have no list of them */
+
+ count_usable_descriptors(&num_present, &num_usable,
+ consensus, get_options(), now, NULL, 0);
+
+ if (num_usable == 0)
+ return 0; /* don't div by 0 */
+ fraction = num_present / (num_usable/4.);
+ if (fraction > 1.0)
+ return 0; /* it's not the number of descriptors holding us back */
+ return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int)
+ (fraction*(BOOTSTRAP_STATUS_CONN_OR-1 -
+ BOOTSTRAP_STATUS_LOADING_DESCRIPTORS));
+}
+
+/** Change the value of have_min_dir_info, setting it true iff we have enough
+ * network and router information to build circuits. Clear the value of
+ * need_to_update_have_min_dir_info. */
+static void
+update_router_have_minimum_dir_info(void)
+{
+ int num_present = 0, num_usable=0;
+ int num_exit_present = 0, num_exit_usable = 0;
+ time_t now = time(NULL);
+ int res;
+ const or_options_t *options = get_options();
+ const networkstatus_t *consensus =
+ networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
+ int using_md;
+
+ if (!consensus) {
+ if (!networkstatus_get_latest_consensus())
+ strlcpy(dir_info_status, "We have no usable consensus.",
+ sizeof(dir_info_status));
+ else
+ strlcpy(dir_info_status, "We have no recent usable consensus.",
+ sizeof(dir_info_status));
+ res = 0;
+ goto done;
+ }
+
+ if (should_delay_dir_fetches(get_options())) {
+ log_notice(LD_DIR, "no known bridge descriptors running yet; stalling");
+ strlcpy(dir_info_status, "No live bridge descriptors.",
+ sizeof(dir_info_status));
+ res = 0;
+ goto done;
+ }
+
+ using_md = consensus->flavor == FLAV_MICRODESC;
+
+ count_usable_descriptors(&num_present, &num_usable, consensus, options, now,
+ NULL, 0);
+ count_usable_descriptors(&num_exit_present, &num_exit_usable,
+ consensus, options, now, options->ExitNodes, 1);
+
+/* What fraction of desired server descriptors do we need before we will
+ * build circuits? */
+#define FRAC_USABLE_NEEDED .75
+/* What fraction of desired _exit_ server descriptors do we need before we
+ * will build circuits? */
+#define FRAC_EXIT_USABLE_NEEDED .5
+
+ if (num_present < num_usable * FRAC_USABLE_NEEDED) {
+ tor_snprintf(dir_info_status, sizeof(dir_info_status),
+ "We have only %d/%d usable %sdescriptors.",
+ num_present, num_usable, using_md ? "micro" : "");
+ res = 0;
+ control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
+ goto done;
+ } else if (num_present < 2) {
+ tor_snprintf(dir_info_status, sizeof(dir_info_status),
+ "Only %d %sdescriptor%s here and believed reachable!",
+ num_present, using_md ? "micro" : "", num_present ? "" : "s");
+ res = 0;
+ goto done;
+ } else if (num_exit_present < num_exit_usable * FRAC_EXIT_USABLE_NEEDED) {
+ tor_snprintf(dir_info_status, sizeof(dir_info_status),
+ "We have only %d/%d usable exit node descriptors.",
+ num_exit_present, num_exit_usable);
+ res = 0;
+ control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
+ goto done;
+ }
+
+ /* Check for entry nodes. */
+ if (options->EntryNodes) {
+ count_usable_descriptors(&num_present, &num_usable, consensus, options,
+ now, options->EntryNodes, 0);
+
+ if (!num_usable || !num_present) {
+ tor_snprintf(dir_info_status, sizeof(dir_info_status),
+ "We have only %d/%d usable entry node %sdescriptors.",
+ num_present, num_usable, using_md?"micro":"");
+ res = 0;
+ goto done;
+ }
+ }
+
+ res = 1;
+
+ done:
+ if (res && !have_min_dir_info) {
+ log(LOG_NOTICE, LD_DIR,
+ "We now have enough directory information to build circuits.");
+ control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
+ control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0);
+ }
+ if (!res && have_min_dir_info) {
+ int quiet = directory_too_idle_to_fetch_descriptors(options, now);
+ log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
+ "Our directory information is no longer up-to-date "
+ "enough to build circuits: %s", dir_info_status);
+
+ /* a) make us log when we next complete a circuit, so we know when Tor
+ * is back up and usable, and b) disable some activities that Tor
+ * should only do while circuits are working, like reachability tests
+ * and fetching bridge descriptors only over circuits. */
+ can_complete_circuit = 0;
+
+ control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
+ }
+ have_min_dir_info = res;
+ need_to_update_have_min_dir_info = 0;
+}
+
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 1e9da88d4e..13a3847414 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -5,17 +5,21 @@
/* See LICENSE for licensing information */
/**
- * \file microdesc.h
- * \brief Header file for microdesc.c.
+ * \file nodelist.h
+ * \brief Header file for nodelist.c.
**/
-#ifndef _TOR_NODELIST_H
-#define _TOR_NODELIST_H
+#ifndef TOR_NODELIST_H
+#define TOR_NODELIST_H
+
+#define node_assert_ok(n) STMT_BEGIN { \
+ tor_assert((n)->ri || (n)->rs); \
+ } STMT_END
node_t *node_get_mutable_by_id(const char *identity_digest);
const node_t *node_get_by_id(const char *identity_digest);
const node_t *node_get_by_hex_id(const char *identity_digest);
-node_t *nodelist_add_routerinfo(routerinfo_t *ri);
+node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
node_t *nodelist_add_microdesc(microdesc_t *md);
void nodelist_set_consensus(networkstatus_t *ns);
@@ -38,18 +42,18 @@ int node_get_purpose(const node_t *node);
int node_is_me(const node_t *node);
int node_exit_policy_rejects_all(const node_t *node);
smartlist_t *node_get_all_orports(const node_t *node);
-void node_get_prim_orport(const node_t *node, tor_addr_port_t *addr_port_out);
-void node_get_pref_orport(const node_t *node, tor_addr_port_t *addr_port_out);
-void node_get_pref_ipv6_orport(const node_t *node,
- tor_addr_port_t *addr_port_out);
-uint32_t node_get_prim_addr_ipv4h(const node_t *node);
int node_allows_single_hop_exits(const node_t *node);
const char *node_get_nickname(const node_t *node);
const char *node_get_platform(const node_t *node);
+uint32_t node_get_prim_addr_ipv4h(const node_t *node);
void node_get_address_string(const node_t *node, char *cp, size_t len);
long node_get_declared_uptime(const node_t *node);
time_t node_get_published_on(const node_t *node);
const smartlist_t *node_get_declared_family(const node_t *node);
+int node_ipv6_preferred(const node_t *node);
+int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out);
+void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
+void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
smartlist_t *nodelist_get_list(void);
@@ -57,11 +61,22 @@ smartlist_t *nodelist_get_list(void);
void node_get_addr(const node_t *node, tor_addr_t *addr_out);
#define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n))
-/* XXXX These need to move out of routerlist.c */
void nodelist_refresh_countries(void);
void node_set_country(node_t *node);
void nodelist_add_node_and_family(smartlist_t *nodes, const node_t *node);
int nodes_in_same_family(const node_t *node1, const node_t *node2);
+const node_t *router_find_exact_exit_enclave(const char *address,
+ uint16_t port);
+int node_is_unreliable(const node_t *router, int need_uptime,
+ int need_capacity, int need_guard);
+int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
+ int need_uptime);
+void router_set_status(const char *digest, int up);
+int router_have_minimum_dir_info(void);
+void router_dir_info_changed(void);
+const char *get_dir_info_status_string(void);
+int count_loading_descriptors_progress(void);
+
#endif
diff --git a/src/or/ntmain.h b/src/or/ntmain.h
index 07fdcf466b..95a835a42e 100644
--- a/src/or/ntmain.h
+++ b/src/or/ntmain.h
@@ -9,8 +9,8 @@
* \brief Header file for ntmain.c.
**/
-#ifndef _TOR_NTMAIN_H
-#define _TOR_NTMAIN_H
+#ifndef TOR_NTMAIN_H
+#define TOR_NTMAIN_H
#ifdef _WIN32
#if !defined (WINCE)
diff --git a/src/or/onion.c b/src/or/onion.c
index f8c4d72b5a..cce4bdf73c 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -106,7 +106,7 @@ onion_next_task(char **onionskin_out)
return NULL; /* no onions pending, we're done */
tor_assert(ol_list->circ);
- tor_assert(ol_list->circ->p_conn); /* make sure it's still valid */
+ tor_assert(ol_list->circ->p_chan); /* make sure it's still valid */
tor_assert(ol_length > 0);
circ = ol_list->circ;
*onionskin_out = ol_list->onionskin;
diff --git a/src/or/onion.h b/src/or/onion.h
index 7e0f873c73..e7626f9709 100644
--- a/src/or/onion.h
+++ b/src/or/onion.h
@@ -9,8 +9,8 @@
* \brief Header file for onion.c.
**/
-#ifndef _TOR_ONION_H
-#define _TOR_ONION_H
+#ifndef TOR_ONION_H
+#define TOR_ONION_H
int onion_pending_add(or_circuit_t *circ, char *onionskin);
or_circuit_t *onion_next_task(char **onionskin_out);
diff --git a/src/or/or.h b/src/or/or.h
index 51c23d305d..06a74f6370 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -9,8 +9,8 @@
* \brief Master header file for Tor-specific functionality.
**/
-#ifndef _TOR_OR_H
-#define _TOR_OR_H
+#ifndef TOR_OR_H
+#define TOR_OR_H
#include "orconfig.h"
@@ -98,6 +98,7 @@
#include "address.h"
#include "compat_libevent.h"
#include "ht.h"
+#include "replaycache.h"
/* These signals are defined to help handle_control_signal work.
*/
@@ -197,7 +198,7 @@ typedef enum {
CIRC_ID_TYPE_NEITHER=2
} circ_id_type_t;
-#define _CONN_TYPE_MIN 3
+#define CONN_TYPE_MIN_ 3
/** Type for sockets listening for OR connections. */
#define CONN_TYPE_OR_LISTENER 3
/** A bidirectional TLS connection transmitting a sequence of cells.
@@ -228,8 +229,8 @@ typedef enum {
#define CONN_TYPE_AP_NATD_LISTENER 14
/** Type for sockets listening for DNS requests. */
#define CONN_TYPE_AP_DNS_LISTENER 15
-#define _CONN_TYPE_MAX 15
-/* !!!! If _CONN_TYPE_MAX is ever over 15, we must grow the type field in
+#define CONN_TYPE_MAX_ 15
+/* !!!! If CONN_TYPE_MAX_ is ever over 15, we must grow the type field in
* connection_t. */
/* Proxy client types */
@@ -269,17 +270,17 @@ typedef enum {
/** State for any listener connection. */
#define LISTENER_STATE_READY 0
-#define _CPUWORKER_STATE_MIN 1
+#define CPUWORKER_STATE_MIN_ 1
/** State for a connection to a cpuworker process that's idle. */
#define CPUWORKER_STATE_IDLE 1
/** State for a connection to a cpuworker process that's processing a
* handshake. */
#define CPUWORKER_STATE_BUSY_ONION 2
-#define _CPUWORKER_STATE_MAX 2
+#define CPUWORKER_STATE_MAX_ 2
#define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION
-#define _OR_CONN_STATE_MIN 1
+#define OR_CONN_STATE_MIN_ 1
/** State for a connection to an OR: waiting for connect() to finish. */
#define OR_CONN_STATE_CONNECTING 1
/** State for a connection to an OR: waiting for proxy handshake to complete */
@@ -304,9 +305,9 @@ typedef enum {
#define OR_CONN_STATE_OR_HANDSHAKING_V3 7
/** State for an OR connection: Ready to send/receive cells. */
#define OR_CONN_STATE_OPEN 8
-#define _OR_CONN_STATE_MAX 8
+#define OR_CONN_STATE_MAX_ 8
-#define _EXIT_CONN_STATE_MIN 1
+#define EXIT_CONN_STATE_MIN_ 1
/** State for an exit connection: waiting for response from DNS farm. */
#define EXIT_CONN_STATE_RESOLVING 1
/** State for an exit connection: waiting for connect() to finish. */
@@ -315,10 +316,10 @@ typedef enum {
#define EXIT_CONN_STATE_OPEN 3
/** State for an exit connection: waiting to be removed. */
#define EXIT_CONN_STATE_RESOLVEFAILED 4
-#define _EXIT_CONN_STATE_MAX 4
+#define EXIT_CONN_STATE_MAX_ 4
/* The AP state values must be disjoint from the EXIT state values. */
-#define _AP_CONN_STATE_MIN 5
+#define AP_CONN_STATE_MIN_ 5
/** State for a SOCKS connection: waiting for SOCKS request. */
#define AP_CONN_STATE_SOCKS_WAIT 5
/** State for a SOCKS connection: got a y.onion URL; waiting to receive
@@ -338,14 +339,14 @@ typedef enum {
/** State for a transparent natd connection: waiting for original
* destination. */
#define AP_CONN_STATE_NATD_WAIT 12
-#define _AP_CONN_STATE_MAX 12
+#define AP_CONN_STATE_MAX_ 12
/** True iff the AP_CONN_STATE_* value <b>s</b> means that the corresponding
* edge connection is not attached to any circuit. */
#define AP_CONN_STATE_IS_UNATTACHED(s) \
((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT)
-#define _DIR_CONN_STATE_MIN 1
+#define DIR_CONN_STATE_MIN_ 1
/** State for connection to directory server: waiting for connect(). */
#define DIR_CONN_STATE_CONNECTING 1
/** State for connection to directory server: sending HTTP request. */
@@ -358,21 +359,21 @@ typedef enum {
#define DIR_CONN_STATE_SERVER_COMMAND_WAIT 5
/** State for connection at directory server: sending HTTP response. */
#define DIR_CONN_STATE_SERVER_WRITING 6
-#define _DIR_CONN_STATE_MAX 6
+#define DIR_CONN_STATE_MAX_ 6
/** True iff the purpose of <b>conn</b> means that it's a server-side
* directory connection. */
#define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER)
-#define _CONTROL_CONN_STATE_MIN 1
+#define CONTROL_CONN_STATE_MIN_ 1
/** State for a control connection: Authenticated and accepting v1 commands. */
#define CONTROL_CONN_STATE_OPEN 1
/** State for a control connection: Waiting for authentication; speaking
* protocol v1. */
#define CONTROL_CONN_STATE_NEEDAUTH 2
-#define _CONTROL_CONN_STATE_MAX 2
+#define CONTROL_CONN_STATE_MAX_ 2
-#define _DIR_PURPOSE_MIN 3
+#define DIR_PURPOSE_MIN_ 3
/** A connection to a directory server: download a rendezvous
* descriptor. */
#define DIR_PURPOSE_FETCH_RENDDESC 3
@@ -420,7 +421,7 @@ typedef enum {
#define DIR_PURPOSE_FETCH_RENDDESC_V2 18
/** A connection to a directory server: download a microdescriptor. */
#define DIR_PURPOSE_FETCH_MICRODESC 19
-#define _DIR_PURPOSE_MAX 19
+#define DIR_PURPOSE_MAX_ 19
/** True iff <b>p</b> is a purpose corresponding to uploading data to a
* directory server. */
@@ -430,12 +431,12 @@ typedef enum {
(p)==DIR_PURPOSE_UPLOAD_VOTE || \
(p)==DIR_PURPOSE_UPLOAD_SIGNATURES)
-#define _EXIT_PURPOSE_MIN 1
+#define EXIT_PURPOSE_MIN_ 1
/** This exit stream wants to do an ordinary connect. */
#define EXIT_PURPOSE_CONNECT 1
/** This exit stream wants to do a resolve (either normal or reverse). */
#define EXIT_PURPOSE_RESOLVE 2
-#define _EXIT_PURPOSE_MAX 2
+#define EXIT_PURPOSE_MAX_ 2
/* !!!! If any connection purpose is ever over 31, we must grow the type
* field in connection_t. */
@@ -444,16 +445,16 @@ typedef enum {
#define CIRCUIT_STATE_BUILDING 0
/** Circuit state: Waiting to process the onionskin. */
#define CIRCUIT_STATE_ONIONSKIN_PENDING 1
-/** Circuit state: I'd like to deliver a create, but my n_conn is still
+/** Circuit state: I'd like to deliver a create, but my n_chan is still
* connecting. */
-#define CIRCUIT_STATE_OR_WAIT 2
+#define CIRCUIT_STATE_CHAN_WAIT 2
/** Circuit state: onionskin(s) processed, ready to send/receive cells. */
#define CIRCUIT_STATE_OPEN 3
-#define _CIRCUIT_PURPOSE_MIN 1
+#define CIRCUIT_PURPOSE_MIN_ 1
/* these circuits were initiated elsewhere */
-#define _CIRCUIT_PURPOSE_OR_MIN 1
+#define CIRCUIT_PURPOSE_OR_MIN_ 1
/** OR-side circuit purpose: normal circuit, at OR. */
#define CIRCUIT_PURPOSE_OR 1
/** OR-side circuit purpose: At OR, from Bob, waiting for intro from Alices. */
@@ -462,7 +463,7 @@ typedef enum {
#define CIRCUIT_PURPOSE_REND_POINT_WAITING 3
/** OR-side circuit purpose: At OR, both circuits have this purpose. */
#define CIRCUIT_PURPOSE_REND_ESTABLISHED 4
-#define _CIRCUIT_PURPOSE_OR_MAX 4
+#define CIRCUIT_PURPOSE_OR_MAX_ 4
/* these circuits originate at this node */
@@ -505,7 +506,7 @@ typedef enum {
#define CIRCUIT_PURPOSE_C_REND_JOINED 12
/** This circuit is used for build time measurement only */
#define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 13
-#define _CIRCUIT_PURPOSE_C_MAX 13
+#define CIRCUIT_PURPOSE_C_MAX_ 13
/** Hidden-service-side circuit purpose: at Bob, waiting for introductions. */
#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 14
/** Hidden-service-side circuit purpose: at Bob, successfully established
@@ -519,19 +520,19 @@ typedef enum {
#define CIRCUIT_PURPOSE_TESTING 18
/** A controller made this circuit and Tor should not use it. */
#define CIRCUIT_PURPOSE_CONTROLLER 19
-#define _CIRCUIT_PURPOSE_MAX 19
+#define CIRCUIT_PURPOSE_MAX_ 19
/** A catch-all for unrecognized purposes. Currently we don't expect
* to make or see any circuits with this purpose. */
#define CIRCUIT_PURPOSE_UNKNOWN 255
/** True iff the circuit purpose <b>p</b> is for a circuit that
* originated at this node. */
-#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>_CIRCUIT_PURPOSE_OR_MAX)
+#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>CIRCUIT_PURPOSE_OR_MAX_)
/** True iff the circuit purpose <b>p</b> is for a circuit that originated
* here to serve as a client. (Hidden services don't count here.) */
#define CIRCUIT_PURPOSE_IS_CLIENT(p) \
- ((p)> _CIRCUIT_PURPOSE_OR_MAX && \
- (p)<=_CIRCUIT_PURPOSE_C_MAX)
+ ((p)> CIRCUIT_PURPOSE_OR_MAX_ && \
+ (p)<=CIRCUIT_PURPOSE_C_MAX_)
/** True iff the circuit_t <b>c</b> is actually an origin_circuit_t. */
#define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose))
/** True iff the circuit purpose <b>p</b> is for an established rendezvous
@@ -664,7 +665,7 @@ typedef enum {
/* Reasons why we (or a remote OR) might close a circuit. See tor-spec.txt for
* documentation of these. */
-#define _END_CIRC_REASON_MIN 0
+#define END_CIRC_REASON_MIN_ 0
#define END_CIRC_REASON_NONE 0
#define END_CIRC_REASON_TORPROTOCOL 1
#define END_CIRC_REASON_INTERNAL 2
@@ -673,12 +674,12 @@ typedef enum {
#define END_CIRC_REASON_RESOURCELIMIT 5
#define END_CIRC_REASON_CONNECTFAILED 6
#define END_CIRC_REASON_OR_IDENTITY 7
-#define END_CIRC_REASON_OR_CONN_CLOSED 8
+#define END_CIRC_REASON_CHANNEL_CLOSED 8
#define END_CIRC_REASON_FINISHED 9
#define END_CIRC_REASON_TIMEOUT 10
#define END_CIRC_REASON_DESTROYED 11
#define END_CIRC_REASON_NOSUCHSERVICE 12
-#define _END_CIRC_REASON_MAX 12
+#define END_CIRC_REASON_MAX_ 12
/** Bitwise-OR this with the argument to circuit_mark_for_close() or
* control_event_circuit_status() to indicate that the reason was
@@ -878,6 +879,147 @@ typedef uint16_t circid_t;
/** Identifies a stream on a circuit */
typedef uint16_t streamid_t;
+/* channel_t typedef; struct channel_s is in channel.h */
+
+typedef struct channel_s channel_t;
+
+/* channel_listener_t typedef; struct channel_listener_s is in channel.h */
+
+typedef struct channel_listener_s channel_listener_t;
+
+/* channel states for channel_t */
+
+typedef enum {
+ /*
+ * Closed state - channel is inactive
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_CLOSING
+ * Permitted transitions to:
+ * - CHANNEL_STATE_OPENING
+ */
+ CHANNEL_STATE_CLOSED = 0,
+ /*
+ * Opening state - channel is trying to connect
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_CLOSED
+ * Permitted transitions to:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_ERROR
+ * - CHANNEL_STATE_OPEN
+ */
+ CHANNEL_STATE_OPENING,
+ /*
+ * Open state - channel is active and ready for use
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_MAINT
+ * - CHANNEL_STATE_OPENING
+ * Permitted transitions to:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_ERROR
+ * - CHANNEL_STATE_MAINT
+ */
+ CHANNEL_STATE_OPEN,
+ /*
+ * Maintenance state - channel is temporarily offline for subclass specific
+ * maintenance activities such as TLS renegotiation.
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_OPEN
+ * Permitted transitions to:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_ERROR
+ * - CHANNEL_STATE_OPEN
+ */
+ CHANNEL_STATE_MAINT,
+ /*
+ * Closing state - channel is shutting down
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_MAINT
+ * - CHANNEL_STATE_OPEN
+ * Permitted transitions to:
+ * - CHANNEL_STATE_CLOSED,
+ * - CHANNEL_STATE_ERROR
+ */
+ CHANNEL_STATE_CLOSING,
+ /*
+ * Error state - channel has experienced a permanent error
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_MAINT
+ * - CHANNEL_STATE_OPENING
+ * - CHANNEL_STATE_OPEN
+ * Permitted transitions to:
+ * - None
+ */
+ CHANNEL_STATE_ERROR,
+ /*
+ * Placeholder for maximum state value
+ */
+ CHANNEL_STATE_LAST
+} channel_state_t;
+
+/* channel listener states for channel_listener_t */
+
+typedef enum {
+ /*
+ * Closed state - channel listener is inactive
+ *
+ * Permitted transitions from:
+ * - CHANNEL_LISTENER_STATE_CLOSING
+ * Permitted transitions to:
+ * - CHANNEL_LISTENER_STATE_LISTENING
+ */
+ CHANNEL_LISTENER_STATE_CLOSED = 0,
+ /*
+ * Listening state - channel listener is listening for incoming
+ * connections
+ *
+ * Permitted transitions from:
+ * - CHANNEL_LISTENER_STATE_CLOSED
+ * Permitted transitions to:
+ * - CHANNEL_LISTENER_STATE_CLOSING
+ * - CHANNEL_LISTENER_STATE_ERROR
+ */
+ CHANNEL_LISTENER_STATE_LISTENING,
+ /*
+ * Closing state - channel listener is shutting down
+ *
+ * Permitted transitions from:
+ * - CHANNEL_LISTENER_STATE_LISTENING
+ * Permitted transitions to:
+ * - CHANNEL_LISTENER_STATE_CLOSED,
+ * - CHANNEL_LISTENER_STATE_ERROR
+ */
+ CHANNEL_LISTENER_STATE_CLOSING,
+ /*
+ * Error state - channel listener has experienced a permanent error
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_LISTENING
+ * Permitted transitions to:
+ * - None
+ */
+ CHANNEL_LISTENER_STATE_ERROR,
+ /*
+ * Placeholder for maximum state value
+ */
+ CHANNEL_LISTENER_STATE_LAST
+} channel_listener_state_t;
+
+/* TLS channel stuff */
+
+typedef struct channel_tls_s channel_tls_t;
+
+/* circuitmux_t typedef; struct circuitmux_s is in circuitmux.h */
+
+typedef struct circuitmux_s circuitmux_t;
+
/** Parsed onion routing cell. All communication between nodes
* is via cells. */
typedef struct cell_t {
@@ -1060,14 +1202,11 @@ typedef struct connection_t {
/** Unique identifier for this connection on this Tor instance. */
uint64_t global_identifier;
-
- /** Unique ID for measuring tunneled network status requests. */
- uint64_t dirreq_id;
} connection_t;
/** Subtype of connection_t; used for a listener socket. */
typedef struct listener_connection_t {
- connection_t _base;
+ connection_t base_;
/** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points
* to the evdns_server_port it uses to listen to and answer connections. */
@@ -1086,6 +1225,18 @@ typedef struct listener_connection_t {
uint8_t isolation_flags;
/**@}*/
+ /** For a SOCKS listener, these fields describe whether we should
+ * allow IPv4 and IPv6 addresses from our exit nodes, respectively.
+ *
+ * @{
+ */
+ unsigned int socks_ipv4_traffic : 1;
+ unsigned int socks_ipv6_traffic : 1;
+ /** @} */
+ /** For a socks listener: should we tell the exit that we prefer IPv6
+ * addresses? */
+ unsigned int socks_prefer_ipv6 : 1;
+
} listener_connection_t;
/** Minimum length of the random part of an AUTH_CHALLENGE cell. */
@@ -1190,7 +1341,7 @@ typedef struct or_handshake_state_t {
/** Subtype of connection_t for an "OR connection" -- that is, one that speaks
* cells over TLS. */
typedef struct or_connection_t {
- connection_t _base;
+ connection_t base_;
/** Hash of the public RSA key for the other side's identity key, or zeroes
* if the other side hasn't shown us a valid identity key. */
@@ -1201,29 +1352,22 @@ typedef struct or_connection_t {
int tls_error; /**< Last tor_tls error code. */
/** When we last used this conn for any client traffic. If not
* recent, we can rate limit it further. */
- time_t client_used;
+
+ /* Channel using this connection */
+ channel_tls_t *chan;
tor_addr_t real_addr; /**< The actual address that this connection came from
* or went to. The <b>addr</b> field is prone to
* getting overridden by the address from the router
* descriptor matching <b>identity_digest</b>. */
- circ_id_type_t circ_id_type:2; /**< When we send CREATE cells along this
- * connection, which half of the space should
- * we use? */
/** Should this connection be used for extending circuits to the server
* matching the <b>identity_digest</b> field? Set to true if we're pretty
* sure we aren't getting MITMed, either because we're connected to an
* address listed in a server descriptor, or because an authenticated
* NETINFO cell listed the address we're connected to as recognized. */
unsigned int is_canonical:1;
- /** True iff this connection shouldn't get any new circs attached to it,
- * because the connection is too old, or because there's a better one.
- * More generally, this flag is used to note an unhealthy connection;
- * for example, if a bad connection fails we shouldn't assume that the
- * router itself has a problem.
- */
- unsigned int is_bad_for_new_circs:1;
+
/** True iff we have decided that the other end of this connection
* is a client. Connections with this flag set should never be used
* to satisfy an EXTEND request. */
@@ -1233,9 +1377,6 @@ typedef struct or_connection_t {
unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */
uint8_t link_proto; /**< What protocol version are we using? 0 for
* "none negotiated yet." */
- circid_t next_circ_id; /**< Which circ_id do we try to use next on
- * this connection? This is always in the
- * range 0..1<<15-1. */
or_handshake_state_t *handshake_state; /**< If we are setting this connection
* up, state information to do so. */
@@ -1257,24 +1398,7 @@ typedef struct or_connection_t {
/* XXXX we could share this among all connections. */
struct ev_token_bucket_cfg *bucket_cfg;
#endif
- int n_circuits; /**< How many circuits use this connection as p_conn or
- * n_conn ? */
-
- /** Double-linked ring of circuits with queued cells waiting for room to
- * free up on this connection's outbuf. Every time we pull cells from a
- * circuit, we advance this pointer to the next circuit in the ring. */
- struct circuit_t *active_circuits;
- /** Priority queue of cell_ewma_t for circuits with queued cells waiting for
- * room to free up on this connection's outbuf. Kept in heap order
- * according to EWMA.
- *
- * This is redundant with active_circuits; if we ever decide only to use the
- * cell_ewma algorithm for choosing circuits, we can remove active_circuits.
- */
- smartlist_t *active_circuit_pqueue;
- /** The tick on which the cell_ewma_ts in active_circuit_pqueue last had
- * their ewma values rescaled. */
- unsigned active_circuit_pqueue_last_recalibrated;
+
struct or_connection_t *next_with_same_id; /**< Next connection with same
* identity digest as this one. */
} or_connection_t;
@@ -1282,7 +1406,7 @@ typedef struct or_connection_t {
/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap)
* connection, or an exit. */
typedef struct edge_connection_t {
- connection_t _base;
+ connection_t base_;
struct edge_connection_t *next_stream; /**< Points to the next stream at this
* edge, if any */
@@ -1302,6 +1426,8 @@ typedef struct edge_connection_t {
uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit
* connection. Exit connections only. */
+ uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell
+ * for this connection */
streamid_t stream_id; /**< The stream ID used for this edge connection on its
* circuit */
@@ -1317,6 +1443,8 @@ typedef struct edge_connection_t {
/** True iff this connection is for a DNS request only. */
unsigned int is_dns_request:1;
+ /** True iff this connection is for a PTR DNS request. (exit only) */
+ unsigned int is_reverse_dns_lookup:1;
unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge
* connections. Set once we've set the stream end,
@@ -1326,12 +1454,16 @@ typedef struct edge_connection_t {
* cells. */
unsigned int edge_blocked_on_circ:1;
+ /** Unique ID for directory requests; this used to be in connection_t, but
+ * that's going away and being used on channels instead. We still tag
+ * edge connections with dirreq_id from circuits, so it's copied here. */
+ uint64_t dirreq_id;
} edge_connection_t;
/** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS
* connection, a DNS request, a TransPort connection or a NATD connection */
typedef struct entry_connection_t {
- edge_connection_t _edge;
+ edge_connection_t edge_;
/** Nickname of planned exit node -- used with .exit support. */
char *chosen_exit_name;
@@ -1404,12 +1536,21 @@ typedef struct entry_connection_t {
*/
unsigned int may_use_optimistic_data : 1;
+ /** Should we permit IPv4 and IPv6 traffic to use this connection?
+ *
+ * @{ */
+ unsigned int ipv4_traffic_ok : 1;
+ unsigned int ipv6_traffic_ok : 1;
+ /** @} */
+ /** Should we say we prefer IPv6 traffic? */
+ unsigned int prefer_ipv6_traffic : 1;
+
} entry_connection_t;
/** Subtype of connection_t for an "directory connection" -- that is, an HTTP
* connection to retrieve or serve directory material. */
typedef struct dir_connection_t {
- connection_t _base;
+ connection_t base_;
/** Which 'resource' did we ask the directory for? This is typically the part
* of the URL string that defines, relative to the directory conn purpose,
@@ -1448,11 +1589,15 @@ typedef struct dir_connection_t {
char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for
* the directory server's signing key. */
+ /** Unique ID for directory requests; this used to be in connection_t, but
+ * that's going away and being used on channels instead. The dirserver still
+ * needs this for the incoming side, so it's moved here. */
+ uint64_t dirreq_id;
} dir_connection_t;
/** Subtype of connection_t for an connection to a controller. */
typedef struct control_connection_t {
- connection_t _base;
+ connection_t base_;
uint32_t event_mask; /**< Bitfield: which events does this controller
* care about? */
@@ -1479,12 +1624,12 @@ typedef struct control_connection_t {
} control_connection_t;
/** Cast a connection_t subtype pointer to a connection_t **/
-#define TO_CONN(c) (&(((c)->_base)))
-/** Helper macro: Given a pointer to to._base, of type from*, return &to. */
-#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, _base))
+#define TO_CONN(c) (&(((c)->base_)))
+/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */
+#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_))
/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/
-#define ENTRY_TO_EDGE_CONN(c) (&(((c))->_edge))
+#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_))
/** Cast a entry_connection_t subtype pointer to a connection_t **/
#define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c)))
@@ -1529,12 +1674,12 @@ static INLINE edge_connection_t *TO_EDGE_CONN(connection_t *c)
static INLINE entry_connection_t *TO_ENTRY_CONN(connection_t *c)
{
tor_assert(c->magic == ENTRY_CONNECTION_MAGIC);
- return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, _edge._base);
+ return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_);
}
static INLINE entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *c)
{
- tor_assert(c->_base.magic == ENTRY_CONNECTION_MAGIC);
- return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, _edge);
+ tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC);
+ return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_);
}
static INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c)
{
@@ -1610,7 +1755,15 @@ typedef struct addr_policy_t {
maskbits_t maskbits; /**< Accept/reject all addresses <b>a</b> such that the
* first <b>maskbits</b> bits of <b>a</b> match
* <b>addr</b>. */
- tor_addr_t addr; /**< Base address to accept or reject. */
+ /** Base address to accept or reject.
+ *
+ * Note that wildcards are treated
+ * differntly depending on address family. An AF_UNSPEC address means
+ * "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means
+ * "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means
+ * "All IPv6 addresses".
+ **/
+ tor_addr_t addr;
uint16_t prt_min; /**< Lowest port number to accept/reject. */
uint16_t prt_max; /**< Highest port number to accept/reject. */
} addr_policy_t;
@@ -1750,7 +1903,10 @@ typedef struct {
/** How many bytes/s is this router known to handle? */
uint32_t bandwidthcapacity;
smartlist_t *exit_policy; /**< What streams will this OR permit
- * to exit? NULL for 'reject *:*'. */
+ * to exit on IPv4? NULL for 'reject *:*'. */
+ /** What streams will this OR permit to exit on IPv6?
+ * NULL for 'reject *:*' */
+ struct short_policy_t *ipv6_exit_policy;
long uptime; /**< How many seconds the router claims to have been up */
smartlist_t *declared_family; /**< Nicknames of router which this router
* claims are its family. */
@@ -1769,8 +1925,6 @@ typedef struct {
/** True if, after we have added this router, we should re-launch
* tests for it. */
unsigned int needs_retest_if_added:1;
- /** True if ipv6_addr:ipv6_orport is preferred. */
- unsigned int ipv6_preferred:1;
/** Tor can use this router for general positions in circuits; we got it
* from a directory server as usual, or we're an authority and a server
@@ -1793,15 +1947,6 @@ typedef struct {
* things; see notes on ROUTER_PURPOSE_* macros above.
*/
uint8_t purpose;
-
- /* The below items are used only by authdirservers for
- * reachability testing. */
-
- /** When was the last time we could reach this OR? */
- time_t last_reachable;
- /** When did we start testing reachability for this OR? */
- time_t testing_since;
-
} routerinfo_t;
/** Information needed to keep and cache a signed extra-info document. */
@@ -1833,6 +1978,8 @@ typedef struct routerstatus_t {
uint32_t addr; /**< IPv4 address for this router. */
uint16_t or_port; /**< OR port for this router. */
uint16_t dir_port; /**< Directory port for this router. */
+ tor_addr_t ipv6_addr; /**< IPv6 address for this router. */
+ uint16_t ipv6_orport; /**<IPV6 OR port for this router. */
unsigned int is_authority:1; /**< True iff this router is an authority. */
unsigned int is_exit:1; /**< True iff this router is a good exit. */
unsigned int is_stable:1; /**< True iff this router stays up a long time. */
@@ -1862,16 +2009,7 @@ typedef struct routerstatus_t {
* included.) We'll replace all these with a big tor_version_t or a char[]
* if the number of traits we care about ever becomes incredibly big. */
unsigned int version_known:1;
- /** True iff this router is a version that supports BEGIN_DIR cells. */
- unsigned int version_supports_begindir:1;
- /** True iff this router is a version that supports conditional consensus
- * downloads (signed by list of authorities). */
- unsigned int version_supports_conditional_consensus:1;
- /** True iff this router is a version that we can post extrainfo docs to. */
- unsigned int version_supports_extrainfo_upload:1;
- /** True iff this router is a version that, if it caches directory info,
- * we can get v3 downloads from. */
- unsigned int version_supports_v3_dir:1;
+
/** True iff this router is a version that, if it caches directory info,
* we can get microdescriptors from. */
unsigned int version_supports_microdesc_cache:1;
@@ -1968,10 +2106,17 @@ typedef struct microdesc_t {
/** As routerinfo_t.onion_pkey */
crypto_pk_t *onion_pkey;
+ /** As routerinfo_t.ipv6_add */
+ tor_addr_t ipv6_addr;
+ /** As routerinfo_t.ipv6_orport */
+ uint16_t ipv6_orport;
/** As routerinfo_t.family */
smartlist_t *family;
- /** Exit policy summary */
+ /** IPv4 exit policy summary */
short_policy_t *exit_policy;
+ /** IPv6 exit policy summary */
+ short_policy_t *ipv6_exit_policy;
+
} microdesc_t;
/** A node_t represents a Tor router.
@@ -2006,13 +2151,13 @@ typedef struct node_t {
routerstatus_t *rs;
/* local info: copied from routerstatus, then possibly frobbed based
- * on experience. Authorities set this stuff directly. */
+ * on experience. Authorities set this stuff directly. Note that
+ * these reflect knowledge of the primary (IPv4) OR port only. */
unsigned int is_running:1; /**< As far as we know, is this OR currently
* running? */
unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR?
- * (For Authdir: Have we validated this OR?)
- */
+ * (For Authdir: Have we validated this OR?) */
unsigned int is_fast:1; /** Do we think this is a fast OR? */
unsigned int is_stable:1; /** Do we think this is a stable OR? */
unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */
@@ -2035,8 +2180,20 @@ typedef struct node_t {
/* Local info: derived. */
+ /** True if the IPv6 OR port is preferred over the IPv4 OR port. */
+ unsigned int ipv6_preferred:1;
+
/** According to the geoip db what country is this router in? */
+ /* XXXprop186 what is this suppose to mean with multiple OR ports? */
country_t country;
+
+ /* The below items are used only by authdirservers for
+ * reachability testing. */
+
+ /** When was the last time we could reach this OR? */
+ time_t last_reachable; /* IPv4. */
+ time_t last_reachable6; /* IPv6. */
+
} node_t;
/** How many times will we try to download a router's descriptor before giving
@@ -2099,6 +2256,9 @@ typedef struct vote_microdesc_hash_t {
typedef struct vote_routerstatus_t {
routerstatus_t status; /**< Underlying 'status' object for this router.
* Flags are redundant. */
+ /** How many known-flags are allowed in a vote? This is the width of
+ * the flags field of vote_routerstatus_t */
+#define MAX_KNOWN_FLAGS_IN_VOTE 64
uint64_t flags; /**< Bit-field for all recognized flags; index into
* networkstatus_t.known_flags. */
char *version; /**< The version that the authority says this router is
@@ -2357,6 +2517,8 @@ typedef enum {
MICRODESC_DIRINFO=1 << 6,
} dirinfo_type_t;
+#define ALL_DIRINFO ((dirinfo_type_t)((1<<7)-1))
+
#define CRYPT_PATH_MAGIC 0x70127012u
/** Holds accounting information for a single step in the layered encryption
@@ -2460,29 +2622,6 @@ typedef struct {
time_t expiry_time;
} cpath_build_state_t;
-/**
- * The cell_ewma_t structure keeps track of how many cells a circuit has
- * transferred recently. It keeps an EWMA (exponentially weighted moving
- * average) of the number of cells flushed from the circuit queue onto a
- * connection in connection_or_flush_from_first_active_circuit().
- */
-typedef struct {
- /** The last 'tick' at which we recalibrated cell_count.
- *
- * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
- * since the start of this tick have weight greater than 1.0; ones sent
- * earlier have less weight. */
- unsigned last_adjusted_tick;
- /** The EWMA of the cell count. */
- double cell_count;
- /** True iff this is the cell count for a circuit's previous
- * connection. */
- unsigned int is_for_p_conn : 1;
- /** The position of the circuit within the OR connection's priority
- * queue. */
- int heap_index;
-} cell_ewma_t;
-
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
@@ -2513,23 +2652,39 @@ typedef struct circuit_t {
uint32_t magic; /**< For memory and type debugging: must equal
* ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
- /** Queue of cells waiting to be transmitted on n_conn. */
- cell_queue_t n_conn_cells;
- /** The OR connection that is next in this circuit. */
- or_connection_t *n_conn;
- /** The circuit_id used in the next (forward) hop of this circuit. */
+ /** The channel that is next in this circuit. */
+ channel_t *n_chan;
+
+ /**
+ * The circuit_id used in the next (forward) hop of this circuit;
+ * this is unique to n_chan, but this ordered pair is globally
+ * unique:
+ *
+ * (n_chan->global_identifier, n_circ_id)
+ */
circid_t n_circ_id;
- /** The hop to which we want to extend this circuit. Should be NULL if
- * the circuit has attached to a connection. */
+ /**
+ * Circuit mux associated with n_chan to which this circuit is attached;
+ * NULL if we have no n_chan.
+ */
+ circuitmux_t *n_mux;
+
+ /** Queue of cells waiting to be transmitted on n_chan */
+ cell_queue_t n_chan_cells;
+
+ /**
+ * The hop to which we want to extend this circuit. Should be NULL if
+ * the circuit has attached to a channel.
+ */
extend_info_t *n_hop;
- /** True iff we are waiting for n_conn_cells to become less full before
+ /** True iff we are waiting for n_chan_cells to become less full before
* allowing p_streams to add any more cells. (Origin circuit only.) */
- unsigned int streams_blocked_on_n_conn : 1;
- /** True iff we are waiting for p_conn_cells to become less full before
+ unsigned int streams_blocked_on_n_chan : 1;
+ /** True iff we are waiting for p_chan_cells to become less full before
* allowing n_streams to add any more cells. (OR circuit only.) */
- unsigned int streams_blocked_on_p_conn : 1;
+ unsigned int streams_blocked_on_p_chan : 1;
uint8_t state; /**< Current status of this circuit. */
uint8_t purpose; /**< Why are we creating this circuit? */
@@ -2544,15 +2699,26 @@ typedef struct circuit_t {
* more. */
int deliver_window;
- /** For storage while n_conn is pending
- * (state CIRCUIT_STATE_OR_WAIT). When defined, it is always
+ /** For storage while n_chan is pending
+ * (state CIRCUIT_STATE_CHAN_WAIT). When defined, it is always
* length ONIONSKIN_CHALLENGE_LEN. */
- char *n_conn_onionskin;
+ char *n_chan_onionskin;
+
+ /** When did circuit construction actually begin (ie send the
+ * CREATE cell or begin cannibalization).
+ *
+ * Note: This timer will get reset if we decide to cannibalize
+ * a circuit. It may also get reset during certain phases of hidden
+ * service circuit use.
+ *
+ * We keep this timestamp with a higher resolution than most so that the
+ * circuit-build-time tracking code can get millisecond resolution.
+ */
+ struct timeval timestamp_began;
- /** When was this circuit created? We keep this timestamp with a higher
- * resolution than most so that the circuit-build-time tracking code can
- * get millisecond resolution. */
+ /** This timestamp marks when the init_circuit_base constructor ran. */
struct timeval timestamp_created;
+
/** When the circuit was first used, or 0 if the circuit is clean.
*
* XXXX023 Note that some code will artifically adjust this value backward
@@ -2573,23 +2739,19 @@ typedef struct circuit_t {
const char *marked_for_close_file; /**< For debugging: in which file was this
* circuit marked for close? */
+ /** Unique ID for measuring tunneled network status requests. */
+ uint64_t dirreq_id;
+
+ struct circuit_t *next; /**< Next circuit in linked list of all circuits. */
+
/** Next circuit in the doubly-linked ring of circuits waiting to add
* cells to n_conn. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
- struct circuit_t *next_active_on_n_conn;
+ struct circuit_t *next_active_on_n_chan;
/** Previous circuit in the doubly-linked ring of circuits waiting to add
* cells to n_conn. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
- struct circuit_t *prev_active_on_n_conn;
- struct circuit_t *next; /**< Next circuit in linked list of all circuits. */
-
- /** Unique ID for measuring tunneled network status requests. */
- uint64_t dirreq_id;
-
- /** The EWMA count for the number of cells flushed from the
- * n_conn_cells queue. Used to determine which circuit to flush from next.
- */
- cell_ewma_t n_cell_ewma;
+ struct circuit_t *prev_active_on_n_chan;
} circuit_t;
/** Largest number of relay_early cells that we can send on a given
@@ -2616,7 +2778,7 @@ typedef enum {
/** An origin_circuit_t holds data necessary to build and use a circuit.
*/
typedef struct origin_circuit_t {
- circuit_t _base;
+ circuit_t base_;
/** Linked list of AP streams (or EXIT streams if hidden service)
* associated with this circuit. */
@@ -2666,6 +2828,10 @@ typedef struct origin_circuit_t {
* service-side introduction circuits never have this flag set.) */
unsigned int hs_circ_has_timed_out : 1;
+ /** Set iff this circuit has been given a relaxed timeout because
+ * no circuits have opened. Used to prevent spamming logs. */
+ unsigned int relaxed_timeout : 1;
+
/** Set iff this is a service-side rendezvous circuit for which a
* new connection attempt has been launched. We consider launching
* a new service-side rend circ to a client when the previous one
@@ -2749,23 +2915,28 @@ typedef struct origin_circuit_t {
/** An or_circuit_t holds information needed to implement a circuit at an
* OR. */
typedef struct or_circuit_t {
- circuit_t _base;
+ circuit_t base_;
/** Next circuit in the doubly-linked ring of circuits waiting to add
- * cells to p_conn. NULL if we have no cells pending, or if we're not
+ * cells to p_chan. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
- struct circuit_t *next_active_on_p_conn;
+ struct circuit_t *next_active_on_p_chan;
/** Previous circuit in the doubly-linked ring of circuits waiting to add
- * cells to p_conn. NULL if we have no cells pending, or if we're not
+ * cells to p_chan. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
- struct circuit_t *prev_active_on_p_conn;
+ struct circuit_t *prev_active_on_p_chan;
/** The circuit_id used in the previous (backward) hop of this circuit. */
circid_t p_circ_id;
/** Queue of cells waiting to be transmitted on p_conn. */
- cell_queue_t p_conn_cells;
- /** The OR connection that is previous in this circuit. */
- or_connection_t *p_conn;
+ cell_queue_t p_chan_cells;
+ /** The channel that is previous in this circuit. */
+ channel_t *p_chan;
+ /**
+ * Circuit mux associated with p_chan to which this circuit is attached;
+ * NULL if we have no p_chan.
+ */
+ circuitmux_t *p_mux;
/** Linked list of Exit streams associated with this circuit. */
edge_connection_t *n_streams;
/** Linked list of Exit streams associated with this circuit that are
@@ -2822,14 +2993,10 @@ typedef struct or_circuit_t {
* exit-ward queues of this circuit; reset every time when writing
* buffer stats to disk. */
uint64_t total_cell_waiting_time;
-
- /** The EWMA count for the number of cells flushed from the
- * p_conn_cells queue. */
- cell_ewma_t p_cell_ewma;
} or_circuit_t;
/** Convert a circuit subtype to a circuit_t. */
-#define TO_CIRCUIT(x) (&((x)->_base))
+#define TO_CIRCUIT(x) (&((x)->base_))
/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert
* if the cast is impossible. */
@@ -2915,8 +3082,11 @@ typedef struct port_cfg_t {
unsigned int no_advertise : 1;
unsigned int no_listen : 1;
unsigned int all_addrs : 1;
- unsigned int ipv4_only : 1;
- unsigned int ipv6_only : 1;
+ unsigned int bind_ipv4_only : 1;
+ unsigned int bind_ipv6_only : 1;
+ unsigned int ipv4_traffic : 1;
+ unsigned int ipv6_traffic : 1;
+ unsigned int prefer_ipv6 : 1;
/* Unix sockets only: */
/** Path for an AF_UNIX address */
@@ -2952,7 +3122,7 @@ typedef struct routerset_t routerset_t;
/** Configuration options for a Tor process. */
typedef struct {
- uint32_t _magic;
+ uint32_t magic_;
/** What should the tor process actually do? */
enum {
@@ -2994,7 +3164,7 @@ typedef struct {
* ORs not to consider as exits. */
/** Union of ExcludeNodes and ExcludeExitNodes */
- routerset_t *_ExcludeExitNodesUnion;
+ routerset_t *ExcludeExitNodesUnion_;
int DisableAllSwap; /**< Boolean: Attempt to call mlockall() on our
* process for all current and future memory. */
@@ -3002,7 +3172,7 @@ typedef struct {
/** List of "entry", "middle", "exit", "introduction", "rendezvous". */
smartlist_t *AllowInvalidNodes;
/** Bitmask; derived from AllowInvalidNodes. */
- invalid_router_usage_t _AllowInvalid;
+ invalid_router_usage_t AllowInvalid_;
config_line_t *ExitPolicy; /**< Lists of exit policy components. */
int ExitPolicyRejectPrivate; /**< Should we not exit to local addresses? */
config_line_t *SocksPolicy; /**< Lists of socks policy components */
@@ -3023,7 +3193,11 @@ typedef struct {
/** Addresses to bind for listening for control connections. */
config_line_t *ControlListenAddress;
/** Local address to bind outbound sockets */
- char *OutboundBindAddress;
+ config_line_t *OutboundBindAddress;
+ /** IPv4 address derived from OutboundBindAddress. */
+ tor_addr_t OutboundBindAddressIPv4_;
+ /** IPv6 address derived from OutboundBindAddress. */
+ tor_addr_t OutboundBindAddressIPv6_;
/** Directory server only: which versions of
* Tor should we tell users to run? */
config_line_t *RecommendedVersions;
@@ -3092,7 +3266,7 @@ typedef struct {
char *BridgePassword;
/** If BridgePassword is set, this is a SHA256 digest of the basic http
* authenticator for it. Used so we can do a time-independent comparison. */
- char *_BridgePassword_AuthDigest;
+ char *BridgePassword_AuthDigest_;
int UseBridges; /**< Boolean: should we start all circuits with a bridge? */
config_line_t *Bridges; /**< List of bootstrap bridge addresses. */
@@ -3103,6 +3277,9 @@ typedef struct {
config_line_t *ServerTransportPlugin; /**< List of client
transport plugins. */
+ /** List of TCP/IP addresses that transports should listen at. */
+ config_line_t *ServerTransportListenAddr;
+
int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make
* this explicit so we can change how we behave in the
* future. */
@@ -3118,7 +3295,7 @@ typedef struct {
* "v1", "v2", "v3", "bridge", or "". */
smartlist_t *PublishServerDescriptor;
/** A bitfield of authority types, derived from PublishServerDescriptor. */
- dirinfo_type_t _PublishServerDescriptor;
+ dirinfo_type_t PublishServerDescriptor_;
/** Boolean: do we publish hidden service descriptors to the HS auths? */
int PublishHidServDescriptors;
int FetchServerDescriptors; /**< Do we fetch server descriptors as normal? */
@@ -3151,7 +3328,7 @@ typedef struct {
int CloseHSServiceRendCircuitsImmediatelyOnTimeout;
int ConnLimit; /**< Demanded minimum number of simultaneous connections. */
- int _ConnLimit; /**< Maximum allowed number of simultaneous connections. */
+ int ConnLimit_; /**< Maximum allowed number of simultaneous connections. */
int RunAsDaemon; /**< If true, run in the background. (Unix only) */
int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */
smartlist_t *FirewallPorts; /**< Which ports our firewall allows
@@ -3264,7 +3441,14 @@ typedef struct {
/** List of configuration lines for replacement directory authorities.
* If you just want to replace one class of authority at a time,
* use the "Alternate*Authority" options below instead. */
- config_line_t *DirServers;
+ config_line_t *DirAuthorities;
+
+ /** List of fallback directory servers */
+ config_line_t *FallbackDir;
+
+ /** Weight to apply to all directory authority rates if considering them
+ * along with fallbackdirs */
+ double DirAuthorityFallbackRate;
/** If set, use these main (currently v3) directory authorities and
* not the default ones. */
@@ -3312,6 +3496,7 @@ typedef struct {
int AuthDirMaxServersPerAuthAddr; /**< Do not permit more than this
* number of servers per IP address shared
* with an authority. */
+ int AuthDirHasIPv6Connectivity; /**< Boolean: are we on IPv6? */
/** If non-zero, always vote the Fast flag for any relay advertising
* this amount of capacity or more. */
@@ -3354,7 +3539,7 @@ typedef struct {
/* Derived from SafeLogging */
enum {
SAFELOG_SCRUB_ALL, SAFELOG_SCRUB_RELAY, SAFELOG_SCRUB_NONE
- } _SafeLogging;
+ } SafeLogging_;
int SafeSocks; /**< Boolean: should we outright refuse application
* connections that use socks4 or socks5-with-local-dns? */
@@ -3478,6 +3663,13 @@ typedef struct {
* over randomly chosen exits. */
int ClientRejectInternalAddresses;
+ /** If true, clients may connect over IPv6. XXX we don't really
+ enforce this -- clients _may_ set up outgoing IPv6 connections
+ even when this option is not set. */
+ int ClientUseIPv6;
+ /** If true, prefer an IPv6 OR port over an IPv4 one. */
+ int ClientPreferIPv6ORPort;
+
/** The length of time that we think a consensus should be fresh. */
int V3AuthVotingInterval;
/** The length of time we think it will take to distribute votes. */
@@ -3525,17 +3717,14 @@ typedef struct {
* of certain configuration options. */
int TestingTorNetwork;
- /** File to check for a consensus networkstatus, if we don't have one
- * cached. */
- char *FallbackNetworkstatusFile;
-
/** If true, and we have GeoIP data, and we're a bridge, keep a per-country
* count of how many client addresses have contacted us so that we can help
* the bridge authority guess which countries have blocked access to us. */
int BridgeRecordUsageByCountry;
- /** Optionally, a file with GeoIP data. */
+ /** Optionally, IPv4 and IPv6 GeoIP data. */
char *GeoIPFile;
+ char *GeoIPv6File;
/** If true, SIGHUP should reload the torrc. Sometimes controllers want
* to make this false. */
@@ -3559,13 +3748,13 @@ typedef struct {
/** If true, do not enable IOCP on windows with bufferevents, even if
* we think we could. */
int DisableIOCP;
- /** For testing only: will go away in 0.2.3.x. */
- int _UseFilteringSSLBufferevents;
+ /** For testing only: will go away eventually. */
+ int UseFilteringSSLBufferevents;
/** Set to true if the TestingTorNetwork configuration option is set.
* This is used so that options_validate() has a chance to realize that
* the defaults have changed. */
- int _UsingTestNetworkDefaults;
+ int UsingTestNetworkDefaults_;
/** If 1, we try to use microdescriptors to build circuits. If 0, we don't.
* If -1, Tor decides. */
@@ -3605,11 +3794,13 @@ typedef struct {
int PathBiasScaleFactor;
/** @} */
+ int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */
+
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
typedef struct {
- uint32_t _magic;
+ uint32_t magic_;
/** The time at which we next plan to write the state to the disk. Equal to
* TIME_MAX if there are no savable changes, 0 if there are changes that
* should be saved right away. */
@@ -4121,10 +4312,10 @@ typedef enum {
/** Flushed last cell from queue of the circuit that initiated a
* tunneled request to the outbuf of the OR connection. */
DIRREQ_CIRC_QUEUE_FLUSHED = 3,
- /** Flushed last byte from buffer of the OR connection belonging to the
+ /** Flushed last byte from buffer of the channel belonging to the
* circuit that initiated a tunneled request; completes a tunneled
* request. */
- DIRREQ_OR_CONN_BUFFER_FLUSHED = 4
+ DIRREQ_CHANNEL_BUFFER_FLUSHED = 4
} dirreq_state_t;
#define WRITE_STATS_INTERVAL (24*60*60)
@@ -4251,12 +4442,15 @@ typedef struct rend_intro_point_t {
* intro point. */
unsigned int rend_service_note_removing_intro_point_called : 1;
- /** (Service side only) A digestmap recording the INTRODUCE2 cells
- * this intro point's circuit has received. Each key is the digest
- * of the RSA-encrypted part of a received INTRODUCE2 cell; each
- * value is a pointer to the time_t at which the cell was received.
- * This digestmap is used to prevent replay attacks. */
- digestmap_t *accepted_intro_rsa_parts;
+ /** (Service side only) A replay cache recording the RSA-encrypted parts
+ * of INTRODUCE2 cells this intro point's circuit has received. This is
+ * used to prevent replay attacks. */
+ replaycache_t *accepted_intro_rsa_parts;
+
+ /** (Service side only) Count of INTRODUCE2 cells accepted from this
+ * intro point.
+ */
+ int accepted_introduce2_count;
/** (Service side only) The time at which this intro point was first
* published, or -1 if this intro point has not yet been
@@ -4312,19 +4506,23 @@ typedef struct rend_cache_entry_t {
/********************************* routerlist.c ***************************/
-/** Represents information about a single trusted directory server. */
-typedef struct trusted_dir_server_t {
+/** Represents information about a single trusted or fallback directory
+ * server. */
+typedef struct dir_server_t {
char *description;
char *nickname;
char *address; /**< Hostname. */
uint32_t addr; /**< IPv4 address. */
uint16_t dir_port; /**< Directory port. */
uint16_t or_port; /**< OR port: Used for tunneling connections. */
+ double weight; /** Weight used when selecting this node at random */
char digest[DIGEST_LEN]; /**< Digest of identity key. */
char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only,
* high-security) identity key. */
unsigned int is_running:1; /**< True iff we think this server is running. */
+ unsigned int is_authority:1; /**< True iff this is a directory authority
+ * of some kind. */
/** True iff this server has accepted the most recent server descriptor
* we tried to upload to it. */
@@ -4343,7 +4541,7 @@ typedef struct trusted_dir_server_t {
* as a routerstatus_t. Not updated by the
* router-status management code!
**/
-} trusted_dir_server_t;
+} dir_server_t;
#define ROUTER_REQUIRED_MIN_BANDWIDTH (20*1024)
@@ -4379,7 +4577,7 @@ typedef struct trusted_dir_server_t {
#define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3)
#define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4)
-#define _PDS_PREFER_TUNNELED_DIR_CONNS (1<<16)
+#define PDS_PREFER_TUNNELED_DIR_CONNS_ (1<<16)
/** Possible ways to weight routers when choosing one randomly. See
* routerlist_sl_choose_by_bandwidth() for more information.*/
diff --git a/src/or/policies.c b/src/or/policies.c
index 81e4809687..27cdd84aff 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. */
@@ -87,7 +89,8 @@ policy_expand_private(smartlist_t **policy)
memcpy(&newpolicy, p, sizeof(addr_policy_t));
newpolicy.is_private = 0;
newpolicy.is_canonical = 0;
- if (tor_addr_parse_mask_ports(private_nets[i], &newpolicy.addr,
+ if (tor_addr_parse_mask_ports(private_nets[i], 0,
+ &newpolicy.addr,
&newpolicy.maskbits, &port_min, &port_max)<0) {
tor_assert(0);
}
@@ -100,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
@@ -144,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);
@@ -319,9 +366,13 @@ addr_is_in_cc_list(uint32_t addr, const smartlist_t *cc_list)
{
country_t country;
const char *name;
+ tor_addr_t tar;
+
if (!cc_list)
return 0;
- country = geoip_get_country_by_ip(addr);
+ /* XXXXipv6 */
+ tor_addr_from_ipv4h(&tar, addr);
+ country = geoip_get_country_by_addr(&tar);
name = geoip_get_country_name(country);
return smartlist_string_isin_case(cc_list, name);
}
@@ -386,6 +437,7 @@ validate_addr_policies(const or_options_t *options, char **msg)
*msg = NULL;
if (policies_parse_exit_policy(options->ExitPolicy, &addr_policy,
+ options->IPv6Exit,
options->ExitPolicyRejectPrivate, NULL,
!options->BridgeRelay))
REJECT("Error in ExitPolicy entry.");
@@ -730,6 +782,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) {
@@ -785,20 +841,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;
}
}
@@ -864,12 +932,20 @@ 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,
+ int ipv6_exit,
int rejectprivate, const char *local_address,
int add_default_policy)
{
+ if (!ipv6_exit) {
+ append_exit_policy_string(dest, "reject *6:*");
+ }
if (rejectprivate) {
append_exit_policy_string(dest, "reject private:*");
if (local_address) {
@@ -880,10 +956,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;
@@ -894,7 +972,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 *:* */
@@ -970,18 +1049,23 @@ exit_policy_is_general_exit(smartlist_t *policy)
/** Return false if <b>policy</b> might permit access to some addr:port;
* otherwise if we are certain it rejects everything, return true. */
int
-policy_is_reject_star(const smartlist_t *policy)
+policy_is_reject_star(const smartlist_t *policy, sa_family_t family)
{
if (!policy) /*XXXX disallow NULL policies? */
return 1;
- SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
- if (p->policy_type == ADDR_POLICY_ACCEPT)
+ SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) {
+ if (p->policy_type == ADDR_POLICY_ACCEPT &&
+ (tor_addr_family(&p->addr) == family ||
+ tor_addr_family(&p->addr) == AF_UNSPEC)) {
return 0;
- else if (p->policy_type == ADDR_POLICY_REJECT &&
- p->prt_min <= 1 && p->prt_max == 65535 &&
- p->maskbits == 0)
+ } else if (p->policy_type == ADDR_POLICY_REJECT &&
+ p->prt_min <= 1 && p->prt_max == 65535 &&
+ p->maskbits == 0 &&
+ (tor_addr_family(&p->addr) == family ||
+ tor_addr_family(&p->addr) == AF_UNSPEC)) {
return 1;
- });
+ }
+ } SMARTLIST_FOREACH_END(p);
return 1;
}
@@ -996,20 +1080,28 @@ 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 %s",
- (is_ip6&&format_for_desc)?"opt ":"",
+ result = tor_snprintf(buf, buflen, "%s%s %s",
is_accept ? "accept" : "reject",
(is_ip6&&format_for_desc)?"6":"",
addrpart);
@@ -1189,8 +1281,8 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p)
for (i = 0; private_nets[i]; ++i) {
tor_addr_t addr;
maskbits_t maskbits;
- if (tor_addr_parse_mask_ports(private_nets[i], &addr,
- &maskbits, NULL, NULL)<0) {
+ if (tor_addr_parse_mask_ports(private_nets[i], 0, &addr,
+ &maskbits, NULL, NULL)<0) {
tor_assert(0);
}
if (tor_addr_compare(&p->addr, &addr, CMP_EXACT) == 0 &&
@@ -1216,7 +1308,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;
@@ -1228,9 +1320,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
@@ -1517,7 +1616,7 @@ short_policy_is_reject_star(const short_policy_t *policy)
policy->entries[0].max_port == 65535);
}
-/** Decides whether addr:port is probably or definitely accepted or rejcted by
+/** Decide whether addr:port is probably or definitely accepted or rejected by
* <b>node</b>. See compare_tor_addr_to_addr_policy for details on addr/port
* interpretation. */
addr_policy_result_t
@@ -1527,16 +1626,29 @@ compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port,
if (node->rejects_all)
return ADDR_POLICY_REJECTED;
- if (node->ri)
+ if (addr && tor_addr_family(addr) == AF_INET6) {
+ const short_policy_t *p = NULL;
+ if (node->ri)
+ p = node->ri->ipv6_exit_policy;
+ else if (node->md)
+ p = node->md->ipv6_exit_policy;
+ if (p)
+ return compare_tor_addr_to_short_policy(addr, port, p);
+ else
+ return ADDR_POLICY_REJECTED;
+ }
+
+ if (node->ri) {
return compare_tor_addr_to_addr_policy(addr, port, node->ri->exit_policy);
- else if (node->md) {
+ } else if (node->md) {
if (node->md->exit_policy == NULL)
return ADDR_POLICY_REJECTED;
else
return compare_tor_addr_to_short_policy(addr, port,
node->md->exit_policy);
- } else
+ } else {
return ADDR_POLICY_PROBABLY_REJECTED;
+ }
}
/** Implementation for GETINFO control command: knows the answer for questions
diff --git a/src/or/policies.h b/src/or/policies.h
index f00d8299b8..d9983e8008 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -9,8 +9,8 @@
* \brief Header file for policies.c.
**/
-#ifndef _TOR_POLICIES_H
-#define _TOR_POLICIES_H
+#ifndef TOR_POLICIES_H
+#define TOR_POLICIES_H
/* (length of "accept 255.255.255.255/255.255.255.255:65535-65535\n" plus a
* NUL.)
@@ -31,6 +31,7 @@ int authdir_policy_badexit_address(uint32_t addr, uint16_t port);
int validate_addr_policies(const or_options_t *options, char **msg);
void policy_expand_private(smartlist_t **policy);
+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);
@@ -42,12 +43,13 @@ addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr,
uint16_t port, const node_t *node);
int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
+ int ipv6exit,
int rejectprivate, const char *local_address,
int add_default_policy);
void policies_exit_policy_append_reject_star(smartlist_t **dest);
void policies_set_node_exitpolicy_to_reject_all(node_t *exitrouter);
int exit_policy_is_general_exit(smartlist_t *policy);
-int policy_is_reject_star(const smartlist_t *policy);
+int policy_is_reject_star(const smartlist_t *policy, sa_family_t family);
int getinfo_helper_policies(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
@@ -58,7 +60,7 @@ void addr_policy_list_free(smartlist_t *p);
void addr_policy_free(addr_policy_t *p);
void policies_free_all(void);
-char *policy_summarize(smartlist_t *policy);
+char *policy_summarize(smartlist_t *policy, sa_family_t family);
short_policy_t *parse_short_policy(const char *summary);
char *write_short_policy(const short_policy_t *policy);
diff --git a/src/or/reasons.c b/src/or/reasons.c
index c51d8ee6f5..874a86774b 100644
--- a/src/or/reasons.c
+++ b/src/or/reasons.c
@@ -300,8 +300,13 @@ errno_to_orconn_end_reason(int e)
const char *
circuit_end_reason_to_control_string(int reason)
{
- if (reason >= 0 && reason & END_CIRC_REASON_FLAG_REMOTE)
+ int is_remote = 0;
+
+ if (reason >= 0 && reason & END_CIRC_REASON_FLAG_REMOTE) {
reason &= ~END_CIRC_REASON_FLAG_REMOTE;
+ is_remote = 1;
+ }
+
switch (reason) {
case END_CIRC_AT_ORIGIN:
/* This shouldn't get passed here; it's a catch-all reason. */
@@ -323,8 +328,8 @@ circuit_end_reason_to_control_string(int reason)
return "CONNECTFAILED";
case END_CIRC_REASON_OR_IDENTITY:
return "OR_IDENTITY";
- case END_CIRC_REASON_OR_CONN_CLOSED:
- return "OR_CONN_CLOSED";
+ case END_CIRC_REASON_CHANNEL_CLOSED:
+ return "CHANNEL_CLOSED";
case END_CIRC_REASON_FINISHED:
return "FINISHED";
case END_CIRC_REASON_TIMEOUT:
@@ -338,7 +343,18 @@ circuit_end_reason_to_control_string(int reason)
case END_CIRC_REASON_MEASUREMENT_EXPIRED:
return "MEASUREMENT_EXPIRED";
default:
- log_warn(LD_BUG, "Unrecognized reason code %d", (int)reason);
+ if (is_remote) {
+ /*
+ * If it's remote, it's not a bug *here*, so don't use LD_BUG, but
+ * do note that the someone we're talking to is speaking the Tor
+ * protocol with a weird accent.
+ */
+ log_warn(LD_PROTOCOL,
+ "Remote server sent bogus reason code %d", reason);
+ } else {
+ log_warn(LD_BUG,
+ "Unrecognized reason code %d", reason);
+ }
return NULL;
}
}
diff --git a/src/or/reasons.h b/src/or/reasons.h
index 377b61b113..0dbf5aa693 100644
--- a/src/or/reasons.h
+++ b/src/or/reasons.h
@@ -9,8 +9,8 @@
* \brief Header file for reasons.c.
**/
-#ifndef _TOR_REASONS_H
-#define _TOR_REASONS_H
+#ifndef TOR_REASONS_H
+#define TOR_REASONS_H
const char *stream_end_reason_to_control_string(int reason);
const char *stream_end_reason_to_string(int reason);
diff --git a/src/or/relay.c b/src/or/relay.c
index 5f7fcd8b7c..7f49299e2b 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -10,10 +10,11 @@
* receiving from circuits, plus queuing on circuits.
**/
-#include <math.h>
#define RELAY_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "config.h"
@@ -166,7 +167,7 @@ int
circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction)
{
- or_connection_t *or_conn=NULL;
+ channel_t *chan = NULL;
crypt_path_t *layer_hint=NULL;
char recognized=0;
int reason;
@@ -213,24 +214,24 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
/* not recognized. pass it on. */
if (cell_direction == CELL_DIRECTION_OUT) {
cell->circ_id = circ->n_circ_id; /* switch it */
- or_conn = circ->n_conn;
+ chan = circ->n_chan;
} else if (! CIRCUIT_IS_ORIGIN(circ)) {
cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */
- or_conn = TO_OR_CIRCUIT(circ)->p_conn;
+ chan = TO_OR_CIRCUIT(circ)->p_chan;
} else {
log_fn(LOG_PROTOCOL_WARN, LD_OR,
"Dropping unrecognized inbound cell on origin circuit.");
return 0;
}
- if (!or_conn) {
+ if (!chan) {
// XXXX Can this splice stuff be done more cleanly?
if (! CIRCUIT_IS_ORIGIN(circ) &&
TO_OR_CIRCUIT(circ)->rend_splice &&
cell_direction == CELL_DIRECTION_OUT) {
or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice;
tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
- tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
+ tor_assert(splice->base_.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
cell->circ_id = splice->p_circ_id;
cell->command = CELL_RELAY; /* can't be relay_early anyway */
if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice),
@@ -254,7 +255,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
* we might kill the circ before we relay
* the cells. */
- append_cell_to_circuit_queue(circ, or_conn, cell, cell_direction, 0);
+ append_cell_to_circuit_queue(circ, chan, cell, cell_direction, 0);
return 0;
}
@@ -353,13 +354,13 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction,
crypt_path_t *layer_hint, streamid_t on_stream)
{
- or_connection_t *conn; /* where to send the cell */
+ channel_t *chan; /* where to send the cell */
if (cell_direction == CELL_DIRECTION_OUT) {
crypt_path_t *thishop; /* counter for repeated crypts */
- conn = circ->n_conn;
- if (!CIRCUIT_IS_ORIGIN(circ) || !conn) {
- log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping.");
+ chan = circ->n_chan;
+ if (!CIRCUIT_IS_ORIGIN(circ) || !chan) {
+ log_warn(LD_BUG,"outgoing relay cell has n_chan==NULL. Dropping.");
return 0; /* just drop it */
}
@@ -388,14 +389,14 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
return 0; /* just drop it */
}
or_circ = TO_OR_CIRCUIT(circ);
- conn = or_circ->p_conn;
+ chan = or_circ->p_chan;
relay_set_digest(or_circ->p_digest, cell);
if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0)
return -1;
}
++stats_n_relay_cells_relayed;
- append_cell_to_circuit_queue(circ, conn, cell, cell_direction, on_stream);
+ append_cell_to_circuit_queue(circ, chan, cell, cell_direction, on_stream);
return 0;
}
@@ -422,7 +423,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell,
for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (rh.stream_id == tmpconn->stream_id &&
- !tmpconn->_base.marked_for_close &&
+ !tmpconn->base_.marked_for_close &&
tmpconn->cpath_layer == layer_hint) {
log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
return tmpconn;
@@ -432,7 +433,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell,
for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (rh.stream_id == tmpconn->stream_id &&
- !tmpconn->_base.marked_for_close) {
+ !tmpconn->base_.marked_for_close) {
log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
if (cell_direction == CELL_DIRECTION_OUT ||
connection_edge_is_rendezvous_stream(tmpconn))
@@ -442,7 +443,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell,
for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (rh.stream_id == tmpconn->stream_id &&
- !tmpconn->_base.marked_for_close) {
+ !tmpconn->base_.marked_for_close) {
log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
return tmpconn;
}
@@ -561,9 +562,9 @@ relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
geoip_change_dirreq_state(circ->dirreq_id, DIRREQ_TUNNELED,
DIRREQ_END_CELL_SENT);
- if (cell_direction == CELL_DIRECTION_OUT && circ->n_conn) {
+ if (cell_direction == CELL_DIRECTION_OUT && circ->n_chan) {
/* if we're using relaybandwidthrate, this conn wants priority */
- circ->n_conn->client_used = approx_time();
+ channel_timestamp_client(circ->n_chan);
}
if (cell_direction == CELL_DIRECTION_OUT) {
@@ -631,16 +632,16 @@ connection_edge_send_command(edge_connection_t *fromconn,
tor_assert(fromconn);
circ = fromconn->on_circuit;
- if (fromconn->_base.marked_for_close) {
+ if (fromconn->base_.marked_for_close) {
log_warn(LD_BUG,
"called on conn that's already marked for close at %s:%d.",
- fromconn->_base.marked_for_close_file,
- fromconn->_base.marked_for_close);
+ fromconn->base_.marked_for_close_file,
+ fromconn->base_.marked_for_close);
return 0;
}
if (!circ) {
- if (fromconn->_base.type == CONN_TYPE_AP) {
+ if (fromconn->base_.type == CONN_TYPE_AP) {
log_info(LD_APP,"no circ. Closing conn.");
connection_mark_unattached_ap(EDGE_TO_ENTRY_CONN(fromconn),
END_STREAM_REASON_INTERNAL);
@@ -704,27 +705,45 @@ connection_ap_process_end_not_open(
switch (reason) {
case END_STREAM_REASON_EXITPOLICY:
if (rh->length >= 5) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
- int ttl;
- if (!addr) {
+ tor_addr_t addr;
+ int ttl = -1;
+ tor_addr_make_unspec(&addr);
+ if (rh->length == 5 || rh->length == 9) {
+ tor_addr_from_ipv4n(&addr,
+ get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
+ if (rh->length == 9)
+ ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
+ } else if (rh->length == 17 || rh->length == 21) {
+ tor_addr_from_ipv6_bytes(&addr,
+ (char*)(cell->payload+RELAY_HEADER_SIZE+1));
+ if (rh->length == 21)
+ ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17));
+ }
+ if (tor_addr_is_null(&addr)) {
log_info(LD_APP,"Address '%s' resolved to 0.0.0.0. Closing,",
safe_str(conn->socks_request->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return 0;
}
- if (rh->length >= 9)
- ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
- else
- ttl = -1;
+ if ((tor_addr_family(&addr) == AF_INET && !conn->ipv4_traffic_ok) ||
+ (tor_addr_family(&addr) == AF_INET6 && !conn->ipv6_traffic_ok)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got an EXITPOLICY failure on a connection with a "
+ "mismatched family. Closing.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+ return 0;
+ }
if (get_options()->ClientDNSRejectInternalAddresses &&
- is_internal_IP(addr, 0)) {
+ tor_addr_is_internal(&addr, 0)) {
log_info(LD_APP,"Address '%s' resolved to internal. Closing,",
safe_str(conn->socks_request->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return 0;
}
- client_dns_set_addressmap(conn->socks_request->address, addr,
+
+ client_dns_set_addressmap(circ,
+ conn->socks_request->address, &addr,
conn->chosen_exit_name, ttl);
}
/* check if he *ought* to have allowed it */
@@ -777,8 +796,8 @@ connection_ap_process_end_not_open(
circuit_log_path(LOG_INFO,LD_APP,circ);
/* Mark this circuit "unusable for new streams". */
/* XXXX024 this is a kludgy way to do this. */
- tor_assert(circ->_base.timestamp_dirty);
- circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ tor_assert(circ->base_.timestamp_dirty);
+ circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
if (conn->chosen_exit_optional) {
/* stop wanting a specific exit */
@@ -827,20 +846,60 @@ connection_ap_process_end_not_open(
}
/** Helper: change the socks_request-&gt;address field on conn to the
- * dotted-quad representation of <b>new_addr</b> (given in host order),
+ * dotted-quad representation of <b>new_addr</b>,
* and send an appropriate REMAP event. */
static void
-remap_event_helper(entry_connection_t *conn, uint32_t new_addr)
+remap_event_helper(entry_connection_t *conn, const tor_addr_t *new_addr)
{
- struct in_addr in;
-
- in.s_addr = htonl(new_addr);
- tor_inet_ntoa(&in, conn->socks_request->address,
- sizeof(conn->socks_request->address));
+ tor_addr_to_str(conn->socks_request->address, new_addr,
+ sizeof(conn->socks_request->address),
+ 1);
control_event_stream_status(conn, STREAM_EVENT_REMAP,
REMAP_STREAM_SOURCE_EXIT);
}
+/** Extract the contents of a connected cell in <b>cell</b>, whose relay
+ * header has already been parsed into <b>rh</b>. On success, set
+ * <b>addr_out</b> to the address we're connected to, and <b>ttl_out</b> to
+ * the ttl of that address, in seconds, and return 0. On failure, return
+ * -1. */
+int
+connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
+ tor_addr_t *addr_out, int *ttl_out)
+{
+ uint32_t bytes;
+ const uint8_t *payload = cell->payload + RELAY_HEADER_SIZE;
+
+ tor_addr_make_unspec(addr_out);
+ *ttl_out = -1;
+ if (rh->length == 0)
+ return 0;
+ if (rh->length < 4)
+ return -1;
+ bytes = ntohl(get_uint32(payload));
+
+ /* If bytes is 0, this is maybe a v6 address. Otherwise it's a v4 address */
+ if (bytes != 0) {
+ /* v4 address */
+ tor_addr_from_ipv4h(addr_out, bytes);
+ if (rh->length >= 8) {
+ bytes = ntohl(get_uint32(payload + 4));
+ if (bytes <= INT32_MAX)
+ *ttl_out = bytes;
+ }
+ } else {
+ if (rh->length < 25) /* 4 bytes of 0s, 1 addr, 16 ipv4, 4 ttl. */
+ return -1;
+ if (get_uint8(payload + 4) != 6)
+ return -1;
+ tor_addr_from_ipv6_bytes(addr_out, (char*)(payload + 5));
+ bytes = ntohl(get_uint32(payload + 21));
+ if (bytes <= INT32_MAX)
+ *ttl_out = (int) bytes;
+ }
+ return 0;
+}
+
/** An incoming relay cell has arrived from circuit <b>circ</b> to
* stream <b>conn</b>.
*
@@ -854,7 +913,7 @@ connection_edge_process_relay_cell_not_open(
edge_connection_t *conn, crypt_path_t *layer_hint)
{
if (rh->command == RELAY_COMMAND_END) {
- if (CIRCUIT_IS_ORIGIN(circ) && conn->_base.type == CONN_TYPE_AP) {
+ if (CIRCUIT_IS_ORIGIN(circ) && conn->base_.type == CONN_TYPE_AP) {
return connection_ap_process_end_not_open(rh, cell,
TO_ORIGIN_CIRCUIT(circ),
EDGE_TO_ENTRY_CONN(conn),
@@ -869,38 +928,55 @@ connection_edge_process_relay_cell_not_open(
}
}
- if (conn->_base.type == CONN_TYPE_AP &&
+ if (conn->base_.type == CONN_TYPE_AP &&
rh->command == RELAY_COMMAND_CONNECTED) {
+ tor_addr_t addr;
+ int ttl;
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
- if (conn->_base.state != AP_CONN_STATE_CONNECT_WAIT) {
+ if (conn->base_.state != AP_CONN_STATE_CONNECT_WAIT) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
"Got 'connected' while not in state connect_wait. Dropping.");
return 0;
}
- conn->_base.state = AP_CONN_STATE_OPEN;
+ conn->base_.state = AP_CONN_STATE_OPEN;
log_info(LD_APP,"'connected' received after %d seconds.",
- (int)(time(NULL) - conn->_base.timestamp_lastread));
- if (rh->length >= 4) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
- int ttl;
- if (!addr || (get_options()->ClientDNSRejectInternalAddresses &&
- is_internal_IP(addr, 0))) {
+ (int)(time(NULL) - conn->base_.timestamp_lastread));
+ if (connected_cell_parse(rh, cell, &addr, &ttl) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got a badly formatted connected cell. Closing.");
+ connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
+ connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL);
+ }
+ if (tor_addr_family(&addr) != AF_UNSPEC) {
+ const sa_family_t family = tor_addr_family(&addr);
+ if (tor_addr_is_null(&addr) ||
+ (get_options()->ClientDNSRejectInternalAddresses &&
+ tor_addr_is_internal(&addr, 0))) {
log_info(LD_APP, "...but it claims the IP address was %s. Closing.",
- fmt_addr32(addr));
+ fmt_addr(&addr));
+ connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
+ connection_mark_unattached_ap(entry_conn,
+ END_STREAM_REASON_TORPROTOCOL);
+ return 0;
+ }
+
+ if ((family == AF_INET && ! entry_conn->ipv4_traffic_ok) ||
+ (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got a connected cell to %s with unsupported address family."
+ " Closing.", fmt_addr(&addr));
connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_TORPROTOCOL);
return 0;
}
- if (rh->length >= 8)
- ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+4));
- else
- ttl = -1;
- client_dns_set_addressmap(entry_conn->socks_request->address, addr,
+
+ client_dns_set_addressmap(TO_ORIGIN_CIRCUIT(circ),
+ entry_conn->socks_request->address, &addr,
entry_conn->chosen_exit_name, ttl);
- remap_event_helper(entry_conn, addr);
+ remap_event_helper(entry_conn, &addr);
}
circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ));
/* don't send a socks reply to transparent conns */
@@ -944,13 +1020,13 @@ connection_edge_process_relay_cell_not_open(
}
return 0;
}
- if (conn->_base.type == CONN_TYPE_AP &&
+ if (conn->base_.type == CONN_TYPE_AP &&
rh->command == RELAY_COMMAND_RESOLVED) {
int ttl;
int answer_len;
uint8_t answer_type;
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
- if (conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT) {
+ if (conn->base_.state != AP_CONN_STATE_RESOLVE_WAIT) {
log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a 'resolved' cell while "
"not in state resolve_wait. Dropping.");
return 0;
@@ -990,8 +1066,15 @@ connection_edge_process_relay_cell_not_open(
ttl,
-1);
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
- remap_event_helper(entry_conn, addr);
+ tor_addr_t addr;
+ tor_addr_from_ipv4n(&addr,
+ get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
+ remap_event_helper(entry_conn, &addr);
+ } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
+ tor_addr_t addr;
+ tor_addr_from_ipv6_bytes(&addr,
+ (char*)(cell->payload+RELAY_HEADER_SIZE+2));
+ remap_event_helper(entry_conn, &addr);
}
connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_DONE |
@@ -1001,8 +1084,8 @@ connection_edge_process_relay_cell_not_open(
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Got an unexpected relay command %d, in state %d (%s). Dropping.",
- rh->command, conn->_base.state,
- conn_state_to_string(conn->_base.type, conn->_base.state));
+ rh->command, conn->base_.state,
+ conn_state_to_string(conn->base_.type, conn->base_.state));
return 0; /* for forward compatibility, don't kill the circuit */
// connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
// connection_mark_for_close(conn);
@@ -1050,9 +1133,9 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
* conn points to the recognized stream. */
if (conn && !connection_state_is_open(TO_CONN(conn))) {
- if (conn->_base.type == CONN_TYPE_EXIT &&
- (conn->_base.state == EXIT_CONN_STATE_CONNECTING ||
- conn->_base.state == EXIT_CONN_STATE_RESOLVING) &&
+ if (conn->base_.type == CONN_TYPE_EXIT &&
+ (conn->base_.state == EXIT_CONN_STATE_CONNECTING ||
+ conn->base_.state == EXIT_CONN_STATE_RESOLVING) &&
rh.command == RELAY_COMMAND_DATA) {
/* Allow DATA cells to be delivered to an exit node in state
* EXIT_CONN_STATE_CONNECTING or EXIT_CONN_STATE_RESOLVING.
@@ -1095,7 +1178,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
* and linked. */
static uint64_t next_id = 0;
circ->dirreq_id = ++next_id;
- TO_CONN(TO_OR_CIRCUIT(circ)->p_conn)->dirreq_id = circ->dirreq_id;
+ TO_OR_CIRCUIT(circ)->p_chan->dirreq_id = circ->dirreq_id;
}
return connection_exit_begin_conn(cell, circ);
@@ -1151,11 +1234,12 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
return 0;
}
/* XXX add to this log_fn the exit node's nickname? */
- log_info(domain,"%d: end cell (%s) for stream %d. Removing stream.",
- conn->_base.s,
+ log_info(domain,TOR_SOCKET_T_FORMAT": end cell (%s) for stream %d. "
+ "Removing stream.",
+ conn->base_.s,
stream_end_reason_to_string(reason),
conn->stream_id);
- if (conn->_base.type == CONN_TYPE_AP) {
+ if (conn->base_.type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
if (entry_conn->socks_request &&
!entry_conn->socks_request->has_finished)
@@ -1166,7 +1250,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
conn->edge_has_sent_end = 1;
if (!conn->end_reason)
conn->end_reason = reason | END_STREAM_REASON_FLAG_REMOTE;
- if (!conn->_base.marked_for_close) {
+ if (!conn->base_.marked_for_close) {
/* only mark it if not already marked. it's possible to
* get the 'end' right around when the client hangs up on us. */
connection_mark_and_flush(TO_CONN(conn));
@@ -1175,7 +1259,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
case RELAY_COMMAND_EXTEND: {
static uint64_t total_n_extend=0, total_nonearly=0;
total_n_extend++;
- if (conn) {
+ if (rh.stream_id) {
log_fn(LOG_PROTOCOL_WARN, domain,
"'extend' cell received for non-zero stream. Dropping.");
return 0;
@@ -1230,12 +1314,12 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
"'truncate' unsupported at origin. Dropping.");
return 0;
}
- if (circ->n_conn) {
- uint8_t trunc_reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE);
- circuit_clear_cell_queue(circ, circ->n_conn);
- connection_or_send_destroy(circ->n_circ_id, circ->n_conn,
- trunc_reason);
- circuit_set_n_circid_orconn(circ, 0, NULL);
+ if (circ->n_chan) {
+ uint8_t trunc_reason = get_uint8(cell->payload + RELAY_HEADER_SIZE);
+ circuit_clear_cell_queue(circ, circ->n_chan);
+ channel_send_destroy(circ->n_circ_id, circ->n_chan,
+ trunc_reason);
+ circuit_set_n_circid_chan(circ, 0, NULL);
}
log_debug(LD_EXIT, "Processed 'truncate', replying.");
{
@@ -1251,7 +1335,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
"'truncated' unsupported at non-origin. Dropping.");
return 0;
}
- circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint);
+ circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint,
+ get_uint8(cell->payload + RELAY_HEADER_SIZE));
return 0;
case RELAY_COMMAND_CONNECTED:
if (conn) {
@@ -1267,7 +1352,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (layer_hint) {
if (layer_hint->package_window + CIRCWINDOW_INCREMENT >
CIRCWINDOW_START_MAX) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ /*XXXX024: Downgrade this back to LOG_PROTOCOL_WARN after a while*/
+ log_fn(LOG_WARN, LD_PROTOCOL,
"Bug/attack: unexpected sendme cell from exit relay. "
"Closing circ.");
return -END_CIRC_REASON_TORPROTOCOL;
@@ -1279,7 +1365,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
} else {
if (circ->package_window + CIRCWINDOW_INCREMENT >
CIRCWINDOW_START_MAX) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ /*XXXX024: Downgrade this back to LOG_PROTOCOL_WARN after a while*/
+ log_fn(LOG_WARN, LD_PROTOCOL,
"Bug/attack: unexpected sendme cell from client. "
"Closing circ.");
return -END_CIRC_REASON_TORPROTOCOL;
@@ -1389,21 +1476,21 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
size_t bytes_to_process, length;
char payload[CELL_PAYLOAD_SIZE];
circuit_t *circ;
- const unsigned domain = conn->_base.type == CONN_TYPE_AP ? LD_APP : LD_EXIT;
+ const unsigned domain = conn->base_.type == CONN_TYPE_AP ? LD_APP : LD_EXIT;
int sending_from_optimistic = 0;
const int sending_optimistically =
- conn->_base.type == CONN_TYPE_AP &&
- conn->_base.state != AP_CONN_STATE_OPEN;
+ conn->base_.type == CONN_TYPE_AP &&
+ conn->base_.state != AP_CONN_STATE_OPEN;
entry_connection_t *entry_conn =
- conn->_base.type == CONN_TYPE_AP ? EDGE_TO_ENTRY_CONN(conn) : NULL;
+ conn->base_.type == CONN_TYPE_AP ? EDGE_TO_ENTRY_CONN(conn) : NULL;
crypt_path_t *cpath_layer = conn->cpath_layer;
tor_assert(conn);
- if (conn->_base.marked_for_close) {
+ if (conn->base_.marked_for_close) {
log_warn(LD_BUG,
"called on conn that's already marked for close at %s:%d.",
- conn->_base.marked_for_close_file, conn->_base.marked_for_close);
+ conn->base_.marked_for_close_file, conn->base_.marked_for_close);
return 0;
}
@@ -1470,7 +1557,8 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
connection_fetch_from_buf(payload, length, TO_CONN(conn));
}
- log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s,
+ log_debug(domain,TOR_SOCKET_T_FORMAT": Packaging %d bytes (%d waiting).",
+ conn->base_.s,
(int)length, (int)connection_get_inbuf_len(TO_CONN(conn)));
if (sending_optimistically && !sending_from_optimistic) {
@@ -1536,9 +1624,9 @@ connection_edge_consider_sending_sendme(edge_connection_t *conn)
}
while (conn->deliver_window <= STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
- log_debug(conn->_base.type == CONN_TYPE_AP ?LD_APP:LD_EXIT,
+ log_debug(conn->base_.type == CONN_TYPE_AP ?LD_APP:LD_EXIT,
"Outbuf %d, Queuing stream sendme.",
- (int)conn->_base.outbuf_flushlen);
+ (int)conn->base_.outbuf_flushlen);
conn->deliver_window += STREAMWINDOW_INCREMENT;
if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME,
NULL, 0) < 0) {
@@ -1591,10 +1679,10 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
* needed to fill the cell queue. */
int max_to_package = circ->package_window;
if (CIRCUIT_IS_ORIGIN(circ)) {
- cells_on_queue = circ->n_conn_cells.n;
+ cells_on_queue = circ->n_chan_cells.n;
} else {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
- cells_on_queue = or_circ->p_conn_cells.n;
+ cells_on_queue = or_circ->p_chan_cells.n;
}
if (CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue < max_to_package)
max_to_package = CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue;
@@ -1627,7 +1715,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
/* Activate reading starting from the chosen stream */
for (conn=chosen_stream; conn; conn = conn->next_stream) {
/* Start reading for the streams starting from here */
- if (conn->_base.marked_for_close || conn->package_window <= 0)
+ if (conn->base_.marked_for_close || conn->package_window <= 0)
continue;
if (!layer_hint || conn->cpath_layer == layer_hint) {
connection_start_reading(TO_CONN(conn));
@@ -1638,7 +1726,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
}
/* Go back and do the ones we skipped, circular-style */
for (conn = first_conn; conn != chosen_stream; conn = conn->next_stream) {
- if (conn->_base.marked_for_close || conn->package_window <= 0)
+ if (conn->base_.marked_for_close || conn->package_window <= 0)
continue;
if (!layer_hint || conn->cpath_layer == layer_hint) {
connection_start_reading(TO_CONN(conn));
@@ -1664,7 +1752,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
* package.
*/
for (conn=first_conn; conn; conn=conn->next_stream) {
- if (conn->_base.marked_for_close || conn->package_window <= 0)
+ if (conn->base_.marked_for_close || conn->package_window <= 0)
continue;
if (!layer_hint || conn->cpath_layer == layer_hint) {
int n = cells_per_conn, r;
@@ -1775,10 +1863,10 @@ circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint)
}
#ifdef ACTIVE_CIRCUITS_PARANOIA
-#define assert_active_circuits_ok_paranoid(conn) \
- assert_active_circuits_ok(conn)
+#define assert_cmux_ok_paranoid(chan) \
+ assert_circuit_mux_okay(chan)
#else
-#define assert_active_circuits_ok_paranoid(conn)
+#define assert_cmux_ok_paranoid(chan)
#endif
/** The total number of cells we have allocated from the memory pool. */
@@ -1833,12 +1921,19 @@ packed_cell_free_unchecked(packed_cell_t *cell)
/** Allocate and return a new packed_cell_t. */
static INLINE packed_cell_t *
-packed_cell_alloc(void)
+packed_cell_new(void)
{
++total_cells_allocated;
return mp_pool_get(cell_pool);
}
+/** Return a packed cell used outside by channel_t lower layer */
+void
+packed_cell_free(packed_cell_t *cell)
+{
+ packed_cell_free_unchecked(cell);
+}
+
/** Log current statistics for cell pool allocation at log level
* <b>severity</b>. */
void
@@ -1847,10 +1942,10 @@ dump_cell_pool_usage(int severity)
circuit_t *c;
int n_circs = 0;
int n_cells = 0;
- for (c = _circuit_get_global_list(); c; c = c->next) {
- n_cells += c->n_conn_cells.n;
+ for (c = circuit_get_global_list_(); c; c = c->next) {
+ n_cells += c->n_chan_cells.n;
if (!CIRCUIT_IS_ORIGIN(c))
- n_cells += TO_OR_CIRCUIT(c)->p_conn_cells.n;
+ n_cells += TO_OR_CIRCUIT(c)->p_chan_cells.n;
++n_circs;
}
log(severity, LD_MM, "%d cells allocated on %d circuits. %d cells leaked.",
@@ -1862,7 +1957,7 @@ dump_cell_pool_usage(int severity)
static INLINE packed_cell_t *
packed_cell_copy(const cell_t *cell)
{
- packed_cell_t *c = packed_cell_alloc();
+ packed_cell_t *c = packed_cell_new();
cell_pack(c, cell);
c->next = NULL;
return c;
@@ -1961,363 +2056,68 @@ cell_queue_pop(cell_queue_t *queue)
return cell;
}
-/** Return a pointer to the "next_active_on_{n,p}_conn" pointer of <b>circ</b>,
- * depending on whether <b>conn</b> matches n_conn or p_conn. */
-static INLINE circuit_t **
-next_circ_on_conn_p(circuit_t *circ, or_connection_t *conn)
-{
- tor_assert(circ);
- tor_assert(conn);
- if (conn == circ->n_conn) {
- return &circ->next_active_on_n_conn;
- } else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(conn == orcirc->p_conn);
- return &orcirc->next_active_on_p_conn;
- }
-}
-
-/** Return a pointer to the "prev_active_on_{n,p}_conn" pointer of <b>circ</b>,
- * depending on whether <b>conn</b> matches n_conn or p_conn. */
-static INLINE circuit_t **
-prev_circ_on_conn_p(circuit_t *circ, or_connection_t *conn)
-{
- tor_assert(circ);
- tor_assert(conn);
- if (conn == circ->n_conn) {
- return &circ->prev_active_on_n_conn;
- } else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(conn == orcirc->p_conn);
- return &orcirc->prev_active_on_p_conn;
- }
-}
-
-/** Helper for sorting cell_ewma_t values in their priority queue. */
-static int
-compare_cell_ewma_counts(const void *p1, const void *p2)
-{
- const cell_ewma_t *e1=p1, *e2=p2;
- if (e1->cell_count < e2->cell_count)
- return -1;
- else if (e1->cell_count > e2->cell_count)
- return 1;
- else
- return 0;
-}
-
-/** Given a cell_ewma_t, return a pointer to the circuit containing it. */
-static circuit_t *
-cell_ewma_to_circuit(cell_ewma_t *ewma)
-{
- if (ewma->is_for_p_conn) {
- /* This is an or_circuit_t's p_cell_ewma. */
- or_circuit_t *orcirc = SUBTYPE_P(ewma, or_circuit_t, p_cell_ewma);
- return TO_CIRCUIT(orcirc);
- } else {
- /* This is some circuit's n_cell_ewma. */
- return SUBTYPE_P(ewma, circuit_t, n_cell_ewma);
- }
-}
-
-/* ==== Functions for scaling cell_ewma_t ====
-
- When choosing which cells to relay first, we favor circuits that have been
- quiet recently. This gives better latency on connections that aren't
- pushing lots of data, and makes the network feel more interactive.
-
- Conceptually, we take an exponentially weighted mean average of the number
- of cells a circuit has sent, and allow active circuits (those with cells to
- relay) to send cells in reverse order of their exponentially-weighted mean
- average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts'
- F^N times as much as a cell sent now, for 0<F<1.0, and we favor the
- circuit that has sent the fewest cells]
-
- If 'double' had infinite precision, we could do this simply by counting a
- cell sent at startup as having weight 1.0, and a cell sent N seconds later
- as having weight F^-N. This way, we would never need to re-scale
- any already-sent cells.
-
- To prevent double from overflowing, we could count a cell sent now as
- having weight 1.0 and a cell sent N seconds ago as having weight F^N.
- This, however, would mean we'd need to re-scale *ALL* old circuits every
- time we wanted to send a cell.
-
- So as a compromise, we divide time into 'ticks' (currently, 10-second
- increments) and say that a cell sent at the start of a current tick is
- worth 1.0, a cell sent N seconds before the start of the current tick is
- worth F^N, and a cell sent N seconds after the start of the current tick is
- worth F^-N. This way we don't overflow, and we don't need to constantly
- rescale.
- */
-
-/** How long does a tick last (seconds)? */
-#define EWMA_TICK_LEN 10
-
-/** The default per-tick scale factor, if it hasn't been overridden by a
- * consensus or a configuration setting. zero means "disabled". */
-#define EWMA_DEFAULT_HALFLIFE 0.0
-
-/** Given a timeval <b>now</b>, compute the cell_ewma tick in which it occurs
- * and the fraction of the tick that has elapsed between the start of the tick
- * and <b>now</b>. Return the former and store the latter in
- * *<b>remainder_out</b>.
- *
- * These tick values are not meant to be shared between Tor instances, or used
- * for other purposes. */
-static unsigned
-cell_ewma_tick_from_timeval(const struct timeval *now,
- double *remainder_out)
-{
- unsigned res = (unsigned) (now->tv_sec / EWMA_TICK_LEN);
- /* rem */
- double rem = (now->tv_sec % EWMA_TICK_LEN) +
- ((double)(now->tv_usec)) / 1.0e6;
- *remainder_out = rem / EWMA_TICK_LEN;
- return res;
-}
-
-/** Compute and return the current cell_ewma tick. */
-unsigned
-cell_ewma_get_tick(void)
-{
- return ((unsigned)approx_time() / EWMA_TICK_LEN);
-}
-
-/** The per-tick scale factor to be used when computing cell-count EWMA
- * values. (A cell sent N ticks before the start of the current tick
- * has value ewma_scale_factor ** N.)
+/**
+ * Update the number of cells available on the circuit's n_chan or p_chan's
+ * circuit mux.
*/
-static double ewma_scale_factor = 0.1;
-/* DOCDOC ewma_enabled */
-static int ewma_enabled = 0;
-
-/*DOCDOC*/
-#define EPSILON 0.00001
-/*DOCDOC*/
-#define LOG_ONEHALF -0.69314718055994529
-
-/** Adjust the global cell scale factor based on <b>options</b> */
-void
-cell_ewma_set_scale_factor(const or_options_t *options,
- const networkstatus_t *consensus)
-{
- int32_t halflife_ms;
- double halflife;
- const char *source;
- if (options && options->CircuitPriorityHalflife >= -EPSILON) {
- halflife = options->CircuitPriorityHalflife;
- source = "CircuitPriorityHalflife in configuration";
- } else if (consensus && (halflife_ms = networkstatus_get_param(
- consensus, "CircuitPriorityHalflifeMsec",
- -1, -1, INT32_MAX)) >= 0) {
- halflife = ((double)halflife_ms)/1000.0;
- source = "CircuitPriorityHalflifeMsec in consensus";
- } else {
- halflife = EWMA_DEFAULT_HALFLIFE;
- source = "Default value";
- }
-
- if (halflife <= EPSILON) {
- /* The cell EWMA algorithm is disabled. */
- ewma_scale_factor = 0.1;
- ewma_enabled = 0;
- log_info(LD_OR,
- "Disabled cell_ewma algorithm because of value in %s",
- source);
- } else {
- /* convert halflife into halflife-per-tick. */
- halflife /= EWMA_TICK_LEN;
- /* compute per-tick scale factor. */
- ewma_scale_factor = exp( LOG_ONEHALF / halflife );
- ewma_enabled = 1;
- log_info(LD_OR,
- "Enabled cell_ewma algorithm because of value in %s; "
- "scale factor is %f per %d seconds",
- source, ewma_scale_factor, EWMA_TICK_LEN);
- }
-}
-
-/** Return the multiplier necessary to convert the value of a cell sent in
- * 'from_tick' to one sent in 'to_tick'. */
-static INLINE double
-get_scale_factor(unsigned from_tick, unsigned to_tick)
-{
- /* This math can wrap around, but that's okay: unsigned overflow is
- well-defined */
- int diff = (int)(to_tick - from_tick);
- return pow(ewma_scale_factor, diff);
-}
-
-/** Adjust the cell count of <b>ewma</b> so that it is scaled with respect to
- * <b>cur_tick</b> */
-static void
-scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick)
-{
- double factor = get_scale_factor(ewma->last_adjusted_tick, cur_tick);
- ewma->cell_count *= factor;
- ewma->last_adjusted_tick = cur_tick;
-}
-
-/** Adjust the cell count of every active circuit on <b>conn</b> so
- * that they are scaled with respect to <b>cur_tick</b> */
-static void
-scale_active_circuits(or_connection_t *conn, unsigned cur_tick)
-{
-
- double factor = get_scale_factor(
- conn->active_circuit_pqueue_last_recalibrated,
- cur_tick);
- /** Ordinarily it isn't okay to change the value of an element in a heap,
- * but it's okay here, since we are preserving the order. */
- SMARTLIST_FOREACH(conn->active_circuit_pqueue, cell_ewma_t *, e, {
- tor_assert(e->last_adjusted_tick ==
- conn->active_circuit_pqueue_last_recalibrated);
- e->cell_count *= factor;
- e->last_adjusted_tick = cur_tick;
- });
- conn->active_circuit_pqueue_last_recalibrated = cur_tick;
-}
-
-/** Rescale <b>ewma</b> to the same scale as <b>conn</b>, and add it to
- * <b>conn</b>'s priority queue of active circuits */
-static void
-add_cell_ewma_to_conn(or_connection_t *conn, cell_ewma_t *ewma)
-{
- tor_assert(ewma->heap_index == -1);
- scale_single_cell_ewma(ewma,
- conn->active_circuit_pqueue_last_recalibrated);
-
- smartlist_pqueue_add(conn->active_circuit_pqueue,
- compare_cell_ewma_counts,
- STRUCT_OFFSET(cell_ewma_t, heap_index),
- ewma);
-}
-
-/** Remove <b>ewma</b> from <b>conn</b>'s priority queue of active circuits */
-static void
-remove_cell_ewma_from_conn(or_connection_t *conn, cell_ewma_t *ewma)
-{
- tor_assert(ewma->heap_index != -1);
- smartlist_pqueue_remove(conn->active_circuit_pqueue,
- compare_cell_ewma_counts,
- STRUCT_OFFSET(cell_ewma_t, heap_index),
- ewma);
-}
-
-/** Remove and return the first cell_ewma_t from conn's priority queue of
- * active circuits. Requires that the priority queue is nonempty. */
-static cell_ewma_t *
-pop_first_cell_ewma_from_conn(or_connection_t *conn)
-{
- return smartlist_pqueue_pop(conn->active_circuit_pqueue,
- compare_cell_ewma_counts,
- STRUCT_OFFSET(cell_ewma_t, heap_index));
-}
-
-/** Add <b>circ</b> to the list of circuits with pending cells on
- * <b>conn</b>. No effect if <b>circ</b> is already linked. */
void
-make_circuit_active_on_conn(circuit_t *circ, or_connection_t *conn)
+update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
+ const char *file, int lineno)
{
- circuit_t **nextp = next_circ_on_conn_p(circ, conn);
- circuit_t **prevp = prev_circ_on_conn_p(circ, conn);
+ channel_t *chan = NULL;
+ or_circuit_t *or_circ = NULL;
+ circuitmux_t *cmux = NULL;
- if (*nextp && *prevp) {
- /* Already active. */
- return;
- }
-
- assert_active_circuits_ok_paranoid(conn);
+ tor_assert(circ);
- if (! conn->active_circuits) {
- conn->active_circuits = circ;
- *prevp = *nextp = circ;
+ /* Okay, get the channel */
+ if (direction == CELL_DIRECTION_OUT) {
+ chan = circ->n_chan;
} else {
- circuit_t *head = conn->active_circuits;
- circuit_t *old_tail = *prev_circ_on_conn_p(head, conn);
- *next_circ_on_conn_p(old_tail, conn) = circ;
- *nextp = head;
- *prev_circ_on_conn_p(head, conn) = circ;
- *prevp = old_tail;
+ or_circ = TO_OR_CIRCUIT(circ);
+ chan = or_circ->p_chan;
}
- if (circ->n_conn == conn) {
- add_cell_ewma_to_conn(conn, &circ->n_cell_ewma);
- } else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(conn == orcirc->p_conn);
- add_cell_ewma_to_conn(conn, &orcirc->p_cell_ewma);
- }
+ tor_assert(chan);
+ tor_assert(chan->cmux);
- assert_active_circuits_ok_paranoid(conn);
-}
+ /* Now get the cmux */
+ cmux = chan->cmux;
-/** Remove <b>circ</b> from the list of circuits with pending cells on
- * <b>conn</b>. No effect if <b>circ</b> is already unlinked. */
-void
-make_circuit_inactive_on_conn(circuit_t *circ, or_connection_t *conn)
-{
- circuit_t **nextp = next_circ_on_conn_p(circ, conn);
- circuit_t **prevp = prev_circ_on_conn_p(circ, conn);
- circuit_t *next = *nextp, *prev = *prevp;
-
- if (!next && !prev) {
- /* Already inactive. */
+ /* Cmux sanity check */
+ if (! circuitmux_is_circuit_attached(cmux, circ)) {
+ log_warn(LD_BUG, "called on non-attachd circuit from %s:%d",
+ file, lineno);
return;
}
+ tor_assert(circuitmux_attached_circuit_direction(cmux, circ) == direction);
- assert_active_circuits_ok_paranoid(conn);
-
- tor_assert(next && prev);
- tor_assert(*prev_circ_on_conn_p(next, conn) == circ);
- tor_assert(*next_circ_on_conn_p(prev, conn) == circ);
-
- if (next == circ) {
- conn->active_circuits = NULL;
- } else {
- *prev_circ_on_conn_p(next, conn) = prev;
- *next_circ_on_conn_p(prev, conn) = next;
- if (conn->active_circuits == circ)
- conn->active_circuits = next;
- }
- *prevp = *nextp = NULL;
+ assert_cmux_ok_paranoid(chan);
- if (circ->n_conn == conn) {
- remove_cell_ewma_from_conn(conn, &circ->n_cell_ewma);
+ /* Update the number of cells we have for the circuit mux */
+ if (direction == CELL_DIRECTION_OUT) {
+ circuitmux_set_num_cells(cmux, circ, circ->n_chan_cells.n);
} else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(conn == orcirc->p_conn);
- remove_cell_ewma_from_conn(conn, &orcirc->p_cell_ewma);
+ circuitmux_set_num_cells(cmux, circ, or_circ->p_chan_cells.n);
}
- assert_active_circuits_ok_paranoid(conn);
+ assert_cmux_ok_paranoid(chan);
}
-/** Remove all circuits from the list of circuits with pending cells on
- * <b>conn</b>. */
+/** Remove all circuits from the cmux on <b>chan</b>. */
void
-connection_or_unlink_all_active_circs(or_connection_t *orconn)
+channel_unlink_all_circuits(channel_t *chan)
{
- circuit_t *head = orconn->active_circuits;
- circuit_t *cur = head;
- if (! head)
- return;
- do {
- circuit_t *next = *next_circ_on_conn_p(cur, orconn);
- *prev_circ_on_conn_p(cur, orconn) = NULL;
- *next_circ_on_conn_p(cur, orconn) = NULL;
- cur = next;
- } while (cur != head);
- orconn->active_circuits = NULL;
-
- SMARTLIST_FOREACH(orconn->active_circuit_pqueue, cell_ewma_t *, e,
- e->heap_index = -1);
- smartlist_clear(orconn->active_circuit_pqueue);
+ tor_assert(chan);
+ tor_assert(chan->cmux);
+
+ circuitmux_detach_all_circuits(chan->cmux);
+ chan->num_n_circuits = 0;
+ chan->num_p_circuits = 0;
}
/** Block (if <b>block</b> is true) or unblock (if <b>block</b> is false)
- * every edge connection that is using <b>circ</b> to write to <b>orconn</b>,
+ * every edge connection that is using <b>circ</b> to write to <b>chan</b>,
* and start or stop reading as appropriate.
*
* If <b>stream_id</b> is nonzero, block only the edge connection whose
@@ -2326,17 +2126,17 @@ connection_or_unlink_all_active_circs(or_connection_t *orconn)
* Returns the number of streams whose status we changed.
*/
static int
-set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
+set_streams_blocked_on_circ(circuit_t *circ, channel_t *chan,
int block, streamid_t stream_id)
{
edge_connection_t *edge = NULL;
int n = 0;
- if (circ->n_conn == orconn) {
- circ->streams_blocked_on_n_conn = block;
+ if (circ->n_chan == chan) {
+ circ->streams_blocked_on_n_chan = block;
if (CIRCUIT_IS_ORIGIN(circ))
edge = TO_ORIGIN_CIRCUIT(circ)->p_streams;
} else {
- circ->streams_blocked_on_p_conn = block;
+ circ->streams_blocked_on_p_chan = block;
tor_assert(!CIRCUIT_IS_ORIGIN(circ));
edge = TO_OR_CIRCUIT(circ)->n_streams;
}
@@ -2371,58 +2171,51 @@ set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
}
/** Pull as many cells as possible (but no more than <b>max</b>) from the
- * queue of the first active circuit on <b>conn</b>, and write them to
- * <b>conn</b>-&gt;outbuf. Return the number of cells written. Advance
+ * queue of the first active circuit on <b>chan</b>, and write them to
+ * <b>chan</b>-&gt;outbuf. Return the number of cells written. Advance
* the active circuit pointer to the next active circuit in the ring. */
int
-connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max,
- time_t now)
+channel_flush_from_first_active_circuit(channel_t *chan, int max)
{
- int n_flushed;
+ circuitmux_t *cmux = NULL;
+ int n_flushed = 0;
cell_queue_t *queue;
circuit_t *circ;
+ or_circuit_t *or_circ;
int streams_blocked;
-
- /* The current (hi-res) time */
- struct timeval now_hires;
-
- /* The EWMA cell counter for the circuit we're flushing. */
- cell_ewma_t *cell_ewma = NULL;
- double ewma_increment = -1;
-
- circ = conn->active_circuits;
- if (!circ) return 0;
- assert_active_circuits_ok_paranoid(conn);
-
- /* See if we're doing the ewma circuit selection algorithm. */
- if (ewma_enabled) {
- unsigned tick;
- double fractional_tick;
- tor_gettimeofday_cached(&now_hires);
- tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick);
-
- if (tick != conn->active_circuit_pqueue_last_recalibrated) {
- scale_active_circuits(conn, tick);
+ packed_cell_t *cell;
+
+ /* Get the cmux */
+ tor_assert(chan);
+ tor_assert(chan->cmux);
+ cmux = chan->cmux;
+
+ /* Main loop: pick a circuit, send a cell, update the cmux */
+ while (n_flushed < max) {
+ circ = circuitmux_get_first_active_circuit(cmux);
+ /* If it returns NULL, no cells left to send */
+ if (!circ) break;
+ assert_cmux_ok_paranoid(chan);
+
+ if (circ->n_chan == chan) {
+ queue = &circ->n_chan_cells;
+ streams_blocked = circ->streams_blocked_on_n_chan;
+ } else {
+ or_circ = TO_OR_CIRCUIT(circ);
+ tor_assert(or_circ->p_chan == chan);
+ queue = &TO_OR_CIRCUIT(circ)->p_chan_cells;
+ streams_blocked = circ->streams_blocked_on_p_chan;
}
- ewma_increment = pow(ewma_scale_factor, -fractional_tick);
-
- cell_ewma = smartlist_get(conn->active_circuit_pqueue, 0);
- circ = cell_ewma_to_circuit(cell_ewma);
- }
-
- if (circ->n_conn == conn) {
- queue = &circ->n_conn_cells;
- streams_blocked = circ->streams_blocked_on_n_conn;
- } else {
- queue = &TO_OR_CIRCUIT(circ)->p_conn_cells;
- streams_blocked = circ->streams_blocked_on_p_conn;
- }
- tor_assert(*next_circ_on_conn_p(circ,conn));
+ /* Circuitmux told us this was active, so it should have cells */
+ tor_assert(queue->n > 0);
- for (n_flushed = 0; n_flushed < max && queue->head; ) {
- packed_cell_t *cell = cell_queue_pop(queue);
- tor_assert(*next_circ_on_conn_p(circ,conn));
+ /*
+ * Get just one cell here; once we've sent it, that can change the circuit
+ * selection, so we have to loop around for another even if this circuit
+ * has more than one.
+ */
+ cell = cell_queue_pop(queue);
/* Calculate the exact time that this cell has spent in the queue. */
if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) {
@@ -2438,8 +2231,8 @@ connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max,
"Looks like the CellStatistics option was "
"recently enabled.");
} else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
insertion_time_elem_t *elem = it_queue->first;
+ or_circ = TO_OR_CIRCUIT(circ);
cell_waiting_time =
(uint32_t)((flushed * 10L + SECONDS_IN_A_DAY * 1000L -
elem->insertion_time * 10L) %
@@ -2452,66 +2245,58 @@ connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max,
it_queue->last = NULL;
mp_pool_release(elem);
}
- orcirc->total_cell_waiting_time += cell_waiting_time;
- orcirc->processed_cells++;
+ or_circ->total_cell_waiting_time += cell_waiting_time;
+ or_circ->processed_cells++;
}
}
/* If we just flushed our queue and this circuit is used for a
* tunneled directory request, possibly advance its state. */
- if (queue->n == 0 && TO_CONN(conn)->dirreq_id)
- geoip_change_dirreq_state(TO_CONN(conn)->dirreq_id,
+ if (queue->n == 0 && chan->dirreq_id)
+ geoip_change_dirreq_state(chan->dirreq_id,
DIRREQ_TUNNELED,
DIRREQ_CIRC_QUEUE_FLUSHED);
- connection_write_to_buf(cell->body, CELL_NETWORK_SIZE, TO_CONN(conn));
+ /* Now send the cell */
+ channel_write_packed_cell(chan, cell);
+ cell = NULL;
- packed_cell_free_unchecked(cell);
+ /*
+ * Don't packed_cell_free_unchecked(cell) here because the channel will
+ * do so when it gets out of the channel queue (probably already did, in
+ * which case that was an immediate double-free bug).
+ */
+
+ /* Update the counter */
++n_flushed;
- if (cell_ewma) {
- cell_ewma_t *tmp;
- cell_ewma->cell_count += ewma_increment;
- /* We pop and re-add the cell_ewma_t here, not above, since we need to
- * re-add it immediately to keep the priority queue consistent with
- * the linked-list implementation */
- tmp = pop_first_cell_ewma_from_conn(conn);
- tor_assert(tmp == cell_ewma);
- add_cell_ewma_to_conn(conn, cell_ewma);
- }
- if (!ewma_enabled && circ != conn->active_circuits) {
- /* If this happens, the current circuit just got made inactive by
- * a call in connection_write_to_buf(). That's nothing to worry about:
- * circuit_make_inactive_on_conn() already advanced conn->active_circuits
- * for us.
- */
- assert_active_circuits_ok_paranoid(conn);
- goto done;
- }
- }
- tor_assert(*next_circ_on_conn_p(circ,conn));
- assert_active_circuits_ok_paranoid(conn);
- conn->active_circuits = *next_circ_on_conn_p(circ, conn);
- /* Is the cell queue low enough to unblock all the streams that are waiting
- * to write to this circuit? */
- if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE)
- set_streams_blocked_on_circ(circ, conn, 0, 0); /* unblock streams */
+ /*
+ * Now update the cmux; tell it we've just sent a cell, and how many
+ * we have left.
+ */
+ circuitmux_notify_xmit_cells(cmux, circ, 1);
+ circuitmux_set_num_cells(cmux, circ, queue->n);
+ if (queue->n == 0)
+ log_debug(LD_GENERAL, "Made a circuit inactive.");
- /* Did we just run out of cells on this circuit's queue? */
- if (queue->n == 0) {
- log_debug(LD_GENERAL, "Made a circuit inactive.");
- make_circuit_inactive_on_conn(circ, conn);
+ /* Is the cell queue low enough to unblock all the streams that are waiting
+ * to write to this circuit? */
+ if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE)
+ set_streams_blocked_on_circ(circ, chan, 0, 0); /* unblock streams */
+
+ /* If n_flushed < max still, loop around and pick another circuit */
}
- done:
- if (n_flushed)
- conn->timestamp_last_added_nonpadding = now;
+
+ /* Okay, we're done sending now */
+ assert_cmux_ok_paranoid(chan);
+
return n_flushed;
}
-/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>orconn</b>
+/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b>
* transmitting in <b>direction</b>. */
void
-append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
+append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
cell_t *cell, cell_direction_t direction,
streamid_t fromstream)
{
@@ -2521,12 +2306,12 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
return;
if (direction == CELL_DIRECTION_OUT) {
- queue = &circ->n_conn_cells;
- streams_blocked = circ->streams_blocked_on_n_conn;
+ queue = &circ->n_chan_cells;
+ streams_blocked = circ->streams_blocked_on_n_chan;
} else {
or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- queue = &orcirc->p_conn_cells;
- streams_blocked = circ->streams_blocked_on_p_conn;
+ queue = &orcirc->p_chan_cells;
+ streams_blocked = circ->streams_blocked_on_p_chan;
}
cell_queue_append_packed_copy(queue, cell);
@@ -2534,27 +2319,27 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
/* If we have too many cells on the circuit, we should stop reading from
* the edge streams for a while. */
if (!streams_blocked && queue->n >= CELL_QUEUE_HIGHWATER_SIZE)
- set_streams_blocked_on_circ(circ, orconn, 1, 0); /* block streams */
+ set_streams_blocked_on_circ(circ, chan, 1, 0); /* block streams */
if (streams_blocked && fromstream) {
/* This edge connection is apparently not blocked; block it. */
- set_streams_blocked_on_circ(circ, orconn, 1, fromstream);
+ set_streams_blocked_on_circ(circ, chan, 1, fromstream);
}
+ update_circuit_on_cmux(circ, direction);
if (queue->n == 1) {
- /* This was the first cell added to the queue. We need to make this
+ /* This was the first cell added to the queue. We just made this
* circuit active. */
log_debug(LD_GENERAL, "Made a circuit active.");
- make_circuit_active_on_conn(circ, orconn);
}
- if (! connection_get_outbuf_len(TO_CONN(orconn))) {
+ if (!channel_has_queued_writes(chan)) {
/* There is no data at all waiting to be sent on the outbuf. Add a
* cell, so that we can notice when it gets flushed, flushed_some can
* get called, and we can start putting more data onto the buffer then.
*/
log_debug(LD_GENERAL, "Primed a buffer.");
- connection_or_flush_from_first_active_circuit(orconn, 1, approx_time());
+ channel_flush_from_first_active_circuit(chan, 1);
}
}
@@ -2618,58 +2403,40 @@ decode_address_from_payload(tor_addr_t *addr_out, const uint8_t *payload,
return payload + 2 + payload[1];
}
-/** Remove all the cells queued on <b>circ</b> for <b>orconn</b>. */
+/** Remove all the cells queued on <b>circ</b> for <b>chan</b>. */
void
-circuit_clear_cell_queue(circuit_t *circ, or_connection_t *orconn)
+circuit_clear_cell_queue(circuit_t *circ, channel_t *chan)
{
cell_queue_t *queue;
- if (circ->n_conn == orconn) {
- queue = &circ->n_conn_cells;
+ cell_direction_t direction;
+
+ if (circ->n_chan == chan) {
+ queue = &circ->n_chan_cells;
+ direction = CELL_DIRECTION_OUT;
} else {
or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(orcirc->p_conn == orconn);
- queue = &orcirc->p_conn_cells;
+ tor_assert(orcirc->p_chan == chan);
+ queue = &orcirc->p_chan_cells;
+ direction = CELL_DIRECTION_IN;
}
- if (queue->n)
- make_circuit_inactive_on_conn(circ,orconn);
-
+ /* Clear the queue */
cell_queue_clear(queue);
+
+ /* Update the cell counter in the cmux */
+ if (chan->cmux && circuitmux_is_circuit_attached(chan->cmux, circ))
+ update_circuit_on_cmux(circ, direction);
}
-/** Fail with an assert if the active circuits ring on <b>orconn</b> is
- * corrupt. */
+/** Fail with an assert if the circuit mux on chan is corrupt
+ */
void
-assert_active_circuits_ok(or_connection_t *orconn)
+assert_circuit_mux_okay(channel_t *chan)
{
- circuit_t *head = orconn->active_circuits;
- circuit_t *cur = head;
- int n = 0;
- if (! head)
- return;
- do {
- circuit_t *next = *next_circ_on_conn_p(cur, orconn);
- circuit_t *prev = *prev_circ_on_conn_p(cur, orconn);
- cell_ewma_t *ewma;
- tor_assert(next);
- tor_assert(prev);
- tor_assert(*next_circ_on_conn_p(prev, orconn) == cur);
- tor_assert(*prev_circ_on_conn_p(next, orconn) == cur);
- if (orconn == cur->n_conn) {
- ewma = &cur->n_cell_ewma;
- tor_assert(!ewma->is_for_p_conn);
- } else {
- ewma = &TO_OR_CIRCUIT(cur)->p_cell_ewma;
- tor_assert(ewma->is_for_p_conn);
- }
- tor_assert(ewma->heap_index != -1);
- tor_assert(ewma == smartlist_get(orconn->active_circuit_pqueue,
- ewma->heap_index));
- n++;
- cur = next;
- } while (cur != head);
-
- tor_assert(n == smartlist_len(orconn->active_circuit_pqueue));
+ tor_assert(chan);
+ tor_assert(chan->cmux);
+
+ circuitmux_assert_okay(chan->cmux);
}
/** Return 1 if we shouldn't restart reading on this circuit, even if
@@ -2679,9 +2446,9 @@ static int
circuit_queue_streams_are_blocked(circuit_t *circ)
{
if (CIRCUIT_IS_ORIGIN(circ)) {
- return circ->streams_blocked_on_n_conn;
+ return circ->streams_blocked_on_n_chan;
} else {
- return circ->streams_blocked_on_p_conn;
+ return circ->streams_blocked_on_p_chan;
}
}
diff --git a/src/or/relay.h b/src/or/relay.h
index 41675e2106..57400fdbd5 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -9,8 +9,8 @@
* \brief Header file for relay.c.
**/
-#ifndef _TOR_RELAY_H
-#define _TOR_RELAY_H
+#ifndef TOR_RELAY_H
+#define TOR_RELAY_H
extern uint64_t stats_n_relay_cells_relayed;
extern uint64_t stats_n_relay_cells_delivered;
@@ -41,32 +41,35 @@ void free_cell_pool(void);
void clean_cell_pool(void);
void dump_cell_pool_usage(int severity);
+/* For channeltls.c */
+void packed_cell_free(packed_cell_t *cell);
+
void cell_queue_clear(cell_queue_t *queue);
void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);
void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell);
-void append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
+void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
cell_t *cell, cell_direction_t direction,
streamid_t fromstream);
-void connection_or_unlink_all_active_circs(or_connection_t *conn);
-int connection_or_flush_from_first_active_circuit(or_connection_t *conn,
- int max, time_t now);
-void assert_active_circuits_ok(or_connection_t *orconn);
-void make_circuit_inactive_on_conn(circuit_t *circ, or_connection_t *conn);
-void make_circuit_active_on_conn(circuit_t *circ, or_connection_t *conn);
+void channel_unlink_all_circuits(channel_t *chan);
+int channel_flush_from_first_active_circuit(channel_t *chan, int max);
+void assert_circuit_mux_okay(channel_t *chan);
+void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
+ const char *file, int lineno);
+#define update_circuit_on_cmux(circ, direction) \
+ update_circuit_on_cmux_((circ), (direction), SHORT_FILE__, __LINE__)
int append_address_to_payload(uint8_t *payload_out, const tor_addr_t *addr);
const uint8_t *decode_address_from_payload(tor_addr_t *addr_out,
const uint8_t *payload,
int payload_len);
-unsigned cell_ewma_get_tick(void);
-void cell_ewma_set_scale_factor(const or_options_t *options,
- const networkstatus_t *consensus);
-void circuit_clear_cell_queue(circuit_t *circ, or_connection_t *orconn);
+void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
#ifdef RELAY_PRIVATE
int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
crypt_path_t **layer_hint, char *recognized);
+int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
+ tor_addr_t *addr_out, int *ttl_out);
#endif
#endif
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 3a0cd1a666..3fb4025e69 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -23,6 +23,7 @@
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
+#include "routerset.h"
static extend_info_t *rend_client_get_random_intro_impl(
const rend_cache_entry_t *rend_query,
@@ -43,7 +44,7 @@ rend_client_purge_state(void)
void
rend_client_introcirc_has_opened(origin_circuit_t *circ)
{
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
tor_assert(circ->cpath);
log_info(LD_REND,"introcirc is open");
@@ -56,7 +57,7 @@ rend_client_introcirc_has_opened(origin_circuit_t *circ)
static int
rend_client_send_establish_rendezvous(origin_circuit_t *circ)
{
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
tor_assert(circ->rend_data);
log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
@@ -102,13 +103,13 @@ rend_client_reextend_intro_circuit(origin_circuit_t *circ)
if (circ->remaining_relay_early_cells) {
log_info(LD_REND,
"Re-extending circ %d, this time to %s.",
- circ->_base.n_circ_id,
+ circ->base_.n_circ_id,
safe_str_client(extend_info_describe(extend_info)));
result = circuit_extend_to_new_exit(circ, extend_info);
} else {
log_info(LD_REND,
"Closing intro circ %d (out of RELAY_EARLY cells).",
- circ->_base.n_circ_id);
+ circ->base_.n_circ_id);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
/* connection_ap_handshake_attach_circuit will launch a new intro circ. */
result = 0;
@@ -132,9 +133,10 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
crypt_path_t *cpath;
off_t dh_offset;
crypto_pk_t *intro_key = NULL;
+ int status = 0;
- tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
+ tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY);
tor_assert(introcirc->rend_data);
tor_assert(rendcirc->rend_data);
tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address,
@@ -161,7 +163,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
}
}
- return -1;
+ status = -1;
+ goto cleanup;
}
/* first 20 bytes of payload are the hash of Bob's pk */
@@ -184,13 +187,16 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
smartlist_len(entry->parsed->intro_nodes));
if (rend_client_reextend_intro_circuit(introcirc)) {
+ status = -2;
goto perm_err;
} else {
- return -1;
+ status = -1;
+ goto cleanup;
}
}
if (crypto_pk_get_digest(intro_key, payload)<0) {
log_warn(LD_BUG, "Internal error: couldn't hash public key.");
+ status = -2;
goto perm_err;
}
@@ -202,10 +208,12 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
cpath->magic = CRYPT_PATH_MAGIC;
if (!(cpath->dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
+ status = -2;
goto perm_err;
}
if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) {
log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
+ status = -2;
goto perm_err;
}
}
@@ -256,6 +264,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset,
DH_KEY_LEN)<0) {
log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
+ status = -2;
goto perm_err;
}
@@ -269,6 +278,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
PK_PKCS1_OAEP_PADDING, 0);
if (r<0) {
log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
+ status = -2;
goto perm_err;
}
@@ -288,7 +298,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
introcirc->cpath->prev)<0) {
/* introcirc is already marked for close. leave rendcirc alone. */
log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
- return -2;
+ status = -2;
+ goto cleanup;
}
/* Now, we wait for an ACK or NAK on this circuit. */
@@ -297,14 +308,19 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
/* Set timestamp_dirty, because circuit_expire_building expects it
* to specify when a circuit entered the _C_INTRODUCE_ACK_WAIT
* state. */
- introcirc->_base.timestamp_dirty = time(NULL);
+ introcirc->base_.timestamp_dirty = time(NULL);
+
+ goto cleanup;
- return 0;
perm_err:
- if (!introcirc->_base.marked_for_close)
+ if (!introcirc->base_.marked_for_close)
circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
- return -2;
+ cleanup:
+ memwipe(payload, 0, sizeof(payload));
+ memwipe(tmp, 0, sizeof(tmp));
+
+ return status;
}
/** Called when a rendezvous circuit is open; sends a establish
@@ -312,7 +328,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
void
rend_client_rendcirc_has_opened(origin_circuit_t *circ)
{
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
log_info(LD_REND,"rendcirc is open");
@@ -331,10 +347,10 @@ rend_client_introduction_acked(origin_circuit_t *circ,
origin_circuit_t *rendcirc;
(void) request; // XXXX Use this.
- if (circ->_base.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
log_warn(LD_PROTOCOL,
"Received REND_INTRODUCE_ACK on unexpected circuit %d.",
- circ->_base.n_circ_id);
+ circ->base_.n_circ_id);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
return -1;
}
@@ -361,7 +377,7 @@ rend_client_introduction_acked(origin_circuit_t *circ,
/* Set timestamp_dirty, because circuit_expire_building expects
* it to specify when a circuit entered the
* _C_REND_READY_INTRO_ACKED state. */
- rendcirc->_base.timestamp_dirty = time(NULL);
+ rendcirc->base_.timestamp_dirty = time(NULL);
} else {
log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
}
@@ -525,7 +541,7 @@ rend_client_purge_last_hid_serv_requests(void)
if (old_last_hid_serv_requests != NULL) {
log_info(LD_REND, "Purging client last-HS-desc-request-time table");
- strmap_free(old_last_hid_serv_requests, _tor_free);
+ strmap_free(old_last_hid_serv_requests, tor_free_);
}
}
@@ -602,7 +618,8 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query)
directory_initiate_command_routerstatus_rend(hs_dir,
DIR_PURPOSE_FETCH_RENDDESC_V2,
ROUTER_PURPOSE_GENERAL,
- !tor2web_mode, desc_id_base32,
+ tor2web_mode?DIRIND_ONEHOP:DIRIND_ANONYMOUS,
+ desc_id_base32,
NULL, 0, 0,
rend_query);
log_info(LD_REND, "Sending fetch request for v2 descriptor for "
@@ -659,10 +676,17 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
time(NULL), chosen_replica) < 0) {
log_warn(LD_REND, "Internal error: Computing v2 rendezvous "
"descriptor ID did not succeed.");
- return;
+ /*
+ * Hmm, can this write anything to descriptor_id and still fail?
+ * Let's clear it just to be safe.
+ *
+ * From here on, any returns should goto done which clears
+ * descriptor_id so we don't leave key-derived material on the stack.
+ */
+ goto done;
}
if (directory_get_from_hs_dir(descriptor_id, rend_query) != 0)
- return; /* either success or failure, but we're done */
+ goto done; /* either success or failure, but we're done */
}
/* If we come here, there are no hidden service directories left. */
log_info(LD_REND, "Could not pick one of the responsible hidden "
@@ -670,6 +694,10 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
"we already tried them all unsuccessfully.");
/* Close pending connections. */
rend_client_desc_trynow(rend_query->onion_address);
+
+ done:
+ memwipe(descriptor_id, 0, sizeof(descriptor_id));
+
return;
}
@@ -818,7 +846,7 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request,
(void) request;
(void) request_len;
/* we just got an ack for our establish-rendezvous. switch purposes. */
- if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
"Closing circ.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
@@ -829,7 +857,7 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request,
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_READY);
/* Set timestamp_dirty, because circuit_expire_building expects it
* to specify when a circuit entered the _C_REND_READY state. */
- circ->_base.timestamp_dirty = time(NULL);
+ circ->base_.timestamp_dirty = time(NULL);
/* XXXX This is a pretty brute-force approach. It'd be better to
* attach only the connections that are waiting on this circuit, rather
* than trying to attach them all. See comments bug 743. */
@@ -847,8 +875,8 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
crypt_path_t *hop;
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
- if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
- circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
+ if ((circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
+ circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
|| !circ->build_state->pending_final_cpath) {
log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
"expecting it. Closing.");
@@ -1172,11 +1200,11 @@ rend_parse_service_authorization(const or_options_t *options,
strmap_t *parsed = strmap_new();
smartlist_t *sl = smartlist_new();
rend_service_authorization_t *auth = NULL;
+ char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
+ char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_BASE64+2+1];
for (line = options->HidServAuth; line; line = line->next) {
char *onion_address, *descriptor_cookie;
- char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
- char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_BASE64+2+1];
int auth_type_val = 0;
auth = NULL;
SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
@@ -1222,7 +1250,7 @@ rend_parse_service_authorization(const or_options_t *options,
descriptor_cookie);
goto err;
}
- auth_type_val = (descriptor_cookie_tmp[16] >> 4) + 1;
+ auth_type_val = (((uint8_t)descriptor_cookie_tmp[16]) >> 4) + 1;
if (auth_type_val < 1 || auth_type_val > 2) {
log_warn(LD_CONFIG, "Authorization cookie has unknown authorization "
"type encoded.");
@@ -1253,6 +1281,8 @@ rend_parse_service_authorization(const or_options_t *options,
} else {
strmap_free(parsed, rend_service_authorization_strmap_item_free);
}
+ memwipe(descriptor_cookie_tmp, 0, sizeof(descriptor_cookie_tmp));
+ memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext));
return res;
}
diff --git a/src/or/rendclient.h b/src/or/rendclient.h
index 393b556e32..b71fe48be3 100644
--- a/src/or/rendclient.h
+++ b/src/or/rendclient.h
@@ -9,8 +9,8 @@
* \brief Header file for rendclient.c.
**/
-#ifndef _TOR_RENDCLIENT_H
-#define _TOR_RENDCLIENT_H
+#ifndef TOR_RENDCLIENT_H
+#define TOR_RENDCLIENT_H
void rend_client_purge_state(void);
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 4722690c15..9e306bdf73 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -439,7 +439,7 @@ rend_intro_point_free(rend_intro_point_t *intro)
crypto_pk_free(intro->intro_key);
if (intro->accepted_intro_rsa_parts != NULL) {
- digestmap_free(intro->accepted_intro_rsa_parts, _tor_free);
+ replaycache_free(intro->accepted_intro_rsa_parts);
}
tor_free(intro);
@@ -800,7 +800,7 @@ rend_cache_entry_free(rend_cache_entry_t *e)
/** Helper: deallocate a rend_cache_entry_t. (Used with strmap_free(), which
* requires a function pointer whose argument is void*). */
static void
-_rend_cache_entry_free(void *p)
+rend_cache_entry_free_(void *p)
{
rend_cache_entry_free(p);
}
@@ -809,8 +809,8 @@ _rend_cache_entry_free(void *p)
void
rend_cache_free_all(void)
{
- strmap_free(rend_cache, _rend_cache_entry_free);
- digestmap_free(rend_cache_v2_dir, _rend_cache_entry_free);
+ strmap_free(rend_cache, rend_cache_entry_free_);
+ digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_);
rend_cache = NULL;
rend_cache_v2_dir = NULL;
}
@@ -844,7 +844,7 @@ rend_cache_purge(void)
{
if (rend_cache) {
log_info(LD_REND, "Purging client/v0-HS-authority HS descriptor cache");
- strmap_free(rend_cache, _rend_cache_entry_free);
+ strmap_free(rend_cache, rend_cache_entry_free_);
}
rend_cache = strmap_new();
}
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index be6bd13d2c..fe574b152f 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -9,8 +9,8 @@
* \brief Header file for rendcommon.c.
**/
-#ifndef _TOR_RENDCOMMON_H
-#define _TOR_RENDCOMMON_H
+#ifndef TOR_RENDCOMMON_H
+#define TOR_RENDCOMMON_H
/** Free all storage associated with <b>data</b> */
static INLINE void
diff --git a/src/or/rendmid.c b/src/or/rendmid.c
index bacd0ef93e..dc2dc1d9e7 100644
--- a/src/or/rendmid.c
+++ b/src/or/rendmid.c
@@ -35,7 +35,7 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request,
"Received an ESTABLISH_INTRO request on circuit %d",
circ->p_circ_id);
- if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
reason = END_CIRC_REASON_TORPROTOCOL;
@@ -142,7 +142,7 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request,
log_info(LD_REND, "Received an INTRODUCE1 request on circuit %d",
circ->p_circ_id);
- if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
log_warn(LD_PROTOCOL,
"Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.",
circ->p_circ_id);
@@ -224,7 +224,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
log_info(LD_REND, "Received an ESTABLISH_RENDEZVOUS request on circuit %d",
circ->p_circ_id);
- if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
log_warn(LD_PROTOCOL,
"Tried to establish rendezvous on non-OR or non-edge circuit.");
goto err;
@@ -277,7 +277,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
char hexid[9];
int reason = END_CIRC_REASON_INTERNAL;
- if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
log_info(LD_REND,
"Tried to complete rendezvous on non-OR or non-edge circuit %d.",
circ->p_circ_id);
diff --git a/src/or/rendmid.h b/src/or/rendmid.h
index 0af6436dea..74ba16b316 100644
--- a/src/or/rendmid.h
+++ b/src/or/rendmid.h
@@ -9,8 +9,8 @@
* \brief Header file for rendmid.c.
**/
-#ifndef _TOR_RENDMID_H
-#define _TOR_RENDMID_H
+#ifndef TOR_RENDMID_H
+#define TOR_RENDMID_H
int rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request,
size_t request_len);
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index d235f089fc..09792bd1d7 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -7,6 +7,8 @@
* \brief The hidden-service side of rendezvous functionality.
**/
+#define RENDSERVICE_PRIVATE
+
#include "or.h"
#include "circuitbuild.h"
#include "circuitlist.h"
@@ -21,16 +23,42 @@
#include "router.h"
#include "relay.h"
#include "rephist.h"
+#include "replaycache.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro,
const char *pk_digest);
static rend_intro_point_t *find_intro_point(origin_circuit_t *circ);
+static extend_info_t *find_rp_for_intro(
+ const rend_intro_cell_t *intro,
+ uint8_t *need_free_out, char **err_msg_out);
+
static int intro_point_accepted_intro_count(rend_intro_point_t *intro);
static int intro_point_should_expire_now(rend_intro_point_t *intro,
time_t now);
+struct rend_service_t;
+static int rend_service_load_keys(struct rend_service_t *s);
+static int rend_service_load_auth_keys(struct rend_service_t *s,
+ const char *hfname);
+
+static ssize_t rend_service_parse_intro_for_v0_or_v1(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out);
+static ssize_t rend_service_parse_intro_for_v2(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out);
+static ssize_t rend_service_parse_intro_for_v3(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out);
/** Represents the mapping from a virtual port of a rendezvous service to
* a real port on some IP.
@@ -91,16 +119,12 @@ typedef struct rend_service_t {
* up-to-date. */
time_t next_upload_time; /**< Scheduled next hidden service descriptor
* upload time. */
- /** Map from digests of Diffie-Hellman values INTRODUCE2 to time_t
- * of when they were received. Clients may send INTRODUCE1 cells
- * for the same rendezvous point through two or more different
- * introduction points; when they do, this digestmap keeps us from
- * launching multiple simultaneous attempts to connect to the same
- * rend point. */
- digestmap_t *accepted_intro_dh_parts;
- /** Time at which we last removed expired values from
- * accepted_intro_dh_parts. */
- time_t last_cleaned_accepted_intro_dh_parts;
+ /** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, to
+ * detect repeats. Clients may send INTRODUCE1 cells for the same
+ * rendezvous point through two or more different introduction points;
+ * when they do, this keeps us from launching multiple simultaneous attempts
+ * to connect to the same rend point. */
+ replaycache_t *accepted_intro_dh_parts;
} rend_service_t;
/** A list of rend_service_t's for services run on this OP.
@@ -135,7 +159,9 @@ rend_authorized_client_free(rend_authorized_client_t *client)
return;
if (client->client_key)
crypto_pk_free(client->client_key);
+ tor_strclear(client->client_name);
tor_free(client->client_name);
+ memwipe(client->descriptor_cookie, 0, sizeof(client->descriptor_cookie));
tor_free(client);
}
@@ -171,7 +197,9 @@ rend_service_free(rend_service_t *service)
rend_authorized_client_free(c););
smartlist_free(service->clients);
}
- digestmap_free(service->accepted_intro_dh_parts, _tor_free);
+ if (service->accepted_intro_dh_parts) {
+ replaycache_free(service->accepted_intro_dh_parts);
+ }
tor_free(service);
}
@@ -244,8 +272,8 @@ rend_add_service(rend_service_t *service)
service->directory);
for (i = 0; i < smartlist_len(service->ports); ++i) {
p = smartlist_get(service->ports, i);
- log_debug(LD_REND,"Service maps port %d to %s:%d",
- p->virtual_port, fmt_addr(&p->real_addr), p->real_port);
+ log_debug(LD_REND,"Service maps port %d to %s",
+ p->virtual_port, fmt_addrport(&p->real_addr, p->real_port));
}
}
}
@@ -515,7 +543,7 @@ rend_config_services(const or_options_t *options, int validate_only)
/* XXXX it would be nicer if we had a nicer abstraction to use here,
* so we could just iterate over the list of services to close, but
* once again, this isn't critical-path code. */
- for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
if (!circ->marked_for_close &&
circ->state == CIRCUIT_STATE_OPEN &&
(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -582,7 +610,7 @@ rend_service_update_descriptor(rend_service_t *service)
}
circ = find_intro_circuit(intro_svc, service->pk_digest);
- if (!circ || circ->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
+ if (!circ || circ->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) {
/* This intro point's circuit isn't finished yet. Don't list it. */
continue;
}
@@ -609,231 +637,274 @@ rend_service_update_descriptor(rend_service_t *service)
/** Load and/or generate private keys for all hidden services, possibly
* including keys for client authorization. Return 0 on success, -1 on
- * failure.
- */
+ * failure. */
int
-rend_service_load_keys(void)
+rend_service_load_all_keys(void)
{
- int r = 0;
- char fname[512];
- char buf[1500];
-
SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) {
if (s->private_key)
continue;
log_info(LD_REND, "Loading hidden-service keys from \"%s\"",
s->directory);
- /* Check/create directory */
- if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0)
+ if (rend_service_load_keys(s) < 0)
return -1;
+ } SMARTLIST_FOREACH_END(s);
+
+ return 0;
+}
+
+/** Load and/or generate private keys for the hidden service <b>s</b>,
+ * possibly including keys for client authorization. Return 0 on success, -1
+ * on failure. */
+static int
+rend_service_load_keys(rend_service_t *s)
+{
+ char fname[512];
+ char buf[128];
+
+ /* Check/create directory */
+ if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0)
+ return -1;
+
+ /* Load key */
+ if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
+ strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname))
+ >= sizeof(fname)) {
+ log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".",
+ s->directory);
+ return -1;
+ }
+ s->private_key = init_key_from_file(fname, 1, LOG_ERR);
+ if (!s->private_key)
+ return -1;
+
+ /* Create service file */
+ if (rend_get_service_id(s->private_key, s->service_id)<0) {
+ log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
+ return -1;
+ }
+ if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) {
+ log_warn(LD_BUG, "Couldn't compute hash of public key.");
+ return -1;
+ }
+ if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
+ strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname))
+ >= sizeof(fname)) {
+ log_warn(LD_CONFIG, "Directory name too long to store hostname file:"
+ " \"%s\".", s->directory);
+ return -1;
+ }
+
+ tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
+ if (write_str_to_file(fname,buf,0)<0) {
+ log_warn(LD_CONFIG, "Could not write onion address to hostname file.");
+ memwipe(buf, 0, sizeof(buf));
+ return -1;
+ }
+ memwipe(buf, 0, sizeof(buf));
- /* Load key */
- if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
- strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname))
- >= sizeof(fname)) {
- log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".",
- s->directory);
+ /* If client authorization is configured, load or generate keys. */
+ if (s->auth_type != REND_NO_AUTH) {
+ if (rend_service_load_auth_keys(s, fname) < 0)
return -1;
+ }
+
+ return 0;
+}
+
+/** Load and/or generate client authorization keys for the hidden service
+ * <b>s</b>, which stores its hostname in <b>hfname</b>. Return 0 on success,
+ * -1 on failure. */
+static int
+rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
+{
+ int r = 0;
+ char cfname[512];
+ char *client_keys_str = NULL;
+ strmap_t *parsed_clients = strmap_new();
+ FILE *cfile, *hfile;
+ open_file_t *open_cfile = NULL, *open_hfile = NULL;
+ char extended_desc_cookie[REND_DESC_COOKIE_LEN+1];
+ char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1];
+ char service_id[16+1];
+ char buf[1500];
+
+ /* Load client keys and descriptor cookies, if available. */
+ if (tor_snprintf(cfname, sizeof(cfname), "%s"PATH_SEPARATOR"client_keys",
+ s->directory)<0) {
+ log_warn(LD_CONFIG, "Directory name too long to store client keys "
+ "file: \"%s\".", s->directory);
+ goto err;
+ }
+ client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL);
+ if (client_keys_str) {
+ if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) {
+ log_warn(LD_CONFIG, "Previously stored client_keys file could not "
+ "be parsed.");
+ goto err;
+ } else {
+ log_info(LD_CONFIG, "Parsed %d previously stored client entries.",
+ strmap_size(parsed_clients));
}
- s->private_key = init_key_from_file(fname, 1, LOG_ERR);
- if (!s->private_key)
- return -1;
+ }
- /* Create service file */
- if (rend_get_service_id(s->private_key, s->service_id)<0) {
- log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
- return -1;
+ /* Prepare client_keys and hostname files. */
+ if (!(cfile = start_writing_to_stdio_file(cfname,
+ OPEN_FLAGS_REPLACE | O_TEXT,
+ 0600, &open_cfile))) {
+ log_warn(LD_CONFIG, "Could not open client_keys file %s",
+ escaped(cfname));
+ goto err;
+ }
+
+ if (!(hfile = start_writing_to_stdio_file(hfname,
+ OPEN_FLAGS_REPLACE | O_TEXT,
+ 0600, &open_hfile))) {
+ log_warn(LD_CONFIG, "Could not open hostname file %s", escaped(hfname));
+ goto err;
+ }
+
+ /* Either use loaded keys for configured clients or generate new
+ * ones if a client is new. */
+ SMARTLIST_FOREACH_BEGIN(s->clients, rend_authorized_client_t *, client) {
+ rend_authorized_client_t *parsed =
+ strmap_get(parsed_clients, client->client_name);
+ int written;
+ size_t len;
+ /* Copy descriptor cookie from parsed entry or create new one. */
+ if (parsed) {
+ memcpy(client->descriptor_cookie, parsed->descriptor_cookie,
+ REND_DESC_COOKIE_LEN);
+ } else {
+ crypto_rand(client->descriptor_cookie, REND_DESC_COOKIE_LEN);
}
- if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) {
- log_warn(LD_BUG, "Couldn't compute hash of public key.");
- return -1;
+ if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
+ client->descriptor_cookie,
+ REND_DESC_COOKIE_LEN) < 0) {
+ log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
+ goto err;
}
- if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
- strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname))
- >= sizeof(fname)) {
- log_warn(LD_CONFIG, "Directory name too long to store hostname file:"
- " \"%s\".", s->directory);
- return -1;
+ /* Copy client key from parsed entry or create new one if required. */
+ if (parsed && parsed->client_key) {
+ client->client_key = crypto_pk_dup_key(parsed->client_key);
+ } else if (s->auth_type == REND_STEALTH_AUTH) {
+ /* Create private key for client. */
+ crypto_pk_t *prkey = NULL;
+ if (!(prkey = crypto_pk_new())) {
+ log_warn(LD_BUG,"Error constructing client key");
+ goto err;
+ }
+ if (crypto_pk_generate_key(prkey)) {
+ log_warn(LD_BUG,"Error generating client key");
+ crypto_pk_free(prkey);
+ goto err;
+ }
+ if (crypto_pk_check_key(prkey) <= 0) {
+ log_warn(LD_BUG,"Generated client key seems invalid");
+ crypto_pk_free(prkey);
+ goto err;
+ }
+ client->client_key = prkey;
}
- tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
- if (write_str_to_file(fname,buf,0)<0) {
- log_warn(LD_CONFIG, "Could not write onion address to hostname file.");
- return -1;
+ /* Add entry to client_keys file. */
+ desc_cook_out[strlen(desc_cook_out)-1] = '\0'; /* Remove newline. */
+ written = tor_snprintf(buf, sizeof(buf),
+ "client-name %s\ndescriptor-cookie %s\n",
+ client->client_name, desc_cook_out);
+ if (written < 0) {
+ log_warn(LD_BUG, "Could not write client entry.");
+ goto err;
}
-
- /* If client authorization is configured, load or generate keys. */
- if (s->auth_type != REND_NO_AUTH) {
- char *client_keys_str = NULL;
- strmap_t *parsed_clients = strmap_new();
- char cfname[512];
- FILE *cfile, *hfile;
- open_file_t *open_cfile = NULL, *open_hfile = NULL;
-
- /* Load client keys and descriptor cookies, if available. */
- if (tor_snprintf(cfname, sizeof(cfname), "%s"PATH_SEPARATOR"client_keys",
- s->directory)<0) {
- log_warn(LD_CONFIG, "Directory name too long to store client keys "
- "file: \"%s\".", s->directory);
+ if (client->client_key) {
+ char *client_key_out = NULL;
+ if (crypto_pk_write_private_key_to_string(client->client_key,
+ &client_key_out, &len) != 0) {
+ log_warn(LD_BUG, "Internal error: "
+ "crypto_pk_write_private_key_to_string() failed.");
goto err;
}
- client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL);
- if (client_keys_str) {
- if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) {
- log_warn(LD_CONFIG, "Previously stored client_keys file could not "
- "be parsed.");
- goto err;
- } else {
- log_info(LD_CONFIG, "Parsed %d previously stored client entries.",
- strmap_size(parsed_clients));
- tor_free(client_keys_str);
- }
- }
-
- /* Prepare client_keys and hostname files. */
- if (!(cfile = start_writing_to_stdio_file(cfname,
- OPEN_FLAGS_REPLACE | O_TEXT,
- 0600, &open_cfile))) {
- log_warn(LD_CONFIG, "Could not open client_keys file %s",
- escaped(cfname));
+ if (rend_get_service_id(client->client_key, service_id)<0) {
+ log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
+ /*
+ * len is string length, not buffer length, but last byte is NUL
+ * anyway.
+ */
+ memwipe(client_key_out, 0, len);
+ tor_free(client_key_out);
goto err;
}
- if (!(hfile = start_writing_to_stdio_file(fname,
- OPEN_FLAGS_REPLACE | O_TEXT,
- 0600, &open_hfile))) {
- log_warn(LD_CONFIG, "Could not open hostname file %s", escaped(fname));
+ written = tor_snprintf(buf + written, sizeof(buf) - written,
+ "client-key\n%s", client_key_out);
+ memwipe(client_key_out, 0, len);
+ tor_free(client_key_out);
+ if (written < 0) {
+ log_warn(LD_BUG, "Could not write client entry.");
goto err;
}
+ }
- /* Either use loaded keys for configured clients or generate new
- * ones if a client is new. */
- SMARTLIST_FOREACH_BEGIN(s->clients, rend_authorized_client_t *, client)
- {
- char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1];
- char service_id[16+1];
- rend_authorized_client_t *parsed =
- strmap_get(parsed_clients, client->client_name);
- int written;
- size_t len;
- /* Copy descriptor cookie from parsed entry or create new one. */
- if (parsed) {
- memcpy(client->descriptor_cookie, parsed->descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- } else {
- crypto_rand(client->descriptor_cookie, REND_DESC_COOKIE_LEN);
- }
- if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
- client->descriptor_cookie,
- REND_DESC_COOKIE_LEN) < 0) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
- return -1;
- }
- /* Copy client key from parsed entry or create new one if required. */
- if (parsed && parsed->client_key) {
- client->client_key = crypto_pk_dup_key(parsed->client_key);
- } else if (s->auth_type == REND_STEALTH_AUTH) {
- /* Create private key for client. */
- crypto_pk_t *prkey = NULL;
- if (!(prkey = crypto_pk_new())) {
- log_warn(LD_BUG,"Error constructing client key");
- goto err;
- }
- if (crypto_pk_generate_key(prkey)) {
- log_warn(LD_BUG,"Error generating client key");
- crypto_pk_free(prkey);
- goto err;
- }
- if (crypto_pk_check_key(prkey) <= 0) {
- log_warn(LD_BUG,"Generated client key seems invalid");
- crypto_pk_free(prkey);
- goto err;
- }
- client->client_key = prkey;
- }
- /* Add entry to client_keys file. */
- desc_cook_out[strlen(desc_cook_out)-1] = '\0'; /* Remove newline. */
- written = tor_snprintf(buf, sizeof(buf),
- "client-name %s\ndescriptor-cookie %s\n",
- client->client_name, desc_cook_out);
- if (written < 0) {
- log_warn(LD_BUG, "Could not write client entry.");
- goto err;
- }
- if (client->client_key) {
- char *client_key_out = NULL;
- crypto_pk_write_private_key_to_string(client->client_key,
- &client_key_out, &len);
- if (rend_get_service_id(client->client_key, service_id)<0) {
- log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
- tor_free(client_key_out);
- goto err;
- }
- written = tor_snprintf(buf + written, sizeof(buf) - written,
- "client-key\n%s", client_key_out);
- tor_free(client_key_out);
- if (written < 0) {
- log_warn(LD_BUG, "Could not write client entry.");
- goto err;
- }
- }
-
- if (fputs(buf, cfile) < 0) {
- log_warn(LD_FS, "Could not append client entry to file: %s",
- strerror(errno));
- goto err;
- }
-
- /* Add line to hostname file. */
- if (s->auth_type == REND_BASIC_AUTH) {
- /* Remove == signs (newline has been removed above). */
- desc_cook_out[strlen(desc_cook_out)-2] = '\0';
- tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
- s->service_id, desc_cook_out, client->client_name);
- } else {
- char extended_desc_cookie[REND_DESC_COOKIE_LEN+1];
- memcpy(extended_desc_cookie, client->descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- extended_desc_cookie[REND_DESC_COOKIE_LEN] =
- ((int)s->auth_type - 1) << 4;
- if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
- extended_desc_cookie,
- REND_DESC_COOKIE_LEN+1) < 0) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- goto err;
- }
- desc_cook_out[strlen(desc_cook_out)-3] = '\0'; /* Remove A= and
- newline. */
- tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
- service_id, desc_cook_out, client->client_name);
- }
+ if (fputs(buf, cfile) < 0) {
+ log_warn(LD_FS, "Could not append client entry to file: %s",
+ strerror(errno));
+ goto err;
+ }
- if (fputs(buf, hfile)<0) {
- log_warn(LD_FS, "Could not append host entry to file: %s",
- strerror(errno));
- goto err;
- }
+ /* Add line to hostname file. */
+ if (s->auth_type == REND_BASIC_AUTH) {
+ /* Remove == signs (newline has been removed above). */
+ desc_cook_out[strlen(desc_cook_out)-2] = '\0';
+ tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
+ s->service_id, desc_cook_out, client->client_name);
+ } else {
+ memcpy(extended_desc_cookie, client->descriptor_cookie,
+ REND_DESC_COOKIE_LEN);
+ extended_desc_cookie[REND_DESC_COOKIE_LEN] =
+ ((int)s->auth_type - 1) << 4;
+ if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
+ extended_desc_cookie,
+ REND_DESC_COOKIE_LEN+1) < 0) {
+ log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
+ goto err;
}
- SMARTLIST_FOREACH_END(client);
+ desc_cook_out[strlen(desc_cook_out)-3] = '\0'; /* Remove A= and
+ newline. */
+ tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
+ service_id, desc_cook_out, client->client_name);
+ }
- goto done;
- err:
- r = -1;
- done:
- tor_free(client_keys_str);
- strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
- if (r<0) {
- if (open_cfile)
- abort_writing_to_file(open_cfile);
- if (open_hfile)
- abort_writing_to_file(open_hfile);
- return r;
- } else {
- finish_writing_to_file(open_cfile);
- finish_writing_to_file(open_hfile);
- }
+ if (fputs(buf, hfile)<0) {
+ log_warn(LD_FS, "Could not append host entry to file: %s",
+ strerror(errno));
+ goto err;
}
- } SMARTLIST_FOREACH_END(s);
+ } SMARTLIST_FOREACH_END(client);
+
+ finish_writing_to_file(open_cfile);
+ finish_writing_to_file(open_hfile);
+
+ goto done;
+ err:
+ r = -1;
+ if (open_cfile)
+ abort_writing_to_file(open_cfile);
+ if (open_hfile)
+ abort_writing_to_file(open_hfile);
+ done:
+ if (client_keys_str) {
+ tor_strclear(client_keys_str);
+ tor_free(client_keys_str);
+ }
+ strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
+
+ memwipe(cfname, 0, sizeof(cfname));
+
+ /* Clear stack buffers that held key-derived material. */
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(desc_cook_out, 0, sizeof(desc_cook_out));
+ memwipe(service_id, 0, sizeof(service_id));
+ memwipe(extended_desc_cookie, 0, sizeof(extended_desc_cookie));
+
return r;
}
@@ -906,26 +977,6 @@ rend_check_authorization(rend_service_t *service,
return 1;
}
-/** Remove elements from <b>service</b>'s replay cache that are old enough to
- * be noticed by timestamp checking. */
-static void
-clean_accepted_intro_dh_parts(rend_service_t *service, time_t now)
-{
- const time_t cutoff = now - REND_REPLAY_TIME_INTERVAL;
-
- service->last_cleaned_accepted_intro_dh_parts = now;
- if (!service->accepted_intro_dh_parts)
- return;
-
- DIGESTMAP_FOREACH_MODIFY(service->accepted_intro_dh_parts, digest,
- time_t *, t) {
- if (*t < cutoff) {
- tor_free(t);
- MAP_DEL_CURRENT(digest);
- }
- } DIGESTMAP_FOREACH_END;
-}
-
/** Called when <b>intro</b> will soon be removed from
* <b>service</b>'s list of intro points. */
static void
@@ -1033,42 +1084,55 @@ rend_service_note_removing_intro_point(rend_service_t *service,
/** Respond to an INTRODUCE2 cell by launching a circuit to the chosen
* rendezvous point.
*/
- /* XXXX024 this function sure could use some organizing. -RD */
int
rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
size_t request_len)
{
- char *ptr, *r_cookie;
- extend_info_t *extend_info = NULL;
+ /* Global status stuff */
+ int status = 0, result;
+ const or_options_t *options = get_options();
+ char *err_msg = NULL;
+ const char *stage_descr = NULL;
+ int reason = END_CIRC_REASON_TORPROTOCOL;
+ /* Service/circuit/key stuff we can learn before parsing */
+ char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
+ rend_service_t *service = NULL;
+ rend_intro_point_t *intro_point = NULL;
+ crypto_pk_t *intro_key = NULL;
+ /* Parsed cell */
+ rend_intro_cell_t *parsed_req = NULL;
+ /* Rendezvous point */
+ extend_info_t *rp = NULL;
+ /*
+ * We need to look up and construct the extend_info_t for v0 and v1,
+ * but all the info is in the cell and it's constructed by the parser
+ * for v2 and v3, so freeing it would be a double-free. Use this to
+ * keep track of whether we should free it.
+ */
+ uint8_t need_rp_free = 0;
+ /* XXX not handled yet */
char buf[RELAY_PAYLOAD_SIZE];
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; /* Holds KH, Df, Db, Kf, Kb */
- rend_service_t *service;
- rend_intro_point_t *intro_point;
- int r, i, v3_shift = 0;
- size_t len, keylen;
+ int i;
crypto_dh_t *dh = NULL;
origin_circuit_t *launched = NULL;
crypt_path_t *cpath = NULL;
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
char hexcookie[9];
int circ_needs_uptime;
- int reason = END_CIRC_REASON_TORPROTOCOL;
- crypto_pk_t *intro_key;
char intro_key_digest[DIGEST_LEN];
- int auth_type;
size_t auth_len = 0;
char auth_data[REND_DESC_COOKIE_LEN];
- crypto_digest_t *digest = NULL;
time_t now = time(NULL);
char diffie_hellman_hash[DIGEST_LEN];
- time_t *access_time;
- const or_options_t *options = get_options();
+ time_t elapsed;
+ int replay;
- if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
+ /* Do some initial validation and logging before we parse the cell */
+ if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) {
log_warn(LD_PROTOCOL,
"Got an INTRODUCE2 over a non-introduction circuit %d.",
- circuit->_base.n_circ_id);
- return -1;
+ circuit->base_.n_circ_id);
+ goto err;
}
#ifndef NON_ANONYMOUS_MODE_ENABLED
@@ -1076,218 +1140,145 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
#endif
tor_assert(circuit->rend_data);
+ /* We'll use this in a bazillion log messages */
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
- log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.",
- escaped(serviceid), circuit->_base.n_circ_id);
-
- /* min key length plus digest length plus nickname length */
- if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+
- DH_KEY_LEN+42) {
- log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.",
- circuit->_base.n_circ_id);
- return -1;
- }
/* look up service depending on circuit. */
- service = rend_service_get_by_pk_digest(
- circuit->rend_data->rend_pk_digest);
+ service =
+ rend_service_get_by_pk_digest(circuit->rend_data->rend_pk_digest);
if (!service) {
- log_warn(LD_BUG, "Internal error: Got an INTRODUCE2 cell on an intro "
+ log_warn(LD_BUG,
+ "Internal error: Got an INTRODUCE2 cell on an intro "
"circ for an unrecognized service %s.",
escaped(serviceid));
- return -1;
- }
-
- /* use intro key instead of service key. */
- intro_key = circuit->intro_key;
-
- /* first DIGEST_LEN bytes of request is intro or service pk digest */
- crypto_pk_get_digest(intro_key, intro_key_digest);
- if (tor_memneq(intro_key_digest, request, DIGEST_LEN)) {
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- (char*)request, REND_SERVICE_ID_LEN);
- log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).",
- escaped(serviceid));
- return -1;
- }
-
- keylen = crypto_pk_keysize(intro_key);
- if (request_len < keylen+DIGEST_LEN) {
- log_warn(LD_PROTOCOL,
- "PK-encrypted portion of INTRODUCE2 cell was truncated.");
- return -1;
+ goto err;
}
intro_point = find_intro_point(circuit);
if (intro_point == NULL) {
- log_warn(LD_BUG, "Internal error: Got an INTRODUCE2 cell on an intro circ "
- "(for service %s) with no corresponding rend_intro_point_t.",
+ log_warn(LD_BUG,
+ "Internal error: Got an INTRODUCE2 cell on an "
+ "intro circ (for service %s) with no corresponding "
+ "rend_intro_point_t.",
escaped(serviceid));
- return -1;
+ goto err;
}
- if (!service->accepted_intro_dh_parts)
- service->accepted_intro_dh_parts = digestmap_new();
+ log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.",
+ escaped(serviceid), circuit->base_.n_circ_id);
- if (!intro_point->accepted_intro_rsa_parts)
- intro_point->accepted_intro_rsa_parts = digestmap_new();
+ /* use intro key instead of service key. */
+ intro_key = circuit->intro_key;
- {
- char pkpart_digest[DIGEST_LEN];
- /* Check for replay of PK-encrypted portion. */
- crypto_digest(pkpart_digest, (char*)request+DIGEST_LEN, keylen);
- access_time = digestmap_get(intro_point->accepted_intro_rsa_parts,
- pkpart_digest);
- if (access_time != NULL) {
- log_warn(LD_REND, "Possible replay detected! We received an "
- "INTRODUCE2 cell with same PK-encrypted part %d seconds ago. "
- "Dropping cell.", (int)(now-*access_time));
- return -1;
- }
- access_time = tor_malloc(sizeof(time_t));
- *access_time = now;
- digestmap_set(intro_point->accepted_intro_rsa_parts,
- pkpart_digest, access_time);
+ tor_free(err_msg);
+ stage_descr = NULL;
+
+ stage_descr = "early parsing";
+ /* Early parsing pass (get pk, ciphertext); type 2 is INTRODUCE2 */
+ parsed_req =
+ rend_service_begin_parse_intro(request, request_len, 2, &err_msg);
+ if (!parsed_req) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id);
+ tor_free(err_msg);
+ }
+
+ stage_descr = "early validation";
+ /* Early validation of pk/ciphertext part */
+ result = rend_service_validate_intro_early(parsed_req, &err_msg);
+ if (result < 0) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id);
+ tor_free(err_msg);
+ }
+
+ /* make sure service replay caches are present */
+ if (!service->accepted_intro_dh_parts) {
+ service->accepted_intro_dh_parts =
+ replaycache_new(REND_REPLAY_TIME_INTERVAL,
+ REND_REPLAY_TIME_INTERVAL);
+ }
+
+ if (!intro_point->accepted_intro_rsa_parts) {
+ intro_point->accepted_intro_rsa_parts = replaycache_new(0, 0);
+ }
+
+ /* check for replay of PK-encrypted portion. */
+ replay = replaycache_add_test_and_elapsed(
+ intro_point->accepted_intro_rsa_parts,
+ parsed_req->ciphertext, (int)parsed_req->ciphertext_len,
+ &elapsed);
+
+ if (replay) {
+ log_warn(LD_REND,
+ "Possible replay detected! We received an "
+ "INTRODUCE2 cell with same PK-encrypted part %d "
+ "seconds ago. Dropping cell.",
+ (int)elapsed);
+ goto err;
}
- /* Next N bytes is encrypted with service key */
- note_crypto_pk_op(REND_SERVER);
- r = crypto_pk_private_hybrid_decrypt(
- intro_key,buf,sizeof(buf),
- (char*)(request+DIGEST_LEN),request_len-DIGEST_LEN,
- PK_PKCS1_OAEP_PADDING,1);
- if (r<0) {
- log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell.");
- return -1;
+ stage_descr = "decryption";
+ /* Now try to decrypt it */
+ result = rend_service_decrypt_intro(parsed_req, intro_key, &err_msg);
+ if (result < 0) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id);
+ tor_free(err_msg);
}
- len = r;
- if (*buf == 3) {
- /* Version 3 INTRODUCE2 cell. */
- v3_shift = 1;
- auth_type = buf[1];
- switch (auth_type) {
- case REND_BASIC_AUTH:
- /* fall through */
- case REND_STEALTH_AUTH:
- auth_len = ntohs(get_uint16(buf+2));
- if (auth_len != REND_DESC_COOKIE_LEN) {
- log_info(LD_REND, "Wrong auth data size %d, should be %d.",
- (int)auth_len, REND_DESC_COOKIE_LEN);
- return -1;
- }
- memcpy(auth_data, buf+4, sizeof(auth_data));
- v3_shift += 2+REND_DESC_COOKIE_LEN;
- break;
- case REND_NO_AUTH:
- break;
- default:
- log_info(LD_REND, "Unknown authorization type '%d'", auth_type);
- }
- /* Skip the timestamp field. We no longer use it. */
- v3_shift += 4;
- }
- if (*buf == 2 || *buf == 3) {
- /* Version 2 INTRODUCE2 cell. */
- int klen;
- extend_info = tor_malloc_zero(sizeof(extend_info_t));
- tor_addr_from_ipv4n(&extend_info->addr, get_uint32(buf+v3_shift+1));
- extend_info->port = ntohs(get_uint16(buf+v3_shift+5));
- memcpy(extend_info->identity_digest, buf+v3_shift+7,
- DIGEST_LEN);
- extend_info->nickname[0] = '$';
- base16_encode(extend_info->nickname+1, sizeof(extend_info->nickname)-1,
- extend_info->identity_digest, DIGEST_LEN);
-
- klen = ntohs(get_uint16(buf+v3_shift+7+DIGEST_LEN));
- if ((int)len != v3_shift+7+DIGEST_LEN+2+klen+20+128) {
- log_warn(LD_PROTOCOL, "Bad length %u for version %d INTRODUCE2 cell.",
- (int)len, *buf);
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
- extend_info->onion_key =
- crypto_pk_asn1_decode(buf+v3_shift+7+DIGEST_LEN+2, klen);
- if (!extend_info->onion_key) {
- log_warn(LD_PROTOCOL, "Error decoding onion key in version %d "
- "INTRODUCE2 cell.", *buf);
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
- ptr = buf+v3_shift+7+DIGEST_LEN+2+klen;
- len -= v3_shift+7+DIGEST_LEN+2+klen;
- } else {
- char *rp_nickname;
- size_t nickname_field_len;
- const node_t *node;
- int version;
- if (*buf == 1) {
- rp_nickname = buf+1;
- nickname_field_len = MAX_HEX_NICKNAME_LEN+1;
- version = 1;
- } else {
- nickname_field_len = MAX_NICKNAME_LEN+1;
- rp_nickname = buf;
- version = 0;
- }
- ptr=memchr(rp_nickname,0,nickname_field_len);
- if (!ptr || ptr == rp_nickname) {
- log_warn(LD_PROTOCOL,
- "Couldn't find a nul-padded nickname in INTRODUCE2 cell.");
- return -1;
- }
- if ((version == 0 && !is_legal_nickname(rp_nickname)) ||
- (version == 1 && !is_legal_nickname_or_hexdigest(rp_nickname))) {
- log_warn(LD_PROTOCOL, "Bad nickname in INTRODUCE2 cell.");
- return -1;
- }
- /* Okay, now we know that a nickname is at the start of the buffer. */
- ptr = rp_nickname+nickname_field_len;
- len -= nickname_field_len;
- len -= rp_nickname - buf; /* also remove header space used by version, if
- * any */
- node = node_get_by_nickname(rp_nickname, 0);
- if (!node) {
- log_info(LD_REND, "Couldn't find router %s named in introduce2 cell.",
- escaped_safe_str_client(rp_nickname));
- /* XXXX Add a no-such-router reason? */
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
-
- extend_info = extend_info_from_node(node, 0);
+ stage_descr = "late parsing";
+ /* Parse the plaintext */
+ result = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
+ if (result < 0) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id);
+ tor_free(err_msg);
}
- if (len != REND_COOKIE_LEN+DH_KEY_LEN) {
- log_warn(LD_PROTOCOL, "Bad length %u for INTRODUCE2 cell.", (int)len);
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
+ stage_descr = "late validation";
+ /* Validate the parsed plaintext parts */
+ result = rend_service_validate_intro_late(parsed_req, &err_msg);
+ if (result < 0) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %d.", err_msg, circuit->base_.n_circ_id);
+ tor_free(err_msg);
}
+ stage_descr = NULL;
+
+ /* Increment INTRODUCE2 counter */
+ ++(intro_point->accepted_introduce2_count);
+
+ /* Find the rendezvous point */
+ rp = find_rp_for_intro(parsed_req, &need_rp_free, &err_msg);
+ if (!rp)
+ goto log_error;
/* Check if we'd refuse to talk to this router */
if (options->StrictNodes &&
- routerset_contains_extendinfo(options->ExcludeNodes, extend_info)) {
+ routerset_contains_extendinfo(options->ExcludeNodes, rp)) {
log_warn(LD_REND, "Client asked to rendezvous at a relay that we "
"exclude, and StrictNodes is set. Refusing service.");
reason = END_CIRC_REASON_INTERNAL; /* XXX might leak why we refused */
goto err;
}
- r_cookie = ptr;
- base16_encode(hexcookie,9,r_cookie,4);
-
- /* Determine hash of Diffie-Hellman, part 1 to detect replays. */
- digest = crypto_digest_new();
- crypto_digest_add_bytes(digest, ptr+REND_COOKIE_LEN, DH_KEY_LEN);
- crypto_digest_get_digest(digest, diffie_hellman_hash, DIGEST_LEN);
- crypto_digest_free(digest);
+ base16_encode(hexcookie, 9, (const char *)(parsed_req->rc), 4);
/* Check whether there is a past request with the same Diffie-Hellman,
* part 1. */
- access_time = digestmap_get(service->accepted_intro_dh_parts,
- diffie_hellman_hash);
- if (access_time != NULL) {
+ replay = replaycache_add_test_and_elapsed(
+ service->accepted_intro_dh_parts,
+ parsed_req->dh, DH_KEY_LEN,
+ &elapsed);
+
+ if (replay) {
/* A Tor client will send a new INTRODUCE1 cell with the same rend
* cookie and DH public key as its previous one if its intro circ
* times out while in state CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT .
@@ -1299,21 +1290,10 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
"INTRODUCE2 cell with same first part of "
"Diffie-Hellman handshake %d seconds ago. Dropping "
"cell.",
- (int) (now - *access_time));
+ (int) elapsed);
goto err;
}
- /* Add request to access history, including time and hash of Diffie-Hellman,
- * part 1, and possibly remove requests from the history that are older than
- * one hour. */
- access_time = tor_malloc(sizeof(time_t));
- *access_time = now;
- digestmap_set(service->accepted_intro_dh_parts,
- diffie_hellman_hash, access_time);
- if (service->last_cleaned_accepted_intro_dh_parts + REND_REPLAY_TIME_INTERVAL
- < now)
- clean_accepted_intro_dh_parts(service, now);
-
/* If the service performs client authorization, check included auth data. */
if (service->clients) {
if (auth_len > 0) {
@@ -1341,7 +1321,8 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
- if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, ptr+REND_COOKIE_LEN,
+ if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh,
+ (char *)(parsed_req->dh),
DH_KEY_LEN, keys,
DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
log_warn(LD_BUG, "Internal error: couldn't complete DH handshake");
@@ -1360,7 +1341,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL;
if (circ_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME;
launched = circuit_launch_by_extend_info(
- CIRCUIT_PURPOSE_S_CONNECT_REND, extend_info, flags);
+ CIRCUIT_PURPOSE_S_CONNECT_REND, rp, flags);
if (launched)
break;
@@ -1368,7 +1349,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
if (!launched) { /* give up */
log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous "
"point %s for service %s.",
- safe_str_client(extend_info_describe(extend_info)),
+ safe_str_client(extend_info_describe(rp)),
serviceid);
reason = END_CIRC_REASON_CONNECTFAILED;
goto err;
@@ -1376,7 +1357,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
log_info(LD_REND,
"Accepted intro; launching circuit to %s "
"(cookie %s) for service %s.",
- safe_str_client(extend_info_describe(extend_info)),
+ safe_str_client(extend_info_describe(rp)),
hexcookie, serviceid);
tor_assert(launched->build_state);
/* Fill in the circuit's state. */
@@ -1384,7 +1365,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
memcpy(launched->rend_data->rend_pk_digest,
circuit->rend_data->rend_pk_digest,
DIGEST_LEN);
- memcpy(launched->rend_data->rend_cookie, r_cookie, REND_COOKIE_LEN);
+ memcpy(launched->rend_data->rend_cookie, parsed_req->rc, REND_COOKIE_LEN);
strlcpy(launched->rend_data->onion_address, service->service_id,
sizeof(launched->rend_data->onion_address));
@@ -1402,19 +1383,878 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0)
goto err;
memcpy(cpath->handshake_digest, keys, DIGEST_LEN);
- if (extend_info) extend_info_free(extend_info);
- memwipe(keys, 0, sizeof(keys));
- return 0;
+ goto done;
+
+ log_error:
+ if (!err_msg) {
+ if (stage_descr) {
+ tor_asprintf(&err_msg,
+ "unknown %s error for INTRODUCE2", stage_descr);
+ } else {
+ err_msg = tor_strdup("unknown error for INTRODUCE2");
+ }
+ }
+
+ log_warn(LD_REND, "%s on circ %d", err_msg, circuit->base_.n_circ_id);
err:
- memwipe(keys, 0, sizeof(keys));
+ status = -1;
if (dh) crypto_dh_free(dh);
- if (launched)
+ if (launched) {
circuit_mark_for_close(TO_CIRCUIT(launched), reason);
- if (extend_info) extend_info_free(extend_info);
+ }
+ tor_free(err_msg);
+
+ done:
+ memwipe(keys, 0, sizeof(keys));
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(serviceid, 0, sizeof(serviceid));
+ memwipe(hexcookie, 0, sizeof(hexcookie));
+ memwipe(intro_key_digest, 0, sizeof(intro_key_digest));
+ memwipe(auth_data, 0, sizeof(auth_data));
+ memwipe(diffie_hellman_hash, 0, sizeof(diffie_hellman_hash));
+
+ /* Free the parsed cell */
+ if (parsed_req) {
+ rend_service_free_intro(parsed_req);
+ parsed_req = NULL;
+ }
+
+ /* Free rp if we must */
+ if (need_rp_free) extend_info_free(rp);
+
+ return status;
+}
+
+/** Given a parsed and decrypted INTRODUCE2, find the rendezvous point or
+ * return NULL and an error string if we can't.
+ */
+
+static extend_info_t *
+find_rp_for_intro(const rend_intro_cell_t *intro,
+ uint8_t *need_free_out, char **err_msg_out)
+{
+ extend_info_t *rp = NULL;
+ char *err_msg = NULL;
+ const char *rp_nickname = NULL;
+ const node_t *node = NULL;
+ uint8_t need_free = 0;
+
+ if (!intro || !need_free_out) {
+ if (err_msg_out)
+ err_msg = tor_strdup("Bad parameters to find_rp_for_intro()");
+
+ goto err;
+ }
+
+ if (intro->version == 0 || intro->version == 1) {
+ if (intro->version == 1) rp_nickname = (const char *)(intro->u.v1.rp);
+ else rp_nickname = (const char *)(intro->u.v0.rp);
+
+ node = node_get_by_nickname(rp_nickname, 0);
+ if (!node) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "Couldn't find router %s named in INTRODUCE2 cell",
+ escaped_safe_str_client(rp_nickname));
+ }
+
+ goto err;
+ }
+
+ rp = extend_info_from_node(node, 0);
+ if (!rp) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "Could build extend_info_t for router %s named "
+ "in INTRODUCE2 cell",
+ escaped_safe_str_client(rp_nickname));
+ }
+
+ goto err;
+ } else {
+ need_free = 1;
+ }
+ } else if (intro->version == 2) {
+ rp = intro->u.v2.extend_info;
+ } else if (intro->version == 3) {
+ rp = intro->u.v3.extend_info;
+ } else {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "Unknown version %d in INTRODUCE2 cell",
+ (int)(intro->version));
+ }
+
+ goto err;
+ }
+
+ goto done;
+
+ err:
+ if (err_msg_out) *err_msg_out = err_msg;
+ else tor_free(err_msg);
+
+ done:
+ if (rp && need_free_out) *need_free_out = need_free;
+
+ return rp;
+}
+
+/** Remove unnecessary parts from a rend_intro_cell_t - the ciphertext if
+ * already decrypted, the plaintext too if already parsed
+ */
+
+void
+rend_service_compact_intro(rend_intro_cell_t *request)
+{
+ if (!request) return;
+
+ if ((request->plaintext && request->plaintext_len > 0) ||
+ request->parsed) {
+ tor_free(request->ciphertext);
+ request->ciphertext_len = 0;
+ }
+
+ if (request->parsed) {
+ tor_free(request->plaintext);
+ request->plaintext_len = 0;
+ }
+}
+
+/** Free a parsed INTRODUCE1 or INTRODUCE2 cell that was allocated by
+ * rend_service_parse_intro().
+ */
+void
+rend_service_free_intro(rend_intro_cell_t *request)
+{
+ if (!request) {
+ log_info(LD_BUG, "rend_service_free_intro() called with NULL request!");
+ return;
+ }
+
+ /* Free ciphertext */
+ tor_free(request->ciphertext);
+ request->ciphertext_len = 0;
+
+ /* Have plaintext? */
+ if (request->plaintext) {
+ /* Zero it out just to be safe */
+ memwipe(request->plaintext, 0, request->plaintext_len);
+ tor_free(request->plaintext);
+ request->plaintext_len = 0;
+ }
+
+ /* Have parsed plaintext? */
+ if (request->parsed) {
+ switch (request->version) {
+ case 0:
+ case 1:
+ /*
+ * Nothing more to do; these formats have no further pointers
+ * in them.
+ */
+ break;
+ case 2:
+ extend_info_free(request->u.v2.extend_info);
+ request->u.v2.extend_info = NULL;
+ break;
+ case 3:
+ if (request->u.v3.auth_data) {
+ memwipe(request->u.v3.auth_data, 0, request->u.v3.auth_len);
+ tor_free(request->u.v3.auth_data);
+ }
+
+ extend_info_free(request->u.v3.extend_info);
+ request->u.v3.extend_info = NULL;
+ break;
+ default:
+ log_info(LD_BUG,
+ "rend_service_free_intro() saw unknown protocol "
+ "version %d.",
+ request->version);
+ }
+ }
+
+ /* Zero it out to make sure sensitive stuff doesn't hang around in memory */
+ memwipe(request, 0, sizeof(*request));
+
+ tor_free(request);
+}
+
+/** Parse an INTRODUCE1 or INTRODUCE2 cell into a newly allocated
+ * rend_intro_cell_t structure. Free it with rend_service_free_intro()
+ * when finished. The type parameter should be 1 or 2 to indicate whether
+ * this is INTRODUCE1 or INTRODUCE2. This parses only the non-encrypted
+ * parts; after this, call rend_service_decrypt_intro() with a key, then
+ * rend_service_parse_intro_plaintext() to finish parsing. The optional
+ * err_msg_out parameter is set to a string suitable for log output
+ * if parsing fails. This function does some validation, but only
+ * that which depends solely on the contents of the cell and the
+ * key; it can be unit-tested. Further validation is done in
+ * rend_service_validate_intro().
+ */
+
+rend_intro_cell_t *
+rend_service_begin_parse_intro(const uint8_t *request,
+ size_t request_len,
+ uint8_t type,
+ char **err_msg_out)
+{
+ rend_intro_cell_t *rv = NULL;
+ char *err_msg = NULL;
+
+ if (!request || request_len <= 0) goto err;
+ if (!(type == 1 || type == 2)) goto err;
+
+ /* First, check that the cell is long enough to be a sensible INTRODUCE */
+
+ /* min key length plus digest length plus nickname length */
+ if (request_len <
+ (DIGEST_LEN + REND_COOKIE_LEN + (MAX_NICKNAME_LEN + 1) +
+ DH_KEY_LEN + 42)) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "got a truncated INTRODUCE%d cell",
+ (int)type);
+ }
+ goto err;
+ }
+
+ /* Allocate a new parsed cell structure */
+ rv = tor_malloc_zero(sizeof(*rv));
+
+ /* Set the type */
+ rv->type = type;
+
+ /* Copy in the ID */
+ memcpy(rv->pk, request, DIGEST_LEN);
+
+ /* Copy in the ciphertext */
+ rv->ciphertext = tor_malloc(request_len - DIGEST_LEN);
+ memcpy(rv->ciphertext, request + DIGEST_LEN, request_len - DIGEST_LEN);
+ rv->ciphertext_len = request_len - DIGEST_LEN;
+
+ goto done;
+
+ err:
+ if (rv) rend_service_free_intro(rv);
+ rv = NULL;
+ if (err_msg_out && !err_msg) {
+ tor_asprintf(&err_msg,
+ "unknown INTRODUCE%d error",
+ (int)type);
+ }
+
+ done:
+ if (err_msg_out) *err_msg_out = err_msg;
+ else tor_free(err_msg);
+
+ return rv;
+}
+
+/** Parse the version-specific parts of a v0 or v1 INTRODUCE1 or INTRODUCE2
+ * cell
+ */
+
+static ssize_t
+rend_service_parse_intro_for_v0_or_v1(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out)
+{
+ const char *rp_nickname, *endptr;
+ size_t nickname_field_len, ver_specific_len;
+
+ if (intro->version == 1) {
+ ver_specific_len = MAX_HEX_NICKNAME_LEN + 2;
+ rp_nickname = ((const char *)buf) + 1;
+ nickname_field_len = MAX_HEX_NICKNAME_LEN + 1;
+ } else if (intro->version == 0) {
+ ver_specific_len = MAX_NICKNAME_LEN + 1;
+ rp_nickname = (const char *)buf;
+ nickname_field_len = MAX_NICKNAME_LEN + 1;
+ } else {
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "rend_service_parse_intro_for_v0_or_v1() called with "
+ "bad version %d on INTRODUCE%d cell (this is a bug)",
+ intro->version,
+ (int)(intro->type));
+ goto err;
+ }
+
+ if (plaintext_len < ver_specific_len) {
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "short plaintext of encrypted part in v1 INTRODUCE%d "
+ "cell (%lu bytes, needed %lu)",
+ (int)(intro->type),
+ (unsigned long)plaintext_len,
+ (unsigned long)ver_specific_len);
+ goto err;
+ }
+
+ endptr = memchr(rp_nickname, 0, nickname_field_len);
+ if (!endptr || endptr == rp_nickname) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "couldn't find a nul-padded nickname in "
+ "INTRODUCE%d cell",
+ (int)(intro->type));
+ }
+ goto err;
+ }
+
+ if ((intro->version == 0 &&
+ !is_legal_nickname(rp_nickname)) ||
+ (intro->version == 1 &&
+ !is_legal_nickname_or_hexdigest(rp_nickname))) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "bad nickname in INTRODUCE%d cell",
+ (int)(intro->type));
+ }
+ goto err;
+ }
+
+ if (intro->version == 1) {
+ memcpy(intro->u.v1.rp, rp_nickname, endptr - rp_nickname + 1);
+ } else {
+ memcpy(intro->u.v0.rp, rp_nickname, endptr - rp_nickname + 1);
+ }
+
+ return ver_specific_len;
+
+ err:
+ return -1;
+}
+
+/** Parse the version-specific parts of a v2 INTRODUCE1 or INTRODUCE2 cell
+ */
+
+static ssize_t
+rend_service_parse_intro_for_v2(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out)
+{
+ unsigned int klen;
+ extend_info_t *extend_info = NULL;
+ ssize_t ver_specific_len;
+
+ /*
+ * We accept version 3 too so that the v3 parser can call this with
+ * and adjusted buffer for the latter part of a v3 cell, which is
+ * identical to a v2 cell.
+ */
+ if (!(intro->version == 2 ||
+ intro->version == 3)) {
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "rend_service_parse_intro_for_v2() called with "
+ "bad version %d on INTRODUCE%d cell (this is a bug)",
+ intro->version,
+ (int)(intro->type));
+ goto err;
+ }
+
+ /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */
+ if (plaintext_len < 7 + DIGEST_LEN + 2) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "truncated plaintext of encrypted parted of "
+ "version %d INTRODUCE%d cell",
+ intro->version,
+ (int)(intro->type));
+ }
+
+ goto err;
+ }
+
+ extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ tor_addr_from_ipv4n(&extend_info->addr, get_uint32(buf + 1));
+ extend_info->port = ntohs(get_uint16(buf + 5));
+ memcpy(extend_info->identity_digest, buf + 7, DIGEST_LEN);
+ extend_info->nickname[0] = '$';
+ base16_encode(extend_info->nickname + 1, sizeof(extend_info->nickname) - 1,
+ extend_info->identity_digest, DIGEST_LEN);
+ klen = ntohs(get_uint16(buf + 7 + DIGEST_LEN));
+
+ /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */
+ if (plaintext_len < 7 + DIGEST_LEN + 2 + klen) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "truncated plaintext of encrypted parted of "
+ "version %d INTRODUCE%d cell",
+ intro->version,
+ (int)(intro->type));
+ }
+
+ goto err;
+ }
+
+ extend_info->onion_key =
+ crypto_pk_asn1_decode((const char *)(buf + 7 + DIGEST_LEN + 2), klen);
+ if (!extend_info->onion_key) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "error decoding onion key in version %d "
+ "INTRODUCE%d cell",
+ intro->version,
+ (intro->type));
+ }
+
+ goto err;
+ }
+
+ ver_specific_len = 7+DIGEST_LEN+2+klen;
+
+ if (intro->version == 2) intro->u.v2.extend_info = extend_info;
+ else intro->u.v3.extend_info = extend_info;
+
+ return ver_specific_len;
+
+ err:
+ extend_info_free(extend_info);
+
+ return -1;
+}
+
+/** Parse the version-specific parts of a v3 INTRODUCE1 or INTRODUCE2 cell
+ */
+
+static ssize_t
+rend_service_parse_intro_for_v3(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out)
+{
+ ssize_t adjust, v2_ver_specific_len, ts_offset;
+
+ /* This should only be called on v3 cells */
+ if (intro->version != 3) {
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "rend_service_parse_intro_for_v3() called with "
+ "bad version %d on INTRODUCE%d cell (this is a bug)",
+ intro->version,
+ (int)(intro->type));
+ goto err;
+ }
+
+ /*
+ * Check that we have at least enough to get auth_len:
+ *
+ * 1 octet for version, 1 for auth_type, 2 for auth_len
+ */
+ if (plaintext_len < 4) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "truncated plaintext of encrypted parted of "
+ "version %d INTRODUCE%d cell",
+ intro->version,
+ (int)(intro->type));
+ }
+
+ goto err;
+ }
+
+ /*
+ * The rend_client_send_introduction() function over in rendclient.c is
+ * broken (i.e., fails to match the spec) in such a way that we can't
+ * change it without breaking the protocol. Specifically, it doesn't
+ * emit auth_len when auth-type is REND_NO_AUTH, so everything is off
+ * by two bytes after that. Calculate ts_offset and do everything from
+ * the timestamp on relative to that to handle this dain bramage.
+ */
+
+ intro->u.v3.auth_type = buf[1];
+ if (intro->u.v3.auth_type != REND_NO_AUTH) {
+ intro->u.v3.auth_len = ntohs(get_uint16(buf + 2));
+ ts_offset = 4 + intro->u.v3.auth_len;
+ } else {
+ intro->u.v3.auth_len = 0;
+ ts_offset = 2;
+ }
+
+ /* Check that auth len makes sense for this auth type */
+ if (intro->u.v3.auth_type == REND_BASIC_AUTH ||
+ intro->u.v3.auth_type == REND_STEALTH_AUTH) {
+ if (intro->u.v3.auth_len != REND_DESC_COOKIE_LEN) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "wrong auth data size %d for INTRODUCE%d cell, "
+ "should be %d",
+ (int)(intro->u.v3.auth_len),
+ (int)(intro->type),
+ REND_DESC_COOKIE_LEN);
+ }
+
+ goto err;
+ }
+ }
+
+ /* Check that we actually have everything up to the timestamp */
+ if (plaintext_len < (size_t)(ts_offset)) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "truncated plaintext of encrypted parted of "
+ "version %d INTRODUCE%d cell",
+ intro->version,
+ (int)(intro->type));
+ }
+
+ goto err;
+ }
+
+ if (intro->u.v3.auth_type != REND_NO_AUTH &&
+ intro->u.v3.auth_len > 0) {
+ /* Okay, we can go ahead and copy auth_data */
+ intro->u.v3.auth_data = tor_malloc(intro->u.v3.auth_len);
+ /*
+ * We know we had an auth_len field in this case, so 4 is
+ * always right.
+ */
+ memcpy(intro->u.v3.auth_data, buf + 4, intro->u.v3.auth_len);
+ }
+
+ /*
+ * Apparently we don't use the timestamp any more, but might as well copy
+ * over just in case we ever care about it.
+ */
+ intro->u.v3.timestamp = ntohl(get_uint32(buf + ts_offset));
+
+ /*
+ * From here on, the format is as in v2, so we call the v2 parser with
+ * adjusted buffer and length. We are 4 + ts_offset octets in, but the
+ * v2 parser expects to skip over a version byte at the start, so we
+ * adjust by 3 + ts_offset.
+ */
+ adjust = 3 + ts_offset;
+
+ v2_ver_specific_len =
+ rend_service_parse_intro_for_v2(intro,
+ buf + adjust, plaintext_len - adjust,
+ err_msg_out);
+
+ /* Success in v2 parser */
+ if (v2_ver_specific_len >= 0) return v2_ver_specific_len + adjust;
+ /* Failure in v2 parser; it will have provided an err_msg */
+ else return v2_ver_specific_len;
+
+ err:
return -1;
}
+/** Table of parser functions for version-specific parts of an INTRODUCE2
+ * cell.
+ */
+
+static ssize_t
+ (*intro_version_handlers[])(
+ rend_intro_cell_t *,
+ const uint8_t *,
+ size_t,
+ char **) =
+{ rend_service_parse_intro_for_v0_or_v1,
+ rend_service_parse_intro_for_v0_or_v1,
+ rend_service_parse_intro_for_v2,
+ rend_service_parse_intro_for_v3 };
+
+/** Decrypt the encrypted part of an INTRODUCE1 or INTRODUCE2 cell,
+ * return 0 if successful, or < 0 and write an error message to
+ * *err_msg_out if provided.
+ */
+
+int
+rend_service_decrypt_intro(
+ rend_intro_cell_t *intro,
+ crypto_pk_t *key,
+ char **err_msg_out)
+{
+ char *err_msg = NULL;
+ uint8_t key_digest[DIGEST_LEN];
+ char service_id[REND_SERVICE_ID_LEN_BASE32+1];
+ ssize_t key_len;
+ uint8_t buf[RELAY_PAYLOAD_SIZE];
+ int result, status = 0;
+
+ if (!intro || !key) {
+ if (err_msg_out) {
+ err_msg =
+ tor_strdup("rend_service_decrypt_intro() called with bad "
+ "parameters");
+ }
+
+ status = -2;
+ goto err;
+ }
+
+ /* Make sure we have ciphertext */
+ if (!(intro->ciphertext) || intro->ciphertext_len <= 0) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "rend_intro_cell_t was missing ciphertext for "
+ "INTRODUCE%d cell",
+ (int)(intro->type));
+ }
+ status = -3;
+ goto err;
+ }
+
+ /* Check that this cell actually matches this service key */
+
+ /* first DIGEST_LEN bytes of request is intro or service pk digest */
+ crypto_pk_get_digest(key, (char *)key_digest);
+ if (tor_memneq(key_digest, intro->pk, DIGEST_LEN)) {
+ if (err_msg_out) {
+ base32_encode(service_id, REND_SERVICE_ID_LEN_BASE32 + 1,
+ (char*)(intro->pk), REND_SERVICE_ID_LEN);
+ tor_asprintf(&err_msg,
+ "got an INTRODUCE%d cell for the wrong service (%s)",
+ (int)(intro->type),
+ escaped(service_id));
+ }
+
+ status = -4;
+ goto err;
+ }
+
+ /* Make sure the encrypted part is long enough to decrypt */
+
+ key_len = crypto_pk_keysize(key);
+ if (intro->ciphertext_len < key_len) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "got an INTRODUCE%d cell with a truncated PK-encrypted "
+ "part",
+ (int)(intro->type));
+ }
+
+ status = -5;
+ goto err;
+ }
+
+ /* Decrypt the encrypted part */
+
+ note_crypto_pk_op(REND_SERVER);
+ result =
+ crypto_pk_private_hybrid_decrypt(
+ key, (char *)buf, sizeof(buf),
+ (const char *)(intro->ciphertext), intro->ciphertext_len,
+ PK_PKCS1_OAEP_PADDING, 1);
+ if (result < 0) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "couldn't decrypt INTRODUCE%d cell",
+ (int)(intro->type));
+ }
+ status = -6;
+ goto err;
+ }
+ intro->plaintext_len = result;
+ intro->plaintext = tor_malloc(intro->plaintext_len);
+ memcpy(intro->plaintext, buf, intro->plaintext_len);
+
+ goto done;
+
+ err:
+ if (err_msg_out && !err_msg) {
+ tor_asprintf(&err_msg,
+ "unknown INTRODUCE%d error decrypting encrypted part",
+ (int)(intro->type));
+ }
+ if (status >= 0) status = -1;
+
+ done:
+ if (err_msg_out) *err_msg_out = err_msg;
+ else tor_free(err_msg);
+
+ /* clean up potentially sensitive material */
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(key_digest, 0, sizeof(key_digest));
+ memwipe(service_id, 0, sizeof(service_id));
+
+ return status;
+}
+
+/** Parse the plaintext of the encrypted part of an INTRODUCE1 or
+ * INTRODUCE2 cell, return 0 if successful, or < 0 and write an error
+ * message to *err_msg_out if provided.
+ */
+
+int
+rend_service_parse_intro_plaintext(
+ rend_intro_cell_t *intro,
+ char **err_msg_out)
+{
+ char *err_msg = NULL;
+ ssize_t ver_specific_len, ver_invariant_len;
+ uint8_t version;
+ int status = 0;
+
+ if (!intro) {
+ if (err_msg_out) {
+ err_msg =
+ tor_strdup("rend_service_parse_intro_plaintext() called with NULL "
+ "rend_intro_cell_t");
+ }
+
+ status = -2;
+ goto err;
+ }
+
+ /* Check that we have plaintext */
+ if (!(intro->plaintext) || intro->plaintext_len <= 0) {
+ if (err_msg_out) {
+ err_msg = tor_strdup("rend_intro_cell_t was missing plaintext");
+ }
+ status = -3;
+ goto err;
+ }
+
+ /* In all formats except v0, the first byte is a version number */
+ version = intro->plaintext[0];
+
+ /* v0 has no version byte (stupid...), so handle it as a fallback */
+ if (version > 3) version = 0;
+
+ /* Copy the version into the parsed cell structure */
+ intro->version = version;
+
+ /* Call the version-specific parser from the table */
+ ver_specific_len =
+ intro_version_handlers[version](intro,
+ intro->plaintext, intro->plaintext_len,
+ &err_msg);
+ if (ver_specific_len < 0) {
+ status = -4;
+ goto err;
+ }
+
+ /** The rendezvous cookie and Diffie-Hellman stuff are version-invariant
+ * and at the end of the plaintext of the encrypted part of the cell.
+ */
+
+ ver_invariant_len = intro->plaintext_len - ver_specific_len;
+ if (ver_invariant_len < REND_COOKIE_LEN + DH_KEY_LEN) {
+ tor_asprintf(&err_msg,
+ "decrypted plaintext of INTRODUCE%d cell was truncated (%ld bytes)",
+ (int)(intro->type),
+ (long)(intro->plaintext_len));
+ status = -5;
+ goto err;
+ } else if (ver_invariant_len > REND_COOKIE_LEN + DH_KEY_LEN) {
+ tor_asprintf(&err_msg,
+ "decrypted plaintext of INTRODUCE%d cell was too long (%ld bytes)",
+ (int)(intro->type),
+ (long)(intro->plaintext_len));
+ status = -6;
+ } else {
+ memcpy(intro->rc,
+ intro->plaintext + ver_specific_len,
+ REND_COOKIE_LEN);
+ memcpy(intro->dh,
+ intro->plaintext + ver_specific_len + REND_COOKIE_LEN,
+ DH_KEY_LEN);
+ }
+
+ /* Flag it as being fully parsed */
+ intro->parsed = 1;
+
+ goto done;
+
+ err:
+ if (err_msg_out && !err_msg) {
+ tor_asprintf(&err_msg,
+ "unknown INTRODUCE%d error parsing encrypted part",
+ (int)(intro->type));
+ }
+ if (status >= 0) status = -1;
+
+ done:
+ if (err_msg_out) *err_msg_out = err_msg;
+ else tor_free(err_msg);
+
+ return status;
+}
+
+/** Do validity checks on a parsed intro cell before decryption; some of
+ * these are not done in rend_service_begin_parse_intro() itself because
+ * they depend on a lot of other state and would make it hard to unit test.
+ * Returns >= 0 if successful or < 0 if the intro cell is invalid, and
+ * optionally writes out an error message for logging. If an err_msg
+ * pointer is provided, it is the caller's responsibility to free any
+ * provided message.
+ */
+
+int
+rend_service_validate_intro_early(const rend_intro_cell_t *intro,
+ char **err_msg_out)
+{
+ int status = 0;
+
+ if (!intro) {
+ if (err_msg_out)
+ *err_msg_out =
+ tor_strdup("NULL intro cell passed to "
+ "rend_service_validate_intro_early()");
+
+ status = -1;
+ goto err;
+ }
+
+ /* TODO */
+
+ err:
+ return status;
+}
+
+/** Do validity checks on a parsed intro cell after decryption; some of
+ * these are not done in rend_service_parse_intro_plaintext() itself because
+ * they depend on a lot of other state and would make it hard to unit test.
+ * Returns >= 0 if successful or < 0 if the intro cell is invalid, and
+ * optionally writes out an error message for logging. If an err_msg
+ * pointer is provided, it is the caller's responsibility to free any
+ * provided message.
+ */
+
+int
+rend_service_validate_intro_late(const rend_intro_cell_t *intro,
+ char **err_msg_out)
+{
+ int status = 0;
+
+ if (!intro) {
+ if (err_msg_out)
+ *err_msg_out =
+ tor_strdup("NULL intro cell passed to "
+ "rend_service_validate_intro_late()");
+
+ status = -1;
+ goto err;
+ }
+
+ if (intro->version == 3 && intro->parsed) {
+ if (!(intro->u.v3.auth_type == REND_NO_AUTH ||
+ intro->u.v3.auth_type == REND_BASIC_AUTH ||
+ intro->u.v3.auth_type == REND_STEALTH_AUTH)) {
+ /* This is an informative message, not an error, as in the old code */
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "unknown authorization type %d",
+ intro->u.v3.auth_type);
+ }
+ }
+
+ err:
+ return status;
+}
+
/** Called when we fail building a rendezvous circuit at some point other
* than the last hop: launches a new circuit to the same rendezvous point.
*/
@@ -1424,7 +2264,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
origin_circuit_t *newcirc;
cpath_build_state_t *newstate, *oldstate;
- tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
/* Don't relaunch the same rend circ twice. */
if (oldcirc->hs_service_side_rend_circ_has_been_relaunched) {
@@ -1529,7 +2369,7 @@ rend_service_launch_establish_intro(rend_service_t *service,
sizeof(launched->rend_data->onion_address));
memcpy(launched->rend_data->rend_pk_digest, service->pk_digest, DIGEST_LEN);
launched->intro_key = crypto_pk_dup_key(intro->intro_key);
- if (launched->_base.state == CIRCUIT_STATE_OPEN)
+ if (launched->base_.state == CIRCUIT_STATE_OPEN)
rend_service_intro_has_opened(launched);
return 0;
}
@@ -1541,7 +2381,7 @@ count_established_intro_points(const char *query)
{
int num_ipos = 0;
circuit_t *circ;
- for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
if (!circ->marked_for_close &&
circ->state == CIRCUIT_STATE_OPEN &&
(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -1570,7 +2410,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
int reason = END_CIRC_REASON_TORPROTOCOL;
crypto_pk_t *intro_key;
- tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
+ tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
#ifndef NON_ANONYMOUS_MODE_ENABLED
tor_assert(!(circuit->build_state->onehop_tunnel));
#endif
@@ -1584,7 +2424,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
circuit->rend_data->rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
- serviceid, circuit->_base.n_circ_id);
+ serviceid, circuit->base_.n_circ_id);
reason = END_CIRC_REASON_NOSUCHSERVICE;
goto err;
}
@@ -1600,8 +2440,8 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
this case, we might as well close the thing. */
log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
"circuit, but we already have enough. Closing it.");
- circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_NONE);
- return;
+ reason = END_CIRC_REASON_NONE;
+ goto err;
} else {
tor_assert(circuit->build_state->is_internal);
log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
@@ -1622,13 +2462,13 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
}
circuit_has_opened(circuit);
- return;
+ goto done;
}
}
log_info(LD_REND,
"Established circuit %d as introduction point for service %s",
- circuit->_base.n_circ_id, serviceid);
+ circuit->base_.n_circ_id, serviceid);
/* Use the intro key instead of the service key in ESTABLISH_INTRO. */
intro_key = circuit->intro_key;
@@ -1663,14 +2503,21 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
buf, len, circuit->cpath->prev)<0) {
log_info(LD_GENERAL,
"Couldn't send introduction request for service %s on circuit %d",
- serviceid, circuit->_base.n_circ_id);
+ serviceid, circuit->base_.n_circ_id);
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
- return;
+ goto done;
+
err:
circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
+ done:
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(auth, 0, sizeof(auth));
+ memwipe(serviceid, 0, sizeof(serviceid));
+
+ return;
}
/** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
@@ -1686,7 +2533,7 @@ rend_service_intro_established(origin_circuit_t *circuit,
(void) request;
(void) request_len;
- if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
+ if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_warn(LD_PROTOCOL,
"received INTRO_ESTABLISHED cell on non-intro circuit.");
goto err;
@@ -1696,7 +2543,7 @@ rend_service_intro_established(origin_circuit_t *circuit,
circuit->rend_data->rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unknown service on introduction circuit %d.",
- circuit->_base.n_circ_id);
+ circuit->base_.n_circ_id);
goto err;
}
service->desc_is_dirty = time(NULL);
@@ -1706,7 +2553,7 @@ rend_service_intro_established(origin_circuit_t *circuit,
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
log_info(LD_REND,
"Received INTRO_ESTABLISHED cell on circuit %d for service %s",
- circuit->_base.n_circ_id, serviceid);
+ circuit->base_.n_circ_id, serviceid);
return 0;
err:
@@ -1727,7 +2574,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
char hexcookie[9];
int reason;
- tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
tor_assert(circuit->cpath);
tor_assert(circuit->build_state);
#ifndef NON_ANONYMOUS_MODE_ENABLED
@@ -1743,7 +2590,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
log_info(LD_REND,
"Done building circuit %d to rendezvous with "
"cookie %s for service %s",
- circuit->_base.n_circ_id, hexcookie, serviceid);
+ circuit->base_.n_circ_id, hexcookie, serviceid);
/* Clear the 'in-progress HS circ has timed out' flag for
* consistency with what happens on the client side; this line has
@@ -1813,9 +2660,16 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
/* Change the circuit purpose. */
circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_S_REND_JOINED);
- return;
+ goto done;
+
err:
circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
+ done:
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(serviceid, 0, sizeof(serviceid));
+ memwipe(hexcookie, 0, sizeof(hexcookie));
+
+ return;
}
/*
@@ -1876,7 +2730,7 @@ find_intro_point(origin_circuit_t *circ)
if (service == NULL) return NULL;
SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro_point,
- if (crypto_pk_cmp_keys(intro_point->intro_key, circ->intro_key) == 0) {
+ if (crypto_pk_eq_keys(intro_point->intro_key, circ->intro_key)) {
return intro_point;
});
@@ -1929,7 +2783,8 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
directory_initiate_command_routerstatus(hs_dir,
DIR_PURPOSE_UPLOAD_RENDDESC_V2,
ROUTER_PURPOSE_GENERAL,
- 1, NULL, desc->desc_str,
+ DIRIND_ANONYMOUS, NULL,
+ desc->desc_str,
strlen(desc->desc_str), 0);
base32_encode(desc_id_base32, sizeof(desc_id_base32),
desc->desc_id, DIGEST_LEN);
@@ -2091,11 +2946,7 @@ upload_service_descriptor(rend_service_t *service)
static int
intro_point_accepted_intro_count(rend_intro_point_t *intro)
{
- if (intro->accepted_intro_rsa_parts == NULL) {
- return 0;
- } else {
- return digestmap_size(intro->accepted_intro_rsa_parts);
- }
+ return intro->accepted_introduce2_count;
}
/** Return non-zero iff <b>intro</b> should 'expire' now (i.e. we
@@ -2299,7 +3150,7 @@ rend_services_introduce(void)
j < (int)n_intro_points_to_open;
++j) { /* XXXX remove casts */
router_crn_flags_t flags = CRN_NEED_UPTIME|CRN_NEED_DESC;
- if (get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION)
+ if (get_options()->AllowInvalid_ & ALLOW_INVALID_INTRODUCTION)
flags |= CRN_ALLOW_INVALID;
node = router_choose_random_node(intro_nodes,
options->ExcludeNodes, flags);
@@ -2449,7 +3300,7 @@ rend_service_dump_stats(int severity)
continue;
}
log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s",
- j, safe_name, circuit_state_to_string(circ->_base.state));
+ j, safe_name, circuit_state_to_string(circ->base_.state));
}
}
}
@@ -2468,7 +3319,7 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
smartlist_t *matching_ports;
rend_service_port_config_t *chosen_port;
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
tor_assert(circ->rend_data);
log_debug(LD_REND,"beginning to hunt for addr/port");
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
@@ -2478,25 +3329,25 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
if (!service) {
log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
"rendezvous circuit %d; closing.",
- serviceid, circ->_base.n_circ_id);
+ serviceid, circ->base_.n_circ_id);
return -1;
}
matching_ports = smartlist_new();
SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p,
{
- if (conn->_base.port == p->virtual_port) {
+ if (conn->base_.port == p->virtual_port) {
smartlist_add(matching_ports, p);
}
});
chosen_port = smartlist_choose(matching_ports);
smartlist_free(matching_ports);
if (chosen_port) {
- tor_addr_copy(&conn->_base.addr, &chosen_port->real_addr);
- conn->_base.port = chosen_port->real_port;
+ tor_addr_copy(&conn->base_.addr, &chosen_port->real_addr);
+ conn->base_.port = chosen_port->real_port;
return 0;
}
log_info(LD_REND, "No virtual port mapping exists for port %d on service %s",
- conn->_base.port,serviceid);
+ conn->base_.port,serviceid);
return -1;
}
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index e5848785a8..1671602348 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -9,12 +9,70 @@
* \brief Header file for rendservice.c.
**/
-#ifndef _TOR_RENDSERVICE_H
-#define _TOR_RENDSERVICE_H
+#ifndef TOR_RENDSERVICE_H
+#define TOR_RENDSERVICE_H
+
+#include "or.h"
+
+typedef struct rend_intro_cell_s rend_intro_cell_t;
+
+#ifdef RENDSERVICE_PRIVATE
+
+/* This can be used for both INTRODUCE1 and INTRODUCE2 */
+
+struct rend_intro_cell_s {
+ /* Is this an INTRODUCE1 or INTRODUCE2? (set to 1 or 2) */
+ uint8_t type;
+ /* Public key digest */
+ uint8_t pk[DIGEST_LEN];
+ /* Optionally, store ciphertext here */
+ uint8_t *ciphertext;
+ ssize_t ciphertext_len;
+ /* Optionally, store plaintext */
+ uint8_t *plaintext;
+ ssize_t plaintext_len;
+ /* Have we parsed the plaintext? */
+ uint8_t parsed;
+ /* intro protocol version (0, 1, 2 or 3) */
+ uint8_t version;
+ /* Version-specific parts */
+ union {
+ struct {
+ /* Rendezvous point nickname */
+ uint8_t rp[20];
+ } v0;
+ struct {
+ /* Rendezvous point nickname or hex-encoded key digest */
+ uint8_t rp[42];
+ } v1;
+ struct {
+ /* The extend_info_t struct has everything v2 uses */
+ extend_info_t *extend_info;
+ } v2;
+ struct {
+ /* Auth type used */
+ uint8_t auth_type;
+ /* Length of auth data */
+ uint16_t auth_len;
+ /* Auth data */
+ uint8_t *auth_data;
+ /* timestamp */
+ uint32_t timestamp;
+ /* Rendezvous point's IP address/port, identity digest and onion key */
+ extend_info_t *extend_info;
+ } v3;
+ } u;
+ /* Rendezvous cookie */
+ uint8_t rc[REND_COOKIE_LEN];
+ /* Diffie-Hellman data */
+ uint8_t dh[DH_KEY_LEN];
+};
+
+#endif
int num_rend_services(void);
int rend_config_services(const or_options_t *options, int validate_only);
-int rend_service_load_keys(void);
+int rend_service_load_all_keys(void);
void rend_services_introduce(void);
void rend_consider_services_upload(time_t now);
void rend_hsdir_routers_changed(void);
@@ -27,6 +85,21 @@ int rend_service_intro_established(origin_circuit_t *circuit,
void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
int rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
size_t request_len);
+void rend_service_compact_intro(rend_intro_cell_t *request);
+int rend_service_decrypt_intro(rend_intro_cell_t *request,
+ crypto_pk_t *key,
+ char **err_msg_out);
+void rend_service_free_intro(rend_intro_cell_t *request);
+rend_intro_cell_t * rend_service_begin_parse_intro(const uint8_t *request,
+ size_t request_len,
+ uint8_t type,
+ char **err_msg_out);
+int rend_service_parse_intro_plaintext(rend_intro_cell_t *intro,
+ char **err_msg_out);
+int rend_service_validate_intro_early(const rend_intro_cell_t *intro,
+ char **err_msg_out);
+int rend_service_validate_intro_late(const rend_intro_cell_t *intro,
+ char **err_msg_out);
void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
int rend_service_set_connection_addr_port(edge_connection_t *conn,
origin_circuit_t *circ);
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 3b0d9dd35f..e61e599d7e 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -160,7 +160,7 @@ get_link_history(const char *from_id, const char *to_id)
/** Helper: free storage held by a single link history entry. */
static void
-_free_link_history(void *val)
+free_link_history_(void *val)
{
rephist_total_alloc -= sizeof(link_history_t);
tor_free(val);
@@ -171,7 +171,7 @@ static void
free_or_history(void *_hist)
{
or_history_t *hist = _hist;
- digestmap_free(hist->link_history_map, _free_link_history);
+ digestmap_free(hist->link_history_map, free_link_history_);
rephist_total_alloc -= sizeof(or_history_t);
rephist_total_num--;
tor_free(hist);
@@ -1136,7 +1136,7 @@ rep_hist_load_mtbf_data(time_t now)
wfu_timebuf[0] = '\0';
if (format == 1) {
- n = sscanf(line, "%40s %ld %lf S=%10s %8s",
+ n = tor_sscanf(line, "%40s %ld %lf S=%10s %8s",
hexbuf, &wrl, &trw, mtbf_timebuf, mtbf_timebuf+11);
if (n != 3 && n != 5) {
log_warn(LD_HIST, "Couldn't scan line %s", escaped(line));
@@ -1153,7 +1153,7 @@ rep_hist_load_mtbf_data(time_t now)
wfu_idx = find_next_with(lines, i+1, "+WFU ");
if (mtbf_idx >= 0) {
const char *mtbfline = smartlist_get(lines, mtbf_idx);
- n = sscanf(mtbfline, "+MTBF %lu %lf S=%10s %8s",
+ n = tor_sscanf(mtbfline, "+MTBF %lu %lf S=%10s %8s",
&wrl, &trw, mtbf_timebuf, mtbf_timebuf+11);
if (n == 2 || n == 4) {
have_mtbf = 1;
@@ -1164,7 +1164,7 @@ rep_hist_load_mtbf_data(time_t now)
}
if (wfu_idx >= 0) {
const char *wfuline = smartlist_get(lines, wfu_idx);
- n = sscanf(wfuline, "+WFU %lu %lu S=%10s %8s",
+ n = tor_sscanf(wfuline, "+WFU %lu %lu S=%10s %8s",
&wt_uptime, &total_wt_time,
wfu_timebuf, wfu_timebuf+11);
if (n == 2 || n == 4) {
@@ -1531,7 +1531,7 @@ rep_hist_get_bandwidth_lines(void)
const char *desc = NULL;
size_t len;
- /* opt [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
+ /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
/* The n,n,n part above. Largest representation of a uint64_t is 20 chars
* long, plus the comma. */
#define MAX_HIST_VALUE_LEN 21*NUM_TOTALS
@@ -2131,7 +2131,7 @@ rep_hist_exit_stats_term(void)
* but works fine for sorting an array of port numbers, which is what we use
* it for. */
static int
-_compare_int(const void *x, const void *y)
+compare_int_(const void *x, const void *y)
{
return (*(int*)x - *(int*)y);
}
@@ -2218,7 +2218,7 @@ rep_hist_format_exit_stats(time_t now)
other_streams = total_streams;
/* Sort the ports; this puts them out of sync with top_bytes, but we
* won't be using top_bytes again anyway */
- qsort(top_ports, top_elements, sizeof(int), _compare_int);
+ qsort(top_ports, top_elements, sizeof(int), compare_int_);
for (j = 0; j < top_elements; j++) {
cur_port = top_ports[j];
if (exit_bytes_written[cur_port] > 0) {
@@ -2440,7 +2440,7 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
/** Sorting helper: return -1, 1, or 0 based on comparison of two
* circ_buffer_stats_t */
static int
-_buffer_stats_compare_entries(const void **_a, const void **_b)
+buffer_stats_compare_entries_(const void **_a, const void **_b)
{
const circ_buffer_stats_t *a = *_a, *b = *_b;
if (a->processed_cells < b->processed_cells)
@@ -2505,7 +2505,7 @@ rep_hist_format_buffer_stats(time_t now)
number_of_circuits = smartlist_len(circuits_for_buffer_stats);
if (number_of_circuits > 0) {
smartlist_sort(circuits_for_buffer_stats,
- _buffer_stats_compare_entries);
+ buffer_stats_compare_entries_);
i = 0;
SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
circ_buffer_stats_t *, stat)
@@ -2590,7 +2590,7 @@ rep_hist_buffer_stats_write(time_t now)
goto done; /* Not ready to write */
/* Add open circuits to the history. */
- for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
rep_hist_buffer_stats_add_circ(circ, now);
}
@@ -3003,6 +3003,8 @@ rep_hist_free_all(void)
digestmap_free(history_map, free_or_history);
tor_free(read_array);
tor_free(write_array);
+ tor_free(dir_read_array);
+ tor_free(dir_write_array);
tor_free(last_stability_doc);
tor_free(exit_bytes_read);
tor_free(exit_bytes_written);
diff --git a/src/or/rephist.h b/src/or/rephist.h
index d47724edb5..28dec8f902 100644
--- a/src/or/rephist.h
+++ b/src/or/rephist.h
@@ -9,8 +9,8 @@
* \brief Header file for rephist.c.
**/
-#ifndef _TOR_REPHIST_H
-#define _TOR_REPHIST_H
+#ifndef TOR_REPHIST_H
+#define TOR_REPHIST_H
void rep_hist_init(void);
void rep_hist_note_connect_failed(const char* nickname, time_t when);
diff --git a/src/or/replaycache.c b/src/or/replaycache.c
new file mode 100644
index 0000000000..868b21c9b0
--- /dev/null
+++ b/src/or/replaycache.c
@@ -0,0 +1,215 @@
+ /* Copyright (c) 2012, The Tor Project, Inc. */
+ /* See LICENSE for licensing information */
+
+/*
+ * \file replaycache.c
+ *
+ * \brief Self-scrubbing replay cache for rendservice.c
+ */
+
+#define REPLAYCACHE_PRIVATE
+
+#include "or.h"
+#include "replaycache.h"
+
+/** Free the replaycache r and all of its entries.
+ */
+
+void
+replaycache_free(replaycache_t *r)
+{
+ if (!r) {
+ log_info(LD_BUG, "replaycache_free() called on NULL");
+ return;
+ }
+
+ if (r->digests_seen) digestmap_free(r->digests_seen, tor_free_);
+
+ tor_free(r);
+}
+
+/** Allocate a new, empty replay detection cache, where horizon is the time
+ * for entries to age out and interval is the time after which the cache
+ * should be scrubbed for old entries.
+ */
+
+replaycache_t *
+replaycache_new(time_t horizon, time_t interval)
+{
+ replaycache_t *r = NULL;
+
+ if (horizon < 0) {
+ log_info(LD_BUG, "replaycache_new() called with negative"
+ " horizon parameter");
+ goto err;
+ }
+
+ if (interval < 0) {
+ log_info(LD_BUG, "replaycache_new() called with negative interval"
+ " parameter");
+ interval = 0;
+ }
+
+ r = tor_malloc(sizeof(*r));
+ r->scrub_interval = interval;
+ r->scrubbed = 0;
+ r->horizon = horizon;
+ r->digests_seen = digestmap_new();
+
+ err:
+ return r;
+}
+
+/** See documentation for replaycache_add_and_test()
+ */
+
+int
+replaycache_add_and_test_internal(
+ time_t present, replaycache_t *r, const void *data, int len,
+ time_t *elapsed)
+{
+ int rv = 0;
+ char digest[DIGEST_LEN];
+ time_t *access_time;
+
+ /* sanity check */
+ if (present <= 0 || !r || !data || len <= 0) {
+ log_info(LD_BUG, "replaycache_add_and_test_internal() called with stupid"
+ " parameters; please fix this.");
+ goto done;
+ }
+
+ /* compute digest */
+ crypto_digest(digest, (const char *)data, len);
+
+ /* check map */
+ access_time = digestmap_get(r->digests_seen, digest);
+
+ /* seen before? */
+ if (access_time != NULL) {
+ /*
+ * If it's far enough in the past, no hit. If the horizon is zero, we
+ * never expire.
+ */
+ if (*access_time >= present - r->horizon || r->horizon == 0) {
+ /* replay cache hit, return 1 */
+ rv = 1;
+ /* If we want to output an elapsed time, do so */
+ if (elapsed) {
+ if (present >= *access_time) {
+ *elapsed = present - *access_time;
+ } else {
+ /* We shouldn't really be seeing hits from the future, but... */
+ *elapsed = 0;
+ }
+ }
+ }
+ /*
+ * If it's ahead of the cached time, update
+ */
+ if (*access_time < present) {
+ *access_time = present;
+ }
+ } else {
+ /* No, so no hit and update the digest map with the current time */
+ access_time = tor_malloc(sizeof(*access_time));
+ *access_time = present;
+ digestmap_set(r->digests_seen, digest, access_time);
+ }
+
+ /* now scrub the cache if it's time */
+ replaycache_scrub_if_needed_internal(present, r);
+
+ done:
+ return rv;
+}
+
+/** See documentation for replaycache_scrub_if_needed()
+ */
+
+void
+replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r)
+{
+ digestmap_iter_t *itr = NULL;
+ const char *digest;
+ void *valp;
+ time_t *access_time;
+ char scrub_this;
+
+ /* sanity check */
+ if (!r || !(r->digests_seen)) {
+ log_info(LD_BUG, "replaycache_scrub_if_needed_internal() called with"
+ " stupid parameters; please fix this.");
+ return;
+ }
+
+ /* scrub time yet? (scrubbed == 0 indicates never scrubbed before) */
+ if (present - r->scrubbed < r->scrub_interval && r->scrubbed > 0) return;
+
+ /* if we're never expiring, don't bother scrubbing */
+ if (r->horizon == 0) return;
+
+ /* okay, scrub time */
+ itr = digestmap_iter_init(r->digests_seen);
+ while (!digestmap_iter_done(itr)) {
+ scrub_this = 0;
+ digestmap_iter_get(itr, &digest, &valp);
+ access_time = (time_t *)valp;
+ if (access_time) {
+ /* aged out yet? */
+ if (*access_time < present - r->horizon) scrub_this = 1;
+ } else {
+ /* Buh? Get rid of it, anyway */
+ log_info(LD_BUG, "replaycache_scrub_if_needed_internal() saw a NULL"
+ " entry in the digestmap.");
+ scrub_this = 1;
+ }
+
+ if (scrub_this) {
+ /* Advance the iterator and remove this one */
+ itr = digestmap_iter_next_rmv(r->digests_seen, itr);
+ /* Free the value removed */
+ tor_free(access_time);
+ } else {
+ /* Just advance the iterator */
+ itr = digestmap_iter_next(r->digests_seen, itr);
+ }
+ }
+
+ /* update scrubbed timestamp */
+ if (present > r->scrubbed) r->scrubbed = present;
+}
+
+/** Test the buffer of length len point to by data against the replay cache r;
+ * the digest of the buffer will be added to the cache at the current time,
+ * and the function will return 1 if it was already seen within the cache's
+ * horizon, or 0 otherwise.
+ */
+
+int
+replaycache_add_and_test(replaycache_t *r, const void *data, int len)
+{
+ return replaycache_add_and_test_internal(time(NULL), r, data, len, NULL);
+}
+
+/** Like replaycache_add_and_test(), but if it's a hit also return the time
+ * elapsed since this digest was last seen.
+ */
+
+int
+replaycache_add_test_and_elapsed(
+ replaycache_t *r, const void *data, int len, time_t *elapsed)
+{
+ return replaycache_add_and_test_internal(time(NULL), r, data, len, elapsed);
+}
+
+/** Scrub aged entries out of r if sufficiently long has elapsed since r was
+ * last scrubbed.
+ */
+
+void
+replaycache_scrub_if_needed(replaycache_t *r)
+{
+ replaycache_scrub_if_needed_internal(time(NULL), r);
+}
+
diff --git a/src/or/replaycache.h b/src/or/replaycache.h
new file mode 100644
index 0000000000..757102b960
--- /dev/null
+++ b/src/or/replaycache.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file replaycache.h
+ * \brief Header file for replaycache.c.
+ **/
+
+#ifndef TOR_REPLAYCACHE_H
+#define TOR_REPLAYCACHE_H
+
+typedef struct replaycache_s replaycache_t;
+
+#ifdef REPLAYCACHE_PRIVATE
+
+struct replaycache_s {
+ /* Scrub interval */
+ time_t scrub_interval;
+ /* Last scrubbed */
+ time_t scrubbed;
+ /*
+ * Horizon
+ * (don't return true on digests in the cache but older than this)
+ */
+ time_t horizon;
+ /*
+ * Digest map: keys are digests, values are times the digest was last seen
+ */
+ digestmap_t *digests_seen;
+};
+
+#endif /* REPLAYCACHE_PRIVATE */
+
+/* replaycache_t free/new */
+
+void replaycache_free(replaycache_t *r);
+replaycache_t * replaycache_new(time_t horizon, time_t interval);
+
+#ifdef REPLAYCACHE_PRIVATE
+
+/*
+ * replaycache_t internal functions:
+ *
+ * These take the time to treat as the present as an argument for easy unit
+ * testing. For everything else, use the wrappers below instead.
+ */
+
+int replaycache_add_and_test_internal(
+ time_t present, replaycache_t *r, const void *data, int len,
+ time_t *elapsed);
+void replaycache_scrub_if_needed_internal(
+ time_t present, replaycache_t *r);
+
+#endif /* REPLAYCACHE_PRIVATE */
+
+/*
+ * replaycache_t methods
+ */
+
+int replaycache_add_and_test(replaycache_t *r, const void *data, int len);
+int replaycache_add_test_and_elapsed(
+ replaycache_t *r, const void *data, int len, time_t *elapsed);
+void replaycache_scrub_if_needed(replaycache_t *r);
+
+#endif
+
diff --git a/src/or/router.c b/src/or/router.c
index 38f1cdd495..5786103b94 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -27,6 +27,9 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "statefile.h"
+#include "transports.h"
+#include "routerset.h"
/**
* \file router.c
@@ -84,7 +87,7 @@ static authority_cert_t *legacy_key_certificate = NULL;
static void
set_onion_key(crypto_pk_t *k)
{
- if (onionkey && !crypto_pk_cmp_keys(onionkey, k)) {
+ if (onionkey && crypto_pk_eq_keys(onionkey, k)) {
/* k is already our onion key; free it and return */
crypto_pk_free(k);
return;
@@ -152,12 +155,11 @@ assert_identity_keys_ok(void)
if (public_server_mode(get_options())) {
/* assert that we have set the client and server keys to be equal */
tor_assert(server_identitykey);
- tor_assert(0==crypto_pk_cmp_keys(client_identitykey, server_identitykey));
+ tor_assert(crypto_pk_eq_keys(client_identitykey, server_identitykey));
} else {
/* assert that we have set the client and server keys to be unequal */
if (server_identitykey)
- tor_assert(0!=crypto_pk_cmp_keys(client_identitykey,
- server_identitykey));
+ tor_assert(!crypto_pk_eq_keys(client_identitykey, server_identitykey));
}
}
@@ -397,7 +399,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out,
log_warn(LD_DIR, "Unable to parse certificate in %s", fname);
goto done;
}
- if (crypto_pk_cmp_keys(signing_key, parsed->signing_key) != 0) {
+ if (!crypto_pk_eq_keys(signing_key, parsed->signing_key)) {
log_warn(LD_DIR, "Stored signing key does not match signing key in "
"certificate");
goto done;
@@ -515,7 +517,7 @@ init_keys(void)
const or_options_t *options = get_options();
dirinfo_type_t type;
time_t now = time(NULL);
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
int v3_digest_set = 0;
authority_cert_t *cert = NULL;
@@ -671,7 +673,7 @@ init_keys(void)
* we don't really need new keys yet so the descriptor doesn't
* change and the old one is still fresh. */
log_info(LD_GENERAL, "Couldn't add own descriptor to directory "
- "after key init: %s. This is usually not a problem.",
+ "after key init: %s This is usually not a problem.",
m?m:"<unknown error>");
}
}
@@ -730,17 +732,18 @@ init_keys(void)
ds = router_get_trusteddirserver_by_digest(digest);
if (!ds) {
- ds = add_trusted_dir_server(options->Nickname, NULL,
+ ds = trusted_dir_server_new(options->Nickname, NULL,
router_get_advertised_dir_port(options, 0),
router_get_advertised_or_port(options),
digest,
v3_digest,
- type);
+ type, 0.0);
if (!ds) {
log_err(LD_GENERAL,"We want to be a directory authority, but we "
"couldn't add ourselves to the authority list. Failing.");
return -1;
}
+ dir_server_add(ds);
}
if (ds->type != type) {
log_warn(LD_DIR, "Configured authority type does not match authority "
@@ -879,6 +882,21 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
return advertising ? dir_port : 0;
}
+/** Allocate and return a new extend_info_t that can be used to build
+ * a circuit to or through the router <b>r</b>. Use the primary
+ * address of the router unless <b>for_direct_connect</b> is true, in
+ * which case the preferred address is used instead. */
+static extend_info_t *
+extend_info_from_router(const routerinfo_t *r)
+{
+ tor_addr_port_t ap;
+ tor_assert(r);
+
+ router_get_prim_orport(r, &ap);
+ return extend_info_new(r->nickname, r->cache_info.identity_digest,
+ r->onion_pkey, &ap.addr, ap.port);
+}
+
/** Some time has passed, or we just got new directory information.
* See if we currently believe our ORPort or DirPort to be
* unreachable. If so, launch a new test for it.
@@ -920,12 +938,11 @@ consider_testing_reachability(int test_or, int test_dir)
}
if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
- extend_info_t *ei;
+ extend_info_t *ei = extend_info_from_router(me);
+ /* XXX IPv6 self testing */
log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
!orport_reachable ? "reachability" : "bandwidth",
me->address, me->or_port);
- /* XXX IPv6 self testing IPv6 orports will need pref_addr */
- ei = extend_info_from_router(me, 0);
circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
extend_info_free(ei);
@@ -939,11 +956,10 @@ consider_testing_reachability(int test_or, int test_dir)
/* ask myself, via tor, for my server descriptor. */
directory_initiate_command(me->address, &addr,
me->or_port, me->dir_port,
- 0, /* does not matter */
- 0, me->cache_info.identity_digest,
+ me->cache_info.identity_digest,
DIR_PURPOSE_FETCH_SERVERDESC,
ROUTER_PURPOSE_GENERAL,
- 1, "authority.z", NULL, 0, 0);
+ DIRIND_ANON_DIRPORT, "authority.z", NULL, 0, 0);
}
}
@@ -955,7 +971,7 @@ router_orport_found_reachable(void)
if (!can_reach_or_port && me) {
log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
"the outside. Excellent.%s",
- get_options()->_PublishServerDescriptor != NO_DIRINFO ?
+ get_options()->PublishServerDescriptor_ != NO_DIRINFO ?
" Publishing server descriptor." : "");
can_reach_or_port = 1;
mark_my_descriptor_dirty("ORPort found reachable");
@@ -998,9 +1014,9 @@ router_perform_bandwidth_test(int num_circs, time_t now)
CIRCUIT_PURPOSE_TESTING))) {
/* dump cells_per_circuit drop cells onto this circ */
int i = cells_per_circuit;
- if (circ->_base.state != CIRCUIT_STATE_OPEN)
+ if (circ->base_.state != CIRCUIT_STATE_OPEN)
continue;
- circ->_base.timestamp_dirty = now;
+ circ->base_.timestamp_dirty = now;
while (i-- > 0) {
if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
RELAY_COMMAND_DROP,
@@ -1194,7 +1210,7 @@ decide_if_publishable_server(void)
if (options->ClientOnly)
return 0;
- if (options->_PublishServerDescriptor == NO_DIRINFO)
+ if (options->PublishServerDescriptor_ == NO_DIRINFO)
return 0;
if (!server_mode(options))
return 0;
@@ -1315,7 +1331,7 @@ router_upload_dir_desc_to_dirservers(int force)
extrainfo_t *ei;
char *msg;
size_t desc_len, extra_len = 0, total_len;
- dirinfo_type_t auth = get_options()->_PublishServerDescriptor;
+ dirinfo_type_t auth = get_options()->PublishServerDescriptor_;
ri = router_get_my_routerinfo();
if (!ri) {
@@ -1355,22 +1371,34 @@ router_upload_dir_desc_to_dirservers(int force)
* conn. Return 0 if we accept; non-0 if we reject.
*/
int
-router_compare_to_my_exit_policy(edge_connection_t *conn)
+router_compare_to_my_exit_policy(const tor_addr_t *addr, uint16_t port)
{
if (!router_get_my_routerinfo()) /* make sure desc_routerinfo exists */
return -1;
/* make sure it's resolved to something. this way we can't get a
'maybe' below. */
- if (tor_addr_is_null(&conn->_base.addr))
+ if (tor_addr_is_null(addr))
return -1;
- /* XXXX IPv6 */
- if (tor_addr_family(&conn->_base.addr) != AF_INET)
+ /* look at desc_routerinfo->exit_policy for both the v4 and the v6
+ * policies. The exit_policy field in desc_routerinfo is a bit unusual,
+ * in that it contains IPv6 and IPv6 entries. We don't want to look
+ * at desc_routerinfio->ipv6_exit_policy, since that's a port summary. */
+ if ((tor_addr_family(addr) == AF_INET ||
+ tor_addr_family(addr) == AF_INET6)) {
+ return compare_tor_addr_to_addr_policy(addr, port,
+ desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED;
+#if 0
+ } else if (tor_addr_family(addr) == AF_INET6) {
+ return get_options()->IPv6Exit &&
+ desc_routerinfo->ipv6_exit_policy &&
+ compare_tor_addr_to_short_policy(addr, port,
+ desc_routerinfo->ipv6_exit_policy) != ADDR_POLICY_ACCEPTED;
+#endif
+ } else {
return -1;
-
- return compare_tor_addr_to_addr_policy(&conn->_base.addr, conn->_base.port,
- desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED;
+ }
}
/** Return true iff my exit policy is reject *:*. Return -1 if we don't
@@ -1539,13 +1567,14 @@ router_rebuild_descriptor(int force)
ri->cache_info.published_on = time(NULL);
ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
* main thread */
- if (options->BridgeRelay) {
- /* For now, only bridges advertise an ipv6 or-address. And only one. */
+
+ /* For now, at most one IPv6 or-address is being advertised. */
+ {
const port_cfg_t *ipv6_orport = NULL;
SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
if (p->type == CONN_TYPE_OR_LISTENER &&
! p->no_advertise &&
- ! p->ipv4_only &&
+ ! p->bind_ipv4_only &&
tor_addr_family(&p->addr) == AF_INET6) {
if (! tor_addr_is_internal(&p->addr, 0)) {
ipv6_orport = p;
@@ -1565,6 +1594,7 @@ router_rebuild_descriptor(int force)
ri->ipv6_orport = ipv6_orport->port;
}
}
+
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (crypto_pk_get_digest(ri->identity_pkey,
ri->cache_info.identity_digest)<0) {
@@ -1587,11 +1617,20 @@ router_rebuild_descriptor(int force)
policies_exit_policy_append_reject_star(&ri->exit_policy);
} else {
policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
+ options->IPv6Exit,
options->ExitPolicyRejectPrivate,
ri->address, !options->BridgeRelay);
}
ri->policy_is_reject_star =
- policy_is_reject_star(ri->exit_policy);
+ policy_is_reject_star(ri->exit_policy, AF_INET) &&
+ policy_is_reject_star(ri->exit_policy, AF_INET6);
+
+ if (options->IPv6Exit) {
+ char *p_tmp = policy_summarize(ri->exit_policy, AF_INET6);
+ if (p_tmp)
+ ri->ipv6_exit_policy = parse_short_policy(p_tmp);
+ tor_free(p_tmp);
+ }
#if 0
/* XXXX NM NM I belive this is safe to remove */
@@ -1779,7 +1818,7 @@ void
mark_my_descriptor_dirty(const char *reason)
{
const or_options_t *options = get_options();
- if (server_mode(options) && options->_PublishServerDescriptor)
+ if (server_mode(options) && options->PublishServerDescriptor_)
log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason);
desc_clean_since = 0;
if (!desc_dirty_reason)
@@ -1911,7 +1950,7 @@ router_new_address_suggestion(const char *suggestion,
/* Don't believe anybody who says our IP is, say, 127.0.0.1. */
return;
}
- if (tor_addr_eq(&d_conn->_base.addr, &addr)) {
+ if (tor_addr_eq(&d_conn->base_.addr, &addr)) {
/* Don't believe anybody who says our IP is their IP. */
log_debug(LD_DIR, "A directory server told us our IP address is %s, "
"but he's just reporting his own IP address. Ignoring.",
@@ -1927,7 +1966,7 @@ router_new_address_suggestion(const char *suggestion,
"EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
suggestion);
log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr,
- d_conn->_base.address);
+ d_conn->base_.address);
ip_address_changed(0);
tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
will fetch it */
@@ -1984,13 +2023,12 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
size_t onion_pkeylen, identity_pkeylen;
size_t written;
int result=0;
- addr_policy_t *tmpe;
char *family_line;
char *extra_or_address = NULL;
const or_options_t *options = get_options();
/* Make sure the identity key matches the one in the routerinfo. */
- if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) {
+ if (!crypto_pk_eq_keys(ident_key, router->identity_pkey)) {
log_warn(LD_BUG,"Tried to sign a router with a private key that didn't "
"match router's public key!");
return -1;
@@ -2054,9 +2092,9 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
"router %s %s %d 0 %d\n"
"%s"
"platform %s\n"
- "opt protocols Link 1 2 Circuit 1\n"
+ "protocols Link 1 2 Circuit 1\n"
"published %s\n"
- "opt fingerprint %s\n"
+ "fingerprint %s\n"
"uptime %ld\n"
"bandwidth %d %d %d\n"
"%s%s%s%s"
@@ -2075,15 +2113,15 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
(int) router->bandwidthrate,
(int) router->bandwidthburst,
(int) router->bandwidthcapacity,
- has_extra_info_digest ? "opt extra-info-digest " : "",
+ has_extra_info_digest ? "extra-info-digest " : "",
has_extra_info_digest ? extra_info_digest : "",
has_extra_info_digest ? "\n" : "",
- options->DownloadExtraInfo ? "opt caches-extra-info\n" : "",
+ options->DownloadExtraInfo ? "caches-extra-info\n" : "",
onion_pkey, identity_pkey,
family_line,
- we_are_hibernating() ? "opt hibernating 1\n" : "",
- options->HidServDirectoryV2 ? "opt hidden-service-dir\n" : "",
- options->AllowSingleHopExits ? "opt allow-single-hop-exits\n" : "");
+ we_are_hibernating() ? "hibernating 1\n" : "",
+ options->HidServDirectoryV2 ? "hidden-service-dir\n" : "",
+ options->AllowSingleHopExits ? "allow-single-hop-exits\n" : "");
tor_free(family_line);
tor_free(onion_pkey);
@@ -2113,11 +2151,12 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
strlcat(s+written, "reject *:*\n", maxlen-written);
written += strlen("reject *:*\n");
- tmpe = NULL;
} else if (router->exit_policy) {
int i;
for (i = 0; i < smartlist_len(router->exit_policy); ++i) {
- tmpe = smartlist_get(router->exit_policy, i);
+ addr_policy_t *tmpe = smartlist_get(router->exit_policy, i);
+ if (tor_addr_family(&tmpe->addr) == AF_INET6)
+ continue; /* Don't include IPv6 parts of address policy */
result = policy_write_item(s+written, maxlen-written, tmpe, 1);
if (result < 0) {
log_warn(LD_BUG,"descriptor policy_write_item ran out of room!");
@@ -2133,6 +2172,20 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
}
}
+ if (router->ipv6_exit_policy) {
+ char *p6 = write_short_policy(router->ipv6_exit_policy);
+ if (p6 && strcmp(p6, "reject 1-65535")) {
+ result = tor_snprintf(s+written, maxlen-written,
+ "ipv6-policy %s\n", p6);
+ if (result<0) {
+ log_warn(LD_BUG,"Descriptor printf of policy ran out of room");
+ return -1;
+ }
+ written += result;
+ }
+ tor_free(p6);
+ }
+
if (written + DIROBJ_MAX_SIG_LEN > maxlen) {
/* Not enough room for signature. */
log_warn(LD_BUG,"not enough room left in descriptor for signature!");
@@ -2194,40 +2247,24 @@ router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *ap_out)
ap_out->port = router->or_port;
}
-/** Return 1 if we prefer the IPv6 address and OR TCP port of
- * <b>router</b>, else 0.
- *
- * We prefer the IPv6 address if the router has one and
- * i) the routerinfo_t says so
- * or
- * ii) the router has no IPv4 address. */
+/** Return 1 if any of <b>router</b>'s addresses are <b>addr</b>.
+ * Otherwise return 0. */
int
-router_ipv6_preferred(const routerinfo_t *router)
-{
- return (!tor_addr_is_null(&router->ipv6_addr)
- && (router->ipv6_preferred || router->addr == 0));
-}
-
-/** Copy the preferred OR port (IP address and TCP port) for
- * <b>router</b> into *<b>addr_out</b>. */
-void
-router_get_pref_orport(const routerinfo_t *router, tor_addr_port_t *ap_out)
+router_has_addr(const routerinfo_t *router, const tor_addr_t *addr)
{
- if (router_ipv6_preferred(router))
- router_get_pref_ipv6_orport(router, ap_out);
- else
- router_get_prim_orport(router, ap_out);
+ return
+ tor_addr_eq_ipv4h(addr, router->addr) ||
+ tor_addr_eq(&router->ipv6_addr, addr);
}
-/** Copy the preferred IPv6 OR port (IP address and TCP port) for
- * <b>router</b> into *<b>ap_out</b>. */
-void
-router_get_pref_ipv6_orport(const routerinfo_t *router,
- tor_addr_port_t *ap_out)
+int
+router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport)
{
- tor_assert(ap_out != NULL);
- tor_addr_copy(&ap_out->addr, &router->ipv6_addr);
- ap_out->port = router->ipv6_orport;
+ return
+ (tor_addr_eq_ipv4h(&orport->addr, router->addr) &&
+ orport->port == router->or_port) ||
+ (tor_addr_eq(&orport->addr, &router->ipv6_addr) &&
+ orport->port == router->ipv6_orport);
}
/** Load the contents of <b>filename</b>, find the last line starting with
@@ -2312,9 +2349,12 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
tor_free(bandwidth_usage);
smartlist_add(chunks, pre);
- if (geoip_is_loaded()) {
- smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", geoip_db_digest());
- }
+ if (geoip_is_loaded(AF_INET))
+ smartlist_add_asprintf(chunks, "geoip-db-digest %s\n",
+ geoip_db_digest(AF_INET));
+ if (geoip_is_loaded(AF_INET6))
+ smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n",
+ geoip_db_digest(AF_INET6));
if (options->ExtraInfoStatistics && write_stats_to_extrainfo) {
log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");
@@ -2345,6 +2385,13 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
}
}
+ /* Add information about the pluggable transports we support. */
+ if (options->ServerTransportPlugin) {
+ char *pluggable_transports = pt_get_extra_info_descriptor_string();
+ if (pluggable_transports)
+ smartlist_add(chunks, pluggable_transports);
+ }
+
if (should_record_bridge_info(options) && write_stats_to_extrainfo) {
const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
if (bridge_stats) {
@@ -2754,3 +2801,30 @@ router_free_all(void)
}
}
+/** Return a smartlist of tor_addr_port_t's with all the OR ports of
+ <b>ri</b>. Note that freeing of the items in the list as well as
+ the smartlist itself is the callers responsibility.
+
+ XXX duplicating code from node_get_all_orports(). */
+smartlist_t *
+router_get_all_orports(const routerinfo_t *ri)
+{
+ smartlist_t *sl = smartlist_new();
+ tor_assert(ri);
+
+ if (ri->addr != 0) {
+ tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
+ tor_addr_from_ipv4h(&ap->addr, ri->addr);
+ ap->port = ri->or_port;
+ smartlist_add(sl, ap);
+ }
+ if (!tor_addr_is_null(&ri->ipv6_addr)) {
+ tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
+ tor_addr_copy(&ap->addr, &ri->ipv6_addr);
+ ap->port = ri->or_port;
+ smartlist_add(sl, ap);
+ }
+
+ return sl;
+}
+
diff --git a/src/or/router.h b/src/or/router.h
index 69805d6f2d..b641c1cc6a 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -9,8 +9,8 @@
* \brief Header file for router.c.
**/
-#ifndef _TOR_ROUTER_H
-#define _TOR_ROUTER_H
+#ifndef TOR_ROUTER_H
+#define TOR_ROUTER_H
crypto_pk_t *get_onion_key(void);
time_t get_onion_key_set_at(void);
@@ -72,7 +72,7 @@ void check_descriptor_bandwidth_changed(time_t now);
void check_descriptor_ipaddress_changed(time_t now);
void router_new_address_suggestion(const char *suggestion,
const dir_connection_t *d_conn);
-int router_compare_to_my_exit_policy(edge_connection_t *conn);
+int router_compare_to_my_exit_policy(const tor_addr_t *addr, uint16_t port);
int router_my_exit_policy_is_reject_star(void);
const routerinfo_t *router_get_my_routerinfo(void);
extrainfo_t *router_get_my_extrainfo(void);
@@ -93,6 +93,9 @@ void router_get_pref_orport(const routerinfo_t *router,
void router_get_pref_ipv6_orport(const routerinfo_t *router,
tor_addr_port_t *addr_port_out);
int router_ipv6_preferred(const routerinfo_t *router);
+int router_has_addr(const routerinfo_t *router, const tor_addr_t *addr);
+int router_has_orport(const routerinfo_t *router,
+ const tor_addr_port_t *orport);
int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo,
crypto_pk_t *ident_key);
int is_legal_nickname(const char *s);
@@ -132,6 +135,8 @@ void router_free_all(void);
const char *router_purpose_to_string(uint8_t p);
uint8_t router_purpose_from_string(const char *s);
+smartlist_t *router_get_all_orports(const routerinfo_t *ri);
+
#ifdef ROUTER_PRIVATE
/* Used only by router.c and test.c */
void get_platform_str(char *platform, size_t len);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 3c39e362df..5536d1c61b 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -11,14 +11,16 @@
* servers.
**/
+#define ROUTERLIST_PRIVATE
#include "or.h"
-#include "circuitbuild.h"
+#include "circuitstats.h"
#include "config.h"
#include "connection.h"
#include "control.h"
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
@@ -33,6 +35,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
// #define DEBUG_ROUTERLIST
@@ -42,15 +45,16 @@
static const routerstatus_t *router_pick_directory_server_impl(
dirinfo_type_t auth, int flags);
static const routerstatus_t *router_pick_trusteddirserver_impl(
- dirinfo_type_t auth, int flags, int *n_busy_out);
-static void mark_all_trusteddirservers_up(void);
+ const smartlist_t *sourcelist, dirinfo_type_t auth,
+ int flags, int *n_busy_out);
+static const routerstatus_t *router_pick_dirserver_generic(
+ smartlist_t *sourcelist,
+ dirinfo_type_t type, int flags);
+static void mark_all_dirservers_up(smartlist_t *server_list);
static int router_nickname_matches(const routerinfo_t *router,
const char *nickname);
-static int node_nickname_matches(const node_t *router,
- const char *nickname);
-static void trusted_dir_server_free(trusted_dir_server_t *ds);
+static void dir_server_free(dir_server_t *ds);
static int signed_desc_digest_is_recognized(signed_descriptor_t *desc);
-static void update_router_have_minimum_dir_info(void);
static const char *signed_descriptor_get_body_impl(
const signed_descriptor_t *desc,
int with_annotations);
@@ -72,9 +76,12 @@ DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
/****************************************************************************/
-/** Global list of a trusted_dir_server_t object for each trusted directory
- * server. */
+/** Global list of a dir_server_t object for each directory
+ * authority. */
static smartlist_t *trusted_dir_servers = NULL;
+/** Global list of dir_server_t objects for all directory authorities
+ * and all fallback directory servers. */
+static smartlist_t *fallback_dir_servers = NULL;
/** List of for a given authority, and download status for latest certificate.
*/
@@ -119,7 +126,7 @@ get_n_authorities(dirinfo_type_t type)
int n = 0;
if (!trusted_dir_servers)
return 0;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ds,
if (ds->type & type)
++n);
return n;
@@ -190,7 +197,7 @@ int
trusted_dirs_load_certs_from_string(const char *contents, int from_store,
int flush)
{
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
const char *s, *eos;
int failure_code = 0;
@@ -530,7 +537,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
} SMARTLIST_FOREACH_END(sig);
} SMARTLIST_FOREACH_END(voter);
}
- SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, ds) {
+ SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ds) {
int found = 0;
if (!(ds->type & V3_DIRINFO))
continue;
@@ -655,7 +662,7 @@ signed_desc_append_to_journal(signed_descriptor_t *desc,
* signed_descriptor_t* in *<b>a</b> is older, the same age as, or newer than
* the signed_descriptor_t* in *<b>b</b>. */
static int
-_compare_signed_descriptors_by_age(const void **_a, const void **_b)
+compare_signed_descriptors_by_age_(const void **_a, const void **_b)
{
const signed_descriptor_t *r1 = *_a, *r2 = *_b;
return (int)(r1->published_on - r2->published_on);
@@ -728,7 +735,7 @@ router_rebuild_store(int flags, desc_store_t *store)
smartlist_add(signed_descriptors, &ri->cache_info));
}
- smartlist_sort(signed_descriptors, _compare_signed_descriptors_by_age);
+ smartlist_sort(signed_descriptors, compare_signed_descriptors_by_age_);
/* Now, add the appropriate members to chunk_list */
SMARTLIST_FOREACH_BEGIN(signed_descriptors, signed_descriptor_t *, sd) {
@@ -914,11 +921,11 @@ router_reload_router_list(void)
return 0;
}
-/** Return a smartlist containing a list of trusted_dir_server_t * for all
+/** Return a smartlist containing a list of dir_server_t * for all
* known trusted dirservers. Callers must not modify the list or its
* contents.
*/
-smartlist_t *
+const smartlist_t *
router_get_trusted_dir_servers(void)
{
if (!trusted_dir_servers)
@@ -927,6 +934,15 @@ router_get_trusted_dir_servers(void)
return trusted_dir_servers;
}
+const smartlist_t *
+router_get_fallback_dir_servers(void)
+{
+ if (!fallback_dir_servers)
+ fallback_dir_servers = smartlist_new();
+
+ return fallback_dir_servers;
+}
+
/** Try to find a running dirserver that supports operations of <b>type</b>.
*
* If there are no running dirservers in our routerlist and the
@@ -947,7 +963,7 @@ router_pick_directory_server(dirinfo_type_t type, int flags)
{
const routerstatus_t *choice;
if (get_options()->PreferTunneledDirConns)
- flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
+ flags |= PDS_PREFER_TUNNELED_DIR_CONNS_;
if (!routerlist)
return NULL;
@@ -960,7 +976,7 @@ router_pick_directory_server(dirinfo_type_t type, int flags)
"No reachable router entries for dirservers. "
"Trying them all again.");
/* mark all authdirservers as up again */
- mark_all_trusteddirservers_up();
+ mark_all_dirservers_up(fallback_dir_servers);
/* try again */
choice = router_pick_directory_server_impl(type, flags);
return choice;
@@ -995,7 +1011,7 @@ router_get_my_share_of_directory_requests(double *v2_share_out,
}
}
- if (rs->version_supports_v3_dir) {
+ {
sl_last_total_weighted_bw = 0;
router_pick_directory_server(V3_DIRINFO, pds_flags);
if (sl_last_total_weighted_bw != 0) {
@@ -1007,16 +1023,34 @@ router_get_my_share_of_directory_requests(double *v2_share_out,
return 0;
}
-/** Return the trusted_dir_server_t for the directory authority whose identity
+/** Return the dir_server_t for the directory authority whose identity
* key hashes to <b>digest</b>, or NULL if no such authority is known.
*/
-trusted_dir_server_t *
+dir_server_t *
router_get_trusteddirserver_by_digest(const char *digest)
{
if (!trusted_dir_servers)
return NULL;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ds,
+ {
+ if (tor_memeq(ds->digest, digest, DIGEST_LEN))
+ return ds;
+ });
+
+ return NULL;
+}
+
+/** Return the dir_server_t for the fallback dirserver whose identity
+ * key hashes to <b>digest</b>, or NULL if no such authority is known.
+ */
+dir_server_t *
+router_get_fallback_dirserver_by_digest(const char *digest)
+{
+ if (!trusted_dir_servers)
+ return NULL;
+
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ds,
{
if (tor_memeq(ds->digest, digest, DIGEST_LEN))
return ds;
@@ -1025,17 +1059,17 @@ router_get_trusteddirserver_by_digest(const char *digest)
return NULL;
}
-/** Return the trusted_dir_server_t for the directory authority whose
+/** Return the dir_server_t for the directory authority whose
* v3 identity key hashes to <b>digest</b>, or NULL if no such authority
* is known.
*/
-trusted_dir_server_t *
+dir_server_t *
trusteddirserver_get_by_v3_auth_digest(const char *digest)
{
if (!trusted_dir_servers)
return NULL;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ds,
{
if (tor_memeq(ds->v3_identity_digest, digest, DIGEST_LEN) &&
(ds->type & V3_DIRINFO))
@@ -1045,18 +1079,37 @@ trusteddirserver_get_by_v3_auth_digest(const char *digest)
return NULL;
}
-/** Try to find a running trusted dirserver. Flags are as for
+/** Try to find a running directory authority. Flags are as for
* router_pick_directory_server.
*/
const routerstatus_t *
router_pick_trusteddirserver(dirinfo_type_t type, int flags)
{
+ return router_pick_dirserver_generic(trusted_dir_servers, type, flags);
+}
+
+/** Try to find a running fallback directory Flags are as for
+ * router_pick_directory_server.
+ */
+const routerstatus_t *
+router_pick_fallback_dirserver(dirinfo_type_t type, int flags)
+{
+ return router_pick_dirserver_generic(fallback_dir_servers, type, flags);
+}
+
+/** Try to find a running fallback directory Flags are as for
+ * router_pick_directory_server.
+ */
+static const routerstatus_t *
+router_pick_dirserver_generic(smartlist_t *sourcelist,
+ dirinfo_type_t type, int flags)
+{
const routerstatus_t *choice;
int busy = 0;
if (get_options()->PreferTunneledDirConns)
- flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
+ flags |= PDS_PREFER_TUNNELED_DIR_CONNS_;
- choice = router_pick_trusteddirserver_impl(type, flags, &busy);
+ choice = router_pick_trusteddirserver_impl(sourcelist, type, flags, &busy);
if (choice || !(flags & PDS_RETRY_IF_NO_SERVERS))
return choice;
if (busy) {
@@ -1069,9 +1122,9 @@ router_pick_trusteddirserver(dirinfo_type_t type, int flags)
}
log_info(LD_DIR,
- "No trusted dirservers are reachable. Trying them all again.");
- mark_all_trusteddirservers_up();
- return router_pick_trusteddirserver_impl(type, flags, NULL);
+ "No dirservers are reachable. Trying them all again.");
+ mark_all_dirservers_up(sourcelist);
+ return router_pick_trusteddirserver_impl(sourcelist, type, flags, NULL);
}
/** How long do we avoid using a directory server after it's given us a 503? */
@@ -1081,7 +1134,7 @@ router_pick_trusteddirserver(dirinfo_type_t type, int flags)
* routerlist. Arguments are as for router_pick_directory_server(), except
* that RETRY_IF_NO_SERVERS is ignored, and:
*
- * If the _PDS_PREFER_TUNNELED_DIR_CONNS flag is set, prefer directory servers
+ * If the PDS_PREFER_TUNNELED_DIR_CONNS_ flag is set, prefer directory servers
* that we can use with BEGINDIR.
*/
static const routerstatus_t *
@@ -1096,7 +1149,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
const networkstatus_t *consensus = networkstatus_get_latest_consensus();
int requireother = ! (flags & PDS_ALLOW_SELF);
int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
- int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
+ int prefer_tunnel = (flags & PDS_PREFER_TUNNELED_DIR_CONNS_);
int try_excluding = 1, n_excluded = 0;
if (!consensus)
@@ -1127,12 +1180,6 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
continue;
if (requireother && router_digest_is_me(node->identity))
continue;
- if (type & V3_DIRINFO) {
- if (!(status->version_supports_v3_dir ||
- router_digest_is_trusted_dir_type(node->identity,
- V3_DIRINFO)))
- continue;
- }
is_trusted = router_digest_is_trusted_dir(node->identity);
if ((type & V2_DIRINFO) && !(node->rs->is_v2_dir || is_trusted))
continue;
@@ -1155,7 +1202,6 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
if (prefer_tunnel &&
- status->version_supports_begindir &&
(!fascistfirewall ||
fascist_firewall_allows_address_or(&addr, status->or_port)))
smartlist_add(is_trusted ? trusted_tunnel :
@@ -1203,11 +1249,36 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
return result ? result->rs : NULL;
}
-/** Choose randomly from among the trusted dirservers that are up. Flags
- * are as for router_pick_directory_server_impl().
+/** Pick a random element from a list of dir_server_t, weighting by their
+ * <b>weight</b> field. */
+static const dir_server_t *
+dirserver_choose_by_weight(const smartlist_t *servers, double authority_weight)
+{
+ int n = smartlist_len(servers);
+ int i;
+ u64_dbl_t *weights;
+ const dir_server_t *ds;
+
+ weights = tor_malloc(sizeof(u64_dbl_t) * n);
+ for (i = 0; i < n; ++i) {
+ ds = smartlist_get(servers, i);
+ weights[i].dbl = ds->weight;
+ if (ds->is_authority)
+ weights[i].dbl *= authority_weight;
+ }
+
+ scale_array_elements_to_u64(weights, n, NULL);
+ i = choose_array_element_by_weight(weights, n);
+ tor_free(weights);
+ return smartlist_get(servers, i);
+}
+
+/** Choose randomly from among the dir_server_ts in sourcelist that
+ * are up. Flags are as for router_pick_directory_server_impl().
*/
static const routerstatus_t *
-router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
+router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
+ dirinfo_type_t type, int flags,
int *n_busy_out)
{
const or_options_t *options = get_options();
@@ -1218,13 +1289,16 @@ router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
time_t now = time(NULL);
const int requireother = ! (flags & PDS_ALLOW_SELF);
const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
- const int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
+ const int prefer_tunnel = (flags & PDS_PREFER_TUNNELED_DIR_CONNS_);
const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH);
const int no_microdesc_fetching =(flags & PDS_NO_EXISTING_MICRODESC_FETCH);
+ const double auth_weight = (sourcelist == fallback_dir_servers) ?
+ options->DirAuthorityFallbackRate : 1.0;
+ smartlist_t *pick_from;
int n_busy = 0;
int try_excluding = 1, n_excluded = 0;
- if (!trusted_dir_servers)
+ if (!sourcelist)
return NULL;
retry_without_exclude:
@@ -1234,7 +1308,7 @@ router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, d)
+ SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d)
{
int is_overloaded =
d->fake_status.last_dir_503_at + DIR_503_TIMEOUT > now;
@@ -1280,23 +1354,29 @@ router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
d->or_port &&
(!fascistfirewall ||
fascist_firewall_allows_address_or(&addr, d->or_port)))
- smartlist_add(is_overloaded ? overloaded_tunnel : tunnel,
- &d->fake_status);
+ smartlist_add(is_overloaded ? overloaded_tunnel : tunnel, (void*)d);
else if (!fascistfirewall ||
fascist_firewall_allows_address_dir(&addr, d->dir_port))
- smartlist_add(is_overloaded ? overloaded_direct : direct,
- &d->fake_status);
+ smartlist_add(is_overloaded ? overloaded_direct : direct, (void*)d);
}
SMARTLIST_FOREACH_END(d);
if (smartlist_len(tunnel)) {
- result = smartlist_choose(tunnel);
+ pick_from = tunnel;
} else if (smartlist_len(overloaded_tunnel)) {
- result = smartlist_choose(overloaded_tunnel);
+ pick_from = overloaded_tunnel;
} else if (smartlist_len(direct)) {
- result = smartlist_choose(direct);
+ pick_from = direct;
} else {
- result = smartlist_choose(overloaded_direct);
+ pick_from = overloaded_direct;
+ }
+
+ {
+ const dir_server_t *selection =
+ dirserver_choose_by_weight(pick_from, auth_weight);
+
+ if (selection)
+ result = &selection->fake_status;
}
if (n_busy_out)
@@ -1318,19 +1398,19 @@ router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
return result;
}
-/** Go through and mark the authoritative dirservers as up. */
+/** Mark as running every dir_server_t in <b>server_list</b>. */
static void
-mark_all_trusteddirservers_up(void)
+mark_all_dirservers_up(smartlist_t *server_list)
{
- SMARTLIST_FOREACH(nodelist_get_list(), node_t *, node, {
- if (router_digest_is_trusted_dir(node->identity))
- node->is_running = 1;
- });
- if (trusted_dir_servers) {
- SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, dir) {
+ if (server_list) {
+ SMARTLIST_FOREACH_BEGIN(server_list, dir_server_t *, dir) {
routerstatus_t *rs;
+ node_t *node;
dir->is_running = 1;
download_status_reset(&dir->v2_ns_dl_status);
+ node = node_get_mutable_by_id(dir->digest);
+ if (node)
+ node->is_running = 1;
rs = router_get_mutable_consensus_status_by_id(dir->digest);
if (rs) {
rs->last_dir_503_at = 0;
@@ -1343,9 +1423,11 @@ mark_all_trusteddirservers_up(void)
/** Return true iff r1 and r2 have the same address and OR port. */
int
-routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2)
+routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2)
{
- return r1->addr == r2->addr && r1->or_port == r2->or_port;
+ return r1->addr == r2->addr && r1->or_port == r2->or_port &&
+ tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) &&
+ r1->ipv6_orport == r2->ipv6_orport;
}
/** Reset all internal variables used to count failed downloads of network
@@ -1353,89 +1435,7 @@ routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2)
void
router_reset_status_download_failures(void)
{
- mark_all_trusteddirservers_up();
-}
-
-/** Return true iff router1 and router2 have similar enough network addresses
- * that we should treat them as being in the same family */
-static INLINE int
-addrs_in_same_network_family(const tor_addr_t *a1,
- const tor_addr_t *a2)
-{
- /* XXXX MOVE ? */
- return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC);
-}
-
-/**
- * Add all the family of <b>node</b>, including <b>node</b> itself, to
- * the smartlist <b>sl</b>.
- *
- * This is used to make sure we don't pick siblings in a single path, or
- * pick more than one relay from a family for our entry guard list.
- * Note that a node may be added to <b>sl</b> more than once if it is
- * part of <b>node</b>'s family for more than one reason.
- */
-void
-nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
-{
- /* XXXX MOVE */
- const smartlist_t *all_nodes = nodelist_get_list();
- const smartlist_t *declared_family;
- const or_options_t *options = get_options();
-
- tor_assert(node);
-
- declared_family = node_get_declared_family(node);
-
- /* Let's make sure that we have the node itself, if it's a real node. */
- {
- const node_t *real_node = node_get_by_id(node->identity);
- if (real_node)
- smartlist_add(sl, (node_t*)real_node);
- }
-
- /* First, add any nodes with similar network addresses. */
- if (options->EnforceDistinctSubnets) {
- tor_addr_t node_addr;
- node_get_addr(node, &node_addr);
-
- SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) {
- tor_addr_t a;
- node_get_addr(node2, &a);
- if (addrs_in_same_network_family(&a, &node_addr))
- smartlist_add(sl, (void*)node2);
- } SMARTLIST_FOREACH_END(node2);
- }
-
- /* Now, add all nodes in the declared_family of this node, if they
- * also declare this node to be in their family. */
- if (declared_family) {
- /* Add every r such that router declares familyness with node, and node
- * declares familyhood with router. */
- SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) {
- const node_t *node2;
- const smartlist_t *family2;
- if (!(node2 = node_get_by_nickname(name, 0)))
- continue;
- if (!(family2 = node_get_declared_family(node2)))
- continue;
- SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) {
- if (node_nickname_matches(node, name2)) {
- smartlist_add(sl, (void*)node2);
- break;
- }
- } SMARTLIST_FOREACH_END(name2);
- } SMARTLIST_FOREACH_END(name);
- }
-
- /* If the user declared any families locally, honor those too. */
- if (options->NodeFamilySets) {
- SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
- if (routerset_contains_node(rs, node)) {
- routerset_get_all_nodes(sl, rs, NULL, 0);
- }
- });
- }
+ mark_all_dirservers_up(fallback_dir_servers);
}
/** Given a <b>router</b>, add every node_t in its family (including the
@@ -1459,59 +1459,6 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router)
nodelist_add_node_and_family(sl, node);
}
-/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */
-static INLINE int
-node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
-{
- /* XXXX MOVE */
- if (!lst) return 0;
- SMARTLIST_FOREACH(lst, const char *, name, {
- if (node_nickname_matches(node, name))
- return 1;
- });
- return 0;
-}
-
-/** Return true iff r1 and r2 are in the same family, but not the same
- * router. */
-int
-nodes_in_same_family(const node_t *node1, const node_t *node2)
-{
- /* XXXX MOVE */
- const or_options_t *options = get_options();
-
- /* Are they in the same family because of their addresses? */
- if (options->EnforceDistinctSubnets) {
- tor_addr_t a1, a2;
- node_get_addr(node1, &a1);
- node_get_addr(node2, &a2);
- if (addrs_in_same_network_family(&a1, &a2))
- return 1;
- }
-
- /* Are they in the same family because the agree they are? */
- {
- const smartlist_t *f1, *f2;
- f1 = node_get_declared_family(node1);
- f2 = node_get_declared_family(node2);
- if (f1 && f2 &&
- node_in_nickname_smartlist(f1, node2) &&
- node_in_nickname_smartlist(f2, node1))
- return 1;
- }
-
- /* Are they in the same option because the user says they are? */
- if (options->NodeFamilySets) {
- SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
- if (routerset_contains_node(rs, node1) &&
- routerset_contains_node(rs, node2))
- return 1;
- });
- }
-
- return 0;
-}
-
/** Return 1 iff any member of the (possibly NULL) comma-separated list
* <b>list</b> is an acceptable nickname or hexdigest for <b>router</b>. Else
* return 0.
@@ -1575,56 +1522,6 @@ routerlist_find_my_routerinfo(void)
return NULL;
}
-/** Find a router that's up, that has this IP address, and
- * that allows exit to this address:port, or return NULL if there
- * isn't a good one.
- * Don't exit enclave to excluded relays -- it wouldn't actually
- * hurt anything, but this way there are fewer confused users.
- */
-const node_t *
-router_find_exact_exit_enclave(const char *address, uint16_t port)
-{/*XXXX MOVE*/
- uint32_t addr;
- struct in_addr in;
- tor_addr_t a;
- const or_options_t *options = get_options();
-
- if (!tor_inet_aton(address, &in))
- return NULL; /* it's not an IP already */
- addr = ntohl(in.s_addr);
-
- tor_addr_from_ipv4h(&a, addr);
-
- SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
- if (node_get_addr_ipv4h(node) == addr &&
- node->is_running &&
- compare_tor_addr_to_node_policy(&a, port, node) ==
- ADDR_POLICY_ACCEPTED &&
- !routerset_contains_node(options->_ExcludeExitNodesUnion, node))
- return node;
- });
- return NULL;
-}
-
-/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
- * If <b>need_uptime</b> is non-zero, we require a minimum uptime.
- * If <b>need_capacity</b> is non-zero, we require a minimum advertised
- * bandwidth.
- * If <b>need_guard</b>, we require that the router is a possible entry guard.
- */
-int
-node_is_unreliable(const node_t *node, int need_uptime,
- int need_capacity, int need_guard)
-{
- if (need_uptime && !node->is_stable)
- return 1;
- if (need_capacity && !node->is_fast)
- return 1;
- if (need_guard && !node->is_possible_guard)
- return 1;
- return 0;
-}
-
/** Return the smaller of the router's configured BandwidthRate
* and its advertised capacity. */
uint32_t
@@ -1652,6 +1549,92 @@ router_get_advertised_bandwidth_capped(const routerinfo_t *router)
return result;
}
+/** Given an array of double/uint64_t unions that are currently being used as
+ * doubles, convert them to uint64_t, and try to scale them linearly so as to
+ * much of the range of uint64_t. If <b>total_out</b> is provided, set it to
+ * the sum of all elements in the array _before_ scaling. */
+/* private */ void
+scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
+ uint64_t *total_out)
+{
+ double total = 0.0;
+ double scale_factor;
+ int i;
+ /* big, but far away from overflowing an int64_t */
+#define SCALE_TO_U64_MAX (INT64_MAX / 4)
+
+ for (i = 0; i < n_entries; ++i)
+ total += entries[i].dbl;
+
+ scale_factor = SCALE_TO_U64_MAX / total;
+
+ for (i = 0; i < n_entries; ++i)
+ entries[i].u64 = tor_llround(entries[i].dbl * scale_factor);
+
+ if (total_out)
+ *total_out = (uint64_t) total;
+
+#undef SCALE_TO_U64_MAX
+}
+
+/** Time-invariant 64-bit greater-than; works on two integers in the range
+ * (0,INT64_MAX). */
+#if SIZEOF_VOID_P == 8
+#define gt_i64_timei(a,b) ((a) > (b))
+#else
+static INLINE int
+gt_i64_timei(uint64_t a, uint64_t b)
+{
+ int64_t diff = (int64_t) (b - a);
+ int res = diff >> 63;
+ return res & 1;
+}
+#endif
+
+/** Pick a random element of <b>n_entries</b>-element array <b>entries</b>,
+ * choosing each element with a probability proportional to its (uint64_t)
+ * value, and return the index of that element. If all elements are 0, choose
+ * an index at random. Return -1 on error.
+ */
+/* private */ int
+choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries)
+{
+ int i, i_chosen=-1, n_chosen=0;
+ uint64_t total_so_far = 0;
+ uint64_t rand_val;
+ uint64_t total = 0;
+
+ for (i = 0; i < n_entries; ++i)
+ total += entries[i].u64;
+
+ if (n_entries < 1)
+ return -1;
+
+ if (total == 0)
+ return crypto_rand_int(n_entries);
+
+ tor_assert(total < INT64_MAX);
+
+ rand_val = crypto_rand_uint64(total);
+
+ for (i = 0; i < n_entries; ++i) {
+ total_so_far += entries[i].u64;
+ if (gt_i64_timei(total_so_far, rand_val)) {
+ i_chosen = i;
+ n_chosen++;
+ /* Set rand_val to INT64_MAX rather than stopping the loop. This way,
+ * the time we spend in the loop does not leak which element we chose. */
+ rand_val = INT64_MAX;
+ }
+ }
+ tor_assert(total_so_far == total);
+ tor_assert(n_chosen == 1);
+ tor_assert(i_chosen >= 0);
+ tor_assert(i_chosen < n_entries);
+
+ return i_chosen;
+}
+
/** When weighting bridges, enforce these values as lower and upper
* bound for believable bandwidth, because there is no way for us
* to verify a bridge's bandwidth currently. */
@@ -1702,16 +1685,10 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
bandwidth_weight_rule_t rule)
{
int64_t weight_scale;
- int64_t rand_bw;
double Wg = -1, Wm = -1, We = -1, Wd = -1;
double Wgb = -1, Wmb = -1, Web = -1, Wdb = -1;
- double weighted_bw = 0, unweighted_bw = 0;
- double *bandwidths;
- double tmp = 0;
- unsigned int i;
- unsigned int i_chosen;
- unsigned int i_has_been_chosen;
- int have_unknown = 0; /* true iff sl contains element not in consensus. */
+ uint64_t weighted_bw = 0;
+ u64_dbl_t *bandwidths;
/* Can't choose exit and guard at same time */
tor_assert(rule == NO_WEIGHTING ||
@@ -1792,7 +1769,7 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
Web /= weight_scale;
Wdb /= weight_scale;
- bandwidths = tor_malloc_zero(sizeof(double)*smartlist_len(sl));
+ bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl));
// Cycle through smartlist and total the bandwidth.
SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
@@ -1815,7 +1792,6 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
} else if (node->ri) {
/* bridge or other descriptor not in our consensus */
this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
- have_unknown = 1;
} else {
/* We can't use this one. */
continue;
@@ -1831,72 +1807,32 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
} else { // middle
weight = (is_dir ? Wmb*Wm : Wm);
}
-
- bandwidths[node_sl_idx] = weight*this_bw;
- weighted_bw += weight*this_bw;
- unweighted_bw += this_bw;
+ /* These should be impossible; but overflows here would be bad, so let's
+ * make sure. */
+ if (this_bw < 0)
+ this_bw = 0;
+ if (weight < 0.0)
+ weight = 0.0;
+
+ bandwidths[node_sl_idx].dbl = weight*this_bw + 0.5;
if (is_me)
- sl_last_weighted_bw_of_me = weight*this_bw;
+ sl_last_weighted_bw_of_me = (uint64_t) bandwidths[node_sl_idx].dbl;
} SMARTLIST_FOREACH_END(node);
- /* XXXX this is a kludge to expose these values. */
- sl_last_total_weighted_bw = weighted_bw;
-
log_debug(LD_CIRC, "Choosing node for rule %s based on weights "
- "Wg=%f Wm=%f We=%f Wd=%f with total bw %f",
+ "Wg=%f Wm=%f We=%f Wd=%f with total bw "U64_FORMAT,
bandwidth_weight_rule_to_string(rule),
- Wg, Wm, We, Wd, weighted_bw);
-
- /* If there is no bandwidth, choose at random */
- if (DBL_TO_U64(weighted_bw) == 0) {
- /* Don't warn when using bridges/relays not in the consensus */
- if (!have_unknown) {
-#define ZERO_BANDWIDTH_WARNING_INTERVAL (15)
- static ratelim_t zero_bandwidth_warning_limit =
- RATELIM_INIT(ZERO_BANDWIDTH_WARNING_INTERVAL);
- char *msg;
- if ((msg = rate_limit_log(&zero_bandwidth_warning_limit,
- approx_time()))) {
- log_warn(LD_CIRC,
- "Weighted bandwidth is %f in node selection for rule %s "
- "(unweighted was %f) %s",
- weighted_bw, bandwidth_weight_rule_to_string(rule),
- unweighted_bw, msg);
- }
- }
- tor_free(bandwidths);
- return smartlist_choose(sl);
- }
+ Wg, Wm, We, Wd, U64_PRINTF_ARG(weighted_bw));
- rand_bw = crypto_rand_uint64(DBL_TO_U64(weighted_bw));
- rand_bw++; /* crypto_rand_uint64() counts from 0, and we need to count
- * from 1 below. See bug 1203 for details. */
-
- /* Last, count through sl until we get to the element we picked */
- i_chosen = (unsigned)smartlist_len(sl);
- i_has_been_chosen = 0;
- tmp = 0.0;
- for (i=0; i < (unsigned)smartlist_len(sl); i++) {
- tmp += bandwidths[i];
- if (tmp >= rand_bw && !i_has_been_chosen) {
- i_chosen = i;
- i_has_been_chosen = 1;
- }
- }
- i = i_chosen;
-
- if (i == (unsigned)smartlist_len(sl)) {
- /* This was once possible due to round-off error, but shouldn't be able
- * to occur any longer. */
- tor_fragile_assert();
- --i;
- log_warn(LD_BUG, "Round-off error in computing bandwidth had an effect on "
- " which router we chose. Please tell the developers. "
- "%f " U64_FORMAT " %f", tmp, U64_PRINTF_ARG(rand_bw),
- weighted_bw);
+ scale_array_elements_to_u64(bandwidths, smartlist_len(sl),
+ &sl_last_total_weighted_bw);
+
+ {
+ int idx = choose_array_element_by_weight(bandwidths,
+ smartlist_len(sl));
+ tor_free(bandwidths);
+ return idx < 0 ? NULL : smartlist_get(sl, idx);
}
- tor_free(bandwidths);
- return smartlist_get(sl, i);
}
/** Helper function:
@@ -1917,17 +1853,16 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
bandwidth_weight_rule_t rule)
{
unsigned int i;
- unsigned int i_chosen;
- unsigned int i_has_been_chosen;
- int32_t *bandwidths;
+ u64_dbl_t *bandwidths;
int is_exit;
int is_guard;
- uint64_t total_nonexit_bw = 0, total_exit_bw = 0, total_bw = 0;
- uint64_t total_nonguard_bw = 0, total_guard_bw = 0;
- uint64_t rand_bw, tmp;
+ int is_fast;
+ double total_nonexit_bw = 0, total_exit_bw = 0;
+ double total_nonguard_bw = 0, total_guard_bw = 0;
double exit_weight;
double guard_weight;
int n_unknown = 0;
+ bitarray_t *fast_bits;
bitarray_t *exit_bits;
bitarray_t *guard_bits;
int me_idx = -1;
@@ -1951,10 +1886,9 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
}
/* First count the total bandwidth weight, and make a list
- * of each value. <0 means "unknown; no routerinfo." We use the
- * bits of negative values to remember whether the router was fast (-x)&1
- * and whether it was an exit (-x)&2 or guard (-x)&4. Yes, it's a hack. */
- bandwidths = tor_malloc(sizeof(int32_t)*smartlist_len(sl));
+ * of each value. We use UINT64_MAX to indicate "unknown". */
+ bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl));
+ fast_bits = bitarray_init_zero(smartlist_len(sl));
exit_bits = bitarray_init_zero(smartlist_len(sl));
guard_bits = bitarray_init_zero(smartlist_len(sl));
@@ -1962,7 +1896,6 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
/* first, learn what bandwidth we think i has */
int is_known = 1;
- int32_t flags = 0;
uint32_t this_bw = 0;
i = node_sl_idx;
@@ -1975,12 +1908,7 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
if (node->rs->has_bandwidth) {
this_bw = kb_to_bytes(node->rs->bandwidth);
} else { /* guess */
- /* XXX024 once consensuses always list bandwidths, we can take
- * this guessing business out. -RD */
is_known = 0;
- flags = node->rs->is_fast ? 1 : 0;
- flags |= is_exit ? 2 : 0;
- flags |= is_guard ? 4 : 0;
}
} else if (node->ri) {
/* Must be a bridge if we're willing to use it */
@@ -1991,12 +1919,11 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
bitarray_set(exit_bits, i);
if (is_guard)
bitarray_set(guard_bits, i);
+ if (node->is_fast)
+ bitarray_set(fast_bits, i);
+
if (is_known) {
- bandwidths[i] = (int32_t) this_bw;
- /* Casting this_bw to int32_t is safe because both kb_to_bytes
- and bridge_get_advertised_bandwidth_bounded limit it to below
- INT32_MAX. */
- tor_assert(bandwidths[i] >= 0);
+ bandwidths[i].dbl = this_bw;
if (is_guard)
total_guard_bw += this_bw;
else
@@ -2007,14 +1934,16 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
total_nonexit_bw += this_bw;
} else {
++n_unknown;
- bandwidths[node_sl_idx] = -flags;
+ bandwidths[i].dbl = -1.0;
}
} SMARTLIST_FOREACH_END(node);
+#define EPSILON .1
+
/* Now, fill in the unknown values. */
if (n_unknown) {
int32_t avg_fast, avg_slow;
- if (total_exit_bw+total_nonexit_bw) {
+ if (total_exit_bw+total_nonexit_bw < EPSILON) {
/* if there's some bandwidth, there's at least one known router,
* so no worries about div by 0 here */
int n_known = smartlist_len(sl)-n_unknown;
@@ -2025,26 +1954,27 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
avg_slow = 20000;
}
for (i=0; i<(unsigned)smartlist_len(sl); ++i) {
- int32_t bw = bandwidths[i];
- if (bw>=0)
+ if (bandwidths[i].dbl >= 0.0)
continue;
- is_exit = ((-bw)&2);
- is_guard = ((-bw)&4);
- bandwidths[i] = ((-bw)&1) ? avg_fast : avg_slow;
+ is_fast = bitarray_is_set(fast_bits, i);
+ is_exit = bitarray_is_set(exit_bits, i);
+ is_guard = bitarray_is_set(guard_bits, i);
+ bandwidths[i].dbl = is_fast ? avg_fast : avg_slow;
if (is_exit)
- total_exit_bw += bandwidths[i];
+ total_exit_bw += bandwidths[i].dbl;
else
- total_nonexit_bw += bandwidths[i];
+ total_nonexit_bw += bandwidths[i].dbl;
if (is_guard)
- total_guard_bw += bandwidths[i];
+ total_guard_bw += bandwidths[i].dbl;
else
- total_nonguard_bw += bandwidths[i];
+ total_nonguard_bw += bandwidths[i].dbl;
}
}
/* If there's no bandwidth at all, pick at random. */
- if (!(total_exit_bw+total_nonexit_bw)) {
+ if (total_exit_bw+total_nonexit_bw < EPSILON) {
tor_free(bandwidths);
+ tor_free(fast_bits);
tor_free(exit_bits);
tor_free(guard_bits);
return smartlist_choose(sl);
@@ -2059,12 +1989,12 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
* For detailed derivation of this formula, see
* http://archives.seul.org/or/dev/Jul-2007/msg00056.html
*/
- if (rule == WEIGHT_FOR_EXIT || !total_exit_bw)
+ if (rule == WEIGHT_FOR_EXIT || total_exit_bw<EPSILON)
exit_weight = 1.0;
else
exit_weight = 1.0 - all_bw/(3.0*exit_bw);
- if (rule == WEIGHT_FOR_GUARD || !total_guard_bw)
+ if (rule == WEIGHT_FOR_GUARD || total_guard_bw<EPSILON)
guard_weight = 1.0;
else
guard_weight = 1.0 - all_bw/(3.0*guard_bw);
@@ -2075,29 +2005,25 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
if (guard_weight <= 0.0)
guard_weight = 0.0;
- total_bw = 0;
sl_last_weighted_bw_of_me = 0;
for (i=0; i < (unsigned)smartlist_len(sl); i++) {
- uint64_t bw;
+ tor_assert(bandwidths[i].dbl >= 0.0);
+
is_exit = bitarray_is_set(exit_bits, i);
is_guard = bitarray_is_set(guard_bits, i);
if (is_exit && is_guard)
- bw = ((uint64_t)(bandwidths[i] * exit_weight * guard_weight));
+ bandwidths[i].dbl *= exit_weight * guard_weight;
else if (is_guard)
- bw = ((uint64_t)(bandwidths[i] * guard_weight));
+ bandwidths[i].dbl *= guard_weight;
else if (is_exit)
- bw = ((uint64_t)(bandwidths[i] * exit_weight));
- else
- bw = bandwidths[i];
- total_bw += bw;
+ bandwidths[i].dbl *= exit_weight;
+
if (i == (unsigned) me_idx)
- sl_last_weighted_bw_of_me = bw;
+ sl_last_weighted_bw_of_me = (uint64_t) bandwidths[i].dbl;
}
}
- /* XXXX this is a kludge to expose these values. */
- sl_last_total_weighted_bw = total_bw;
-
+#if 0
log_debug(LD_CIRC, "Total weighted bw = "U64_FORMAT
", exit bw = "U64_FORMAT
", nonexit bw = "U64_FORMAT", exit weight = %f "
@@ -2110,50 +2036,20 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
exit_weight, (int)(rule == WEIGHT_FOR_EXIT),
U64_PRINTF_ARG(total_guard_bw), U64_PRINTF_ARG(total_nonguard_bw),
guard_weight, (int)(rule == WEIGHT_FOR_GUARD));
+#endif
- /* Almost done: choose a random value from the bandwidth weights. */
- rand_bw = crypto_rand_uint64(total_bw);
- rand_bw++; /* crypto_rand_uint64() counts from 0, and we need to count
- * from 1 below. See bug 1203 for details. */
-
- /* Last, count through sl until we get to the element we picked */
- tmp = 0;
- i_chosen = (unsigned)smartlist_len(sl);
- i_has_been_chosen = 0;
- for (i=0; i < (unsigned)smartlist_len(sl); i++) {
- is_exit = bitarray_is_set(exit_bits, i);
- is_guard = bitarray_is_set(guard_bits, i);
-
- /* Weights can be 0 if not counting guards/exits */
- if (is_exit && is_guard)
- tmp += ((uint64_t)(bandwidths[i] * exit_weight * guard_weight));
- else if (is_guard)
- tmp += ((uint64_t)(bandwidths[i] * guard_weight));
- else if (is_exit)
- tmp += ((uint64_t)(bandwidths[i] * exit_weight));
- else
- tmp += bandwidths[i];
+ scale_array_elements_to_u64(bandwidths, smartlist_len(sl),
+ &sl_last_total_weighted_bw);
- if (tmp >= rand_bw && !i_has_been_chosen) {
- i_chosen = i;
- i_has_been_chosen = 1;
- }
- }
- i = i_chosen;
- if (i == (unsigned)smartlist_len(sl)) {
- /* This was once possible due to round-off error, but shouldn't be able
- * to occur any longer. */
- tor_fragile_assert();
- --i;
- log_warn(LD_BUG, "Round-off error in computing bandwidth had an effect on "
- " which router we chose. Please tell the developers. "
- U64_FORMAT " " U64_FORMAT " " U64_FORMAT, U64_PRINTF_ARG(tmp),
- U64_PRINTF_ARG(rand_bw), U64_PRINTF_ARG(total_bw));
+ {
+ int idx = choose_array_element_by_weight(bandwidths,
+ smartlist_len(sl));
+ tor_free(bandwidths);
+ tor_free(fast_bits);
+ tor_free(exit_bits);
+ tor_free(guard_bits);
+ return idx < 0 ? NULL : smartlist_get(sl, idx);
}
- tor_free(bandwidths);
- tor_free(exit_bits);
- tor_free(guard_bits);
- return smartlist_get(sl, i);
}
/** Choose a random element of status list <b>sl</b>, weighted by
@@ -2306,7 +2202,7 @@ hex_digest_nickname_decode(const char *hexdigest,
* combination of a router, encoded in hexadecimal, matches <b>hexdigest</b>
* (which is optionally prefixed with a single dollar sign). Return false if
* <b>hexdigest</b> is malformed, or it doesn't match. */
-static int
+int
hex_digest_nickname_matches(const char *hexdigest, const char *identity_digest,
const char *nickname, int is_named)
{
@@ -2366,129 +2262,6 @@ router_nickname_matches(const routerinfo_t *router, const char *nickname)
return router_hex_digest_matches(router, nickname);
}
-/** Return true if <b>node</b>'s nickname matches <b>nickname</b>
- * (case-insensitive), or if <b>node's</b> identity key digest
- * matches a hexadecimal value stored in <b>nickname</b>. Return
- * false otherwise. */
-static int
-node_nickname_matches(const node_t *node, const char *nickname)
-{
- const char *n = node_get_nickname(node);
- if (n && nickname[0]!='$' && !strcasecmp(n, nickname))
- return 1;
- return hex_digest_nickname_matches(nickname,
- node->identity,
- n,
- node_is_named(node));
-}
-
-/** Return the router in our routerlist whose (case-insensitive)
- * nickname or (case-sensitive) hexadecimal key digest is
- * <b>nickname</b>. Return NULL if no such router is known.
- */
-const routerinfo_t *
-router_get_by_nickname(const char *nickname, int warn_if_unnamed)
-{
-#if 1
- const node_t *node = node_get_by_nickname(nickname, warn_if_unnamed);
- if (node)
- return node->ri;
- else
- return NULL;
-#else
- int maybedigest;
- char digest[DIGEST_LEN];
- routerinfo_t *best_match=NULL;
- int n_matches = 0;
- const char *named_digest = NULL;
-
- tor_assert(nickname);
- if (!routerlist)
- return NULL;
- if (nickname[0] == '$')
- return router_get_by_hexdigest(nickname);
- if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME))
- return NULL;
-
- maybedigest = (strlen(nickname) >= HEX_DIGEST_LEN) &&
- (base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0);
-
- if ((named_digest = networkstatus_get_router_digest_by_nickname(nickname))) {
- return rimap_get(routerlist->identity_map, named_digest);
- }
- if (networkstatus_nickname_is_unnamed(nickname))
- return NULL;
-
- /* If we reach this point, there's no canonical value for the nickname. */
-
- SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
- {
- if (!strcasecmp(router->nickname, nickname)) {
- ++n_matches;
- if (n_matches <= 1 || router->is_running)
- best_match = router;
- } else if (maybedigest &&
- tor_memeq(digest, router->cache_info.identity_digest,
- DIGEST_LEN)) {
- if (router_hex_digest_matches(router, nickname))
- return router;
- /* If we reach this point, we have a ID=name syntax that matches the
- * identity but not the name. That isn't an acceptable match. */
- }
- });
-
- if (best_match) {
- if (warn_if_unnamed && n_matches > 1) {
- smartlist_t *fps = smartlist_new();
- int any_unwarned = 0;
- SMARTLIST_FOREACH_BEGIN(routerlist->routers, routerinfo_t *, router) {
- routerstatus_t *rs;
- char fp[HEX_DIGEST_LEN+1];
- if (strcasecmp(router->nickname, nickname))
- continue;
- rs = router_get_mutable_consensus_status_by_id(
- router->cache_info.identity_digest);
- if (rs && !rs->name_lookup_warned) {
- rs->name_lookup_warned = 1;
- any_unwarned = 1;
- }
- base16_encode(fp, sizeof(fp),
- router->cache_info.identity_digest, DIGEST_LEN);
- smartlist_add_asprintf(fps, "\"$%s\" for the one at %s:%d",
- fp, router->address, router->or_port);
- } SMARTLIST_FOREACH_END(router);
- if (any_unwarned) {
- char *alternatives = smartlist_join_strings(fps, "; ",0,NULL);
- log_warn(LD_CONFIG,
- "There are multiple matches for the nickname \"%s\","
- " but none is listed as named by the directory authorities. "
- "Choosing one arbitrarily. If you meant one in particular, "
- "you should say %s.", nickname, alternatives);
- tor_free(alternatives);
- }
- SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
- smartlist_free(fps);
- } else if (warn_if_unnamed) {
- routerstatus_t *rs = router_get_mutable_consensus_status_by_id(
- best_match->cache_info.identity_digest);
- if (rs && !rs->name_lookup_warned) {
- char fp[HEX_DIGEST_LEN+1];
- base16_encode(fp, sizeof(fp),
- best_match->cache_info.identity_digest, DIGEST_LEN);
- log_warn(LD_CONFIG, "You specified a server \"%s\" by name, but this "
- "name is not registered, so it could be used by any server, "
- "not just the one you meant. "
- "To make sure you get the same server in the future, refer to "
- "it by key, as \"$%s\".", nickname, fp);
- rs->name_lookup_warned = 1;
- }
- }
- return best_match;
- }
- return NULL;
-#endif
-}
-
/** Return true iff <b>digest</b> is the digest of the identity key of a
* trusted directory matching at least one bit of <b>type</b>. If <b>type</b>
* is zero, any authority is okay. */
@@ -2499,7 +2272,7 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
return 0;
if (authdir_mode(get_options()) && router_digest_is_me(digest))
return 1;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ent,
if (tor_memeq(digest, ent->digest, DIGEST_LEN)) {
return (!type) || ((type & ent->type) != 0);
});
@@ -2513,7 +2286,7 @@ router_addr_is_trusted_dir(uint32_t addr)
{
if (!trusted_dir_servers)
return 0;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ent,
if (ent->addr == addr)
return 1;
);
@@ -2535,18 +2308,6 @@ hexdigest_to_digest(const char *hexdigest, char *digest)
return 0;
}
-/** Return the router in our routerlist whose hexadecimal key digest
- * is <b>hexdigest</b>. Return NULL if no such router is known. */
-const routerinfo_t *
-router_get_by_hexdigest(const char *hexdigest)
-{
- if (is_legal_nickname(hexdigest))
- return NULL;
-
- /* It's not a legal nickname, so it must be a hexdigest or nothing. */
- return router_get_by_nickname(hexdigest, 1);
-}
-
/** As router_get_by_id_digest,but return a pointer that you're allowed to
* modify */
routerinfo_t *
@@ -2728,6 +2489,7 @@ routerinfo_free(routerinfo_t *router)
smartlist_free(router->declared_family);
}
addr_policy_list_free(router->exit_policy);
+ short_policy_free(router->ipv6_exit_policy);
memset(router, 77, sizeof(routerinfo_t));
@@ -2778,7 +2540,7 @@ signed_descriptor_from_routerinfo(routerinfo_t *ri)
/** Helper: free the storage held by the extrainfo_t in <b>e</b>. */
static void
-_extrainfo_free(void *e)
+extrainfo_free_(void *e)
{
extrainfo_free(e);
}
@@ -2792,7 +2554,7 @@ routerlist_free(routerlist_t *rl)
rimap_free(rl->identity_map, NULL);
sdmap_free(rl->desc_digest_map, NULL);
sdmap_free(rl->desc_by_eid_map, NULL);
- eimap_free(rl->extra_info_map, _extrainfo_free);
+ eimap_free(rl->extra_info_map, extrainfo_free_);
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
routerinfo_free(r));
SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd,
@@ -2834,7 +2596,7 @@ dump_routerlist_mem_usage(int severity)
* <b>ri</b>. Return the index of <b>ri</b> in <b>sl</b>, or -1 if <b>ri</b>
* is not in <b>sl</b>. */
static INLINE int
-_routerlist_find_elt(smartlist_t *sl, void *ri, int idx)
+routerlist_find_elt_(smartlist_t *sl, void *ri, int idx)
{
if (idx < 0) {
idx = -1;
@@ -2890,7 +2652,7 @@ routerlist_insert(routerlist_t *rl, routerinfo_t *ri)
&ri->cache_info);
smartlist_add(rl->routers, ri);
ri->cache_info.routerlist_index = smartlist_len(rl->routers) - 1;
- nodelist_add_routerinfo(ri);
+ nodelist_set_routerinfo(ri, NULL);
router_dir_info_changed();
#ifdef DEBUG_ROUTERLIST
routerlist_assert_ok(rl);
@@ -3119,8 +2881,11 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old,
tor_assert(0 <= idx && idx < smartlist_len(rl->routers));
tor_assert(smartlist_get(rl->routers, idx) == ri_old);
- nodelist_remove_routerinfo(ri_old);
- nodelist_add_routerinfo(ri_new);
+ {
+ routerinfo_t *ri_old_tmp=NULL;
+ nodelist_set_routerinfo(ri_new, &ri_old_tmp);
+ tor_assert(ri_old == ri_old_tmp);
+ }
router_dir_info_changed();
if (idx >= 0) {
@@ -3128,7 +2893,7 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old,
ri_old->cache_info.routerlist_index = -1;
ri_new->cache_info.routerlist_index = idx;
/* Check that ri_old is not in rl->routers anymore: */
- tor_assert( _routerlist_find_elt(rl->routers, ri_old, -1) == -1 );
+ tor_assert( routerlist_find_elt_(rl->routers, ri_old, -1) == -1 );
} else {
log_warn(LD_BUG, "Appending entry from routerlist_replace.");
routerlist_insert(rl, ri_new);
@@ -3232,12 +2997,10 @@ routerlist_free_all(void)
smartlist_free(warned_nicknames);
warned_nicknames = NULL;
}
- if (trusted_dir_servers) {
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
- trusted_dir_server_free(ds));
- smartlist_free(trusted_dir_servers);
- trusted_dir_servers = NULL;
- }
+ clear_dir_servers();
+ smartlist_free(trusted_dir_servers);
+ smartlist_free(fallback_dir_servers);
+ trusted_dir_servers = fallback_dir_servers = NULL;
if (trusted_dir_certs) {
DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) {
SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
@@ -3263,33 +3026,6 @@ routerlist_reset_warnings(void)
networkstatus_reset_warnings();
}
-/** Mark the router with ID <b>digest</b> as running or non-running
- * in our routerlist. */
-void
-router_set_status(const char *digest, int up)
-{
- node_t *node;
- tor_assert(digest);
-
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
- if (tor_memeq(d->digest, digest, DIGEST_LEN))
- d->is_running = up);
-
- node = node_get_mutable_by_id(digest);
- if (node) {
-#if 0
- log_debug(LD_DIR,"Marking router %s as %s.",
- node_describe(node), up ? "up" : "down");
-#endif
- if (!up && node_is_me(node) && !net_is_disabled())
- log_warn(LD_NET, "We just marked ourself as down. Are your external "
- "addresses reachable?");
- node->is_running = up;
- }
-
- router_dir_info_changed();
-}
-
/** Add <b>router</b> to the routerlist, if we don't already have it. Replace
* older entries (if any) with the same key. Note: Callers should not hold
* their pointers to <b>router</b> if this function fails; <b>router</b>
@@ -3457,11 +3193,6 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
/* Same key, and either new, or listed in the consensus. */
log_debug(LD_DIR, "Replacing entry for router %s",
router_describe(router));
- if (routers_have_same_or_addr(router, old_router)) {
- /* these carry over when the address and orport are unchanged. */
- router->last_reachable = old_router->last_reachable;
- router->testing_since = old_router->testing_since;
- }
routerlist_replace(routerlist, old_router, router);
if (!from_cache) {
signed_desc_append_to_journal(&router->cache_info,
@@ -3522,7 +3253,7 @@ router_add_extrainfo_to_routerlist(extrainfo_t *ei, const char **msg,
* signed_descriptor_t* in *<b>a</b> has an identity digest preceding, equal
* to, or later than that of *<b>b</b>. */
static int
-_compare_old_routers_by_identity(const void **_a, const void **_b)
+compare_old_routers_by_identity_(const void **_a, const void **_b)
{
int i;
const signed_descriptor_t *r1 = *_a, *r2 = *_b;
@@ -3542,7 +3273,7 @@ struct duration_idx_t {
/** Sorting helper: compare two duration_idx_t by their duration. */
static int
-_compare_duration_idx(const void *_d1, const void *_d2)
+compare_duration_idx_(const void *_d1, const void *_d2)
{
const struct duration_idx_t *d1 = _d1;
const struct duration_idx_t *d2 = _d2;
@@ -3619,7 +3350,7 @@ routerlist_remove_old_cached_routers_with_id(time_t now,
* the duration of liveness, and remove the ones we're not already going to
* remove based on how long they were alive.
**/
- qsort(lifespans, n, sizeof(struct duration_idx_t), _compare_duration_idx);
+ qsort(lifespans, n, sizeof(struct duration_idx_t), compare_duration_idx_);
for (i = 0; i < n && n_rmv < n_extra; ++i) {
if (!must_keep[lifespans[i].idx-lo] && !lifespans[i].old) {
rmv[lifespans[i].idx-lo] = 1;
@@ -3773,7 +3504,7 @@ routerlist_remove_old_routers(void)
goto done;
/* Sort by identity, then fix indices. */
- smartlist_sort(routerlist->old_routers, _compare_old_routers_by_identity);
+ smartlist_sort(routerlist->old_routers, compare_old_routers_by_identity_);
/* Fix indices. */
for (i = 0; i < smartlist_len(routerlist->old_routers); ++i) {
signed_descriptor_t *r = smartlist_get(routerlist->old_routers, i);
@@ -4068,27 +3799,6 @@ routerlist_retry_directory_downloads(time_t now)
update_all_descriptor_downloads(now);
}
-/** Return 1 if all running sufficiently-stable routers we can use will reject
- * addr:port, return 0 if any might accept it. */
-int
-router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
- int need_uptime)
-{ /* XXXX MOVE */
- addr_policy_result_t r;
-
- SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
- if (node->is_running &&
- !node_is_unreliable(node, need_uptime, 0, 0)) {
-
- r = compare_tor_addr_to_node_policy(addr, port, node);
-
- if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
- return 0; /* this one could be ok. good enough. */
- }
- } SMARTLIST_FOREACH_END(node);
- return 1; /* all will reject. */
-}
-
/** Return true iff <b>router</b> does not permit exit streams.
*/
int
@@ -4097,47 +3807,47 @@ router_exit_policy_rejects_all(const routerinfo_t *router)
return router->policy_is_reject_star;
}
-/** Add to the list of authoritative directory servers one at
- * <b>address</b>:<b>port</b>, with identity key <b>digest</b>. If
- * <b>address</b> is NULL, add ourself. Return the new trusted directory
- * server entry on success or NULL if we couldn't add it. */
-trusted_dir_server_t *
-add_trusted_dir_server(const char *nickname, const char *address,
- uint16_t dir_port, uint16_t or_port,
- const char *digest, const char *v3_auth_digest,
- dirinfo_type_t type)
-{
- trusted_dir_server_t *ent;
+/** Create an directory server at <b>address</b>:<b>port</b>, with OR identity
+ * key <b>digest</b>. If <b>address</b> is NULL, add ourself. If
+ * <b>is_authority</b>, this is a directory authority. Return the new
+ * directory server entry on success or NULL on failure. */
+static dir_server_t *
+dir_server_new(int is_authority,
+ const char *nickname,
+ const tor_addr_t *addr,
+ const char *hostname,
+ uint16_t dir_port, uint16_t or_port,
+ const char *digest, const char *v3_auth_digest,
+ dirinfo_type_t type,
+ double weight)
+{
+ dir_server_t *ent;
uint32_t a;
- char *hostname = NULL;
- if (!trusted_dir_servers)
- trusted_dir_servers = smartlist_new();
+ char *hostname_ = NULL;
- if (!address) { /* The address is us; we should guess. */
- if (resolve_my_address(LOG_WARN, get_options(), &a, &hostname) < 0) {
- log_warn(LD_CONFIG,
- "Couldn't find a suitable address when adding ourself as a "
- "trusted directory server.");
- return NULL;
- }
- } else {
- if (tor_lookup_hostname(address, &a)) {
- log_warn(LD_CONFIG,
- "Unable to lookup address for directory server at '%s'",
- address);
- return NULL;
- }
- hostname = tor_strdup(address);
- }
+ if (weight < 0)
+ return NULL;
+
+ if (tor_addr_family(addr) == AF_INET)
+ a = tor_addr_to_ipv4h(addr);
+ else
+ return NULL; /*XXXX Support IPv6 */
+
+ if (!hostname)
+ hostname_ = tor_dup_addr(addr);
+ else
+ hostname_ = tor_strdup(hostname);
- ent = tor_malloc_zero(sizeof(trusted_dir_server_t));
+ ent = tor_malloc_zero(sizeof(dir_server_t));
ent->nickname = nickname ? tor_strdup(nickname) : NULL;
- ent->address = hostname;
+ ent->address = hostname_;
ent->addr = a;
ent->dir_port = dir_port;
ent->or_port = or_port;
ent->is_running = 1;
+ ent->is_authority = is_authority;
ent->type = type;
+ ent->weight = weight;
memcpy(ent->digest, digest, DIGEST_LEN);
if (v3_auth_digest && (type & V3_DIRINFO))
memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN);
@@ -4159,14 +3869,75 @@ add_trusted_dir_server(const char *nickname, const char *address,
ent->fake_status.dir_port = ent->dir_port;
ent->fake_status.or_port = ent->or_port;
- if (ent->or_port)
- ent->fake_status.version_supports_begindir = 1;
+ return ent;
+}
- ent->fake_status.version_supports_conditional_consensus = 1;
+/** Create an authoritative directory server at
+ * <b>address</b>:<b>port</b>, with identity key <b>digest</b>. If
+ * <b>address</b> is NULL, add ourself. Return the new trusted directory
+ * server entry on success or NULL if we couldn't add it. */
+dir_server_t *
+trusted_dir_server_new(const char *nickname, const char *address,
+ uint16_t dir_port, uint16_t or_port,
+ const char *digest, const char *v3_auth_digest,
+ dirinfo_type_t type, double weight)
+{
+ uint32_t a;
+ tor_addr_t addr;
+ char *hostname=NULL;
+ dir_server_t *result;
- smartlist_add(trusted_dir_servers, ent);
+ if (!address) { /* The address is us; we should guess. */
+ if (resolve_my_address(LOG_WARN, get_options(), &a, &hostname) < 0) {
+ log_warn(LD_CONFIG,
+ "Couldn't find a suitable address when adding ourself as a "
+ "trusted directory server.");
+ return NULL;
+ }
+ } else {
+ if (tor_lookup_hostname(address, &a)) {
+ log_warn(LD_CONFIG,
+ "Unable to lookup address for directory server at '%s'",
+ address);
+ return NULL;
+ }
+ hostname = tor_strdup(address);
+ }
+ tor_addr_from_ipv4h(&addr, a);
+
+ result = dir_server_new(1, nickname, &addr, hostname,
+ dir_port, or_port, digest,
+ v3_auth_digest, type, weight);
+ tor_free(hostname);
+ return result;
+}
+
+/** Return a new dir_server_t for a fallback directory server at
+ * <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest
+ * <b>id_digest</b> */
+dir_server_t *
+fallback_dir_server_new(const tor_addr_t *addr,
+ uint16_t dir_port, uint16_t or_port,
+ const char *id_digest, double weight)
+{
+ return dir_server_new(0, NULL, addr, NULL, dir_port, or_port, id_digest,
+ NULL, ALL_DIRINFO, weight);
+}
+
+/** Add a directory server to the global list(s). */
+void
+dir_server_add(dir_server_t *ent)
+{
+ if (!trusted_dir_servers)
+ trusted_dir_servers = smartlist_new();
+ if (!fallback_dir_servers)
+ fallback_dir_servers = smartlist_new();
+
+ if (ent->is_authority)
+ smartlist_add(trusted_dir_servers, ent);
+
+ smartlist_add(fallback_dir_servers, ent);
router_dir_info_changed();
- return ent;
}
/** Free storage held in <b>cert</b>. */
@@ -4185,7 +3956,7 @@ authority_cert_free(authority_cert_t *cert)
/** Free storage held in <b>ds</b>. */
static void
-trusted_dir_server_free(trusted_dir_server_t *ds)
+dir_server_free(dir_server_t *ds)
{
if (!ds)
return;
@@ -4196,13 +3967,18 @@ trusted_dir_server_free(trusted_dir_server_t *ds)
tor_free(ds);
}
-/** Remove all members from the list of trusted dir servers. */
+/** Remove all members from the list of dir servers. */
void
-clear_trusted_dir_servers(void)
+clear_dir_servers(void)
{
+ if (fallback_dir_servers) {
+ SMARTLIST_FOREACH(fallback_dir_servers, dir_server_t *, ent,
+ dir_server_free(ent));
+ smartlist_clear(fallback_dir_servers);
+ } else {
+ fallback_dir_servers = smartlist_new();
+ }
if (trusted_dir_servers) {
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
- trusted_dir_server_free(ent));
smartlist_clear(trusted_dir_servers);
} else {
trusted_dir_servers = smartlist_new();
@@ -4338,7 +4114,7 @@ initiate_descriptor_downloads(const routerstatus_t *source,
/* We know which authority we want. */
directory_initiate_command_routerstatus(source, purpose,
ROUTER_PURPOSE_GENERAL,
- 0, /* not private */
+ DIRIND_ONEHOP,
resource, NULL, 0, 0);
} else {
directory_get_from_dirserver(purpose, ROUTER_PURPOSE_GENERAL, resource,
@@ -4347,30 +4123,6 @@ initiate_descriptor_downloads(const routerstatus_t *source,
tor_free(resource);
}
-/** Return 0 if this routerstatus is obsolete, too new, isn't
- * running, or otherwise not a descriptor that we would make any
- * use of even if we had it. Else return 1. */
-static INLINE int
-client_would_use_router(const routerstatus_t *rs, time_t now,
- const or_options_t *options)
-{
- if (!rs->is_flagged_running && !options->FetchUselessDescriptors) {
- /* If we had this router descriptor, we wouldn't even bother using it.
- * But, if we want to have a complete list, fetch it anyway. */
- return 0;
- }
- if (rs->published_on + options->TestingEstimatedDescriptorPropagationTime
- > now) {
- /* Most caches probably don't have this descriptor yet. */
- return 0;
- }
- if (rs->published_on + OLD_ROUTER_DESC_MAX_AGE < now) {
- /* We'd drop it immediately for being too old. */
- return 0;
- }
- return 1;
-}
-
/** Max amount of hashes to download per request.
* Since squid does not like URLs >= 4096 bytes we limit it to 96.
* 4096 - strlen(http://255.255.255.255/tor/server/d/.z) == 4058
@@ -4440,11 +4192,6 @@ launch_descriptor_downloads(int purpose,
}
}
}
- /* XXX should we consider having even the dir mirrors delay
- * a little bit, so we don't load the authorities as much? -RD
- * I don't think so. If we do, clients that want those descriptors may
- * not actually find them if the caches haven't got them yet. -NM
- */
if (! should_delay && n_downloadable) {
int i, n_per_request;
@@ -4484,9 +4231,9 @@ launch_descriptor_downloads(int purpose,
rtr_plural = "s";
log_info(LD_DIR,
- "Launching %d request%s for %d router%s, %d at a time",
- CEIL_DIV(n_downloadable, n_per_request),
- req_plural, n_downloadable, rtr_plural, n_per_request);
+ "Launching %d request%s for %d %s%s, %d at a time",
+ CEIL_DIV(n_downloadable, n_per_request), req_plural,
+ n_downloadable, descname, rtr_plural, n_per_request);
smartlist_sort_digests(downloadable);
for (i=0; i < n_downloadable; i += n_per_request) {
initiate_descriptor_downloads(source, purpose,
@@ -4537,7 +4284,7 @@ update_router_descriptor_cache_downloads_v2(time_t now)
*/
n_download = 0;
SMARTLIST_FOREACH_BEGIN(networkstatus_v2_list, networkstatus_v2_t *, ns) {
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
smartlist_t *dl;
dl = downloadable[ns_sl_idx] = smartlist_new();
download_from[ns_sl_idx] = smartlist_new();
@@ -4612,7 +4359,7 @@ update_router_descriptor_cache_downloads_v2(time_t now)
/* Now, we can actually launch our requests. */
for (i=0; i<n; ++i) {
networkstatus_v2_t *ns = smartlist_get(networkstatus_v2_list, i);
- trusted_dir_server_t *ds =
+ dir_server_t *ds =
router_get_trusteddirserver_by_digest(ns->identity_digest);
smartlist_t *dl = download_from[i];
int pds_flags = PDS_RETRY_IF_NO_SERVERS;
@@ -4665,7 +4412,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
if (is_vote) {
/* where's it from, so we know whom to ask for descriptors */
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
networkstatus_voter_info_t *voter = smartlist_get(consensus->voters, 0);
tor_assert(voter);
ds = trusteddirserver_get_by_v3_auth_digest(voter->identity_digest);
@@ -4888,230 +4635,6 @@ update_extrainfo_downloads(time_t now)
smartlist_free(wanted);
}
-/** True iff, the last time we checked whether we had enough directory info
- * to build circuits, the answer was "yes". */
-static int have_min_dir_info = 0;
-/** True iff enough has changed since the last time we checked whether we had
- * enough directory info to build circuits that our old answer can no longer
- * be trusted. */
-static int need_to_update_have_min_dir_info = 1;
-/** String describing what we're missing before we have enough directory
- * info. */
-static char dir_info_status[128] = "";
-
-/** Return true iff we have enough networkstatus and router information to
- * start building circuits. Right now, this means "more than half the
- * networkstatus documents, and at least 1/4 of expected routers." */
-//XXX should consider whether we have enough exiting nodes here.
-int
-router_have_minimum_dir_info(void)
-{
- if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) {
- update_router_have_minimum_dir_info();
- need_to_update_have_min_dir_info = 0;
- }
- return have_min_dir_info;
-}
-
-/** Called when our internal view of the directory has changed. This can be
- * when the authorities change, networkstatuses change, the list of routerdescs
- * changes, or number of running routers changes.
- */
-void
-router_dir_info_changed(void)
-{
- need_to_update_have_min_dir_info = 1;
- rend_hsdir_routers_changed();
-}
-
-/** Return a string describing what we're missing before we have enough
- * directory info. */
-const char *
-get_dir_info_status_string(void)
-{
- return dir_info_status;
-}
-
-/** Iterate over the servers listed in <b>consensus</b>, and count how many of
- * them seem like ones we'd use, and how many of <em>those</em> we have
- * descriptors for. Store the former in *<b>num_usable</b> and the latter in
- * *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those
- * routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes
- * with the Exit flag.
- */
-static void
-count_usable_descriptors(int *num_present, int *num_usable,
- const networkstatus_t *consensus,
- const or_options_t *options, time_t now,
- routerset_t *in_set, int exit_only)
-{
- const int md = (consensus->flavor == FLAV_MICRODESC);
- *num_present = 0, *num_usable=0;
-
- SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
- {
- if (exit_only && ! rs->is_exit)
- continue;
- if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
- continue;
- if (client_would_use_router(rs, now, options)) {
- const char * const digest = rs->descriptor_digest;
- int present;
- ++*num_usable; /* the consensus says we want it. */
- if (md)
- present = NULL != microdesc_cache_lookup_by_digest256(NULL, digest);
- else
- present = NULL != router_get_by_descriptor_digest(digest);
- if (present) {
- /* we have the descriptor listed in the consensus. */
- ++*num_present;
- }
- }
- }
- SMARTLIST_FOREACH_END(rs);
-
- log_debug(LD_DIR, "%d usable, %d present.", *num_usable, *num_present);
-}
-
-/** We just fetched a new set of descriptors. Compute how far through
- * the "loading descriptors" bootstrapping phase we are, so we can inform
- * the controller of our progress. */
-int
-count_loading_descriptors_progress(void)
-{
- int num_present = 0, num_usable=0;
- time_t now = time(NULL);
- const networkstatus_t *consensus =
- networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
- double fraction;
-
- if (!consensus)
- return 0; /* can't count descriptors if we have no list of them */
-
- count_usable_descriptors(&num_present, &num_usable,
- consensus, get_options(), now, NULL, 0);
-
- if (num_usable == 0)
- return 0; /* don't div by 0 */
- fraction = num_present / (num_usable/4.);
- if (fraction > 1.0)
- return 0; /* it's not the number of descriptors holding us back */
- return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int)
- (fraction*(BOOTSTRAP_STATUS_CONN_OR-1 -
- BOOTSTRAP_STATUS_LOADING_DESCRIPTORS));
-}
-
-/** Change the value of have_min_dir_info, setting it true iff we have enough
- * network and router information to build circuits. Clear the value of
- * need_to_update_have_min_dir_info. */
-static void
-update_router_have_minimum_dir_info(void)
-{
- int num_present = 0, num_usable=0;
- int num_exit_present = 0, num_exit_usable = 0;
- time_t now = time(NULL);
- int res;
- const or_options_t *options = get_options();
- const networkstatus_t *consensus =
- networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
- int using_md;
-
- if (!consensus) {
- if (!networkstatus_get_latest_consensus())
- strlcpy(dir_info_status, "We have no usable consensus.",
- sizeof(dir_info_status));
- else
- strlcpy(dir_info_status, "We have no recent usable consensus.",
- sizeof(dir_info_status));
- res = 0;
- goto done;
- }
-
- if (should_delay_dir_fetches(get_options())) {
- log_notice(LD_DIR, "no known bridge descriptors running yet; stalling");
- strlcpy(dir_info_status, "No live bridge descriptors.",
- sizeof(dir_info_status));
- res = 0;
- goto done;
- }
-
- using_md = consensus->flavor == FLAV_MICRODESC;
-
- count_usable_descriptors(&num_present, &num_usable, consensus, options, now,
- NULL, 0);
- count_usable_descriptors(&num_exit_present, &num_exit_usable,
- consensus, options, now, options->ExitNodes, 1);
-
-/* What fraction of desired server descriptors do we need before we will
- * build circuits? */
-#define FRAC_USABLE_NEEDED .75
-/* What fraction of desired _exit_ server descriptors do we need before we
- * will build circuits? */
-#define FRAC_EXIT_USABLE_NEEDED .5
-
- if (num_present < num_usable * FRAC_USABLE_NEEDED) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "We have only %d/%d usable %sdescriptors.",
- num_present, num_usable, using_md ? "micro" : "");
- res = 0;
- control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
- goto done;
- } else if (num_present < 2) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "Only %d %sdescriptor%s here and believed reachable!",
- num_present, using_md ? "micro" : "", num_present ? "" : "s");
- res = 0;
- goto done;
- } else if (num_exit_present < num_exit_usable * FRAC_EXIT_USABLE_NEEDED) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "We have only %d/%d usable exit node descriptors.",
- num_exit_present, num_exit_usable);
- res = 0;
- control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
- goto done;
- }
-
- /* Check for entry nodes. */
- if (options->EntryNodes) {
- count_usable_descriptors(&num_present, &num_usable, consensus, options,
- now, options->EntryNodes, 0);
-
- if (!num_usable || !num_present) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "We have only %d/%d usable entry node %sdescriptors.",
- num_present, num_usable, using_md?"micro":"");
- res = 0;
- goto done;
- }
- }
-
- res = 1;
-
- done:
- if (res && !have_min_dir_info) {
- log(LOG_NOTICE, LD_DIR,
- "We now have enough directory information to build circuits.");
- control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
- control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0);
- }
- if (!res && have_min_dir_info) {
- int quiet = directory_too_idle_to_fetch_descriptors(options, now);
- log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
- "Our directory information is no longer up-to-date "
- "enough to build circuits: %s", dir_info_status);
-
- /* a) make us log when we next complete a circuit, so we know when Tor
- * is back up and usable, and b) disable some activities that Tor
- * should only do while circuits are working, like reachability tests
- * and fetching bridge descriptors only over circuits. */
- can_complete_circuit = 0;
-
- control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
- }
- have_min_dir_info = res;
- need_to_update_have_min_dir_info = 0;
-}
-
/** Reset the descriptor download failure count on all routers, so that we
* can retry any long-failed routers immediately.
*/
@@ -5164,8 +4687,8 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
r1->ipv6_orport != r2->ipv6_orport ||
r1->dir_port != r2->dir_port ||
r1->purpose != r2->purpose ||
- crypto_pk_cmp_keys(r1->onion_pkey, r2->onion_pkey) ||
- crypto_pk_cmp_keys(r1->identity_pkey, r2->identity_pkey) ||
+ !crypto_pk_eq_keys(r1->onion_pkey, r2->onion_pkey) ||
+ !crypto_pk_eq_keys(r1->identity_pkey, r2->identity_pkey) ||
strcasecmp(r1->platform, r2->platform) ||
(r1->contact_info && !r2->contact_info) || /* contact_info is optional */
(!r1->contact_info && r2->contact_info) ||
@@ -5410,7 +4933,7 @@ esc_router_info(const routerinfo_t *router)
/** Helper for sorting: compare two routerinfos by their identity
* digest. */
static int
-_compare_routerinfo_by_id_digest(const void **a, const void **b)
+compare_routerinfo_by_id_digest_(const void **a, const void **b)
{
routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b;
return fast_memcmp(first->cache_info.identity_digest,
@@ -5422,153 +4945,10 @@ _compare_routerinfo_by_id_digest(const void **a, const void **b)
void
routers_sort_by_identity(smartlist_t *routers)
{
- smartlist_sort(routers, _compare_routerinfo_by_id_digest);
-}
-
-/** A routerset specifies constraints on a set of possible routerinfos, based
- * on their names, identities, or addresses. It is optimized for determining
- * whether a router is a member or not, in O(1+P) time, where P is the number
- * of address policy constraints. */
-struct routerset_t {
- /** A list of strings for the elements of the policy. Each string is either
- * a nickname, a hexadecimal identity fingerprint, or an address policy. A
- * router belongs to the set if its nickname OR its identity OR its address
- * matches an entry here. */
- smartlist_t *list;
- /** A map from lowercase nicknames of routers in the set to (void*)1 */
- strmap_t *names;
- /** A map from identity digests routers in the set to (void*)1 */
- digestmap_t *digests;
- /** An address policy for routers in the set. For implementation reasons,
- * a router belongs to the set if it is _rejected_ by this policy. */
- smartlist_t *policies;
-
- /** A human-readable description of what this routerset is for. Used in
- * log messages. */
- char *description;
-
- /** A list of the country codes in this set. */
- smartlist_t *country_names;
- /** Total number of countries we knew about when we built <b>countries</b>.*/
- int n_countries;
- /** Bit array mapping the return value of geoip_get_country() to 1 iff the
- * country is a member of this routerset. Note that we MUST call
- * routerset_refresh_countries() whenever the geoip country list is
- * reloaded. */
- bitarray_t *countries;
-};
-
-/** Return a new empty routerset. */
-routerset_t *
-routerset_new(void)
-{
- routerset_t *result = tor_malloc_zero(sizeof(routerset_t));
- result->list = smartlist_new();
- result->names = strmap_new();
- result->digests = digestmap_new();
- result->policies = smartlist_new();
- result->country_names = smartlist_new();
- return result;
-}
-
-/** If <b>c</b> is a country code in the form {cc}, return a newly allocated
- * string holding the "cc" part. Else, return NULL. */
-static char *
-routerset_get_countryname(const char *c)
-{
- char *country;
-
- if (strlen(c) < 4 || c[0] !='{' || c[3] !='}')
- return NULL;
-
- country = tor_strndup(c+1, 2);
- tor_strlower(country);
- return country;
-}
-
-/** Update the routerset's <b>countries</b> bitarray_t. Called whenever
- * the GeoIP database is reloaded.
- */
-void
-routerset_refresh_countries(routerset_t *target)
-{
- int cc;
- bitarray_free(target->countries);
-
- if (!geoip_is_loaded()) {
- target->countries = NULL;
- target->n_countries = 0;
- return;
- }
- target->n_countries = geoip_get_n_countries();
- target->countries = bitarray_init_zero(target->n_countries);
- SMARTLIST_FOREACH_BEGIN(target->country_names, const char *, country) {
- cc = geoip_get_country(country);
- if (cc >= 0) {
- tor_assert(cc < target->n_countries);
- bitarray_set(target->countries, cc);
- } else {
- log(LOG_WARN, LD_CONFIG, "Country code '%s' is not recognized.",
- country);
- }
- } SMARTLIST_FOREACH_END(country);
-}
-
-/** Parse the string <b>s</b> to create a set of routerset entries, and add
- * them to <b>target</b>. In log messages, refer to the string as
- * <b>description</b>. Return 0 on success, -1 on failure.
- *
- * Three kinds of elements are allowed in routersets: nicknames, IP address
- * patterns, and fingerprints. They may be surrounded by optional space, and
- * must be separated by commas.
- */
-int
-routerset_parse(routerset_t *target, const char *s, const char *description)
-{
- int r = 0;
- int added_countries = 0;
- char *countryname;
- smartlist_t *list = smartlist_new();
- smartlist_split_string(list, s, ",",
- SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0);
- SMARTLIST_FOREACH_BEGIN(list, char *, nick) {
- addr_policy_t *p;
- if (is_legal_hexdigest(nick)) {
- char d[DIGEST_LEN];
- if (*nick == '$')
- ++nick;
- log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description);
- base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN);
- digestmap_set(target->digests, d, (void*)1);
- } else if (is_legal_nickname(nick)) {
- log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description);
- strmap_set_lc(target->names, nick, (void*)1);
- } else if ((countryname = routerset_get_countryname(nick)) != NULL) {
- log_debug(LD_CONFIG, "Adding country %s to %s", nick,
- description);
- smartlist_add(target->country_names, countryname);
- added_countries = 1;
- } else if ((strchr(nick,'.') || strchr(nick, '*')) &&
- (p = router_parse_addr_policy_item_from_string(
- nick, ADDR_POLICY_REJECT))) {
- log_debug(LD_CONFIG, "Adding address %s to %s", nick, description);
- smartlist_add(target->policies, p);
- } else {
- log_warn(LD_CONFIG, "Entry '%s' in %s is misformed.", nick,
- description);
- r = -1;
- tor_free(nick);
- SMARTLIST_DEL_CURRENT(list, nick);
- }
- } SMARTLIST_FOREACH_END(nick);
- smartlist_add_all(target->list, list);
- smartlist_free(list);
- if (added_countries)
- routerset_refresh_countries(target);
- return r;
+ smartlist_sort(routers, compare_routerinfo_by_id_digest_);
}
-/** Called when we change a node set, or when we reload the geoip list:
+/** Called when we change a node set, or when we reload the geoip IPv4 list:
* recompute all country info in all configuration node sets and in the
* routerlist. */
void
@@ -5584,303 +4964,12 @@ refresh_all_country_info(void)
routerset_refresh_countries(options->ExcludeNodes);
if (options->ExcludeExitNodes)
routerset_refresh_countries(options->ExcludeExitNodes);
- if (options->_ExcludeExitNodesUnion)
- routerset_refresh_countries(options->_ExcludeExitNodesUnion);
+ if (options->ExcludeExitNodesUnion_)
+ routerset_refresh_countries(options->ExcludeExitNodesUnion_);
nodelist_refresh_countries();
}
-/** Add all members of the set <b>source</b> to <b>target</b>. */
-void
-routerset_union(routerset_t *target, const routerset_t *source)
-{
- char *s;
- tor_assert(target);
- if (!source || !source->list)
- return;
- s = routerset_to_string(source);
- routerset_parse(target, s, "other routerset");
- tor_free(s);
-}
-
-/** Return true iff <b>set</b> lists only nicknames and digests, and includes
- * no IP ranges or countries. */
-int
-routerset_is_list(const routerset_t *set)
-{
- return smartlist_len(set->country_names) == 0 &&
- smartlist_len(set->policies) == 0;
-}
-
-/** Return true iff we need a GeoIP IP-to-country database to make sense of
- * <b>set</b>. */
-int
-routerset_needs_geoip(const routerset_t *set)
-{
- return set && smartlist_len(set->country_names);
-}
-
-/** Return true iff there are no entries in <b>set</b>. */
-int
-routerset_is_empty(const routerset_t *set)
-{
- return !set || smartlist_len(set->list) == 0;
-}
-
-/** Helper. Return true iff <b>set</b> contains a router based on the other
- * provided fields. Return higher values for more specific subentries: a
- * single router is more specific than an address range of routers, which is
- * more specific in turn than a country code.
- *
- * (If country is -1, then we take the country
- * from addr.) */
-static int
-routerset_contains(const routerset_t *set, const tor_addr_t *addr,
- uint16_t orport,
- const char *nickname, const char *id_digest,
- country_t country)
-{
- if (!set || !set->list)
- return 0;
- if (nickname && strmap_get_lc(set->names, nickname))
- return 4;
- if (id_digest && digestmap_get(set->digests, id_digest))
- return 4;
- if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
- == ADDR_POLICY_REJECTED)
- return 3;
- if (set->countries) {
- if (country < 0 && addr)
- country = geoip_get_country_by_ip(tor_addr_to_ipv4h(addr));
-
- if (country >= 0 && country < set->n_countries &&
- bitarray_is_set(set->countries, country))
- return 2;
- }
- return 0;
-}
-
-/** Return true iff we can tell that <b>ei</b> is a member of <b>set</b>. */
-int
-routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei)
-{
- return routerset_contains(set,
- &ei->addr,
- ei->port,
- ei->nickname,
- ei->identity_digest,
- -1 /*country*/);
-}
-
-/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we
- * look up the country. */
-int
-routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
- country_t country)
-{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ri->addr);
- return routerset_contains(set,
- &addr,
- ri->or_port,
- ri->nickname,
- ri->cache_info.identity_digest,
- country);
-}
-
-/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we
- * look up the country. */
-int
-routerset_contains_routerstatus(const routerset_t *set,
- const routerstatus_t *rs,
- country_t country)
-{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, rs->addr);
- return routerset_contains(set,
- &addr,
- rs->or_port,
- rs->nickname,
- rs->identity_digest,
- country);
-}
-
-/** Return true iff <b>node</b> is in <b>set</b>. */
-int
-routerset_contains_node(const routerset_t *set, const node_t *node)
-{
- if (node->rs)
- return routerset_contains_routerstatus(set, node->rs, node->country);
- else if (node->ri)
- return routerset_contains_router(set, node->ri, node->country);
- else
- return 0;
-}
-
-/** Add every known node_t that is a member of <b>routerset</b> to
- * <b>out</b>, but never add any that are part of <b>excludeset</b>.
- * If <b>running_only</b>, only add the running ones. */
-void
-routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
- const routerset_t *excludeset, int running_only)
-{ /* XXXX MOVE */
- tor_assert(out);
- if (!routerset || !routerset->list)
- return;
-
- if (routerset_is_list(routerset)) {
- /* No routers are specified by type; all are given by name or digest.
- * we can do a lookup in O(len(routerset)). */
- SMARTLIST_FOREACH(routerset->list, const char *, name, {
- const node_t *node = node_get_by_nickname(name, 1);
- if (node) {
- if (!running_only || node->is_running)
- if (!routerset_contains_node(excludeset, node))
- smartlist_add(out, (void*)node);
- }
- });
- } else {
- /* We need to iterate over the routerlist to get all the ones of the
- * right kind. */
- smartlist_t *nodes = nodelist_get_list();
- SMARTLIST_FOREACH(nodes, const node_t *, node, {
- if (running_only && !node->is_running)
- continue;
- if (routerset_contains_node(routerset, node) &&
- !routerset_contains_node(excludeset, node))
- smartlist_add(out, (void*)node);
- });
- }
-}
-
-#if 0
-/** Add to <b>target</b> every node_t from <b>source</b> except:
- *
- * 1) Don't add it if <b>include</b> is non-empty and the relay isn't in
- * <b>include</b>; and
- * 2) Don't add it if <b>exclude</b> is non-empty and the relay is
- * excluded in a more specific fashion by <b>exclude</b>.
- * 3) If <b>running_only</b>, don't add non-running routers.
- */
-void
-routersets_get_node_disjunction(smartlist_t *target,
- const smartlist_t *source,
- const routerset_t *include,
- const routerset_t *exclude, int running_only)
-{
- SMARTLIST_FOREACH(source, const node_t *, node, {
- int include_result;
- if (running_only && !node->is_running)
- continue;
- if (!routerset_is_empty(include))
- include_result = routerset_contains_node(include, node);
- else
- include_result = 1;
-
- if (include_result) {
- int exclude_result = routerset_contains_node(exclude, node);
- if (include_result >= exclude_result)
- smartlist_add(target, (void*)node);
- }
- });
-}
-#endif
-
-/** Remove every node_t from <b>lst</b> that is in <b>routerset</b>. */
-void
-routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset)
-{ /*XXXX MOVE ? */
- tor_assert(lst);
- if (!routerset)
- return;
- SMARTLIST_FOREACH(lst, const node_t *, node, {
- if (routerset_contains_node(routerset, node)) {
- //log_debug(LD_DIR, "Subtracting %s",r->nickname);
- SMARTLIST_DEL_CURRENT(lst, node);
- }
- });
-}
-
-/** Return a new string that when parsed by routerset_parse_string() will
- * yield <b>set</b>. */
-char *
-routerset_to_string(const routerset_t *set)
-{
- if (!set || !set->list)
- return tor_strdup("");
- return smartlist_join_strings(set->list, ",", 0, NULL);
-}
-
-/** Helper: return true iff old and new are both NULL, or both non-NULL
- * equal routersets. */
-int
-routerset_equal(const routerset_t *old, const routerset_t *new)
-{
- if (routerset_is_empty(old) && routerset_is_empty(new)) {
- /* Two empty sets are equal */
- return 1;
- } else if (routerset_is_empty(old) || routerset_is_empty(new)) {
- /* An empty set is equal to nothing else. */
- return 0;
- }
- tor_assert(old != NULL);
- tor_assert(new != NULL);
-
- if (smartlist_len(old->list) != smartlist_len(new->list))
- return 0;
-
- SMARTLIST_FOREACH(old->list, const char *, cp1, {
- const char *cp2 = smartlist_get(new->list, cp1_sl_idx);
- if (strcmp(cp1, cp2))
- return 0;
- });
-
- return 1;
-}
-
-/** Free all storage held in <b>routerset</b>. */
-void
-routerset_free(routerset_t *routerset)
-{
- if (!routerset)
- return;
-
- SMARTLIST_FOREACH(routerset->list, char *, cp, tor_free(cp));
- smartlist_free(routerset->list);
- SMARTLIST_FOREACH(routerset->policies, addr_policy_t *, p,
- addr_policy_free(p));
- smartlist_free(routerset->policies);
- SMARTLIST_FOREACH(routerset->country_names, char *, cp, tor_free(cp));
- smartlist_free(routerset->country_names);
-
- strmap_free(routerset->names, NULL);
- digestmap_free(routerset->digests, NULL);
- bitarray_free(routerset->countries);
- tor_free(routerset);
-}
-
-/** Refresh the country code of <b>ri</b>. This function MUST be called on
- * each router when the GeoIP database is reloaded, and on all new routers. */
-void
-node_set_country(node_t *node)
-{
- if (node->rs)
- node->country = geoip_get_country_by_ip(node->rs->addr);
- else if (node->ri)
- node->country = geoip_get_country_by_ip(node->ri->addr);
- else
- node->country = -1;
-}
-
-/** Set the country code of all routers in the routerlist. */
-void
-nodelist_refresh_countries(void) /* MOVE */
-{
- smartlist_t *nodes = nodelist_get_list();
- SMARTLIST_FOREACH(nodes, node_t *, node,
- node_set_country(node));
-}
-
/** Determine the routers that are responsible for <b>id</b> (binary) and
* add pointers to those routers' routerstatus_t to <b>responsible_dirs</b>.
* Return -1 if we're returning an empty smartlist, else return 0.
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index 8dcc6eb026..81ba1ac54f 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -8,8 +8,8 @@
* \brief Header file for routerlist.c.
**/
-#ifndef _TOR_ROUTERLIST_H
-#define _TOR_ROUTERLIST_H
+#ifndef TOR_ROUTERLIST_H
+#define TOR_ROUTERLIST_H
int get_n_authorities(dirinfo_type_t type);
int trusted_dirs_reload_certs(void);
@@ -25,24 +25,25 @@ void authority_cert_dl_failed(const char *id_digest, int status);
void authority_certs_fetch_missing(networkstatus_t *status, time_t now);
int router_reload_router_list(void);
int authority_cert_dl_looks_uncertain(const char *id_digest);
-smartlist_t *router_get_trusted_dir_servers(void);
+const smartlist_t *router_get_trusted_dir_servers(void);
+const smartlist_t *router_get_fallback_dir_servers(void);
const routerstatus_t *router_pick_directory_server(dirinfo_type_t type,
int flags);
-trusted_dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
-trusted_dir_server_t *trusteddirserver_get_by_v3_auth_digest(const char *d);
+dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
+dir_server_t *router_get_fallback_dirserver_by_digest(
+ const char *digest);
+dir_server_t *trusteddirserver_get_by_v3_auth_digest(const char *d);
const routerstatus_t *router_pick_trusteddirserver(dirinfo_type_t type,
int flags);
+const routerstatus_t *router_pick_fallback_dirserver(dirinfo_type_t type,
+ int flags);
int router_get_my_share_of_directory_requests(double *v2_share_out,
double *v3_share_out);
void router_reset_status_download_failures(void);
-int routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2);
+int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
int router_nickname_is_in_list(const routerinfo_t *router, const char *list);
const routerinfo_t *routerlist_find_my_routerinfo(void);
-const node_t *router_find_exact_exit_enclave(const char *address,
- uint16_t port);
-int node_is_unreliable(const node_t *router, int need_uptime,
- int need_capacity, int need_guard);
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router);
@@ -53,8 +54,6 @@ const node_t *router_choose_random_node(smartlist_t *excludedsmartlist,
struct routerset_t *excludedset,
router_crn_flags_t flags);
-const routerinfo_t *router_get_by_nickname(const char *nickname,
- int warn_if_unnamed);
int router_is_named(const routerinfo_t *router);
int router_digest_is_trusted_dir_type(const char *digest,
dirinfo_type_t type);
@@ -63,7 +62,6 @@ int router_digest_is_trusted_dir_type(const char *digest,
int router_addr_is_trusted_dir(uint32_t addr);
int hexdigest_to_digest(const char *hexdigest, char *digest);
-const routerinfo_t *router_get_by_hexdigest(const char *hexdigest);
const routerinfo_t *router_get_by_id_digest(const char *digest);
routerinfo_t *router_get_mutable_by_digest(const char *digest);
signed_descriptor_t *router_get_by_descriptor_digest(const char *digest);
@@ -80,7 +78,6 @@ void routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int make_old,
time_t now);
void routerlist_free_all(void);
void routerlist_reset_warnings(void);
-void router_set_status(const char *digest, int up);
static int WRA_WAS_ADDED(was_router_added_t s);
static int WRA_WAS_OUTDATED(was_router_added_t s);
@@ -133,27 +130,26 @@ void router_load_extrainfo_from_string(const char *s, const char *eos,
int descriptor_digests);
void routerlist_retry_directory_downloads(time_t now);
-int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
- int need_uptime);
int router_exit_policy_rejects_all(const routerinfo_t *router);
-trusted_dir_server_t *add_trusted_dir_server(const char *nickname,
- const char *address,
- uint16_t dir_port, uint16_t or_port,
- const char *digest, const char *v3_auth_digest,
- dirinfo_type_t type);
+
+dir_server_t *trusted_dir_server_new(const char *nickname, const char *address,
+ uint16_t dir_port, uint16_t or_port,
+ const char *digest, const char *v3_auth_digest,
+ dirinfo_type_t type, double weight);
+dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
+ uint16_t dir_port, uint16_t or_port,
+ const char *id_digest, double weight);
+void dir_server_add(dir_server_t *ent);
+
void authority_cert_free(authority_cert_t *cert);
-void clear_trusted_dir_servers(void);
+void clear_dir_servers(void);
int any_trusted_dir_is_v1_authority(void);
void update_consensus_router_descriptor_downloads(time_t now, int is_vote,
networkstatus_t *consensus);
void update_router_descriptor_downloads(time_t now);
void update_all_descriptor_downloads(time_t now);
void update_extrainfo_downloads(time_t now);
-int router_have_minimum_dir_info(void);
-void router_dir_info_changed(void);
-const char *get_dir_info_status_string(void);
-int count_loading_descriptors_progress(void);
void router_reset_descriptor_download_failures(void);
int router_differences_are_cosmetic(const routerinfo_t *r1,
const routerinfo_t *r2);
@@ -166,38 +162,6 @@ void routerlist_assert_ok(const routerlist_t *rl);
const char *esc_router_info(const routerinfo_t *router);
void routers_sort_by_identity(smartlist_t *routers);
-routerset_t *routerset_new(void);
-void routerset_refresh_countries(routerset_t *rs);
-int routerset_parse(routerset_t *target, const char *s,
- const char *description);
-void routerset_union(routerset_t *target, const routerset_t *source);
-int routerset_is_list(const routerset_t *set);
-int routerset_needs_geoip(const routerset_t *set);
-int routerset_is_empty(const routerset_t *set);
-int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
- country_t country);
-int routerset_contains_routerstatus(const routerset_t *set,
- const routerstatus_t *rs,
- country_t country);
-int routerset_contains_extendinfo(const routerset_t *set,
- const extend_info_t *ei);
-
-int routerset_contains_node(const routerset_t *set, const node_t *node);
-void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
- const routerset_t *excludeset,
- int running_only);
-#if 0
-void routersets_get_node_disjunction(smartlist_t *target,
- const smartlist_t *source,
- const routerset_t *include,
- const routerset_t *exclude, int running_only);
-#endif
-void routerset_subtract_nodes(smartlist_t *out,
- const routerset_t *routerset);
-
-char *routerset_to_string(const routerset_t *routerset);
-int routerset_equal(const routerset_t *old, const routerset_t *new);
-void routerset_free(routerset_t *routerset);
void refresh_all_country_info(void);
int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
@@ -215,6 +179,23 @@ int hex_digest_nickname_decode(const char *hexdigest,
char *digest_out,
char *nickname_qualifier_out,
char *nickname_out);
+int hex_digest_nickname_matches(const char *hexdigest,
+ const char *identity_digest,
+ const char *nickname, int is_named);
+
+#ifdef ROUTERLIST_PRIVATE
+/** Helper type for choosing routers by bandwidth: contains a union of
+ * double and uint64_t. Before we call scale_array_elements_to_u64, it holds
+ * a double; after, it holds a uint64_t. */
+typedef union u64_dbl_t {
+ uint64_t u64;
+ double dbl;
+} u64_dbl_t;
+
+int choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries);
+void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
+ uint64_t *total_out);
+#endif
#endif
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 299d07d376..1aee4e5332 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -11,7 +11,7 @@
#include "or.h"
#include "config.h"
-#include "circuitbuild.h"
+#include "circuitstats.h"
#include "dirserv.h"
#include "dirvote.h"
#include "policies.h"
@@ -29,8 +29,8 @@
/****************************************************************************/
/** Enumeration of possible token types. The ones starting with K_ correspond
- * to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF
- * is an end-of-file marker, and _NIL is used to encode not-a-token.
+ * to directory 'keywords'. ERR_ is an error in the tokenizing process, EOF_
+ * is an end-of-file marker, and NIL_ is used to encode not-a-token.
*/
typedef enum {
K_ACCEPT = 0,
@@ -66,7 +66,9 @@ typedef enum {
K_SERVER_VERSIONS,
K_OR_ADDRESS,
K_P,
+ K_P6,
K_R,
+ K_A,
K_S,
K_V,
K_W,
@@ -76,6 +78,7 @@ typedef enum {
K_CACHES_EXTRA_INFO,
K_HIDDEN_SERVICE_DIR,
K_ALLOW_SINGLE_HOP_EXITS,
+ K_IPV6_POLICY,
K_DIRREQ_END,
K_DIRREQ_V2_IPS,
@@ -130,7 +133,7 @@ typedef enum {
A_PURPOSE,
A_LAST_LISTED,
- _A_UNKNOWN,
+ A_UNKNOWN_,
R_RENDEZVOUS_SERVICE_DESCRIPTOR,
R_VERSION,
@@ -151,13 +154,13 @@ typedef enum {
C_DESCRIPTOR_COOKIE,
C_CLIENT_KEY,
- _ERR,
- _EOF,
- _NIL
+ ERR_,
+ EOF_,
+ NIL_
} directory_keyword;
#define MIN_ANNOTATION A_PURPOSE
-#define MAX_ANNOTATION _A_UNKNOWN
+#define MAX_ANNOTATION A_UNKNOWN_
/** Structure to hold a single directory token.
*
@@ -180,7 +183,7 @@ typedef struct directory_token_t {
crypto_pk_t *key; /**< For public keys only. Heap-allocated. */
- char *error; /**< For _ERR tokens only. */
+ char *error; /**< For ERR_ tokens only. */
} directory_token_t;
/* ********************************************************************** */
@@ -234,7 +237,7 @@ typedef struct token_rule_t {
*/
/** Appears to indicate the end of a table. */
-#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
+#define END_OF_TABLE { NULL, NIL_, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
/** An item with no restrictions: used for obsolete document types */
#define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
/** An item with no restrictions on multiplicity or location. */
@@ -270,6 +273,7 @@ static token_rule_t routerdesc_token_table[] = {
T0N("reject6", K_REJECT6, ARGS, NO_OBJ ),
T0N("accept6", K_ACCEPT6, ARGS, NO_OBJ ),
T1_START( "router", K_ROUTER, GE(5), NO_OBJ ),
+ T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ),
T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
@@ -338,6 +342,7 @@ static token_rule_t extrainfo_token_table[] = {
static token_rule_t rtrstatus_token_table[] = {
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
T1( "r", K_R, GE(7), NO_OBJ ),
+ T0N("a", K_A, GE(1), NO_OBJ ),
T1( "s", K_S, ARGS, NO_OBJ ),
T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
T01("w", K_W, ARGS, NO_OBJ ),
@@ -371,25 +376,6 @@ static token_rule_t dir_footer_token_table[] = {
END_OF_TABLE
};
-/** List of tokens recognized in v1 directory headers/footers. */
-static token_rule_t dir_token_table[] = {
- /* don't enforce counts; this is obsolete. */
- T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ),
- T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ),
- T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ),
- T( "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ ),
-
- T( "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ ),
- T( "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ ),
- T( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
- T( "opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
- T( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
- T( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK ),
- T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
-
- END_OF_TABLE
-};
-
/** List of tokens common to V3 authority certificates and V3 consensuses. */
#define CERTIFICATE_MEMBERS \
T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
@@ -522,8 +508,10 @@ static token_rule_t networkstatus_detached_signature_token_table[] = {
/** List of tokens recognized in microdescriptors */
static token_rule_t microdesc_token_table[] = {
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
+ T0N("a", K_A, GE(1), NO_OBJ ),
T01("family", K_FAMILY, ARGS, NO_OBJ ),
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
+ T01("p6", K_P6, CONCAT_ARGS, NO_OBJ ),
A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
@@ -532,7 +520,8 @@ static token_rule_t microdesc_token_table[] = {
/* static function prototypes */
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
-static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
+static addr_policy_t *router_parse_addr_policy(directory_token_t *tok,
+ unsigned fmt_flags);
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
@@ -546,10 +535,10 @@ static int router_get_hashes_impl(const char *s, size_t s_len,
static void token_clear(directory_token_t *tok);
static smartlist_t *find_all_by_keyword(smartlist_t *s, directory_keyword k);
static smartlist_t *find_all_exitpolicy(smartlist_t *s);
-static directory_token_t *_find_by_keyword(smartlist_t *s,
+static directory_token_t *find_by_keyword_(smartlist_t *s,
directory_keyword keyword,
const char *keyword_str);
-#define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword)
+#define find_by_keyword(s, keyword) find_by_keyword_((s), (keyword), #keyword)
static directory_token_t *find_opt_by_keyword(smartlist_t *s,
directory_keyword keyword);
@@ -573,7 +562,6 @@ static int check_signature_token(const char *digest,
crypto_pk_t *pkey,
int flags,
const char *doctype);
-static crypto_pk_t *find_dir_signing_key(const char *str, const char *eos);
#undef DEBUG_AREA_ALLOC
@@ -816,218 +804,6 @@ tor_version_is_obsolete(const char *myversion, const char *versionlist)
return ret;
}
-/** Read a signed directory from <b>str</b>. If it's well-formed, return 0.
- * Otherwise, return -1. If we're a directory cache, cache it.
- */
-int
-router_parse_directory(const char *str)
-{
- directory_token_t *tok;
- char digest[DIGEST_LEN];
- time_t published_on;
- int r;
- const char *end, *cp, *str_dup = str;
- smartlist_t *tokens = NULL;
- crypto_pk_t *declared_key = NULL;
- memarea_t *area = memarea_new();
-
- /* XXXX This could be simplified a lot, but it will all go away
- * once pre-0.1.1.8 is obsolete, and for now it's better not to
- * touch it. */
-
- if (router_get_dir_hash(str, digest)) {
- log_warn(LD_DIR, "Unable to compute digest of directory");
- goto err;
- }
- log_debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
-
- /* Check signature first, before we try to tokenize. */
- cp = str;
- while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
- cp = end;
- if (cp == str || !cp) {
- log_warn(LD_DIR, "No signature found on directory."); goto err;
- }
- ++cp;
- tokens = smartlist_new();
- if (tokenize_string(area,cp,strchr(cp,'\0'),tokens,dir_token_table,0)) {
- log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
- }
- if (smartlist_len(tokens) != 1) {
- log_warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
- }
- tok=smartlist_get(tokens,0);
- if (tok->tp != K_DIRECTORY_SIGNATURE) {
- log_warn(LD_DIR,"Expected a single directory signature"); goto err;
- }
- declared_key = find_dir_signing_key(str, str+strlen(str));
- note_crypto_pk_op(VERIFY_DIR);
- if (check_signature_token(digest, DIGEST_LEN, tok, declared_key,
- CST_CHECK_AUTHORITY, "directory")<0)
- goto err;
-
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_clear(tokens);
- memarea_clear(area);
-
- /* Now try to parse the first part of the directory. */
- if ((end = strstr(str,"\nrouter "))) {
- ++end;
- } else if ((end = strstr(str, "\ndirectory-signature"))) {
- ++end;
- } else {
- end = str + strlen(str);
- }
-
- if (tokenize_string(area,str,end,tokens,dir_token_table,0)) {
- log_warn(LD_DIR, "Error tokenizing directory"); goto err;
- }
-
- tok = find_by_keyword(tokens, K_PUBLISHED);
- tor_assert(tok->n_args == 1);
-
- if (parse_iso_time(tok->args[0], &published_on) < 0) {
- goto err;
- }
-
- /* Now that we know the signature is okay, and we have a
- * publication time, cache the directory. */
- if (directory_caches_v1_dir_info(get_options()) &&
- !authdir_mode_v1(get_options()))
- dirserv_set_cached_directory(str, published_on, 0);
-
- r = 0;
- goto done;
- err:
- dump_desc(str_dup, "v1 directory");
- r = -1;
- done:
- if (declared_key) crypto_pk_free(declared_key);
- if (tokens) {
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- }
- if (area) {
- DUMP_AREA(area, "v1 directory");
- memarea_drop_all(area);
- }
- return r;
-}
-
-/** Read a signed router status statement from <b>str</b>. If it's
- * well-formed, return 0. Otherwise, return -1. If we're a directory cache,
- * cache it.*/
-int
-router_parse_runningrouters(const char *str)
-{
- char digest[DIGEST_LEN];
- directory_token_t *tok;
- time_t published_on;
- int r = -1;
- crypto_pk_t *declared_key = NULL;
- smartlist_t *tokens = NULL;
- const char *eos = str + strlen(str), *str_dup = str;
- memarea_t *area = NULL;
-
- if (router_get_runningrouters_hash(str, digest)) {
- log_warn(LD_DIR, "Unable to compute digest of running-routers");
- goto err;
- }
- area = memarea_new();
- tokens = smartlist_new();
- if (tokenize_string(area,str,eos,tokens,dir_token_table,0)) {
- log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
- }
- tok = smartlist_get(tokens,0);
- if (tok->tp != K_NETWORK_STATUS) {
- log_warn(LD_DIR, "Network-status starts with wrong token");
- goto err;
- }
-
- tok = find_by_keyword(tokens, K_PUBLISHED);
- tor_assert(tok->n_args == 1);
- if (parse_iso_time(tok->args[0], &published_on) < 0) {
- goto err;
- }
- if (!(tok = find_opt_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
- log_warn(LD_DIR, "Missing signature on running-routers");
- goto err;
- }
- declared_key = find_dir_signing_key(str, eos);
- note_crypto_pk_op(VERIFY_DIR);
- if (check_signature_token(digest, DIGEST_LEN, tok, declared_key,
- CST_CHECK_AUTHORITY, "running-routers")
- < 0)
- goto err;
-
- /* Now that we know the signature is okay, and we have a
- * publication time, cache the list. */
- if (get_options()->DirPort_set && !authdir_mode_v1(get_options()))
- dirserv_set_cached_directory(str, published_on, 1);
-
- r = 0;
- err:
- dump_desc(str_dup, "v1 running-routers");
- if (declared_key) crypto_pk_free(declared_key);
- if (tokens) {
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- }
- if (area) {
- DUMP_AREA(area, "v1 running-routers");
- memarea_drop_all(area);
- }
- return r;
-}
-
-/** Given a directory or running-routers string in <b>str</b>, try to
- * find the its dir-signing-key token (if any). If this token is
- * present, extract and return the key. Return NULL on failure. */
-static crypto_pk_t *
-find_dir_signing_key(const char *str, const char *eos)
-{
- const char *cp;
- directory_token_t *tok;
- crypto_pk_t *key = NULL;
- memarea_t *area = NULL;
- tor_assert(str);
- tor_assert(eos);
-
- /* Is there a dir-signing-key in the directory? */
- cp = tor_memstr(str, eos-str, "\nopt dir-signing-key");
- if (!cp)
- cp = tor_memstr(str, eos-str, "\ndir-signing-key");
- if (!cp)
- return NULL;
- ++cp; /* Now cp points to the start of the token. */
-
- area = memarea_new();
- tok = get_next_token(area, &cp, eos, dir_token_table);
- if (!tok) {
- log_warn(LD_DIR, "Unparseable dir-signing-key token");
- goto done;
- }
- if (tok->tp != K_DIR_SIGNING_KEY) {
- log_warn(LD_DIR, "Dir-signing-key token did not parse as expected");
- goto done;
- }
-
- if (tok->key) {
- key = tok->key;
- tok->key = NULL; /* steal reference. */
- } else {
- log_warn(LD_DIR, "Dir-signing-key token contained no key");
- }
-
- done:
- if (tok) token_clear(tok);
- if (area) {
- DUMP_AREA(area, "dir-signing-key token");
- memarea_drop_all(area);
- }
- return key;
-}
-
/** Return true iff <b>key</b> is allowed to sign directories.
*/
static int
@@ -1257,6 +1033,43 @@ dump_distinct_digest_count(int severity)
#endif
}
+/** Try to find an IPv6 OR port in <b>list</b> of directory_token_t's
+ * with at least one argument (use GE(1) in setup). If found, store
+ * address and port number to <b>addr_out</b> and
+ * <b>port_out</b>. Return number of OR ports found. */
+static int
+find_single_ipv6_orport(const smartlist_t *list,
+ tor_addr_t *addr_out,
+ uint16_t *port_out)
+{
+ int ret = 0;
+ tor_assert(list != NULL);
+ tor_assert(addr_out != NULL);
+ tor_assert(port_out != NULL);
+
+ SMARTLIST_FOREACH_BEGIN(list, directory_token_t *, t) {
+ tor_addr_t a;
+ maskbits_t bits;
+ uint16_t port_min, port_max;
+ tor_assert(t->n_args >= 1);
+ /* XXXX Prop186 the full spec allows much more than this. */
+ if (tor_addr_parse_mask_ports(t->args[0], 0,
+ &a, &bits, &port_min,
+ &port_max) == AF_INET6 &&
+ bits == 128 &&
+ port_min == port_max) {
+ /* Okay, this is one we can understand. Use it and ignore
+ any potential more addresses in list. */
+ tor_addr_copy(addr_out, &a);
+ *port_out = port_min;
+ ret = 1;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(t);
+
+ return ret;
+}
+
/** Helper function: reads a single router entry from *<b>s</b> ...
* *<b>end</b>. Mallocs a new router and returns it if all goes well, else
* returns NULL. If <b>cache_copy</b> is true, duplicate the contents of
@@ -1513,21 +1326,8 @@ router_parse_entry_from_string(const char *s, const char *end,
{
smartlist_t *or_addresses = find_all_by_keyword(tokens, K_OR_ADDRESS);
if (or_addresses) {
- SMARTLIST_FOREACH_BEGIN(or_addresses, directory_token_t *, t) {
- tor_addr_t a;
- maskbits_t bits;
- uint16_t port_min, port_max;
- /* XXXX Prop186 the full spec allows much more than this. */
- if (tor_addr_parse_mask_ports(t->args[0], &a, &bits, &port_min,
- &port_max) == AF_INET6 &&
- bits == 128 &&
- port_min == port_max) {
- /* Okay, this is one we can understand. */
- tor_addr_copy(&router->ipv6_addr, &a);
- router->ipv6_orport = port_min;
- break;
- }
- } SMARTLIST_FOREACH_END(t);
+ find_single_ipv6_orport(or_addresses, &router->ipv6_addr,
+ &router->ipv6_orport);
smartlist_free(or_addresses);
}
}
@@ -1542,7 +1342,18 @@ router_parse_entry_from_string(const char *s, const char *end,
goto err;
});
policy_expand_private(&router->exit_policy);
- if (policy_is_reject_star(router->exit_policy))
+
+ if ((tok = find_opt_by_keyword(tokens, K_IPV6_POLICY)) && tok->n_args) {
+ router->ipv6_exit_policy = parse_short_policy(tok->args[0]);
+ if (! router->ipv6_exit_policy) {
+ log_warn(LD_DIR , "Error in ipv6-policy %s", escaped(tok->args[0]));
+ goto err;
+ }
+ }
+
+ if (policy_is_reject_star(router->exit_policy, AF_INET) &&
+ (!router->ipv6_exit_policy ||
+ short_policy_is_reject_star(router->ipv6_exit_policy)))
router->policy_is_reject_star = 1;
if ((tok = find_opt_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
@@ -2060,6 +1871,14 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset],
10,0,65535,NULL,NULL);
+ {
+ smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
+ if (a_lines) {
+ find_single_ipv6_orport(a_lines, &rs->ipv6_addr, &rs->ipv6_orport);
+ smartlist_free(a_lines);
+ }
+ }
+
tok = find_opt_by_keyword(tokens, K_S);
if (tok && vote) {
int i;
@@ -2067,7 +1886,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
for (i=0; i < tok->n_args; ++i) {
int p = smartlist_string_pos(vote->known_flags, tok->args[i]);
if (p >= 0) {
- vote_rs->flags |= (1<<p);
+ vote_rs->flags |= (U64_LITERAL(1)<<p);
} else {
log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.",
escaped(tok->args[i]));
@@ -2112,20 +1931,9 @@ routerstatus_parse_entry_from_string(memarea_t *area,
tor_assert(tok->n_args == 1);
rs->version_known = 1;
if (strcmpstart(tok->args[0], "Tor ")) {
- rs->version_supports_begindir = 1;
- rs->version_supports_extrainfo_upload = 1;
- rs->version_supports_conditional_consensus = 1;
rs->version_supports_microdesc_cache = 1;
rs->version_supports_optimistic_data = 1;
} else {
- rs->version_supports_begindir =
- tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
- rs->version_supports_extrainfo_upload =
- tor_version_as_new_as(tok->args[0], "0.2.0.0-alpha-dev (r10070)");
- rs->version_supports_v3_dir =
- tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha");
- rs->version_supports_conditional_consensus =
- tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha");
rs->version_supports_microdesc_cache =
tor_version_supports_microdescriptors(tok->args[0]);
rs->version_supports_optimistic_data =
@@ -2240,7 +2048,7 @@ compare_routerstatus_entries(const void **_a, const void **_b)
/** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */
static void
-_free_duplicate_routerstatus_entry(void *e)
+free_duplicate_routerstatus_entry_(void *e)
{
log_warn(LD_DIR,
"Network-status has two entries for the same router. "
@@ -2381,7 +2189,7 @@ networkstatus_v2_parse_from_string(const char *s)
}
smartlist_sort(ns->entries, compare_routerstatus_entries);
smartlist_uniq(ns->entries, compare_routerstatus_entries,
- _free_duplicate_routerstatus_entry);
+ free_duplicate_routerstatus_entry_);
if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) {
log_warn(LD_DIR, "Error tokenizing network-status footer.");
@@ -2981,6 +2789,16 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
log_warn(LD_DIR, "known-flags not in order");
goto err;
}
+ if (ns->type != NS_TYPE_CONSENSUS &&
+ smartlist_len(ns->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
+ /* If we allowed more than 64 flags in votes, then parsing them would make
+ * us invoke undefined behavior whenever we used 1<<flagnum to do a
+ * bit-shift. This is only for votes and opinions: consensus users don't
+ * care about flags they don't recognize, and so don't build a bitfield
+ * for them. */
+ log_warn(LD_DIR, "Too many known-flags in consensus vote or opinion");
+ goto err;
+ }
tok = find_opt_by_keyword(tokens, K_PARAMS);
if (tok) {
@@ -3599,6 +3417,10 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
/** Parse the addr policy in the string <b>s</b> and return it. If
* assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
* ADDR_POLICY_REJECT) for items that specify no action.
+ *
+ * The addr_policy_t returned by this function can have its address set to
+ * AF_UNSPEC for '*'. Use policy_expand_unspec() to turn this into a pair
+ * of AF_INET and AF_INET6 items.
*/
addr_policy_t *
router_parse_addr_policy_item_from_string(const char *s, int assume_action)
@@ -3628,7 +3450,7 @@ router_parse_addr_policy_item_from_string(const char *s, int assume_action)
eos = cp + strlen(cp);
area = memarea_new();
tok = get_next_token(area, &cp, eos, routerdesc_token_table);
- if (tok->tp == _ERR) {
+ if (tok->tp == ERR_) {
log_warn(LD_DIR, "Error reading address policy: %s", tok->error);
goto err;
}
@@ -3638,7 +3460,7 @@ router_parse_addr_policy_item_from_string(const char *s, int assume_action)
goto err;
}
- r = router_parse_addr_policy(tok);
+ r = router_parse_addr_policy(tok, TAPMP_EXTENDED_STAR);
goto done;
err:
r = NULL;
@@ -3657,7 +3479,7 @@ static int
router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
{
addr_policy_t *newe;
- newe = router_parse_addr_policy(tok);
+ newe = router_parse_addr_policy(tok, 0);
if (!newe)
return -1;
if (! router->exit_policy)
@@ -3682,7 +3504,7 @@ router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
/** Given a K_ACCEPT or K_REJECT token and a router, create and return
* a new exit_policy_t corresponding to the token. */
static addr_policy_t *
-router_parse_addr_policy(directory_token_t *tok)
+router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags)
{
addr_policy_t newe;
char *arg;
@@ -3704,7 +3526,7 @@ router_parse_addr_policy(directory_token_t *tok)
else
newe.policy_type = ADDR_POLICY_ACCEPT;
- if (tor_addr_parse_mask_ports(arg, &newe.addr, &newe.maskbits,
+ if (tor_addr_parse_mask_ports(arg, fmt_flags, &newe.addr, &newe.maskbits,
&newe.prt_min, &newe.prt_max) < 0) {
log_warn(LD_DIR,"Couldn't parse line %s. Dropping", escaped(arg));
return NULL;
@@ -3781,14 +3603,14 @@ token_clear(directory_token_t *tok)
STMT_BEGIN \
if (tok) token_clear(tok); \
tok = ALLOC_ZERO(sizeof(directory_token_t)); \
- tok->tp = _ERR; \
+ tok->tp = ERR_; \
tok->error = STRDUP(msg); \
goto done_tokenizing; \
STMT_END
/** Helper: make sure that the token <b>tok</b> with keyword <b>kwd</b> obeys
* the object syntax of <b>o_syn</b>. Allocate all storage in <b>area</b>.
- * Return <b>tok</b> on success, or a new _ERR token if the token didn't
+ * Return <b>tok</b> on success, or a new ERR_ token if the token didn't
* conform to the syntax we wanted.
**/
static INLINE directory_token_t *
@@ -3907,7 +3729,7 @@ get_next_token(memarea_t *area,
tor_assert(area);
tok = ALLOC_ZERO(sizeof(directory_token_t));
- tok->tp = _ERR;
+ tok->tp = ERR_;
/* Set *s to first token, eol to end-of-line, next to after first token */
*s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */
@@ -3964,10 +3786,10 @@ get_next_token(memarea_t *area,
}
}
- if (tok->tp == _ERR) {
+ if (tok->tp == ERR_) {
/* No keyword matched; call it an "K_opt" or "A_unrecognized" */
if (**s == '@')
- tok->tp = _A_UNKNOWN;
+ tok->tp = A_UNKNOWN_;
else
tok->tp = K_OPT;
tok->args = ALLOC(sizeof(char*));
@@ -4057,7 +3879,7 @@ tokenize_string(memarea_t *area,
{
const char **s;
directory_token_t *tok = NULL;
- int counts[_NIL];
+ int counts[NIL_];
int i;
int first_nonannotation;
int prev_len = smartlist_len(out);
@@ -4066,14 +3888,14 @@ tokenize_string(memarea_t *area,
s = &start;
if (!end)
end = start+strlen(start);
- for (i = 0; i < _NIL; ++i)
+ for (i = 0; i < NIL_; ++i)
counts[i] = 0;
SMARTLIST_FOREACH(out, const directory_token_t *, t, ++counts[t->tp]);
- while (*s < end && (!tok || tok->tp != _EOF)) {
+ while (*s < end && (!tok || tok->tp != EOF_)) {
tok = get_next_token(area, s, end, table);
- if (tok->tp == _ERR) {
+ if (tok->tp == ERR_) {
log_warn(LD_DIR, "parse error: %s", tok->error);
token_clear(tok);
return -1;
@@ -4163,7 +3985,7 @@ find_opt_by_keyword(smartlist_t *s, directory_keyword keyword)
* with an assert if no such keyword is found.
*/
static directory_token_t *
-_find_by_keyword(smartlist_t *s, directory_keyword keyword,
+find_by_keyword_(smartlist_t *s, directory_keyword keyword,
const char *keyword_as_string)
{
directory_token_t *tok = find_opt_by_keyword(s, keyword);
@@ -4251,8 +4073,8 @@ router_get_hash_impl_helper(const char *s, size_t s_len,
/** Compute the digest of the substring of <b>s</b> taken from the first
* occurrence of <b>start_str</b> through the first instance of c after the
- * first subsequent occurrence of <b>end_str</b>; store the 20-byte result in
- * <b>digest</b>; return 0 on success.
+ * first subsequent occurrence of <b>end_str</b>; store the 20-byte or 32-byte
+ * result in <b>digest</b>; return 0 on success.
*
* If no such substring exists, return -1.
*/
@@ -4421,6 +4243,14 @@ microdescs_parse_from_string(const char *s, const char *eos,
md->onion_pkey = tok->key;
tok->key = NULL;
+ {
+ smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
+ if (a_lines) {
+ find_single_ipv6_orport(a_lines, &md->ipv6_addr, &md->ipv6_orport);
+ smartlist_free(a_lines);
+ }
+ }
+
if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) {
int i;
md->family = smartlist_new();
@@ -4437,6 +4267,9 @@ microdescs_parse_from_string(const char *s, const char *eos,
if ((tok = find_opt_by_keyword(tokens, K_P))) {
md->exit_policy = parse_short_policy(tok->args[0]);
}
+ if ((tok = find_opt_by_keyword(tokens, K_P6))) {
+ md->ipv6_exit_policy = parse_short_policy(tok->args[0]);
+ }
crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
@@ -4654,7 +4487,7 @@ tor_version_same_series(tor_version_t *a, tor_version_t *b)
* if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent.
* Used to sort a list of versions. */
static int
-_compare_tor_version_str_ptr(const void **_a, const void **_b)
+compare_tor_version_str_ptr_(const void **_a, const void **_b)
{
const char *a = *_a, *b = *_b;
int ca, cb;
@@ -4678,10 +4511,10 @@ _compare_tor_version_str_ptr(const void **_a, const void **_b)
void
sort_version_list(smartlist_t *versions, int remove_duplicates)
{
- smartlist_sort(versions, _compare_tor_version_str_ptr);
+ smartlist_sort(versions, compare_tor_version_str_ptr_);
if (remove_duplicates)
- smartlist_uniq(versions, _compare_tor_version_str_ptr, _tor_free);
+ smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_);
}
/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
diff --git a/src/or/routerparse.h b/src/or/routerparse.h
index c6382a7f6b..256fcca579 100644
--- a/src/or/routerparse.h
+++ b/src/or/routerparse.h
@@ -9,8 +9,8 @@
* \brief Header file for routerparse.c.
**/
-#ifndef _TOR_ROUTERPARSE_H
-#define _TOR_ROUTERPARSE_H
+#ifndef TOR_ROUTERPARSE_H
+#define TOR_ROUTERPARSE_H
int router_get_router_hash(const char *s, size_t s_len, char *digest);
int router_get_dir_hash(const char *s, char *digest);
@@ -31,8 +31,6 @@ int router_parse_list_from_string(const char **s, const char *eos,
int is_extrainfo,
int allow_annotations,
const char *prepend_annotations);
-int router_parse_runningrouters(const char *str);
-int router_parse_directory(const char *str);
routerinfo_t *router_parse_entry_from_string(const char *s, const char *end,
int cache_copy,
diff --git a/src/or/routerset.c b/src/or/routerset.c
new file mode 100644
index 0000000000..a495863d8e
--- /dev/null
+++ b/src/or/routerset.c
@@ -0,0 +1,427 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "geoip.h"
+#include "nodelist.h"
+#include "policies.h"
+#include "router.h"
+#include "routerparse.h"
+#include "routerset.h"
+
+/** A routerset specifies constraints on a set of possible routerinfos, based
+ * on their names, identities, or addresses. It is optimized for determining
+ * whether a router is a member or not, in O(1+P) time, where P is the number
+ * of address policy constraints. */
+struct routerset_t {
+ /** A list of strings for the elements of the policy. Each string is either
+ * a nickname, a hexadecimal identity fingerprint, or an address policy. A
+ * router belongs to the set if its nickname OR its identity OR its address
+ * matches an entry here. */
+ smartlist_t *list;
+ /** A map from lowercase nicknames of routers in the set to (void*)1 */
+ strmap_t *names;
+ /** A map from identity digests routers in the set to (void*)1 */
+ digestmap_t *digests;
+ /** An address policy for routers in the set. For implementation reasons,
+ * a router belongs to the set if it is _rejected_ by this policy. */
+ smartlist_t *policies;
+
+ /** A human-readable description of what this routerset is for. Used in
+ * log messages. */
+ char *description;
+
+ /** A list of the country codes in this set. */
+ smartlist_t *country_names;
+ /** Total number of countries we knew about when we built <b>countries</b>.*/
+ int n_countries;
+ /** Bit array mapping the return value of geoip_get_country() to 1 iff the
+ * country is a member of this routerset. Note that we MUST call
+ * routerset_refresh_countries() whenever the geoip country list is
+ * reloaded. */
+ bitarray_t *countries;
+};
+
+/** Return a new empty routerset. */
+routerset_t *
+routerset_new(void)
+{
+ routerset_t *result = tor_malloc_zero(sizeof(routerset_t));
+ result->list = smartlist_new();
+ result->names = strmap_new();
+ result->digests = digestmap_new();
+ result->policies = smartlist_new();
+ result->country_names = smartlist_new();
+ return result;
+}
+
+/** If <b>c</b> is a country code in the form {cc}, return a newly allocated
+ * string holding the "cc" part. Else, return NULL. */
+static char *
+routerset_get_countryname(const char *c)
+{
+ char *country;
+
+ if (strlen(c) < 4 || c[0] !='{' || c[3] !='}')
+ return NULL;
+
+ country = tor_strndup(c+1, 2);
+ tor_strlower(country);
+ return country;
+}
+
+/** Update the routerset's <b>countries</b> bitarray_t. Called whenever
+ * the GeoIP IPv4 database is reloaded.
+ */
+void
+routerset_refresh_countries(routerset_t *target)
+{
+ int cc;
+ bitarray_free(target->countries);
+
+ if (!geoip_is_loaded(AF_INET)) {
+ target->countries = NULL;
+ target->n_countries = 0;
+ return;
+ }
+ target->n_countries = geoip_get_n_countries();
+ target->countries = bitarray_init_zero(target->n_countries);
+ SMARTLIST_FOREACH_BEGIN(target->country_names, const char *, country) {
+ cc = geoip_get_country(country);
+ if (cc >= 0) {
+ tor_assert(cc < target->n_countries);
+ bitarray_set(target->countries, cc);
+ } else {
+ log(LOG_WARN, LD_CONFIG, "Country code '%s' is not recognized.",
+ country);
+ }
+ } SMARTLIST_FOREACH_END(country);
+}
+
+/** Parse the string <b>s</b> to create a set of routerset entries, and add
+ * them to <b>target</b>. In log messages, refer to the string as
+ * <b>description</b>. Return 0 on success, -1 on failure.
+ *
+ * Three kinds of elements are allowed in routersets: nicknames, IP address
+ * patterns, and fingerprints. They may be surrounded by optional space, and
+ * must be separated by commas.
+ */
+int
+routerset_parse(routerset_t *target, const char *s, const char *description)
+{
+ int r = 0;
+ int added_countries = 0;
+ char *countryname;
+ smartlist_t *list = smartlist_new();
+ smartlist_split_string(list, s, ",",
+ SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0);
+ SMARTLIST_FOREACH_BEGIN(list, char *, nick) {
+ addr_policy_t *p;
+ if (is_legal_hexdigest(nick)) {
+ char d[DIGEST_LEN];
+ if (*nick == '$')
+ ++nick;
+ log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description);
+ base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN);
+ digestmap_set(target->digests, d, (void*)1);
+ } else if (is_legal_nickname(nick)) {
+ log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description);
+ strmap_set_lc(target->names, nick, (void*)1);
+ } else if ((countryname = routerset_get_countryname(nick)) != NULL) {
+ log_debug(LD_CONFIG, "Adding country %s to %s", nick,
+ description);
+ smartlist_add(target->country_names, countryname);
+ added_countries = 1;
+ } else if ((strchr(nick,'.') || strchr(nick, '*')) &&
+ (p = router_parse_addr_policy_item_from_string(
+ nick, ADDR_POLICY_REJECT))) {
+ log_debug(LD_CONFIG, "Adding address %s to %s", nick, description);
+ smartlist_add(target->policies, p);
+ } else {
+ log_warn(LD_CONFIG, "Entry '%s' in %s is misformed.", nick,
+ description);
+ r = -1;
+ tor_free(nick);
+ SMARTLIST_DEL_CURRENT(list, nick);
+ }
+ } SMARTLIST_FOREACH_END(nick);
+ policy_expand_unspec(&target->policies);
+ smartlist_add_all(target->list, list);
+ smartlist_free(list);
+ if (added_countries)
+ routerset_refresh_countries(target);
+ return r;
+}
+
+/** Add all members of the set <b>source</b> to <b>target</b>. */
+void
+routerset_union(routerset_t *target, const routerset_t *source)
+{
+ char *s;
+ tor_assert(target);
+ if (!source || !source->list)
+ return;
+ s = routerset_to_string(source);
+ routerset_parse(target, s, "other routerset");
+ tor_free(s);
+}
+
+/** Return true iff <b>set</b> lists only nicknames and digests, and includes
+ * no IP ranges or countries. */
+int
+routerset_is_list(const routerset_t *set)
+{
+ return smartlist_len(set->country_names) == 0 &&
+ smartlist_len(set->policies) == 0;
+}
+
+/** Return true iff we need a GeoIP IP-to-country database to make sense of
+ * <b>set</b>. */
+int
+routerset_needs_geoip(const routerset_t *set)
+{
+ return set && smartlist_len(set->country_names);
+}
+
+/** Return true iff there are no entries in <b>set</b>. */
+int
+routerset_is_empty(const routerset_t *set)
+{
+ return !set || smartlist_len(set->list) == 0;
+}
+
+/** Helper. Return true iff <b>set</b> contains a router based on the other
+ * provided fields. Return higher values for more specific subentries: a
+ * single router is more specific than an address range of routers, which is
+ * more specific in turn than a country code.
+ *
+ * (If country is -1, then we take the country
+ * from addr.) */
+static int
+routerset_contains(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport,
+ const char *nickname, const char *id_digest,
+ country_t country)
+{
+ if (!set || !set->list)
+ return 0;
+ if (nickname && strmap_get_lc(set->names, nickname))
+ return 4;
+ if (id_digest && digestmap_get(set->digests, id_digest))
+ return 4;
+ if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
+ == ADDR_POLICY_REJECTED)
+ return 3;
+ if (set->countries) {
+ if (country < 0 && addr)
+ country = geoip_get_country_by_addr(addr);
+
+ if (country >= 0 && country < set->n_countries &&
+ bitarray_is_set(set->countries, country))
+ return 2;
+ }
+ return 0;
+}
+
+/** Return true iff we can tell that <b>ei</b> is a member of <b>set</b>. */
+int
+routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei)
+{
+ return routerset_contains(set,
+ &ei->addr,
+ ei->port,
+ ei->nickname,
+ ei->identity_digest,
+ -1 /*country*/);
+}
+
+/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we
+ * look up the country. */
+int
+routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
+ country_t country)
+{
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, ri->addr);
+ return routerset_contains(set,
+ &addr,
+ ri->or_port,
+ ri->nickname,
+ ri->cache_info.identity_digest,
+ country);
+}
+
+/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we
+ * look up the country. */
+int
+routerset_contains_routerstatus(const routerset_t *set,
+ const routerstatus_t *rs,
+ country_t country)
+{
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, rs->addr);
+ return routerset_contains(set,
+ &addr,
+ rs->or_port,
+ rs->nickname,
+ rs->identity_digest,
+ country);
+}
+
+/** Return true iff <b>node</b> is in <b>set</b>. */
+int
+routerset_contains_node(const routerset_t *set, const node_t *node)
+{
+ if (node->rs)
+ return routerset_contains_routerstatus(set, node->rs, node->country);
+ else if (node->ri)
+ return routerset_contains_router(set, node->ri, node->country);
+ else
+ return 0;
+}
+
+/** Add every known node_t that is a member of <b>routerset</b> to
+ * <b>out</b>, but never add any that are part of <b>excludeset</b>.
+ * If <b>running_only</b>, only add the running ones. */
+void
+routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
+ const routerset_t *excludeset, int running_only)
+{
+ tor_assert(out);
+ if (!routerset || !routerset->list)
+ return;
+
+ if (routerset_is_list(routerset)) {
+ /* No routers are specified by type; all are given by name or digest.
+ * we can do a lookup in O(len(routerset)). */
+ SMARTLIST_FOREACH(routerset->list, const char *, name, {
+ const node_t *node = node_get_by_nickname(name, 1);
+ if (node) {
+ if (!running_only || node->is_running)
+ if (!routerset_contains_node(excludeset, node))
+ smartlist_add(out, (void*)node);
+ }
+ });
+ } else {
+ /* We need to iterate over the routerlist to get all the ones of the
+ * right kind. */
+ smartlist_t *nodes = nodelist_get_list();
+ SMARTLIST_FOREACH(nodes, const node_t *, node, {
+ if (running_only && !node->is_running)
+ continue;
+ if (routerset_contains_node(routerset, node) &&
+ !routerset_contains_node(excludeset, node))
+ smartlist_add(out, (void*)node);
+ });
+ }
+}
+
+#if 0
+/** Add to <b>target</b> every node_t from <b>source</b> except:
+ *
+ * 1) Don't add it if <b>include</b> is non-empty and the relay isn't in
+ * <b>include</b>; and
+ * 2) Don't add it if <b>exclude</b> is non-empty and the relay is
+ * excluded in a more specific fashion by <b>exclude</b>.
+ * 3) If <b>running_only</b>, don't add non-running routers.
+ */
+void
+routersets_get_node_disjunction(smartlist_t *target,
+ const smartlist_t *source,
+ const routerset_t *include,
+ const routerset_t *exclude, int running_only)
+{
+ SMARTLIST_FOREACH(source, const node_t *, node, {
+ int include_result;
+ if (running_only && !node->is_running)
+ continue;
+ if (!routerset_is_empty(include))
+ include_result = routerset_contains_node(include, node);
+ else
+ include_result = 1;
+
+ if (include_result) {
+ int exclude_result = routerset_contains_node(exclude, node);
+ if (include_result >= exclude_result)
+ smartlist_add(target, (void*)node);
+ }
+ });
+}
+#endif
+
+/** Remove every node_t from <b>lst</b> that is in <b>routerset</b>. */
+void
+routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset)
+{
+ tor_assert(lst);
+ if (!routerset)
+ return;
+ SMARTLIST_FOREACH(lst, const node_t *, node, {
+ if (routerset_contains_node(routerset, node)) {
+ //log_debug(LD_DIR, "Subtracting %s",r->nickname);
+ SMARTLIST_DEL_CURRENT(lst, node);
+ }
+ });
+}
+
+/** Return a new string that when parsed by routerset_parse_string() will
+ * yield <b>set</b>. */
+char *
+routerset_to_string(const routerset_t *set)
+{
+ if (!set || !set->list)
+ return tor_strdup("");
+ return smartlist_join_strings(set->list, ",", 0, NULL);
+}
+
+/** Helper: return true iff old and new are both NULL, or both non-NULL
+ * equal routersets. */
+int
+routerset_equal(const routerset_t *old, const routerset_t *new)
+{
+ if (routerset_is_empty(old) && routerset_is_empty(new)) {
+ /* Two empty sets are equal */
+ return 1;
+ } else if (routerset_is_empty(old) || routerset_is_empty(new)) {
+ /* An empty set is equal to nothing else. */
+ return 0;
+ }
+ tor_assert(old != NULL);
+ tor_assert(new != NULL);
+
+ if (smartlist_len(old->list) != smartlist_len(new->list))
+ return 0;
+
+ SMARTLIST_FOREACH(old->list, const char *, cp1, {
+ const char *cp2 = smartlist_get(new->list, cp1_sl_idx);
+ if (strcmp(cp1, cp2))
+ return 0;
+ });
+
+ return 1;
+}
+
+/** Free all storage held in <b>routerset</b>. */
+void
+routerset_free(routerset_t *routerset)
+{
+ if (!routerset)
+ return;
+
+ SMARTLIST_FOREACH(routerset->list, char *, cp, tor_free(cp));
+ smartlist_free(routerset->list);
+ SMARTLIST_FOREACH(routerset->policies, addr_policy_t *, p,
+ addr_policy_free(p));
+ smartlist_free(routerset->policies);
+ SMARTLIST_FOREACH(routerset->country_names, char *, cp, tor_free(cp));
+ smartlist_free(routerset->country_names);
+
+ strmap_free(routerset->names, NULL);
+ digestmap_free(routerset->digests, NULL);
+ bitarray_free(routerset->countries);
+ tor_free(routerset);
+}
+
diff --git a/src/or/routerset.h b/src/or/routerset.h
new file mode 100644
index 0000000000..ad0832e4df
--- /dev/null
+++ b/src/or/routerset.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file routerlist.h
+ * \brief Header file for routerset.c
+ **/
+
+#ifndef TOR_ROUTERSET_H
+#define TOR_ROUTERSET_H
+
+routerset_t *routerset_new(void);
+void routerset_refresh_countries(routerset_t *rs);
+int routerset_parse(routerset_t *target, const char *s,
+ const char *description);
+void routerset_union(routerset_t *target, const routerset_t *source);
+int routerset_is_list(const routerset_t *set);
+int routerset_needs_geoip(const routerset_t *set);
+int routerset_is_empty(const routerset_t *set);
+int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
+ country_t country);
+int routerset_contains_routerstatus(const routerset_t *set,
+ const routerstatus_t *rs,
+ country_t country);
+int routerset_contains_extendinfo(const routerset_t *set,
+ const extend_info_t *ei);
+
+int routerset_contains_node(const routerset_t *set, const node_t *node);
+void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
+ const routerset_t *excludeset,
+ int running_only);
+#if 0
+void routersets_get_node_disjunction(smartlist_t *target,
+ const smartlist_t *source,
+ const routerset_t *include,
+ const routerset_t *exclude, int running_only);
+#endif
+void routerset_subtract_nodes(smartlist_t *out,
+ const routerset_t *routerset);
+
+char *routerset_to_string(const routerset_t *routerset);
+int routerset_equal(const routerset_t *old, const routerset_t *new);
+void routerset_free(routerset_t *routerset);
+
+#endif
+
diff --git a/src/or/statefile.c b/src/or/statefile.c
new file mode 100644
index 0000000000..1429efda12
--- /dev/null
+++ b/src/or/statefile.c
@@ -0,0 +1,615 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "circuitstats.h"
+#include "config.h"
+#include "confparse.h"
+#include "entrynodes.h"
+#include "hibernate.h"
+#include "rephist.h"
+#include "router.h"
+#include "statefile.h"
+
+/** A list of state-file "abbreviations," for compatibility. */
+static config_abbrev_t state_abbrevs_[] = {
+ { "AccountingBytesReadInterval", "AccountingBytesReadInInterval", 0, 0 },
+ { "HelperNode", "EntryGuard", 0, 0 },
+ { "HelperNodeDownSince", "EntryGuardDownSince", 0, 0 },
+ { "HelperNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
+ { "EntryNode", "EntryGuard", 0, 0 },
+ { "EntryNodeDownSince", "EntryGuardDownSince", 0, 0 },
+ { "EntryNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
+ { NULL, NULL, 0, 0},
+};
+
+/*XXXX these next two are duplicates or near-duplicates from config.c */
+#define VAR(name,conftype,member,initvalue) \
+ { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_state_t, member), \
+ initvalue }
+/** As VAR, but the option name and member name are the same. */
+#define V(member,conftype,initvalue) \
+ VAR(#member, conftype, member, initvalue)
+
+/** Array of "state" variables saved to the ~/.tor/state file. */
+static config_var_t state_vars_[] = {
+ /* Remember to document these in state-contents.txt ! */
+
+ V(AccountingBytesReadInInterval, MEMUNIT, NULL),
+ V(AccountingBytesWrittenInInterval, MEMUNIT, NULL),
+ V(AccountingExpectedUsage, MEMUNIT, NULL),
+ V(AccountingIntervalStart, ISOTIME, NULL),
+ V(AccountingSecondsActive, INTERVAL, NULL),
+ V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL),
+ V(AccountingSoftLimitHitAt, ISOTIME, NULL),
+ V(AccountingBytesAtSoftLimit, MEMUNIT, NULL),
+
+ VAR("EntryGuard", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardUnlistedSince", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardPathBias", LINELIST_S, EntryGuards, NULL),
+ V(EntryGuards, LINELIST_V, NULL),
+
+ VAR("TransportProxy", LINELIST_S, TransportProxies, NULL),
+ V(TransportProxies, LINELIST_V, NULL),
+
+ V(BWHistoryReadEnds, ISOTIME, NULL),
+ V(BWHistoryReadInterval, UINT, "900"),
+ V(BWHistoryReadValues, CSV, ""),
+ V(BWHistoryReadMaxima, CSV, ""),
+ V(BWHistoryWriteEnds, ISOTIME, NULL),
+ V(BWHistoryWriteInterval, UINT, "900"),
+ V(BWHistoryWriteValues, CSV, ""),
+ V(BWHistoryWriteMaxima, CSV, ""),
+ V(BWHistoryDirReadEnds, ISOTIME, NULL),
+ V(BWHistoryDirReadInterval, UINT, "900"),
+ V(BWHistoryDirReadValues, CSV, ""),
+ V(BWHistoryDirReadMaxima, CSV, ""),
+ V(BWHistoryDirWriteEnds, ISOTIME, NULL),
+ V(BWHistoryDirWriteInterval, UINT, "900"),
+ V(BWHistoryDirWriteValues, CSV, ""),
+ V(BWHistoryDirWriteMaxima, CSV, ""),
+
+ V(TorVersion, STRING, NULL),
+
+ V(LastRotatedOnionKey, ISOTIME, NULL),
+ V(LastWritten, ISOTIME, NULL),
+
+ V(TotalBuildTimes, UINT, NULL),
+ V(CircuitBuildAbandonedCount, UINT, "0"),
+ VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
+ VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
+ { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
+};
+
+#undef VAR
+#undef V
+
+static int or_state_validate(or_state_t *old_options, or_state_t *options,
+ int from_setconf, char **msg);
+
+/** Magic value for or_state_t. */
+#define OR_STATE_MAGIC 0x57A73f57
+
+/** "Extra" variable in the state that receives lines we can't parse. This
+ * lets us preserve options from versions of Tor newer than us. */
+static config_var_t state_extra_var = {
+ "__extra", CONFIG_TYPE_LINELIST, STRUCT_OFFSET(or_state_t, ExtraLines), NULL
+};
+
+/** Configuration format for or_state_t. */
+static const config_format_t state_format = {
+ sizeof(or_state_t),
+ OR_STATE_MAGIC,
+ STRUCT_OFFSET(or_state_t, magic_),
+ state_abbrevs_,
+ state_vars_,
+ (validate_fn_t)or_state_validate,
+ &state_extra_var,
+};
+
+/** Persistent serialized state. */
+static or_state_t *global_state = NULL;
+
+/** Return the persistent state struct for this Tor. */
+or_state_t *
+get_or_state(void)
+{
+ tor_assert(global_state);
+ return global_state;
+}
+
+/** Return true iff we have loaded the global state for this Tor */
+int
+or_state_loaded(void)
+{
+ return global_state != NULL;
+}
+
+/** Return true if <b>line</b> is a valid state TransportProxy line.
+ * Return false otherwise. */
+static int
+state_transport_line_is_valid(const char *line)
+{
+ smartlist_t *items = NULL;
+ char *addrport=NULL;
+ tor_addr_t addr;
+ uint16_t port = 0;
+ int r;
+
+ items = smartlist_new();
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(items) != 2) {
+ log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line.");
+ goto err;
+ }
+
+ addrport = smartlist_get(items, 1);
+ if (tor_addr_port_lookup(addrport, &addr, &port) < 0) {
+ log_warn(LD_CONFIG, "state: Could not parse addrport.");
+ goto err;
+ }
+
+ if (!port) {
+ log_warn(LD_CONFIG, "state: Transport line did not contain port.");
+ goto err;
+ }
+
+ r = 1;
+ goto done;
+
+ err:
+ r = 0;
+
+ done:
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+ return r;
+}
+
+/** Return 0 if all TransportProxy lines in <b>state</b> are well
+ * formed. Otherwise, return -1. */
+static int
+validate_transports_in_state(or_state_t *state)
+{
+ int broken = 0;
+ config_line_t *line;
+
+ for (line = state->TransportProxies ; line ; line = line->next) {
+ tor_assert(!strcmp(line->key, "TransportProxy"));
+ if (!state_transport_line_is_valid(line->value))
+ broken = 1;
+ }
+
+ if (broken)
+ log_warn(LD_CONFIG, "state: State file seems to be broken.");
+
+ return 0;
+}
+
+/** Return 0 if every setting in <b>state</b> is reasonable, and a
+ * permissible transition from <b>old_state</b>. Else warn and return -1.
+ * Should have no side effects, except for normalizing the contents of
+ * <b>state</b>.
+ */
+/* XXX from_setconf is here because of bug 238 */
+static int
+or_state_validate(or_state_t *old_state, or_state_t *state,
+ int from_setconf, char **msg)
+{
+ /* We don't use these; only options do. Still, we need to match that
+ * signature. */
+ (void) from_setconf;
+ (void) old_state;
+
+ if (entry_guards_parse_state(state, 0, msg)<0)
+ return -1;
+
+ if (validate_transports_in_state(state)<0)
+ return -1;
+
+ return 0;
+}
+
+/** Replace the current persistent state with <b>new_state</b> */
+static int
+or_state_set(or_state_t *new_state)
+{
+ char *err = NULL;
+ int ret = 0;
+ tor_assert(new_state);
+ config_free(&state_format, global_state);
+ global_state = new_state;
+ if (entry_guards_parse_state(global_state, 1, &err)<0) {
+ log_warn(LD_GENERAL,"%s",err);
+ tor_free(err);
+ ret = -1;
+ }
+ if (rep_hist_load_state(global_state, &err)<0) {
+ log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
+ tor_free(err);
+ ret = -1;
+ }
+ if (circuit_build_times_parse_state(&circ_times, global_state) < 0) {
+ ret = -1;
+ }
+ return ret;
+}
+
+/**
+ * Save a broken state file to a backup location.
+ */
+static void
+or_state_save_broken(char *fname)
+{
+ int i;
+ file_status_t status;
+ char *fname2 = NULL;
+ for (i = 0; i < 100; ++i) {
+ tor_asprintf(&fname2, "%s.%d", fname, i);
+ status = file_status(fname2);
+ if (status == FN_NOENT)
+ break;
+ tor_free(fname2);
+ }
+ if (i == 100) {
+ log_warn(LD_BUG, "Unable to parse state in \"%s\"; too many saved bad "
+ "state files to move aside. Discarding the old state file.",
+ fname);
+ unlink(fname);
+ } else {
+ log_warn(LD_BUG, "Unable to parse state in \"%s\". Moving it aside "
+ "to \"%s\". This could be a bug in Tor; please tell "
+ "the developers.", fname, fname2);
+ if (rename(fname, fname2) < 0) {
+ log_warn(LD_BUG, "Weirdly, I couldn't even move the state aside. The "
+ "OS gave an error of %s", strerror(errno));
+ }
+ }
+ tor_free(fname2);
+}
+
+/** Reload the persistent state from disk, generating a new state as needed.
+ * Return 0 on success, less than 0 on failure.
+ */
+int
+or_state_load(void)
+{
+ or_state_t *new_state = NULL;
+ char *contents = NULL, *fname;
+ char *errmsg = NULL;
+ int r = -1, badstate = 0;
+
+ fname = get_datadir_fname("state");
+ switch (file_status(fname)) {
+ case FN_FILE:
+ if (!(contents = read_file_to_str(fname, 0, NULL))) {
+ log_warn(LD_FS, "Unable to read state file \"%s\"", fname);
+ goto done;
+ }
+ break;
+ case FN_NOENT:
+ break;
+ case FN_ERROR:
+ case FN_DIR:
+ default:
+ log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname);
+ goto done;
+ }
+ new_state = tor_malloc_zero(sizeof(or_state_t));
+ new_state->magic_ = OR_STATE_MAGIC;
+ config_init(&state_format, new_state);
+ if (contents) {
+ config_line_t *lines=NULL;
+ int assign_retval;
+ if (config_get_lines(contents, &lines, 0)<0)
+ goto done;
+ assign_retval = config_assign(&state_format, new_state,
+ lines, 0, 0, &errmsg);
+ config_free_lines(lines);
+ if (assign_retval<0)
+ badstate = 1;
+ if (errmsg) {
+ log_warn(LD_GENERAL, "%s", errmsg);
+ tor_free(errmsg);
+ }
+ }
+
+ if (!badstate && or_state_validate(NULL, new_state, 1, &errmsg) < 0)
+ badstate = 1;
+
+ if (errmsg) {
+ log_warn(LD_GENERAL, "%s", errmsg);
+ tor_free(errmsg);
+ }
+
+ if (badstate && !contents) {
+ log_warn(LD_BUG, "Uh oh. We couldn't even validate our own default state."
+ " This is a bug in Tor.");
+ goto done;
+ } else if (badstate && contents) {
+ or_state_save_broken(fname);
+
+ tor_free(contents);
+ config_free(&state_format, new_state);
+
+ new_state = tor_malloc_zero(sizeof(or_state_t));
+ new_state->magic_ = OR_STATE_MAGIC;
+ config_init(&state_format, new_state);
+ } else if (contents) {
+ log_info(LD_GENERAL, "Loaded state from \"%s\"", fname);
+ } else {
+ log_info(LD_GENERAL, "Initialized state");
+ }
+ if (or_state_set(new_state) == -1) {
+ or_state_save_broken(fname);
+ }
+ new_state = NULL;
+ if (!contents) {
+ global_state->next_write = 0;
+ or_state_save(time(NULL));
+ }
+ r = 0;
+
+ done:
+ tor_free(fname);
+ tor_free(contents);
+ if (new_state)
+ config_free(&state_format, new_state);
+
+ return r;
+}
+
+/** Did the last time we tried to write the state file fail? If so, we
+ * should consider disabling such features as preemptive circuit generation
+ * to compute circuit-build-time. */
+static int last_state_file_write_failed = 0;
+
+/** Return whether the state file failed to write last time we tried. */
+int
+did_last_state_file_write_fail(void)
+{
+ return last_state_file_write_failed;
+}
+
+/** If writing the state to disk fails, try again after this many seconds. */
+#define STATE_WRITE_RETRY_INTERVAL 3600
+
+/** If we're a relay, how often should we checkpoint our state file even
+ * if nothing else dirties it? This will checkpoint ongoing stats like
+ * bandwidth used, per-country user stats, etc. */
+#define STATE_RELAY_CHECKPOINT_INTERVAL (12*60*60)
+
+/** Write the persistent state to disk. Return 0 for success, <0 on failure. */
+int
+or_state_save(time_t now)
+{
+ char *state, *contents;
+ char tbuf[ISO_TIME_LEN+1];
+ char *fname;
+
+ tor_assert(global_state);
+
+ if (global_state->next_write > now)
+ return 0;
+
+ /* Call everything else that might dirty the state even more, in order
+ * to avoid redundant writes. */
+ entry_guards_update_state(global_state);
+ rep_hist_update_state(global_state);
+ circuit_build_times_update_state(&circ_times, global_state);
+ if (accounting_is_enabled(get_options()))
+ accounting_run_housekeeping(now);
+
+ global_state->LastWritten = now;
+
+ tor_free(global_state->TorVersion);
+ tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
+
+ state = config_dump(&state_format, NULL, global_state, 1, 0);
+ format_local_iso_time(tbuf, now);
+ tor_asprintf(&contents,
+ "# Tor state file last generated on %s local time\n"
+ "# Other times below are in UTC\n"
+ "# You *do not* need to edit this file.\n\n%s",
+ tbuf, state);
+ tor_free(state);
+ fname = get_datadir_fname("state");
+ if (write_str_to_file(fname, contents, 0)<0) {
+ log_warn(LD_FS, "Unable to write state to file \"%s\"; "
+ "will try again later", fname);
+ last_state_file_write_failed = 1;
+ tor_free(fname);
+ tor_free(contents);
+ /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state
+ * changes sooner). */
+ global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL;
+ return -1;
+ }
+
+ last_state_file_write_failed = 0;
+ log_info(LD_GENERAL, "Saved state to \"%s\"", fname);
+ tor_free(fname);
+ tor_free(contents);
+
+ if (server_mode(get_options()))
+ global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL;
+ else
+ global_state->next_write = TIME_MAX;
+
+ return 0;
+}
+
+/** Return the config line for transport <b>transport</b> in the current state.
+ * Return NULL if there is no config line for <b>transport</b>. */
+static config_line_t *
+get_transport_in_state_by_name(const char *transport)
+{
+ or_state_t *or_state = get_or_state();
+ config_line_t *line;
+ config_line_t *ret = NULL;
+ smartlist_t *items = NULL;
+
+ for (line = or_state->TransportProxies ; line ; line = line->next) {
+ tor_assert(!strcmp(line->key, "TransportProxy"));
+
+ items = smartlist_new();
+ smartlist_split_string(items, line->value, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+ if (smartlist_len(items) != 2) /* broken state */
+ goto done;
+
+ if (!strcmp(smartlist_get(items, 0), transport)) {
+ ret = line;
+ goto done;
+ }
+
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+ items = NULL;
+ }
+
+ done:
+ if (items) {
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+ }
+ return ret;
+}
+
+/** Return string containing the address:port part of the
+ * TransportProxy <b>line</b> for transport <b>transport</b>.
+ * If the line is corrupted, return NULL. */
+static const char *
+get_transport_bindaddr(const char *line, const char *transport)
+{
+ char *line_tmp = NULL;
+
+ if (strlen(line) < strlen(transport) + 2) {
+ goto broken_state;
+ } else {
+ /* line should start with the name of the transport and a space.
+ (for example, "obfs2 127.0.0.1:47245") */
+ tor_asprintf(&line_tmp, "%s ", transport);
+ if (strcmpstart(line, line_tmp))
+ goto broken_state;
+
+ tor_free(line_tmp);
+ return (line+strlen(transport)+1);
+ }
+
+ broken_state:
+ tor_free(line_tmp);
+ return NULL;
+}
+
+/** Return a string containing the address:port that a proxy transport
+ * should bind on. The string is stored on the heap and must be freed
+ * by the caller of this function. */
+char *
+get_stored_bindaddr_for_server_transport(const char *transport)
+{
+ char *default_addrport = NULL;
+ const char *stored_bindaddr = NULL;
+ config_line_t *line = NULL;
+
+ {
+ /* See if the user explicitly asked for a specific listening
+ address for this transport. */
+ char *conf_bindaddr = get_transport_bindaddr_from_config(transport);
+ if (conf_bindaddr)
+ return conf_bindaddr;
+ }
+
+ line = get_transport_in_state_by_name(transport);
+ if (!line) /* Found no references in state for this transport. */
+ goto no_bindaddr_found;
+
+ stored_bindaddr = get_transport_bindaddr(line->value, transport);
+ if (stored_bindaddr) /* found stored bindaddr in state file. */
+ return tor_strdup(stored_bindaddr);
+
+ no_bindaddr_found:
+ /** If we didn't find references for this pluggable transport in the
+ state file, we should instruct the pluggable transport proxy to
+ listen on INADDR_ANY on a random ephemeral port. */
+ tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0");
+ return default_addrport;
+}
+
+/** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to
+ state */
+void
+save_transport_to_state(const char *transport,
+ const tor_addr_t *addr, uint16_t port)
+{
+ or_state_t *state = get_or_state();
+
+ char *transport_addrport=NULL;
+
+ /** find where to write on the state */
+ config_line_t **next, *line;
+
+ /* see if this transport is already stored in state */
+ config_line_t *transport_line =
+ get_transport_in_state_by_name(transport);
+
+ if (transport_line) { /* if transport already exists in state... */
+ const char *prev_bindaddr = /* get its addrport... */
+ get_transport_bindaddr(transport_line->value, transport);
+ transport_addrport = tor_strdup(fmt_addrport(addr, port));
+
+ /* if transport in state has the same address as this one, life is good */
+ if (!strcmp(prev_bindaddr, transport_addrport)) {
+ log_info(LD_CONFIG, "Transport seems to have spawned on its usual "
+ "address:port.");
+ goto done;
+ } else { /* if addrport in state is different than the one we got */
+ log_info(LD_CONFIG, "Transport seems to have spawned on different "
+ "address:port. Let's update the state file with the new "
+ "address:port");
+ tor_free(transport_line->value); /* free the old line */
+ /* replace old addrport line with new line */
+ tor_asprintf(&transport_line->value, "%s %s", transport,
+ fmt_addrport(addr, port));
+ }
+ } else { /* never seen this one before; save it in state for next time */
+ log_info(LD_CONFIG, "It's the first time we see this transport. "
+ "Let's save its address:port");
+ next = &state->TransportProxies;
+ /* find the last TransportProxy line in the state and point 'next'
+ right after it */
+ line = state->TransportProxies;
+ while (line) {
+ next = &(line->next);
+ line = line->next;
+ }
+
+ /* allocate space for the new line and fill it in */
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("TransportProxy");
+ tor_asprintf(&line->value, "%s %s", transport, fmt_addrport(addr, port));
+
+ next = &(line->next);
+ }
+
+ if (!get_options()->AvoidDiskWrites)
+ or_state_mark_dirty(state, 0);
+
+ done:
+ tor_free(transport_addrport);
+}
+
+void
+or_state_free_all(void)
+{
+ config_free(&state_format, global_state);
+ global_state = NULL;
+}
+
diff --git a/src/or/statefile.h b/src/or/statefile.h
new file mode 100644
index 0000000000..4770d500d1
--- /dev/null
+++ b/src/or/statefile.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_STATEFILE_H
+#define TOR_STATEFILE_H
+
+or_state_t *get_or_state(void);
+int did_last_state_file_write_fail(void);
+int or_state_save(time_t now);
+
+void save_transport_to_state(const char *transport_name,
+ const tor_addr_t *addr, uint16_t port);
+char *get_stored_bindaddr_for_server_transport(const char *transport);
+int or_state_load(void);
+int or_state_loaded(void);
+void or_state_free_all(void);
+
+#endif
+
diff --git a/src/or/status.c b/src/or/status.c
index 04cd96eed5..fc01d0a242 100644
--- a/src/or/status.c
+++ b/src/or/status.c
@@ -21,7 +21,7 @@ count_circuits(void)
circuit_t *circ;
int nr=0;
- for (circ = _circuit_get_global_list(); circ; circ = circ->next)
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next)
nr++;
return nr;
diff --git a/src/or/status.h b/src/or/status.h
index 189ac789e1..de49d751c3 100644
--- a/src/or/status.h
+++ b/src/or/status.h
@@ -1,8 +1,8 @@
/* Copyright (c) 2010-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_STATUS_H
-#define _TOR_STATUS_H
+#ifndef TOR_STATUS_H
+#define TOR_STATUS_H
int log_heartbeat(time_t now);
diff --git a/src/or/transports.c b/src/or/transports.c
index 4ba239562a..0319071097 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -39,13 +39,17 @@
* transport_t structs.
*
* When the managed proxy stops spitting METHOD lines (signified by a
- * '{S,C}METHODS DONE' message) we register all the transports
- * collected to the circuitbuild.c subsystem. At this point, the
- * pointers to transport_t can be transformed into dangling pointers
- * at any point by the circuitbuild.c subsystem, and so we replace all
- * transport_t pointers with strings describing the transport names.
- * We can still go from a transport name to a transport_t using the
- * fact that each transport name uniquely identifies a transport_t.
+ * '{S,C}METHODS DONE' message) we pass copies of its transports to
+ * the bridge subsystem. We keep copies of the 'transport_t's on the
+ * managed proxy to be able to associate the proxy with its
+ * transports, and we pass copies to the bridge subsystem so that
+ * transports can be associated with bridges.
+ * [ XXX We should try see whether the two copies are really needed
+ * and maybe cut it into a single copy of the 'transport_t' shared
+ * between the managed proxy and the bridge subsystem. Preliminary
+ * analysis shows that both copies are needed with the current code
+ * logic, because of race conditions that can cause dangling
+ * pointers. ]
*
* <b>In even more detail, this is what happens when a SIGHUP
* occurs:</b>
@@ -90,6 +94,7 @@
#include "transports.h"
#include "util.h"
#include "router.h"
+#include "statefile.h"
static process_environment_t *
create_managed_proxy_environment(const managed_proxy_t *mp);
@@ -127,6 +132,224 @@ static INLINE void free_execve_args(char **arg);
protocol version. */
#define PROTO_VERSION_ONE 1
+/** A list of pluggable transports found in torrc. */
+static smartlist_t *transport_list = NULL;
+
+/** Returns a transport_t struct for a transport proxy supporting the
+ protocol <b>name</b> listening at <b>addr</b>:<b>port</b> using
+ SOCKS version <b>socks_ver</b>. */
+static transport_t *
+transport_new(const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver)
+{
+ transport_t *t = tor_malloc_zero(sizeof(transport_t));
+
+ tor_addr_copy(&t->addr, addr);
+ t->port = port;
+ t->name = tor_strdup(name);
+ t->socks_version = socks_ver;
+
+ return t;
+}
+
+/** Free the pluggable transport struct <b>transport</b>. */
+void
+transport_free(transport_t *transport)
+{
+ if (!transport)
+ return;
+
+ tor_free(transport->name);
+ tor_free(transport);
+}
+
+/** Mark every entry of the transport list to be removed on our next call to
+ * sweep_transport_list unless it has first been un-marked. */
+void
+mark_transport_list(void)
+{
+ if (!transport_list)
+ transport_list = smartlist_new();
+ SMARTLIST_FOREACH(transport_list, transport_t *, t,
+ t->marked_for_removal = 1);
+}
+
+/** Remove every entry of the transport list that was marked with
+ * mark_transport_list if it has not subsequently been un-marked. */
+void
+sweep_transport_list(void)
+{
+ if (!transport_list)
+ transport_list = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, t) {
+ if (t->marked_for_removal) {
+ SMARTLIST_DEL_CURRENT(transport_list, t);
+ transport_free(t);
+ }
+ } SMARTLIST_FOREACH_END(t);
+}
+
+/** Initialize the pluggable transports list to empty, creating it if
+ * needed. */
+static void
+clear_transport_list(void)
+{
+ if (!transport_list)
+ transport_list = smartlist_new();
+ SMARTLIST_FOREACH(transport_list, transport_t *, t, transport_free(t));
+ smartlist_clear(transport_list);
+}
+
+/** Return a deep copy of <b>transport</b>. */
+static transport_t *
+transport_copy(const transport_t *transport)
+{
+ transport_t *new_transport = NULL;
+
+ tor_assert(transport);
+
+ new_transport = tor_malloc_zero(sizeof(transport_t));
+
+ new_transport->socks_version = transport->socks_version;
+ new_transport->name = tor_strdup(transport->name);
+ tor_addr_copy(&new_transport->addr, &transport->addr);
+ new_transport->port = transport->port;
+ new_transport->marked_for_removal = transport->marked_for_removal;
+
+ return new_transport;
+}
+
+/** Returns the transport in our transport list that has the name <b>name</b>.
+ * Else returns NULL. */
+transport_t *
+transport_get_by_name(const char *name)
+{
+ tor_assert(name);
+
+ if (!transport_list)
+ return NULL;
+
+ SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) {
+ if (!strcmp(transport->name, name))
+ return transport;
+ } SMARTLIST_FOREACH_END(transport);
+
+ return NULL;
+}
+
+/** Resolve any conflicts that the insertion of transport <b>t</b>
+ * might cause.
+ * Return 0 if <b>t</b> is OK and should be registered, 1 if there is
+ * a transport identical to <b>t</b> already registered and -1 if
+ * <b>t</b> cannot be added due to conflicts. */
+static int
+transport_resolve_conflicts(const transport_t *t)
+{
+ /* This is how we resolve transport conflicts:
+
+ If there is already a transport with the same name and addrport,
+ we either have duplicate torrc lines OR we are here post-HUP and
+ this transport was here pre-HUP as well. In any case, mark the
+ old transport so that it doesn't get removed and ignore the new
+ one. Our caller has to free the new transport so we return '1' to
+ signify this.
+
+ If there is already a transport with the same name but different
+ addrport:
+ * if it's marked for removal, it means that it either has a lower
+ priority than 't' in torrc (otherwise the mark would have been
+ cleared by the paragraph above), or it doesn't exist at all in
+ the post-HUP torrc. We destroy the old transport and register 't'.
+ * if it's *not* marked for removal, it means that it was newly
+ added in the post-HUP torrc or that it's of higher priority, in
+ this case we ignore 't'. */
+ transport_t *t_tmp = transport_get_by_name(t->name);
+ if (t_tmp) { /* same name */
+ if (tor_addr_eq(&t->addr, &t_tmp->addr) && (t->port == t_tmp->port)) {
+ /* same name *and* addrport */
+ t_tmp->marked_for_removal = 0;
+ return 1;
+ } else { /* same name but different addrport */
+ char *new_transport_addrport =
+ tor_strdup(fmt_addrport(&t->addr, t->port));
+ if (t_tmp->marked_for_removal) { /* marked for removal */
+ log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s' "
+ "but there was already a transport marked for deletion at "
+ "'%s'. We deleted the old transport and registered the "
+ "new one.", t->name, new_transport_addrport,
+ fmt_addrport(&t_tmp->addr, t_tmp->port));
+ smartlist_remove(transport_list, t_tmp);
+ transport_free(t_tmp);
+ tor_free(new_transport_addrport);
+ } else { /* *not* marked for removal */
+ log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s' "
+ "but the same transport already exists at '%s'. "
+ "Skipping.", t->name, new_transport_addrport,
+ fmt_addrport(&t_tmp->addr, t_tmp->port));
+ tor_free(new_transport_addrport);
+ return -1;
+ }
+ tor_free(new_transport_addrport);
+ }
+ }
+
+ return 0;
+}
+
+/** Add transport <b>t</b> to the internal list of pluggable
+ * transports.
+ * Returns 0 if the transport was added correctly, 1 if the same
+ * transport was already registered (in this case the caller must
+ * free the transport) and -1 if there was an error. */
+static int
+transport_add(transport_t *t)
+{
+ int r;
+ tor_assert(t);
+
+ r = transport_resolve_conflicts(t);
+
+ switch (r) {
+ case 0: /* should register transport */
+ if (!transport_list)
+ transport_list = smartlist_new();
+ smartlist_add(transport_list, t);
+ return 0;
+ default: /* let our caller know the return code */
+ return r;
+ }
+}
+
+/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
+ * <b>name</b> is set to the name of the protocol this proxy uses.
+ * <b>socks_ver</b> is set to the SOCKS version of the proxy. */
+int
+transport_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver)
+{
+ transport_t *t = transport_new(addr, port, name, socks_ver);
+
+ int r = transport_add(t);
+
+ switch (r) {
+ case -1:
+ default:
+ log_notice(LD_GENERAL, "Could not add transport %s at %s. Skipping.",
+ t->name, fmt_addrport(&t->addr, t->port));
+ transport_free(t);
+ return -1;
+ case 1:
+ log_info(LD_GENERAL, "Succesfully registered transport %s at %s.",
+ t->name, fmt_addrport(&t->addr, t->port));
+ transport_free(t); /* falling */
+ return 0;
+ case 0:
+ log_info(LD_GENERAL, "Succesfully registered transport %s at %s.",
+ t->name, fmt_addrport(&t->addr, t->port));
+ return 0;
+ }
+}
+
/** List of unconfigured managed proxies. */
static smartlist_t *managed_proxy_list = NULL;
/** Number of still unconfigured proxies. */
@@ -217,11 +440,11 @@ proxy_needs_restart(const managed_proxy_t *mp)
{
/* mp->transport_to_launch is populated with the names of the
transports that must be launched *after* the SIGHUP.
- mp->transports is populated with the names of the transports that
- were launched *before* the SIGHUP.
+ mp->transports is populated with the transports that were
+ launched *before* the SIGHUP.
- If the two lists contain the same strings, we don't need to
- restart the proxy, since it already does what we want. */
+ Check if all the transports that need to be launched are already
+ launched: */
tor_assert(smartlist_len(mp->transports_to_launch) > 0);
tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
@@ -229,11 +452,11 @@ proxy_needs_restart(const managed_proxy_t *mp)
if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports))
goto needs_restart;
- SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t_t_l) {
- if (!smartlist_string_isin(mp->transports, t_t_l))
+ SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
+ if (!smartlist_string_isin(mp->transports_to_launch, t->name))
goto needs_restart;
- } SMARTLIST_FOREACH_END(t_t_l);
+ } SMARTLIST_FOREACH_END(t);
return 0;
@@ -245,6 +468,7 @@ proxy_needs_restart(const managed_proxy_t *mp)
* preparations and then flag its state so that it will be relaunched
* in the next tick. */
static void
+
proxy_prepare_for_restart(managed_proxy_t *mp)
{
transport_t *t_tmp = NULL;
@@ -255,16 +479,17 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
tor_process_handle_destroy(mp->process_handle, 1);
mp->process_handle = NULL;
- /* destroy all its old transports. we no longer use them. */
- SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) {
- t_tmp = transport_get_by_name(t_name);
+ /* destroy all its registered transports, since we will no longer
+ use them. */
+ SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
+ t_tmp = transport_get_by_name(t->name);
if (t_tmp)
t_tmp->marked_for_removal = 1;
- } SMARTLIST_FOREACH_END(t_name);
+ } SMARTLIST_FOREACH_END(t);
sweep_transport_list();
- /* free the transport names in mp->transports */
- SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name));
+ /* free the transport in mp->transports */
+ SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
smartlist_clear(mp->transports);
/* flag it as an infant proxy so that it gets launched on next tick */
@@ -315,6 +540,7 @@ launch_managed_proxy(managed_proxy_t *mp)
void
pt_configure_remaining_proxies(void)
{
+ int at_least_a_proxy_config_finished = 0;
smartlist_t *tmp = smartlist_new();
log_debug(LD_CONFIG, "Configuring remaining managed proxies (%d)!",
@@ -352,22 +578,25 @@ pt_configure_remaining_proxies(void)
if (!proxy_configuration_finished(mp))
configure_proxy(mp);
+ if (proxy_configuration_finished(mp))
+ at_least_a_proxy_config_finished = 1;
+
} SMARTLIST_FOREACH_END(mp);
smartlist_free(tmp);
check_if_restarts_needed = 0;
assert_unconfigured_count_ok();
-}
-#ifdef _WIN32
+ if (at_least_a_proxy_config_finished)
+ mark_my_descriptor_dirty("configured managed proxies");
+}
/** Attempt to continue configuring managed proxy <b>mp</b>. */
static void
configure_proxy(managed_proxy_t *mp)
{
- int pos;
- char stdout_buf[200];
- smartlist_t *lines = NULL;
+ smartlist_t *proxy_output = NULL;
+ enum stream_status stream_status = 0;
/* if we haven't launched the proxy yet, do it now */
if (mp->conf_state == PT_PROTO_INFANT) {
@@ -381,28 +610,25 @@ configure_proxy(managed_proxy_t *mp)
tor_assert(mp->conf_state != PT_PROTO_INFANT);
tor_assert(mp->process_handle);
- pos = tor_read_all_handle(tor_process_get_stdout_pipe(mp->process_handle),
- stdout_buf, sizeof(stdout_buf) - 1, NULL);
- if (pos < 0) {
- log_notice(LD_GENERAL, "Failed to read data from managed proxy '%s'.",
- mp->argv[0]);
- mp->conf_state = PT_PROTO_BROKEN;
+ proxy_output =
+ tor_get_lines_from_handle(tor_process_get_stdout_pipe(mp->process_handle),
+ &stream_status);
+ if (!proxy_output) { /* failed to get input from proxy */
+ if (stream_status != IO_STREAM_EAGAIN) { /* bad stream status! */
+ mp->conf_state = PT_PROTO_BROKEN;
+ log_warn(LD_GENERAL, "The communication stream of managed proxy '%s' "
+ "is '%s'. Most probably the managed proxy stopped running. "
+ "This might be a bug of the managed proxy, a bug of Tor, or "
+ "a misconfiguration. Please enable logging on your managed "
+ "proxy and check the logs for errors.",
+ mp->argv[0], stream_status_to_string(stream_status));
+ }
+
goto done;
}
- if (pos == 0) /* proxy has nothing interesting to say. */
- return;
-
- /* End with a null even if there isn't a \r\n at the end */
- /* TODO: What if this is a partial line? */
- stdout_buf[pos] = '\0';
-
- /* Split up the buffer */
- lines = smartlist_new();
- tor_split_lines(lines, stdout_buf, pos);
-
/* Handle lines. */
- SMARTLIST_FOREACH_BEGIN(lines, const char *, line) {
+ SMARTLIST_FOREACH_BEGIN(proxy_output, const char *, line) {
handle_proxy_line(line, mp);
if (proxy_configuration_finished(mp))
goto done;
@@ -413,123 +639,56 @@ configure_proxy(managed_proxy_t *mp)
if (proxy_configuration_finished(mp))
handle_finished_proxy(mp);
- if (lines)
- smartlist_free(lines);
-}
-
-#else /* _WIN32 */
-
-/** Attempt to continue configuring managed proxy <b>mp</b>. */
-static void
-configure_proxy(managed_proxy_t *mp)
-{
- enum stream_status r;
- char stdout_buf[200];
-
- /* if we haven't launched the proxy yet, do it now */
- if (mp->conf_state == PT_PROTO_INFANT) {
- if (launch_managed_proxy(mp) < 0) { /* launch fail */
- mp->conf_state = PT_PROTO_FAILED_LAUNCH;
- handle_finished_proxy(mp);
- }
- return;
- }
-
- tor_assert(mp->conf_state != PT_PROTO_INFANT);
- tor_assert(mp->process_handle);
-
- while (1) {
- r = get_string_from_pipe(tor_process_get_stdout_pipe(mp->process_handle),
- stdout_buf, sizeof(stdout_buf) - 1);
-
- if (r == IO_STREAM_OKAY) { /* got a line; handle it! */
- handle_proxy_line((const char *)stdout_buf, mp);
- } else if (r == IO_STREAM_EAGAIN) { /* check back later */
- return;
- } else if (r == IO_STREAM_CLOSED || r == IO_STREAM_TERM) { /* snap! */
- log_warn(LD_GENERAL, "Our communication channel with the managed proxy "
- "'%s' closed. Most probably application stopped running.",
- mp->argv[0]);
- mp->conf_state = PT_PROTO_BROKEN;
- } else { /* unknown stream status */
- log_warn(LD_BUG, "Unknown stream status '%d' while configuring managed "
- "proxy '%s'.", (int)r, mp->argv[0]);
- }
-
- /* if the proxy finished configuring, exit the loop. */
- if (proxy_configuration_finished(mp)) {
- handle_finished_proxy(mp);
- return;
- }
+ if (proxy_output) {
+ SMARTLIST_FOREACH(proxy_output, char *, cp, tor_free(cp));
+ smartlist_free(proxy_output);
}
}
-#endif /* _WIN32 */
-
/** Register server managed proxy <b>mp</b> transports to state */
static void
-register_server_proxy(managed_proxy_t *mp)
+register_server_proxy(const managed_proxy_t *mp)
{
- /* After we register this proxy's transports, we switch its
- mp->transports to a list containing strings of its transport
- names. (See transports.h) */
- smartlist_t *sm_tmp = smartlist_new();
-
tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
+
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
save_transport_to_state(t->name, &t->addr, t->port);
- log_notice(LD_GENERAL, "Registered server transport '%s' at '%s:%d'",
- t->name, fmt_addr(&t->addr), (int)t->port);
- smartlist_add(sm_tmp, tor_strdup(t->name));
+ log_notice(LD_GENERAL, "Registered server transport '%s' at '%s'",
+ t->name, fmt_addrport(&t->addr, t->port));
} SMARTLIST_FOREACH_END(t);
-
- /* Since server proxies don't register their transports in the
- circuitbuild.c subsystem, it's our duty to free them when we
- switch mp->transports to strings. */
- SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
- smartlist_free(mp->transports);
-
- mp->transports = sm_tmp;
}
/** Register all the transports supported by client managed proxy
* <b>mp</b> to the bridge subsystem. */
static void
-register_client_proxy(managed_proxy_t *mp)
+register_client_proxy(const managed_proxy_t *mp)
{
int r;
- /* After we register this proxy's transports, we switch its
- mp->transports to a list containing strings of its transport
- names. (See transports.h) */
- smartlist_t *sm_tmp = smartlist_new();
tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
+
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
- r = transport_add(t);
+ transport_t *transport_tmp = transport_copy(t);
+ r = transport_add(transport_tmp);
switch (r) {
case -1:
log_notice(LD_GENERAL, "Could not add transport %s. Skipping.", t->name);
- transport_free(t);
+ transport_free(transport_tmp);
break;
case 0:
log_info(LD_GENERAL, "Succesfully registered transport %s", t->name);
- smartlist_add(sm_tmp, tor_strdup(t->name));
break;
case 1:
log_info(LD_GENERAL, "Succesfully registered transport %s", t->name);
- smartlist_add(sm_tmp, tor_strdup(t->name));
- transport_free(t);
+ transport_free(transport_tmp);
break;
}
} SMARTLIST_FOREACH_END(t);
-
- smartlist_free(mp->transports);
- mp->transports = sm_tmp;
}
/** Register the transports of managed proxy <b>mp</b>. */
static INLINE void
-register_proxy(managed_proxy_t *mp)
+register_proxy(const managed_proxy_t *mp)
{
if (mp->is_server)
register_server_proxy(mp);
@@ -542,10 +701,7 @@ static void
managed_proxy_destroy(managed_proxy_t *mp,
int also_terminate_process)
{
- if (mp->conf_state != PT_PROTO_COMPLETED)
- SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
- else
- SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name));
+ SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
/* free the transports smartlist */
smartlist_free(mp->transports);
@@ -815,7 +971,7 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
}
addrport = smartlist_get(items, 2);
- if (tor_addr_port_split(LOG_PROTOCOL_WARN, addrport, &address, &port)<0) {
+ if (tor_addr_port_split(LOG_WARN, addrport, &address, &port)<0) {
log_warn(LD_CONFIG, "Error parsing transport "
"address '%s'", addrport);
goto err;
@@ -907,7 +1063,7 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp)
}
addrport = smartlist_get(items, 3);
- if (tor_addr_port_split(LOG_PROTOCOL_WARN, addrport, &address, &port)<0) {
+ if (tor_addr_port_split(LOG_WARN, addrport, &address, &port)<0) {
log_warn(LD_CONFIG, "Error parsing transport "
"address '%s'", addrport);
goto err;
@@ -1039,7 +1195,7 @@ create_managed_proxy_environment(const managed_proxy_t *mp)
SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) {
set_environment_variable_in_smartlist(merged_env_vars, env_var,
- _tor_free, 1);
+ tor_free_, 1);
} SMARTLIST_FOREACH_END(env_var);
env = process_environment_make(merged_env_vars);
@@ -1143,7 +1299,7 @@ free_execve_args(char **arg)
char **tmp = arg;
while (*tmp) /* use the fact that the last element of the array is a
NULL pointer to know when to stop freeing */
- _tor_free(*tmp++);
+ tor_free_(*tmp++);
tor_free(arg);
}
@@ -1181,6 +1337,93 @@ pt_prepare_proxy_list_for_config_read(void)
tor_assert(unconfigured_proxies_n == 0);
}
+/** Return a smartlist containing the ports where our pluggable
+ * transports are listening. */
+smartlist_t *
+get_transport_proxy_ports(void)
+{
+ smartlist_t *sl = NULL;
+
+ if (!managed_proxy_list)
+ return NULL;
+
+ /** XXX assume that external proxy ports have been forwarded
+ manually */
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, const managed_proxy_t *, mp) {
+ if (!mp->is_server || mp->conf_state != PT_PROTO_COMPLETED)
+ continue;
+
+ if (!sl) sl = smartlist_new();
+
+ tor_assert(mp->transports);
+ SMARTLIST_FOREACH(mp->transports, const transport_t *, t,
+ smartlist_add_asprintf(sl, "%u:%u", t->port, t->port));
+
+ } SMARTLIST_FOREACH_END(mp);
+
+ return sl;
+}
+
+/** Return the pluggable transport string that we should display in
+ * our extra-info descriptor. If we shouldn't display such a string,
+ * or we have nothing to display, return NULL. The string is
+ * allocated on the heap and it's the responsibility of the caller to
+ * free it. */
+char *
+pt_get_extra_info_descriptor_string(void)
+{
+ char *the_string = NULL;
+ smartlist_t *string_chunks = NULL;
+
+ if (!managed_proxy_list)
+ return NULL;
+
+ string_chunks = smartlist_new();
+
+ /* For each managed proxy, add its transports to the chunks list. */
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, const managed_proxy_t *, mp) {
+ if ((!mp->is_server) || (mp->conf_state != PT_PROTO_COMPLETED))
+ continue;
+
+ tor_assert(mp->transports);
+
+ SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
+ /* If the transport proxy returned "0.0.0.0" as its address, and
+ * we know our external IP address, use it. Otherwise, use the
+ * returned address. */
+ const char *addrport = NULL;
+ uint32_t external_ip_address = 0;
+ if (tor_addr_is_null(&t->addr) &&
+ router_pick_published_address(get_options(),
+ &external_ip_address) >= 0) {
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, external_ip_address);
+ addrport = fmt_addrport(&addr, t->port);
+ } else {
+ addrport = fmt_addrport(&t->addr, t->port);
+ }
+
+ smartlist_add_asprintf(string_chunks,
+ "transport %s %s",
+ t->name, addrport);
+ } SMARTLIST_FOREACH_END(t);
+
+ } SMARTLIST_FOREACH_END(mp);
+
+ if (smartlist_len(string_chunks) == 0) {
+ smartlist_free(string_chunks);
+ return NULL;
+ }
+
+ /* Join all the chunks into the final string. */
+ the_string = smartlist_join_strings(string_chunks, "\n", 1, NULL);
+
+ SMARTLIST_FOREACH(string_chunks, char *, s, tor_free(s));
+ smartlist_free(string_chunks);
+
+ return the_string;
+}
+
/** The tor config was read.
* Destroy all managed proxies that were marked by a previous call to
* prepare_proxy_list_for_config_read() and are not used by the new
@@ -1204,6 +1447,12 @@ sweep_proxy_list(void)
void
pt_free_all(void)
{
+ if (transport_list) {
+ clear_transport_list();
+ smartlist_free(transport_list);
+ transport_list = NULL;
+ }
+
if (managed_proxy_list) {
/* If the proxy is in PT_PROTO_COMPLETED, it has registered its
transports and it's the duty of the circuitbuild.c subsystem to
diff --git a/src/or/transports.h b/src/or/transports.h
index 02f159a5d6..86a2530fcb 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -11,6 +11,30 @@
#ifndef TOR_TRANSPORTS_H
#define TOR_TRANSPORTS_H
+/** Represents a pluggable transport used by a bridge. */
+typedef struct transport_t {
+ /** SOCKS version: One of PROXY_SOCKS4, PROXY_SOCKS5. */
+ int socks_version;
+ /** Name of pluggable transport protocol */
+ char *name;
+ /** The IP address where the transport bound and is waiting for
+ * connections. */
+ tor_addr_t addr;
+ /** Port of proxy */
+ uint16_t port;
+ /** Boolean: We are re-parsing our transport list, and we are going to remove
+ * this one if we don't find it in the list of configured transports. */
+ unsigned marked_for_removal : 1;
+} transport_t;
+
+void mark_transport_list(void);
+void sweep_transport_list(void);
+int transport_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver);
+void transport_free(transport_t *transport);
+
+transport_t *transport_get_by_name(const char *name);
+
void pt_kickstart_proxy(const smartlist_t *transport_list, char **proxy_argv,
int is_server);
@@ -23,11 +47,15 @@ void pt_configure_remaining_proxies(void);
int pt_proxies_configuration_pending(void);
+char *pt_get_extra_info_descriptor_string(void);
+
void pt_free_all(void);
void pt_prepare_proxy_list_for_config_read(void);
void sweep_proxy_list(void);
+smartlist_t *get_transport_proxy_ports(void);
+
#ifdef PT_PRIVATE
/** State of the managed proxy configuration protocol. */
enum pt_proto_state {
@@ -68,28 +96,7 @@ typedef struct {
smartlist_t *transports_to_launch;
/* The 'transports' list contains all the transports this proxy has
- launched.
-
- Before a managed_proxy_t reaches the PT_PROTO_COMPLETED phase,
- this smartlist contains a 'transport_t' for every transport it
- has launched.
-
- When the managed_proxy_t reaches the PT_PROTO_COMPLETED phase, it
- registers all its transports to the circuitbuild.c subsystem. At
- that point the 'transport_t's are owned by the circuitbuild.c
- subsystem.
-
- To avoid carrying dangling 'transport_t's in this smartlist,
- right before the managed_proxy_t reaches the PT_PROTO_COMPLETED
- phase we replace all 'transport_t's with strings of their
- transport names.
-
- So, tl;dr:
- When (conf_state != PT_PROTO_COMPLETED) this list carries
- (transport_t *).
- When (conf_state == PT_PROTO_COMPLETED) this list carries
- (char *).
- */
+ launched. */
smartlist_t *transports;
} managed_proxy_t;
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
deleted file mode 100644
index 31a464ee7a..0000000000
--- a/src/test/Makefile.am
+++ /dev/null
@@ -1,49 +0,0 @@
-TESTS = test
-
-noinst_PROGRAMS = test test-child bench
-
-AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
- -DLOCALSTATEDIR="\"$(localstatedir)\"" \
- -DBINDIR="\"$(bindir)\"" \
- -I"$(top_srcdir)/src/or"
-
-# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
-# This seems to matter nowhere but on Windows, but I assure you that it
-# matters a lot there, and is quite hard to debug if you forget to do it.
-
-test_SOURCES = \
- test.c \
- test_addr.c \
- test_containers.c \
- test_crypto.c \
- test_data.c \
- test_dir.c \
- test_microdesc.c \
- test_pt.c \
- test_util.c \
- test_config.c \
- tinytest.c
-
-bench_SOURCES = \
- bench.c
-
-test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
- @TOR_LDFLAGS_libevent@
-test_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
- ../common/libor-event.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
- @TOR_LDFLAGS_libevent@
-bench_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
- ../common/libor-event.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-noinst_HEADERS = \
- tinytest.h \
- tinytest_macros.h \
- test.h
-
-
diff --git a/src/test/bench.c b/src/test/bench.c
index 3eae532d30..2e65d0b2d4 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -214,8 +214,8 @@ bench_cell_ops(void)
crypto_rand((char*)cell->payload, sizeof(cell->payload));
/* Mock-up or_circuit_t */
- or_circ->_base.magic = OR_CIRCUIT_MAGIC;
- or_circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
/* Initialize crypto */
or_circ->p_crypto = crypto_cipher_new(NULL);
diff --git a/src/test/include.am b/src/test/include.am
new file mode 100644
index 0000000000..075df36460
--- /dev/null
+++ b/src/test/include.am
@@ -0,0 +1,53 @@
+TESTS+= src/test/test
+
+noinst_PROGRAMS+= src/test/test src/test/test-child src/test/bench
+
+src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
+ -DLOCALSTATEDIR="\"$(localstatedir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
+ -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext"
+
+# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
+# This seems to matter nowhere but on Windows, but I assure you that it
+# matters a lot there, and is quite hard to debug if you forget to do it.
+
+src_test_test_SOURCES = \
+ src/test/test.c \
+ src/test/test_addr.c \
+ src/test/test_cell_formats.c \
+ src/test/test_containers.c \
+ src/test/test_crypto.c \
+ src/test/test_data.c \
+ src/test/test_dir.c \
+ src/test/test_introduce.c \
+ src/test/test_microdesc.c \
+ src/test/test_pt.c \
+ src/test/test_replay.c \
+ src/test/test_util.c \
+ src/test/test_config.c \
+ src/ext/tinytest.c
+
+src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS)
+
+src_test_bench_SOURCES = \
+ src/test/bench.c
+
+src_test_bench_CPPFLAGS= $(src_test_AM_CPPFLAGS)
+
+src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
+ @TOR_LDFLAGS_libevent@
+src_test_test_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypto.a \
+ src/common/libor-event.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+
+src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
+ @TOR_LDFLAGS_libevent@
+src_test_bench_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypto.a \
+ src/common/libor-event.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+
+noinst_HEADERS+= \
+ src/test/test.h
+
diff --git a/src/test/test.c b/src/test/test.c
index ddfd6337bd..c96aeb7053 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -32,7 +32,7 @@ const char tor_git_revision[] = "";
#define CONFIG_PRIVATE
#define GEOIP_PRIVATE
#define ROUTER_PRIVATE
-#define CIRCUIT_PRIVATE
+#define CIRCUITSTATS_PRIVATE
/*
* Linux doesn't provide lround in math.h by default, but mac os does...
@@ -44,7 +44,7 @@ double fabs(double x);
#include "or.h"
#include "buffers.h"
-#include "circuitbuild.h"
+#include "circuitstats.h"
#include "config.h"
#include "connection_edge.h"
#include "geoip.h"
@@ -1044,9 +1044,9 @@ test_policy_summary_helper(const char *policy_str,
line.value = (char *)policy_str;
line.next = NULL;
- r = policies_parse_exit_policy(&line, &policy, 0, NULL, 1);
+ r = policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1);
test_eq(r, 0);
- summary = policy_summarize(policy);
+ summary = policy_summarize(policy, AF_INET);
test_assert(summary != NULL);
test_streq(summary, expected_summary);
@@ -1101,7 +1101,7 @@ test_policies(void)
test_assert(ADDR_POLICY_REJECTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
- test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, NULL, 1));
+ test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, NULL, 1));
test_assert(policy2);
policy3 = smartlist_new();
@@ -1176,9 +1176,9 @@ test_policies(void)
test_assert(!cmp_addr_policies(policy2, policy2));
test_assert(!cmp_addr_policies(NULL, NULL));
- test_assert(!policy_is_reject_star(policy2));
- test_assert(policy_is_reject_star(policy));
- test_assert(policy_is_reject_star(NULL));
+ test_assert(!policy_is_reject_star(policy2, AF_INET));
+ test_assert(policy_is_reject_star(policy, AF_INET));
+ test_assert(policy_is_reject_star(NULL, AF_INET));
addr_policy_list_free(policy);
policy = NULL;
@@ -1188,11 +1188,11 @@ test_policies(void)
line.key = (char*)"foo";
line.value = (char*)"accept *:80,reject private:*,reject *:*";
line.next = NULL;
- test_assert(0 == policies_parse_exit_policy(&line, &policy, 0, NULL, 1));
+ test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1));
test_assert(policy);
//test_streq(policy->string, "accept *:80");
//test_streq(policy->next->string, "reject *:*");
- test_eq(smartlist_len(policy), 2);
+ test_eq(smartlist_len(policy), 4);
/* test policy summaries */
/* check if we properly ignore private IP addresses */
@@ -1454,10 +1454,11 @@ test_geoip(void)
{
int i, j;
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- char *s = NULL;
+ char *s = NULL, *v = NULL;
const char *bridge_stats_1 =
"bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "bridge-ips zz=24,xy=8\n",
+ "bridge-ips zz=24,xy=8\n"
+ "bridge-ip-versions v4=16,v6=16\n",
*dirreq_stats_1 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips ab=8\n"
@@ -1521,61 +1522,109 @@ test_geoip(void)
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips \n";
tor_addr_t addr;
+ struct in6_addr in6;
/* Populate the DB a bit. Add these in order, since we can't do the final
* 'sort' step. These aren't very good IP addresses, but they're perfectly
* fine uint32_t values. */
- test_eq(0, geoip_parse_entry("10,50,AB"));
- test_eq(0, geoip_parse_entry("52,90,XY"));
- test_eq(0, geoip_parse_entry("95,100,AB"));
- test_eq(0, geoip_parse_entry("\"105\",\"140\",\"ZZ\""));
- test_eq(0, geoip_parse_entry("\"150\",\"190\",\"XY\""));
- test_eq(0, geoip_parse_entry("\"200\",\"250\",\"AB\""));
+ test_eq(0, geoip_parse_entry("10,50,AB", AF_INET));
+ test_eq(0, geoip_parse_entry("52,90,XY", AF_INET));
+ test_eq(0, geoip_parse_entry("95,100,AB", AF_INET));
+ test_eq(0, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET));
+ test_eq(0, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET));
+ test_eq(0, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET));
+
+ /* Populate the IPv6 DB equivalently with fake IPs in the same range */
+ test_eq(0, geoip_parse_entry("::a,::32,AB", AF_INET6));
+ test_eq(0, geoip_parse_entry("::34,::5a,XY", AF_INET6));
+ test_eq(0, geoip_parse_entry("::5f,::64,AB", AF_INET6));
+ test_eq(0, geoip_parse_entry("::69,::8c,ZZ", AF_INET6));
+ test_eq(0, geoip_parse_entry("::96,::be,XY", AF_INET6));
+ test_eq(0, geoip_parse_entry("::c8,::fa,AB", AF_INET6));
/* We should have 4 countries: ??, ab, xy, zz. */
test_eq(4, geoip_get_n_countries());
+ memset(&in6, 0, sizeof(in6));
+
/* Make sure that country ID actually works. */
-#define NAMEFOR(x) geoip_get_country_name(geoip_get_country_by_ip(x))
- test_streq("??", NAMEFOR(3));
- test_eq(0, geoip_get_country_by_ip(3));
- test_streq("ab", NAMEFOR(32));
- test_streq("??", NAMEFOR(5));
- test_streq("??", NAMEFOR(51));
- test_streq("xy", NAMEFOR(150));
- test_streq("xy", NAMEFOR(190));
- test_streq("??", NAMEFOR(2000));
-#undef NAMEFOR
+#define SET_TEST_IPV6(i) \
+ do { \
+ set_uint32(in6.s6_addr + 12, htonl((uint32_t) (i))); \
+ } while (0)
+#define CHECK_COUNTRY(country, val) do { \
+ /* test ipv4 country lookup */ \
+ test_streq(country, \
+ geoip_get_country_name(geoip_get_country_by_ipv4(val))); \
+ /* test ipv6 country lookup */ \
+ SET_TEST_IPV6(val); \
+ test_streq(country, \
+ geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \
+ } while (0)
+
+ CHECK_COUNTRY("??", 3);
+ CHECK_COUNTRY("ab", 32);
+ CHECK_COUNTRY("??", 5);
+ CHECK_COUNTRY("??", 51);
+ CHECK_COUNTRY("xy", 150);
+ CHECK_COUNTRY("xy", 190);
+ CHECK_COUNTRY("??", 2000);
+
+ test_eq(0, geoip_get_country_by_ipv4(3));
+ SET_TEST_IPV6(3);
+ test_eq(0, geoip_get_country_by_ipv6(&in6));
+
+#undef CHECK_COUNTRY
+
+ /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs
+ * using ipv4. Since our fake geoip database is the same between
+ * ipv4 and ipv6, we should get the same result no matter which
+ * address family we pick for each IP. */
+#define SET_TEST_ADDRESS(i) do { \
+ if ((i) & 1) { \
+ SET_TEST_IPV6(i); \
+ tor_addr_from_in6(&addr, &in6); \
+ } else { \
+ tor_addr_from_ipv4h(&addr, (uint32_t) i); \
+ } \
+ } while (0)
get_options_mutable()->BridgeRelay = 1;
get_options_mutable()->BridgeRecordUsageByCountry = 1;
/* Put 9 observations in AB... */
for (i=32; i < 40; ++i) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
}
- tor_addr_from_ipv4h(&addr, (uint32_t) 225);
+ SET_TEST_ADDRESS(225);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
/* and 3 observations in XY, several times. */
for (j=0; j < 10; ++j)
for (i=52; i < 55; ++i) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-3600);
}
/* and 17 observations in ZZ... */
for (i=110; i < 127; ++i) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
}
- s = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
test_assert(s);
+ test_assert(v);
test_streq("zz=24,ab=16,xy=8", s);
+ test_streq("v4=16,v6=16", v);
tor_free(s);
+ tor_free(v);
/* Now clear out all the AB observations. */
geoip_remove_old_clients(now-6000);
- s = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
test_assert(s);
+ test_assert(v);
test_streq("zz=24,xy=8", s);
+ test_streq("v4=16,v6=16", v);
+ tor_free(s);
+ tor_free(v);
/* Start testing bridge statistics by making sure that we don't output
* bridge stats without initializing them. */
@@ -1604,7 +1653,7 @@ test_geoip(void)
/* Start testing dirreq statistics by making sure that we don't collect
* dirreq stats without initializing them. */
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
@@ -1612,7 +1661,7 @@ test_geoip(void)
/* Initialize stats, note one connecting client, and generate the
* dirreq-stats history string. */
geoip_dirreq_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_1, s);
@@ -1621,7 +1670,7 @@ test_geoip(void)
/* Stop collecting stats, add another connecting client, and ensure we
* don't generate a history string. */
geoip_dirreq_stats_term();
- tor_addr_from_ipv4h(&addr, (uint32_t) 101);
+ SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
@@ -1629,7 +1678,7 @@ test_geoip(void)
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
geoip_dirreq_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
geoip_reset_dirreq_stats(now);
s = geoip_format_dirreq_stats(now + 86400);
@@ -1657,7 +1706,7 @@ test_geoip(void)
/* Start testing entry statistics by making sure that we don't collect
* anything without initializing entry stats. */
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
@@ -1665,7 +1714,7 @@ test_geoip(void)
/* Initialize stats, note one connecting client, and generate the
* entry-stats history string. */
geoip_entry_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_1, s);
@@ -1674,7 +1723,7 @@ test_geoip(void)
/* Stop collecting stats, add another connecting client, and ensure we
* don't generate a history string. */
geoip_entry_stats_term();
- tor_addr_from_ipv4h(&addr, (uint32_t) 101);
+ SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
@@ -1682,13 +1731,16 @@ test_geoip(void)
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
geoip_entry_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
geoip_reset_entry_stats(now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_2, s);
tor_free(s);
+#undef SET_TEST_ADDRESS
+#undef SET_TEST_IPV6
+
/* Stop collecting entry statistics. */
geoip_entry_stats_term();
get_options_mutable()->EntryStatistics = 0;
@@ -1929,6 +1981,9 @@ extern struct testcase_t dir_tests[];
extern struct testcase_t microdesc_tests[];
extern struct testcase_t pt_tests[];
extern struct testcase_t config_tests[];
+extern struct testcase_t introduce_tests[];
+extern struct testcase_t replaycache_tests[];
+extern struct testcase_t cell_format_tests[];
static struct testgroup_t testgroups[] = {
{ "", test_array },
@@ -1937,10 +1992,13 @@ static struct testgroup_t testgroups[] = {
{ "crypto/", crypto_tests },
{ "container/", container_tests },
{ "util/", util_tests },
+ { "cellfmt/", cell_format_tests },
{ "dir/", dir_tests },
{ "dir/md/", microdesc_tests },
{ "pt/", pt_tests },
{ "config/", config_tests },
+ { "replaycache/", replaycache_tests },
+ { "introduce/", introduce_tests },
END_OF_GROUPS
};
@@ -1956,7 +2014,7 @@ main(int c, const char **v)
#ifdef USE_DMALLOC
{
- int r = CRYPTO_set_mem_ex_functions(_tor_malloc, _tor_realloc, _tor_free);
+ int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
tor_assert(r);
}
#endif
diff --git a/src/test/test.h b/src/test/test.h
index 0b6e6c60cb..08fad6b313 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -3,8 +3,8 @@
* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_TEST_H
-#define _TOR_TEST_H
+#ifndef TOR_TEST_H
+#define TOR_TEST_H
/**
* \file test.h
@@ -65,6 +65,10 @@
#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, ==, hex)
+#define tt_double_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%f", \
+ TT_EXIT_TEST_FUNCTION)
+
const char *get_fname(const char *name);
crypto_pk_t *pk_generate(int idx);
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 9007a23c5c..d2b25e5e6c 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -38,7 +38,7 @@ test_addr_basic(void)
tor_free(cp);
u32 = 3;
test_assert(!addr_port_lookup(LOG_WARN, "localhost", NULL, &u32, &u16));
- test_eq(cp, NULL);
+ test_eq_ptr(cp, NULL);
test_eq(u32, 0x7f000001u);
test_eq(u16, 0);
tor_free(cp);
@@ -70,7 +70,7 @@ test_addr_basic(void)
;
}
-#define _test_op_ip6(a,op,b,e1,e2) \
+#define test_op_ip6_(a,op,b,e1,e2) \
STMT_BEGIN \
tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \
(memcmp(val1_->s6_addr, val2_->s6_addr, 16) op 0), \
@@ -93,7 +93,7 @@ test_addr_basic(void)
#define test_pton6_same(a,b) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
- _test_op_ip6(&a1,==,&a2,#a,#b); \
+ test_op_ip6_(&a1,==,&a2,#a,#b); \
STMT_END
/** Helper: Assert that <b>a</b> is recognized as a bad IPv6 address by
@@ -108,7 +108,7 @@ test_addr_basic(void)
test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
test_streq(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), b); \
test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
- _test_op_ip6(&a1, ==, &a2, a, b); \
+ test_op_ip6_(&a1, ==, &a2, a, b); \
STMT_END
/** Helper: assert that <b>a</b> parses by tor_inet_pton() into a address that
@@ -159,7 +159,8 @@ test_addr_basic(void)
* as <b>pt1..pt2</b>. */
#define test_addr_mask_ports_parse(xx, f, ip1, ip2, ip3, ip4, mm, pt1, pt2) \
STMT_BEGIN \
- test_eq(tor_addr_parse_mask_ports(xx, &t1, &mask, &port1, &port2), f); \
+ test_eq(tor_addr_parse_mask_ports(xx, 0, &t1, &mask, &port1, &port2), \
+ f); \
p1=tor_inet_ntop(AF_INET6, &t1.addr.in6_addr, bug, sizeof(bug)); \
test_eq(htonl(ip1), tor_addr_to_in6_addr32(&t1)[0]); \
test_eq(htonl(ip2), tor_addr_to_in6_addr32(&t1)[1]); \
@@ -401,11 +402,11 @@ test_addr_ip6_helpers(void)
test_addr_compare("0::2:2:1", <, "0::ffff:0.3.2.1");
test_addr_compare("0::ffff:0.3.2.1", >, "0::0:0:0");
test_addr_compare("0::ffff:5.2.2.1", <, "::ffff:6.0.0.0"); /* XXXX wrong. */
- tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", &t1, NULL, NULL, NULL);
- tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", 0, &t1, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0);
- tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", &t1, NULL, NULL, NULL);
- tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", 0, &t1, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0);
/* test compare_masked */
@@ -568,6 +569,7 @@ test_addr_ip6_helpers(void)
test_streq(rbuf, addr_PTR);
}
+ /* XXXX turn this into a separate function; it's not all IPv6. */
/* test tor_addr_parse_mask_ports */
test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6,
0, 0, 0, 0x0000000f, 17, 47, 95);
@@ -581,27 +583,123 @@ test_addr_ip6_helpers(void)
0xabcd0002, 0, 0, 0x044a0000, 128, 2, 65000);
test_streq(p1, "abcd:2::44a:0");
- r=tor_addr_parse_mask_ports("[fefef::]/112", &t1, NULL, NULL, NULL);
+ /* Try some long addresses. */
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == AF_INET6);
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:11111]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111:1]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports(
+ "[ffff:1111:1111:1111:1111:1111:1111:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ /* Try some failing cases. */
+ r=tor_addr_parse_mask_ports("[fefef::]/112", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::/112", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::X]", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("efef::/112", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]",0,&t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("efef::/112", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/fred",0,&t1,&mask, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/255.255.0.0",
+ 0,&t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ /* This one will get rejected because it isn't a pure prefix. */
+ r=tor_addr_parse_mask_ports("1.1.2.3/255.255.64.0",0,&t1, &mask,NULL,NULL);
test_assert(r == -1);
/* Test for V4-mapped address with mask < 96. (arguably not valid) */
- r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]", &t1, &mask, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("1.1.2.2/33",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ /* Try extended wildcard addresses with out TAPMP_EXTENDED_STAR*/
+ r=tor_addr_parse_mask_ports("*4",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("*6",0,&t1, &mask, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("1.1.2.2/33", &t1, &mask, NULL, NULL);
+#if 0
+ /* Try a mask with a wildcard. */
+ r=tor_addr_parse_mask_ports("*/16",0,&t1, &mask, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("1.1.2.2/31", &t1, &mask, NULL, NULL);
+ r=tor_addr_parse_mask_ports("*4/16",TAPMP_EXTENDED_STAR,
+ &t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("*6/30",TAPMP_EXTENDED_STAR,
+ &t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+#endif
+ /* Basic mask tests*/
+ r=tor_addr_parse_mask_ports("1.1.2.2/31",0,&t1, &mask, NULL, NULL);
+ test_assert(r == AF_INET);
+ tt_int_op(mask,==,31);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010202);
+ r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2);
+ test_assert(r == AF_INET);
+ tt_int_op(mask,==,32);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x03041020);
+ test_assert(port1 == 1);
+ test_assert(port2 == 2);
+ r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
test_assert(r == AF_INET);
- r=tor_addr_parse_mask_ports("[efef::]/112", &t1, &mask, &port1, &port2);
+ tt_int_op(mask,==,17);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010203);
+ r=tor_addr_parse_mask_ports("[efef::]/112",0,&t1, &mask, &port1, &port2);
test_assert(r == AF_INET6);
test_assert(port1 == 1);
test_assert(port2 == 65535);
+ /* Try regular wildcard behavior without TAPMP_EXTENDED_STAR */
+ r=tor_addr_parse_mask_ports("*:80-443",0,&t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET); /* Old users of this always get inet */
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,80);
+ tt_int_op(port2,==,443);
+ /* Now try wildcards *with* TAPMP_EXTENDED_STAR */
+ r=tor_addr_parse_mask_ports("*:8000-9000",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_UNSPEC);
+ tt_int_op(tor_addr_family(&t1),==,AF_UNSPEC);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,8000);
+ tt_int_op(port2,==,9000);
+ r=tor_addr_parse_mask_ports("*4:6667",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,6667);
+ tt_int_op(port2,==,6667);
+ r=tor_addr_parse_mask_ports("*6",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET6);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET6);
+ tt_assert(tor_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16));
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,1);
+ tt_int_op(port2,==,65535);
/* make sure inet address lengths >= max */
test_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255"));
@@ -623,12 +721,65 @@ test_addr_ip6_helpers(void)
;
}
+/** Test tor_addr_port_parse(). */
+static void
+test_addr_parse(void)
+{
+ int r;
+ tor_addr_t addr;
+ char buf[TOR_ADDR_BUF_LEN];
+ uint16_t port = 0;
+
+ /* Correct call. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.1:1234",
+ &addr, &port);
+ test_assert(r == 0);
+ tor_addr_to_str(buf, &addr, sizeof(buf), 0);
+ test_streq(buf, "192.0.2.1");
+ test_eq(port, 1234);
+
+ /* Domain name. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "torproject.org:1234",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Only IP. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Bad port. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2:66666",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Only domain name */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "torproject.org",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Bad IP address */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2:1234",
+ &addr, &port);
+ test_assert(r == -1);
+
+ done:
+ ;
+}
+
#define ADDR_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name }
struct testcase_t addr_tests[] = {
ADDR_LEGACY(basic),
ADDR_LEGACY(ip6_helpers),
+ ADDR_LEGACY(parse),
END_OF_TESTCASES
};
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
new file mode 100644
index 0000000000..4222c79d92
--- /dev/null
+++ b/src/test/test_cell_formats.c
@@ -0,0 +1,386 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define CONNECTION_EDGE_PRIVATE
+#define RELAY_PRIVATE
+#include "or.h"
+#include "connection_edge.h"
+#include "relay.h"
+#include "test.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static void
+test_cfmt_relay_header(void *arg)
+{
+ relay_header_t rh;
+ const uint8_t hdr_1[RELAY_HEADER_SIZE] =
+ "\x03" "\x00\x00" "\x21\x22" "ABCD" "\x01\x03";
+ uint8_t hdr_out[RELAY_HEADER_SIZE];
+ (void)arg;
+
+ tt_int_op(sizeof(hdr_1), ==, RELAY_HEADER_SIZE);
+ relay_header_unpack(&rh, hdr_1);
+ tt_int_op(rh.command, ==, 3);
+ tt_int_op(rh.recognized, ==, 0);
+ tt_int_op(rh.stream_id, ==, 0x2122);
+ test_mem_op(rh.integrity, ==, "ABCD", 4);
+ tt_int_op(rh.length, ==, 0x103);
+
+ relay_header_pack(hdr_out, &rh);
+ test_mem_op(hdr_out, ==, hdr_1, RELAY_HEADER_SIZE);
+
+ done:
+ ;
+}
+
+static void
+make_relay_cell(cell_t *out, uint8_t command,
+ const void *body, size_t bodylen)
+{
+ relay_header_t rh;
+
+ memset(&rh, 0, sizeof(rh));
+ rh.stream_id = 5;
+ rh.command = command;
+ rh.length = bodylen;
+
+ out->command = CELL_RELAY;
+ out->circ_id = 10;
+ relay_header_pack(out->payload, &rh);
+
+ memcpy(out->payload + RELAY_HEADER_SIZE, body, bodylen);
+}
+
+static void
+test_cfmt_begin_cells(void *arg)
+{
+ cell_t cell;
+ begin_cell_t bcell;
+ uint8_t end_reason;
+ (void)arg;
+
+ /* Try begindir. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "", 0);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_ptr_op(NULL, ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(0, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(1, ==, bcell.is_begindir);
+
+ /* A Begindir with extra stuff. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "12345", 5);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_ptr_op(NULL, ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(0, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(1, ==, bcell.is_begindir);
+
+ /* A short but valid begin cell */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:9", 6);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("a.b", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(9, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* A significantly loner begin cell */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "here-is-a-nice-long.hostname.com:65535";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, strlen(c)+1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("here-is-a-nice-long.hostname.com", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(65535, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* An IPv4 begin cell. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("18.9.22.169", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* An IPv6 begin cell. Let's make sure we handle colons*/
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN,
+ "[2620::6b0:b:1a1a:0:26e5:480e]:80", 34);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with extra junk but not enough for flags. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "another.example.com:80\x00\x01\x02";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("another.example.com", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with flags. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "another.example.com:443\x00\x01\x02\x03\x04";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("another.example.com", ==, bcell.address);
+ tt_int_op(0x1020304, ==, bcell.flags);
+ tt_int_op(443, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with flags and even more cruft after that. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "a-further.example.com:22\x00\xee\xaa\x00\xffHi mom";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("a-further.example.com", ==, bcell.address);
+ tt_int_op(0xeeaa00ff, ==, bcell.flags);
+ tt_int_op(22, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* bad begin cell: impossible length. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 7);
+ cell.payload[9] = 0x01; /* Set length to 510 */
+ cell.payload[10] = 0xfe;
+ {
+ relay_header_t rh;
+ relay_header_unpack(&rh, cell.payload);
+ tt_int_op(rh.length, ==, 510);
+ }
+ tt_int_op(-2, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* Bad begin cell: no body. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no body. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no colon */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b", 4);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no ports */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:", 5);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: bad port */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:xyz", 8);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:100000", 11);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no nul */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 6);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ done:
+ tor_free(bcell.address);
+}
+
+static void
+test_cfmt_connected_cells(void *arg)
+{
+ relay_header_t rh;
+ cell_t cell;
+ tor_addr_t addr;
+ int ttl, r;
+ char *mem_op_hex_tmp = NULL;
+ (void)arg;
+
+ /* Let's try an oldschool one with nothing in it. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "", 0);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_UNSPEC);
+ tt_int_op(ttl, ==, -1);
+
+ /* A slightly less oldschool one: only an IPv4 address */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "32.48.64.80");
+ tt_int_op(ttl, ==, -1);
+
+ /* Bogus but understandable: truncated TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "17.18.19.20");
+ tt_int_op(ttl, ==, -1);
+
+ /* Regular IPv4 one: address and TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x02\x03\x04\x05\x00\x00\x0e\x10", 8);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "2.3.4.5");
+ tt_int_op(ttl, ==, 3600);
+
+ /* IPv4 with too-big TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x02\x03\x04\x05\xf0\x00\x00\x00", 8);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "2.3.4.5");
+ tt_int_op(ttl, ==, -1);
+
+ /* IPv6 (ttl is mandatory) */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x00\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68");
+ tt_int_op(ttl, ==, 600);
+
+ /* IPv6 (ttl too big) */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x90\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68");
+ tt_int_op(ttl, ==, -1);
+
+ /* Bogus size: 3. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x01\x02", 3);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Bogus family: 7. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x07"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x90\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Truncated IPv6. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x00\x00\x02", 24);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Now make sure we can generate connected cells correctly. */
+ /* Try an IPv4 address */
+ memset(&rh, 0, sizeof(rh));
+ memset(&cell, 0, sizeof(cell));
+ tor_addr_parse(&addr, "30.40.50.60");
+ rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+ &addr, 128);
+ tt_int_op(rh.length, ==, 8);
+ test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000080");
+
+ /* Try parsing it. */
+ tor_addr_make_unspec(&addr);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "30.40.50.60");
+ tt_int_op(ttl, ==, 128);
+
+ /* Try an IPv6 address */
+ memset(&rh, 0, sizeof(rh));
+ memset(&cell, 0, sizeof(cell));
+ tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e");
+ rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+ &addr, 3600);
+ tt_int_op(rh.length, ==, 25);
+ test_memeq_hex(cell.payload + RELAY_HEADER_SIZE,
+ "00000000" "06"
+ "2620000006b0000b1a1a000026e5480e" "00000e10");
+
+ /* Try parsing it. */
+ tor_addr_make_unspec(&addr);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2620:0:6b0:b:1a1a:0:26e5:480e");
+ tt_int_op(ttl, ==, 3600);
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+#define TEST(name, flags) \
+ { #name, test_cfmt_ ## name, flags, 0, NULL }
+
+struct testcase_t cell_format_tests[] = {
+ TEST(relay_header, 0),
+ TEST(begin_cells, 0),
+ TEST(connected_cells, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_config.c b/src/test/test_config.c
index ff251a24d8..e04b9dfc2e 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -5,7 +5,9 @@
#include "orconfig.h"
#include "or.h"
+#include "addressmap.h"
#include "config.h"
+#include "confparse.h"
#include "connection_edge.h"
#include "test.h"
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 45898df4eb..580c5779f0 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -10,7 +10,7 @@
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>. */
static int
-_compare_strs(const void **a, const void **b)
+compare_strs_(const void **a, const void **b)
{
const char *s1 = *a, *s2 = *b;
return strcmp(s1, s2);
@@ -28,7 +28,7 @@ compare_strs_for_bsearch_(const void *a, const void **b)
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>, excluding a's first character, and ignoring case. */
static int
-_compare_without_first_ch(const void *a, const void **b)
+compare_without_first_ch_(const void *a, const void **b)
{
const char *s1 = a, *s2 = *b;
return strcasecmp(s1+1, s2);
@@ -185,7 +185,7 @@ test_container_smartlist_strings(void)
/* Test swapping, shuffling, and sorting. */
smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0);
test_eq(7, smartlist_len(sl));
- smartlist_sort(sl, _compare_strs);
+ smartlist_sort(sl, compare_strs_);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc,"and,arma,by,nickm,onion,router,the");
tor_free(cp_alloc);
@@ -204,28 +204,28 @@ test_container_smartlist_strings(void)
test_assert(smartlist_string_isin(sl, "the"));
/* Test bsearch. */
- smartlist_sort(sl, _compare_strs);
+ smartlist_sort(sl, compare_strs_);
test_streq("nickm", smartlist_bsearch(sl, "zNicKM",
- _compare_without_first_ch));
- test_streq("and", smartlist_bsearch(sl, " AND", _compare_without_first_ch));
- test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", _compare_without_first_ch));
+ compare_without_first_ch_));
+ test_streq("and", smartlist_bsearch(sl, " AND", compare_without_first_ch_));
+ test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", compare_without_first_ch_));
/* Test bsearch_idx */
{
int f;
smartlist_t *tmp = NULL;
- test_eq(0, smartlist_bsearch_idx(sl," aaa",_compare_without_first_ch,&f));
+ test_eq(0, smartlist_bsearch_idx(sl," aaa",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(0, smartlist_bsearch_idx(sl," and",_compare_without_first_ch,&f));
+ test_eq(0, smartlist_bsearch_idx(sl," and",compare_without_first_ch_,&f));
test_eq(f, 1);
- test_eq(1, smartlist_bsearch_idx(sl," arm",_compare_without_first_ch,&f));
+ test_eq(1, smartlist_bsearch_idx(sl," arm",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(1, smartlist_bsearch_idx(sl," arma",_compare_without_first_ch,&f));
+ test_eq(1, smartlist_bsearch_idx(sl," arma",compare_without_first_ch_,&f));
test_eq(f, 1);
- test_eq(2, smartlist_bsearch_idx(sl," armb",_compare_without_first_ch,&f));
+ test_eq(2, smartlist_bsearch_idx(sl," armb",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(7, smartlist_bsearch_idx(sl," zzzz",_compare_without_first_ch,&f));
+ test_eq(7, smartlist_bsearch_idx(sl," zzzz",compare_without_first_ch_,&f));
test_eq(f, 0);
/* Test trivial cases for list of length 0 or 1 */
@@ -266,14 +266,14 @@ test_container_smartlist_strings(void)
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
cp_alloc = smartlist_pop_last(sl);
- test_eq(cp_alloc, NULL);
+ test_eq_ptr(cp_alloc, NULL);
/* Test uniq() */
smartlist_split_string(sl,
"50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50",
",", 0, 0);
- smartlist_sort(sl, _compare_strs);
- smartlist_uniq(sl, _compare_strs, _tor_free);
+ smartlist_sort(sl, compare_strs_);
+ smartlist_uniq(sl, compare_strs_, tor_free_);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc, "50,a,canal,man,noon,panama,plan,radar");
tor_free(cp_alloc);
@@ -558,7 +558,7 @@ typedef struct pq_entry_t {
/** Helper: return a tristate based on comparing two pq_entry_t values. */
static int
-_compare_strings_for_pqueue(const void *p1, const void *p2)
+compare_strings_for_pqueue_(const void *p1, const void *p2)
{
const pq_entry_t *e1=p1, *e2=p2;
return strcmp(e1->val, e2->val);
@@ -588,7 +588,7 @@ test_container_pqueue(void)
#define OK() smartlist_pqueue_assert_ok(sl, cmp, offset)
- cmp = _compare_strings_for_pqueue;
+ cmp = compare_strings_for_pqueue_;
smartlist_pqueue_add(sl, cmp, offset, &cows);
smartlist_pqueue_add(sl, cmp, offset, &zebras);
smartlist_pqueue_add(sl, cmp, offset, &fish);
@@ -677,12 +677,12 @@ test_container_strmap(void)
test_eq(strmap_size(map), 0);
test_assert(strmap_isempty(map));
v = strmap_set(map, "K1", (void*)99);
- test_eq(v, NULL);
+ test_eq_ptr(v, NULL);
test_assert(!strmap_isempty(map));
v = strmap_set(map, "K2", (void*)101);
- test_eq(v, NULL);
+ test_eq_ptr(v, NULL);
v = strmap_set(map, "K1", (void*)100);
- test_eq(v, (void*)99);
+ test_eq_ptr(v, (void*)99);
test_eq_ptr(strmap_get(map,"K1"), (void*)100);
test_eq_ptr(strmap_get(map,"K2"), (void*)101);
test_eq_ptr(strmap_get(map,"K-not-there"), NULL);
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 7f4347a41c..ed1da39670 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -119,9 +119,9 @@ test_crypto_aes(void *arg)
memset(data2, 0, 1024);
memset(data3, 0, 1024);
env1 = crypto_cipher_new(NULL);
- test_neq(env1, 0);
+ test_neq_ptr(env1, 0);
env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
- test_neq(env2, 0);
+ test_neq_ptr(env2, 0);
/* Try encrypting 512 chars. */
crypto_cipher_encrypt(env1, data2, data1, 512);
@@ -152,7 +152,7 @@ test_crypto_aes(void *arg)
memset(data3, 0, 1024);
env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
- test_neq(env2, 0);
+ test_neq_ptr(env2, NULL);
for (j = 0; j < 1024-16; j += 17) {
crypto_cipher_encrypt(env2, data3+j, data1+j, 17);
}
@@ -427,6 +427,11 @@ test_crypto_pk(void)
test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size));
test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
+ /* comparison between keys and NULL */
+ tt_int_op(crypto_pk_cmp_keys(NULL, pk1), <, 0);
+ tt_int_op(crypto_pk_cmp_keys(NULL, NULL), ==, 0);
+ tt_int_op(crypto_pk_cmp_keys(pk1, NULL), >, 0);
+
test_eq(128, crypto_pk_keysize(pk1));
test_eq(1024, crypto_pk_num_bits(pk1));
test_eq(128, crypto_pk_keysize(pk2));
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 83c612045b..ff41bf2f3f 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -4,9 +4,12 @@
/* See LICENSE for licensing information */
#include "orconfig.h"
+#include <math.h>
+
#define DIRSERV_PRIVATE
#define DIRVOTE_PRIVATE
#define ROUTER_PRIVATE
+#define ROUTERLIST_PRIVATE
#define HIBERNATE_PRIVATE
#include "or.h"
#include "directory.h"
@@ -147,9 +150,9 @@ test_dir_formats(void)
"platform Tor "VERSION" on ", sizeof(buf2));
strlcat(buf2, get_uname(), sizeof(buf2));
strlcat(buf2, "\n"
- "opt protocols Link 1 2 Circuit 1\n"
+ "protocols Link 1 2 Circuit 1\n"
"published 1970-01-01 00:00:00\n"
- "opt fingerprint ", sizeof(buf2));
+ "fingerprint ", sizeof(buf2));
test_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1));
strlcat(buf2, fingerprint, sizeof(buf2));
strlcat(buf2, "\nuptime 0\n"
@@ -161,7 +164,7 @@ test_dir_formats(void)
strlcat(buf2, pk1_str, sizeof(buf2));
strlcat(buf2, "signing-key\n", sizeof(buf2));
strlcat(buf2, pk2_str, sizeof(buf2));
- strlcat(buf2, "opt hidden-service-dir\n", sizeof(buf2));
+ strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
strlcat(buf2, "reject *:*\nrouter-signature\n", sizeof(buf2));
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
* twice */
@@ -220,24 +223,6 @@ test_dir_formats(void)
add_fingerprint_to_dir("Fred", buf, fingerprint_list);
}
- {
- char d[DIGEST_LEN];
- const char *m;
- /* XXXX NM re-enable. */
- /* Make sure routers aren't too far in the past any more. */
- r1->cache_info.published_on = time(NULL);
- r2->cache_info.published_on = time(NULL)-3*60*60;
- test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
- test_eq(dirserv_add_descriptor(buf,&m,""), ROUTER_ADDED_NOTIFY_GENERATOR);
- test_assert(router_dump_router_to_string(buf, 2048, r2, pk1)>0);
- test_eq(dirserv_add_descriptor(buf,&m,""), ROUTER_ADDED_NOTIFY_GENERATOR);
- get_options()->Nickname = tor_strdup("DirServer");
- test_assert(!dirserv_dump_directory_to_string(&cp,pk3, 0));
- crypto_pk_get_digest(pk3, d);
- test_assert(!router_parse_directory(cp));
- test_eq(2, smartlist_len(dir1->routers));
- tor_free(cp);
- }
#endif
dirserv_free_fingerprint_list();
@@ -797,6 +782,7 @@ test_dir_v3_networkstatus(void)
networkstatus_t *vote=NULL, *v1=NULL, *v2=NULL, *v3=NULL, *con=NULL,
*con_md=NULL;
vote_routerstatus_t *vrs;
+ tor_addr_t addr_ipv6;
routerstatus_t *rs;
char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, *cp;
smartlist_t *votes = smartlist_new();
@@ -893,6 +879,9 @@ test_dir_v3_networkstatus(void)
rs->addr = 0x99009901;
rs->or_port = 443;
rs->dir_port = 0;
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
+ rs->ipv6_orport = 4711;
rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running =
rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1;
smartlist_add(vote->routerstatus_list, vrs);
@@ -987,6 +976,8 @@ test_dir_v3_networkstatus(void)
test_eq(rs->addr, 0x99009901);
test_eq(rs->or_port, 443);
test_eq(rs->dir_port, 0);
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority."
{
@@ -1169,6 +1160,8 @@ test_dir_v3_networkstatus(void)
test_eq(rs->addr, 0x99009901);
test_eq(rs->or_port, 443);
test_eq(rs->dir_port, 0);
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
test_assert(!rs->is_authority);
test_assert(rs->is_exit);
test_assert(rs->is_fast);
@@ -1381,6 +1374,124 @@ test_dir_v3_networkstatus(void)
ns_detached_signatures_free(dsig2);
}
+static void
+test_dir_scale_bw(void *testdata)
+{
+ double v[8] = { 2.0/3,
+ 7.0,
+ 1.0,
+ 3.0,
+ 1.0/5,
+ 1.0/7,
+ 12.0,
+ 24.0 };
+ u64_dbl_t vals[8];
+ uint64_t total;
+ int i;
+
+ (void) testdata;
+
+ for (i=0; i<8; ++i)
+ vals[i].dbl = v[i];
+
+ scale_array_elements_to_u64(vals, 8, &total);
+
+ tt_int_op((int)total, ==, 48);
+ total = 0;
+ for (i=0; i<8; ++i) {
+ total += vals[i].u64;
+ }
+ tt_assert(total >= (U64_LITERAL(1)<<60));
+ tt_assert(total <= (U64_LITERAL(1)<<62));
+
+ for (i=0; i<8; ++i) {
+ double ratio = ((double)vals[i].u64) / vals[2].u64;
+ tt_double_op(fabs(ratio - v[i]), <, .00001);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_dir_random_weighted(void *testdata)
+{
+ int histogram[10];
+ uint64_t vals[10] = {3,1,2,4,6,0,7,5,8,9}, total=0;
+ u64_dbl_t inp[10];
+ int i, choice;
+ const int n = 50000;
+ double max_sq_error;
+ (void) testdata;
+
+ /* Try a ten-element array with values from 0 through 10. The values are
+ * in a scrambled order to make sure we don't depend on order. */
+ memset(histogram,0,sizeof(histogram));
+ for (i=0; i<10; ++i) {
+ inp[i].u64 = vals[i];
+ total += vals[i];
+ }
+ tt_int_op(total, ==, 45);
+ for (i=0; i<n; ++i) {
+ choice = choose_array_element_by_weight(inp, 10);
+ tt_int_op(choice, >=, 0);
+ tt_int_op(choice, <, 10);
+ histogram[choice]++;
+ }
+
+ /* Now see if we chose things about frequently enough. */
+ max_sq_error = 0;
+ for (i=0; i<10; ++i) {
+ int expected = (int)(n*vals[i]/total);
+ double frac_diff = 0, sq;
+ TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected));
+ if (expected)
+ frac_diff = (histogram[i] - expected) / ((double)expected);
+ else
+ tt_int_op(histogram[i], ==, 0);
+
+ sq = frac_diff * frac_diff;
+ if (sq > max_sq_error)
+ max_sq_error = sq;
+ }
+ /* It should almost always be much much less than this. If you want to
+ * figure out the odds, please feel free. */
+ tt_double_op(max_sq_error, <, .05);
+
+ /* Now try a singleton; do we choose it? */
+ for (i = 0; i < 100; ++i) {
+ choice = choose_array_element_by_weight(inp, 1);
+ tt_int_op(choice, ==, 0);
+ }
+
+ /* Now try an array of zeros. We should choose randomly. */
+ memset(histogram,0,sizeof(histogram));
+ for (i = 0; i < 5; ++i)
+ inp[i].u64 = 0;
+ for (i = 0; i < n; ++i) {
+ choice = choose_array_element_by_weight(inp, 5);
+ tt_int_op(choice, >=, 0);
+ tt_int_op(choice, <, 5);
+ histogram[choice]++;
+ }
+ /* Now see if we chose things about frequently enough. */
+ max_sq_error = 0;
+ for (i=0; i<5; ++i) {
+ int expected = n/5;
+ double frac_diff = 0, sq;
+ TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected));
+ frac_diff = (histogram[i] - expected) / ((double)expected);
+ sq = frac_diff * frac_diff;
+ if (sq > max_sq_error)
+ max_sq_error = sq;
+ }
+ /* It should almost always be much much less than this. If you want to
+ * figure out the odds, please feel free. */
+ tt_double_op(max_sq_error, <, .05);
+ done:
+ ;
+}
+
#define DIR_LEGACY(name) \
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name }
@@ -1396,6 +1507,8 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(measured_bw),
DIR_LEGACY(param_voting),
DIR_LEGACY(v3_networkstatus),
+ DIR(random_weighted),
+ DIR(scale_bw),
END_OF_TESTCASES
};
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
new file mode 100644
index 0000000000..992d9cd507
--- /dev/null
+++ b/src/test/test_introduce.c
@@ -0,0 +1,528 @@
+/* Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "crypto.h"
+#include "or.h"
+#include "test.h"
+
+#define RENDSERVICE_PRIVATE
+#include "rendservice.h"
+
+extern const char AUTHORITY_SIGNKEY_1[];
+
+static uint8_t v0_test_plaintext[] =
+ /* 20 bytes of rendezvous point nickname */
+ { 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v1_test_plaintext[] =
+ /* Version byte */
+ { 0x01,
+ /* 42 bytes of dummy rendezvous point hex digest */
+ 0x24, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30,
+ 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30,
+ 0x37, 0x30, 0x38, 0x30, 0x39, 0x30, 0x41, 0x30,
+ 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30,
+ 0x46, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31,
+ 0x33, 0x00,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v2_test_plaintext[] =
+ /* Version byte */
+ { 0x02,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v3_no_auth_test_plaintext[] =
+ /* Version byte */
+ { 0x03,
+ /* Auth type (0 for no auth len/auth data) */
+ 0x00,
+ /* Timestamp */
+ 0x50, 0x0b, 0xb5, 0xaa,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v3_basic_auth_test_plaintext[] =
+ /* Version byte */
+ { 0x03,
+ /* Auth type (1 for REND_BASIC_AUTH) */
+ 0x01,
+ /* Auth len (must be 16 bytes for REND_BASIC_AUTH) */
+ 0x00, 0x10,
+ /* Auth data (a 16-byte dummy descriptor cookie) */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ /* Timestamp */
+ 0x50, 0x0b, 0xb5, 0xaa,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static void do_decrypt_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_early_parse_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_late_parse_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase);
+static ssize_t make_intro_from_plaintext(
+ void *buf, size_t len, crypto_pk_t *key, void **cell_out);
+
+#define EARLY_PARSE_ONLY 1
+#define DECRYPT_ONLY 2
+#define ALL_PARSING 3
+
+static void
+do_early_parse_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, EARLY_PARSE_ONLY);
+}
+
+static void
+do_decrypt_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, DECRYPT_ONLY);
+}
+
+static void
+do_late_parse_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, ALL_PARSING);
+}
+
+/** Test utility function: checks that the <b>plaintext_len</b>-byte string at
+ * <b>plaintext</b> is at least superficially parseable.
+ */
+static void
+do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
+{
+ crypto_pk_t *k = NULL;
+ ssize_t r;
+ uint8_t *cell = NULL;
+ size_t cell_len;
+ rend_intro_cell_t *parsed_req = NULL;
+ char *err_msg = NULL;
+ char digest[DIGEST_LEN];
+
+ /* Get a key */
+ k = crypto_pk_new();
+ test_assert(k);
+ r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1);
+ test_assert(!r);
+
+ /* Get digest for future comparison */
+ r = crypto_pk_get_digest(k, digest);
+ test_assert(r >= 0);
+
+ /* Make a cell out of it */
+ r = make_intro_from_plaintext(
+ plaintext, plaintext_len,
+ k, (void **)(&cell));
+ test_assert(r > 0);
+ test_assert(cell);
+ cell_len = r;
+
+ /* Do early parsing */
+ parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg);
+ test_assert(parsed_req);
+ test_assert(!err_msg);
+ test_memeq(parsed_req->pk, digest, DIGEST_LEN);
+ test_assert(parsed_req->ciphertext);
+ test_assert(parsed_req->ciphertext_len > 0);
+
+ if (phase == EARLY_PARSE_ONLY)
+ goto done;
+
+ /* Do decryption */
+ r = rend_service_decrypt_intro(parsed_req, k, &err_msg);
+ test_assert(!r);
+ test_assert(!err_msg);
+ test_assert(parsed_req->plaintext);
+ test_assert(parsed_req->plaintext_len > 0);
+
+ if (phase == DECRYPT_ONLY)
+ goto done;
+
+ /* Do late parsing */
+ r = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
+ test_assert(!r);
+ test_assert(!err_msg);
+ test_assert(parsed_req->parsed);
+
+ done:
+ tor_free(cell);
+ crypto_pk_free(k);
+ rend_service_free_intro(parsed_req);
+ tor_free(err_msg);
+}
+
+/** Given the plaintext of the encrypted part of an INTRODUCE1/2 and a key,
+ * construct the encrypted cell for testing.
+ */
+
+static ssize_t
+make_intro_from_plaintext(
+ void *buf, size_t len, crypto_pk_t *key, void **cell_out)
+{
+ char *cell = NULL;
+ ssize_t cell_len = -1, r;
+ /* Assemble key digest and ciphertext, then construct the cell */
+ ssize_t ciphertext_size;
+
+ if (!(buf && key && len > 0 && cell_out)) goto done;
+
+ /*
+ * Figure out an upper bound on how big the ciphertext will be
+ * (see crypto_pk_public_hybrid_encrypt())
+ */
+ ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD;
+ ciphertext_size += crypto_pk_keysize(key);
+ ciphertext_size += CIPHER_KEY_LEN;
+ ciphertext_size += len;
+
+ /*
+ * Allocate space for the cell
+ */
+ cell = tor_malloc(DIGEST_LEN + ciphertext_size);
+
+ /* Compute key digest (will be first DIGEST_LEN octets of cell) */
+ r = crypto_pk_get_digest(key, cell);
+ test_assert(r >= 0);
+
+ /* Do encryption */
+ r = crypto_pk_public_hybrid_encrypt(
+ key, cell + DIGEST_LEN, ciphertext_size,
+ buf, len,
+ PK_PKCS1_OAEP_PADDING, 0);
+ test_assert(r >= 0);
+
+ /* Figure out cell length */
+ cell_len = DIGEST_LEN + r;
+
+ /* Output the cell */
+ *cell_out = cell;
+
+ done:
+ return cell_len;
+}
+
+/** Test v0 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v0(void)
+{
+ do_decrypt_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v1(void)
+{
+ do_decrypt_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v2(void)
+{
+ do_decrypt_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v3(void)
+{
+ do_decrypt_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_decrypt_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+/** Test v0 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v0(void)
+{
+ do_early_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v1(void)
+{
+ do_early_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v2(void)
+{
+ do_early_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v3(void)
+{
+ do_early_parse_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_early_parse_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+/** Test v0 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v0(void)
+{
+ do_late_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v1(void)
+{
+ do_late_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v2(void)
+{
+ do_late_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v3(void)
+{
+ do_late_parse_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_late_parse_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+#define INTRODUCE_LEGACY(name) \
+ { #name, legacy_test_helper, 0, &legacy_setup, test_introduce_ ## name }
+
+struct testcase_t introduce_tests[] = {
+ INTRODUCE_LEGACY(early_parse_v0),
+ INTRODUCE_LEGACY(early_parse_v1),
+ INTRODUCE_LEGACY(early_parse_v2),
+ INTRODUCE_LEGACY(early_parse_v3),
+ INTRODUCE_LEGACY(decrypt_v0),
+ INTRODUCE_LEGACY(decrypt_v1),
+ INTRODUCE_LEGACY(decrypt_v2),
+ INTRODUCE_LEGACY(decrypt_v3),
+ INTRODUCE_LEGACY(late_parse_v0),
+ INTRODUCE_LEGACY(late_parse_v1),
+ INTRODUCE_LEGACY(late_parse_v2),
+ INTRODUCE_LEGACY(late_parse_v3),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
new file mode 100644
index 0000000000..b08818f06b
--- /dev/null
+++ b/src/test/test_replay.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define REPLAYCACHE_PRIVATE
+
+#include "orconfig.h"
+#include "or.h"
+#include "replaycache.h"
+#include "test.h"
+
+static const char *test_buffer =
+ "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed do eiusmod"
+ " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim"
+ " veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea"
+ " commodo consequat. Duis aute irure dolor in reprehenderit in voluptate"
+ " velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint"
+ " occaecat cupidatat non proident, sunt in culpa qui officia deserunt"
+ " mollit anim id est laborum.";
+
+static void
+test_replaycache_alloc(void)
+{
+ replaycache_t *r = NULL;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+ if (!r) goto done;
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_miss(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+ if (!r) goto done;
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_hit(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+ if (!r) goto done;
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_age(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+ if (!r) goto done;
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ result =
+ replaycache_add_and_test_internal(3000, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_elapsed(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+ time_t elapsed;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+ if (!r) goto done;
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), &elapsed);
+ test_eq(result, 1);
+ test_eq(elapsed, 100);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_noexpire(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(0, 0);
+ test_assert(r != NULL);
+ if (!r) goto done;
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ result =
+ replaycache_add_and_test_internal(3000, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+#define REPLAYCACHE_LEGACY(name) \
+ { #name, legacy_test_helper, 0, &legacy_setup, test_replaycache_ ## name }
+
+struct testcase_t replaycache_tests[] = {
+ REPLAYCACHE_LEGACY(alloc),
+ REPLAYCACHE_LEGACY(miss),
+ REPLAYCACHE_LEGACY(hit),
+ REPLAYCACHE_LEGACY(age),
+ REPLAYCACHE_LEGACY(elapsed),
+ REPLAYCACHE_LEGACY(noexpire),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 4f9eb73e03..3ed2cbb54d 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -32,6 +32,74 @@ tor_timegm_wrapper(const struct tm *tm)
#define tor_timegm tor_timegm_wrapper
static void
+test_util_read_until_eof_impl(const char *fname, size_t file_len,
+ size_t read_limit)
+{
+ char *fifo_name = NULL;
+ char *test_str = NULL;
+ char *str = NULL;
+ size_t sz = 9999999;
+ int fd = -1;
+ int r;
+
+ fifo_name = tor_strdup(get_fname(fname));
+ test_str = tor_malloc(file_len);
+ crypto_rand(test_str, file_len);
+
+ r = write_bytes_to_file(fifo_name, test_str, file_len, 1);
+ tt_int_op(r, ==, 0);
+
+ fd = open(fifo_name, O_RDONLY|O_BINARY);
+ tt_int_op(fd, >=, 0);
+ str = read_file_to_str_until_eof(fd, read_limit, &sz);
+ close(fd);
+ tt_assert(str != NULL);
+
+ if (read_limit < file_len)
+ tt_int_op(sz, ==, read_limit);
+ else
+ tt_int_op(sz, ==, file_len);
+
+ test_mem_op(test_str, ==, str, sz);
+ test_assert(str[sz] == '\0');
+
+ done:
+ unlink(fifo_name);
+ tor_free(fifo_name);
+ tor_free(test_str);
+ tor_free(str);
+}
+
+static void
+test_util_read_file_eof_tiny_limit(void *arg)
+{
+ (void)arg;
+ // purposely set limit shorter than what we wrote to the FIFO to
+ // test the maximum, and that it puts the NUL in the right spot
+
+ test_util_read_until_eof_impl("tor_test_fifo_tiny", 5, 4);
+}
+
+static void
+test_util_read_file_eof_two_loops(void *arg)
+{
+ (void)arg;
+ // write more than 1024 bytes to the FIFO to test two passes through
+ // the loop in the method; if the re-alloc size is changed this
+ // should be updated as well.
+
+ test_util_read_until_eof_impl("tor_test_fifo_2k", 2048, 10000);
+}
+
+static void
+test_util_read_file_eof_zero_bytes(void *arg)
+{
+ (void)arg;
+ // zero-byte fifo
+ test_util_read_until_eof_impl("tor_test_fifo_empty", 0, 10000);
+}
+
+static void
test_util_time(void)
{
struct timeval start, end;
@@ -152,6 +220,7 @@ test_util_time(void)
test_eq(-1, parse_iso_time("2011-03-30 23:59:62 GMT", &t_res));
test_eq(-1, parse_iso_time("1969-03-30 23:59:59 GMT", &t_res));
test_eq(-1, parse_iso_time("2011-00-30 23:59:59 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2147483647-08-29 14:00:00", &t_res));
test_eq(-1, parse_iso_time("2011-03-30 23:59", &t_res));
/* Test tor_gettimeofday */
@@ -936,7 +1005,7 @@ test_util_strmisc(void)
const char *s = "abcdefghijklmnopqrstuvwxyz";
cp = tor_strndup(s, 30);
test_streq(cp, s); /* same string, */
- test_neq(cp, s); /* but different pointers. */
+ test_neq_ptr(cp, s); /* but different pointers. */
tor_free(cp);
cp = tor_strndup(s, 5);
@@ -946,7 +1015,7 @@ test_util_strmisc(void)
s = "a\0b\0c\0d\0e\0";
cp = tor_memdup(s,10);
test_memeq(cp, s, 10); /* same ram, */
- test_neq(cp, s); /* but different pointers. */
+ test_neq_ptr(cp, s); /* but different pointers. */
tor_free(cp);
}
@@ -1109,6 +1178,7 @@ test_util_pow2(void)
test_eq(tor_log2(64), 6);
test_eq(tor_log2(65), 6);
test_eq(tor_log2(63), 5);
+ test_eq(tor_log2(0), 0); /* incorrect mathematically, but as specified */
test_eq(tor_log2(1), 0);
test_eq(tor_log2(2), 1);
test_eq(tor_log2(3), 1);
@@ -1123,26 +1193,35 @@ test_util_pow2(void)
test_eq(round_to_power_of_2(130), 128);
test_eq(round_to_power_of_2(U64_LITERAL(40000000000000000)),
U64_LITERAL(1)<<55);
- test_eq(round_to_power_of_2(0), 2);
+ test_eq(round_to_power_of_2(U64_LITERAL(0xffffffffffffffff)),
+ U64_LITERAL(1)<<63);
+ test_eq(round_to_power_of_2(0), 1);
+ test_eq(round_to_power_of_2(1), 1);
+ test_eq(round_to_power_of_2(2), 2);
+ test_eq(round_to_power_of_2(3), 2);
+ test_eq(round_to_power_of_2(4), 4);
+ test_eq(round_to_power_of_2(5), 4);
+ test_eq(round_to_power_of_2(6), 4);
+ test_eq(round_to_power_of_2(7), 8);
done:
;
}
/** mutex for thread test to stop the threads hitting data at the same time. */
-static tor_mutex_t *_thread_test_mutex = NULL;
+static tor_mutex_t *thread_test_mutex_ = NULL;
/** mutexes for the thread test to make sure that the threads have to
* interleave somewhat. */
-static tor_mutex_t *_thread_test_start1 = NULL,
- *_thread_test_start2 = NULL;
+static tor_mutex_t *thread_test_start1_ = NULL,
+ *thread_test_start2_ = NULL;
/** Shared strmap for the thread test. */
-static strmap_t *_thread_test_strmap = NULL;
+static strmap_t *thread_test_strmap_ = NULL;
/** The name of thread1 for the thread test */
-static char *_thread1_name = NULL;
+static char *thread1_name_ = NULL;
/** The name of thread2 for the thread test */
-static char *_thread2_name = NULL;
+static char *thread2_name_ = NULL;
-static void _thread_test_func(void* _s) ATTR_NORETURN;
+static void thread_test_func_(void* _s) ATTR_NORETURN;
/** How many iterations have the threads in the unit test run? */
static int t1_count = 0, t2_count = 0;
@@ -1150,9 +1229,9 @@ static int t1_count = 0, t2_count = 0;
/** Helper function for threading unit tests: This function runs in a
* subthread. It grabs its own mutex (start1 or start2) to make sure that it
* should start, then it repeatedly alters _test_thread_strmap protected by
- * _thread_test_mutex. */
+ * thread_test_mutex_. */
static void
-_thread_test_func(void* _s)
+thread_test_func_(void* _s)
{
char *s = _s;
int i, *count;
@@ -1160,12 +1239,12 @@ _thread_test_func(void* _s)
char buf[64];
char **cp;
if (!strcmp(s, "thread 1")) {
- m = _thread_test_start1;
- cp = &_thread1_name;
+ m = thread_test_start1_;
+ cp = &thread1_name_;
count = &t1_count;
} else {
- m = _thread_test_start2;
- cp = &_thread2_name;
+ m = thread_test_start2_;
+ cp = &thread2_name_;
count = &t2_count;
}
@@ -1175,14 +1254,14 @@ _thread_test_func(void* _s)
tor_mutex_acquire(m);
for (i=0; i<10000; ++i) {
- tor_mutex_acquire(_thread_test_mutex);
- strmap_set(_thread_test_strmap, "last to run", *cp);
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_set(thread_test_strmap_, "last to run", *cp);
++*count;
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_release(thread_test_mutex_);
}
- tor_mutex_acquire(_thread_test_mutex);
- strmap_set(_thread_test_strmap, s, *cp);
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_set(thread_test_strmap_, s, *cp);
+ tor_mutex_release(thread_test_mutex_);
tor_mutex_release(m);
@@ -1207,67 +1286,67 @@ test_util_threads(void)
if (1)
return;
#endif
- _thread_test_mutex = tor_mutex_new();
- _thread_test_start1 = tor_mutex_new();
- _thread_test_start2 = tor_mutex_new();
- _thread_test_strmap = strmap_new();
+ thread_test_mutex_ = tor_mutex_new();
+ thread_test_start1_ = tor_mutex_new();
+ thread_test_start2_ = tor_mutex_new();
+ thread_test_strmap_ = strmap_new();
s1 = tor_strdup("thread 1");
s2 = tor_strdup("thread 2");
- tor_mutex_acquire(_thread_test_start1);
- tor_mutex_acquire(_thread_test_start2);
- spawn_func(_thread_test_func, s1);
- spawn_func(_thread_test_func, s2);
- tor_mutex_release(_thread_test_start2);
- tor_mutex_release(_thread_test_start1);
+ tor_mutex_acquire(thread_test_start1_);
+ tor_mutex_acquire(thread_test_start2_);
+ spawn_func(thread_test_func_, s1);
+ spawn_func(thread_test_func_, s2);
+ tor_mutex_release(thread_test_start2_);
+ tor_mutex_release(thread_test_start1_);
started = time(NULL);
while (!done) {
- tor_mutex_acquire(_thread_test_mutex);
- strmap_assert_ok(_thread_test_strmap);
- if (strmap_get(_thread_test_strmap, "thread 1") &&
- strmap_get(_thread_test_strmap, "thread 2")) {
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_assert_ok(thread_test_strmap_);
+ if (strmap_get(thread_test_strmap_, "thread 1") &&
+ strmap_get(thread_test_strmap_, "thread 2")) {
done = 1;
} else if (time(NULL) > started + 150) {
timedout = done = 1;
}
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_release(thread_test_mutex_);
#ifndef _WIN32
/* Prevent the main thread from starving the worker threads. */
select(0, NULL, NULL, NULL, &tv);
#endif
}
- tor_mutex_acquire(_thread_test_start1);
- tor_mutex_release(_thread_test_start1);
- tor_mutex_acquire(_thread_test_start2);
- tor_mutex_release(_thread_test_start2);
+ tor_mutex_acquire(thread_test_start1_);
+ tor_mutex_release(thread_test_start1_);
+ tor_mutex_acquire(thread_test_start2_);
+ tor_mutex_release(thread_test_start2_);
- tor_mutex_free(_thread_test_mutex);
+ tor_mutex_free(thread_test_mutex_);
if (timedout) {
printf("\nTimed out: %d %d", t1_count, t2_count);
- test_assert(strmap_get(_thread_test_strmap, "thread 1"));
- test_assert(strmap_get(_thread_test_strmap, "thread 2"));
+ test_assert(strmap_get(thread_test_strmap_, "thread 1"));
+ test_assert(strmap_get(thread_test_strmap_, "thread 2"));
test_assert(!timedout);
}
/* different thread IDs. */
- test_assert(strcmp(strmap_get(_thread_test_strmap, "thread 1"),
- strmap_get(_thread_test_strmap, "thread 2")));
- test_assert(!strcmp(strmap_get(_thread_test_strmap, "thread 1"),
- strmap_get(_thread_test_strmap, "last to run")) ||
- !strcmp(strmap_get(_thread_test_strmap, "thread 2"),
- strmap_get(_thread_test_strmap, "last to run")));
+ test_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"),
+ strmap_get(thread_test_strmap_, "thread 2")));
+ test_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"),
+ strmap_get(thread_test_strmap_, "last to run")) ||
+ !strcmp(strmap_get(thread_test_strmap_, "thread 2"),
+ strmap_get(thread_test_strmap_, "last to run")));
done:
tor_free(s1);
tor_free(s2);
- tor_free(_thread1_name);
- tor_free(_thread2_name);
- if (_thread_test_strmap)
- strmap_free(_thread_test_strmap, NULL);
- if (_thread_test_start1)
- tor_mutex_free(_thread_test_start1);
- if (_thread_test_start2)
- tor_mutex_free(_thread_test_start2);
+ tor_free(thread1_name_);
+ tor_free(thread2_name_);
+ if (thread_test_strmap_)
+ strmap_free(thread_test_strmap_, NULL);
+ if (thread_test_start1_)
+ tor_mutex_free(thread_test_start1_);
+ if (thread_test_start2_)
+ tor_mutex_free(thread_test_start2_);
}
/** Run unit tests for compression functions */
@@ -1416,7 +1495,7 @@ test_util_mmap(void)
/* Now a zero-length file. */
write_str_to_file(fname1, "", 1);
mapping = tor_mmap_file(fname1);
- test_eq(mapping, NULL);
+ test_eq_ptr(mapping, NULL);
test_eq(ERANGE, errno);
unlink(fname1);
@@ -1474,12 +1553,28 @@ test_util_control_formats(void)
tor_free(out);
}
+#define test_feq(value1,value2) do { \
+ double v1 = (value1), v2=(value2); \
+ double tf_diff = v1-v2; \
+ double tf_tolerance = ((v1+v2)/2.0)/1e8; \
+ if (tf_diff<0) tf_diff=-tf_diff; \
+ if (tf_tolerance<0) tf_tolerance=-tf_tolerance; \
+ if (tf_diff<tf_tolerance) { \
+ TT_BLATHER(("%s ~~ %s: %f ~~ %f",#value1,#value2,v1,v2)); \
+ } else { \
+ TT_FAIL(("%s ~~ %s: %f != %f",#value1,#value2,v1,v2)); \
+ } \
+ } while (0)
+
static void
test_util_sscanf(void)
{
unsigned u1, u2, u3;
char s1[20], s2[10], s3[10], ch;
int r;
+ long lng1,lng2;
+ int int1, int2;
+ double d1,d2,d3,d4;
/* Simple tests (malformed patterns, literal matching, ...) */
test_eq(-1, tor_sscanf("123", "%i", &r)); /* %i is not supported */
@@ -1608,6 +1703,65 @@ test_util_sscanf(void)
test_eq(4, tor_sscanf("1.2.3 foobar", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
test_eq(' ', ch);
+ r = tor_sscanf("12345 -67890 -1", "%d %ld %d", &int1, &lng1, &int2);
+ test_eq(r,3);
+ test_eq(int1, 12345);
+ test_eq(lng1, -67890);
+ test_eq(int2, -1);
+
+#if SIZEOF_INT == 4
+ r = tor_sscanf("-2147483648. 2147483647.", "%d. %d.", &int1, &int2);
+ test_eq(r,2);
+ test_eq(int1, -2147483647-1);
+ test_eq(int2, 2147483647);
+
+ r = tor_sscanf("-2147483679.", "%d.", &int1);
+ test_eq(r,0);
+
+ r = tor_sscanf("2147483678.", "%d.", &int1);
+ test_eq(r,0);
+#elif SIZEOF_INT == 8
+ r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
+ "%d. %d.", &int1, &int2);
+ test_eq(r,2);
+ test_eq(int1, -9223372036854775807-1);
+ test_eq(int2, 9223372036854775807);
+
+ r = tor_sscanf("-9223372036854775809.", "%d.", &int1);
+ test_eq(r,0);
+
+ r = tor_sscanf("9223372036854775808.", "%d.", &int1);
+ test_eq(r,0);
+#endif
+
+#if SIZEOF_LONG == 4
+ r = tor_sscanf("-2147483648. 2147483647.", "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,2);
+ test_eq(lng1, -2147483647 - 1);
+ test_eq(lng2, 2147483647);
+#elif SIZEOF_LONG == 8
+ r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,2);
+ test_eq(lng1, -9223372036854775807L - 1);
+ test_eq(lng2, 9223372036854775807L);
+
+ r = tor_sscanf("-9223372036854775808. 9223372036854775808.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,1);
+ r = tor_sscanf("-9223372036854775809. 9223372036854775808.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,0);
+#endif
+
+ r = tor_sscanf("123.456 .000007 -900123123.2000787 00003.2",
+ "%lf %lf %lf %lf", &d1,&d2,&d3,&d4);
+ test_eq(r,4);
+ test_feq(d1, 123.456);
+ test_feq(d2, .000007);
+ test_feq(d3, -900123123.2000787);
+ test_feq(d4, 3.2);
+
done:
;
}
@@ -1735,7 +1889,7 @@ test_util_memarea(void)
/* Make sure we don't overalign. */
p1 = memarea_alloc(area, 1);
p2 = memarea_alloc(area, 1);
- test_eq(p1+sizeof(void*), p2);
+ test_eq_ptr(p1+sizeof(void*), p2);
{
malloced_ptr = tor_malloc(64);
test_assert(!memarea_owns_ptr(area, malloced_ptr));
@@ -1780,7 +1934,7 @@ test_util_memarea(void)
memarea_clear(area);
p1 = memarea_alloc(area, 1);
- test_eq(p1, p1_orig);
+ test_eq_ptr(p1, p1_orig);
memarea_clear(area);
/* Check for running over an area's size. */
@@ -2136,7 +2290,7 @@ test_util_load_win_lib(void *ptr)
tt_assert(h);
done:
if (h)
- CloseHandle(h);
+ FreeLibrary(h);
}
#endif
@@ -3044,7 +3198,7 @@ test_util_set_env_var_in_sl(void *ptr)
SMARTLIST_FOREACH(new_env_vars, char *, env_var,
set_environment_variable_in_smartlist(merged_env_vars,
env_var,
- _tor_free,
+ tor_free_,
1));
smartlist_sort_strings(merged_env_vars);
@@ -3129,6 +3283,9 @@ struct testcase_t util_tests[] = {
UTIL_TEST(envnames, 0),
UTIL_TEST(make_environment, 0),
UTIL_TEST(set_env_var_in_sl, 0),
+ UTIL_TEST(read_file_eof_tiny_limit, 0),
+ UTIL_TEST(read_file_eof_two_loops, 0),
+ UTIL_TEST(read_file_eof_zero_bytes, 0),
END_OF_TESTCASES
};
diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am
deleted file mode 100644
index 35b0a41f53..0000000000
--- a/src/tools/Makefile.am
+++ /dev/null
@@ -1,22 +0,0 @@
-bin_PROGRAMS = tor-resolve tor-gencert
-noinst_PROGRAMS = tor-checkkey
-
-tor_resolve_SOURCES = tor-resolve.c
-tor_resolve_LDFLAGS =
-tor_resolve_LDADD = ../common/libor.a @TOR_LIB_MATH@ @TOR_LIB_WS32@
-
-tor_gencert_SOURCES = tor-gencert.c
-tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
-tor_gencert_LDADD = ../common/libor.a ../common/libor-crypto.a \
- @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-tor_checkkey_SOURCES = tor-checkkey.c
-tor_checkkey_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
-tor_checkkey_LDADD = ../common/libor.a ../common/libor-crypto.a \
- @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-SUBDIRS = tor-fw-helper
-DIST_SUBDIRS = tor-fw-helper
-
diff --git a/src/tools/include.am b/src/tools/include.am
new file mode 100644
index 0000000000..7337eff163
--- /dev/null
+++ b/src/tools/include.am
@@ -0,0 +1,22 @@
+bin_PROGRAMS+= src/tools/tor-resolve src/tools/tor-gencert
+noinst_PROGRAMS+= src/tools/tor-checkkey
+
+src_tools_tor_resolve_SOURCES = src/tools/tor-resolve.c
+src_tools_tor_resolve_LDFLAGS =
+src_tools_tor_resolve_LDADD = src/common/libor.a @TOR_LIB_MATH@ @TOR_LIB_WS32@
+
+src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c
+src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
+src_tools_tor_gencert_LDADD = src/common/libor.a src/common/libor-crypto.a \
+ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+
+src_tools_tor_checkkey_SOURCES = src/tools/tor-checkkey.c
+src_tools_tor_checkkey_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
+src_tools_tor_checkkey_LDADD = src/common/libor.a src/common/libor-crypto.a \
+ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+
+include src/tools/tor-fw-helper/include.am
+
+
diff --git a/src/tools/tor-checkkey.c b/src/tools/tor-checkkey.c
index 10d13d8371..05fc8d86c8 100644
--- a/src/tools/tor-checkkey.c
+++ b/src/tools/tor-checkkey.c
@@ -71,7 +71,7 @@ main(int c, char **v)
return 1;
printf("%s\n",digest);
} else {
- rsa = _crypto_pk_get_rsa(env);
+ rsa = crypto_pk_get_rsa_(env);
str = BN_bn2hex(rsa->n);
printf("%s\n", str);
diff --git a/src/tools/tor-fw-helper/Makefile.am b/src/tools/tor-fw-helper/Makefile.am
deleted file mode 100644
index 393562db03..0000000000
--- a/src/tools/tor-fw-helper/Makefile.am
+++ /dev/null
@@ -1,38 +0,0 @@
-if USE_FW_HELPER
-bin_PROGRAMS = tor-fw-helper
-else
-bin_PROGRAMS =
-endif
-
-tor_fw_helper_SOURCES = \
- tor-fw-helper.c \
- tor-fw-helper-natpmp.c \
- tor-fw-helper-upnp.c
-noinst_HEADERS = \
- tor-fw-helper.h \
- tor-fw-helper-natpmp.h \
- tor-fw-helper-upnp.h
-
-if NAT_PMP
-nat_pmp_ldflags = @TOR_LDFLAGS_libnatpmp@
-nat_pmp_ldadd = -lnatpmp @TOR_LIB_IPHLPAPI@
-nat_pmp_cppflags = @TOR_CPPFLAGS_libnatpmp@
-else
-nat_pmp_ldflags =
-nat_pmp_ldadd =
-nat_pmp_cppflags =
-endif
-
-if MINIUPNPC
-miniupnpc_ldflags = @TOR_LDFLAGS_libminiupnpc@
-miniupnpc_ldadd = -lminiupnpc -lm @TOR_LIB_IPHLPAPI@
-miniupnpc_cppflags = @TOR_CPPFLAGS_libminiupnpc@
-else
-miniupnpc_ldflags =
-miniupnpc_ldadd =
-miniupnpc_cppflags =
-endif
-
-tor_fw_helper_LDFLAGS = $(nat_pmp_ldflags) $(miniupnpc_ldflags)
-tor_fw_helper_LDADD = ../../common/libor.a $(nat_pmp_ldadd) $(miniupnpc_ldadd) @TOR_LIB_WS32@
-tor_fw_helper_CPPFLAGS = $(nat_pmp_cppflags) $(miniupnpc_cppflags)
diff --git a/src/tools/tor-fw-helper/include.am b/src/tools/tor-fw-helper/include.am
new file mode 100644
index 0000000000..275a0e237c
--- /dev/null
+++ b/src/tools/tor-fw-helper/include.am
@@ -0,0 +1,36 @@
+if USE_FW_HELPER
+bin_PROGRAMS+= src/tools/tor-fw-helper/tor-fw-helper
+endif
+
+src_tools_tor_fw_helper_tor_fw_helper_SOURCES = \
+ src/tools/tor-fw-helper/tor-fw-helper.c \
+ src/tools/tor-fw-helper/tor-fw-helper-natpmp.c \
+ src/tools/tor-fw-helper/tor-fw-helper-upnp.c
+noinst_HEADERS+= \
+ src/tools/tor-fw-helper/tor-fw-helper.h \
+ src/tools/tor-fw-helper/tor-fw-helper-natpmp.h \
+ src/tools/tor-fw-helper/tor-fw-helper-upnp.h
+
+if NAT_PMP
+nat_pmp_ldflags = @TOR_LDFLAGS_libnatpmp@
+nat_pmp_ldadd = -lnatpmp @TOR_LIB_IPHLPAPI@
+nat_pmp_cppflags = @TOR_CPPFLAGS_libnatpmp@
+else
+nat_pmp_ldflags =
+nat_pmp_ldadd =
+nat_pmp_cppflags =
+endif
+
+if MINIUPNPC
+miniupnpc_ldflags = @TOR_LDFLAGS_libminiupnpc@
+miniupnpc_ldadd = -lminiupnpc @TOR_LIB_IPHLPAPI@
+miniupnpc_cppflags = @TOR_CPPFLAGS_libminiupnpc@
+else
+miniupnpc_ldflags =
+miniupnpc_ldadd =
+miniupnpc_cppflags =
+endif
+
+src_tools_tor_fw_helper_tor_fw_helper_LDFLAGS = $(nat_pmp_ldflags) $(miniupnpc_ldflags)
+src_tools_tor_fw_helper_tor_fw_helper_LDADD = src/common/libor.a $(nat_pmp_ldadd) $(miniupnpc_ldadd) -lm @TOR_LIB_WS32@
+src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS = $(nat_pmp_cppflags) $(miniupnpc_cppflags)
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
index 0e0b385f9b..ee6d5f3434 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
@@ -60,15 +60,15 @@ tor_natpmp_init(tor_fw_options_t *tor_fw_options, void *backend_state)
state->lease = NATPMP_DEFAULT_LEASE;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: natpmp init...\n");
+ fprintf(stderr, "V: natpmp init...\n");
r = initnatpmp(&(state->natpmp), 0, 0);
if (r == 0) {
state->init = 1;
- fprintf(stdout, "tor-fw-helper: natpmp initialized...\n");
+ fprintf(stderr, "V: natpmp initialized...\n");
return r;
} else {
- fprintf(stderr, "tor-fw-helper: natpmp failed to initialize...\n");
+ fprintf(stderr, "V: natpmp failed to initialize...\n");
return r;
}
}
@@ -80,10 +80,10 @@ tor_natpmp_cleanup(tor_fw_options_t *tor_fw_options, void *backend_state)
natpmp_state_t *state = (natpmp_state_t *) backend_state;
int r = 0;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: natpmp cleanup...\n");
+ fprintf(stderr, "V: natpmp cleanup...\n");
r = closenatpmp(&(state->natpmp));
if (tor_fw_options->verbose)
- fprintf(stdout, "V: closing natpmp socket: %d\n", r);
+ fprintf(stderr, "V: closing natpmp socket: %d\n", r);
return r;
}
@@ -101,7 +101,7 @@ wait_until_fd_readable(tor_socket_t fd, struct timeval *timeout)
FD_SET(fd, &fds);
r = select(fd+1, &fds, NULL, NULL, timeout);
if (r == -1) {
- fprintf(stdout, "V: select failed in wait_until_fd_readable: %s\n",
+ fprintf(stderr, "V: select failed in wait_until_fd_readable: %s\n",
strerror(errno));
return -1;
}
@@ -110,27 +110,25 @@ wait_until_fd_readable(tor_socket_t fd, struct timeval *timeout)
return 0;
}
-/** Add a TCP port mapping for a single port stored in <b>tor_fw_options</b>
- * using the <b>natpmp_t</b> stored in <b>backend_state</b>. */
int
-tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
- void *backend_state)
+tor_natpmp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state)
{
- natpmp_state_t *state = (natpmp_state_t *) backend_state;
int r = 0;
int x = 0;
int sav_errno;
+ natpmp_state_t *state = (natpmp_state_t *) backend_state;
struct timeval timeout;
- if (tor_fw_options->verbose)
- fprintf(stdout, "V: sending natpmp portmapping request...\n");
+ if (is_verbose)
+ fprintf(stderr, "V: sending natpmp portmapping request...\n");
r = sendnewportmappingrequest(&(state->natpmp), state->protocol,
- tor_fw_options->internal_port,
- tor_fw_options->external_port,
+ internal_port,
+ external_port,
state->lease);
- if (tor_fw_options->verbose)
- fprintf(stdout, "tor-fw-helper: NAT-PMP sendnewportmappingrequest "
+ if (is_verbose)
+ fprintf(stderr, "tor-fw-helper: NAT-PMP sendnewportmappingrequest "
"returned %d (%s)\n", r, r==12?"SUCCESS":"FAILED");
do {
@@ -139,8 +137,8 @@ tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
if (x == -1)
return -1;
- if (tor_fw_options->verbose)
- fprintf(stdout, "V: attempting to readnatpmpreponseorretry...\n");
+ if (is_verbose)
+ fprintf(stderr, "V: attempting to readnatpmpreponseorretry...\n");
r = readnatpmpresponseorretry(&(state->natpmp), &(state->response));
sav_errno = errno;
@@ -163,16 +161,14 @@ tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
}
if (r == NATPMP_SUCCESS) {
- fprintf(stdout, "tor-fw-helper: NAT-PMP mapped public port %hu to"
+ fprintf(stderr, "tor-fw-helper: NAT-PMP mapped public port %hu to"
" localport %hu liftime %u\n",
(state->response).pnu.newportmapping.mappedpublicport,
(state->response).pnu.newportmapping.privateport,
(state->response).pnu.newportmapping.lifetime);
}
- tor_fw_options->nat_pmp_status = 1;
-
- return r;
+ return (r == NATPMP_SUCCESS) ? 0 : -1;
}
/** Fetch our likely public IP from our upstream NAT-PMP enabled NAT device.
@@ -189,7 +185,7 @@ tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
struct timeval timeout;
r = sendpublicaddressrequest(&(state->natpmp));
- fprintf(stdout, "tor-fw-helper: NAT-PMP sendpublicaddressrequest returned"
+ fprintf(stderr, "tor-fw-helper: NAT-PMP sendpublicaddressrequest returned"
" %d (%s)\n", r, r==2?"SUCCESS":"FAILED");
do {
@@ -200,12 +196,12 @@ tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
return -1;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: NAT-PMP attempting to read reponse...\n");
+ fprintf(stderr, "V: NAT-PMP attempting to read reponse...\n");
r = readnatpmpresponseorretry(&(state->natpmp), &(state->response));
sav_errno = errno;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: NAT-PMP readnatpmpresponseorretry returned"
+ fprintf(stderr, "V: NAT-PMP readnatpmpresponseorretry returned"
" %d\n", r);
if ( r < 0 && r != NATPMP_TRYAGAIN) {
@@ -223,15 +219,15 @@ tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
return r;
}
- fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
+ fprintf(stderr, "tor-fw-helper: ExternalIPAddress = %s\n",
inet_ntoa((state->response).pnu.publicaddress.addr));
tor_fw_options->public_ip_status = 1;
if (tor_fw_options->verbose) {
- fprintf(stdout, "V: result = %u\n", r);
- fprintf(stdout, "V: type = %u\n", (state->response).type);
- fprintf(stdout, "V: resultcode = %u\n", (state->response).resultcode);
- fprintf(stdout, "V: epoch = %u\n", (state->response).epoch);
+ fprintf(stderr, "V: result = %u\n", r);
+ fprintf(stderr, "V: type = %u\n", (state->response).type);
+ fprintf(stderr, "V: resultcode = %u\n", (state->response).resultcode);
+ fprintf(stderr, "V: epoch = %u\n", (state->response).epoch);
}
return r;
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
index 54f541bcf4..037d409ac7 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
@@ -7,8 +7,8 @@
**/
#ifdef NAT_PMP
-#ifndef _TOR_FW_HELPER_NATPMP_H
-#define _TOR_FW_HELPER_NATPMP_H
+#ifndef TOR_TOR_FW_HELPER_NATPMP_H
+#define TOR_TOR_FW_HELPER_NATPMP_H
#include <natpmp.h>
@@ -36,8 +36,8 @@ int tor_natpmp_init(tor_fw_options_t *tor_fw_options, void *backend_state);
int tor_natpmp_cleanup(tor_fw_options_t *tor_fw_options, void *backend_state);
-int tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
- void *backend_state);
+int tor_natpmp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state);
int tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
void *backend_state);
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-upnp.c b/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
index 7c104f11cd..e5c33db0b4 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
@@ -91,7 +91,7 @@ tor_upnp_init(tor_fw_options_t *options, void *backend_state)
assert(options);
r = UPNP_GetValidIGD(devlist, &(state->urls), &(state->data),
state->lanaddr, UPNP_LANADDR_SZ);
- fprintf(stdout, "tor-fw-helper: UPnP GetValidIGD returned: %d (%s)\n", r,
+ fprintf(stderr, "tor-fw-helper: UPnP GetValidIGD returned: %d (%s)\n", r,
r==UPNP_SUCCESS?"SUCCESS":"FAILED");
freeUPNPDevlist(devlist);
@@ -141,7 +141,7 @@ tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state)
goto err;
if (externalIPAddress[0]) {
- fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
+ fprintf(stderr, "tor-fw-helper: ExternalIPAddress = %s\n",
externalIPAddress); tor_upnp_cleanup(options, state);
options->public_ip_status = 1;
return UPNP_ERR_SUCCESS;
@@ -154,44 +154,40 @@ tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state)
return UPNP_ERR_GETEXTERNALIP;
}
-/** Add a TCP port mapping for a single port stored in <b>tor_fw_options</b>
- * and store the results in <b>backend_state</b>. */
int
-tor_upnp_add_tcp_mapping(tor_fw_options_t *options, void *backend_state)
+tor_upnp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state)
{
- miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
- int r;
+ int retval;
char internal_port_str[6];
char external_port_str[6];
+ miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
if (!state->init) {
- r = tor_upnp_init(options, state);
- if (r != UPNP_ERR_SUCCESS)
- return r;
+ fprintf(stderr, "E: %s but state is not initialized.\n", __func__);
+ return -1;
}
- if (options->verbose)
- fprintf(stdout, "V: internal port: %d, external port: %d\n",
- (int)options->internal_port, (int)options->external_port);
+ if (is_verbose)
+ fprintf(stderr, "V: UPnP: internal port: %u, external port: %u\n",
+ internal_port, external_port);
tor_snprintf(internal_port_str, sizeof(internal_port_str),
- "%d", (int)options->internal_port);
+ "%u", internal_port);
tor_snprintf(external_port_str, sizeof(external_port_str),
- "%d", (int)options->external_port);
+ "%u", external_port);
- r = UPNP_AddPortMapping(state->urls.controlURL,
- state->data.first.servicetype,
- external_port_str, internal_port_str,
+ retval = UPNP_AddPortMapping(state->urls.controlURL,
+ state->data.first.servicetype,
+ external_port_str, internal_port_str,
#ifdef MINIUPNPC15
- state->lanaddr, UPNP_DESC, "TCP", 0);
+ state->lanaddr, UPNP_DESC, "TCP", 0);
#else
- state->lanaddr, UPNP_DESC, "TCP", 0, 0);
+ state->lanaddr, UPNP_DESC, "TCP", 0, 0);
#endif
- if (r != UPNPCOMMAND_SUCCESS)
- return UPNP_ERR_ADDPORTMAPPING;
- options->upnp_status = 1;
- return UPNP_ERR_SUCCESS;
+ return (retval == UPNP_ERR_SUCCESS) ? 0 : -1;
}
+
#endif
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-upnp.h b/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
index f037c75bab..add350d2f6 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
@@ -8,8 +8,8 @@
**/
#ifdef MINIUPNPC
-#ifndef _TOR_FW_HELPER_UPNP_H
-#define _TOR_FW_HELPER_UPNP_H
+#ifndef TOR_TOR_FW_HELPER_UPNP_H
+#define TOR_TOR_FW_HELPER_UPNP_H
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
@@ -36,7 +36,8 @@ int tor_upnp_cleanup(tor_fw_options_t *options, void *backend_state);
int tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state);
-int tor_upnp_add_tcp_mapping(tor_fw_options_t *options, void *backend_state);
+int tor_upnp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state);
#endif
#endif
diff --git a/src/tools/tor-fw-helper/tor-fw-helper.c b/src/tools/tor-fw-helper/tor-fw-helper.c
index 0510e65d11..4efe515cc4 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper.c
@@ -20,6 +20,9 @@
#include <getopt.h>
#include <time.h>
#include <string.h>
+#include <assert.h>
+
+#include "container.h"
#ifdef _WIN32
#include <winsock2.h>
@@ -45,7 +48,7 @@ typedef struct backends_t {
void *backend_state[MAX_BACKENDS];
} backends_t;
-/** Initalize each backend helper with the user input stored in <b>options</b>
+/** Initialize each backend helper with the user input stored in <b>options</b>
* and put the results in the <b>backends</b> struct. */
static int
init_backends(tor_fw_options_t *options, backends_t *backends)
@@ -97,10 +100,7 @@ usage(void)
" [-T|--Test]\n"
" [-v|--verbose]\n"
" [-g|--fetch-public-ip]\n"
- " -i|--internal-or-port [TCP port]\n"
- " [-e|--external-or-port [TCP port]]\n"
- " [-d|--internal-dir-port [TCP port]\n"
- " [-p|--external-dir-port [TCP port]]]\n");
+ " [-p|--forward-port ([<external port>]:<internal port>])\n");
}
/** Log commandline options to a hardcoded file <b>tor-fw-helper.log</b> in the
@@ -125,7 +125,7 @@ log_commandline_options(int argc, char **argv)
if (retval < 0)
goto error;
- retval = fprintf(stdout, "ARG: %d: %s\n", i, argv[i]);
+ retval = fprintf(stderr, "ARG: %d: %s\n", i, argv[i]);
if (retval < 0)
goto error;
}
@@ -152,82 +152,141 @@ tor_fw_fetch_public_ip(tor_fw_options_t *tor_fw_options,
int r = 0;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: tor_fw_fetch_public_ip\n");
+ fprintf(stderr, "V: tor_fw_fetch_public_ip\n");
for (i=0; i<backends->n_backends; ++i) {
if (tor_fw_options->verbose) {
- fprintf(stdout, "V: running backend_state now: %i\n", i);
- fprintf(stdout, "V: size of backend state: %u\n",
+ fprintf(stderr, "V: running backend_state now: %i\n", i);
+ fprintf(stderr, "V: size of backend state: %u\n",
(int)(backends->backend_ops)[i].state_len);
- fprintf(stdout, "V: backend state name: %s\n",
+ fprintf(stderr, "V: backend state name: %s\n",
(char *)(backends->backend_ops)[i].name);
}
r = backends->backend_ops[i].fetch_public_ip(tor_fw_options,
backends->backend_state[i]);
- fprintf(stdout, "tor-fw-helper: tor_fw_fetch_public_ip backend %s "
+ fprintf(stderr, "tor-fw-helper: tor_fw_fetch_public_ip backend %s "
" returned: %i\n", (char *)(backends->backend_ops)[i].name, r);
}
}
-/** Iterate over each of the supported <b>backends</b> and attempt to add a
- * port forward for the OR port stored in <b>tor_fw_options</b>. */
+/** Print a spec-conformant string to stdout describing the results of
+ * the TCP port forwarding operation from <b>external_port</b> to
+ * <b>internal_port</b>. */
static void
-tor_fw_add_or_port(tor_fw_options_t *tor_fw_options,
- backends_t *backends)
+tor_fw_helper_report_port_fw_results(uint16_t internal_port,
+ uint16_t external_port,
+ int succeded,
+ const char *message)
+{
+ char *report_string = NULL;
+
+ tor_asprintf(&report_string, "%s %s %u %u %s %s\n",
+ "tor-fw-helper",
+ "tcp-forward",
+ external_port, internal_port,
+ succeded ? "SUCCESS" : "FAIL",
+ message);
+ fprintf(stdout, "%s", report_string);
+ fflush(stdout);
+ tor_free(report_string);
+}
+
+#define tor_fw_helper_report_port_fw_fail(i, e, m) \
+ tor_fw_helper_report_port_fw_results((i), (e), 0, (m))
+
+#define tor_fw_helper_report_port_fw_success(i, e, m) \
+ tor_fw_helper_report_port_fw_results((i), (e), 1, (m))
+
+/** Return a heap-allocated string containing the list of our
+ * backends. It can be used in log messages. Be sure to free it
+ * afterwards! */
+static char *
+get_list_of_backends_string(backends_t *backends)
{
+ char *backend_names = NULL;
int i;
- int r = 0;
+ smartlist_t *backend_names_sl = smartlist_new();
- if (tor_fw_options->verbose)
- fprintf(stdout, "V: tor_fw_add_or_port\n");
+ assert(backends->n_backends);
- for (i=0; i<backends->n_backends; ++i) {
- if (tor_fw_options->verbose) {
- fprintf(stdout, "V: running backend_state now: %i\n", i);
- fprintf(stdout, "V: size of backend state: %u\n",
- (int)(backends->backend_ops)[i].state_len);
- fprintf(stdout, "V: backend state name: %s\n",
- (const char *) backends->backend_ops[i].name);
- }
- r = backends->backend_ops[i].add_tcp_mapping(tor_fw_options,
- backends->backend_state[i]);
- fprintf(stdout, "tor-fw-helper: tor_fw_add_or_port backend %s "
- "returned: %i\n", (const char *) backends->backend_ops[i].name, r);
- }
+ for (i=0; i<backends->n_backends; ++i)
+ smartlist_add(backend_names_sl, (char *) backends->backend_ops[i].name);
+
+ backend_names = smartlist_join_strings(backend_names_sl, ", ", 0, NULL);
+ smartlist_free(backend_names_sl);
+
+ return backend_names;
}
/** Iterate over each of the supported <b>backends</b> and attempt to add a
- * port forward for the Dir port stored in <b>tor_fw_options</b>. */
+ * port forward for the port stored in <b>tor_fw_options</b>. */
static void
-tor_fw_add_dir_port(tor_fw_options_t *tor_fw_options,
- backends_t *backends)
+tor_fw_add_ports(tor_fw_options_t *tor_fw_options,
+ backends_t *backends)
{
int i;
int r = 0;
+ int succeeded = 0;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: tor_fw_add_dir_port\n");
+ fprintf(stderr, "V: %s\n", __func__);
- for (i=0; i<backends->n_backends; ++i) {
- if (tor_fw_options->verbose) {
- fprintf(stdout, "V: running backend_state now: %i\n", i);
- fprintf(stdout, "V: size of backend state: %u\n",
- (int)(backends->backend_ops)[i].state_len);
- fprintf(stdout, "V: backend state name: %s\n",
- (char *)(backends->backend_ops)[i].name);
+ /** Loop all ports that need to be forwarded, and try to use our
+ * backends for each port. If a backend succeeds, break the loop,
+ * report success and get to the next port. If all backends fail,
+ * report failure for that port. */
+ SMARTLIST_FOREACH_BEGIN(tor_fw_options->ports_to_forward,
+ port_to_forward_t *, port_to_forward) {
+
+ succeeded = 0;
+
+ for (i=0; i<backends->n_backends; ++i) {
+ if (tor_fw_options->verbose) {
+ fprintf(stderr, "V: running backend_state now: %i\n", i);
+ fprintf(stderr, "V: size of backend state: %u\n",
+ (int)(backends->backend_ops)[i].state_len);
+ fprintf(stderr, "V: backend state name: %s\n",
+ (const char *) backends->backend_ops[i].name);
+ }
+
+ r =
+ backends->backend_ops[i].add_tcp_mapping(port_to_forward->internal_port,
+ port_to_forward->external_port,
+ tor_fw_options->verbose,
+ backends->backend_state[i]);
+ if (r == 0) { /* backend success */
+ tor_fw_helper_report_port_fw_success(port_to_forward->internal_port,
+ port_to_forward->external_port,
+ backends->backend_ops[i].name);
+ succeeded = 1;
+ break;
+ }
+
+ fprintf(stderr, "tor-fw-helper: tor_fw_add_port backend %s "
+ "returned: %i\n",
+ (const char *) backends->backend_ops[i].name, r);
}
- r = backends->backend_ops[i].add_tcp_mapping(tor_fw_options,
- backends->backend_state[i]);
- fprintf(stdout, "tor-fw-helper: tor_fw_add_dir_port backend %s "
- "returned: %i\n", (const char *)backends->backend_ops[i].name, r);
- }
+
+ if (!succeeded) { /* all backends failed */
+ char *list_of_backends_str = get_list_of_backends_string(backends);
+ char *fail_msg = NULL;
+ tor_asprintf(&fail_msg, "All port forwarding backends (%s) failed.",
+ list_of_backends_str);
+ tor_fw_helper_report_port_fw_fail(port_to_forward->internal_port,
+ port_to_forward->external_port,
+ fail_msg);
+ tor_free(list_of_backends_str);
+ tor_free(fail_msg);
+ }
+
+ } SMARTLIST_FOREACH_END(port_to_forward);
}
/** Called before we make any calls to network-related functions.
* (Some operating systems require their network libraries to be
* initialized.) (from common/compat.c) */
static int
-network_init(void)
+tor_fw_helper_network_init(void)
{
#ifdef _WIN32
/* This silly exercise is necessary before windows will allow
@@ -247,6 +306,67 @@ network_init(void)
return 0;
}
+/** Parse the '-p' argument of tor-fw-helper. Its format is
+ * [<external port>]:<internal port>, and <external port> is optional.
+ * Return NULL if <b>arg</b> was c0rrupted. */
+static port_to_forward_t *
+parse_port(const char *arg)
+{
+ smartlist_t *sl = smartlist_new();
+ port_to_forward_t *port_to_forward = NULL;
+ char *port_str = NULL;
+ int ok;
+ int port;
+
+ smartlist_split_string(sl, arg, ":", 0, 0);
+ if (smartlist_len(sl) != 2)
+ goto err;
+
+ port_to_forward = tor_malloc(sizeof(port_to_forward_t));
+ if (!port_to_forward)
+ goto err;
+
+ port_str = smartlist_get(sl, 0); /* macroify ? */
+ port = (int)tor_parse_long(port_str, 10, 1, 65535, &ok, NULL);
+ if (!ok && strlen(port_str)) /* ":1555" is valid */
+ goto err;
+ port_to_forward->external_port = port;
+
+ port_str = smartlist_get(sl, 1);
+ port = (int)tor_parse_long(port_str, 10, 1, 65535, &ok, NULL);
+ if (!ok)
+ goto err;
+ port_to_forward->internal_port = port;
+
+ goto done;
+
+ err:
+ tor_free(port_to_forward);
+
+ done:
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+
+ return port_to_forward;
+}
+
+/** Report a failure of epic proportions: We didn't manage to
+ * initialize any port forwarding backends. */
+static void
+report_full_fail(const smartlist_t *ports_to_forward)
+{
+ if (!ports_to_forward)
+ return;
+
+ SMARTLIST_FOREACH_BEGIN(ports_to_forward,
+ const port_to_forward_t *, port_to_forward) {
+ tor_fw_helper_report_port_fw_fail(port_to_forward->internal_port,
+ port_to_forward->external_port,
+ "All backends (NAT-PMP, UPnP) failed "
+ "to initialize!"); /* XXX hardcoded */
+ } SMARTLIST_FOREACH_END(port_to_forward);
+}
+
int
main(int argc, char **argv)
{
@@ -259,22 +379,20 @@ main(int argc, char **argv)
memset(&tor_fw_options, 0, sizeof(tor_fw_options));
memset(&backend_state, 0, sizeof(backend_state));
+ // Parse CLI arguments.
while (1) {
int option_index = 0;
static struct option long_options[] =
{
{"verbose", 0, 0, 'v'},
{"help", 0, 0, 'h'},
- {"internal-or-port", 1, 0, 'i'},
- {"external-or-port", 1, 0, 'e'},
- {"internal-dir-port", 1, 0, 'd'},
- {"external-dir-port", 1, 0, 'p'},
+ {"port", 1, 0, 'p'},
{"fetch-public-ip", 0, 0, 'g'},
{"test-commandline", 0, 0, 'T'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "vhi:e:d:p:gT",
+ c = getopt_long(argc, argv, "vhp:gT",
long_options, &option_index);
if (c == -1)
break;
@@ -282,14 +400,31 @@ main(int argc, char **argv)
switch (c) {
case 'v': tor_fw_options.verbose = 1; break;
case 'h': tor_fw_options.help = 1; usage(); exit(1); break;
- case 'i': sscanf(optarg, "%hu", &tor_fw_options.private_or_port);
- break;
- case 'e': sscanf(optarg, "%hu", &tor_fw_options.public_or_port);
- break;
- case 'd': sscanf(optarg, "%hu", &tor_fw_options.private_dir_port);
- break;
- case 'p': sscanf(optarg, "%hu", &tor_fw_options.public_dir_port);
+ case 'p': {
+ port_to_forward_t *port_to_forward = parse_port(optarg);
+ if (!port_to_forward) {
+ fprintf(stderr, "E: Failed to parse '%s'.\n", optarg);
+ usage();
+ exit(1);
+ }
+
+ /* If no external port was given (it's optional), set it to be
+ * equal with the internal port. */
+ if (!port_to_forward->external_port) {
+ assert(port_to_forward->internal_port);
+ if (tor_fw_options.verbose)
+ fprintf(stderr, "V: No external port was given. Setting to %u.\n",
+ port_to_forward->internal_port);
+ port_to_forward->external_port = port_to_forward->internal_port;
+ }
+
+ if (!tor_fw_options.ports_to_forward)
+ tor_fw_options.ports_to_forward = smartlist_new();
+
+ smartlist_add(tor_fw_options.ports_to_forward, port_to_forward);
+
break;
+ }
case 'g': tor_fw_options.fetch_public_ip = 1; break;
case 'T': tor_fw_options.test_commandline = 1; break;
case '?': break;
@@ -297,98 +432,68 @@ main(int argc, char **argv)
}
}
- if (tor_fw_options.verbose) {
- fprintf(stderr, "V: tor-fw-helper version %s\n"
- "V: We were called with the following arguments:\n"
- "V: verbose = %d, help = %d, pub or port = %u, "
- "priv or port = %u\n"
- "V: pub dir port = %u, priv dir port = %u\n"
- "V: fetch_public_ip = %u\n",
- tor_fw_version, tor_fw_options.verbose, tor_fw_options.help,
- tor_fw_options.private_or_port, tor_fw_options.public_or_port,
- tor_fw_options.private_dir_port, tor_fw_options.public_dir_port,
- tor_fw_options.fetch_public_ip);
+ { // Verbose output
+
+ if (tor_fw_options.verbose)
+ fprintf(stderr, "V: tor-fw-helper version %s\n"
+ "V: We were called with the following arguments:\n"
+ "V: verbose = %d, help = %d, fetch_public_ip = %u\n",
+ tor_fw_version, tor_fw_options.verbose, tor_fw_options.help,
+ tor_fw_options.fetch_public_ip);
+
+ if (tor_fw_options.verbose && tor_fw_options.ports_to_forward) {
+ fprintf(stderr, "V: TCP forwarding:\n");
+ SMARTLIST_FOREACH(tor_fw_options.ports_to_forward,
+ const port_to_forward_t *, port_to_forward,
+ fprintf(stderr, "V: External: %u, Internal: %u\n",
+ port_to_forward->external_port,
+ port_to_forward->internal_port));
+ }
}
if (tor_fw_options.test_commandline) {
return log_commandline_options(argc, argv);
}
- /* At the very least, we require an ORPort;
- Given a private ORPort, we can ask for a mapping that matches the port
- externally.
- */
- if (!tor_fw_options.private_or_port && !tor_fw_options.fetch_public_ip) {
- fprintf(stderr, "E: We require an ORPort or fetch_public_ip"
- " request!\n");
+ // See if the user actually wants us to do something.
+ if (!tor_fw_options.fetch_public_ip && !tor_fw_options.ports_to_forward) {
+ fprintf(stderr, "E: We require a port to be forwarded or "
+ "fetch_public_ip request!\n");
usage();
exit(1);
- } else {
- /* When we only have one ORPort, internal/external are
- set to be the same.*/
- if (!tor_fw_options.public_or_port && tor_fw_options.private_or_port) {
- if (tor_fw_options.verbose)
- fprintf(stdout, "V: We're setting public_or_port = "
- "private_or_port.\n");
- tor_fw_options.public_or_port = tor_fw_options.private_or_port;
- }
- }
- if (!tor_fw_options.private_dir_port) {
- if (tor_fw_options.verbose)
- fprintf(stdout, "V: We have no DirPort; no hole punching for "
- "DirPorts\n");
-
- } else {
- /* When we only have one DirPort, internal/external are
- set to be the same.*/
- if (!tor_fw_options.public_dir_port && tor_fw_options.private_dir_port) {
- if (tor_fw_options.verbose)
- fprintf(stdout, "V: We're setting public_or_port = "
- "private_or_port.\n");
-
- tor_fw_options.public_dir_port = tor_fw_options.private_dir_port;
- }
- }
-
- if (tor_fw_options.verbose) {
- fprintf(stdout, "V: pub or port = %u, priv or port = %u\n"
- "V: pub dir port = %u, priv dir port = %u\n",
- tor_fw_options.private_or_port, tor_fw_options.public_or_port,
- tor_fw_options.private_dir_port,
- tor_fw_options.public_dir_port);
}
// Initialize networking
- if (network_init())
+ if (tor_fw_helper_network_init())
exit(1);
// Initalize the various fw-helper backend helpers
r = init_backends(&tor_fw_options, &backend_state);
- if (r)
- printf("tor-fw-helper: %i NAT traversal helper(s) loaded\n", r);
-
- if (tor_fw_options.fetch_public_ip) {
- tor_fw_fetch_public_ip(&tor_fw_options, &backend_state);
+ if (!r) { // all backends failed:
+ // report our failure
+ report_full_fail(tor_fw_options.ports_to_forward);
+ fprintf(stderr, "tor-fw-helper: All backends failed.\n");
+ exit(1);
+ } else { // some backends succeeded:
+ fprintf(stderr, "tor-fw-helper: %i NAT traversal helper(s) loaded\n", r);
}
- if (tor_fw_options.private_or_port) {
- tor_fw_options.internal_port = tor_fw_options.private_or_port;
- tor_fw_options.external_port = tor_fw_options.private_or_port;
- tor_fw_add_or_port(&tor_fw_options, &backend_state);
+ // Forward TCP ports.
+ if (tor_fw_options.ports_to_forward) {
+ tor_fw_add_ports(&tor_fw_options, &backend_state);
}
- if (tor_fw_options.private_dir_port) {
- tor_fw_options.internal_port = tor_fw_options.private_dir_port;
- tor_fw_options.external_port = tor_fw_options.private_dir_port;
- tor_fw_add_dir_port(&tor_fw_options, &backend_state);
+ // Fetch our public IP.
+ if (tor_fw_options.fetch_public_ip) {
+ tor_fw_fetch_public_ip(&tor_fw_options, &backend_state);
}
- r = (((tor_fw_options.nat_pmp_status | tor_fw_options.upnp_status)
- |tor_fw_options.public_ip_status));
- if (r > 0) {
- fprintf(stdout, "tor-fw-helper: SUCCESS\n");
- } else {
- fprintf(stderr, "tor-fw-helper: FAILURE\n");
+ // Cleanup and exit.
+ if (tor_fw_options.ports_to_forward) {
+ SMARTLIST_FOREACH(tor_fw_options.ports_to_forward,
+ port_to_forward_t *, port,
+ tor_free(port));
+ smartlist_free(tor_fw_options.ports_to_forward);
}
exit(r);
diff --git a/src/tools/tor-fw-helper/tor-fw-helper.h b/src/tools/tor-fw-helper/tor-fw-helper.h
index 058afc4e09..1f6c1ff26b 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper.h
@@ -7,8 +7,8 @@
* \brief The main header for our firewall helper.
**/
-#ifndef _TOR_FW_HELPER_H
-#define _TOR_FW_HELPER_H
+#ifndef TOR_TOR_FW_HELPER_H
+#define TOR_TOR_FW_HELPER_H
#include <stdint.h>
#include <stdio.h>
@@ -17,24 +17,26 @@
#include <time.h>
/** The current version of tor-fw-helper. */
-#define tor_fw_version "0.1"
+#define tor_fw_version "0.2"
/** This is an arbitrary hard limit - We currently have two (NAT-PMP and UPnP).
We're likely going to add the Intel UPnP library but nothing else comes to
mind at the moment. */
#define MAX_BACKENDS 23
+/** Forward traffic received in port <b>external_port</b> in the
+ * external side of our NAT to <b>internal_port</b> in this host. */
+typedef struct {
+ uint16_t external_port;
+ uint16_t internal_port;
+} port_to_forward_t;
+
/** This is where we store parsed commandline options. */
typedef struct {
int verbose;
int help;
int test_commandline;
- uint16_t private_dir_port;
- uint16_t private_or_port;
- uint16_t public_dir_port;
- uint16_t public_or_port;
- uint16_t internal_port;
- uint16_t external_port;
+ struct smartlist_t *ports_to_forward;
int fetch_public_ip;
int nat_pmp_status;
int upnp_status;
@@ -50,8 +52,8 @@ typedef struct tor_fw_backend_t {
int (*init)(tor_fw_options_t *options, void *backend_state);
int (*cleanup)(tor_fw_options_t *options, void *backend_state);
int (*fetch_public_ip)(tor_fw_options_t *options, void *backend_state);
- int (*add_tcp_mapping)(tor_fw_options_t *options, void *backend_state);
+ int (*add_tcp_mapping)(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state);
} tor_fw_backend_t;
-
#endif
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index c7ab8dc615..91b1e3c234 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -227,7 +227,7 @@ generate_key(int bits)
crypto_pk_t *env = crypto_pk_new();
if (crypto_pk_generate_key_with_bits(env,bits)<0)
goto done;
- rsa = _crypto_pk_get_rsa(env);
+ rsa = crypto_pk_get_rsa_(env);
rsa = RSAPrivateKey_dup(rsa);
done:
crypto_pk_free(env);
@@ -401,7 +401,7 @@ static int
get_fingerprint(EVP_PKEY *pkey, char *out)
{
int r = 1;
- crypto_pk_t *pk = _crypto_new_pk_from_rsa(EVP_PKEY_get1_RSA(pkey));
+ crypto_pk_t *pk = crypto_new_pk_from_rsa_(EVP_PKEY_get1_RSA(pkey));
if (pk) {
r = crypto_pk_get_fingerprint(pk, out, 0);
crypto_pk_free(pk);
@@ -414,7 +414,7 @@ static int
get_digest(EVP_PKEY *pkey, char *out)
{
int r = 1;
- crypto_pk_t *pk = _crypto_new_pk_from_rsa(EVP_PKEY_get1_RSA(pkey));
+ crypto_pk_t *pk = crypto_new_pk_from_rsa_(EVP_PKEY_get1_RSA(pkey));
if (pk) {
r = crypto_pk_get_digest(pk, out);
crypto_pk_free(pk);
diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c
index 4ef84f491c..cae5fbbbb4 100644
--- a/src/tools/tor-resolve.c
+++ b/src/tools/tor-resolve.c
@@ -74,23 +74,29 @@ build_socks_resolve_request(char **out,
memcpy((*out)+8+strlen(username)+1, hostname, strlen(hostname)+1);
} else if (version == 5) {
int is_ip_address;
- struct in_addr in;
+ tor_addr_t addr;
size_t addrlen;
- is_ip_address = tor_inet_aton(hostname, &in);
+ int ipv6;
+ is_ip_address = tor_addr_parse(&addr, hostname) != -1;
if (!is_ip_address && reverse) {
log_err(LD_GENERAL, "Tried to do a reverse lookup on a non-IP!");
return -1;
}
- addrlen = reverse ? 4 : 1 + strlen(hostname);
+ ipv6 = reverse && tor_addr_family(&addr) == AF_INET6;
+ addrlen = reverse ? (ipv6 ? 16 : 4) : 1 + strlen(hostname);
len = 6 + addrlen;
*out = tor_malloc(len);
(*out)[0] = 5; /* SOCKS version 5 */
(*out)[1] = reverse ? '\xF1' : '\xF0'; /* RESOLVE_PTR or RESOLVE */
(*out)[2] = 0; /* reserved. */
- (*out)[3] = reverse ? 1 : 3;
if (reverse) {
- set_uint32((*out)+4, in.s_addr);
+ (*out)[3] = ipv6 ? 4 : 1;
+ if (ipv6)
+ memcpy((*out)+4, tor_addr_to_in6_addr8(&addr), 16);
+ else
+ set_uint32((*out)+4, tor_addr_to_ipv4n(&addr));
} else {
+ (*out)[3] = 3;
(*out)[4] = (char)(uint8_t)(addrlen - 1);
memcpy((*out)+5, hostname, addrlen - 1);
}
@@ -109,7 +115,7 @@ build_socks_resolve_request(char **out,
static int
parse_socks4a_resolve_response(const char *hostname,
const char *response, size_t len,
- uint32_t *addr_out)
+ tor_addr_t *addr_out)
{
uint8_t status;
tor_assert(response);
@@ -140,7 +146,7 @@ parse_socks4a_resolve_response(const char *hostname,
return -1;
}
- *addr_out = ntohl(get_uint32(response+4));
+ tor_addr_from_ipv4n(addr_out, get_uint32(response+4));
return 0;
}
@@ -179,7 +185,7 @@ socks5_reason_to_string(char reason)
static int
do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
int reverse, int version,
- uint32_t *result_addr, char **result_hostname)
+ tor_addr_t *result_addr, char **result_hostname)
{
int s;
struct sockaddr_in socksaddr;
@@ -190,7 +196,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
tor_assert(result_addr);
tor_assert(version == 4 || version == 5);
- *result_addr = 0;
+ tor_addr_make_unspec(result_addr);
*result_hostname = NULL;
s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
@@ -255,7 +261,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
return -1;
}
} else {
- char reply_buf[4];
+ char reply_buf[16];
if (read_all(s, reply_buf, 4, 1) != 4) {
log_err(LD_NET, "Error reading SOCKS5 response.");
return -1;
@@ -284,8 +290,16 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
log_err(LD_NET, "Error reading address in socks5 response.");
return -1;
}
- *result_addr = ntohl(get_uint32(reply_buf));
+ tor_addr_from_ipv4n(result_addr, get_uint32(reply_buf));
+ } else if (reply_buf[3] == 4) {
+ /* IPv6 address */
+ if (read_all(s, reply_buf, 16, 1) != 16) {
+ log_err(LD_NET, "Error reading address in socks5 response.");
+ return -1;
+ }
+ tor_addr_from_ipv6_bytes(result_addr, reply_buf);
} else if (reply_buf[3] == 3) {
+ /* Domain name */
size_t result_len;
if (read_all(s, reply_buf, 1, 1) != 1) {
log_err(LD_NET, "Error reading address_length in socks5 response.");
@@ -322,10 +336,8 @@ main(int argc, char **argv)
int isSocks4 = 0, isVerbose = 0, isReverse = 0;
char **arg;
int n_args;
- struct in_addr a;
- uint32_t result = 0;
+ tor_addr_t result;
char *result_hostname = NULL;
- char buf[INET_NTOA_BUF_LEN];
log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
init_logging();
@@ -423,9 +435,7 @@ main(int argc, char **argv)
if (result_hostname) {
printf("%s\n", result_hostname);
} else {
- a.s_addr = htonl(result);
- tor_inet_ntoa(&a, buf, sizeof(buf));
- printf("%s\n", buf);
+ printf("%s\n", fmt_addr(&result));
}
return 0;
}
diff --git a/src/win32/Makefile.am b/src/win32/Makefile.am
deleted file mode 100644
index 7f5d742481..0000000000
--- a/src/win32/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-
-EXTRA_DIST = orconfig.h
-
diff --git a/src/win32/include.am b/src/win32/include.am
new file mode 100644
index 0000000000..dad59af3ae
--- /dev/null
+++ b/src/win32/include.am
@@ -0,0 +1,3 @@
+
+EXTRA_DIST+= src/win32/orconfig.h
+
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index d780d5d73d..cca73b0a30 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -145,6 +145,9 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
+/* Define to 1 if you have the `_vscprintf' function. */
+#define HAVE__VSCPRINTF 1
+
/* Define to 1 iff NULL is represented by a 0 in memory. */
#define NULL_REP_IS_ZERO_BYTES 1
@@ -190,6 +193,9 @@
/* The size of a `long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG
+/* The size of `pid_t', as computed by sizeof. */
+#define SIZEOF_PID_T 0
+
/* The size of a `short', as computed by sizeof. */
#define SIZEOF_SHORT 2
@@ -232,7 +238,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.2.3.18-rc-dev"
+#define VERSION "0.2.4.6-alpha-dev"