diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-07-10 12:56:09 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-07-10 13:00:02 -0400 |
commit | c2ddb7b231c640a292d261af265dd423cee09179 (patch) | |
tree | a9c125f730396d4e7247b7c77628c3b306540658 /src/lib/net/resolve.c | |
parent | 5d8336c182777c36ebff561b420d67fcafb9a9f7 (diff) | |
download | tor-c2ddb7b231c640a292d261af265dd423cee09179.tar.gz tor-c2ddb7b231c640a292d261af265dd423cee09179.zip |
Move tor_addr_{,port_}lookup to resolve.c
Diffstat (limited to 'src/lib/net/resolve.c')
-rw-r--r-- | src/lib/net/resolve.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index c620d4f6ab..ff9c93989a 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -9,8 +9,12 @@ **/ #include "lib/net/resolve.h" + #include "lib/net/address.h" +#include "lib/net/inaddr.h" #include "lib/malloc/util_malloc.h" +#include "lib/string/parse_int.h" +#include "lib/string/util_string.h" #include "siphash.h" #include "ht.h" @@ -52,6 +56,185 @@ tor_lookup_hostname,(const char *name, uint32_t *addr)) return -1; } +/** 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. + * + * Return 0 on success, -1 on failure; 1 on transient failure. + */ +MOCK_IMPL(int, +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; + 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; + } else { +#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; +#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 +#endif /* defined(HAVE_GETADDRINFO) */ + } +} + +/** 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. */ +int +tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) +{ + const char *port; + tor_addr_t addr; + uint16_t portval; + char *tmp = NULL; + + 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; + } + + if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0) + goto err; + tor_free(tmp); + + if (port) { + portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL); + if (!portval) + goto err; + } else { + portval = 0; + } + + if (port_out) + *port_out = portval; + tor_addr_copy(addr_out, &addr); + + return 0; + err: + tor_free(tmp); + return -1; +} + #ifdef USE_SANDBOX_GETADDRINFO /** True if we should only return cached values */ static int sandbox_getaddrinfo_is_active = 0; |