aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-06-26 09:57:20 -0400
committerNick Mathewson <nickm@torproject.org>2019-06-26 09:57:20 -0400
commit089ef46063f49d9a0c8a4ebfdcf5ac2ca0bf5a1e (patch)
tree804556e9b22099de1d56cd27eeef0a4a5b410f97
parentc2a326d34f18b23f4e772f9290bde6bfa180c220 (diff)
parent6ef555bda0f7cc1248a133f197fcd0a5f92f5cf1 (diff)
downloadtor-089ef46063f49d9a0c8a4ebfdcf5ac2ca0bf5a1e.tar.gz
tor-089ef46063f49d9a0c8a4ebfdcf5ac2ca0bf5a1e.zip
Merge branch 'bug30721_squashed'
-rw-r--r--changes/bug3072110
-rw-r--r--scripts/maint/practracker/exceptions.txt1
-rw-r--r--src/lib/net/address.c110
-rw-r--r--src/lib/net/resolve.c339
-rw-r--r--src/test/test_addr.c675
5 files changed, 851 insertions, 284 deletions
diff --git a/changes/bug30721 b/changes/bug30721
new file mode 100644
index 0000000000..5ea4a14625
--- /dev/null
+++ b/changes/bug30721
@@ -0,0 +1,10 @@
+ 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/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt
index 03011b770b..3ed76a2bfd 100644
--- a/scripts/maint/practracker/exceptions.txt
+++ b/scripts/maint/practracker/exceptions.txt
@@ -266,7 +266,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/address.c b/src/lib/net/address.c
index 546af800a9..0a2c84caf2 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 <b>accept_regular</b> 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,
@@ -1187,17 +1188,22 @@ fmt_addr32(uint32_t addr)
}
/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. 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 <b>allow_ipv6_without_brackets</b> 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;
@@ -1211,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 <b>src</b> to a tor_addr_t <b>addr</b>. 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 <b>ifaddrs</b> structures
@@ -1718,6 +1749,11 @@ get_interface_address6_list,(int severity,
* form "ip" or "ip:0". Otherwise, accept those forms, and set
* *<b>port_out</b> to <b>default_port</b>.
*
+ * 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,
@@ -1727,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);
@@ -1736,28 +1773,47 @@ 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;
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;
}
/** Given an address of the form "host[:port]", try to divide it into its host
- * and port portions, setting *<b>address_out</b> to a newly allocated string
- * holding the address portion and *<b>port_out</b> to the port (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 *<b>address_out</b> to a newly allocated string holding the address
+ * portion, and *<b>port_out</b> to the port (or 0 if no port is given).
+ *
+ * Return 0 on success, -1 on failure. */
int
tor_addr_port_split(int severity, const char *addrport,
char **address_out, uint16_t *port_out)
@@ -1766,8 +1822,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);
@@ -1807,8 +1866,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 2dda491d14..e8d7d0d94d 100644
--- a/src/lib/net/resolve.c
+++ b/src/lib/net/resolve.c
@@ -35,6 +35,8 @@
* *<b>addr</b> 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.)
*/
@@ -45,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;
@@ -56,12 +63,125 @@ 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 <b>name</b>, and set
* *<b>addr</b> to the proper IP address and family. The <b>family</b>
* argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a
* <i>preferred</i> 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,169 +190,134 @@ 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;
+ int result = -1;
+
tor_assert(name);
tor_assert(addr);
tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
+
if (!*name) {
/* Empty address is an error. */
- return -1;
- } else if (tor_inet_pton(AF_INET, name, &iaddr)) {
- /* It's an IPv4 IP. */
- if (family == AF_INET6)
- return -1;
- tor_addr_from_in(addr, &iaddr);
- return 0;
- } else if (tor_inet_pton(AF_INET6, name, &iaddr6)) {
- if (family == AF_INET)
- return -1;
- tor_addr_from_in6(addr, &iaddr6);
- return 0;
+ goto permfail;
+ }
+
+ /* Is it an IP address? */
+ parsed_family = tor_addr_parse(addr, name);
+
+ if (parsed_family >= 0) {
+ /* If the IP address family matches, or was unspecified */
+ if (parsed_family == family || family == AF_UNSPEC) {
+ goto success;
+ } else {
+ 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 <b>s</b>, resolve the
* address as needed, and put the result in <b>addr_out</b> and (optionally)
- * <b>port_out</b>. Return 0 on success, negative on failure. */
+ * <b>port_out</b>.
+ *
+ * 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;
+ uint16_t portval = 0;
char *tmp = NULL;
+ int rv = 0;
+ int result;
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;
+ /* 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;
}
- if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0)
+ /* 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;
- tor_free(tmp);
- if (port) {
- portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL);
- if (!portval)
- goto err;
- } else {
- portval = 0;
- }
+ /* And feed the hostname to the lookup function. */
+ if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0)
+ goto err;
+ 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
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 05d8bf6c7b..0f50a43615 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -724,155 +724,570 @@ 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 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 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_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_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_port_lookup(), 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_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); \
+ 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_lookup() with AF_INET6,
+ * - 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,
+ * - 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_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); \
+ 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_lookup() with AF_INET6,
+ * - 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,
+ * - 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_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); \
+ STMT_END
+
+/* Test that addr_port_str successfully parses to the canonical IPv4 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_lookup().
+ * 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 \
+ 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_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); \
+ 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
+ * 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_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
+ * 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 \
+ 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_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); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \
+ STMT_END
+
+/* 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_port_lookup().
+ */
+#define TEST_ADDR_PARSE_XFAIL_MALFORMED(bad_str) \
+ STMT_BEGIN \
+ 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); \
+ 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_port_lookup(), expecting a zero port.
+ * 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_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); \
+ STMT_END
+
+/* 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,
+ * - 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, 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); \
+ 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(). */
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");
-
- 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");
-
- 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");
-
- 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");
- /* Empty string. */
- r= tor_addr_parse(&addr, "");
- tt_int_op(r,OP_EQ, -1);
+ /* Correct calls. */
+ TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.1");
+ TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.2");
- /* Square brackets around IPv4 address. */
- r= tor_addr_parse(&addr, "[192.0.2.1]");
- tt_int_op(r,OP_EQ, -1);
+ 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);
- /* Only left square bracket. */
- r= tor_addr_parse(&addr, "[11:22::33:44");
- tt_int_op(r,OP_EQ, -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);
- /* Only right square bracket. */
- r= tor_addr_parse(&addr, "11:22::33:44]");
- tt_int_op(r,OP_EQ, -1);
+ /* 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");
- /* Leading colon. */
- r= tor_addr_parse(&addr, ":11:22::33:44");
- tt_int_op(r,OP_EQ, -1);
+ TEST_ADDR_V6_PARSE("11:22::33:44:1.2.3.4", 0,
+ "11:22::33:44:102:304");
- /* Trailing colon. */
- r= tor_addr_parse(&addr, "11:22::33:44:");
- tt_int_op(r,OP_EQ, -1);
-
- /* 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);
-
- /* 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);
-
- 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);
-
- /* Domain name. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "torproject.org:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ /* 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);
- /* Only IP. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ /* Host names. */
+ TEST_HOSTNAME("localhost");
+ TEST_HOSTNAME_PORT("localhost:1234", 1234);
+ TEST_HOSTNAME_PORT("localhost:0", 0);
- 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_HOSTNAME("torproject.org");
+ TEST_HOSTNAME_PORT("torproject.org:56", 56);
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ TEST_HOSTNAME("probably-not-a-valid-dns.name-tld");
+ TEST_HOSTNAME_PORT("probably-not-a-valid-dns.name-tld:789", 789);
- 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);
+ /* Malformed addresses. */
+ /* Empty string. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("");
- /* 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);
+ /* 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 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);
+ /* Only left square bracket. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[11:22::33:44");
- /* Bad IP address */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ /* Only right square bracket. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44]");
+
+ /* Leading colon. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED(":11:22::33:44");
+
+ /* Trailing colon. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:");
- /* 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);
+ /* 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");
+
+ 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, 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);
+
+ /* 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);
+ /* 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);
done:
;