From cd1de99468aa4d7b48c9f3bcb7c7d4fb5b3bfe9a Mon Sep 17 00:00:00 2001 From: teor Date: Sun, 2 Jun 2019 17:46:58 +1000 Subject: [PATCH 01/12] resolve: consistently parse IP addresses in square brackets When parsing addreses via Tor's internal DNS lookup API: * reject IPv4 addresses in square brackets (with or without a port), * accept IPv6 addresses in square brackets (with or without a port), and * accept IPv6 addresses without square brackets, as long as they have no port. This change completes the work started in 23082, making address parsing consistent between tor's internal DNS lookup and address parsing APIs. Fixes bug 30721; bugfix on 0.2.1.5-alpha. --- changes/bug30721 | 6 ++++ src/lib/net/address.c | 31 +++++++++++++++--- src/lib/net/resolve.c | 75 ++++++++++++++++++++++--------------------- 3 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 changes/bug30721 diff --git a/changes/bug30721 b/changes/bug30721 new file mode 100644 index 0000000000..5e03653005 --- /dev/null +++ b/changes/bug30721 @@ -0,0 +1,6 @@ + o Minor bugfixes (networking): + - When parsing addreses via Tor's internal DNS lookup API, reject IPv4 + addresses in square brackets, and accept IPv6 addresses in square + brackets. This change completes the work started in 23082, making + address parsing consistent between tor's internal DNS lookup and address + parsing APIs. Fixes bug 30721; bugfix on 0.2.1.5-alpha. diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 546af800a9..4989e4ab2b 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -373,7 +373,8 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) * * If accept_regular is set and the address is in neither recognized * reverse lookup hostname format, try parsing the address as a regular - * IPv4 or IPv6 address too. + * IPv4 or IPv6 address too. This mode will accept IPv6 addresses with or + * without square brackets. */ int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, @@ -1204,6 +1205,10 @@ tor_addr_parse(tor_addr_t *addr, const char *src) tor_assert(addr && src); + /* Clear the address before starting, to avoid returning uninitialised data. + */ + memset(addr, 0, sizeof(tor_addr_t)); + size_t len = strlen(src); if (len && src[0] == '[' && src[len - 1] == ']') { @@ -1718,6 +1723,11 @@ get_interface_address6_list,(int severity, * form "ip" or "ip:0". Otherwise, accept those forms, and set * *port_out to default_port. * + * This function accepts: + * - IPv6 address and port, when the IPv6 address is in square brackets, + * - IPv6 address with square brackets, + * - IPv6 address without square brackets. + * * Return 0 on success, -1 on failure. */ int tor_addr_port_parse(int severity, const char *addrport, @@ -1755,9 +1765,17 @@ tor_addr_port_parse(int severity, const char *addrport, } /** Given an address of the form "host[:port]", try to divide it into its host - * and port portions, setting *address_out to a newly allocated string - * holding the address portion and *port_out to the port (or 0 if no - * port is given). Return 0 on success, -1 on failure. */ + * and port portions. + * + * Like tor_addr_port_parse(), this function accepts: + * - IPv6 address and port, when the IPv6 address is in square brackets, + * - IPv6 address with square brackets, + * - IPv6 address without square brackets. + * + * Sets *address_out to a newly allocated string holding the address + * portion, and *port_out to the port (or 0 if no port is given). + * + * Return 0 on success, -1 on failure. */ int tor_addr_port_split(int severity, const char *addrport, char **address_out, uint16_t *port_out) @@ -1766,8 +1784,11 @@ tor_addr_port_split(int severity, const char *addrport, tor_assert(addrport); tor_assert(address_out); tor_assert(port_out); + /* We need to check for IPv6 manually because the logic below doesn't - * do a good job on IPv6 addresses that lack a port. */ + * do a good job on IPv6 addresses that lack a port. + * If an IPv6 address without square brackets is ambiguous, it gets parsed + * here as an address, rather than address:port. */ if (tor_addr_parse(&a_tmp, addrport) == AF_INET6) { *port_out = 0; *address_out = tor_strdup(addrport); diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index 49c263faa2..71c033fe7a 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -35,6 +35,8 @@ * *addr to the proper IP address, in host byte order. Returns 0 * on success, -1 on failure; 1 on transient failure. * + * This function only accepts IPv4 addresses. + * * (This function exists because standard windows gethostbyname * doesn't treat raw IP addresses properly.) */ @@ -62,6 +64,9 @@ tor_lookup_hostname,(const char *name, uint32_t *addr)) * preferred family, though another one may be returned if only one * family is implemented for this address. * + * Like tor_addr_parse(), this function accepts IPv6 addresses with or without + * square brackets. + * * Return 0 on success, -1 on failure; 1 on transient failure. */ MOCK_IMPL(int, @@ -70,26 +75,39 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) /* Perhaps eventually this should be replaced by a tor_getaddrinfo or * something. */ - struct in_addr iaddr; - struct in6_addr iaddr6; + int parsed_family = 0; + tor_assert(name); tor_assert(addr); tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC); + + /* Clear address before starting, to avoid returning uninitialised data */ + memset(addr, 0, sizeof(tor_addr_t)); + if (!*name) { /* Empty address is an error. */ return -1; - } else if (tor_inet_pton(AF_INET, name, &iaddr)) { + } + + /* Is it an IP address? */ + parsed_family = tor_addr_parse(addr, name); + + if (parsed_family == AF_INET) { /* It's an IPv4 IP. */ - if (family == AF_INET6) + if (family == AF_INET6) { + memset(addr, 0, sizeof(tor_addr_t)); return -1; - tor_addr_from_in(addr, &iaddr); + } return 0; - } else if (tor_inet_pton(AF_INET6, name, &iaddr6)) { - if (family == AF_INET) + } else if (parsed_family == AF_INET6) { + if (family == AF_INET) { + memset(addr, 0, sizeof(tor_addr_t)); return -1; - tor_addr_from_in6(addr, &iaddr6); + } return 0; } else { + /* Clear the address after a failed tor_addr_parse(). */ + memset(addr, 0, sizeof(tor_addr_t)); #ifdef HAVE_GETADDRINFO int err; struct addrinfo *res=NULL, *res_p; @@ -179,52 +197,35 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) /** Parse an address or address-port combination from s, resolve the * address as needed, and put the result in addr_out and (optionally) - * port_out. Return 0 on success, negative on failure. */ + * port_out. + * + * Like tor_addr_port_parse(), this function accepts: + * - IPv6 address and port, when the IPv6 address is in square brackets, + * - IPv6 address with square brackets, + * - IPv6 address without square brackets. + * + * Return 0 on success, negative on failure. */ int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) { - const char *port; tor_addr_t addr; uint16_t portval; char *tmp = NULL; + int rv = 0; tor_assert(s); tor_assert(addr_out); s = eat_whitespace(s); - if (*s == '[') { - port = strstr(s, "]"); - if (!port) - goto err; - tmp = tor_strndup(s+1, port-(s+1)); - port = port+1; - if (*port == ':') - port++; - else - port = NULL; - } else { - port = strchr(s, ':'); - if (port) - tmp = tor_strndup(s, port-s); - else - tmp = tor_strdup(s); - if (port) - ++port; - } + rv = tor_addr_port_split(LOG_WARN, s, &tmp, &portval); + if (rv < 0) + goto err; if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0) goto err; tor_free(tmp); - if (port) { - portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL); - if (!portval) - goto err; - } else { - portval = 0; - } - if (port_out) *port_out = portval; tor_addr_copy(addr_out, &addr); From 29cf64c8389fd4de1e4419cb8ac30b2ca582ba5e Mon Sep 17 00:00:00 2001 From: teor Date: Sun, 2 Jun 2019 18:20:25 +1000 Subject: [PATCH 02/12] resolve: refactor address family logic in tor_addr_lookup() Cleanup after 30721. --- src/lib/net/resolve.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index 71c033fe7a..1b68a0b33a 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -81,30 +81,24 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) tor_assert(addr); tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC); - /* Clear address before starting, to avoid returning uninitialised data */ - memset(addr, 0, sizeof(tor_addr_t)); - if (!*name) { /* Empty address is an error. */ + memset(addr, 0, sizeof(tor_addr_t)); return -1; } /* Is it an IP address? */ parsed_family = tor_addr_parse(addr, name); - if (parsed_family == AF_INET) { - /* It's an IPv4 IP. */ - if (family == AF_INET6) { + if (parsed_family >= 0) { + /* If the IP address family matches, or was unspecified */ + if (parsed_family == family || family == AF_UNSPEC) { + return 0; + } else { + /* Clear the address before returning an error. */ memset(addr, 0, sizeof(tor_addr_t)); return -1; } - return 0; - } else if (parsed_family == AF_INET6) { - if (family == AF_INET) { - memset(addr, 0, sizeof(tor_addr_t)); - return -1; - } - return 0; } else { /* Clear the address after a failed tor_addr_parse(). */ memset(addr, 0, sizeof(tor_addr_t)); From fb93646c1c2e97a978045019403d9cfb43f55cbc Mon Sep 17 00:00:00 2001 From: teor Date: Sun, 2 Jun 2019 18:42:01 +1000 Subject: [PATCH 03/12] resolve: split sub-functions out of tor_addr_lookup() And remove the practracker exception for tor_addr_lookup(). Cleanup after 30721. --- scripts/maint/practracker/exceptions.txt | 1 - src/lib/net/resolve.c | 221 ++++++++++++++--------- 2 files changed, 134 insertions(+), 88 deletions(-) diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 3a32e97beb..4c1ae1ba51 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -272,7 +272,6 @@ problem function-size /src/lib/math/prob_distr.c:sample_uniform_interval() 145 problem function-size /src/lib/net/address.c:tor_addr_parse_mask_ports() 198 problem function-size /src/lib/net/address.c:tor_addr_compare_masked() 111 problem function-size /src/lib/net/inaddr.c:tor_inet_pton() 107 -problem function-size /src/lib/net/resolve.c:tor_addr_lookup() 110 problem function-size /src/lib/net/socketpair.c:tor_ersatz_socketpair() 102 problem function-size /src/lib/osinfo/uname.c:get_uname() 116 problem function-size /src/lib/process/process_unix.c:process_unix_exec() 220 diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index 1b68a0b33a..a70fb0a823 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -58,6 +58,116 @@ tor_lookup_hostname,(const char *name, uint32_t *addr)) return -1; } +#ifdef HAVE_GETADDRINFO + +/* Host lookup helper for tor_addr_lookup(), when getaddrinfo() is + * available on this system. + * + * See tor_addr_lookup() for details. + */ +static int +tor_addr_lookup_host_getaddrinfo(const char *name, + uint16_t family, + tor_addr_t *addr) +{ + int err; + struct addrinfo *res=NULL, *res_p; + struct addrinfo *best=NULL; + struct addrinfo hints; + int result = -1; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + err = tor_getaddrinfo(name, NULL, &hints, &res); + /* The check for 'res' here shouldn't be necessary, but it makes static + * analysis tools happy. */ + if (!err && res) { + best = NULL; + for (res_p = res; res_p; res_p = res_p->ai_next) { + if (family == AF_UNSPEC) { + if (res_p->ai_family == AF_INET) { + best = res_p; + break; + } else if (res_p->ai_family == AF_INET6 && !best) { + best = res_p; + } + } else if (family == res_p->ai_family) { + best = res_p; + break; + } + } + if (!best) + best = res; + if (best->ai_family == AF_INET) { + tor_addr_from_in(addr, + &((struct sockaddr_in*)best->ai_addr)->sin_addr); + result = 0; + } else if (best->ai_family == AF_INET6) { + tor_addr_from_in6(addr, + &((struct sockaddr_in6*)best->ai_addr)->sin6_addr); + result = 0; + } + tor_freeaddrinfo(res); + return result; + } + return (err == EAI_AGAIN) ? 1 : -1; +} + +#else /* !(defined(HAVE_GETADDRINFO)) */ + +/* Host lookup helper for tor_addr_lookup(), which calls getaddrinfo(). + * Used when gethostbyname() is not available on this system. + * + * See tor_addr_lookup() for details. + */ +static int +tor_addr_lookup_host_gethostbyname(const char *name, + tor_addr_t *addr) +{ + struct hostent *ent; + int err; +#ifdef HAVE_GETHOSTBYNAME_R_6_ARG + char buf[2048]; + struct hostent hostent; + int r; + r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err); +#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) + char buf[2048]; + struct hostent hostent; + ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err); +#elif defined(HAVE_GETHOSTBYNAME_R_3_ARG) + struct hostent_data data; + struct hostent hent; + memset(&data, 0, sizeof(data)); + err = gethostbyname_r(name, &hent, &data); + ent = err ? NULL : &hent; +#else + ent = gethostbyname(name); +#ifdef _WIN32 + err = WSAGetLastError(); +#else + err = h_errno; +#endif /* defined(_WIN32) */ +#endif /* defined(HAVE_GETHOSTBYNAME_R_6_ARG) || ... */ + if (ent) { + if (ent->h_addrtype == AF_INET) { + tor_addr_from_in(addr, (struct in_addr*) ent->h_addr); + } else if (ent->h_addrtype == AF_INET6) { + tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr); + } else { + tor_assert(0); // LCOV_EXCL_LINE: gethostbyname() returned bizarre type + } + return 0; + } +#ifdef _WIN32 + return (err == WSATRY_AGAIN) ? 1 : -1; +#else + return (err == TRY_AGAIN) ? 1 : -1; +#endif +} + +#endif /* defined(HAVE_GETADDRINFO) */ + /** Similar behavior to Unix gethostbyname: resolve name, and set * *addr to the proper IP address and family. The family * argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a @@ -76,6 +186,7 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) * something. */ int parsed_family = 0; + int result = -1; tor_assert(name); tor_assert(addr); @@ -83,8 +194,7 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) if (!*name) { /* Empty address is an error. */ - memset(addr, 0, sizeof(tor_addr_t)); - return -1; + goto permfail; } /* Is it an IP address? */ @@ -93,100 +203,37 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) if (parsed_family >= 0) { /* If the IP address family matches, or was unspecified */ if (parsed_family == family || family == AF_UNSPEC) { - return 0; + goto success; } else { - /* Clear the address before returning an error. */ - memset(addr, 0, sizeof(tor_addr_t)); - return -1; + goto permfail; } } else { /* Clear the address after a failed tor_addr_parse(). */ memset(addr, 0, sizeof(tor_addr_t)); #ifdef HAVE_GETADDRINFO - int err; - struct addrinfo *res=NULL, *res_p; - struct addrinfo *best=NULL; - struct addrinfo hints; - int result = -1; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - err = tor_getaddrinfo(name, NULL, &hints, &res); - /* The check for 'res' here shouldn't be necessary, but it makes static - * analysis tools happy. */ - if (!err && res) { - best = NULL; - for (res_p = res; res_p; res_p = res_p->ai_next) { - if (family == AF_UNSPEC) { - if (res_p->ai_family == AF_INET) { - best = res_p; - break; - } else if (res_p->ai_family == AF_INET6 && !best) { - best = res_p; - } - } else if (family == res_p->ai_family) { - best = res_p; - break; - } - } - if (!best) - best = res; - if (best->ai_family == AF_INET) { - tor_addr_from_in(addr, - &((struct sockaddr_in*)best->ai_addr)->sin_addr); - result = 0; - } else if (best->ai_family == AF_INET6) { - tor_addr_from_in6(addr, - &((struct sockaddr_in6*)best->ai_addr)->sin6_addr); - result = 0; - } - tor_freeaddrinfo(res); - return result; - } - return (err == EAI_AGAIN) ? 1 : -1; + result = tor_addr_lookup_host_getaddrinfo(name, family, addr); + goto done; #else /* !(defined(HAVE_GETADDRINFO)) */ - struct hostent *ent; - int err; -#ifdef HAVE_GETHOSTBYNAME_R_6_ARG - char buf[2048]; - struct hostent hostent; - int r; - r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err); -#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) - char buf[2048]; - struct hostent hostent; - ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err); -#elif defined(HAVE_GETHOSTBYNAME_R_3_ARG) - struct hostent_data data; - struct hostent hent; - memset(&data, 0, sizeof(data)); - err = gethostbyname_r(name, &hent, &data); - ent = err ? NULL : &hent; -#else - ent = gethostbyname(name); -#ifdef _WIN32 - err = WSAGetLastError(); -#else - err = h_errno; -#endif -#endif /* defined(HAVE_GETHOSTBYNAME_R_6_ARG) || ... */ - if (ent) { - if (ent->h_addrtype == AF_INET) { - tor_addr_from_in(addr, (struct in_addr*) ent->h_addr); - } else if (ent->h_addrtype == AF_INET6) { - tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr); - } else { - tor_assert(0); // LCOV_EXCL_LINE: gethostbyname() returned bizarre type - } - return 0; - } -#ifdef _WIN32 - return (err == WSATRY_AGAIN) ? 1 : -1; -#else - return (err == TRY_AGAIN) ? 1 : -1; -#endif + result = tor_addr_lookup_host_gethostbyname(name, addr); + goto done; #endif /* defined(HAVE_GETADDRINFO) */ } + + /* If we weren't successful, and haven't already set the result, + * assume it's a permanent failure */ + permfail: + result = -1; + goto done; + success: + result = 0; + + /* We have set the result, now it's time to clean up */ + done: + if (result) { + /* Clear the address on error */ + memset(addr, 0, sizeof(tor_addr_t)); + } + return result; } /** Parse an address or address-port combination from s, resolve the From 308d3002130cfb5b9ad2100dab25b0c4c83162f6 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 13 Jun 2019 21:14:36 +1000 Subject: [PATCH 04/12] address/resolve: try harder to avoid returning uninitialised data Cleanup after 30721. --- src/lib/net/address.c | 10 ++++++++-- src/lib/net/resolve.c | 11 ++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 4989e4ab2b..75322ad886 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -1760,6 +1760,13 @@ tor_addr_port_parse(int severity, const char *addrport, retval = 0; done: + /* Clear the address and port on error, to avoid returning uninitialised or + * partly parsed data. + */ + if (retval == -1) { + memset(address_out, 0, sizeof(tor_addr_t)); + *port_out = 0; + } tor_free(addr_tmp); return retval; } @@ -1828,8 +1835,7 @@ tor_addr_port_split(int severity, const char *addrport, tor_free(address_); } - if (port_out) - *port_out = ok ? ((uint16_t) port_) : 0; + *port_out = ok ? ((uint16_t) port_) : 0; return ok ? 0 : -1; } diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index a70fb0a823..9555720883 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -47,6 +47,11 @@ tor_lookup_hostname,(const char *name, uint32_t *addr)) tor_addr_t myaddr; int ret; + if (BUG(!addr)) + return -1; + + *addr = 0; + if ((ret = tor_addr_lookup(name, AF_INET, &myaddr))) return ret; @@ -250,7 +255,7 @@ int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) { tor_addr_t addr; - uint16_t portval; + uint16_t portval = 0; char *tmp = NULL; int rv = 0; @@ -273,6 +278,10 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) return 0; err: + /* Clear the address and port on error */ + memset(addr_out, 0, sizeof(tor_addr_t)); + if (port_out) + *port_out = 0; tor_free(tmp); return -1; } From adb8538e7b6a7a2531233797990f6d11be86a718 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 13 Jun 2019 21:21:19 +1000 Subject: [PATCH 05/12] address/resolve: Require square brackets on IPv6 address:ports When parsing addreses via Tor's internal address:port parsing and DNS lookup APIs, require IPv6 addresses with ports to have square brackets. But allow IPv6 addresses without ports, whether or not they have square brackets. Fixes bug 30721; bugfix on 0.2.1.5-alpha. --- changes/bug30721 | 6 +++- src/lib/net/address.c | 77 ++++++++++++++++++++++++++++++------------- src/lib/net/resolve.c | 40 ++++++++++++++++++++-- 3 files changed, 96 insertions(+), 27 deletions(-) diff --git a/changes/bug30721 b/changes/bug30721 index 5e03653005..5ea4a14625 100644 --- a/changes/bug30721 +++ b/changes/bug30721 @@ -1,6 +1,10 @@ - o Minor bugfixes (networking): + o Minor bugfixes (networking, IP addresses): - When parsing addreses via Tor's internal DNS lookup API, reject IPv4 addresses in square brackets, and accept IPv6 addresses in square brackets. This change completes the work started in 23082, making address parsing consistent between tor's internal DNS lookup and address parsing APIs. Fixes bug 30721; bugfix on 0.2.1.5-alpha. + - When parsing addreses via Tor's internal address:port parsing and + DNS lookup APIs, require IPv6 addresses with ports to have square + brackets. But allow IPv6 addresses without ports, whether or not they + have square brackets. Fixes bug 30721; bugfix on 0.2.1.5-alpha. diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 75322ad886..0a2c84caf2 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -1188,27 +1188,28 @@ fmt_addr32(uint32_t addr) } /** Convert the string in src to a tor_addr_t addr. The string - * may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by - * square brackets. + * may be an IPv4 address, or an IPv6 address surrounded by square brackets. * - * Return an address family on success, or -1 if an invalid address string is - * provided. */ -int -tor_addr_parse(tor_addr_t *addr, const char *src) + * If allow_ipv6_without_brackets is true, also allow IPv6 addresses + * without brackets. + * + * Always rejects IPv4 addresses with brackets. + * + * Returns an address family on success, or -1 if an invalid address string is + * provided. */ +static int +tor_addr_parse_impl(tor_addr_t *addr, const char *src, + bool allow_ipv6_without_brackets) { /* Holds substring of IPv6 address after removing square brackets */ char *tmp = NULL; - int result; + int result = -1; struct in_addr in_tmp; struct in6_addr in6_tmp; int brackets_detected = 0; tor_assert(addr && src); - /* Clear the address before starting, to avoid returning uninitialised data. - */ - memset(addr, 0, sizeof(tor_addr_t)); - size_t len = strlen(src); if (len && src[0] == '[' && src[len - 1] == ']') { @@ -1216,21 +1217,46 @@ tor_addr_parse(tor_addr_t *addr, const char *src) src = tmp = tor_strndup(src+1, strlen(src)-2); } - if (tor_inet_pton(AF_INET6, src, &in6_tmp) > 0) { - result = AF_INET6; - tor_addr_from_in6(addr, &in6_tmp); - } else if (!brackets_detected && - tor_inet_pton(AF_INET, src, &in_tmp) > 0) { - result = AF_INET; - tor_addr_from_in(addr, &in_tmp); - } else { - result = -1; + /* Try to parse an IPv6 address if it has brackets, or if IPv6 addresses + * without brackets are allowed */ + if (brackets_detected || allow_ipv6_without_brackets) { + if (tor_inet_pton(AF_INET6, src, &in6_tmp) > 0) { + result = AF_INET6; + tor_addr_from_in6(addr, &in6_tmp); + } + } + + /* Try to parse an IPv4 address without brackets */ + if (!brackets_detected) { + if (tor_inet_pton(AF_INET, src, &in_tmp) > 0) { + result = AF_INET; + tor_addr_from_in(addr, &in_tmp); + } + } + + /* Clear the address on error, to avoid returning uninitialised or partly + * parsed data. + */ + if (result == -1) { + memset(addr, 0, sizeof(tor_addr_t)); } tor_free(tmp); return result; } +/** Convert the string in src to a tor_addr_t addr. The string + * may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by + * square brackets. + * + * Returns an address family on success, or -1 if an invalid address string is + * provided. */ +int +tor_addr_parse(tor_addr_t *addr, const char *src) +{ + return tor_addr_parse_impl(addr, src, 1); +} + #ifdef HAVE_IFADDRS_TO_SMARTLIST /* * Convert a linked list consisting of ifaddrs structures @@ -1737,6 +1763,7 @@ tor_addr_port_parse(int severity, const char *addrport, int retval = -1; int r; char *addr_tmp = NULL; + bool has_port; tor_assert(addrport); tor_assert(address_out); @@ -1746,15 +1773,19 @@ tor_addr_port_parse(int severity, const char *addrport, if (r < 0) goto done; - if (!*port_out) { + has_port = !! *port_out; + /* If there's no port, use the default port, or fail if there is no default + */ + if (!has_port) { if (default_port >= 0) *port_out = default_port; else goto done; } - /* make sure that address_out is an IP address */ - if (tor_addr_parse(address_out, addr_tmp) < 0) + /* Make sure that address_out is an IP address. + * If there is no port in addrport, allow IPv6 addresses without brackets. */ + if (tor_addr_parse_impl(address_out, addr_tmp, !has_port) < 0) goto done; retval = 0; diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index 9555720883..1097e36bd8 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -258,32 +258,66 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) uint16_t portval = 0; char *tmp = NULL; int rv = 0; + int result; tor_assert(s); tor_assert(addr_out); s = eat_whitespace(s); + /* Try parsing s as an address:port first, so we don't have to duplicate + * the logic that rejects IPv6:Port with no square brackets. */ + rv = tor_addr_port_parse(LOG_WARN, s, &addr, &portval, 0); + /* That was easy, no DNS required. */ + if (rv == 0) + goto success; + + /* Now let's check for malformed IPv6 addresses and ports: + * tor_addr_port_parse() requires squared brackes if there is a port, + * and we want tor_addr_port_lookup() to have the same requirement. + * But we strip the port using tor_addr_port_split(), so tor_addr_lookup() + * only sees the address, and will accept it without square brackets. */ + int family = tor_addr_parse(&addr, s); + /* If tor_addr_parse() succeeds where tor_addr_port_parse() failed, we need + * to reject this address as malformed. */ + if (family >= 0) { + /* Double-check it's an IPv6 address. If not, we have a parsing bug. + */ + tor_assertf_nonfatal(family == AF_INET6, + "Wrong family: %d (should be IPv6: %d) which " + "failed IP:port parsing, but passed IP parsing. " + "input string: '%s'; parsed address: '%s'.", + family, AF_INET6, s, fmt_addr(&addr)); + goto err; + } + + /* Now we have a hostname. Let's split off the port, if any. */ rv = tor_addr_port_split(LOG_WARN, s, &tmp, &portval); if (rv < 0) goto err; + /* And feed the hostname to the lookup function. */ if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0) goto err; - tor_free(tmp); + success: if (port_out) *port_out = portval; tor_addr_copy(addr_out, &addr); + result = 0; + goto done; - return 0; err: /* Clear the address and port on error */ memset(addr_out, 0, sizeof(tor_addr_t)); if (port_out) *port_out = 0; + result = -1; + + /* We have set the result, now it's time to clean up */ + done: tor_free(tmp); - return -1; + return result; } #ifdef USE_SANDBOX_GETADDRINFO From 1d3d6bf6b18ff7d3462d48d33d3e982f063f35d6 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 13 Jun 2019 21:22:27 +1000 Subject: [PATCH 06/12] test/addr: Add unit tests for the fixes in 30721 --- src/test/test_addr.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 05d8bf6c7b..a961a46854 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -788,6 +788,10 @@ test_addr_parse(void *arg) r= tor_addr_parse(&addr, "11:22:33:44:55:66:77:88:1.2.3.4"); tt_int_op(r,OP_EQ, -1); + /* IPv6 address with port and no brackets */ + r= tor_addr_parse(&addr, "11:22::33:44:12345"); + tt_int_op(r, OP_EQ, -1); + /* Correct call. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.1:1234", @@ -834,6 +838,18 @@ test_addr_parse(void *arg) tt_int_op(r, OP_EQ, 0); tt_int_op(port,OP_EQ,400); + /* Allow IPv6 without square brackets, when there is no port */ + r= tor_addr_port_parse(LOG_DEBUG, + "::1", + &addr, &port, -1); + tt_int_op(r, OP_EQ, -1); + + r= tor_addr_port_parse(LOG_DEBUG, + "::1", + &addr, &port, 600); + tt_int_op(r, OP_EQ, 0); + tt_int_op(port,OP_EQ,600); + /* Bad port. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.2:66666", @@ -854,12 +870,29 @@ test_addr_parse(void *arg) &addr, &port, 200); tt_int_op(r, OP_EQ, -1); - /* Bad IP address */ + /* Bad IPv4 address */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2:1234", &addr, &port, -1); tt_int_op(r, OP_EQ, -1); + /* Bad IPv4 address and port: brackets */ + r= tor_addr_port_parse(LOG_DEBUG, + "[192.0.2.3]:12345", + &addr, &port, -1); + tt_int_op(r, OP_EQ, -1); + + /* Bad IPv6 addresses and ports: no brackets */ + r= tor_addr_port_parse(LOG_DEBUG, + "::1:12345", + &addr, &port, -1); + tt_int_op(r, OP_EQ, -1); + + r= tor_addr_port_parse(LOG_DEBUG, + "11:22::33:44:12345", + &addr, &port, -1); + tt_int_op(r, OP_EQ, -1); + /* Make sure that the default port has lower priority than the real one */ r= tor_addr_port_parse(LOG_DEBUG, From 5a3770dc6cf5490b0e1c3951e8e12c815ec7891e Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 13 Jun 2019 22:30:03 +1000 Subject: [PATCH 07/12] test/addr: Stop repeating so much code in test_addr_parse() Cleanup after 30721. --- src/test/test_addr.c | 286 +++++++++++++++++++++++-------------------- 1 file changed, 151 insertions(+), 135 deletions(-) diff --git a/src/test/test_addr.c b/src/test/test_addr.c index a961a46854..f8fa7b9503 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -724,188 +724,204 @@ test_addr_ip6_helpers(void *arg) ; } +/* Test that addr_str successfully parses, and: + * - the address has family expect_family, + * - the fmt_decorated result of tor_addr_to_str() is expect_str. + */ +#define TEST_ADDR_PARSE_FMT(addr_str, expect_family, fmt_decorated, \ + expect_str) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + char buf[TOR_ADDR_BUF_LEN]; \ + const char *sv; \ + r = tor_addr_parse(&addr, addr_str); \ + tt_int_op(r, OP_EQ, expect_family); \ + sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \ + tt_str_op(sv, OP_EQ, buf); \ + tt_str_op(buf, OP_EQ, expect_str); \ + STMT_END + +/* Test that addr_str fails to parse, and: + * - the returned address is null. + */ +#define TEST_ADDR_PARSE_XFAIL(addr_str) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + r = tor_addr_parse(&addr, addr_str); \ + tt_int_op(r, OP_EQ, -1); \ + tt_assert(tor_addr_is_null(&addr)); \ + STMT_END + +/* Test that addr_port_str and default_port successfully parse, and: + * - the address has family expect_family, + * - the fmt_decorated result of tor_addr_to_str() is expect_str, + * - the port is expect_port. + */ +#define TEST_ADDR_PORT_PARSE_FMT(addr_port_str, default_port, expect_family, \ + fmt_decorated, expect_str, expect_port) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + uint16_t port; \ + char buf[TOR_ADDR_BUF_LEN]; \ + const char *sv; \ + r = tor_addr_port_parse(LOG_DEBUG, addr_port_str, &addr, &port, \ + default_port); \ + tt_int_op(r, OP_EQ, 0); \ + tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \ + sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \ + tt_str_op(sv, OP_EQ, buf); \ + tt_str_op(buf, OP_EQ, expect_str); \ + tt_int_op(port, OP_EQ, expect_port); \ + STMT_END + +/* Test that addr_port_str and default_port fail to parse, and: + * - the returned address is null, + * - the returned port is 0. + */ +#define TEST_ADDR_PORT_PARSE_XFAIL(addr_port_str, default_port) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + uint16_t port; \ + r = tor_addr_port_parse(LOG_DEBUG, addr_port_str, &addr, &port, \ + default_port); \ + tt_int_op(r, OP_EQ, -1); \ + tt_assert(tor_addr_is_null(&addr)); \ + tt_int_op(port, OP_EQ, 0); \ + STMT_END + +/* Test that addr_str successfully parses as a canonical IPv4 address. */ +#define TEST_ADDR_V4_PARSE_CANONICAL(addr_str) \ + TEST_ADDR_PARSE_FMT(addr_str, AF_INET, 0, addr_str) + +/* Test that addr_str successfully parses as a canonical fmt_decorated + * IPv6 address. */ +#define TEST_ADDR_V6_PARSE_CANONICAL(addr_str, fmt_decorated) \ + TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, addr_str) + +/* Test that addr_str successfully parses, and the fmt_decorated canonical + * IPv6 string is expect_str. */ +#define TEST_ADDR_V6_PARSE(addr_str, fmt_decorated, expect_str) \ + TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, expect_str) + +/* Test that addr_port_str successfully parses to the canonical IPv4 address + * string expect_str, and port expect_port. */ +#define TEST_ADDR_V4_PORT_PARSE(addr_port_str, expect_str, expect_port) \ + TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET, 0, expect_str, \ + expect_port) + +/* Test that addr_port_str successfully parses to the canonical undecorated + * IPv6 address string expect_str, and port expect_port. */ +#define TEST_ADDR_V6_PORT_PARSE(addr_port_str, expect_str, expect_port) \ + TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET6, 0, expect_str, \ + expect_port) + +/* Test that addr_port_str and default_port successfully parse to the canonical + * IPv4 address string expect_str, and port expect_port. */ +#define TEST_ADDR_V4_PORT_DEF_PARSE(addr_port_str, default_port, expect_str, \ + expect_port) \ + TEST_ADDR_PORT_PARSE_FMT(addr_port_str, default_port, AF_INET, 0, \ + expect_str, expect_port) + +/* Test that addr_port_str successfully parses to the canonical undecorated + * IPv6 address string expect_str, and port expect_port. */ +#define TEST_ADDR_V6_PORT_DEF_PARSE(addr_port_str, default_port, expect_str, \ + expect_port) \ + TEST_ADDR_PORT_PARSE_FMT(addr_port_str, default_port, AF_INET6, 0, \ + expect_str, expect_port) + /** Test tor_addr_parse() and tor_addr_port_parse(). */ static void test_addr_parse(void *arg) { - int r; - tor_addr_t addr; - char buf[TOR_ADDR_BUF_LEN]; - uint16_t port = 0; - - /* Correct call. */ (void)arg; - r= tor_addr_parse(&addr, "192.0.2.1"); - tt_int_op(r,OP_EQ, AF_INET); - tor_addr_to_str(buf, &addr, sizeof(buf), 0); - tt_str_op(buf,OP_EQ, "192.0.2.1"); - r= tor_addr_parse(&addr, "11:22::33:44"); - tt_int_op(r,OP_EQ, AF_INET6); - tor_addr_to_str(buf, &addr, sizeof(buf), 0); - tt_str_op(buf,OP_EQ, "11:22::33:44"); + /* Correct calls. */ + TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.1"); - r= tor_addr_parse(&addr, "[11:22::33:44]"); - tt_int_op(r,OP_EQ, AF_INET6); - tor_addr_to_str(buf, &addr, sizeof(buf), 0); - tt_str_op(buf,OP_EQ, "11:22::33:44"); + TEST_ADDR_V6_PARSE_CANONICAL("11:22::33:44", 0); + TEST_ADDR_V6_PARSE_CANONICAL("[11:22::33:44]", 1); - r= tor_addr_parse(&addr, "11:22:33:44:55:66:1.2.3.4"); - tt_int_op(r,OP_EQ, AF_INET6); - tor_addr_to_str(buf, &addr, sizeof(buf), 0); - tt_str_op(buf,OP_EQ, "11:22:33:44:55:66:102:304"); + TEST_ADDR_V6_PARSE("11:22:33:44:55:66:1.2.3.4", 0, + "11:22:33:44:55:66:102:304"); - r= tor_addr_parse(&addr, "11:22::33:44:1.2.3.4"); - tt_int_op(r,OP_EQ, AF_INET6); - tor_addr_to_str(buf, &addr, sizeof(buf), 0); - tt_str_op(buf,OP_EQ, "11:22::33:44:102:304"); + TEST_ADDR_V6_PARSE("11:22::33:44:1.2.3.4", 0, + "11:22::33:44:102:304"); /* Empty string. */ - r= tor_addr_parse(&addr, ""); - tt_int_op(r,OP_EQ, -1); + TEST_ADDR_PARSE_XFAIL(""); /* Square brackets around IPv4 address. */ - r= tor_addr_parse(&addr, "[192.0.2.1]"); - tt_int_op(r,OP_EQ, -1); + TEST_ADDR_PARSE_XFAIL("[192.0.2.1]"); /* Only left square bracket. */ - r= tor_addr_parse(&addr, "[11:22::33:44"); - tt_int_op(r,OP_EQ, -1); + TEST_ADDR_PARSE_XFAIL("[11:22::33:44"); /* Only right square bracket. */ - r= tor_addr_parse(&addr, "11:22::33:44]"); - tt_int_op(r,OP_EQ, -1); + TEST_ADDR_PARSE_XFAIL("11:22::33:44]"); /* Leading colon. */ - r= tor_addr_parse(&addr, ":11:22::33:44"); - tt_int_op(r,OP_EQ, -1); + TEST_ADDR_PARSE_XFAIL(":11:22::33:44"); /* Trailing colon. */ - r= tor_addr_parse(&addr, "11:22::33:44:"); - tt_int_op(r,OP_EQ, -1); + TEST_ADDR_PARSE_XFAIL("11:22::33:44:"); /* Too many hex words in IPv4-mapped IPv6 address. */ - r= tor_addr_parse(&addr, "11:22:33:44:55:66:77:88:1.2.3.4"); - tt_int_op(r,OP_EQ, -1); + TEST_ADDR_PARSE_XFAIL("11:22:33:44:55:66:77:88:1.2.3.4"); /* IPv6 address with port and no brackets */ - r= tor_addr_parse(&addr, "11:22::33:44:12345"); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PARSE_XFAIL("11:22::33:44:12345"); - /* Correct call. */ - r= tor_addr_port_parse(LOG_DEBUG, - "192.0.2.1:1234", - &addr, &port, -1); - tt_int_op(r, OP_EQ, 0); - tor_addr_to_str(buf, &addr, sizeof(buf), 0); - tt_str_op(buf,OP_EQ, "192.0.2.1"); - tt_int_op(port,OP_EQ, 1234); + /* Correct calls. */ + TEST_ADDR_V4_PORT_PARSE("192.0.2.1:1234", "192.0.2.1", 1234); - r= tor_addr_port_parse(LOG_DEBUG, - "[::1]:1234", - &addr, &port, -1); - tt_int_op(r, OP_EQ, 0); - tor_addr_to_str(buf, &addr, sizeof(buf), 0); - tt_str_op(buf,OP_EQ, "::1"); - tt_int_op(port,OP_EQ, 1234); + TEST_ADDR_V6_PORT_PARSE("[::1]:1234", "::1", 1234); /* Domain name. */ - r= tor_addr_port_parse(LOG_DEBUG, - "torproject.org:1234", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PORT_PARSE_XFAIL("torproject.org:1234", -1); /* Only IP. */ - r= tor_addr_port_parse(LOG_DEBUG, - "192.0.2.2", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PORT_PARSE_XFAIL("192.0.2.2", -1); + TEST_ADDR_V4_PORT_DEF_PARSE("192.0.2.2", 200, "192.0.2.2", 200); - r= tor_addr_port_parse(LOG_DEBUG, - "192.0.2.2", - &addr, &port, 200); - tt_int_op(r, OP_EQ, 0); - tt_int_op(port,OP_EQ,200); + TEST_ADDR_PORT_PARSE_XFAIL("[::1]", -1); + TEST_ADDR_V6_PORT_DEF_PARSE("[::1]", 400, "::1", 400); - r= tor_addr_port_parse(LOG_DEBUG, - "[::1]", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); - - r= tor_addr_port_parse(LOG_DEBUG, - "[::1]", - &addr, &port, 400); - tt_int_op(r, OP_EQ, 0); - tt_int_op(port,OP_EQ,400); - - /* Allow IPv6 without square brackets, when there is no port */ - r= tor_addr_port_parse(LOG_DEBUG, - "::1", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); - - r= tor_addr_port_parse(LOG_DEBUG, - "::1", - &addr, &port, 600); - tt_int_op(r, OP_EQ, 0); - tt_int_op(port,OP_EQ,600); + /* Allow IPv6 without square brackets, when there is no port, but only if + * there is a default port */ + TEST_ADDR_PORT_PARSE_XFAIL("::1", -1); + TEST_ADDR_V6_PORT_DEF_PARSE("::1", 600, "::1", 600); /* Bad port. */ - r= tor_addr_port_parse(LOG_DEBUG, - "192.0.2.2:66666", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); - r= tor_addr_port_parse(LOG_DEBUG, - "192.0.2.2:66666", - &addr, &port, 200); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PORT_PARSE_XFAIL("192.0.2.2:66666", -1); + TEST_ADDR_PORT_PARSE_XFAIL("192.0.2.2:66666", 200); /* Only domain name */ - r= tor_addr_port_parse(LOG_DEBUG, - "torproject.org", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); - r= tor_addr_port_parse(LOG_DEBUG, - "torproject.org", - &addr, &port, 200); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PORT_PARSE_XFAIL("torproject.org", -1); + TEST_ADDR_PORT_PARSE_XFAIL("torproject.org", 200); /* Bad IPv4 address */ - r= tor_addr_port_parse(LOG_DEBUG, - "192.0.2:1234", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PORT_PARSE_XFAIL("192.0.2:1234", -1); + TEST_ADDR_PORT_PARSE_XFAIL("192.0.2:1234", 200); /* Bad IPv4 address and port: brackets */ - r= tor_addr_port_parse(LOG_DEBUG, - "[192.0.2.3]:12345", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PORT_PARSE_XFAIL("[192.0.2.3]:12345", -1); + TEST_ADDR_PORT_PARSE_XFAIL("[192.0.2.3]:12345", 200); /* Bad IPv6 addresses and ports: no brackets */ - r= tor_addr_port_parse(LOG_DEBUG, - "::1:12345", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PORT_PARSE_XFAIL("::1:12345", -1); + TEST_ADDR_PORT_PARSE_XFAIL("::1:12345", 200); - r= tor_addr_port_parse(LOG_DEBUG, - "11:22::33:44:12345", - &addr, &port, -1); - tt_int_op(r, OP_EQ, -1); + TEST_ADDR_PORT_PARSE_XFAIL("11:22::33:44:12345", -1); + TEST_ADDR_PORT_PARSE_XFAIL("11:22::33:44:12345", 200); /* Make sure that the default port has lower priority than the real one */ - r= tor_addr_port_parse(LOG_DEBUG, - "192.0.2.2:1337", - &addr, &port, 200); - tt_int_op(r, OP_EQ, 0); - tt_int_op(port,OP_EQ,1337); - - r= tor_addr_port_parse(LOG_DEBUG, - "[::1]:1369", - &addr, &port, 200); - tt_int_op(r, OP_EQ, 0); - tt_int_op(port,OP_EQ,1369); + TEST_ADDR_V4_PORT_DEF_PARSE("192.0.2.2:1337", 200, "192.0.2.2", 1337); + TEST_ADDR_V6_PORT_DEF_PARSE("[::1]:1369", 200, "::1", 1369); done: ; From 2dbde3617f5d117e708dbd83410c8c73dc134902 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 13 Jun 2019 23:14:16 +1000 Subject: [PATCH 08/12] test/addr: Increase coverage in test_addr_parse() Do as many tests as possible for each input string. Then remove some redundant test cases. Cleanup after 30721. --- src/test/test_addr.c | 130 +++++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/src/test/test_addr.c b/src/test/test_addr.c index f8fa7b9503..6a6796c987 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -793,45 +793,72 @@ test_addr_ip6_helpers(void *arg) tt_int_op(port, OP_EQ, 0); \ STMT_END -/* Test that addr_str successfully parses as a canonical IPv4 address. */ +/* Test that addr_str successfully parses as a canonical IPv4 address. + * Use tor_addr_parse(), and tor_addr_port_parse() with a default port. + * Also check that tor_addr_port_parse() fails without a default port. */ #define TEST_ADDR_V4_PARSE_CANONICAL(addr_str) \ - TEST_ADDR_PARSE_FMT(addr_str, AF_INET, 0, addr_str) + STMT_BEGIN \ + TEST_ADDR_PARSE_FMT(addr_str, AF_INET, 0, addr_str); \ + TEST_ADDR_PORT_PARSE_FMT(addr_str, 111, AF_INET, 0, \ + addr_str, 111); \ + TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ + STMT_END /* Test that addr_str successfully parses as a canonical fmt_decorated - * IPv6 address. */ + * IPv6 address. + * Use tor_addr_parse(), and tor_addr_port_parse() with a default port. + * Also check that tor_addr_port_parse() fails without a default port. */ #define TEST_ADDR_V6_PARSE_CANONICAL(addr_str, fmt_decorated) \ - TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, addr_str) + STMT_BEGIN \ + TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, addr_str); \ + TEST_ADDR_PORT_PARSE_FMT(addr_str, 222, AF_INET6, fmt_decorated, \ + addr_str, 222); \ + TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ + STMT_END /* Test that addr_str successfully parses, and the fmt_decorated canonical - * IPv6 string is expect_str. */ + * IPv6 string is expect_str. + * Use tor_addr_parse(), and tor_addr_port_parse() with a default port. + * Also check that tor_addr_port_parse() fails without a default port. */ #define TEST_ADDR_V6_PARSE(addr_str, fmt_decorated, expect_str) \ - TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, expect_str) + STMT_BEGIN \ + TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, expect_str); \ + TEST_ADDR_PORT_PARSE_FMT(addr_str, 333, AF_INET6, fmt_decorated, \ + expect_str, 333); \ + TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ + STMT_END /* Test that addr_port_str successfully parses to the canonical IPv4 address - * string expect_str, and port expect_port. */ + * string expect_str, and port expect_port. + * Check with and without a default port. */ #define TEST_ADDR_V4_PORT_PARSE(addr_port_str, expect_str, expect_port) \ - TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET, 0, expect_str, \ - expect_port) + STMT_BEGIN \ + TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET, 0, expect_str, \ + expect_port); \ + TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 444, AF_INET, 0, expect_str, \ + expect_port); \ + STMT_END /* Test that addr_port_str successfully parses to the canonical undecorated - * IPv6 address string expect_str, and port expect_port. */ + * IPv6 address string expect_str, and port expect_port. + * Check with and without a default port. */ #define TEST_ADDR_V6_PORT_PARSE(addr_port_str, expect_str, expect_port) \ - TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET6, 0, expect_str, \ - expect_port) + STMT_BEGIN \ + TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET6, 0, expect_str, \ + expect_port); \ + TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 555, AF_INET6, 0, expect_str, \ + expect_port); \ + STMT_END -/* Test that addr_port_str and default_port successfully parse to the canonical - * IPv4 address string expect_str, and port expect_port. */ -#define TEST_ADDR_V4_PORT_DEF_PARSE(addr_port_str, default_port, expect_str, \ - expect_port) \ - TEST_ADDR_PORT_PARSE_FMT(addr_port_str, default_port, AF_INET, 0, \ - expect_str, expect_port) - -/* Test that addr_port_str successfully parses to the canonical undecorated - * IPv6 address string expect_str, and port expect_port. */ -#define TEST_ADDR_V6_PORT_DEF_PARSE(addr_port_str, default_port, expect_str, \ - expect_port) \ - TEST_ADDR_PORT_PARSE_FMT(addr_port_str, default_port, AF_INET6, 0, \ - expect_str, expect_port) +/* Test that addr_str fails to parse due to a bad address or port. + * Use tor_addr_parse(), and tor_addr_port_parse() with and without a + * default port. */ +#define TEST_ADDR_PARSE_XFAIL_MALFORMED(addr_str) \ + STMT_BEGIN \ + TEST_ADDR_PARSE_XFAIL(addr_str); \ + TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ + TEST_ADDR_PORT_PARSE_XFAIL(addr_str, 666); \ + STMT_END /** Test tor_addr_parse() and tor_addr_port_parse(). */ static void @@ -852,76 +879,59 @@ test_addr_parse(void *arg) "11:22::33:44:102:304"); /* Empty string. */ - TEST_ADDR_PARSE_XFAIL(""); + TEST_ADDR_PARSE_XFAIL_MALFORMED(""); /* Square brackets around IPv4 address. */ - TEST_ADDR_PARSE_XFAIL("[192.0.2.1]"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.1]"); /* Only left square bracket. */ - TEST_ADDR_PARSE_XFAIL("[11:22::33:44"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("[11:22::33:44"); /* Only right square bracket. */ - TEST_ADDR_PARSE_XFAIL("11:22::33:44]"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44]"); /* Leading colon. */ - TEST_ADDR_PARSE_XFAIL(":11:22::33:44"); + TEST_ADDR_PARSE_XFAIL_MALFORMED(":11:22::33:44"); /* Trailing colon. */ - TEST_ADDR_PARSE_XFAIL("11:22::33:44:"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:"); /* Too many hex words in IPv4-mapped IPv6 address. */ - TEST_ADDR_PARSE_XFAIL("11:22:33:44:55:66:77:88:1.2.3.4"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22:33:44:55:66:77:88:1.2.3.4"); /* IPv6 address with port and no brackets */ - TEST_ADDR_PARSE_XFAIL("11:22::33:44:12345"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:12345"); /* Correct calls. */ TEST_ADDR_V4_PORT_PARSE("192.0.2.1:1234", "192.0.2.1", 1234); - TEST_ADDR_V6_PORT_PARSE("[::1]:1234", "::1", 1234); /* Domain name. */ - TEST_ADDR_PORT_PARSE_XFAIL("torproject.org:1234", -1); + TEST_ADDR_PARSE_XFAIL_MALFORMED("torproject.org:1234"); /* Only IP. */ - TEST_ADDR_PORT_PARSE_XFAIL("192.0.2.2", -1); - TEST_ADDR_V4_PORT_DEF_PARSE("192.0.2.2", 200, "192.0.2.2", 200); - - TEST_ADDR_PORT_PARSE_XFAIL("[::1]", -1); - TEST_ADDR_V6_PORT_DEF_PARSE("[::1]", 400, "::1", 400); + TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.2"); + TEST_ADDR_V6_PARSE_CANONICAL("[::1]", 1); /* Allow IPv6 without square brackets, when there is no port, but only if * there is a default port */ - TEST_ADDR_PORT_PARSE_XFAIL("::1", -1); - TEST_ADDR_V6_PORT_DEF_PARSE("::1", 600, "::1", 600); + TEST_ADDR_V6_PARSE_CANONICAL("::1", 0); /* Bad port. */ - TEST_ADDR_PORT_PARSE_XFAIL("192.0.2.2:66666", -1); - TEST_ADDR_PORT_PARSE_XFAIL("192.0.2.2:66666", 200); + TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:66666"); /* Only domain name */ - TEST_ADDR_PORT_PARSE_XFAIL("torproject.org", -1); - TEST_ADDR_PORT_PARSE_XFAIL("torproject.org", 200); + TEST_ADDR_PARSE_XFAIL_MALFORMED("torproject.org"); /* Bad IPv4 address */ - TEST_ADDR_PORT_PARSE_XFAIL("192.0.2:1234", -1); - TEST_ADDR_PORT_PARSE_XFAIL("192.0.2:1234", 200); + TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2:1234"); /* Bad IPv4 address and port: brackets */ - TEST_ADDR_PORT_PARSE_XFAIL("[192.0.2.3]:12345", -1); - TEST_ADDR_PORT_PARSE_XFAIL("[192.0.2.3]:12345", 200); + TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.3]:12345"); /* Bad IPv6 addresses and ports: no brackets */ - TEST_ADDR_PORT_PARSE_XFAIL("::1:12345", -1); - TEST_ADDR_PORT_PARSE_XFAIL("::1:12345", 200); - - TEST_ADDR_PORT_PARSE_XFAIL("11:22::33:44:12345", -1); - TEST_ADDR_PORT_PARSE_XFAIL("11:22::33:44:12345", 200); - - /* Make sure that the default port has lower priority than the real - one */ - TEST_ADDR_V4_PORT_DEF_PARSE("192.0.2.2:1337", 200, "192.0.2.2", 1337); - TEST_ADDR_V6_PORT_DEF_PARSE("[::1]:1369", 200, "::1", 1369); + TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:12345"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:12345"); done: ; From 60ce431c5440ee08e100a1f70a4d7224b7dc9c21 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 13 Jun 2019 23:15:52 +1000 Subject: [PATCH 09/12] test/addr: Add some ambiguous IPv6 cases to test_addr_parse() Test some strings which could be parsed as IPv6 addresses, or as IPv6:port strings. Additional tests for 30721. --- src/test/test_addr.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 6a6796c987..1b25c4c643 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -901,6 +901,23 @@ test_addr_parse(void *arg) /* IPv6 address with port and no brackets */ TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:12345"); + /* Is it a port, or are there too many hex words? + * We reject it either way. */ + TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22:33:44:55:66:77:88:99"); + /* But we accept it if it has square brackets. */ + TEST_ADDR_V6_PORT_PARSE("[11:22:33:44:55:66:77:88]:99", + "11:22:33:44:55:66:77:88",99); + + /* This is an IPv6 address */ + TEST_ADDR_V6_PARSE_CANONICAL("11:22:33:44:55:66:77:88", 0); + TEST_ADDR_V6_PARSE_CANONICAL("[11:22:33:44:55:66:77:88]", 1); + + /* And this is an ambiguous case, which is interpreted as an IPv6 address. */ + TEST_ADDR_V6_PARSE_CANONICAL("11:22::88:99", 0); + /* Use square brackets to resolve the ambiguity */ + TEST_ADDR_V6_PARSE_CANONICAL("[11:22::88:99]", 1); + TEST_ADDR_V6_PORT_PARSE("[11:22::88]:99", + "11:22::88",99); /* Correct calls. */ TEST_ADDR_V4_PORT_PARSE("192.0.2.1:1234", "192.0.2.1", 1234); From 1c92d7f3882e6bd43e871ff1b17ca8c4a65b1e08 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 14 Jun 2019 00:00:05 +1000 Subject: [PATCH 10/12] test/addr: test that tor_lookup_hostname() handles IPv4 addresses And that it fails on IPv6 and host:port, and does something sensible with host. Tests for 30721. --- src/test/test_addr.c | 142 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 128 insertions(+), 14 deletions(-) diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 1b25c4c643..53f41bcf1b 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -793,71 +793,187 @@ test_addr_ip6_helpers(void *arg) tt_int_op(port, OP_EQ, 0); \ STMT_END +/* Test that addr_str successfully parses as an IPv4 address using + * tor_lookup_hostname(), and: + * - the fmt_addr32() of the result is expect_str. + */ +#define TEST_ADDR_V4_LOOKUP_HOSTNAME(addr_str, expect_str) \ + STMT_BEGIN \ + int r; \ + uint32_t addr32h; \ + r = tor_lookup_hostname(addr_str, &addr32h); \ + tt_int_op(r, OP_EQ, 0); \ + tt_str_op(fmt_addr32(addr32h), OP_EQ, expect_str); \ + STMT_END + +/* Test that bad_str fails to parse using tor_lookup_hostname(), with a + * permanent failure, and: + * - the returned address is 0. + */ +#define TEST_ADDR_V4_LOOKUP_XFAIL(bad_str) \ + STMT_BEGIN \ + int r; \ + uint32_t addr32h; \ + r = tor_lookup_hostname(bad_str, &addr32h); \ + tt_int_op(r, OP_EQ, -1); \ + tt_int_op(addr32h, OP_EQ, 0); \ + STMT_END + +/* Test that looking up host_str as an IPv4 address using tor_lookup_hostname() + * does something sensible: + * - the result is -1, 0, or 1. + * - if the result is a failure, the returned address is 0. + * We can't rely on the result of this function, because it depends on the + * network. + */ +#define TEST_HOST_V4_LOOKUP(host_str) \ + STMT_BEGIN \ + int r; \ + uint32_t addr32h; \ + r = tor_lookup_hostname(host_str, &addr32h); \ + tt_int_op(r, OP_GE, -1); \ + tt_int_op(r, OP_LE, 1); \ + if (r != 0) \ + tt_int_op(addr32h, OP_EQ, 0); \ + STMT_END + /* Test that addr_str successfully parses as a canonical IPv4 address. - * Use tor_addr_parse(), and tor_addr_port_parse() with a default port. - * Also check that tor_addr_port_parse() fails without a default port. */ + * Check for successful parsing using: + * - tor_addr_parse(), + * - tor_addr_port_parse() with a default port, + * - tor_lookup_hostname(). + * Check for failures using: + * - tor_addr_port_parse() without a default port, because there is no port. + */ #define TEST_ADDR_V4_PARSE_CANONICAL(addr_str) \ STMT_BEGIN \ TEST_ADDR_PARSE_FMT(addr_str, AF_INET, 0, addr_str); \ TEST_ADDR_PORT_PARSE_FMT(addr_str, 111, AF_INET, 0, \ addr_str, 111); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ + TEST_ADDR_V4_LOOKUP_HOSTNAME(addr_str, addr_str); \ STMT_END /* Test that addr_str successfully parses as a canonical fmt_decorated * IPv6 address. - * Use tor_addr_parse(), and tor_addr_port_parse() with a default port. - * Also check that tor_addr_port_parse() fails without a default port. */ + * Check for successful parsing using: + * - tor_addr_parse(), + * - tor_addr_port_parse() with a default port. + * Check for failures using: + * - tor_addr_port_parse() without a default port, because there is no port, + * - tor_lookup_hostname(), because it only supports IPv4. + */ #define TEST_ADDR_V6_PARSE_CANONICAL(addr_str, fmt_decorated) \ STMT_BEGIN \ TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, addr_str); \ TEST_ADDR_PORT_PARSE_FMT(addr_str, 222, AF_INET6, fmt_decorated, \ addr_str, 222); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ + TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \ STMT_END /* Test that addr_str successfully parses, and the fmt_decorated canonical * IPv6 string is expect_str. - * Use tor_addr_parse(), and tor_addr_port_parse() with a default port. - * Also check that tor_addr_port_parse() fails without a default port. */ + * Check for successful parsing using: + * - tor_addr_parse(), + * - tor_addr_port_parse() with a default port. + * Check for failures using: + * - tor_addr_port_parse() without a default port, because there is no port. + * - tor_lookup_hostname(), because it only supports IPv4. + */ #define TEST_ADDR_V6_PARSE(addr_str, fmt_decorated, expect_str) \ STMT_BEGIN \ TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, expect_str); \ TEST_ADDR_PORT_PARSE_FMT(addr_str, 333, AF_INET6, fmt_decorated, \ expect_str, 333); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ + TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \ STMT_END /* Test that addr_port_str successfully parses to the canonical IPv4 address * string expect_str, and port expect_port. - * Check with and without a default port. */ + * Check for successful parsing using: + * - tor_addr_port_parse() without a default port, + * - tor_addr_port_parse() with a default port. + * Check for failures using: + * - tor_addr_parse(), because there is a port, + * - tor_lookup_hostname(), because there is a port. + */ #define TEST_ADDR_V4_PORT_PARSE(addr_port_str, expect_str, expect_port) \ STMT_BEGIN \ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET, 0, expect_str, \ expect_port); \ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 444, AF_INET, 0, expect_str, \ expect_port); \ + TEST_ADDR_PARSE_XFAIL(addr_port_str); \ + TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \ STMT_END /* Test that addr_port_str successfully parses to the canonical undecorated * IPv6 address string expect_str, and port expect_port. - * Check with and without a default port. */ + * Check for successful parsing using: + * - tor_addr_port_parse() without a default port, + * - tor_addr_port_parse() with a default port. + * Check for failures using: + * - tor_addr_parse(), because there is a port, + * - tor_lookup_hostname(), because there is a port, and because it only + * supports IPv4. + */ #define TEST_ADDR_V6_PORT_PARSE(addr_port_str, expect_str, expect_port) \ STMT_BEGIN \ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET6, 0, expect_str, \ expect_port); \ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 555, AF_INET6, 0, expect_str, \ expect_port); \ + TEST_ADDR_PARSE_XFAIL(addr_port_str); \ + TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \ STMT_END /* Test that addr_str fails to parse due to a bad address or port. - * Use tor_addr_parse(), and tor_addr_port_parse() with and without a - * default port. */ + * Check for failures using: + * - tor_addr_parse(), + * - tor_addr_port_parse() without a default port, + * - tor_addr_port_parse() with a default port. + * - tor_lookup_hostname(). + */ #define TEST_ADDR_PARSE_XFAIL_MALFORMED(addr_str) \ STMT_BEGIN \ TEST_ADDR_PARSE_XFAIL(addr_str); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, 666); \ + TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \ + STMT_END + +/* Test that host_str is treated as a hostname, and not an address. + * Check for success or failure using: + * - tor_lookup_hostname(), because it depends on the network. + * Check for failures using: + * - tor_addr_parse(), + * - tor_addr_port_parse() without a default port, + * - tor_addr_port_parse() with a default port. + */ +#define TEST_HOSTNAME(host_str) \ + STMT_BEGIN \ + TEST_HOST_V4_LOOKUP(host_str); \ + TEST_ADDR_PARSE_XFAIL(host_str); \ + TEST_ADDR_PORT_PARSE_XFAIL(host_str, -1); \ + TEST_ADDR_PORT_PARSE_XFAIL(host_str, 777); \ + STMT_END + +/* Test that host_port_str is treated as a hostname and port, and not a + * hostname or an address. + * Check for failures using: + * - tor_lookup_hostname(), because it doesn't support ports, + * - tor_addr_parse(), + * - tor_addr_port_parse() without a default port, + * - tor_addr_port_parse() with a default port. + */ +#define TEST_HOSTNAME_PORT(host_port_str) \ + STMT_BEGIN \ + TEST_ADDR_V4_LOOKUP_XFAIL(host_port_str); \ + TEST_ADDR_PARSE_XFAIL(host_port_str); \ + TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, -1); \ + TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, 888); \ STMT_END /** Test tor_addr_parse() and tor_addr_port_parse(). */ @@ -924,7 +1040,8 @@ test_addr_parse(void *arg) TEST_ADDR_V6_PORT_PARSE("[::1]:1234", "::1", 1234); /* Domain name. */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("torproject.org:1234"); + TEST_HOSTNAME("torproject.org"); + TEST_HOSTNAME_PORT("torproject.org:1234"); /* Only IP. */ TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.2"); @@ -937,9 +1054,6 @@ test_addr_parse(void *arg) /* Bad port. */ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:66666"); - /* Only domain name */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("torproject.org"); - /* Bad IPv4 address */ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2:1234"); From 6079dfd1032add1c952f22b831d0f3c38147ea08 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 14 Jun 2019 00:49:45 +1000 Subject: [PATCH 11/12] test/addr: test that tor_addr_lookup() handles IP addresses And that it fails on IP:port and host:port, and does something sensible with host. Tests for 30721. --- src/test/test_addr.c | 138 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 118 insertions(+), 20 deletions(-) diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 53f41bcf1b..d5f7cda438 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -837,57 +837,130 @@ test_addr_ip6_helpers(void *arg) tt_int_op(addr32h, OP_EQ, 0); \ STMT_END +/* Test that addr_str successfully parses as a require_family IP address using + * tor_addr_lookup(), and: + * - the address has family expect_family, + * - the fmt_decorated result of tor_addr_to_str() is expect_str. + */ +#define TEST_ADDR_LOOKUP_FMT(addr_str, require_family, expect_family, \ + fmt_decorated, expect_str) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + char buf[TOR_ADDR_BUF_LEN]; \ + const char *sv; \ + r = tor_addr_lookup(addr_str, require_family, &addr); \ + tt_int_op(r, OP_EQ, 0); \ + tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \ + sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \ + tt_str_op(sv, OP_EQ, buf); \ + tt_str_op(buf, OP_EQ, expect_str); \ + STMT_END + +/* Test that bad_str fails to parse as a require_family IP address using + * tor_addr_lookup(), with a permanent failure, and: + * - the returned address is null. + */ +#define TEST_ADDR_LOOKUP_XFAIL(bad_str, require_family) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + r = tor_addr_lookup(bad_str, require_family, &addr); \ + tt_int_op(r, OP_EQ, -1); \ + tt_assert(tor_addr_is_null(&addr)); \ + STMT_END + +/* Test that looking up host_string as a require_family IP address using + * tor_addr_lookup(), does something sensible: + * - the result is -1, 0, or 1. + * - if the result is a failure, the returned address is null. + * We can't rely on the result of this function, because it depends on the + * network. + */ +#define TEST_HOST_LOOKUP(host_str, require_family) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + r = tor_addr_lookup(host_str, require_family, &addr); \ + tt_int_op(r, OP_GE, -1); \ + tt_int_op(r, OP_LE, 1); \ + if (r != 0) \ + tt_assert(tor_addr_is_null(&addr)); \ + STMT_END + /* Test that addr_str successfully parses as a canonical IPv4 address. * Check for successful parsing using: * - tor_addr_parse(), * - tor_addr_port_parse() with a default port, - * - tor_lookup_hostname(). + * - tor_lookup_hostname(), + * - tor_addr_lookup() with AF_INET, + * - tor_addr_lookup() with AF_UNSPEC. * Check for failures using: - * - tor_addr_port_parse() without a default port, because there is no port. + * - tor_addr_port_parse() without a default port, because there is no port, + * - tor_addr_lookup() with AF_INET6. */ #define TEST_ADDR_V4_PARSE_CANONICAL(addr_str) \ STMT_BEGIN \ TEST_ADDR_PARSE_FMT(addr_str, AF_INET, 0, addr_str); \ TEST_ADDR_PORT_PARSE_FMT(addr_str, 111, AF_INET, 0, \ addr_str, 111); \ - TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ TEST_ADDR_V4_LOOKUP_HOSTNAME(addr_str, addr_str); \ + TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET, AF_INET, 0, addr_str); \ + TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET, 0, addr_str); \ + TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ + TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET6); \ STMT_END /* Test that addr_str successfully parses as a canonical fmt_decorated * IPv6 address. * Check for successful parsing using: * - tor_addr_parse(), - * - tor_addr_port_parse() with a default port. + * - tor_addr_port_parse() with a default port, + * - tor_addr_lookup() with AF_INET6, + * - tor_addr_lookup() with AF_UNSPEC. * Check for failures using: * - tor_addr_port_parse() without a default port, because there is no port, - * - tor_lookup_hostname(), because it only supports IPv4. + * - tor_lookup_hostname(), because it only supports IPv4, + * - tor_addr_lookup() with AF_INET. */ #define TEST_ADDR_V6_PARSE_CANONICAL(addr_str, fmt_decorated) \ STMT_BEGIN \ TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, addr_str); \ TEST_ADDR_PORT_PARSE_FMT(addr_str, 222, AF_INET6, fmt_decorated, \ addr_str, 222); \ + TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET6, AF_INET6, fmt_decorated, \ + addr_str); \ + TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET6, fmt_decorated, \ + addr_str); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \ + TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET); \ STMT_END /* Test that addr_str successfully parses, and the fmt_decorated canonical * IPv6 string is expect_str. * Check for successful parsing using: * - tor_addr_parse(), - * - tor_addr_port_parse() with a default port. + * - tor_addr_port_parse() with a default port, + * - tor_addr_lookup() with AF_INET6, + * - tor_addr_lookup() with AF_UNSPEC. * Check for failures using: * - tor_addr_port_parse() without a default port, because there is no port. - * - tor_lookup_hostname(), because it only supports IPv4. + * - tor_lookup_hostname(), because it only supports IPv4, + * - tor_addr_lookup() with AF_INET. */ #define TEST_ADDR_V6_PARSE(addr_str, fmt_decorated, expect_str) \ STMT_BEGIN \ TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, expect_str); \ TEST_ADDR_PORT_PARSE_FMT(addr_str, 333, AF_INET6, fmt_decorated, \ expect_str, 333); \ + TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET6, AF_INET6, fmt_decorated, \ + expect_str); \ + TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET6, fmt_decorated, \ + expect_str); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \ + TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET); \ STMT_END /* Test that addr_port_str successfully parses to the canonical IPv4 address @@ -898,6 +971,8 @@ test_addr_ip6_helpers(void *arg) * Check for failures using: * - tor_addr_parse(), because there is a port, * - tor_lookup_hostname(), because there is a port. + * - tor_addr_lookup(), regardless of the address family, because there is a + * port. */ #define TEST_ADDR_V4_PORT_PARSE(addr_port_str, expect_str, expect_port) \ STMT_BEGIN \ @@ -907,6 +982,9 @@ test_addr_ip6_helpers(void *arg) expect_port); \ TEST_ADDR_PARSE_XFAIL(addr_port_str); \ TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \ + TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \ + TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_UNSPEC); \ + TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET6); \ STMT_END /* Test that addr_port_str successfully parses to the canonical undecorated @@ -917,7 +995,9 @@ test_addr_ip6_helpers(void *arg) * Check for failures using: * - tor_addr_parse(), because there is a port, * - tor_lookup_hostname(), because there is a port, and because it only - * supports IPv4. + * supports IPv4, + * - tor_addr_lookup(), regardless of the address family, because there is a + * port. */ #define TEST_ADDR_V6_PORT_PARSE(addr_port_str, expect_str, expect_port) \ STMT_BEGIN \ @@ -927,26 +1007,34 @@ test_addr_ip6_helpers(void *arg) expect_port); \ TEST_ADDR_PARSE_XFAIL(addr_port_str); \ TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \ + TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET6); \ + TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_UNSPEC); \ + TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \ STMT_END /* Test that addr_str fails to parse due to a bad address or port. * Check for failures using: * - tor_addr_parse(), * - tor_addr_port_parse() without a default port, - * - tor_addr_port_parse() with a default port. - * - tor_lookup_hostname(). + * - tor_addr_port_parse() with a default port, + * - tor_lookup_hostname(), + * - tor_addr_lookup(), regardless of the address family. */ -#define TEST_ADDR_PARSE_XFAIL_MALFORMED(addr_str) \ +#define TEST_ADDR_PARSE_XFAIL_MALFORMED(bad_str) \ STMT_BEGIN \ - TEST_ADDR_PARSE_XFAIL(addr_str); \ - TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ - TEST_ADDR_PORT_PARSE_XFAIL(addr_str, 666); \ - TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \ + TEST_ADDR_PARSE_XFAIL(bad_str); \ + TEST_ADDR_PORT_PARSE_XFAIL(bad_str, -1); \ + TEST_ADDR_PORT_PARSE_XFAIL(bad_str, 666); \ + TEST_ADDR_V4_LOOKUP_XFAIL(bad_str); \ + TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_UNSPEC); \ + TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_INET); \ + TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_INET6); \ STMT_END /* Test that host_str is treated as a hostname, and not an address. - * Check for success or failure using: - * - tor_lookup_hostname(), because it depends on the network. + * Check for success or failure using the network-dependent functions: + * - tor_lookup_hostname(), + * - tor_addr_lookup(), regardless of the address family. * Check for failures using: * - tor_addr_parse(), * - tor_addr_port_parse() without a default port, @@ -955,6 +1043,9 @@ test_addr_ip6_helpers(void *arg) #define TEST_HOSTNAME(host_str) \ STMT_BEGIN \ TEST_HOST_V4_LOOKUP(host_str); \ + TEST_HOST_LOOKUP(host_str, AF_UNSPEC); \ + TEST_HOST_LOOKUP(host_str, AF_INET); \ + TEST_HOST_LOOKUP(host_str, AF_INET6); \ TEST_ADDR_PARSE_XFAIL(host_str); \ TEST_ADDR_PORT_PARSE_XFAIL(host_str, -1); \ TEST_ADDR_PORT_PARSE_XFAIL(host_str, 777); \ @@ -963,17 +1054,22 @@ test_addr_ip6_helpers(void *arg) /* Test that host_port_str is treated as a hostname and port, and not a * hostname or an address. * Check for failures using: - * - tor_lookup_hostname(), because it doesn't support ports, * - tor_addr_parse(), * - tor_addr_port_parse() without a default port, - * - tor_addr_port_parse() with a default port. + * - tor_addr_port_parse() with a default port, + * - tor_lookup_hostname(), because it doesn't support ports, + * - tor_addr_lookup(), regardless of the address family, because it doesn't + * support ports. */ #define TEST_HOSTNAME_PORT(host_port_str) \ STMT_BEGIN \ - TEST_ADDR_V4_LOOKUP_XFAIL(host_port_str); \ TEST_ADDR_PARSE_XFAIL(host_port_str); \ TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, -1); \ TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, 888); \ + TEST_ADDR_V4_LOOKUP_XFAIL(host_port_str); \ + TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_UNSPEC); \ + TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_INET); \ + TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_INET6); \ STMT_END /** Test tor_addr_parse() and tor_addr_port_parse(). */ @@ -1040,6 +1136,8 @@ test_addr_parse(void *arg) TEST_ADDR_V6_PORT_PARSE("[::1]:1234", "::1", 1234); /* Domain name. */ + TEST_HOSTNAME("localhost"); + TEST_HOSTNAME_PORT("localhost:1234"); TEST_HOSTNAME("torproject.org"); TEST_HOSTNAME_PORT("torproject.org:1234"); From 6ef555bda0f7cc1248a133f197fcd0a5f92f5cf1 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 14 Jun 2019 11:06:21 +1000 Subject: [PATCH 12/12] test/addr: test that tor_addr_port_lookup() handles IP addresses and ports And that it does something sensible with host and host:port. Also reorder the tests into valid, invalid, and ambiguous. And add some missing cases. Note: tor_addr_port_lookup() handles ip, ip:port, host, and host:port. Tests for 30721. --- src/test/test_addr.c | 229 +++++++++++++++++++++++++++++++++---------- 1 file changed, 178 insertions(+), 51 deletions(-) diff --git a/src/test/test_addr.c b/src/test/test_addr.c index d5f7cda438..0f50a43615 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -888,16 +888,85 @@ test_addr_ip6_helpers(void *arg) tt_assert(tor_addr_is_null(&addr)); \ STMT_END +/* Test that addr_port_str successfully parses as an IP address and port + * using tor_addr_port_lookup(), and: + * - the address has family expect_family, + * - the fmt_decorated result of tor_addr_to_str() is expect_str, + * - the port is expect_port. + */ +#define TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, expect_family, \ + fmt_decorated, expect_str, expect_port) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + uint16_t port; \ + char buf[TOR_ADDR_BUF_LEN]; \ + const char *sv; \ + r = tor_addr_port_lookup(addr_port_str, &addr, &port); \ + tt_int_op(r, OP_EQ, 0); \ + tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \ + sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \ + tt_str_op(sv, OP_EQ, buf); \ + tt_str_op(buf, OP_EQ, expect_str); \ + tt_int_op(port, OP_EQ, expect_port); \ + STMT_END + +/* Test that bad_str fails to parse as an IP address and port + * using tor_addr_port_lookup(), and: + * - the returned address is null, + * - the returned port is 0. + */ +#define TEST_ADDR_PORT_LOOKUP_XFAIL(bad_str) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + uint16_t port; \ + r = tor_addr_port_lookup(bad_str, &addr, &port); \ + tt_int_op(r, OP_EQ, -1); \ + tt_assert(tor_addr_is_null(&addr)); \ + tt_int_op(port, OP_EQ, 0); \ + STMT_END + +/* Test that looking up host_port_str as an IP address using + * tor_addr_port_lookup(), does something sensible: + * - the result is -1 or 0. + * - if the result is a failure, the returned address is null, and the + * returned port is zero, + * - if the result is a success, the returned port is expect_success_port, + * and the returned family is AF_INET or AF_INET6. + * We can't rely on the result of this function, because it depends on the + * network. + */ +#define TEST_HOST_PORT_LOOKUP(host_port_str, expect_success_port) \ + STMT_BEGIN \ + int r; \ + tor_addr_t addr; \ + uint16_t port; \ + r = tor_addr_port_lookup(host_port_str, &addr, &port); \ + tt_int_op(r, OP_GE, -1); \ + tt_int_op(r, OP_LE, 0); \ + if (r == -1) { \ + tt_assert(tor_addr_is_null(&addr)); \ + tt_int_op(port, OP_EQ, 0); \ + } else { \ + tt_assert(tor_addr_family(&addr) == AF_INET || \ + tor_addr_family(&addr) == AF_INET6); \ + tt_int_op(port, OP_EQ, expect_success_port); \ + } \ + STMT_END + /* Test that addr_str successfully parses as a canonical IPv4 address. * Check for successful parsing using: * - tor_addr_parse(), * - tor_addr_port_parse() with a default port, * - tor_lookup_hostname(), * - tor_addr_lookup() with AF_INET, - * - tor_addr_lookup() with AF_UNSPEC. + * - tor_addr_lookup() with AF_UNSPEC, + * - tor_addr_port_lookup(), with a zero port. * Check for failures using: * - tor_addr_port_parse() without a default port, because there is no port, - * - tor_addr_lookup() with AF_INET6. + * - tor_addr_lookup() with AF_INET6, + * - tor_addr_port_lookup(), because there is no port. */ #define TEST_ADDR_V4_PARSE_CANONICAL(addr_str) \ STMT_BEGIN \ @@ -905,6 +974,7 @@ test_addr_ip6_helpers(void *arg) TEST_ADDR_PORT_PARSE_FMT(addr_str, 111, AF_INET, 0, \ addr_str, 111); \ TEST_ADDR_V4_LOOKUP_HOSTNAME(addr_str, addr_str); \ + TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET, 0, addr_str, 0); \ TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET, AF_INET, 0, addr_str); \ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET, 0, addr_str); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ @@ -917,7 +987,8 @@ test_addr_ip6_helpers(void *arg) * - tor_addr_parse(), * - tor_addr_port_parse() with a default port, * - tor_addr_lookup() with AF_INET6, - * - tor_addr_lookup() with AF_UNSPEC. + * - tor_addr_lookup() with AF_UNSPEC, + * - tor_addr_port_lookup(), with a zero port. * Check for failures using: * - tor_addr_port_parse() without a default port, because there is no port, * - tor_lookup_hostname(), because it only supports IPv4, @@ -932,6 +1003,8 @@ test_addr_ip6_helpers(void *arg) addr_str); \ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET6, fmt_decorated, \ addr_str); \ + TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET6, fmt_decorated, addr_str, \ + 0); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \ TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET); \ @@ -943,7 +1016,8 @@ test_addr_ip6_helpers(void *arg) * - tor_addr_parse(), * - tor_addr_port_parse() with a default port, * - tor_addr_lookup() with AF_INET6, - * - tor_addr_lookup() with AF_UNSPEC. + * - tor_addr_lookup() with AF_UNSPEC, + * - tor_addr_port_lookup(), with a zero port. * Check for failures using: * - tor_addr_port_parse() without a default port, because there is no port. * - tor_lookup_hostname(), because it only supports IPv4, @@ -958,6 +1032,8 @@ test_addr_ip6_helpers(void *arg) expect_str); \ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET6, fmt_decorated, \ expect_str); \ + TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET6, fmt_decorated, expect_str, \ + 0); \ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \ TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \ TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET); \ @@ -967,7 +1043,8 @@ test_addr_ip6_helpers(void *arg) * string expect_str, and port expect_port. * Check for successful parsing using: * - tor_addr_port_parse() without a default port, - * - tor_addr_port_parse() with a default port. + * - tor_addr_port_parse() with a default port, + * - tor_addr_port_lookup(). * Check for failures using: * - tor_addr_parse(), because there is a port, * - tor_lookup_hostname(), because there is a port. @@ -980,6 +1057,8 @@ test_addr_ip6_helpers(void *arg) expect_port); \ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 444, AF_INET, 0, expect_str, \ expect_port); \ + TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, AF_INET, 0, expect_str, \ + expect_port); \ TEST_ADDR_PARSE_XFAIL(addr_port_str); \ TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \ @@ -991,7 +1070,8 @@ test_addr_ip6_helpers(void *arg) * IPv6 address string expect_str, and port expect_port. * Check for successful parsing using: * - tor_addr_port_parse() without a default port, - * - tor_addr_port_parse() with a default port. + * - tor_addr_port_parse() with a default port, + * - tor_addr_port_lookup(). * Check for failures using: * - tor_addr_parse(), because there is a port, * - tor_lookup_hostname(), because there is a port, and because it only @@ -1005,6 +1085,8 @@ test_addr_ip6_helpers(void *arg) expect_port); \ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 555, AF_INET6, 0, expect_str, \ expect_port); \ + TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, AF_INET6, 0, expect_str, \ + expect_port); \ TEST_ADDR_PARSE_XFAIL(addr_port_str); \ TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET6); \ @@ -1012,13 +1094,14 @@ test_addr_ip6_helpers(void *arg) TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \ STMT_END -/* Test that addr_str fails to parse due to a bad address or port. +/* Test that bad_str fails to parse due to a bad address or port. * Check for failures using: * - tor_addr_parse(), * - tor_addr_port_parse() without a default port, * - tor_addr_port_parse() with a default port, * - tor_lookup_hostname(), - * - tor_addr_lookup(), regardless of the address family. + * - tor_addr_lookup(), regardless of the address family, + * - tor_addr_port_lookup(). */ #define TEST_ADDR_PARSE_XFAIL_MALFORMED(bad_str) \ STMT_BEGIN \ @@ -1029,12 +1112,14 @@ test_addr_ip6_helpers(void *arg) TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_UNSPEC); \ TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_INET); \ TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_INET6); \ + TEST_ADDR_PORT_LOOKUP_XFAIL(bad_str); \ STMT_END /* Test that host_str is treated as a hostname, and not an address. * Check for success or failure using the network-dependent functions: * - tor_lookup_hostname(), - * - tor_addr_lookup(), regardless of the address family. + * - tor_addr_lookup(), regardless of the address family, + * - tor_addr_port_lookup(), expecting a zero port. * Check for failures using: * - tor_addr_parse(), * - tor_addr_port_parse() without a default port, @@ -1046,6 +1131,7 @@ test_addr_ip6_helpers(void *arg) TEST_HOST_LOOKUP(host_str, AF_UNSPEC); \ TEST_HOST_LOOKUP(host_str, AF_INET); \ TEST_HOST_LOOKUP(host_str, AF_INET6); \ + TEST_HOST_PORT_LOOKUP(host_str, 0); \ TEST_ADDR_PARSE_XFAIL(host_str); \ TEST_ADDR_PORT_PARSE_XFAIL(host_str, -1); \ TEST_ADDR_PORT_PARSE_XFAIL(host_str, 777); \ @@ -1053,6 +1139,9 @@ test_addr_ip6_helpers(void *arg) /* Test that host_port_str is treated as a hostname and port, and not a * hostname or an address. + * Check for success or failure using the network-dependent function: + * - tor_addr_port_lookup(), expecting expect_success_port if the lookup is + * successful. * Check for failures using: * - tor_addr_parse(), * - tor_addr_port_parse() without a default port, @@ -1061,8 +1150,9 @@ test_addr_ip6_helpers(void *arg) * - tor_addr_lookup(), regardless of the address family, because it doesn't * support ports. */ -#define TEST_HOSTNAME_PORT(host_port_str) \ +#define TEST_HOSTNAME_PORT(host_port_str, expect_success_port) \ STMT_BEGIN \ + TEST_HOST_PORT_LOOKUP(host_port_str, expect_success_port); \ TEST_ADDR_PARSE_XFAIL(host_port_str); \ TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, -1); \ TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, 888); \ @@ -1080,21 +1170,51 @@ test_addr_parse(void *arg) /* Correct calls. */ TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.1"); + TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.2"); - TEST_ADDR_V6_PARSE_CANONICAL("11:22::33:44", 0); TEST_ADDR_V6_PARSE_CANONICAL("[11:22::33:44]", 1); + TEST_ADDR_V6_PARSE_CANONICAL("[::1]", 1); + TEST_ADDR_V6_PARSE_CANONICAL("[::]", 1); + TEST_ADDR_V6_PARSE_CANONICAL("[2::]", 1); + TEST_ADDR_V6_PARSE_CANONICAL("[11:22:33:44:55:66:77:88]", 1); + /* Allow IPv6 without square brackets, when there is no port, but only if + * there is a default port */ + TEST_ADDR_V6_PARSE_CANONICAL("11:22::33:44", 0); + TEST_ADDR_V6_PARSE_CANONICAL("::1", 0); + TEST_ADDR_V6_PARSE_CANONICAL("::", 0); + TEST_ADDR_V6_PARSE_CANONICAL("2::", 0); + TEST_ADDR_V6_PARSE_CANONICAL("11:22:33:44:55:66:77:88", 0); + + /* IPv6-mapped IPv4 addresses. Tor doesn't really use these. */ TEST_ADDR_V6_PARSE("11:22:33:44:55:66:1.2.3.4", 0, "11:22:33:44:55:66:102:304"); TEST_ADDR_V6_PARSE("11:22::33:44:1.2.3.4", 0, "11:22::33:44:102:304"); + /* Ports. */ + TEST_ADDR_V4_PORT_PARSE("192.0.2.1:1234", "192.0.2.1", 1234); + TEST_ADDR_V6_PORT_PARSE("[::1]:1234", "::1", 1234); + + /* Host names. */ + TEST_HOSTNAME("localhost"); + TEST_HOSTNAME_PORT("localhost:1234", 1234); + TEST_HOSTNAME_PORT("localhost:0", 0); + + TEST_HOSTNAME("torproject.org"); + TEST_HOSTNAME_PORT("torproject.org:56", 56); + + TEST_HOSTNAME("probably-not-a-valid-dns.name-tld"); + TEST_HOSTNAME_PORT("probably-not-a-valid-dns.name-tld:789", 789); + + /* Malformed addresses. */ /* Empty string. */ TEST_ADDR_PARSE_XFAIL_MALFORMED(""); /* Square brackets around IPv4 address. */ TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.1]"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.3]:12345"); /* Only left square bracket. */ TEST_ADDR_PARSE_XFAIL_MALFORMED("[11:22::33:44"); @@ -1107,22 +1227,60 @@ test_addr_parse(void *arg) /* Trailing colon. */ TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:"); - /* Too many hex words in IPv4-mapped IPv6 address. */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22:33:44:55:66:77:88:1.2.3.4"); + /* Bad port. */ + TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:66666"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:77777"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:88888"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:99999"); - /* IPv6 address with port and no brackets */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:12345"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:-1"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:-2"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:-3"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:-4"); + + TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:1 bad"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:bad-port"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:bad-port-1"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:1-bad-port"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:1-bad-port"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:1-bad-port-1"); + + /* Bad hostname */ + TEST_ADDR_PARSE_XFAIL_MALFORMED("definitely invalid"); + TEST_ADDR_PARSE_XFAIL_MALFORMED("definitely invalid:22222"); + + /* Ambiguous cases */ + /* Too many hex words in IPv4-mapped IPv6 address. + * But some OS host lookup routines accept it as a hostname, or + * as an IP address?? (I assume they discard unused characters). */ + TEST_HOSTNAME("11:22:33:44:55:66:77:88:1.2.3.4"); + + /* IPv6 address with port and no brackets + * We reject it, but some OS host lookup routines accept it as an + * IPv6 address:port ? */ + TEST_HOSTNAME_PORT("11:22::33:44:12345", 12345); /* Is it a port, or are there too many hex words? - * We reject it either way. */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22:33:44:55:66:77:88:99"); + * We reject it either way, but some OS host lookup routines accept it as an + * IPv6 address:port */ + TEST_HOSTNAME_PORT("11:22:33:44:55:66:77:88:99", 99); /* But we accept it if it has square brackets. */ TEST_ADDR_V6_PORT_PARSE("[11:22:33:44:55:66:77:88]:99", "11:22:33:44:55:66:77:88",99); - /* This is an IPv6 address */ - TEST_ADDR_V6_PARSE_CANONICAL("11:22:33:44:55:66:77:88", 0); - TEST_ADDR_V6_PARSE_CANONICAL("[11:22:33:44:55:66:77:88]", 1); + /* Bad IPv4 address + * We reject it, but some OS host lookup routines accept it as an + * IPv4 address[:port], with a zero last octet */ + TEST_HOSTNAME("192.0.1"); + TEST_HOSTNAME_PORT("192.0.2:1234", 1234); + + /* More bad IPv6 addresses and ports: no brackets + * We reject it, but some OS host lookup routines accept it as an + * IPv6 address[:port] */ + TEST_HOSTNAME_PORT("::1:12345", 12345); + TEST_HOSTNAME_PORT("11:22::33:44:12345", 12345); /* And this is an ambiguous case, which is interpreted as an IPv6 address. */ TEST_ADDR_V6_PARSE_CANONICAL("11:22::88:99", 0); @@ -1131,37 +1289,6 @@ test_addr_parse(void *arg) TEST_ADDR_V6_PORT_PARSE("[11:22::88]:99", "11:22::88",99); - /* Correct calls. */ - TEST_ADDR_V4_PORT_PARSE("192.0.2.1:1234", "192.0.2.1", 1234); - TEST_ADDR_V6_PORT_PARSE("[::1]:1234", "::1", 1234); - - /* Domain name. */ - TEST_HOSTNAME("localhost"); - TEST_HOSTNAME_PORT("localhost:1234"); - TEST_HOSTNAME("torproject.org"); - TEST_HOSTNAME_PORT("torproject.org:1234"); - - /* Only IP. */ - TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.2"); - TEST_ADDR_V6_PARSE_CANONICAL("[::1]", 1); - - /* Allow IPv6 without square brackets, when there is no port, but only if - * there is a default port */ - TEST_ADDR_V6_PARSE_CANONICAL("::1", 0); - - /* Bad port. */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:66666"); - - /* Bad IPv4 address */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2:1234"); - - /* Bad IPv4 address and port: brackets */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.3]:12345"); - - /* Bad IPv6 addresses and ports: no brackets */ - TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:12345"); - TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:12345"); - done: ; }