diff options
Diffstat (limited to 'src')
34 files changed, 1045 insertions, 200 deletions
diff --git a/src/common/address.c b/src/common/address.c index dd336257ef..163db59ac4 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -620,13 +620,20 @@ tor_addr_to_PTR_name(char *out, size_t outlen, * 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 + * yields an AF_UNSPEC wildcard address, which expands to corresponding + * wildcard IPv4 and IPv6 rules, 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. * - */ + * If 'flags & TAPMP_EXTENDED_STAR' and 'flags & TAPMP_STAR_IPV4_ONLY' are + * both true, then the wildcard address '*' yields an IPv4 wildcard. + * + * If 'flags & TAPMP_EXTENDED_STAR' and 'flags & TAPMP_STAR_IPV6_ONLY' are + * both true, then the wildcard address '*' yields an IPv6 wildcard. + * + * TAPMP_STAR_IPV4_ONLY and TAPMP_STAR_IPV6_ONLY are mutually exclusive. */ int tor_addr_parse_mask_ports(const char *s, unsigned flags, @@ -643,6 +650,10 @@ tor_addr_parse_mask_ports(const char *s, tor_assert(s); tor_assert(addr_out); + /* We can either only want an IPv4 address or only want an IPv6 address, + * but we can't only want IPv4 & IPv6 at the same time. */ + tor_assert(!((flags & TAPMP_STAR_IPV4_ONLY) + && (flags & TAPMP_STAR_IPV6_ONLY))); /** Longest possible length for an address, mask, and port-range combination. * Includes IP, [], /mask, :, ports */ @@ -688,8 +699,21 @@ tor_addr_parse_mask_ports(const char *s, if (!strcmp(address, "*")) { if (flags & TAPMP_EXTENDED_STAR) { - family = AF_UNSPEC; - tor_addr_make_unspec(addr_out); + if (flags & TAPMP_STAR_IPV4_ONLY) { + family = AF_INET; + tor_addr_from_ipv4h(addr_out, 0); + } else if (flags & TAPMP_STAR_IPV6_ONLY) { + static char nil_bytes[16] = { [0]=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); + } else { + family = AF_UNSPEC; + tor_addr_make_unspec(addr_out); + log_info(LD_GENERAL, + "'%s' expands into rules which apply to all IPv4 and IPv6 " + "addresses. (Use accept/reject *4:* for IPv4 or " + "accept[6]/reject[6] *6:* for IPv6.)", s); + } } else { family = AF_INET; tor_addr_from_ipv4h(addr_out, 0); @@ -1503,7 +1527,7 @@ get_interface_addresses_raw(int severity) } /** Return true iff <b>a</b> is a multicast address. */ -static int +STATIC int tor_addr_is_multicast(const tor_addr_t *a) { sa_family_t family = tor_addr_family(a); @@ -1593,43 +1617,108 @@ get_interface_address6_via_udp_socket_hack(int severity, return r; } -/** Set *<b>addr</b> to the IP address (if any) of whatever interface - * connects to the Internet. This address should only be used in checking - * whether our address has changed. Return 0 on success, -1 on failure. +/** Set *<b>addr</b> to an arbitrary IP address (if any) of an interface that + * connects to the Internet. Prefer public IP addresses to internal IP + * addresses. This address should only be used in checking whether our + * address has changed, as it may be an internal IP address. Return 0 on + * success, -1 on failure. + * Prefer get_interface_address6_list for a list of all addresses on all + * interfaces which connect to the Internet. */ MOCK_IMPL(int, get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) { - /* XXX really, this function should yield a smartlist of addresses. */ smartlist_t *addrs; + int rv = -1; tor_assert(addr); + /* Get a list of public or internal IPs in arbitrary order */ + addrs = get_interface_address6_list(severity, family, 1); + + /* Find the first non-internal address, or the last internal address + * Ideally, we want the default route, see #12377 for details */ + SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { + tor_addr_copy(addr, a); + rv = 0; + + /* If we found a non-internal address, declare success. Otherwise, + * keep looking. */ + if (!tor_addr_is_internal(a, 0)) + break; + } SMARTLIST_FOREACH_END(a); + + free_interface_address6_list(addrs); + return rv; +} + +/** Free a smartlist of IP addresses returned by get_interface_address6_list. + */ +void +free_interface_address6_list(smartlist_t *addrs) +{ + SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a)); + smartlist_free(addrs); +} + +/** Return a smartlist of the IP addresses of type family from all interfaces + * on the server. Excludes loopback and multicast addresses. Only includes + * internal addresses if include_internal is true. (Note that a relay behind + * NAT may use an internal address to connect to the Internet.) + * An empty smartlist means that there are no addresses of the selected type + * matching these criteria. + * Returns NULL on failure. + * Use free_interface_address6_list to free the returned list. + */ +MOCK_IMPL(smartlist_t *,get_interface_address6_list,(int severity, + sa_family_t family, + int include_internal)) +{ + smartlist_t *addrs; + tor_addr_t addr; + /* Try to do this the smart way if possible. */ if ((addrs = get_interface_addresses_raw(severity))) { - int rv = -1; - SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { - if (family != AF_UNSPEC && family != tor_addr_family(a)) + SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) + { + if (family != AF_UNSPEC && family != tor_addr_family(a)) { + SMARTLIST_DEL_CURRENT(addrs, a); + tor_free(a); continue; + } + if (tor_addr_is_loopback(a) || - tor_addr_is_multicast(a)) + tor_addr_is_multicast(a)) { + SMARTLIST_DEL_CURRENT(addrs, a); + tor_free(a); continue; + } - tor_addr_copy(addr, a); - rv = 0; - - /* If we found a non-internal address, declare success. Otherwise, - * keep looking. */ - if (!tor_addr_is_internal(a, 0)) - break; + if (!include_internal && tor_addr_is_internal(a, 0)) { + SMARTLIST_DEL_CURRENT(addrs, a); + tor_free(a); + continue; + } } SMARTLIST_FOREACH_END(a); + } + + if (addrs && smartlist_len(addrs) > 0) { + return addrs; + } - SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a)); + /* if we removed all entries as unsuitable */ + if (addrs) { smartlist_free(addrs); - return rv; } /* Okay, the smart way is out. */ - return get_interface_address6_via_udp_socket_hack(severity,family,addr); + get_interface_address6_via_udp_socket_hack(severity,family,&addr); + if (!include_internal && tor_addr_is_internal(&addr, 0)) { + return smartlist_new(); + } else { + addrs = smartlist_new(); + smartlist_add(addrs, tor_dup_addr(&addr)); + return addrs; + } } /* ====== @@ -1871,10 +1960,13 @@ tor_dup_ip(uint32_t addr) } /** - * Set *<b>addr</b> to the host-order IPv4 address (if any) of whatever - * interface connects to the Internet. This address should only be used in - * checking whether our address has changed. Return 0 on success, -1 on - * failure. + * Set *<b>addr</b> to a host-order IPv4 address (if any) of an + * interface that connects to the Internet. Prefer public IP addresses to + * internal IP addresses. This address should only be used in checking + * whether our address has changed, as it may be an internal IPv4 address. + * Return 0 on success, -1 on failure. + * Prefer get_interface_address_list6 for a list of all IPv4 and IPv6 + * addresses on all interfaces which connect to the Internet. */ MOCK_IMPL(int, get_interface_address,(int severity, uint32_t *addr)) diff --git a/src/common/address.h b/src/common/address.h index cd80615f93..7d49fb59bc 100644 --- a/src/common/address.h +++ b/src/common/address.h @@ -15,6 +15,7 @@ #include "orconfig.h" #include "torint.h" #include "compat.h" +#include "container.h" #ifdef ADDRESS_PRIVATE @@ -43,7 +44,6 @@ #endif // TODO win32 specific includes -#include "container.h" #endif // ADDRESS_PRIVATE /** The number of bits from an address to consider while doing a masked @@ -190,8 +190,13 @@ char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC; 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); + MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)); +void free_interface_address6_list(smartlist_t * addrs); +MOCK_DECL(smartlist_t *,get_interface_address6_list,(int severity, + sa_family_t family, + int include_internal)); /** Flag to specify how to do a comparison between addresses. In an "exact" * comparison, addresses are equivalent only if they are in the same family @@ -227,7 +232,19 @@ 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); + +/* Does the address * yield an AF_UNSPEC wildcard address (1), + * which expands to corresponding wildcard IPv4 and IPv6 rules, and do we + * allow *4 and *6 for IPv4 and IPv6 wildcards, respectively; + * or does the address * yield IPv4 wildcard address (0). */ #define TAPMP_EXTENDED_STAR 1 +/* Does the address * yield an IPv4 wildcard address rule (1); + * or does it yield wildcard IPv4 and IPv6 rules (0) */ +#define TAPMP_STAR_IPV4_ONLY (1 << 1) +/* Does the address * yield an IPv6 wildcard address rule (1); + * or does it yield wildcard IPv4 and IPv6 rules (0) */ +#define TAPMP_STAR_IPV6_ONLY (1 << 2) +/* TAPMP_STAR_IPV4_ONLY and TAPMP_STAR_IPV6_ONLY are mutually exclusive. */ 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); @@ -269,11 +286,32 @@ int addr_mask_get_bits(uint32_t mask); int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); char *tor_dup_ip(uint32_t addr) ATTR_MALLOC; MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr)); +/** Free a smartlist of IP addresses returned by get_interface_address_list. + */ +static INLINE void +free_interface_address_list(smartlist_t *addrs) +{ + free_interface_address6_list(addrs); +} +/** Return a smartlist of the IPv4 addresses of all interfaces on the server. + * Excludes loopback and multicast addresses. Only includes internal addresses + * if include_internal is true. (Note that a relay behind NAT may use an + * internal address to connect to the Internet.) + * An empty smartlist means that there are no IPv4 addresses. + * Returns NULL on failure. + * Use free_interface_address_list to free the returned list. + */ +static INLINE smartlist_t * +get_interface_address_list(int severity, int include_internal) +{ + return get_interface_address6_list(severity, AF_INET, include_internal); +} tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port); #ifdef ADDRESS_PRIVATE STATIC smartlist_t *get_interface_addresses_raw(int severity); +STATIC int tor_addr_is_multicast(const tor_addr_t *a); STATIC int get_interface_address6_via_udp_socket_hack(int severity, sa_family_t family, tor_addr_t *addr); diff --git a/src/common/crypto.c b/src/common/crypto.c index 6d4b0d7e16..815c2ec0c5 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -2440,7 +2440,8 @@ crypto_rand_uint64_range(uint64_t min, uint64_t max) time_t crypto_rand_time_range(time_t min, time_t max) { - return (time_t) crypto_rand_uint64_range(min, max); + tor_assert(min < max); + return min + (time_t)crypto_rand_uint64(max - min); } /** Return a pseudorandom 64-bit integer, chosen uniformly from the values diff --git a/src/common/tortls.c b/src/common/tortls.c index 7447822d48..20c898456a 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -1563,7 +1563,7 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl) { STACK_OF(SSL_CIPHER) *ciphers; #ifdef HAVE_SSL_GET_CLIENT_CIPHERS - ciphers = SSL_get_ciphers(ssl); + ciphers = SSL_get_client_ciphers(ssl); #else SSL_SESSION *session; if (!(session = SSL_get_session((SSL *)ssl))) { diff --git a/src/config/torrc.minimal.in-staging b/src/config/torrc.minimal.in-staging index d54a5599cd..ff324a96da 100644 --- a/src/config/torrc.minimal.in-staging +++ b/src/config/torrc.minimal.in-staging @@ -1,5 +1,5 @@ ## Configuration file for a typical Tor user -## Last updated 2 September 2014 for Tor 0.2.6.1-alpha. +## Last updated 22 September 2015 for Tor 0.2.7.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 @@ -24,6 +24,7 @@ ## can access your SocksPort may be able to learn about the connections ## you make. #SocksPolicy accept 192.168.0.0/16 +#SocksPolicy accept6 FC00::/7 #SocksPolicy reject * ## Logs go to stdout at level "notice" unless redirected by something @@ -156,10 +157,16 @@ #MyFamily $keyid,$keyid,... ## A comma-separated list of exit policies. They're considered first -## to last, and the first match wins. If you want to _replace_ -## the default exit policy, end this with either a reject *:* or an -## accept *:*. Otherwise, you're _augmenting_ (prepending to) the -## default exit policy. Leave commented to just use the default, which is +## to last, and the first match wins. +## +## If you want to allow the same ports on IPv4 and IPv6, write your rules +## using accept/reject *. If you want to allow different ports on IPv4 and +## IPv6, write your IPv6 rules using accept6/reject6 *6, and your IPv4 rules +## using accept/reject *4. +## +## If you want to _replace_ the default exit policy, end this with either a +## reject *:* or an accept *:*. Otherwise, you're _augmenting_ (prepending to) +## the default exit policy. Leave commented to just use the default, which is ## described in the man page or at ## https://www.torproject.org/documentation.html ## @@ -171,11 +178,15 @@ ## users will be told that those destinations are down. ## ## For security, by default Tor rejects connections to private (local) -## networks, including to your public IP address. See the man page entry -## for ExitPolicyRejectPrivate if you want to allow "exit enclaving". +## networks, including to the configured primary public IPv4 and IPv6 addresses, +## and any public IPv4 and IPv6 addresses on any interface on the relay. +## See the man page entry for ExitPolicyRejectPrivate if you want to allow +## "exit enclaving". ## -#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports but no more -#ExitPolicy accept *:119 # accept nntp as well as default exit policy +#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports on IPv4 and IPv6 but no more +#ExitPolicy accept *:119 # accept nntp ports on IPv4 and IPv6 as well as default exit policy +#ExitPolicy accept *4:119 # accept nntp ports on IPv4 only as well as default exit policy +#ExitPolicy accept6 *6:119 # accept nntp ports on IPv6 only as well as default exit policy #ExitPolicy reject *:* # no exits allowed ## Bridge relays (or "bridges") are Tor relays that aren't listed in the diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in index d54a5599cd..ff324a96da 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 2 September 2014 for Tor 0.2.6.1-alpha. +## Last updated 22 September 2015 for Tor 0.2.7.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 @@ -24,6 +24,7 @@ ## can access your SocksPort may be able to learn about the connections ## you make. #SocksPolicy accept 192.168.0.0/16 +#SocksPolicy accept6 FC00::/7 #SocksPolicy reject * ## Logs go to stdout at level "notice" unless redirected by something @@ -156,10 +157,16 @@ #MyFamily $keyid,$keyid,... ## A comma-separated list of exit policies. They're considered first -## to last, and the first match wins. If you want to _replace_ -## the default exit policy, end this with either a reject *:* or an -## accept *:*. Otherwise, you're _augmenting_ (prepending to) the -## default exit policy. Leave commented to just use the default, which is +## to last, and the first match wins. +## +## If you want to allow the same ports on IPv4 and IPv6, write your rules +## using accept/reject *. If you want to allow different ports on IPv4 and +## IPv6, write your IPv6 rules using accept6/reject6 *6, and your IPv4 rules +## using accept/reject *4. +## +## If you want to _replace_ the default exit policy, end this with either a +## reject *:* or an accept *:*. Otherwise, you're _augmenting_ (prepending to) +## the default exit policy. Leave commented to just use the default, which is ## described in the man page or at ## https://www.torproject.org/documentation.html ## @@ -171,11 +178,15 @@ ## users will be told that those destinations are down. ## ## For security, by default Tor rejects connections to private (local) -## networks, including to your public IP address. See the man page entry -## for ExitPolicyRejectPrivate if you want to allow "exit enclaving". +## networks, including to the configured primary public IPv4 and IPv6 addresses, +## and any public IPv4 and IPv6 addresses on any interface on the relay. +## See the man page entry for ExitPolicyRejectPrivate if you want to allow +## "exit enclaving". ## -#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports but no more -#ExitPolicy accept *:119 # accept nntp as well as default exit policy +#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports on IPv4 and IPv6 but no more +#ExitPolicy accept *:119 # accept nntp ports on IPv4 and IPv6 as well as default exit policy +#ExitPolicy accept *4:119 # accept nntp ports on IPv4 only as well as default exit policy +#ExitPolicy accept6 *6:119 # accept nntp ports on IPv6 only as well as default exit policy #ExitPolicy reject *:* # no exits allowed ## Bridge relays (or "bridges") are Tor relays that aren't listed in the diff --git a/src/ext/ed25519/donna/ed25519-donna-portable.h b/src/ext/ed25519/donna/ed25519-donna-portable.h index 9c9c55577c..75a53a570f 100644 --- a/src/ext/ed25519/donna/ed25519-donna-portable.h +++ b/src/ext/ed25519/donna/ed25519-donna-portable.h @@ -148,7 +148,7 @@ static inline void U64TO8_LE(unsigned char *p, const uint64_t v) { * architecture supports it. This is not done on x86-64 as the non-SSE2 * code benchmarks better, at least on Haswell. */ -#if defined(__SSE2__) /* && !defined(CPU_X86_64) */ +#if defined(__SSE2__) && !defined(CPU_X86_64) /* undef in case it's manually specified... */ #undef ED25519_SSE2 #define ED25519_SSE2 diff --git a/src/ext/ed25519/donna/ed25519_tor.c b/src/ext/ed25519/donna/ed25519_tor.c index 7f5894da79..12493f7d14 100644 --- a/src/ext/ed25519/donna/ed25519_tor.c +++ b/src/ext/ed25519/donna/ed25519_tor.c @@ -323,7 +323,7 @@ int ed25519_donna_pubkey_from_curve25519_pubkey(unsigned char *out, const unsigned char *inp, int signbit) { - static const bignum25519 one = { 1 }; + static const bignum25519 ALIGN(16) one = { 1 }; bignum25519 ALIGN(16) u, uminus1, uplus1, inv_uplus1, y; /* Prop228: y = (u-1)/(u+1) */ diff --git a/src/or/buffers.c b/src/or/buffers.c index 85fcbc64e8..cc2f6f409b 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -178,13 +178,10 @@ preferred_chunk_size(size_t target) /** Collapse data from the first N chunks from <b>buf</b> into buf->head, * growing it as necessary, until buf->head has the first <b>bytes</b> bytes * of data from the buffer, or until buf->head has all the data in <b>buf</b>. - * - * If <b>nulterminate</b> is true, ensure that there is a 0 byte in - * buf->head->mem right after all the data. */ + */ STATIC void -buf_pullup(buf_t *buf, size_t bytes, int nulterminate) +buf_pullup(buf_t *buf, size_t bytes) { - /* XXXX nothing uses nulterminate; remove it. */ chunk_t *dest, *src; size_t capacity; if (!buf->head) @@ -194,17 +191,9 @@ buf_pullup(buf_t *buf, size_t bytes, int nulterminate) if (buf->datalen < bytes) bytes = buf->datalen; - if (nulterminate) { - capacity = bytes + 1; - if (buf->head->datalen >= bytes && CHUNK_REMAINING_CAPACITY(buf->head)) { - *CHUNK_WRITE_PTR(buf->head) = '\0'; - return; - } - } else { - capacity = bytes; - if (buf->head->datalen >= bytes) - return; - } + capacity = bytes; + if (buf->head->datalen >= bytes) + return; if (buf->head->memlen >= capacity) { /* We don't need to grow the first chunk, but we might need to repack it.*/ @@ -248,11 +237,6 @@ buf_pullup(buf_t *buf, size_t bytes, int nulterminate) } } - if (nulterminate) { - tor_assert(CHUNK_REMAINING_CAPACITY(buf->head)); - *CHUNK_WRITE_PTR(buf->head) = '\0'; - } - check(); } @@ -1203,7 +1187,7 @@ fetch_from_buf_http(buf_t *buf, /* Okay, we have a full header. Make sure it all appears in the first * chunk. */ if ((int)buf->head->datalen < crlf_offset + 4) - buf_pullup(buf, crlf_offset+4, 0); + buf_pullup(buf, crlf_offset+4); headerlen = crlf_offset + 4; headers = buf->head->data; @@ -1451,7 +1435,7 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req, do { n_drain = 0; - buf_pullup(buf, want_length, 0); + buf_pullup(buf, want_length); tor_assert(buf->head && buf->head->datalen >= 2); want_length = 0; @@ -1870,7 +1854,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req, *want_length_out = SOCKS4_NETWORK_LEN; return 0; /* not yet */ } - // buf_pullup(buf, 1280, 0); + // buf_pullup(buf, 1280); req->command = (unsigned char) *(data+1); if (req->command != SOCKS_COMMAND_CONNECT && req->command != SOCKS_COMMAND_RESOLVE) { @@ -2038,7 +2022,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason) if (buf->datalen < 2) return 0; - buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN, 0); + buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN); tor_assert(buf->head && buf->head->datalen >= 2); r = parse_socks_client((uint8_t*)buf->head->data, buf->head->datalen, diff --git a/src/or/buffers.h b/src/or/buffers.h index 6d0c68500b..7f79e3c0b2 100644 --- a/src/or/buffers.h +++ b/src/or/buffers.h @@ -101,7 +101,7 @@ void assert_buf_ok(buf_t *buf); #ifdef BUFFERS_PRIVATE STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n); -STATIC void buf_pullup(buf_t *buf, size_t bytes, int nulterminate); +STATIC void buf_pullup(buf_t *buf, size_t bytes); void buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz); #define DEBUG_CHUNK_ALLOC diff --git a/src/or/circuituse.c b/src/or/circuituse.c index a3b71974ca..00340fd689 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -2284,8 +2284,15 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn, base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - if (!circ->base_.timestamp_dirty) - circ->base_.timestamp_dirty = time(NULL); + if (!circ->base_.timestamp_dirty || + ((conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) && + (conn->entry_cfg.socks_iso_keep_alive) && + (conn->socks_request->usernamelen || + conn->socks_request->passwordlen))) { + /* When stream isolation is in use and controlled by an application + * we are willing to keep using the stream. */ + circ->base_.timestamp_dirty = approx_time(); + } pathbias_count_use_attempt(circ); diff --git a/src/or/config.c b/src/or/config.c index 3b8bf55875..47a1ee1fa5 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -289,7 +289,7 @@ static config_var_t option_vars_[] = { VAR("HiddenServiceMaxStreams",LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceNumIntroductionPoints", LINELIST_S, RendConfigLines, NULL), - V(HiddenServiceStatistics, BOOL, "0"), + V(HiddenServiceStatistics, BOOL, "1"), V(HidServAuth, LINELIST, NULL), V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"), V(CloseHSServiceRendCircuitsImmediatelyOnTimeout, BOOL, "0"), @@ -3174,6 +3174,21 @@ options_validate(or_options_t *old_options, or_options_t *options, "http://freehaven.net/anonbib/#hs-attack06 for details."); } + if (options->EntryNodes && + routerset_is_list(options->EntryNodes) && + (routerset_len(options->EntryNodes) == 1) && + (options->RendConfigLines != NULL)) { + tor_asprintf(msg, + "You have one single EntryNodes and at least one hidden service " + "configured. This is bad because it's very easy to locate your " + "entry guard which can then lead to the deanonymization of your " + "hidden service -- for more details, see " + "https://trac.torproject.org/projects/tor/ticket/14917. " + "For this reason, the use of one EntryNodes with an hidden " + "service is prohibited until a better solution is found."); + return -1; + } + if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout && options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) { log_warn(LD_CONFIG, @@ -6023,6 +6038,7 @@ parse_port_config(smartlist_t *out, int sessiongroup = SESSION_GROUP_UNSET; unsigned isolation = ISO_DEFAULT; int prefer_no_auth = 0; + int socks_iso_keep_alive = 0; char *addrport; uint16_t ptmp=0; @@ -6232,6 +6248,9 @@ parse_port_config(smartlist_t *out, } else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) { prefer_no_auth = ! no; continue; + } else if (!strcasecmp(elt, "KeepAliveIsolateSOCKSAuth")) { + socks_iso_keep_alive = ! no; + continue; } if (!strcasecmpend(elt, "s")) @@ -6277,6 +6296,13 @@ parse_port_config(smartlist_t *out, goto err; } + if (!(isolation & ISO_SOCKSAUTH) && socks_iso_keep_alive) { + log_warn(LD_CONFIG, "You have a %sPort entry with both " + "NoIsolateSOCKSAuth and KeepAliveIsolateSOCKSAuth set.", + portname); + goto err; + } + if (out && port) { size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0; port_cfg_t *cfg = port_cfg_new(namelen); @@ -6310,6 +6336,7 @@ parse_port_config(smartlist_t *out, cfg->entry_cfg.socks_prefer_no_auth = prefer_no_auth; if (! (isolation & ISO_SOCKSAUTH)) cfg->entry_cfg.socks_prefer_no_auth = 1; + cfg->entry_cfg.socks_iso_keep_alive = socks_iso_keep_alive; smartlist_add(out, cfg); } diff --git a/src/or/dirserv.c b/src/or/dirserv.c index e5b180696b..53b450cef5 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -1344,7 +1344,7 @@ dirserv_thinks_router_is_unreliable(time_t now, /** Return true iff <b>router</b> should be assigned the "HSDir" flag. * Right now this means it advertises support for it, it has a high uptime, - * it has a DirPort open, it has the Stable flag and it's currently + * it has a DirPort open, it has the Stable and Fast flag and it's currently * considered Running. * * This function needs to be called after router-\>is_running has @@ -1372,7 +1372,7 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router, uptime = real_uptime(router, now); return (router->wants_to_be_hs_dir && router->dir_port && - node->is_stable && + node->is_stable && node->is_fast && uptime >= get_options()->MinUptimeHidServDirectoryV2 && router_is_active(router, node, now)); } diff --git a/src/or/include.am b/src/or/include.am index 959b26dcf9..7b12b56eb1 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -153,6 +153,7 @@ ORHEADERS = \ src/or/dirserv.h \ src/or/dirvote.h \ src/or/dns.h \ + src/or/dns_structs.h \ src/or/dnsserv.h \ src/or/eventdns_tor.h \ src/or/ext_orport.h \ diff --git a/src/or/main.c b/src/or/main.c index 0b0207b975..693d13cd13 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -2019,6 +2019,14 @@ do_hup(void) * force a retry there. */ if (server_mode(options)) { + /* Maybe we've been given a new ed25519 key or certificate? + */ + time_t now = approx_time(); + if (load_ed_keys(options, now) < 0 || + generate_ed_link_cert(options, now)) { + log_warn(LD_OR, "Problem reloading Ed25519 keys; still using old keys."); + } + /* Update cpuworker and dnsworker processes, so they get up-to-date * configuration options. */ cpuworkers_rotate_keyinfo(); @@ -3034,12 +3042,19 @@ sandbox_init_filter(void) OPEN_DATADIR_SUFFIX("state", ".tmp"); OPEN_DATADIR_SUFFIX("unparseable-desc", ".tmp"); OPEN_DATADIR_SUFFIX("v3-status-votes", ".tmp"); + OPEN_DATADIR("key-pinning-journal"); OPEN("/dev/srandom"); OPEN("/dev/urandom"); OPEN("/dev/random"); OPEN("/etc/hosts"); OPEN("/proc/meminfo"); + if (options->BridgeAuthoritativeDir) + OPEN_DATADIR_SUFFIX("networkstatus-bridges", ".tmp"); + + if (authdir_mode_handles_descs(options, -1)) + OPEN_DATADIR("approved-routers"); + if (options->ServerDNSResolvConfFile) sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->ServerDNSResolvConfFile)); @@ -3080,6 +3095,9 @@ sandbox_init_filter(void) RENAME_SUFFIX("unparseable-desc", ".tmp"); RENAME_SUFFIX("v3-status-votes", ".tmp"); + if (options->BridgeAuthoritativeDir) + RENAME_SUFFIX("networkstatus-bridges", ".tmp"); + #define STAT_DATADIR(name) \ sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname(name)) @@ -3148,6 +3166,13 @@ sandbox_init_filter(void) OPEN_DATADIR2("keys", "secret_onion_key.old"); OPEN_DATADIR2("keys", "secret_onion_key_ntor.old"); + OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_secret_key", ".tmp"); + OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_secret_key_encrypted", + ".tmp"); + OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_public_key", ".tmp"); + OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_secret_key", ".tmp"); + OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_cert", ".tmp"); + OPEN_DATADIR2_SUFFIX("stats", "bridge-stats", ".tmp"); OPEN_DATADIR2_SUFFIX("stats", "dirreq-stats", ".tmp"); @@ -3178,6 +3203,12 @@ sandbox_init_filter(void) RENAME_SUFFIX("hashed-fingerprint", ".tmp"); RENAME_SUFFIX("router-stability", ".tmp"); + RENAME_SUFFIX2("keys", "ed25519_master_id_secret_key", ".tmp"); + RENAME_SUFFIX2("keys", "ed25519_master_id_secret_key_encrypted", ".tmp"); + RENAME_SUFFIX2("keys", "ed25519_master_id_public_key", ".tmp"); + RENAME_SUFFIX2("keys", "ed25519_signing_secret_key", ".tmp"); + RENAME_SUFFIX2("keys", "ed25519_signing_cert", ".tmp"); + sandbox_cfg_allow_rename(&cfg, get_datadir_fname2("keys", "secret_onion_key"), get_datadir_fname2("keys", "secret_onion_key.old")); diff --git a/src/or/or.h b/src/or/or.h index b753f7c11e..503eb56b65 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1155,6 +1155,8 @@ typedef struct entry_port_cfg_t { /** When both no-auth and user/pass are advertised by a SOCKS client, select * no-auth. */ unsigned int socks_prefer_no_auth : 1; + /** When ISO_SOCKSAUTH is in use, Keep-Alive circuits indefinitely. */ + unsigned int socks_iso_keep_alive : 1; /* Client port types only: */ unsigned int ipv4_traffic : 1; @@ -2877,6 +2879,11 @@ typedef struct circuit_t { * circuits entered certain states. This usage probably won't * interfere with this field's primary purpose, but we should * document it more thoroughly to make sure of that. + * + * XXX027 The SocksPort option KeepaliveIsolateSOCKSAuth will artificially + * adjust this value forward each time a suitable stream is attached to an + * already constructed circuit, potentially keeping the circuit alive + * indefinitely. */ time_t timestamp_dirty; diff --git a/src/or/policies.c b/src/or/policies.c index 560b8cb4c3..86eedd2c17 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -67,6 +67,8 @@ static int policies_parse_exit_policy_internal(config_line_t *cfg, int ipv6_exit, int rejectprivate, uint32_t local_address, + tor_addr_t *ipv6_local_address, + int reject_interface_addresses, int add_default_policy); /** Replace all "private" entries in *<b>policy</b> with their expanded @@ -152,7 +154,7 @@ policy_expand_unspec(smartlist_t **policy) } /** - * Given a linked list of config lines containing "allow" and "deny" + * Given a linked list of config lines containing "accept[6]" and "reject[6]" * tokens, parse them and append the result to <b>dest</b>. Return -1 * if any tokens are malformed (and don't append any), else return 0. * @@ -167,6 +169,7 @@ parse_addr_policy(config_line_t *cfg, smartlist_t **dest, smartlist_t *result; smartlist_t *entries; addr_policy_t *item; + int malformed_list; int r = 0; if (!cfg) @@ -179,12 +182,22 @@ parse_addr_policy(config_line_t *cfg, smartlist_t **dest, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(entries, const char *, ent) { log_debug(LD_CONFIG,"Adding new entry '%s'",ent); - item = router_parse_addr_policy_item_from_string(ent, assume_action); + malformed_list = 0; + item = router_parse_addr_policy_item_from_string(ent, assume_action, + &malformed_list); if (item) { smartlist_add(result, item); - } else { - log_warn(LD_CONFIG,"Malformed policy '%s'.", ent); + } else if (malformed_list) { + /* the error is so severe the entire list should be discarded */ + log_warn(LD_CONFIG, "Malformed policy '%s'. Discarding entire policy " + "list.", ent); r = -1; + } else { + /* the error is minor: don't add the item, but keep processing the + * rest of the policies in the list */ + log_debug(LD_CONFIG, "Ignored policy '%s' due to non-fatal error. " + "The remainder of the policy list will be used.", + ent); } } SMARTLIST_FOREACH_END(ent); SMARTLIST_FOREACH(entries, char *, ent, tor_free(ent)); @@ -430,7 +443,7 @@ validate_addr_policies(const or_options_t *options, char **msg) smartlist_t *addr_policy=NULL; *msg = NULL; - if (policies_parse_exit_policy_from_options(options,0,&addr_policy)) { + if (policies_parse_exit_policy_from_options(options,0,NULL,0,&addr_policy)) { REJECT("Error in ExitPolicy entry."); } @@ -568,6 +581,8 @@ cmp_single_addr_policy(addr_policy_t *a, addr_policy_t *b) return r; if ((r=((int)a->is_private - (int)b->is_private))) return r; + /* refcnt and is_canonical are irrelevant to equality, + * they are hash table implementation details */ if ((r=tor_addr_compare(&a->addr, &b->addr, CMP_EXACT))) return r; if ((r=((int)a->maskbits - (int)b->maskbits))) @@ -969,12 +984,24 @@ exit_policy_remove_redundancies(smartlist_t *dest) "reject *:563,reject *:1214,reject *:4661-4666," \ "reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*" -/** Parse the exit policy <b>cfg</b> into the linked list *<b>dest</b>. If - * cfg doesn't end in an absolute accept or reject and if +/** Parse the exit policy <b>cfg</b> into the linked list *<b>dest</b>. + * + * If <b>ipv6_exit</b> is true, prepend "reject *6:*" to the policy. + * + * If <b>rejectprivate</b> is true: + * - prepend "reject private:*" to the policy. + * - if local_address is non-zero, treat it as a host-order IPv4 address, + * and prepend an entry that rejects it as a destination. + * - if ipv6_local_address is non-NULL, prepend an entry that rejects it as + * a destination. + * - if reject_interface_addresses is true, prepend entries that reject each + * public IPv4 and IPv6 address of each interface on this machine. + * + * If cfg doesn't end in an absolute accept or reject and if * <b>add_default_policy</b> is true, add the default exit - * 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. + * policy afterwards. + * + * 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, @@ -985,21 +1012,142 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, int ipv6_exit, int rejectprivate, uint32_t local_address, + tor_addr_t *ipv6_local_address, + int reject_interface_addresses, int add_default_policy) { if (!ipv6_exit) { append_exit_policy_string(dest, "reject *6:*"); } if (rejectprivate) { + /* Reject IPv4 and IPv6 reserved private netblocks */ append_exit_policy_string(dest, "reject private:*"); + /* Reject our local IPv4 address */ if (local_address) { char buf[POLICY_BUF_LEN]; tor_snprintf(buf, sizeof(buf), "reject %s:*", fmt_addr32(local_address)); append_exit_policy_string(dest, buf); + log_info(LD_CONFIG, "Adding a reject ExitPolicy '%s' for our published " + "IPv4 address", buf); + } + /* Reject our local IPv6 address */ + if (ipv6_exit && ipv6_local_address != NULL) { + if (tor_addr_is_v4(ipv6_local_address)) { + log_warn(LD_CONFIG, "IPv4 address '%s' provided as our IPv6 local " + "address", fmt_addr(ipv6_local_address)); + } else { + char buf6[POLICY_BUF_LEN]; + tor_snprintf(buf6, sizeof(buf6), "reject %s:*", + fmt_addr(ipv6_local_address)); + append_exit_policy_string(dest, buf6); + log_info(LD_CONFIG, "Adding a reject ExitPolicy '%s' for our " + "published IPv6 address", buf6); + } + } + /* Reject local addresses from public netblocks on any interface, + * but don't reject our published addresses twice */ + if (reject_interface_addresses) { + smartlist_t *public_addresses = NULL; + char bufif[POLICY_BUF_LEN]; + + /* Reject public IPv4 addresses on any interface, + * but don't reject our published IPv4 address twice */ + public_addresses = get_interface_address6_list(LOG_INFO, AF_INET, 0); + SMARTLIST_FOREACH_BEGIN(public_addresses, tor_addr_t *, a) { + if (!tor_addr_eq_ipv4h(a, local_address)) { + tor_snprintf(bufif, sizeof(bufif), "reject %s:*", + fmt_addr(a)); + append_exit_policy_string(dest, bufif); + log_info(LD_CONFIG, "Adding a reject ExitPolicy '%s' for a local " + "interface's public IPv4 address", bufif); + } + } SMARTLIST_FOREACH_END(a); + free_interface_address6_list(public_addresses); + + if (ipv6_exit) { + /* Reject public IPv6 addresses on any interface, + * but don't reject our published IPv6 address (if any) twice */ + public_addresses = get_interface_address6_list(LOG_INFO, AF_INET6, 0); + SMARTLIST_FOREACH_BEGIN(public_addresses, tor_addr_t *, a) { + /* if we don't have an IPv6 local address, we won't have rejected + * it above. This could happen if a future release does IPv6 + * autodiscovery, and we are waiting to discover our external IPv6 + * address */ + if (ipv6_local_address == NULL + || !tor_addr_eq(ipv6_local_address, a)) { + tor_snprintf(bufif, sizeof(bufif), "reject6 %s:*", + fmt_addr(a)); + append_exit_policy_string(dest, bufif); + log_info(LD_CONFIG, "Adding a reject ExitPolicy '%s' for a local " + "interface's public IPv6 address", bufif); + } + } SMARTLIST_FOREACH_END(a); + free_interface_address6_list(public_addresses); + } } } if (parse_addr_policy(cfg, dest, -1)) return -1; + + /* Before we add the default policy and final rejects, check to see if + * there are any lines after accept *:* or reject *:*. These lines have no + * effect, and are most likely an error. */ + int found_final_effective_entry = 0; + int first_redundant_entry = 0; + for (int i = 0; i < smartlist_len(*dest); ++i) { + sa_family_t family; + addr_policy_t *p; + int found_ipv4_wildcard = 0, found_ipv6_wildcard = 0; + + p = smartlist_get(*dest, i); + + /* Look for accept/reject *[4|6|]:* entires */ + if (p->prt_min <= 1 && p->prt_max == 65535 && p->maskbits == 0) { + family = tor_addr_family(&p->addr); + /* accept/reject *:* may have already been expanded into + * accept/reject *4:*,accept/reject *6:* + * But handle both forms. + */ + if (family == AF_INET || family == AF_UNSPEC) { + found_ipv4_wildcard = 1; + } + if (family == AF_INET6 || family == AF_UNSPEC) { + found_ipv6_wildcard = 1; + } + } + + /* We also find accept *4:*,reject *6:* ; and + * accept *4:*,<other policies>,accept *6:* ; and similar. + * That's ok, because they make any subsequent entries redundant. */ + if (found_ipv4_wildcard && found_ipv6_wildcard) { + found_final_effective_entry = 1; + /* if we're not on the final entry in the list */ + if (i < smartlist_len(*dest) - 1) { + first_redundant_entry = i + 1; + } + break; + } + } + /* Work out if there are redundant trailing entries in the policy list */ + if (found_final_effective_entry && first_redundant_entry > 0) { + addr_policy_t *p; + /* Longest possible policy is + * "accept6 ffff:ffff:..255/128:10000-65535", + * which contains a max-length IPv6 address, plus 24 characters. */ + char line[TOR_ADDR_BUF_LEN + 32]; + + tor_assert(first_redundant_entry < smartlist_len(*dest)); + p = smartlist_get(*dest, first_redundant_entry); + /* since we've already parsed the policy into an addr_policy_t struct, + * we might not log exactly what the user typed in */ + policy_write_item(line, TOR_ADDR_BUF_LEN + 32, p, 0); + log_warn(LD_DIR, "Exit policy '%s' and all following policies are " + "redundant, as it follows accept/reject *:* rules for both " + "IPv4 and IPv6. They will be removed from the exit policy. (Use " + "accept/reject *:* as the last entry in any exit policy.)", + line); + } + if (add_default_policy) { append_exit_policy_string(dest, DEFAULT_EXIT_POLICY); } else { @@ -1013,20 +1161,28 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, /** Parse exit policy in <b>cfg</b> into <b>dest</b> smartlist. * - * Add entry that rejects all IPv6 destinations unless + * Prepend an entry that rejects all IPv6 destinations unless * <b>EXIT_POLICY_IPV6_ENABLED</b> bit is set in <b>options</b> bitmask. * - * If <b>EXIT_POLICY_REJECT_PRIVATE</b> bit is set in <b>options</b>, - * do add entry that rejects all destinations in private subnetwork - * Tor is running in. + * If <b>EXIT_POLICY_REJECT_PRIVATE</b> bit is set in <b>options</b>: + * - prepend an entry that rejects all destinations in all netblocks + * reserved for private use. + * - if local_address is non-zero, treat it as a host-order IPv4 address, + * and prepend an entry that rejects it as a destination. + * - if ipv6_local_address is non-NULL, prepend an entry that rejects it as + * a destination. + * - if reject_interface_addresses is true, prepend entries that reject each + * public IPv4 and IPv6 address of each interface on this machine. * - * Respectively, if <b>EXIT_POLICY_ADD_DEFAULT</b> bit is set, add + * If <b>EXIT_POLICY_ADD_DEFAULT</b> bit is set in <b>options</b>, append * default exit policy entries to <b>result</b> smartlist. */ int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, exit_policy_parser_cfg_t options, - uint32_t local_address) + uint32_t local_address, + tor_addr_t *ipv6_local_address, + int reject_interface_addresses) { int ipv6_enabled = (options & EXIT_POLICY_IPV6_ENABLED) ? 1 : 0; int reject_private = (options & EXIT_POLICY_REJECT_PRIVATE) ? 1 : 0; @@ -1035,19 +1191,27 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, return policies_parse_exit_policy_internal(cfg,dest,ipv6_enabled, reject_private, local_address, + ipv6_local_address, + reject_interface_addresses, add_default); } /** Parse <b>ExitPolicy</b> member of <b>or_options</b> into <b>result</b> * smartlist. - * If <b>or_options->IPv6Exit</b> is false, add an entry that + * If <b>or_options->IPv6Exit</b> is false, prepend an entry that * rejects all IPv6 destinations. * - * If <b>or_options->ExitPolicyRejectPrivate</b> is true, add entry that - * rejects all destinations in the private subnetwork of machine Tor - * instance is running in. + * If <b>or_options->ExitPolicyRejectPrivate</b> is true: + * - prepend an entry that rejects all destinations in all netblocks reserved + * for private use. + * - if local_address is non-zero, treat it as a host-order IPv4 address, and + * prepend an entry that rejects it as a destination. + * - if ipv6_local_address is non-NULL, prepend an entry that rejects it as a + * destination. + * - if reject_interface_addresses is true, prepend entries that reject each + * public IPv4 and IPv6 address of each interface on this machine. * - * If <b>or_options->BridgeRelay</b> is false, add entries of default + * If <b>or_options->BridgeRelay</b> is false, append entries of default * Tor exit policy into <b>result</b> smartlist. * * If or_options->ExitRelay is false, then make our exit policy into @@ -1056,6 +1220,8 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, int policies_parse_exit_policy_from_options(const or_options_t *or_options, uint32_t local_address, + tor_addr_t *ipv6_local_address, + int reject_interface_addresses, smartlist_t **result) { exit_policy_parser_cfg_t parser_cfg = 0; @@ -1079,7 +1245,9 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options, } return policies_parse_exit_policy(or_options->ExitPolicy,result, - parser_cfg,local_address); + parser_cfg,local_address, + ipv6_local_address, + reject_interface_addresses); } /** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating diff --git a/src/or/policies.h b/src/or/policies.h index 0225b57a2c..f200d7babe 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -48,18 +48,16 @@ MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy, 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, uint32_t local_address, - int add_default_policy); -*/ int policies_parse_exit_policy_from_options(const or_options_t *or_options, uint32_t local_address, + tor_addr_t *ipv6_local_address, + int reject_interface_addresses, smartlist_t **result); int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, exit_policy_parser_cfg_t options, - uint32_t local_address); + uint32_t local_address, + tor_addr_t *ipv6_local_address, + int reject_interface_addresses); void policies_exit_policy_append_reject_star(smartlist_t **dest); void addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr); diff --git a/src/or/rendcache.c b/src/or/rendcache.c index fe9a1344f6..542d322c79 100644 --- a/src/or/rendcache.c +++ b/src/or/rendcache.c @@ -334,6 +334,17 @@ cache_failure_intro_lookup(const uint8_t *identity, const char *service_id, return 0; } +/** Allocate a new cache failure intro object and copy the content from + * <b>entry</b> to this newly allocated object. Return it. */ +static rend_cache_failure_intro_t * +cache_failure_intro_dup(const rend_cache_failure_intro_t *entry) +{ + rend_cache_failure_intro_t *ent_dup = + rend_cache_failure_intro_entry_new(entry->failure_type); + ent_dup->created_ts = entry->created_ts; + return ent_dup; +} + /** Add an intro point failure to the failure cache using the relay * <b>identity</b> and service ID <b>service_id</b>. Record the * <b>failure</b> in that object. */ @@ -383,12 +394,15 @@ validate_intro_point_failure(const rend_service_descriptor_t *desc, found = cache_failure_intro_lookup(identity, service_id, &entry); if (found) { + /* Dup here since it will be freed at the end when removing the + * original entry in the cache. */ + rend_cache_failure_intro_t *ent_dup = cache_failure_intro_dup(entry); /* This intro point is in our cache, discard it from the descriptor * because chances are that it's unusable. */ SMARTLIST_DEL_CURRENT(desc->intro_nodes, intro); rend_intro_point_free(intro); /* Keep it for our new entry. */ - digestmap_set(new_entry->intro_failures, (char *) identity, entry); + digestmap_set(new_entry->intro_failures, (char *) identity, ent_dup); continue; } } SMARTLIST_FOREACH_END(intro); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index f3a09ddaf2..8ba5327b1d 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -1762,7 +1762,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, /** Given a parsed and decrypted INTRODUCE2, find the rendezvous point or * return NULL and an error string if we can't. Return a newly allocated - * extend_info_t* for the introduction point. */ + * extend_info_t* for the rendezvous point. */ static extend_info_t * find_rp_for_intro(const rend_intro_cell_t *intro, char **err_msg_out) diff --git a/src/or/router.c b/src/or/router.c index 03973ae90a..8fdad9a5fa 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1922,7 +1922,7 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) /* DNS is screwed up; don't claim to be an exit. */ policies_exit_policy_append_reject_star(&ri->exit_policy); } else { - policies_parse_exit_policy_from_options(options,ri->addr, + policies_parse_exit_policy_from_options(options,ri->addr,&ri->ipv6_addr,1, &ri->exit_policy); } ri->policy_is_reject_star = diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c index d65b62991b..b1e9ed36f0 100644 --- a/src/or/routerkeys.c +++ b/src/or/routerkeys.c @@ -321,6 +321,7 @@ ed_key_init_from_file(const char *fname, uint32_t flags, if (r > 0) { have_secret = 1; have_encrypted_secret_file = 1; + tor_free(got_tag); /* convince coverity we aren't leaking */ got_tag = tor_strdup(tag); loaded_secret_fname = encrypted_secret_fname; } else if (errno != ENOENT && norepair) { @@ -646,11 +647,13 @@ load_ed_keys(const or_options_t *options, time_t now) goto err; \ } while (0) #define SET_KEY(key, newval) do { \ - ed25519_keypair_free(key); \ + if ((key) != (newval)) \ + ed25519_keypair_free(key); \ key = (newval); \ } while (0) #define SET_CERT(cert, newval) do { \ - tor_cert_free(cert); \ + if ((cert) != (newval)) \ + tor_cert_free(cert); \ cert = (newval); \ } while (0) #define EXPIRES_SOON(cert, interval) \ @@ -659,10 +662,7 @@ load_ed_keys(const or_options_t *options, time_t now) /* XXXX support encrypted identity keys fully */ /* First try to get the signing key to see how it is. */ - if (master_signing_key) { - check_signing_cert = signing_key_cert; - use_signing = master_signing_key; - } else { + { char *fname = options_get_datadir_fname2(options, "keys", "ed25519_signing"); sign = ed_key_init_from_file( @@ -676,9 +676,13 @@ load_ed_keys(const or_options_t *options, time_t now) use_signing = sign; } + if (!use_signing && master_signing_key) { + check_signing_cert = signing_key_cert; + use_signing = master_signing_key; + } + const int offline_master = options->OfflineMasterKey && options->command != CMD_KEYGEN; - const int need_new_signing_key = NULL == use_signing || EXPIRES_SOON(check_signing_cert, 0) || diff --git a/src/or/routerparse.c b/src/or/routerparse.c index c2206f1075..17c46acfda 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -3666,24 +3666,38 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or * ADDR_POLICY_REJECT) for items that specify no action. * + * Returns NULL on policy errors. + * + * If there is a policy error, malformed_list is set to true if the entire + * policy list should be discarded. Otherwise, it is set to false, and only + * this item should be ignored - the rest of the policy list can continue to + * be processed and used. + * * 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. */ MOCK_IMPL(addr_policy_t *, -router_parse_addr_policy_item_from_string,(const char *s, int assume_action)) +router_parse_addr_policy_item_from_string,(const char *s, int assume_action, + int *malformed_list)) { directory_token_t *tok = NULL; const char *cp, *eos; /* Longest possible policy is - * "accept6 ffff:ffff:..255/ffff:...255:10000-65535", - * which contains 2 max-length IPv6 addresses, plus 21 characters. + * "accept6 ffff:ffff:..255/128:10000-65535", + * which contains a max-length IPv6 address, plus 24 characters. * But note that there can be an arbitrary amount of space between the - * accept and the address:mask/port element. */ + * accept and the address:mask/port element. + * We don't need to multiply TOR_ADDR_BUF_LEN by 2, as there is only one + * IPv6 address. But making the buffer shorter might cause valid long lines, + * which parsed in previous versions, to fail to parse in new versions. + * (These lines would have to have excessive amounts of whitespace.) */ char line[TOR_ADDR_BUF_LEN*2 + 32]; addr_policy_t *r; memarea_t *area = NULL; + tor_assert(malformed_list); + s = eat_whitespace(s); if ((*s == '*' || TOR_ISDIGIT(*s)) && assume_action >= 0) { if (tor_snprintf(line, sizeof(line), "%s %s", @@ -3710,9 +3724,32 @@ router_parse_addr_policy_item_from_string,(const char *s, int assume_action)) goto err; } + /* Use the extended interpretation of accept/reject *, + * expanding it into an IPv4 wildcard and an IPv6 wildcard. + * Also permit *4 and *6 for IPv4 and IPv6 only wildcards. */ r = router_parse_addr_policy(tok, TAPMP_EXTENDED_STAR); + if (!r) { + goto err; + } + + /* Ensure that accept6/reject6 fields are followed by IPv6 addresses. + * AF_UNSPEC addresses are only permitted on the accept/reject field type. + * Unlike descriptors, torrcs exit policy accept/reject can be followed by + * either an IPv4 or IPv6 address. */ + if ((tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) && + tor_addr_family(&r->addr) != AF_INET6) { + /* This is a non-fatal error, just ignore this one entry. */ + *malformed_list = 0; + log_warn(LD_DIR, "IPv4 address '%s' with accept6/reject6 field type in " + "exit policy. Ignoring, but continuing to parse rules. (Use " + "accept/reject with IPv4 addresses.)", + tok->n_args == 1 ? tok->args[0] : ""); + return NULL; + } + goto done; err: + *malformed_list = 1; r = NULL; done: token_clear(tok); @@ -3729,19 +3766,27 @@ static int router_add_exit_policy(routerinfo_t *router, directory_token_t *tok) { addr_policy_t *newe; + /* Use the standard interpretation of accept/reject *, an IPv4 wildcard. */ newe = router_parse_addr_policy(tok, 0); if (!newe) return -1; if (! router->exit_policy) router->exit_policy = smartlist_new(); + /* Ensure that in descriptors, accept/reject fields are followed by + * IPv4 addresses, and accept6/reject6 fields are followed by + * IPv6 addresses. Unlike torrcs, descriptor exit policies do not permit + * accept/reject followed by IPv6. */ if (((tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) && tor_addr_family(&newe->addr) == AF_INET) || ((tok->tp == K_ACCEPT || tok->tp == K_REJECT) && tor_addr_family(&newe->addr) == AF_INET6)) { + /* There's nothing the user can do about other relays' descriptors, + * so we don't provide usage advice here. */ log_warn(LD_DIR, "Mismatch between field type and address type in exit " - "policy"); + "policy '%s'. Discarding entire router descriptor.", + tok->n_args == 1 ? tok->args[0] : ""); addr_policy_free(newe); return -1; } @@ -3751,8 +3796,11 @@ router_add_exit_policy(routerinfo_t *router, directory_token_t *tok) return 0; } -/** Given a K_ACCEPT or K_REJECT token and a router, create and return - * a new exit_policy_t corresponding to the token. */ +/** Given a K_ACCEPT[6] or K_REJECT[6] token and a router, create and return + * a new exit_policy_t corresponding to the token. If TAPMP_EXTENDED_STAR + * is set in fmt_flags, K_ACCEPT6 and K_REJECT6 tokens followed by * + * expand to IPv6-only policies, otherwise they expand to IPv4 and IPv6 + * policies */ static addr_policy_t * router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags) { @@ -3776,6 +3824,13 @@ router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags) else newe.policy_type = ADDR_POLICY_ACCEPT; + /* accept6/reject6 * produces an IPv6 wildcard address only. + * (accept/reject * produces rules for IPv4 and IPv6 wildcard addresses.) */ + if ((fmt_flags & TAPMP_EXTENDED_STAR) + && (tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6)) { + fmt_flags |= TAPMP_STAR_IPV6_ONLY; + } + 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)); @@ -3785,9 +3840,12 @@ router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags) return addr_policy_get_canonical_entry(&newe); } -/** Parse an exit policy line of the format "accept/reject private:...". +/** Parse an exit policy line of the format "accept[6]/reject[6] private:...". * This didn't exist until Tor 0.1.1.15, so nobody should generate it in * router descriptors until earlier versions are obsolete. + * + * accept/reject and accept6/reject6 private all produce rules for both + * IPv4 and IPv6 addresses. */ static addr_policy_t * router_parse_addr_policy_private(directory_token_t *tok) @@ -3817,6 +3875,13 @@ router_parse_addr_policy_private(directory_token_t *tok) result.prt_min = port_min; result.prt_max = port_max; + if (tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) { + log_warn(LD_GENERAL, + "'%s' expands into rules which apply to all private IPv4 and " + "IPv6 addresses. (Use accept/reject private:* for IPv4 and " + "IPv6.)", tok->n_args == 1 ? tok->args[0] : ""); + } + return addr_policy_get_canonical_entry(&result); } diff --git a/src/or/routerparse.h b/src/or/routerparse.h index 85e4b7d88e..99fd52866c 100644 --- a/src/or/routerparse.h +++ b/src/or/routerparse.h @@ -41,7 +41,7 @@ extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end, int cache_copy, struct digest_ri_map_t *routermap, int *can_dl_again_out); MOCK_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string, - (const char *s, int assume_action)); + (const char *s, int assume_action, int *malformed_list)); version_status_t tor_version_is_obsolete(const char *myversion, const char *versionlist); int tor_version_as_new_as(const char *platform, const char *cutoff); diff --git a/src/or/routerset.c b/src/or/routerset.c index 99de11ed5e..3be55d3404 100644 --- a/src/or/routerset.c +++ b/src/or/routerset.c @@ -85,10 +85,13 @@ routerset_parse(routerset_t *target, const char *s, const char *description) int added_countries = 0; char *countryname; smartlist_t *list = smartlist_new(); + int malformed_list; smartlist_split_string(list, s, ",", SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(list, char *, nick) { addr_policy_t *p; + /* if it doesn't pass our validation, assume it's malformed */ + malformed_list = 1; if (is_legal_hexdigest(nick)) { char d[DIGEST_LEN]; if (*nick == '$') @@ -106,15 +109,21 @@ routerset_parse(routerset_t *target, const char *s, const char *description) added_countries = 1; } else if ((strchr(nick,'.') || strchr(nick, '*')) && (p = router_parse_addr_policy_item_from_string( - nick, ADDR_POLICY_REJECT))) { + nick, ADDR_POLICY_REJECT, + &malformed_list))) { 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 malformed.", nick, - description); + } else if (malformed_list) { + log_warn(LD_CONFIG, "Entry '%s' in %s is malformed. Discarding entire" + " list.", nick, description); r = -1; tor_free(nick); SMARTLIST_DEL_CURRENT(list, nick); + } else { + log_notice(LD_CONFIG, "Entry '%s' in %s is ignored. Using the" + " remainder of the list.", nick, description); + tor_free(nick); + SMARTLIST_DEL_CURRENT(list, nick); } } SMARTLIST_FOREACH_END(nick); policy_expand_unspec(&target->policies); @@ -162,6 +171,17 @@ routerset_is_empty(const routerset_t *set) return !set || smartlist_len(set->list) == 0; } +/** Return the number of entries in <b>set</b>. This does NOT return a + * negative value. */ +int +routerset_len(const routerset_t *set) +{ + if (!set) { + return 0; + } + return smartlist_len(set->list); +} + /** 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 diff --git a/src/or/routerset.h b/src/or/routerset.h index 8d41de8b6b..aca7c6e74e 100644 --- a/src/or/routerset.h +++ b/src/or/routerset.h @@ -38,6 +38,7 @@ void routerset_subtract_nodes(smartlist_t *out, 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); +int routerset_len(const routerset_t *set); #ifdef ROUTERSET_PRIVATE STATIC char * routerset_get_countryname(const char *c); diff --git a/src/or/tor_main.c b/src/or/tor_main.c index af03b8c06a..65bb020c2c 100644 --- a/src/or/tor_main.c +++ b/src/or/tor_main.c @@ -27,6 +27,10 @@ int tor_main(int argc, char *argv[]); int main(int argc, char *argv[]) { - return tor_main(argc, argv); + int r = tor_main(argc, argv); + if (r < 0 || r > 255) + return 1; + else + return r; } diff --git a/src/test/include.am b/src/test/include.am index ff5e456cff..f7c0204832 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -8,6 +8,13 @@ endif TESTS += src/test/test src/test/test-slow src/test/test-memwipe \ src/test/test_workqueue src/test/test_keygen.sh $(TESTSCRIPTS) +# These flavors are run using automake's test-driver and test-network.sh +TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-min bridges+hs +# only run if we can ping6 ::1 (localhost) +TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min +# only run if we can find a stable (or simply another) version of tor +TEST_CHUTNEY_FLAVORS_MIXED = mixed + ### This is a lovely feature, but it requires automake >= 1.12, and Tor ### doesn't require that yet. Below is a kludge to work around. ### @@ -186,4 +193,5 @@ EXTRA_DIST += \ src/test/bt_test.py \ src/test/ntor_ref.py \ src/test/slownacl_curve25519.py \ - src/test/zero_length_keys.sh + src/test/zero_length_keys.sh \ + src/test/test_keygen.sh diff --git a/src/test/test-network.sh b/src/test/test-network.sh index cc74c0f823..05080e0c52 100755 --- a/src/test/test-network.sh +++ b/src/test/test-network.sh @@ -3,9 +3,9 @@ ECHO_N="/bin/echo -n" use_coverage_binary=false -until [ -z $1 ] +until [ -z "$1" ] do - case $1 in + case "$1" in --chutney-path) export CHUTNEY_PATH="$2" shift @@ -55,12 +55,20 @@ do done TOR_DIR="${TOR_DIR:-$PWD}" -NETWORK_FLAVOUR=${NETWORK_FLAVOUR:-basic} +NETWORK_FLAVOUR=${NETWORK_FLAVOUR:-"bridges+hs"} CHUTNEY_NETWORK=networks/$NETWORK_FLAVOUR myname=$(basename $0) +[ -n "$CHUTNEY_PATH" ] || { + echo "$myname: \$CHUTNEY_PATH not set, trying $TOR_DIR/../chutney" + CHUTNEY_PATH="$TOR_DIR/../chutney" +} + [ -d "$CHUTNEY_PATH" ] && [ -x "$CHUTNEY_PATH/chutney" ] || { echo "$myname: missing 'chutney' in CHUTNEY_PATH ($CHUTNEY_PATH)" + echo "$myname: Get chutney: git clone https://git.torproject.org/\ +chutney.git" + echo "$myname: Set \$CHUTNEY_PATH to a non-standard location: export CHUTNEY_PATH=\`pwd\`/chutney" exit 1 } @@ -78,7 +86,7 @@ export CHUTNEY_TOR_GENCERT="${TOR_DIR}/src/tools/${tor_gencert_name}" # Sleep some, waiting for the network to bootstrap. # TODO: Add chutney command 'bootstrap-status' and use that instead. -BOOTSTRAP_TIME=${BOOTSTRAP_TIME:-25} +BOOTSTRAP_TIME=${BOOTSTRAP_TIME:-35} $ECHO_N "$myname: sleeping for $BOOTSTRAP_TIME seconds" n=$BOOTSTRAP_TIME; while [ $n -gt 0 ]; do sleep 1; n=$(expr $n - 1); $ECHO_N . diff --git a/src/test/test_address.c b/src/test/test_address.c index 9d6456315c..72742df2cd 100644 --- a/src/test/test_address.c +++ b/src/test/test_address.c @@ -74,35 +74,79 @@ sockaddr_in_from_string(const char *ip_str, struct sockaddr_in *out) } /** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure - * that points to 127.0.0.1. Otherwise, return 0. + * that is an IPv4 or IPv6 localhost address. Otherwise, return 0. */ static int smartlist_contains_localhost_tor_addr(smartlist_t *smartlist) { - int found_localhost = 0; + SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { + if (tor_addr_is_loopback(tor_addr)) { + return 1; + } + } SMARTLIST_FOREACH_END(tor_addr); - struct sockaddr_in *sockaddr_localhost; - struct sockaddr_storage *sockaddr_to_check; + return 0; +} - sockaddr_localhost = sockaddr_in_from_string("127.0.0.1",NULL); +/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure + * that is an IPv4 or IPv6 multicast address. Otherwise, return 0. + */ +static int +smartlist_contains_multicast_tor_addr(smartlist_t *smartlist) +{ + SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { + if (tor_addr_is_multicast(tor_addr)) { + return 1; + } + } SMARTLIST_FOREACH_END(tor_addr); - sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in)); + return 0; +} +/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure + * that is an IPv4 or IPv6 internal address. Otherwise, return 0. + */ +static int +smartlist_contains_internal_tor_addr(smartlist_t *smartlist) +{ SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { - tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check, - sizeof(struct sockaddr_in)); + if (tor_addr_is_internal(tor_addr, 0)) { + return 1; + } + } SMARTLIST_FOREACH_END(tor_addr); - if (sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check, - sockaddr_localhost)) { - found_localhost = 1; - break; + return 0; +} + +/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure + * that is an IPv4 address. Otherwise, return 0. + */ +static int +smartlist_contains_ipv4_tor_addr(smartlist_t *smartlist) +{ + SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { + if (tor_addr_is_v4(tor_addr)) { + return 1; } } SMARTLIST_FOREACH_END(tor_addr); - tor_free(sockaddr_localhost); - tor_free(sockaddr_to_check); + return 0; +} - return found_localhost; +/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure + * that is an IPv6 address. Otherwise, return 0. + */ +static int +smartlist_contains_ipv6_tor_addr(smartlist_t *smartlist) +{ + SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) { + /* Since there's no tor_addr_is_v6, assume all non-v4s are v6 */ + if (!tor_addr_is_v4(tor_addr)) { + return 1; + } + } SMARTLIST_FOREACH_END(tor_addr); + + return 0; } #ifdef HAVE_IFADDRS_TO_SMARTLIST @@ -634,12 +678,168 @@ test_address_udp_socket_trick_blackbox(void *arg) return; } +static void +test_address_get_if_addrs_list_internal(void *arg) +{ + smartlist_t *results = NULL; + + (void)arg; + + results = get_interface_address_list(LOG_ERR, 1); + + tt_assert(results != NULL); + /* Assume every system has at least 1 non-local non-multicast IPv4 + * interface, even if it is an internal one */ + tt_int_op(smartlist_len(results),>=,1); + + tt_assert(!smartlist_contains_localhost_tor_addr(results)); + tt_assert(!smartlist_contains_multicast_tor_addr(results)); + /* The list may or may not contain internal addresses */ + + tt_assert(smartlist_contains_ipv4_tor_addr(results)); + tt_assert(!smartlist_contains_ipv6_tor_addr(results)); + + done: + free_interface_address_list(results); + return; +} + +static void +test_address_get_if_addrs_list_no_internal(void *arg) +{ + smartlist_t *results = NULL; + + (void)arg; + + results = get_interface_address_list(LOG_ERR, 0); + + tt_assert(results != NULL); + /* Work even on systems with only internal IPv4 addresses */ + tt_int_op(smartlist_len(results),>=,0); + + tt_assert(!smartlist_contains_localhost_tor_addr(results)); + tt_assert(!smartlist_contains_multicast_tor_addr(results)); + tt_assert(!smartlist_contains_internal_tor_addr(results)); + + /* The list may or may not contain IPv4 addresses */ + tt_assert(!smartlist_contains_ipv6_tor_addr(results)); + + done: + free_interface_address_list(results); + return; +} + +static void +test_address_get_if_addrs6_list_internal(void *arg) +{ + smartlist_t *results = NULL; + + (void)arg; + + results = get_interface_address6_list(LOG_ERR, AF_INET6, 1); + + tt_assert(results != NULL); + /* Work even on systems without IPv6 interfaces */ + tt_int_op(smartlist_len(results),>=,0); + + tt_assert(!smartlist_contains_localhost_tor_addr(results)); + tt_assert(!smartlist_contains_multicast_tor_addr(results)); + /* The list may or may not contain internal addresses */ + + tt_assert(!smartlist_contains_ipv4_tor_addr(results)); + /* The list may or may not contain IPv6 addresses */ + + done: + free_interface_address6_list(results); + return; +} + +static void +test_address_get_if_addrs6_list_no_internal(void *arg) +{ + smartlist_t *results = NULL; + + (void)arg; + + results = get_interface_address6_list(LOG_ERR, AF_INET6, 0); + + tt_assert(results != NULL); + /* Work even on systems without IPv6 interfaces */ + tt_int_op(smartlist_len(results),>=,0); + + tt_assert(!smartlist_contains_localhost_tor_addr(results)); + tt_assert(!smartlist_contains_multicast_tor_addr(results)); + tt_assert(!smartlist_contains_internal_tor_addr(results)); + + tt_assert(!smartlist_contains_ipv4_tor_addr(results)); + /* The list may or may not contain IPv6 addresses */ + + done: + free_interface_address6_list(results); + return; +} + +static void +test_address_get_if_addrs(void *arg) +{ + int rv; + uint32_t addr_h = 0; + tor_addr_t tor_addr; + + (void)arg; + + rv = get_interface_address(LOG_ERR, &addr_h); + + /* Assume every system has at least 1 non-local non-multicast IPv4 + * interface, even if it is an internal one */ + tt_assert(rv == 0); + tor_addr_from_ipv4h(&tor_addr, addr_h); + + tt_assert(!tor_addr_is_loopback(&tor_addr)); + tt_assert(!tor_addr_is_multicast(&tor_addr)); + /* The address may or may not be an internal address */ + + tt_assert(tor_addr_is_v4(&tor_addr)); + + done: + return; +} + +static void +test_address_get_if_addrs6(void *arg) +{ + int rv; + tor_addr_t tor_addr; + + (void)arg; + + rv = get_interface_address6(LOG_ERR, AF_INET6, &tor_addr); + + /* Work even on systems without IPv6 interfaces */ + if (rv == 0) { + tt_assert(!tor_addr_is_loopback(&tor_addr)); + tt_assert(!tor_addr_is_multicast(&tor_addr)); + /* The address may or may not be an internal address */ + + tt_assert(!tor_addr_is_v4(&tor_addr)); + } + + done: + return; +} + #define ADDRESS_TEST(name, flags) \ { #name, test_address_ ## name, flags, NULL, NULL } struct testcase_t address_tests[] = { ADDRESS_TEST(udp_socket_trick_whitebox, TT_FORK), ADDRESS_TEST(udp_socket_trick_blackbox, TT_FORK), + ADDRESS_TEST(get_if_addrs_list_internal, 0), + ADDRESS_TEST(get_if_addrs_list_no_internal, 0), + ADDRESS_TEST(get_if_addrs6_list_internal, 0), + ADDRESS_TEST(get_if_addrs6_list_no_internal, 0), + ADDRESS_TEST(get_if_addrs, 0), + ADDRESS_TEST(get_if_addrs6, 0), #ifdef HAVE_IFADDRS_TO_SMARTLIST ADDRESS_TEST(get_if_addrs_ifaddrs, TT_FORK), ADDRESS_TEST(ifaddrs_to_smartlist, 0), diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c index e8fce12314..29ee408616 100644 --- a/src/test/test_buffers.c +++ b/src/test/test_buffers.c @@ -206,9 +206,6 @@ test_buffer_pullup(void *arg) stuff = tor_malloc(16384); tmp = tor_malloc(16384); - /* Note: this test doesn't check the nulterminate argument to buf_pullup, - since nothing actually uses it. We should remove it some time. */ - buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ tt_assert(buf); @@ -218,7 +215,7 @@ test_buffer_pullup(void *arg) /* There are a bunch of cases for pullup. One is the trivial case. Let's mess around with an empty buffer. */ - buf_pullup(buf, 16, 1); + buf_pullup(buf, 16); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_EQ, NULL); tt_uint_op(sz, OP_EQ, 0); @@ -240,7 +237,7 @@ test_buffer_pullup(void *arg) * can get tested. */ tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 3000); tt_mem_op(tmp,OP_EQ, stuff, 3000); - buf_pullup(buf, 2048, 0); + buf_pullup(buf, 2048); assert_buf_ok(buf); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_NE, NULL); @@ -263,7 +260,7 @@ test_buffer_pullup(void *arg) tt_ptr_op(cp, OP_NE, NULL); tt_int_op(sz, OP_LE, 4096); - buf_pullup(buf, 12500, 0); + buf_pullup(buf, 12500); assert_buf_ok(buf); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_NE, NULL); @@ -286,7 +283,7 @@ test_buffer_pullup(void *arg) write_to_buf(stuff, 4000, buf); write_to_buf(stuff+4000, 4000, buf); fetch_from_buf(tmp, 100, buf); /* dump 100 bytes from first chunk */ - buf_pullup(buf, 16000, 0); /* Way too much. */ + buf_pullup(buf, 16000); /* Way too much. */ assert_buf_ok(buf); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_NE, NULL); diff --git a/src/test/test_keygen.sh b/src/test/test_keygen.sh index e8e3c3d219..87012cd283 100755 --- a/src/test/test_keygen.sh +++ b/src/test/test_keygen.sh @@ -46,11 +46,12 @@ fi fi +dump() { xxd -p "$1" | tr -d '\n '; } die() { echo "$1" >&2 ; exit 5; } check_dir() { [ -d "$1" ] || die "$1 did not exist"; } check_file() { [ -e "$1" ] || die "$1 did not exist"; } check_no_file() { [ -e "$1" ] && die "$1 was not supposed to exist" || true; } -check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match"; } +check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: `dump $1` vs `dump $2`"; } check_keys_eq() { check_files_eq "${SRC}/keys/${1}" "${ME}/keys/${1}"; } DATA_DIR=`mktemp -d -t tor_keygen_tests.XXXXXX` @@ -64,9 +65,13 @@ if [ ! -d "$DATA_DIR" ]; then fi trap "rm -rf '$DATA_DIR'" 0 +# Use an absolute path for this or Tor will complain +DATA_DIR=`cd "${DATA_DIR}" && pwd` + touch "${DATA_DIR}/empty_torrc" QUIETLY="--hush" +SILENTLY="--quiet" TOR="${TOR_BINARY} ${QUIETLY} --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort 12345 --ExitRelay 0 -f ${DATA_DIR}/empty_torrc" ##### SETUP @@ -76,9 +81,9 @@ TOR="${TOR_BINARY} ${QUIETLY} --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort # copying them into different keys directories in order to simulate # different kinds of configuration problems/issues. -# Step 1: Start Tor with --list-fingerprint. Make sure everything is there. +# Step 1: Start Tor with --list-fingerprint --quiet. Make sure everything is there. mkdir "${DATA_DIR}/orig" -${TOR} --DataDirectory "${DATA_DIR}/orig" --list-fingerprint > /dev/null +${TOR} --DataDirectory "${DATA_DIR}/orig" --list-fingerprint ${SILENTLY} > /dev/null check_dir "${DATA_DIR}/orig/keys" check_file "${DATA_DIR}/orig/keys/ed25519_master_id_public_key" @@ -109,7 +114,7 @@ check_file "${DATA_DIR}/encrypted/keys/ed25519_signing_cert" check_file "${DATA_DIR}/encrypted/keys/ed25519_signing_secret_key" -echo "=== Starting tests." +echo "=== Starting keygen tests." # # The "case X" numbers below come from s7r's email on @@ -124,7 +129,7 @@ ME="${DATA_DIR}/case2a" SRC="${DATA_DIR}/orig" mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout" && die "Somehow succeeded when missing secret key, certs" || true +${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout" && die "Somehow succeeded when missing secret key, certs: `cat ${ME}/stdout`" || true check_files_eq "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/ed25519_master_id_public_key" grep "We needed to load a secret key.*but couldn't find it" "${ME}/stdout" >/dev/null || die "Tor didn't declare that it was missing a secret key" @@ -162,7 +167,7 @@ SRC="${DATA_DIR}/orig" mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_master_id_"* "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint >/dev/null || die "Tor failed when starting with only master key" +${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Tor failed when starting with only master key" check_files_eq "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/ed25519_master_id_public_key" check_files_eq "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/ed25519_master_id_secret_key" check_file "${ME}/keys/ed25519_signing_cert" @@ -220,11 +225,11 @@ SRC="${DATA_DIR}/orig" mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/fp1" || die "Tor wouldn't start with only unencrypted secret key" +${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} > "${ME}/fp1" || die "Tor wouldn't start with only unencrypted secret key" check_file "${ME}/keys/ed25519_master_id_public_key" check_file "${ME}/keys/ed25519_signing_cert" check_file "${ME}/keys/ed25519_signing_secret_key" -${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/fp2" || die "Tor wouldn't start again after starting once with only unencrypted secret key." +${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} > "${ME}/fp2" || die "Tor wouldn't start again after starting once with only unencrypted secret key." check_files_eq "${ME}/fp1" "${ME}/fp2" @@ -284,7 +289,7 @@ cp "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint >/dev/null || die "Failed when starting with missing public key" +${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with missing public key" check_keys_eq ed25519_master_id_secret_key check_keys_eq ed25519_master_id_public_key check_keys_eq ed25519_signing_secret_key @@ -306,7 +311,7 @@ cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint >/dev/null || die "Failed when starting with offline secret key" +${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with offline secret key" check_no_file "${ME}/keys/ed25519_master_id_secret_key" check_keys_eq ed25519_master_id_public_key check_keys_eq ed25519_signing_secret_key @@ -327,7 +332,7 @@ mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint >/dev/null || die "Failed when starting with only signing material" +${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with only signing material" check_no_file "${ME}/keys/ed25519_master_id_secret_key" check_file "${ME}/keys/ed25519_master_id_public_key" check_keys_eq ed25519_signing_secret_key diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 33f90c7da5..37c36fed99 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -49,7 +49,7 @@ test_policy_summary_helper(const char *policy_str, r = policies_parse_exit_policy(&line, &policy, EXIT_POLICY_IPV6_ENABLED | - EXIT_POLICY_ADD_DEFAULT ,0); + EXIT_POLICY_ADD_DEFAULT, 0, NULL, 0); tt_int_op(r,OP_EQ, 0); summary = policy_summarize(policy, AF_INET); @@ -77,18 +77,21 @@ test_policies_general(void *arg) int i; smartlist_t *policy = NULL, *policy2 = NULL, *policy3 = NULL, *policy4 = NULL, *policy5 = NULL, *policy6 = NULL, - *policy7 = NULL; + *policy7 = NULL, *policy8 = NULL, *policy9 = NULL, + *policy10 = NULL, *policy11 = NULL, *policy12 = NULL; addr_policy_t *p; tor_addr_t tar; config_line_t line; smartlist_t *sm = NULL; char *policy_str = NULL; short_policy_t *short_parsed = NULL; + int malformed_list = -1; (void)arg; policy = smartlist_new(); - p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); + p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*", -1, + &malformed_list); tt_assert(p != NULL); tt_int_op(ADDR_POLICY_REJECT,OP_EQ, p->policy_type); tor_addr_from_ipv4h(&tar, 0xc0a80000u); @@ -112,68 +115,122 @@ test_policies_general(void *arg) tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy2, EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_REJECT_PRIVATE | - EXIT_POLICY_ADD_DEFAULT, 0)); + EXIT_POLICY_ADD_DEFAULT, 0, + NULL, 0)); tt_assert(policy2); + tor_addr_parse(&tar, "[2000::1234]"); + tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy12, + EXIT_POLICY_IPV6_ENABLED | + EXIT_POLICY_REJECT_PRIVATE | + EXIT_POLICY_ADD_DEFAULT, + 0x0306090cu, &tar, 1)); + + tt_assert(policy12); + policy3 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("reject *:*",-1); + p = router_parse_addr_policy_item_from_string("reject *:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy3, p); - p = router_parse_addr_policy_item_from_string("accept *:*",-1); + p = router_parse_addr_policy_item_from_string("accept *:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy3, p); policy4 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept *:443",-1); + p = router_parse_addr_policy_item_from_string("accept *:443", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy4, p); - p = router_parse_addr_policy_item_from_string("accept *:443",-1); + p = router_parse_addr_policy_item_from_string("accept *:443", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy4, p); policy5 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1); + p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1); + p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1); + p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); + p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*", + -1, &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1); + p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1); + p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1); + p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1); + p = router_parse_addr_policy_item_from_string("reject *:1-65534", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject *:65535",-1); + p = router_parse_addr_policy_item_from_string("reject *:65535", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1); + p = router_parse_addr_policy_item_from_string("accept *:1-65535", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy5, p); policy6 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1); + p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy6, p); policy7 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1); + p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*", -1, + &malformed_list); tt_assert(p != NULL); smartlist_add(policy7, p); + tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy8, + EXIT_POLICY_IPV6_ENABLED | + EXIT_POLICY_REJECT_PRIVATE | + EXIT_POLICY_ADD_DEFAULT, 0, + NULL, 0)); + + tt_assert(policy8); + + tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy9, + EXIT_POLICY_REJECT_PRIVATE | + EXIT_POLICY_ADD_DEFAULT, 0, + NULL, 0)); + + tt_assert(policy9); + + /* accept6 * and reject6 * produce IPv6 wildcards only */ + policy10 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("accept6 *:*", -1, + &malformed_list); + tt_assert(p != NULL); + smartlist_add(policy10, p); + + policy11 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("reject6 *:*", -1, + &malformed_list); + tt_assert(p != NULL); + smartlist_add(policy11, p); + tt_assert(!exit_policy_is_general_exit(policy)); tt_assert(exit_policy_is_general_exit(policy2)); tt_assert(!exit_policy_is_general_exit(NULL)); @@ -182,6 +239,10 @@ test_policies_general(void *arg) tt_assert(!exit_policy_is_general_exit(policy5)); tt_assert(!exit_policy_is_general_exit(policy6)); tt_assert(!exit_policy_is_general_exit(policy7)); + tt_assert(exit_policy_is_general_exit(policy8)); + tt_assert(exit_policy_is_general_exit(policy9)); + tt_assert(!exit_policy_is_general_exit(policy10)); + tt_assert(!exit_policy_is_general_exit(policy11)); tt_assert(cmp_addr_policies(policy, policy2)); tt_assert(cmp_addr_policies(policy, NULL)); @@ -190,7 +251,12 @@ test_policies_general(void *arg) tt_assert(!policy_is_reject_star(policy2, AF_INET)); tt_assert(policy_is_reject_star(policy, AF_INET)); + tt_assert(policy_is_reject_star(policy10, AF_INET)); + tt_assert(!policy_is_reject_star(policy10, AF_INET6)); + tt_assert(policy_is_reject_star(policy11, AF_INET)); + tt_assert(policy_is_reject_star(policy11, AF_INET6)); tt_assert(policy_is_reject_star(NULL, AF_INET)); + tt_assert(policy_is_reject_star(NULL, AF_INET6)); addr_policy_list_free(policy); policy = NULL; @@ -202,7 +268,8 @@ test_policies_general(void *arg) line.next = NULL; tt_int_op(0, OP_EQ, policies_parse_exit_policy(&line,&policy, EXIT_POLICY_IPV6_ENABLED | - EXIT_POLICY_ADD_DEFAULT,0)); + EXIT_POLICY_ADD_DEFAULT, 0, + NULL, 0)); tt_assert(policy); //test_streq(policy->string, "accept *:80"); @@ -297,6 +364,68 @@ test_policies_general(void *arg) TT_BAD_SHORT_POLICY("accept 1-,3"); TT_BAD_SHORT_POLICY("accept 1-,3"); + /* Make sure that IPv4 addresses are ignored in accept6/reject6 lines. */ + p = router_parse_addr_policy_item_from_string("accept6 1.2.3.4:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(!malformed_list); + + p = router_parse_addr_policy_item_from_string("reject6 2.4.6.0/24:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(!malformed_list); + + p = router_parse_addr_policy_item_from_string("accept6 *4:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(!malformed_list); + + /* Make sure malformed policies are detected as such. */ + p = router_parse_addr_policy_item_from_string("bad_token *4:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("accept6 **:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("accept */15:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("reject6 */:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("accept 127.0.0.1/33:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("accept6 [::1]/129:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("reject 8.8.8.8/-1:*", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("reject 8.8.4.4:10-5", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + + p = router_parse_addr_policy_item_from_string("reject 1.2.3.4:-1", -1, + &malformed_list); + tt_assert(p == NULL); + tt_assert(malformed_list); + /* Test a too-long policy. */ { int i; @@ -347,6 +476,11 @@ test_policies_general(void *arg) addr_policy_list_free(policy5); addr_policy_list_free(policy6); addr_policy_list_free(policy7); + addr_policy_list_free(policy8); + addr_policy_list_free(policy9); + addr_policy_list_free(policy10); + addr_policy_list_free(policy11); + addr_policy_list_free(policy12); tor_free(policy_str); if (sm) { SMARTLIST_FOREACH(sm, char *, s, tor_free(s)); @@ -360,6 +494,7 @@ test_dump_exit_policy_to_string(void *arg) { char *ep; addr_policy_t *policy_entry; + int malformed_list = -1; routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t)); @@ -376,7 +511,8 @@ test_dump_exit_policy_to_string(void *arg) ri->exit_policy = smartlist_new(); ri->policy_is_reject_star = 0; - policy_entry = router_parse_addr_policy_item_from_string("accept *:*",-1); + policy_entry = router_parse_addr_policy_item_from_string("accept *:*", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); @@ -386,7 +522,8 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); - policy_entry = router_parse_addr_policy_item_from_string("reject *:25",-1); + policy_entry = router_parse_addr_policy_item_from_string("reject *:25", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); @@ -397,7 +534,8 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); policy_entry = - router_parse_addr_policy_item_from_string("reject 8.8.8.8:*",-1); + router_parse_addr_policy_item_from_string("reject 8.8.8.8:*", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); @@ -407,7 +545,8 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); policy_entry = - router_parse_addr_policy_item_from_string("reject6 [FC00::]/7:*",-1); + router_parse_addr_policy_item_from_string("reject6 [FC00::]/7:*", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); @@ -418,7 +557,8 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); policy_entry = - router_parse_addr_policy_item_from_string("accept6 [c000::]/3:*",-1); + router_parse_addr_policy_item_from_string("accept6 [c000::]/3:*", -1, + &malformed_list); smartlist_add(ri->exit_policy,policy_entry); diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c index 9bd0c125c3..90dfb28c6b 100644 --- a/src/test/test_routerset.c +++ b/src/test/test_routerset.c @@ -430,7 +430,7 @@ NS(test_main)(void *arg) */ NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string, - (const char *s, int assume_action)); + (const char *s, int assume_action, int *malformed_list)); addr_policy_t *NS(mock_addr_policy); @@ -457,10 +457,13 @@ NS(test_main)(void *arg) } addr_policy_t * -NS(router_parse_addr_policy_item_from_string)(const char *s, int assume_action) +NS(router_parse_addr_policy_item_from_string)(const char *s, + int assume_action, + int *malformed_list) { (void)s; (void)assume_action; + (void)malformed_list; CALLED(router_parse_addr_policy_item_from_string)++; return NS(mock_addr_policy); |