diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-07-10 14:48:12 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-07-10 14:48:12 -0400 |
commit | 422abd4fa3c2c9c10f4e7f83eced7416785e89c4 (patch) | |
tree | 51a1644fa11f08dc438bf2802201fd52a370cef3 /src/lib | |
parent | ef106ce7884b0af7adcf9f3965ebbe843a47912c (diff) | |
parent | a2c44a7a7e3810bb18121561f012830da696724d (diff) | |
download | tor-422abd4fa3c2c9c10f4e7f83eced7416785e89c4.tar.gz tor-422abd4fa3c2c9c10f4e7f83eced7416785e89c4.zip |
Merge branch 'ticket26526_26532'
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/net/address.c | 223 | ||||
-rw-r--r-- | src/lib/net/address.h | 9 | ||||
-rw-r--r-- | src/lib/net/inaddr.c (renamed from src/lib/net/ipv6.c) | 57 | ||||
-rw-r--r-- | src/lib/net/inaddr.h (renamed from src/lib/net/ipv4.h) | 14 | ||||
-rw-r--r-- | src/lib/net/inaddr_st.h (renamed from src/lib/net/ipv6.h) | 21 | ||||
-rw-r--r-- | src/lib/net/include.am | 7 | ||||
-rw-r--r-- | src/lib/net/ipv4.c | 57 | ||||
-rw-r--r-- | src/lib/net/resolve.c | 183 | ||||
-rw-r--r-- | src/lib/net/resolve.h | 8 |
9 files changed, 272 insertions, 307 deletions
diff --git a/src/lib/net/address.c b/src/lib/net/address.c index f3eddca7bb..3b624da096 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -6,6 +6,9 @@ /** * \file address.c * \brief Functions to use and manipulate the tor_addr_t structure. + * + * This module doesn't have any support for the libc resolver: that is all in + * resolve.c. **/ #define ADDRESS_PRIVATE @@ -37,13 +40,12 @@ #include "lib/net/address.h" #include "lib/net/socket.h" -#include "lib/net/resolve.h" #include "lib/container/smartlist.h" #include "lib/ctime/di_ops.h" #include "lib/log/torlog.h" #include "lib/log/escape.h" #include "lib/malloc/util_malloc.h" -#include "lib/net/ipv4.h" +#include "lib/net/inaddr.h" #include "lib/string/compat_ctype.h" #include "lib/string/compat_string.h" #include "lib/string/parse_int.h" @@ -234,127 +236,6 @@ tor_addr_make_null(tor_addr_t *a, sa_family_t family) a->family = family; } -/** 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) */ - } -} - /** Return true iff <b>ip</b> is an IP reserved to localhost or local networks * in RFC1918 or RFC4193 or RFC4291. (fec0::/10, deprecated by RFC3879, is * also treated as internal for now.) @@ -1324,64 +1205,6 @@ tor_addr_parse(tor_addr_t *addr, const char *src) 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. */ -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 _WIN32 typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)( ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG); @@ -1927,7 +1750,7 @@ 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 addr_port_lookup() doesn't + /* We need to check for IPv6 manually because the logic below doesn't * do a good job on IPv6 addresses that lack a port. */ if (tor_addr_parse(&a_tmp, addrport) == AF_INET6) { *port_out = 0; @@ -1935,30 +1758,11 @@ tor_addr_port_split(int severity, const char *addrport, return 0; } - return addr_port_lookup(severity, addrport, address_out, NULL, port_out); -} - -/** Parse a string of the form "host[:port]" from <b>addrport</b>. If - * <b>address</b> is provided, set *<b>address</b> to a copy of the - * host portion of the string. If <b>addr</b> is provided, try to - * resolve the host portion of the string and store it into - * *<b>addr</b> (in host byte order). If <b>port_out</b> is provided, - * store the port number into *<b>port_out</b>, or 0 if no port is given. - * If <b>port_out</b> is NULL, then there must be no port number in - * <b>addrport</b>. - * Return 0 on success, -1 on failure. - */ -int -addr_port_lookup(int severity, const char *addrport, char **address, - uint32_t *addr, uint16_t *port_out) -{ const char *colon; char *address_ = NULL; int port_; int ok = 1; - tor_assert(addrport); - colon = strrchr(addrport, ':'); if (colon) { address_ = tor_strndup(addrport, colon-addrport); @@ -1980,22 +1784,13 @@ addr_port_lookup(int severity, const char *addrport, char **address, port_ = 0; } - if (addr) { - /* There's an addr pointer, so we need to resolve the hostname. */ - if (tor_lookup_hostname(address_,addr)) { - log_fn(severity, LD_NET, "Couldn't look up %s", escaped(address_)); - ok = 0; - *addr = 0; - } - } - - if (address && ok) { - *address = address_; + if (ok) { + *address_out = address_; } else { - if (address) - *address = NULL; + *address_out = NULL; tor_free(address_); } + if (port_out) *port_out = ok ? ((uint16_t) port_) : 0; diff --git a/src/lib/net/address.h b/src/lib/net/address.h index f8ea573c30..e857b4068b 100644 --- a/src/lib/net/address.h +++ b/src/lib/net/address.h @@ -14,7 +14,7 @@ #include "orconfig.h" #include "lib/cc/torint.h" #include "lib/log/util_bug.h" -#include "lib/net/ipv6.h" +#include "lib/net/inaddr_st.h" #include "lib/net/nettypes.h" #ifdef HAVE_NETINET_IN_H @@ -204,8 +204,6 @@ tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u) */ #define TOR_ADDR_BUF_LEN 48 -MOCK_DECL(int, tor_addr_lookup,(const char *name, uint16_t family, - tor_addr_t *addr_out)); char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC; /** Wrapper function of fmt_addr_impl(). It does not decorate IPv6 @@ -263,9 +261,6 @@ int tor_addr_to_PTR_name(char *out, size_t outlen, int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, int family, int accept_regular); -int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, - uint16_t *port_out); - /* Does the address * yield an AF_UNSPEC wildcard address (1), * which expands to corresponding wildcard IPv4 and IPv6 rules, and do we * allow *4 and *6 for IPv4 and IPv6 wildcards, respectively; @@ -330,8 +325,6 @@ int tor_addr_port_parse(int severity, const char *addrport, int tor_addr_hostname_is_local(const char *name); /* IPv4 helpers */ -int addr_port_lookup(int severity, const char *addrport, char **address, - uint32_t *addr, uint16_t *port_out); int parse_port_range(const char *port, uint16_t *port_min_out, uint16_t *port_max_out); int addr_mask_get_bits(uint32_t mask); diff --git a/src/lib/net/ipv6.c b/src/lib/net/inaddr.c index 630d6f1db4..dcd8fcdd65 100644 --- a/src/lib/net/ipv6.c +++ b/src/lib/net/inaddr.c @@ -4,20 +4,20 @@ /* See LICENSE for licensing information */ /** - * \file ipv6.c - * \brief Functions for encoding and decoding IPv6 addresses - * - * (Because these functions are generic, they can also handle IPv4 addresses). + * \file inaddr.c + * \brief Convert in_addr and in6_addr to and from strings. **/ -#include "lib/net/ipv6.h" -#include "lib/net/ipv4.h" -#include "lib/string/util_string.h" -#include "lib/string/compat_string.h" +#include "lib/net/inaddr.h" + +#include "lib/cc/torint.h" +#include "lib/log/util_bug.h" +#include "lib/net/inaddr_st.h" #include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" #include "lib/string/printf.h" #include "lib/string/scanf.h" -#include "lib/log/util_bug.h" +#include "lib/string/util_string.h" #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> @@ -26,6 +26,45 @@ #include <stdlib.h> #include <string.h> +#ifdef _WIN32 +#include <winsock2.h> +#endif + +/** Set *addr to the IP address (in dotted-quad notation) stored in *str. + * Return 1 on success, 0 if *str is badly formatted. + * (Like inet_aton(str,addr), but works on Windows and Solaris.) + */ +int +tor_inet_aton(const char *str, struct in_addr* addr) +{ + unsigned a,b,c,d; + char more; + if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4) + return 0; + if (a > 255) return 0; + if (b > 255) return 0; + if (c > 255) return 0; + if (d > 255) return 0; + addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); + return 1; +} + +/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual), + * write it as a string into the <b>buf_len</b>-byte buffer in + * <b>buf</b>. Returns a non-negative integer on success. + * Returns -1 on failure. + */ +int +tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) +{ + uint32_t a = ntohl(in->s_addr); + return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", + (int)(uint8_t)((a>>24)&0xff), + (int)(uint8_t)((a>>16)&0xff), + (int)(uint8_t)((a>>8 )&0xff), + (int)(uint8_t)((a )&0xff)); +} + /** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns diff --git a/src/lib/net/ipv4.h b/src/lib/net/inaddr.h index 0127f09e09..121025a126 100644 --- a/src/lib/net/ipv4.h +++ b/src/lib/net/inaddr.h @@ -4,18 +4,24 @@ /* See LICENSE for licensing information */ /** - * \file ipv4.h - * \brief Header for ipv4.c + * \file inaddr.h + * \brief Header for inaddr.c. **/ -#ifndef TOR_IPV4_H -#define TOR_IPV4_H +#ifndef TOR_INADDR_H +#define TOR_INADDR_H + +#include "orconfig.h" #include <stddef.h> struct in_addr; + int tor_inet_aton(const char *str, struct in_addr *addr); /** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/ #define INET_NTOA_BUF_LEN 16 int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); +const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); +int tor_inet_pton(int af, const char *src, void *dst); + #endif diff --git a/src/lib/net/ipv6.h b/src/lib/net/inaddr_st.h index 4e5ef4da88..cc72621e99 100644 --- a/src/lib/net/ipv6.h +++ b/src/lib/net/inaddr_st.h @@ -4,25 +4,29 @@ /* See LICENSE for licensing information */ /** - * \file ipv6.h - * \brief Header for ipv6.c + * \file inaddr_st.h + * + * \brief Define in6_addr, its members, and related types on platforms that + * lack it. **/ -#ifndef TOR_IPV6_H -#define TOR_IPV6_H +#ifndef TOR_INADDR_ST_H +#define TOR_INADDR_ST_H -#include "orconfig.h" -#include <stddef.h> #ifdef HAVE_NETINET_IN6_H #include <netinet/in6.h> #endif + #ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h> #endif + #include "lib/cc/torint.h" +struct in_addr; + /** Implementation of struct in6_addr for platforms that do not have it. * Generally, these platforms are ones without IPv6 support, but we want to * have a working in6_addr there anyway, so we can use it to parse IPv6 @@ -85,7 +89,4 @@ struct sockaddr_in6 { }; #endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */ -const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); -int tor_inet_pton(int af, const char *src, void *dst); - -#endif +#endif /* TOR_INADDR_ST_H */ diff --git a/src/lib/net/include.am b/src/lib/net/include.am index 6fda173614..67db0d5af2 100644 --- a/src/lib/net/include.am +++ b/src/lib/net/include.am @@ -10,8 +10,7 @@ src_lib_libtor_net_a_SOURCES = \ src/lib/net/alertsock.c \ src/lib/net/buffers_net.c \ src/lib/net/gethostname.c \ - src/lib/net/ipv4.c \ - src/lib/net/ipv6.c \ + src/lib/net/inaddr.c \ src/lib/net/resolve.c \ src/lib/net/socket.c @@ -25,8 +24,8 @@ noinst_HEADERS += \ src/lib/net/alertsock.h \ src/lib/net/buffers_net.h \ src/lib/net/gethostname.h \ - src/lib/net/ipv4.h \ - src/lib/net/ipv6.h \ + src/lib/net/inaddr.h \ + src/lib/net/inaddr_st.h \ src/lib/net/nettypes.h \ src/lib/net/resolve.h \ src/lib/net/socket.h \ diff --git a/src/lib/net/ipv4.c b/src/lib/net/ipv4.c deleted file mode 100644 index db1429f49c..0000000000 --- a/src/lib/net/ipv4.c +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file ipv4.c - * \brief Functions for encoding and decoding IPv4 addresses into strings - **/ - -#include "orconfig.h" -#include "lib/cc/torint.h" -#include "lib/net/ipv4.h" -#include "lib/string/printf.h" -#include "lib/string/scanf.h" - -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef _WIN32 -#include <winsock2.h> -#endif - -/** Set *addr to the IP address (in dotted-quad notation) stored in *str. - * Return 1 on success, 0 if *str is badly formatted. - * (Like inet_aton(str,addr), but works on Windows and Solaris.) - */ -int -tor_inet_aton(const char *str, struct in_addr* addr) -{ - unsigned a,b,c,d; - char more; - if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4) - return 0; - if (a > 255) return 0; - if (b > 255) return 0; - if (c > 255) return 0; - if (d > 255) return 0; - addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); - return 1; -} - -/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual), - * write it as a string into the <b>buf_len</b>-byte buffer in - * <b>buf</b>. Returns a non-negative integer on success. - * Returns -1 on failure. - */ -int -tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) -{ - uint32_t a = ntohl(in->s_addr); - return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", - (int)(uint8_t)((a>>24)&0xff), - (int)(uint8_t)((a>>16)&0xff), - (int)(uint8_t)((a>>8 )&0xff), - (int)(uint8_t)((a )&0xff)); -} 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; diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h index c91aecfee4..bf870c44c4 100644 --- a/src/lib/net/resolve.h +++ b/src/lib/net/resolve.h @@ -22,7 +22,13 @@ #define USE_SANDBOX_GETADDRINFO #endif -MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr)); +struct tor_addr_t; + +MOCK_DECL(int, tor_lookup_hostname,(const char *name, uint32_t *addr)); +MOCK_DECL(int, tor_addr_lookup,(const char *name, uint16_t family, + struct tor_addr_t *addr_out)); +int tor_addr_port_lookup(const char *s, struct tor_addr_t *addr_out, + uint16_t *port_out); struct addrinfo; #ifdef USE_SANDBOX_GETADDRINFO |