Merge branch 'bug30721_squashed'

This commit is contained in:
Nick Mathewson
2019-06-26 09:57:20 -04:00
5 changed files with 843 additions and 276 deletions
+84 -26
View File
@@ -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;
}
+212 -127
View File
@@ -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;
}
/* 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);
if (port) {
portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL);
if (!portval)
goto err;
} else {
portval = 0;
}
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
+537 -122
View File
@@ -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");
/* Correct calls. */
TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.1");
TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.2");
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]", 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);
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");
/* 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);
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");
/* 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. */
r= tor_addr_parse(&addr, "");
tt_int_op(r,OP_EQ, -1);
TEST_ADDR_PARSE_XFAIL_MALFORMED("");
/* 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_MALFORMED("[192.0.2.1]");
TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.3]:12345");
/* Only left square bracket. */
r= tor_addr_parse(&addr, "[11:22::33:44");
tt_int_op(r,OP_EQ, -1);
TEST_ADDR_PARSE_XFAIL_MALFORMED("[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_MALFORMED("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_MALFORMED(":11:22::33:44");
/* 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);
/* Only IP. */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.2",
&addr, &port, -1);
tt_int_op(r, OP_EQ, -1);
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);
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);
TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:");
TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:");
TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:");
/* 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_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");
/* 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_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");
/* Bad IP address */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2:1234",
&addr, &port, -1);
tt_int_op(r, OP_EQ, -1);
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");
/* 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);
/* Bad hostname */
TEST_ADDR_PARSE_XFAIL_MALFORMED("definitely invalid");
TEST_ADDR_PARSE_XFAIL_MALFORMED("definitely invalid:22222");
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);
/* 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:
;