mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
Merge branch 'bug30721_squashed'
This commit is contained in:
@@ -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.
|
||||
@@ -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
|
||||
|
||||
+84
-26
@@ -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
@@ -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
@@ -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:
|
||||
;
|
||||
|
||||
Reference in New Issue
Block a user