aboutsummaryrefslogtreecommitdiff
path: root/src/lib/net/resolve.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-07-10 12:56:09 -0400
committerNick Mathewson <nickm@torproject.org>2018-07-10 13:00:02 -0400
commitc2ddb7b231c640a292d261af265dd423cee09179 (patch)
treea9c125f730396d4e7247b7c77628c3b306540658 /src/lib/net/resolve.c
parent5d8336c182777c36ebff561b420d67fcafb9a9f7 (diff)
downloadtor-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.c183
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;