diff options
Diffstat (limited to 'src/lib/net/address.c')
-rw-r--r-- | src/lib/net/address.c | 304 |
1 files changed, 246 insertions, 58 deletions
diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 69004ddb0e..21794fb4fc 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -40,6 +40,7 @@ #include "lib/net/address.h" #include "lib/net/socket.h" +#include "lib/cc/ctassert.h" #include "lib/container/smartlist.h" #include "lib/ctime/di_ops.h" #include "lib/log/log.h" @@ -52,7 +53,7 @@ #include "lib/string/printf.h" #include "lib/string/util_string.h" -#include "siphash.h" +#include "ext/siphash.h" #ifdef HAVE_SYS_TIME_H #include <sys/time.h> @@ -96,8 +97,9 @@ * work correctly. Bail out here if we've found a platform where AF_UNSPEC * isn't 0. */ #if AF_UNSPEC != 0 -#error We rely on AF_UNSPEC being 0. Let us know about your platform, please! +#error "We rely on AF_UNSPEC being 0. Yours isn't. Please tell us more!" #endif +CTASSERT(AF_UNSPEC == 0); /** Convert the tor_addr_t in <b>a</b>, with port in <b>port</b>, into a * sockaddr object in *<b>sa_out</b> of object size <b>len</b>. If not enough @@ -337,7 +339,7 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) break; case AF_INET6: /* Shortest addr [ :: ] + \0 */ - if (len < (3 + (decorate ? 2u : 0u))) + if (len < (3u + (decorate ? 2 : 0))) return NULL; if (decorate) @@ -371,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, @@ -605,7 +608,8 @@ tor_addr_parse_mask_ports(const char *s, family = AF_INET; tor_addr_from_ipv4h(addr_out, 0); } else if (flags & TAPMP_STAR_IPV6_ONLY) { - static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + static uint8_t nil_bytes[16] = + { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; family = AF_INET6; tor_addr_from_ipv6_bytes(addr_out, nil_bytes); } else { @@ -626,7 +630,7 @@ tor_addr_parse_mask_ports(const char *s, tor_addr_from_ipv4h(addr_out, 0); any_flag = 1; } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) { - static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + static uint8_t nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; family = AF_INET6; tor_addr_from_ipv6_bytes(addr_out, nil_bytes); any_flag = 1; @@ -760,6 +764,15 @@ tor_addr_is_v4(const tor_addr_t *addr) return 0; /* Not IPv4 - unknown family or a full-blood IPv6 address */ } +/** Determine whether an address <b>addr</b> is an IPv6 (AF_INET6). Return + * true if so else false. */ +int +tor_addr_is_v6(const tor_addr_t *addr) +{ + tor_assert(addr); + return (tor_addr_family(addr) == AF_INET6); +} + /** Determine whether an address <b>addr</b> is null, either all zeroes or * belonging to family AF_UNSPEC. */ @@ -814,8 +827,12 @@ tor_addr_is_loopback(const tor_addr_t *addr) /* Is addr valid? * Checks that addr is non-NULL and not tor_addr_is_null(). - * If for_listening is true, IPv4 addr 0.0.0.0 is allowed. - * It means "bind to all addresses on the local machine". */ + * If for_listening is true, all IPv4 and IPv6 addresses are valid, including + * 0.0.0.0 (for IPv4) and :: (for IPv6). When listening, these addresses mean + * "bind to all addresses on the local machine". + * Otherwise, 0.0.0.0 and :: are invalid, because they are null addresses. + * All unspecified and unix addresses are invalid, regardless of for_listening. + */ int tor_addr_is_valid(const tor_addr_t *addr, int for_listening) { @@ -824,10 +841,11 @@ tor_addr_is_valid(const tor_addr_t *addr, int for_listening) return 0; } - /* Only allow IPv4 0.0.0.0 for_listening. */ - if (for_listening && addr->family == AF_INET - && tor_addr_to_ipv4h(addr) == 0) { - return 1; + /* Allow all IPv4 and IPv6 addresses, when for_listening is true */ + if (for_listening) { + if (addr->family == AF_INET || addr->family == AF_INET6) { + return 1; + } } /* Otherwise, the address is valid if it's not tor_addr_is_null() */ @@ -879,7 +897,7 @@ tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr) /** Set <b>dest</b> to equal the IPv6 address in the 16 bytes at * <b>ipv6_bytes</b>. */ void -tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes) +tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *ipv6_bytes) { tor_assert(dest); tor_assert(ipv6_bytes); @@ -892,7 +910,21 @@ tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes) void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6) { - tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr); + tor_addr_from_ipv6_bytes(dest, in6->s6_addr); +} + +/** Set the 16 bytes at <b>dest</b> to equal the IPv6 address <b>src</b>. + * <b>src</b> must be an IPv6 address, if it is not, log a warning, and clear + * <b>dest</b>. */ +void +tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src) +{ + tor_assert(dest); + tor_assert(src); + memset(dest, 0, 16); + IF_BUG_ONCE(src->family != AF_INET6) + return; + memcpy(dest, src->addr.in6_addr.s6_addr, 16); } /** Copy a tor_addr_t from <b>src</b> to <b>dest</b>. @@ -1166,57 +1198,159 @@ fmt_addr_impl(const tor_addr_t *addr, int decorate) const char * fmt_addrport(const tor_addr_t *addr, uint16_t port) { - /* Add space for a colon and up to 5 digits. */ - static char buf[TOR_ADDR_BUF_LEN + 6]; + static char buf[TOR_ADDRPORT_BUF_LEN]; tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port); return buf; } /** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4 * addresses. Also not thread-safe, also clobbers its return buffer on - * repeated calls. */ + * repeated calls. Clean internal buffer and return empty string on failure. */ const char * fmt_addr32(uint32_t addr) { static char buf[INET_NTOA_BUF_LEN]; struct in_addr in; + int success; + in.s_addr = htonl(addr); - tor_inet_ntoa(&in, buf, sizeof(buf)); + + success = tor_inet_ntoa(&in, buf, sizeof(buf)); + tor_assertf_nonfatal(success >= 0, + "Failed to convert IP 0x%08X (HBO) to string", addr); + + IF_BUG_ONCE(success < 0) { + memset(buf, 0, INET_NTOA_BUF_LEN); + } + + return buf; +} + +/** Like fmt_addrport(), but takes <b>addr</b> as a host-order IPv4 + * addresses. Also not thread-safe, also clobbers its return buffer on + * repeated calls. */ +const char * +fmt_addr32_port(uint32_t addr, uint16_t port) +{ + static char buf[INET_NTOA_BUF_LEN + 6]; + snprintf(buf, sizeof(buf), "%s:%u", fmt_addr32(addr), port); return buf; } +/** Return a string representing <b>family</b>. + * + * This string is a string constant, and must not be freed. + * This function is thread-safe. + */ +const char * +fmt_af_family(sa_family_t family) +{ + static int default_bug_once = 0; + + switch (family) { + case AF_INET6: + return "IPv6"; + case AF_INET: + return "IPv4"; + case AF_UNIX: + return "UNIX socket"; + case AF_UNSPEC: + return "unspecified"; + default: + if (!default_bug_once) { + log_warn(LD_BUG, "Called with unknown address family %d", + (int)family); + default_bug_once = 1; + } + return "unknown"; + } + //return "(unreachable code)"; +} + +/** Return a string representing the family of <b>addr</b>. + * + * This string is a string constant, and must not be freed. + * This function is thread-safe. + */ +const char * +fmt_addr_family(const tor_addr_t *addr) +{ + IF_BUG_ONCE(!addr) + return "NULL pointer"; + + return fmt_af_family(tor_addr_family(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; + tor_assert(addr && src); - if (src[0] == '[' && src[1]) + + size_t len = strlen(src); + + if (len && src[0] == '[' && src[len - 1] == ']') { + brackets_detected = 1; 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 (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 @@ -1352,7 +1486,7 @@ get_interface_addresses_win32(int severity, sa_family_t family) /* This is defined on Mac OS X */ #ifndef _SIZEOF_ADDR_IFREQ -#define _SIZEOF_ADDR_IFREQ sizeof +#define _SIZEOF_ADDR_IFREQ(x) sizeof(x) #endif /* Free ifc->ifc_buf safely. */ @@ -1371,10 +1505,10 @@ ifconf_free_ifc_buf(struct ifconf *ifc) * into smartlist of <b>tor_addr_t</b> structures. */ STATIC smartlist_t * -ifreq_to_smartlist(char *buf, size_t buflen) +ifreq_to_smartlist(const uint8_t *buf, size_t buflen) { smartlist_t *result = smartlist_new(); - char *end = buf + buflen; + const uint8_t *end = buf + buflen; /* These acrobatics are due to alignment issues which trigger * undefined behaviour traps on OSX. */ @@ -1448,7 +1582,7 @@ get_interface_addresses_ioctl(int severity, sa_family_t family) /* Ensure we have least IFREQ_SIZE bytes unused at the end. Otherwise, we * don't know if we got everything during ioctl. */ } while (mult * IFREQ_SIZE - ifc.ifc_len <= IFREQ_SIZE); - result = ifreq_to_smartlist(ifc.ifc_buf, ifc.ifc_len); + result = ifreq_to_smartlist((const uint8_t *)ifc.ifc_buf, ifc.ifc_len); done: if (fd >= 0) @@ -1597,15 +1731,19 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) /* Get a list of public or internal IPs in arbitrary order */ addrs = get_interface_address6_list(severity, family, 1); - /* Find the first non-internal address, or the last internal address - * Ideally, we want the default route, see #12377 for details */ + /* Find the first non-internal address, or the last internal address. + * Ideally, we want the default route; see #12377 for details. */ SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { tor_addr_copy(addr, a); + const bool is_internal = tor_addr_is_internal(a, 0); rv = 0; + log_debug(LD_NET, "Found %s interface address '%s'", + (is_internal ? "internal" : "external"), fmt_addr(addr)); + /* If we found a non-internal address, declare success. Otherwise, * keep looking. */ - if (!tor_addr_is_internal(a, 0)) + if (!is_internal) break; } SMARTLIST_FOREACH_END(a); @@ -1709,6 +1847,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, @@ -1718,6 +1861,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); @@ -1727,28 +1871,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) @@ -1757,8 +1920,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); @@ -1798,8 +1964,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; } @@ -1875,17 +2040,24 @@ parse_port_range(const char *port, uint16_t *port_min_out, } /** Given a host-order <b>addr</b>, call tor_inet_ntop() on it - * and return a strdup of the resulting address. + * and return a strdup of the resulting address. Return NULL if + * tor_inet_ntop() fails. */ char * tor_dup_ip(uint32_t addr) { + const char *ip_str; char buf[TOR_ADDR_BUF_LEN]; struct in_addr in; in.s_addr = htonl(addr); - tor_inet_ntop(AF_INET, &in, buf, sizeof(buf)); - return tor_strdup(buf); + ip_str = tor_inet_ntop(AF_INET, &in, buf, sizeof(buf)); + + tor_assertf_nonfatal(ip_str, "Failed to duplicate IP %08X", addr); + if (ip_str) + return tor_strdup(buf); + + return NULL; } /** @@ -1934,7 +2106,7 @@ tor_addr_port_new(const tor_addr_t *addr, uint16_t port) return ap; } -/** Return true iff <a>a</b> and <b>b</b> are the same address and port */ +/** Return true iff <b>a</b> and <b>b</b> are the same address and port */ int tor_addr_port_eq(const tor_addr_port_t *a, const tor_addr_port_t *b) @@ -1942,7 +2114,19 @@ tor_addr_port_eq(const tor_addr_port_t *a, return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port; } -/** Return true if <b>string</b> represents a valid IPv4 adddress in +/** + * Copy a tor_addr_port_t from @a source to @a dest. + **/ +void +tor_addr_port_copy(tor_addr_port_t *dest, + const tor_addr_port_t *source) +{ + tor_assert(dest); + tor_assert(source); + memcpy(dest, source, sizeof(tor_addr_port_t)); +} + +/** Return true if <b>string</b> represents a valid IPv4 address in * 'a.b.c.d' form. */ int @@ -2018,8 +2202,12 @@ string_is_valid_nonrfc_hostname(const char *string) smartlist_split_string(components,string,".",0,0); - if (BUG(smartlist_len(components) == 0)) - return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks. + if (BUG(smartlist_len(components) == 0)) { + // LCOV_EXCL_START should be impossible given the earlier checks. + smartlist_free(components); + return 0; + // LCOV_EXCL_STOP + } /* Allow a single terminating '.' used rarely to indicate domains * are FQDNs rather than relative. */ |