Commit 422abd4f authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Merge branch 'ticket26526_26532'

parents ef106ce7 a2c44a7a
o Code simplification and refactoring:
- Utility functions that can perform a DNS lookup are now wholly
separated from those that can't, in separate headers and C
modules. Closes ticket 26526.
o Minor features (tor-resolve):
- The tor-resolve utility can now be used with IPv6 SOCKS proxies.
Side-effect of the refactoring for ticket 26526.
......@@ -106,6 +106,7 @@
#include "feature/client/transports.h"
#include "feature/relay/ext_orport.h"
#include "feature/dircommon/voting_schedule.h"
#include "lib/net/resolve.h"
#ifdef _WIN32
#include <shlobj.h>
#endif
......@@ -6459,26 +6460,17 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
addrport = smartlist_get(items, 0);
smartlist_del_keeporder(items, 0);
const char *addrport_sep = strchr(addrport, ':');
if (!addrport_sep) {
log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s' "
"(':' not found)", addrport);
if (tor_addr_port_split(LOG_WARN, addrport, &address, &dir_port) < 0) {
log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s'.", addrport);
goto err;
}
address = tor_strndup(addrport, addrport_sep - addrport);
if (!string_is_valid_ipv4_address(address)) {
log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s' "
"(invalid IPv4 address)", address);
goto err;
}
tor_free(address);
if (addr_port_lookup(LOG_WARN, addrport, &address, NULL, &dir_port)<0) {
log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s'", addrport);
goto err;
}
if (!dir_port) {
log_warn(LD_CONFIG, "Missing port in DirAuthority address '%s'",addrport);
goto err;
......
......@@ -43,6 +43,7 @@
#include "lib/sandbox/sandbox.h"
#include "app/config/statefile.h"
#include "lib/encoding/confline.h"
#include "lib/net/resolve.h"
#include "app/config/or_state_st.h"
......
......@@ -116,6 +116,7 @@
#include "lib/sandbox/sandbox.h"
#include "lib/fs/lockfile.h"
#include "lib/net/buffers_net.h"
#include "lib/net/resolve.h"
#include "lib/tls/tortls.h"
#include "lib/evloop/compat_libevent.h"
#include "lib/encoding/confline.h"
......
......@@ -49,9 +49,7 @@
#include "lib/log/util_bug.h"
#include "lib/malloc/util_malloc.h"
#include "lib/net/address.h"
#include "lib/net/ipv4.h"
#include "lib/net/ipv6.h"
#include "lib/net/resolve.h"
#include "lib/net/inaddr.h"
#include "lib/net/socket.h"
#include "lib/string/compat_ctype.h"
#include "lib/string/compat_string.h"
......
......@@ -123,6 +123,7 @@
#include "lib/sandbox/sandbox.h"
#include "feature/nodelist/torcert.h"
#include "lib/math/fp.h"
#include "lib/net/resolve.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/mode.h"
......
......@@ -37,6 +37,7 @@
#include "feature/nodelist/routerparse.h"
#include "feature/nodelist/routerset.h"
#include "lib/encoding/confline.h"
#include "lib/net/resolve.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
......
......@@ -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;
......
......@@ -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);
......
......@@ -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
......
......@@ -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
......@@ -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 */
......@@ -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 \
......
/* 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);