diff options
Diffstat (limited to 'src/common/address.c')
-rw-r--r-- | src/common/address.c | 328 |
1 files changed, 239 insertions, 89 deletions
diff --git a/src/common/address.c b/src/common/address.c index 8591f387e6..42a116a91e 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2013, The Tor Project, Inc. */ + * Copyright (c) 2007-2015, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,24 +8,26 @@ * \brief Functions to use and manipulate the tor_addr_t structure. **/ -#include "orconfig.h" -#include "compat.h" -#include "util.h" -#include "address.h" -#include "torlog.h" -#include "container.h" -#include "sandbox.h" +#define ADDRESS_PRIVATE #ifdef _WIN32 -#include <process.h> -#include <windows.h> -#include <winsock2.h> /* For access to structs needed by GetAdaptersAddresses */ #undef _WIN32_WINNT #define _WIN32_WINNT 0x0501 +#include <process.h> +#include <winsock2.h> +#include <windows.h> #include <iphlpapi.h> #endif +#include "orconfig.h" +#include "compat.h" +#include "util.h" +#include "address.h" +#include "torlog.h" +#include "container.h" +#include "sandbox.h" + #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -89,13 +91,14 @@ tor_addr_to_sockaddr(const tor_addr_t *a, struct sockaddr *sa_out, socklen_t len) { + memset(sa_out, 0, len); + sa_family_t family = tor_addr_family(a); if (family == AF_INET) { struct sockaddr_in *sin; if (len < (int)sizeof(struct sockaddr_in)) return 0; sin = (struct sockaddr_in *)sa_out; - memset(sin, 0, sizeof(struct sockaddr_in)); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin->sin_len = sizeof(struct sockaddr_in); #endif @@ -108,7 +111,6 @@ tor_addr_to_sockaddr(const tor_addr_t *a, if (len < (int)sizeof(struct sockaddr_in6)) return 0; sin6 = (struct sockaddr_in6 *)sa_out; - memset(sin6, 0, sizeof(struct sockaddr_in6)); #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); #endif @@ -121,14 +123,26 @@ tor_addr_to_sockaddr(const tor_addr_t *a, } } +/** Set address <b>a</b> to zero. This address belongs to + * the AF_UNIX family. */ +static void +tor_addr_make_af_unix(tor_addr_t *a) +{ + memset(a, 0, sizeof(*a)); + a->family = AF_UNIX; +} + /** Set the tor_addr_t in <b>a</b> to contain the socket address contained in - * <b>sa</b>. */ + * <b>sa</b>. Return 0 on success and -1 on failure. */ int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, uint16_t *port_out) { tor_assert(a); tor_assert(sa); + + memset(a, 0, sizeof(*a)); + if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *) sa; tor_addr_from_ipv4n(a, sin->sin_addr.s_addr); @@ -139,6 +153,9 @@ tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, tor_addr_from_in6(a, &sin6->sin6_addr); if (port_out) *port_out = ntohs(sin6->sin6_port); + } else if (sa->sa_family == AF_UNIX) { + tor_addr_make_af_unix(a); + return 0; } else { tor_addr_make_unspec(a); return -1; @@ -323,17 +340,23 @@ tor_addr_is_internal_(const tor_addr_t *addr, int for_listening, { uint32_t iph4 = 0; uint32_t iph6[4]; - sa_family_t v_family; tor_assert(addr); - v_family = tor_addr_family(addr); + sa_family_t v_family = tor_addr_family(addr); if (v_family == AF_INET) { iph4 = tor_addr_to_ipv4h(addr); } else if (v_family == AF_INET6) { if (tor_addr_is_v4(addr)) { /* v4-mapped */ + uint32_t *addr32 = NULL; v_family = AF_INET; - iph4 = ntohl(tor_addr_to_in6_addr32(addr)[3]); + // Work around an incorrect NULL pointer dereference warning in + // "clang --analyze" due to limited analysis depth + addr32 = tor_addr_to_in6_addr32(addr); + // To improve performance, wrap this assertion in: + // #if !defined(__clang_analyzer__) || PARANOIA + tor_assert(addr32); + iph4 = ntohl(addr32[3]); } } @@ -412,6 +435,10 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) ptr = dest; } break; + case AF_UNIX: + tor_snprintf(dest, len, "AF_UNIX"); + ptr = dest; + break; default: return NULL; } @@ -465,7 +492,6 @@ tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, if (!strcasecmpend(address, ".ip6.arpa")) { const char *cp; - int i; int n0, n1; struct in6_addr in6; @@ -473,7 +499,7 @@ tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, return -1; cp = address; - for (i = 0; i < 16; ++i) { + for (int i = 0; i < 16; ++i) { n0 = hex_decode_digit(*cp++); /* The low-order nybble appears first. */ if (*cp++ != '.') return -1; /* Then a dot. */ n1 = hex_decode_digit(*cp++); /* The high-order nybble appears first. */ @@ -598,7 +624,7 @@ tor_addr_parse_mask_ports(const char *s, int any_flag=0, v4map=0; sa_family_t family; struct in6_addr in6_tmp; - struct in_addr in_tmp; + struct in_addr in_tmp = { .s_addr = 0 }; tor_assert(s); tor_assert(addr_out); @@ -659,7 +685,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 }; + static char 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; @@ -718,6 +744,11 @@ tor_addr_parse_mask_ports(const char *s, /* XXXX_IP6 is this really what we want? */ bits = 96 + bits%32; /* map v4-mapped masks onto 96-128 bits */ } + if (any_flag) { + log_warn(LD_GENERAL, + "Found bit prefix with wildcard address; rejecting"); + goto err; + } } else { /* pick an appropriate mask, as none was given */ if (any_flag) bits = 0; /* This is okay whether it's V6 or V4 (FIX V4-mapped V6!) */ @@ -803,6 +834,8 @@ tor_addr_is_null(const tor_addr_t *addr) } case AF_INET: return (tor_addr_to_ipv4n(addr) == 0); + case AF_UNIX: + return 1; case AF_UNSPEC: return 1; default: @@ -878,7 +911,7 @@ tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src) memcpy(dest, src, sizeof(tor_addr_t)); } -/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>, taking extra case to +/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>, taking extra care to * copy only the well-defined portions. Used for computing hashes of * addresses. */ @@ -1013,7 +1046,6 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, } else { a2 = tor_addr_to_ipv4h(addr2); } - if (mbits <= 0) return 0; if (mbits > 32) mbits = 32; a1 >>= (32-mbits); a2 >>= (32-mbits); @@ -1109,7 +1141,8 @@ fmt_addr32(uint32_t addr) int tor_addr_parse(tor_addr_t *addr, const char *src) { - char *tmp = NULL; /* Holds substring if we got a dotted quad. */ + /* Holds substring of IPv6 address after removing square brackets */ + char *tmp = NULL; int result; struct in_addr in_tmp; struct in6_addr in6_tmp; @@ -1194,26 +1227,17 @@ typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)( ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG); #endif -/** Try to ask our network interfaces what addresses they are bound to. - * Return a new smartlist of tor_addr_t on success, and NULL on failure. - * (An empty smartlist indicates that we successfully learned that we have no - * addresses.) Log failure messages at <b>severity</b>. */ -static smartlist_t * -get_interface_addresses_raw(int severity) +#ifdef HAVE_IFADDRS_TO_SMARTLIST +/* + * Convert a linked list consisting of <b>ifaddrs</b> structures + * into smartlist of <b>tor_addr_t</b> structures. + */ +STATIC smartlist_t * +ifaddrs_to_smartlist(const struct ifaddrs *ifa) { -#if defined(HAVE_GETIFADDRS) - /* Most free Unixy systems provide getifaddrs, which gives us a linked list - * of struct ifaddrs. */ - struct ifaddrs *ifa = NULL; + smartlist_t *result = smartlist_new(); const struct ifaddrs *i; - smartlist_t *result; - if (getifaddrs(&ifa) < 0) { - log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s", - strerror(errno)); - return NULL; - } - result = smartlist_new(); for (i = ifa; i; i = i->ifa_next) { tor_addr_t tmp; if ((i->ifa_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) @@ -1228,9 +1252,72 @@ get_interface_addresses_raw(int severity) smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); } + return result; +} + +/** Use getiffaddrs() function to get list of current machine + * network interface addresses. Represent the result by smartlist of + * <b>tor_addr_t</b> structures. + */ +STATIC smartlist_t * +get_interface_addresses_ifaddrs(int severity) +{ + + /* Most free Unixy systems provide getifaddrs, which gives us a linked list + * of struct ifaddrs. */ + struct ifaddrs *ifa = NULL; + smartlist_t *result; + if (getifaddrs(&ifa) < 0) { + log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s", + strerror(errno)); + return NULL; + } + + result = ifaddrs_to_smartlist(ifa); + freeifaddrs(ifa); + + return result; +} +#endif + +#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST + +/** Convert a Windows-specific <b>addresses</b> linked list into smartlist + * of <b>tor_addr_t</b> structures. + */ + +STATIC smartlist_t * +ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses) +{ + smartlist_t *result = smartlist_new(); + const IP_ADAPTER_ADDRESSES *address; + + for (address = addresses; address; address = address->Next) { + const IP_ADAPTER_UNICAST_ADDRESS *a; + for (a = address->FirstUnicastAddress; a; a = a->Next) { + /* Yes, it's a linked list inside a linked list */ + const struct sockaddr *sa = a->Address.lpSockaddr; + tor_addr_t tmp; + if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) + continue; + if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) + continue; + smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); + } + } + return result; -#elif defined(_WIN32) +} + +/** Windows only: use GetAdaptersInfo() function to retrieve network interface + * addresses of current machine and return them to caller as smartlist of + * <b>tor_addr_t</b> structures. + */ +STATIC smartlist_t * +get_interface_addresses_win32(int severity) +{ + /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a "GetAdaptersInfo", but that's deprecated; let's just try GetAdaptersAddresses and fall back to connect+getsockname. @@ -1239,7 +1326,7 @@ get_interface_addresses_raw(int severity) smartlist_t *result = NULL; GetAdaptersAddresses_fn_t fn; ULONG size, res; - IP_ADAPTER_ADDRESSES *addresses = NULL, *address; + IP_ADAPTER_ADDRESSES *addresses = NULL; (void) severity; @@ -1274,67 +1361,130 @@ get_interface_addresses_raw(int severity) goto done; } - result = smartlist_new(); - for (address = addresses; address; address = address->Next) { - IP_ADAPTER_UNICAST_ADDRESS *a; - for (a = address->FirstUnicastAddress; a; a = a->Next) { - /* Yes, it's a linked list inside a linked list */ - struct sockaddr *sa = a->Address.lpSockaddr; - tor_addr_t tmp; - if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) - continue; - if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) - continue; - smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); - } - } + result = ip_adapter_addresses_to_smartlist(addresses); done: if (lib) FreeLibrary(lib); tor_free(addresses); return result; -#elif defined(SIOCGIFCONF) && defined(HAVE_IOCTL) +} + +#endif + +#ifdef HAVE_IFCONF_TO_SMARTLIST + +/* Guess how much space we need. There shouldn't be any struct ifreqs + * larger than this, even on OS X where the struct's size is dynamic. */ +#define IFREQ_SIZE 4096 + +/* This is defined on Mac OS X */ +#ifndef _SIZEOF_ADDR_IFREQ +#define _SIZEOF_ADDR_IFREQ sizeof +#endif + +/** Convert <b>*buf</b>, an ifreq structure array of size <b>buflen</b>, + * into smartlist of <b>tor_addr_t</b> structures. + */ +STATIC smartlist_t * +ifreq_to_smartlist(char *buf, size_t buflen) +{ + smartlist_t *result = smartlist_new(); + char *end = buf + buflen; + + /* These acrobatics are due to alignment issues which trigger + * undefined behaviour traps on OSX. */ + struct ifreq *r = tor_malloc(IFREQ_SIZE); + + while (buf < end) { + /* Copy up to IFREQ_SIZE bytes into the struct ifreq, but don't overrun + * buf. */ + memcpy(r, buf, end - buf < IFREQ_SIZE ? end - buf : IFREQ_SIZE); + + const struct sockaddr *sa = &r->ifr_addr; + tor_addr_t tmp; + int valid_sa_family = (sa->sa_family == AF_INET || + sa->sa_family == AF_INET6); + + int conversion_success = (tor_addr_from_sockaddr(&tmp, sa, NULL) == 0); + + if (valid_sa_family && conversion_success) + smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); + + buf += _SIZEOF_ADDR_IFREQ(*r); + } + + tor_free(r); + return result; +} + +/** Use ioctl(.,SIOCGIFCONF,.) to get a list of current machine + * network interface addresses. Represent the result by smartlist of + * <b>tor_addr_t</b> structures. + */ +STATIC smartlist_t * +get_interface_addresses_ioctl(int severity) +{ /* Some older unixy systems make us use ioctl(SIOCGIFCONF) */ struct ifconf ifc; - int fd, i, sz, n; + int fd; smartlist_t *result = NULL; + /* This interface, AFAICT, only supports AF_INET addresses */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { tor_log(severity, LD_NET, "socket failed: %s", strerror(errno)); goto done; } - /* Guess how much space we need. */ - ifc.ifc_len = sz = 15*1024; - ifc.ifc_ifcu.ifcu_req = tor_malloc(sz); - if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { - tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno)); - close(fd); - goto done; - } - close(fd); - result = smartlist_new(); - if (ifc.ifc_len < sz) - sz = ifc.ifc_len; - n = sz / sizeof(struct ifreq); - for (i = 0; i < n ; ++i) { - struct ifreq *r = &ifc.ifc_ifcu.ifcu_req[i]; - struct sockaddr *sa = &r->ifr_addr; - tor_addr_t tmp; - if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) - continue; /* should be impossible */ - if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) - continue; - smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); - } + + int mult = 1; + ifc.ifc_buf = NULL; + do { + mult *= 2; + ifc.ifc_len = mult * IFREQ_SIZE; + ifc.ifc_buf = tor_realloc(ifc.ifc_buf, ifc.ifc_len); + + tor_assert(ifc.ifc_buf); + + if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { + tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno)); + goto done; + } + /* 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); + done: - tor_free(ifc.ifc_ifcu.ifcu_req); + if (fd >= 0) + close(fd); + tor_free(ifc.ifc_buf); return result; -#else +} +#endif + +/** Try to ask our network interfaces what addresses they are bound to. + * Return a new smartlist of tor_addr_t on success, and NULL on failure. + * (An empty smartlist indicates that we successfully learned that we have no + * addresses.) Log failure messages at <b>severity</b>. */ +STATIC smartlist_t * +get_interface_addresses_raw(int severity) +{ + smartlist_t *result = NULL; +#if defined(HAVE_IFADDRS_TO_SMARTLIST) + if ((result = get_interface_addresses_ifaddrs(severity))) + return result; +#endif +#if defined(HAVE_IP_ADAPTER_TO_SMARTLIST) + if ((result = get_interface_addresses_win32(severity))) + return result; +#endif +#if defined(HAVE_IFCONF_TO_SMARTLIST) + if ((result = get_interface_addresses_ioctl(severity))) + return result; +#endif (void) severity; return NULL; -#endif } /** Return true iff <b>a</b> is a multicast address. */ @@ -1358,8 +1508,8 @@ tor_addr_is_multicast(const tor_addr_t *a) * connects to the Internet. This address should only be used in checking * whether our address has changed. Return 0 on success, -1 on failure. */ -int -get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr) +MOCK_IMPL(int, +get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) { /* XXX really, this function should yield a smartlist of addresses. */ smartlist_t *addrs; @@ -1688,8 +1838,8 @@ tor_dup_ip(uint32_t addr) * checking whether our address has changed. Return 0 on success, -1 on * failure. */ -int -get_interface_address(int severity, uint32_t *addr) +MOCK_IMPL(int, +get_interface_address,(int severity, uint32_t *addr)) { tor_addr_t local_addr; int r; |