Move network code to libtor-net.

There are some additional changes to come: those points are marked
by XXXX.
This commit is contained in:
Nick Mathewson
2018-06-26 20:42:47 -04:00
parent 80730c45e0
commit 42b3caa6ad
23 changed files with 1554 additions and 1280 deletions
-2172
View File
File diff suppressed because it is too large Load Diff
-379
View File
@@ -1,379 +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 address.h
* \brief Headers for address.h
**/
#ifndef TOR_ADDRESS_H
#define TOR_ADDRESS_H
//#include <sys/sockio.h>
#include "orconfig.h"
#include "lib/cc/torint.h"
#include "common/compat.h"
#include "lib/log/util_bug.h"
#ifdef ADDRESS_PRIVATE
#if defined(HAVE_SYS_IOCTL_H)
#include <sys/ioctl.h>
#endif
#ifdef HAVE_GETIFADDRS
#define HAVE_IFADDRS_TO_SMARTLIST
#endif
#ifdef _WIN32
#define HAVE_IP_ADAPTER_TO_SMARTLIST
#endif
#if defined(SIOCGIFCONF) && defined(HAVE_IOCTL)
#define HAVE_IFCONF_TO_SMARTLIST
#endif
#if defined(HAVE_NET_IF_H)
#include <net/if.h> // for struct ifconf
#endif
#if defined(HAVE_IFADDRS_TO_SMARTLIST)
#include <ifaddrs.h>
#endif
// TODO win32 specific includes
#endif /* defined(ADDRESS_PRIVATE) */
/** The number of bits from an address to consider while doing a masked
* comparison. */
typedef uint8_t maskbits_t;
struct in_addr;
/** Holds an IPv4 or IPv6 address. (Uses less memory than struct
* sockaddr_storage.) */
typedef struct tor_addr_t
{
sa_family_t family;
union {
uint32_t dummy_; /* This field is here so we have something to initialize
* with a reliable cross-platform type. */
struct in_addr in_addr;
struct in6_addr in6_addr;
} addr;
} tor_addr_t;
/** Holds an IP address and a TCP/UDP port. */
typedef struct tor_addr_port_t
{
tor_addr_t addr;
uint16_t port;
} tor_addr_port_t;
#define TOR_ADDR_NULL {AF_UNSPEC, {0}}
static inline const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a);
static inline const struct in6_addr *tor_addr_to_in6_assert(
const tor_addr_t *a);
static inline uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
static inline uint32_t tor_addr_to_ipv4h(const tor_addr_t *a);
static inline uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a);
static inline sa_family_t tor_addr_family(const tor_addr_t *a);
static inline const struct in_addr *tor_addr_to_in(const tor_addr_t *a);
static inline int tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u);
socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port,
struct sockaddr *sa_out, socklen_t len);
int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out);
void tor_addr_make_unspec(tor_addr_t *a);
void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
char *tor_sockaddr_to_str(const struct sockaddr *sa);
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
* an IPv6 address. */
static inline const struct in6_addr *
tor_addr_to_in6(const tor_addr_t *a)
{
return a->family == AF_INET6 ? &a->addr.in6_addr : NULL;
}
/** As tor_addr_to_in6, but assert that the address truly is an IPv6
* address. */
static inline const struct in6_addr *
tor_addr_to_in6_assert(const tor_addr_t *a)
{
tor_assert(a->family == AF_INET6);
return &a->addr.in6_addr;
}
/** Given an IPv6 address <b>x</b>, yield it as an array of uint8_t.
*
* Requires that <b>x</b> is actually an IPv6 address.
*/
#define tor_addr_to_in6_addr8(x) tor_addr_to_in6_assert(x)->s6_addr
/** Given an IPv6 address <b>x</b>, yield it as an array of uint16_t.
*
* Requires that <b>x</b> is actually an IPv6 address.
*/
#define tor_addr_to_in6_addr16(x) S6_ADDR16(*tor_addr_to_in6_assert(x))
/** Given an IPv6 address <b>x</b>, yield it as an array of uint32_t.
*
* Requires that <b>x</b> is actually an IPv6 address.
*/
#define tor_addr_to_in6_addr32(x) S6_ADDR32(*tor_addr_to_in6_assert(x))
/** Return an IPv4 address in network order for <b>a</b>, or 0 if
* <b>a</b> is not an IPv4 address. */
static inline uint32_t
tor_addr_to_ipv4n(const tor_addr_t *a)
{
return a->family == AF_INET ? a->addr.in_addr.s_addr : 0;
}
/** Return an IPv4 address in host order for <b>a</b>, or 0 if
* <b>a</b> is not an IPv4 address. */
static inline uint32_t
tor_addr_to_ipv4h(const tor_addr_t *a)
{
return ntohl(tor_addr_to_ipv4n(a));
}
/** Given an IPv6 address, return its mapped IPv4 address in host order, or
* 0 if <b>a</b> is not an IPv6 address.
*
* (Does not check whether the address is really a mapped address */
static inline uint32_t
tor_addr_to_mapped_ipv4h(const tor_addr_t *a)
{
if (a->family == AF_INET6) {
uint32_t *addr32 = NULL;
// Work around an incorrect NULL pointer dereference warning in
// "clang --analyze" due to limited analysis depth
addr32 = tor_addr_to_in6_addr32(a);
// To improve performance, wrap this assertion in:
// #if !defined(__clang_analyzer__) || PARANOIA
tor_assert(addr32);
return ntohl(addr32[3]);
} else {
return 0;
}
}
/** Return the address family of <b>a</b>. Possible values are:
* AF_INET6, AF_INET, AF_UNSPEC. */
static inline sa_family_t
tor_addr_family(const tor_addr_t *a)
{
return a->family;
}
/** Return an in_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
* an IPv4 address. */
static inline const struct in_addr *
tor_addr_to_in(const tor_addr_t *a)
{
return a->family == AF_INET ? &a->addr.in_addr : NULL;
}
/** Return true iff <b>a</b> is an IPv4 address equal to the host-ordered
* address in <b>u</b>. */
static inline int
tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u)
{
return a->family == AF_INET ? (tor_addr_to_ipv4h(a) == u) : 0;
}
/** Length of a buffer that you need to allocate to be sure you can encode
* any tor_addr_t.
*
* This allows enough space for
* "[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]",
* plus a terminating NUL.
*/
#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
* addresses. */
#define fmt_addr(a) fmt_addr_impl((a), 0)
/** Wrapper function of fmt_addr_impl(). It decorates IPv6
* addresses. */
#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1)
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
const char * fmt_addr32(uint32_t addr);
MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
tor_addr_t *addr));
struct smartlist_t;
void interface_address6_list_free_(struct smartlist_t * addrs);// XXXX
#define interface_address6_list_free(addrs) \
FREE_AND_NULL(struct smartlist_t, interface_address6_list_free_, (addrs))
MOCK_DECL(struct smartlist_t *,get_interface_address6_list,(int severity,
sa_family_t family,
int include_internal));
/** Flag to specify how to do a comparison between addresses. In an "exact"
* comparison, addresses are equivalent only if they are in the same family
* with the same value. In a "semantic" comparison, IPv4 addresses match all
* IPv6 encodings of those addresses. */
typedef enum {
CMP_EXACT,
CMP_SEMANTIC,
} tor_addr_comparison_t;
int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2,
tor_addr_comparison_t how);
int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
maskbits_t mask, tor_addr_comparison_t how);
/** Return true iff a and b are the same address. The comparison is done
* "exactly". */
#define tor_addr_eq(a,b) (0==tor_addr_compare((a),(b),CMP_EXACT))
uint64_t tor_addr_hash(const tor_addr_t *addr);
struct sipkey;
uint64_t tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr);
int tor_addr_is_v4(const tor_addr_t *addr);
int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
const char *filename, int lineno);
#define tor_addr_is_internal(addr, for_listening) \
tor_addr_is_internal_((addr), (for_listening), SHORT_FILE__, __LINE__)
int tor_addr_is_multicast(const tor_addr_t *a);
/** Longest length that can be required for a reverse lookup name. */
/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */
#define REVERSE_LOOKUP_NAME_BUF_LEN 73
int tor_addr_to_PTR_name(char *out, size_t outlen,
const tor_addr_t *addr);
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;
* or does the address * yield IPv4 wildcard address (0). */
#define TAPMP_EXTENDED_STAR 1
/* Does the address * yield an IPv4 wildcard address rule (1);
* or does it yield wildcard IPv4 and IPv6 rules (0) */
#define TAPMP_STAR_IPV4_ONLY (1 << 1)
/* Does the address * yield an IPv6 wildcard address rule (1);
* or does it yield wildcard IPv4 and IPv6 rules (0) */
#define TAPMP_STAR_IPV6_ONLY (1 << 2)
/* TAPMP_STAR_IPV4_ONLY and TAPMP_STAR_IPV6_ONLY are mutually exclusive. */
int tor_addr_parse_mask_ports(const char *s, unsigned flags,
tor_addr_t *addr_out, maskbits_t *mask_out,
uint16_t *port_min_out, uint16_t *port_max_out);
const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len,
int decorate);
int tor_addr_parse(tor_addr_t *addr, const char *src);
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src);
void tor_addr_copy_tight(tor_addr_t *dest, const tor_addr_t *src);
void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr);
/** Set <b>dest</b> to the IPv4 address encoded in <b>v4addr</b> in host
* order. */
#define tor_addr_from_ipv4h(dest, v4addr) \
tor_addr_from_ipv4n((dest), htonl(v4addr))
void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes);
/** Set <b>dest</b> to the IPv4 address incoded in <b>in</b>. */
#define tor_addr_from_in(dest, in) \
tor_addr_from_ipv4n((dest), (in)->s_addr);
void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6);
int tor_addr_is_null(const tor_addr_t *addr);
int tor_addr_is_loopback(const tor_addr_t *addr);
int tor_addr_is_valid(const tor_addr_t *addr, int for_listening);
int tor_addr_is_valid_ipv4n(uint32_t v4n_addr, int for_listening);
#define tor_addr_is_valid_ipv4h(v4h_addr, for_listening) \
tor_addr_is_valid_ipv4n(htonl(v4h_addr), (for_listening))
int tor_port_is_valid(uint16_t port, int for_listening);
/* Are addr and port both valid? */
#define tor_addr_port_is_valid(addr, port, for_listening) \
(tor_addr_is_valid((addr), (for_listening)) && \
tor_port_is_valid((port), (for_listening)))
/* Are ap->addr and ap->port both valid? */
#define tor_addr_port_is_valid_ap(ap, for_listening) \
tor_addr_port_is_valid(&(ap)->addr, (ap)->port, (for_listening))
/* Are the network-order v4addr and port both valid? */
#define tor_addr_port_is_valid_ipv4n(v4n_addr, port, for_listening) \
(tor_addr_is_valid_ipv4n((v4n_addr), (for_listening)) && \
tor_port_is_valid((port), (for_listening)))
/* Are the host-order v4addr and port both valid? */
#define tor_addr_port_is_valid_ipv4h(v4h_addr, port, for_listening) \
(tor_addr_is_valid_ipv4h((v4h_addr), (for_listening)) && \
tor_port_is_valid((port), (for_listening)))
int tor_addr_port_split(int severity, const char *addrport,
char **address_out, uint16_t *port_out);
int tor_addr_port_parse(int severity, const char *addrport,
tor_addr_t *address_out, uint16_t *port_out,
int default_port);
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);
/** 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);
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr));
#define interface_address_list_free(lst)\
interface_address6_list_free(lst)
/** Return a smartlist of the IPv4 addresses of all interfaces on the server.
* Excludes loopback and multicast addresses. Only includes internal addresses
* if include_internal is true. (Note that a relay behind NAT may use an
* internal address to connect to the Internet.)
* An empty smartlist means that there are no IPv4 addresses.
* Returns NULL on failure.
* Use free_interface_address_list to free the returned list.
*/
static inline struct smartlist_t *
get_interface_address_list(int severity, int include_internal)
{
return get_interface_address6_list(severity, AF_INET, include_internal);
}
tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
int tor_addr_port_eq(const tor_addr_port_t *a,
const tor_addr_port_t *b);
#ifdef ADDRESS_PRIVATE
MOCK_DECL(struct smartlist_t *,get_interface_addresses_raw,(int severity,
sa_family_t family));
MOCK_DECL(int,get_interface_address6_via_udp_socket_hack,(int severity,
sa_family_t family,
tor_addr_t *addr));
#ifdef HAVE_IFADDRS_TO_SMARTLIST
STATIC struct smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa,
sa_family_t family);
STATIC struct smartlist_t *get_interface_addresses_ifaddrs(int severity,
sa_family_t family);
#endif /* defined(HAVE_IFADDRS_TO_SMARTLIST) */
#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
STATIC struct smartlist_t *ip_adapter_addresses_to_smartlist(
const IP_ADAPTER_ADDRESSES *addresses);
STATIC struct smartlist_t *get_interface_addresses_win32(int severity,
sa_family_t family);
#endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */
#ifdef HAVE_IFCONF_TO_SMARTLIST
STATIC struct smartlist_t *ifreq_to_smartlist(char *ifr,
size_t buflen);
STATIC struct smartlist_t *get_interface_addresses_ioctl(int severity,
sa_family_t family);
#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
#endif /* defined(ADDRESS_PRIVATE) */
#endif /* !defined(TOR_ADDRESS_H) */
+5 -864
View File
@@ -131,11 +131,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#include "common/address.h"
#include "common/sandbox.h"
/* When set_max_file_descriptors() is called, update this with the max file
* descriptor value so we can use it to check the limit when opening a new
* socket. Default value is what Debian sets as the default hard limit. */
static int max_sockets = 1024;
/** As open(path, flags, mode), but return an fd with the close-on-exec mode
* set. */
int
@@ -707,618 +702,6 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
tor_free(lockfile);
}
#undef DEBUG_SOCKET_COUNTING
#ifdef DEBUG_SOCKET_COUNTING
/** A bitarray of all fds that should be passed to tor_socket_close(). Only
* used if DEBUG_SOCKET_COUNTING is defined. */
static bitarray_t *open_sockets = NULL;
/** The size of <b>open_sockets</b>, in bits. */
static int max_socket = -1;
#endif /* defined(DEBUG_SOCKET_COUNTING) */
/** Count of number of sockets currently open. (Undercounts sockets opened by
* eventdns and libevent.) */
static int n_sockets_open = 0;
/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */
static tor_mutex_t *socket_accounting_mutex = NULL;
/** Helper: acquire the socket accounting lock. */
static inline void
socket_accounting_lock(void)
{
if (PREDICT_UNLIKELY(!socket_accounting_mutex))
socket_accounting_mutex = tor_mutex_new();
tor_mutex_acquire(socket_accounting_mutex);
}
/** Helper: release the socket accounting lock. */
static inline void
socket_accounting_unlock(void)
{
tor_mutex_release(socket_accounting_mutex);
}
/** As close(), but guaranteed to work for sockets across platforms (including
* Windows, where close()ing a socket doesn't work. Returns 0 on success and
* the socket error code on failure. */
int
tor_close_socket_simple(tor_socket_t s)
{
int r = 0;
/* On Windows, you have to call close() on fds returned by open(),
* and closesocket() on fds returned by socket(). On Unix, everything
* gets close()'d. We abstract this difference by always using
* tor_close_socket to close sockets, and always using close() on
* files.
*/
#if defined(_WIN32)
r = closesocket(s);
#else
r = close(s);
#endif
if (r != 0) {
int err = tor_socket_errno(-1);
log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err));
return err;
}
return r;
}
/** As tor_close_socket_simple(), but keeps track of the number
* of open sockets. Returns 0 on success, -1 on failure. */
MOCK_IMPL(int,
tor_close_socket,(tor_socket_t s))
{
int r = tor_close_socket_simple(s);
socket_accounting_lock();
#ifdef DEBUG_SOCKET_COUNTING
if (s > max_socket || ! bitarray_is_set(open_sockets, s)) {
log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_"
"socket(), or that was already closed or something.", s);
} else {
tor_assert(open_sockets && s <= max_socket);
bitarray_clear(open_sockets, s);
}
#endif /* defined(DEBUG_SOCKET_COUNTING) */
if (r == 0) {
--n_sockets_open;
} else {
#ifdef _WIN32
if (r != WSAENOTSOCK)
--n_sockets_open;
#else
if (r != EBADF)
--n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force.
#endif /* defined(_WIN32) */
r = -1;
}
tor_assert_nonfatal(n_sockets_open >= 0);
socket_accounting_unlock();
return r;
}
/** @{ */
#ifdef DEBUG_SOCKET_COUNTING
/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is
* now an open socket. */
static inline void
mark_socket_open(tor_socket_t s)
{
/* XXXX This bitarray business will NOT work on windows: sockets aren't
small ints there. */
if (s > max_socket) {
if (max_socket == -1) {
open_sockets = bitarray_init_zero(s+128);
max_socket = s+128;
} else {
open_sockets = bitarray_expand(open_sockets, max_socket, s+128);
max_socket = s+128;
}
}
if (bitarray_is_set(open_sockets, s)) {
log_warn(LD_BUG, "I thought that %d was already open, but socket() just "
"gave it to me!", s);
}
bitarray_set(open_sockets, s);
}
#else /* !(defined(DEBUG_SOCKET_COUNTING)) */
#define mark_socket_open(s) ((void) (s))
#endif /* defined(DEBUG_SOCKET_COUNTING) */
/** @} */
/** As socket(), but counts the number of open sockets. */
MOCK_IMPL(tor_socket_t,
tor_open_socket,(int domain, int type, int protocol))
{
return tor_open_socket_with_extensions(domain, type, protocol, 1, 0);
}
/** Mockable wrapper for connect(). */
MOCK_IMPL(tor_socket_t,
tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address,
socklen_t address_len))
{
return connect(sock,address,address_len);
}
/** As socket(), but creates a nonblocking socket and
* counts the number of open sockets. */
tor_socket_t
tor_open_socket_nonblocking(int domain, int type, int protocol)
{
return tor_open_socket_with_extensions(domain, type, protocol, 1, 1);
}
/** As socket(), but counts the number of open sockets and handles
* socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
* <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
* if the corresponding extension should be used.*/
tor_socket_t
tor_open_socket_with_extensions(int domain, int type, int protocol,
int cloexec, int nonblock)
{
tor_socket_t s;
/* We are about to create a new file descriptor so make sure we have
* enough of them. */
if (get_n_open_sockets() >= max_sockets - 1) {
#ifdef _WIN32
WSASetLastError(WSAEMFILE);
#else
errno = EMFILE;
#endif
return TOR_INVALID_SOCKET;
}
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
(nonblock ? SOCK_NONBLOCK : 0);
s = socket(domain, type|ext_flags, protocol);
if (SOCKET_OK(s))
goto socket_ok;
/* If we got an error, see if it is EINVAL. EINVAL might indicate that,
* even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK
* support, we are running on one without. */
if (errno != EINVAL)
return s;
#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */
s = socket(domain, type, protocol);
if (! SOCKET_OK(s))
return s;
#if defined(FD_CLOEXEC)
if (cloexec) {
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
tor_close_socket_simple(s);
return TOR_INVALID_SOCKET;
}
}
#else /* !(defined(FD_CLOEXEC)) */
(void)cloexec;
#endif /* defined(FD_CLOEXEC) */
if (nonblock) {
if (set_socket_nonblocking(s) == -1) {
tor_close_socket_simple(s);
return TOR_INVALID_SOCKET;
}
}
goto socket_ok; /* So that socket_ok will not be unused. */
socket_ok:
tor_take_socket_ownership(s);
return s;
}
/**
* For socket accounting: remember that we are the owner of the socket
* <b>s</b>. This will prevent us from overallocating sockets, and prevent us
* from asserting later when we close the socket <b>s</b>.
*/
void
tor_take_socket_ownership(tor_socket_t s)
{
socket_accounting_lock();
++n_sockets_open;
mark_socket_open(s);
socket_accounting_unlock();
}
/** As accept(), but counts the number of open sockets. */
tor_socket_t
tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
{
return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0);
}
/** As accept(), but returns a nonblocking socket and
* counts the number of open sockets. */
tor_socket_t
tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr,
socklen_t *len)
{
return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1);
}
/** As accept(), but counts the number of open sockets and handles
* socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
* <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
* if the corresponding extension should be used.*/
tor_socket_t
tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr,
socklen_t *len, int cloexec, int nonblock)
{
tor_socket_t s;
/* We are about to create a new file descriptor so make sure we have
* enough of them. */
if (get_n_open_sockets() >= max_sockets - 1) {
#ifdef _WIN32
WSASetLastError(WSAEMFILE);
#else
errno = EMFILE;
#endif
return TOR_INVALID_SOCKET;
}
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \
&& defined(SOCK_NONBLOCK)
int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
(nonblock ? SOCK_NONBLOCK : 0);
s = accept4(sockfd, addr, len, ext_flags);
if (SOCKET_OK(s))
goto socket_ok;
/* If we got an error, see if it is ENOSYS. ENOSYS indicates that,
* even though we were built on a system with accept4 support, we
* are running on one without. Also, check for EINVAL, which indicates that
* we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */
if (errno != EINVAL && errno != ENOSYS)
return s;
#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */
s = accept(sockfd, addr, len);
if (!SOCKET_OK(s))
return s;
#if defined(FD_CLOEXEC)
if (cloexec) {
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
tor_close_socket_simple(s);
return TOR_INVALID_SOCKET;
}
}
#else /* !(defined(FD_CLOEXEC)) */
(void)cloexec;
#endif /* defined(FD_CLOEXEC) */
if (nonblock) {
if (set_socket_nonblocking(s) == -1) {
tor_close_socket_simple(s);
return TOR_INVALID_SOCKET;
}
}
goto socket_ok; /* So that socket_ok will not be unused. */
socket_ok:
tor_take_socket_ownership(s);
return s;
}
/** Return the number of sockets we currently have opened. */
int
get_n_open_sockets(void)
{
int n;
socket_accounting_lock();
n = n_sockets_open;
socket_accounting_unlock();
return n;
}
/** Mockable wrapper for getsockname(). */
MOCK_IMPL(int,
tor_getsockname,(tor_socket_t sock, struct sockaddr *address,
socklen_t *address_len))
{
return getsockname(sock, address, address_len);
}
/**
* Find the local address associated with the socket <b>sock</b>, and
* place it in *<b>addr_out</b>. Return 0 on success, -1 on failure.
*
* (As tor_getsockname, but instead places the result in a tor_addr_t.) */
int
tor_addr_from_getsockname(tor_addr_t *addr_out, tor_socket_t sock)
{
struct sockaddr_storage ss;
socklen_t ss_len = sizeof(ss);
memset(&ss, 0, sizeof(ss));
if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0)
return -1;
return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL);
}
/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
* on failure.
*/
int
set_socket_nonblocking(tor_socket_t sock)
{
#if defined(_WIN32)
unsigned long nonblocking = 1;
ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking);
#else
int flags;
flags = fcntl(sock, F_GETFL, 0);
if (flags == -1) {
log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno));
return -1;
}
flags |= O_NONBLOCK;
if (fcntl(sock, F_SETFL, flags) == -1) {
log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno));
return -1;
}
#endif /* defined(_WIN32) */
return 0;
}
/**
* Allocate a pair of connected sockets. (Like socketpair(family,
* type,protocol,fd), but works on systems that don't have
* socketpair.)
*
* Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported.
*
* Note that on systems without socketpair, this call will fail if
* localhost is inaccessible (for example, if the networking
* stack is down). And even if it succeeds, the socket pair will not
* be able to read while localhost is down later (the socket pair may
* even close, depending on OS-specific timeouts).
*
* Returns 0 on success and -errno on failure; do not rely on the value
* of errno or WSAGetLastError().
**/
/* It would be nicer just to set errno, but that won't work for windows. */
int
tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
{
//don't use win32 socketpairs (they are always bad)
#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32)
int r;
#ifdef SOCK_CLOEXEC
r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd);
if (r == 0)
goto sockets_ok;
/* If we got an error, see if it is EINVAL. EINVAL might indicate that,
* even though we were built on a system with SOCK_CLOEXEC support, we
* are running on one without. */
if (errno != EINVAL)
return -errno;
#endif /* defined(SOCK_CLOEXEC) */
r = socketpair(family, type, protocol, fd);
if (r < 0)
return -errno;
#if defined(FD_CLOEXEC)
if (SOCKET_OK(fd[0])) {
r = fcntl(fd[0], F_SETFD, FD_CLOEXEC);
if (r == -1) {
close(fd[0]);
close(fd[1]);
return -errno;
}
}
if (SOCKET_OK(fd[1])) {
r = fcntl(fd[1], F_SETFD, FD_CLOEXEC);
if (r == -1) {
close(fd[0]);
close(fd[1]);
return -errno;
}
}
#endif /* defined(FD_CLOEXEC) */
goto sockets_ok; /* So that sockets_ok will not be unused. */
sockets_ok:
socket_accounting_lock();
if (SOCKET_OK(fd[0])) {
++n_sockets_open;
mark_socket_open(fd[0]);
}
if (SOCKET_OK(fd[1])) {
++n_sockets_open;
mark_socket_open(fd[1]);
}
socket_accounting_unlock();
return 0;
#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */
return tor_ersatz_socketpair(family, type, protocol, fd);
#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */
}
#ifdef NEED_ERSATZ_SOCKETPAIR
static inline socklen_t
SIZEOF_SOCKADDR(int domain)
{
switch (domain) {
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
default:
return 0;
}
}
/**
* Helper used to implement socketpair on systems that lack it, by
* making a direct connection to localhost.
*/
STATIC int
tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
{
/* This socketpair does not work when localhost is down. So
* it's really not the same thing at all. But it's close enough
* for now, and really, when localhost is down sometimes, we
* have other problems too.
*/
tor_socket_t listener = TOR_INVALID_SOCKET;
tor_socket_t connector = TOR_INVALID_SOCKET;
tor_socket_t acceptor = TOR_INVALID_SOCKET;
tor_addr_t listen_tor_addr;
struct sockaddr_storage connect_addr_ss, listen_addr_ss;
struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss;
uint16_t listen_port = 0;
tor_addr_t connect_tor_addr;
uint16_t connect_port = 0;
struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss;
socklen_t size;
int saved_errno = -1;
int ersatz_domain = AF_INET;
memset(&connect_tor_addr, 0, sizeof(connect_tor_addr));
memset(&connect_addr_ss, 0, sizeof(connect_addr_ss));
memset(&listen_tor_addr, 0, sizeof(listen_tor_addr));
memset(&listen_addr_ss, 0, sizeof(listen_addr_ss));
if (protocol
#ifdef AF_UNIX
|| family != AF_UNIX
#endif
) {
#ifdef _WIN32
return -WSAEAFNOSUPPORT;
#else
return -EAFNOSUPPORT;
#endif
}
if (!fd) {
return -EINVAL;
}
listener = tor_open_socket(ersatz_domain, type, 0);
if (!SOCKET_OK(listener)) {
int first_errno = tor_socket_errno(-1);
if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT)
&& ersatz_domain == AF_INET) {
/* Assume we're on an IPv6-only system */
ersatz_domain = AF_INET6;
listener = tor_open_socket(ersatz_domain, type, 0);
if (!SOCKET_OK(listener)) {
/* Keep the previous behaviour, which was to return the IPv4 error.
* (This may be less informative on IPv6-only systems.)
* XX/teor - is there a better way to decide which errno to return?
* (I doubt we care much either way, once there is an error.)
*/
return -first_errno;
}
}
}
/* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we
* risk exposing a socketpair on a routable IP address. (Some BSD jails
* use a routable address for localhost. Fortunately, they have the real
* AF_UNIX socketpair.) */
if (ersatz_domain == AF_INET) {
tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK);
} else {
tor_addr_parse(&listen_tor_addr, "[::1]");
}
tor_assert(tor_addr_is_loopback(&listen_tor_addr));
size = tor_addr_to_sockaddr(&listen_tor_addr,
0 /* kernel chooses port. */,
listen_addr,
sizeof(listen_addr_ss));
if (bind(listener, listen_addr, size) == -1)
goto tidy_up_and_fail;
if (listen(listener, 1) == -1)
goto tidy_up_and_fail;
connector = tor_open_socket(ersatz_domain, type, 0);
if (!SOCKET_OK(connector))
goto tidy_up_and_fail;
/* We want to find out the port number to connect to. */
size = sizeof(connect_addr_ss);
if (getsockname(listener, connect_addr, &size) == -1)
goto tidy_up_and_fail;
if (size != SIZEOF_SOCKADDR (connect_addr->sa_family))
goto abort_tidy_up_and_fail;
if (connect(connector, connect_addr, size) == -1)
goto tidy_up_and_fail;
size = sizeof(listen_addr_ss);
acceptor = tor_accept_socket(listener, listen_addr, &size);
if (!SOCKET_OK(acceptor))
goto tidy_up_and_fail;
if (size != SIZEOF_SOCKADDR(listen_addr->sa_family))
goto abort_tidy_up_and_fail;
/* Now check we are talking to ourself by matching port and host on the
two sockets. */
if (getsockname(connector, connect_addr, &size) == -1)
goto tidy_up_and_fail;
/* Set *_tor_addr and *_port to the address and port that was used */
tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port);
tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port);
if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)
|| tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC)
|| listen_port != connect_port) {
goto abort_tidy_up_and_fail;
}
tor_close_socket(listener);
fd[0] = connector;
fd[1] = acceptor;
return 0;
abort_tidy_up_and_fail:
#ifdef _WIN32
saved_errno = WSAECONNABORTED;
#else
saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */
#endif
tidy_up_and_fail:
if (saved_errno < 0)
saved_errno = errno;
if (SOCKET_OK(listener))
tor_close_socket(listener);
if (SOCKET_OK(connector))
tor_close_socket(connector);
if (SOCKET_OK(acceptor))
tor_close_socket(acceptor);
return -saved_errno;
}
#undef SIZEOF_SOCKADDR
#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */
/* Return the maximum number of allowed sockets. */
int
get_max_sockets(void)
{
return max_sockets;
}
/** Number of extra file descriptors to keep in reserve beyond those that we
* tell Tor it's allowed to use. */
#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */
@@ -1396,7 +779,8 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
}
/* Set the current limit value so if the attempt to set the limit to the
* max fails at least we'll have a valid value of maximum sockets. */
*max_out = max_sockets = (int)rlim.rlim_cur - ULIMIT_BUFFER;
*max_out = (int)rlim.rlim_cur - ULIMIT_BUFFER;
set_max_sockets(*max_out);
rlim.rlim_cur = rlim.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
@@ -1438,7 +822,9 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
if (limit > INT_MAX)
limit = INT_MAX;
tor_assert(max_out);
*max_out = max_sockets = (int)limit - ULIMIT_BUFFER;
*max_out = (int)limit - ULIMIT_BUFFER;
set_max_sockets(*max_out);
return 0;
}
@@ -2124,251 +1510,6 @@ tor_gethostname,(char *name, size_t namelen))
return gethostname(name,namelen);
}
/** 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 <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
* <b>dst</b> on success, NULL on failure.
*
* (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it:
* Tor sometimes needs to format ipv6 addresses even on platforms without ipv6
* support.) */
const char *
tor_inet_ntop(int af, const void *src, char *dst, size_t len)
{
if (af == AF_INET) {
if (tor_inet_ntoa(src, dst, len) < 0)
return NULL;
else
return dst;
} else if (af == AF_INET6) {
const struct in6_addr *addr = src;
char buf[64], *cp;
int longestGapLen = 0, longestGapPos = -1, i,
curGapPos = -1, curGapLen = 0;
uint16_t words[8];
for (i = 0; i < 8; ++i) {
words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
}
if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
(words[5] == 0xffff))) {
/* This is an IPv4 address. */
if (words[5] == 0) {
tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
addr->s6_addr[12], addr->s6_addr[13],
addr->s6_addr[14], addr->s6_addr[15]);
} else {
tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
addr->s6_addr[12], addr->s6_addr[13],
addr->s6_addr[14], addr->s6_addr[15]);
}
if ((strlen(buf) + 1) > len) /* +1 for \0 */
return NULL;
strlcpy(dst, buf, len);
return dst;
}
i = 0;
while (i < 8) {
if (words[i] == 0) {
curGapPos = i++;
curGapLen = 1;
while (i<8 && words[i] == 0) {
++i; ++curGapLen;
}
if (curGapLen > longestGapLen) {
longestGapPos = curGapPos;
longestGapLen = curGapLen;
}
} else {
++i;
}
}
if (longestGapLen<=1)
longestGapPos = -1;
cp = buf;
for (i = 0; i < 8; ++i) {
if (words[i] == 0 && longestGapPos == i) {
if (i == 0)
*cp++ = ':';
*cp++ = ':';
while (i < 8 && words[i] == 0)
++i;
--i; /* to compensate for loop increment. */
} else {
tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
cp += strlen(cp);
if (i != 7)
*cp++ = ':';
}
}
*cp = '\0';
if ((strlen(buf) + 1) > len) /* +1 for \0 */
return NULL;
strlcpy(dst, buf, len);
return dst;
} else {
return NULL;
}
}
/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b>
* encoding an IPv4 address or IPv6 address correspondingly, try to parse the
* address and store the result in <b>dst</b> (which must have space for a
* struct in_addr or a struct in6_addr, as appropriate). Return 1 on success,
* 0 on a bad parse, and -1 on a bad <b>af</b>.
*
* (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor
* sometimes needs to format ipv6 addresses even on platforms without ipv6
* support.) */
int
tor_inet_pton(int af, const char *src, void *dst)
{
if (af == AF_INET) {
return tor_inet_aton(src, dst);
} else if (af == AF_INET6) {
struct in6_addr *out = dst;
uint16_t words[8];
int gapPos = -1, i, setWords=0;
const char *dot = strchr(src, '.');
const char *eow; /* end of words. */
memset(words, 0xf8, sizeof(words));
if (dot == src)
return 0;
else if (!dot)
eow = src+strlen(src);
else {
unsigned byte1,byte2,byte3,byte4;
char more;
for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow)
;
if (*eow != ':')
return 0;
++eow;
/* We use "scanf" because some platform inet_aton()s are too lax
* about IPv4 addresses of the form "1.2.3" */
if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c",
&byte1,&byte2,&byte3,&byte4,&more) != 4)
return 0;
if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255)
return 0;
words[6] = (byte1<<8) | byte2;
words[7] = (byte3<<8) | byte4;
setWords += 2;
}
i = 0;
while (src < eow) {
if (i > 7)
return 0;
if (TOR_ISXDIGIT(*src)) {
char *next;
ssize_t len;
long r = strtol(src, &next, 16);
if (next == NULL || next == src) {
/* The 'next == src' error case can happen on versions of openbsd
* which treat "0xfoo" as an error, rather than as "0" followed by
* "xfoo". */
return 0;
}
len = *next == '\0' ? eow - src : next - src;
if (len > 4)
return 0;
if (len > 1 && !TOR_ISXDIGIT(src[1]))
return 0; /* 0x is not valid */
tor_assert(r >= 0);
tor_assert(r < 65536);
words[i++] = (uint16_t)r;
setWords++;
src = next;
if (*src != ':' && src != eow)
return 0;
++src;
} else if (*src == ':' && i > 0 && gapPos == -1) {
gapPos = i;
++src;
} else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' &&
gapPos == -1) {
gapPos = i;
src += 2;
} else {
return 0;
}
}
if (setWords > 8 ||
(setWords == 8 && gapPos != -1) ||
(setWords < 8 && gapPos == -1))
return 0;
if (gapPos >= 0) {
int nToMove = setWords - (dot ? 2 : 0) - gapPos;
int gapLen = 8 - setWords;
tor_assert(nToMove >= 0);
memmove(&words[gapPos+gapLen], &words[gapPos],
sizeof(uint16_t)*nToMove);
memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
}
for (i = 0; i < 8; ++i) {
out->s6_addr[2*i ] = words[i] >> 8;
out->s6_addr[2*i+1] = words[i] & 0xff;
}
return 1;
} else {
return -1;
}
}
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
* *<b>addr</b> to the proper IP address, in host byte order. Returns 0
* on success, -1 on failure; 1 on transient failure.
*
* (This function exists because standard windows gethostbyname
* doesn't treat raw IP addresses properly.)
*/
MOCK_IMPL(int,
tor_lookup_hostname,(const char *name, uint32_t *addr))
{
tor_addr_t myaddr;
int ret;
if ((ret = tor_addr_lookup(name, AF_INET, &myaddr)))
return ret;
if (tor_addr_family(&myaddr) == AF_INET) {
*addr = tor_addr_to_ipv4h(&myaddr);
return ret;
}
return -1;
}
/** Hold the result of our call to <b>uname</b>. */
static char uname_result[256];
/** True iff uname_result is set. */
+4 -182
View File
@@ -50,6 +50,10 @@
#include "lib/string/compat_ctype.h"
#include "lib/string/compat_string.h"
#include "lib/string/printf.h"
#include "lib/net/socket.h"
#include "lib/net/ipv4.h"
#include "lib/net/ipv6.h"
#include "lib/net/resolve.h"
#include <stdio.h>
#include <errno.h>
@@ -162,180 +166,7 @@ int64_t tor_get_avail_disk_space(const char *path);
/* ===== Net compatibility */
#if (SIZEOF_SOCKLEN_T == 0)
typedef int socklen_t;
#endif
#ifdef _WIN32
/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that
* any inadvertent checks for the socket being <= 0 or > 0 will probably
* still work. */
#define tor_socket_t intptr_t
#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT
#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET)
#define TOR_INVALID_SOCKET INVALID_SOCKET
#else /* !(defined(_WIN32)) */
/** Type used for a network socket. */
#define tor_socket_t int
#define TOR_SOCKET_T_FORMAT "%d"
/** Macro: true iff 's' is a possible value for a valid initialized socket. */
#define SOCKET_OK(s) ((s) >= 0)
/** Error/uninitialized value for a tor_socket_t. */
#define TOR_INVALID_SOCKET (-1)
#endif /* defined(_WIN32) */
int tor_close_socket_simple(tor_socket_t s);
MOCK_DECL(int, tor_close_socket, (tor_socket_t s));
void tor_take_socket_ownership(tor_socket_t s);
tor_socket_t tor_open_socket_with_extensions(
int domain, int type, int protocol,
int cloexec, int nonblock);
MOCK_DECL(tor_socket_t,
tor_open_socket,(int domain, int type, int protocol));
tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol);
tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr,
socklen_t *len);
tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd,
struct sockaddr *addr,
socklen_t *len);
tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd,
struct sockaddr *addr,
socklen_t *len,
int cloexec, int nonblock);
MOCK_DECL(tor_socket_t,
tor_connect_socket,(tor_socket_t socket,const struct sockaddr *address,
socklen_t address_len));
int get_n_open_sockets(void);
MOCK_DECL(int,
tor_getsockname,(tor_socket_t socket, struct sockaddr *address,
socklen_t *address_len));
struct tor_addr_t;
int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock);
#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags)
#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags)
/** 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
* addresses. */
#if !defined(HAVE_STRUCT_IN6_ADDR)
struct in6_addr
{
union {
uint8_t u6_addr8[16];
uint16_t u6_addr16[8];
uint32_t u6_addr32[4];
} in6_u;
#define s6_addr in6_u.u6_addr8
#define s6_addr16 in6_u.u6_addr16
#define s6_addr32 in6_u.u6_addr32
};
#endif /* !defined(HAVE_STRUCT_IN6_ADDR) */
/** @{ */
/** Many BSD variants seem not to define these. */
#if defined(__APPLE__) || defined(__darwin__) || \
defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#ifndef s6_addr16
#define s6_addr16 __u6_addr.__u6_addr16
#endif
#ifndef s6_addr32
#define s6_addr32 __u6_addr.__u6_addr32
#endif
#endif /* defined(__APPLE__) || defined(__darwin__) || ... */
/** @} */
#ifndef HAVE_SA_FAMILY_T
typedef uint16_t sa_family_t;
#endif
/** @{ */
/** Apparently, MS and Solaris don't define s6_addr16 or s6_addr32; these
* macros get you a pointer to s6_addr32 or local equivalent. */
#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR32
#define S6_ADDR32(x) ((uint32_t*)(x).s6_addr32)
#else
#define S6_ADDR32(x) ((uint32_t*)((char*)&(x).s6_addr))
#endif
#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR16
#define S6_ADDR16(x) ((uint16_t*)(x).s6_addr16)
#else
#define S6_ADDR16(x) ((uint16_t*)((char*)&(x).s6_addr))
#endif
/** @} */
/** Implementation of struct sockaddr_in6 on platforms that do not have
* it. See notes on struct in6_addr. */
#if !defined(HAVE_STRUCT_SOCKADDR_IN6)
struct sockaddr_in6 {
sa_family_t sin6_family;
uint16_t sin6_port;
// uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
// uint32_t sin6_scope_id;
};
#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */
MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen));
int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2));
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);
MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr));
int set_socket_nonblocking(tor_socket_t socket);
int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]);
int network_init(void);
/* For stupid historical reasons, windows sockets have an independent
* set of errnos, and an independent way to get them. Also, you can't
* always believe WSAEWOULDBLOCK. Use the macros below to compare
* errnos against expected values, and use tor_socket_errno to find
* the actual errno after a socket operation fails.
*/
#if defined(_WIN32)
/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */
#define SOCK_ERRNO(e) WSA##e
/** Return true if e is EAGAIN or the local equivalent. */
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK)
/** Return true if e is EINPROGRESS or the local equivalent. */
#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS)
/** Return true if e is EINPROGRESS or the local equivalent as returned by
* a call to connect(). */
#define ERRNO_IS_CONN_EINPROGRESS(e) \
((e) == WSAEINPROGRESS || (e)== WSAEINVAL || (e) == WSAEWOULDBLOCK)
/** Return true if e is EAGAIN or another error indicating that a call to
* accept() has no pending connections to return. */
#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e)
/** Return true if e is EMFILE or another error indicating that a call to
* accept() has failed because we're out of fds or something. */
#define ERRNO_IS_RESOURCE_LIMIT(e) \
((e) == WSAEMFILE || (e) == WSAENOBUFS)
/** Return true if e is EADDRINUSE or the local equivalent. */
#define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE)
/** Return true if e is EINTR or the local equivalent */
#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0)
int tor_socket_errno(tor_socket_t sock);
const char *tor_socket_strerror(int e);
#else /* !(defined(_WIN32)) */
#define SOCK_ERRNO(e) e
#if EAGAIN == EWOULDBLOCK
/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0)
#else
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK)
#endif /* EAGAIN == EWOULDBLOCK */
#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0)
#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0)
#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0)
#define ERRNO_IS_ACCEPT_EAGAIN(e) \
(ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED)
#define ERRNO_IS_RESOURCE_LIMIT(e) \
((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0)
#define tor_socket_errno(sock) (errno)
#define tor_socket_strerror(e) strerror(e)
#endif /* defined(_WIN32) */
/** Specified SOCKS5 status codes. */
typedef enum {
@@ -372,7 +203,6 @@ set_uint8(void *cp, uint8_t v)
#if !defined(HAVE_RLIM_T)
typedef unsigned long rlim_t;
#endif
int get_max_sockets(void);
int set_max_file_descriptors(rlim_t limit, int *max);
int tor_disable_debugger_attach(void);
@@ -440,14 +270,6 @@ char *format_win32_error(DWORD err);
#endif /* defined(_WIN32) */
#ifdef COMPAT_PRIVATE
#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS)
#define NEED_ERSATZ_SOCKETPAIR
STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
tor_socket_t fd[2]);
#endif
#endif /* defined(COMPAT_PRIVATE) */
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen);
/* This needs some of the declarations above so we include it here. */
-2
View File
@@ -31,7 +31,6 @@ readpassphrase_source=
endif
LIBOR_A_SRC = \
src/common/address.c \
src/common/address_set.c \
src/common/buffers.c \
src/common/compat.c \
@@ -76,7 +75,6 @@ src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
COMMONHEADERS = \
src/common/address.h \
src/common/address_set.h \
src/common/buffers.h \
src/common/compat.h \
+2 -177
View File
@@ -37,6 +37,7 @@
#include "lib/err/torerr.h"
#include "lib/log/torlog.h"
#include "lib/cc/torint.h"
#include "lib/net/resolve.h"
#include "common/util.h"
#include "tor_queue.h"
@@ -1458,183 +1459,6 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
return 0;
}
/** Cache entry for getaddrinfo results; used when sandboxing is implemented
* so that we can consult the cache when the sandbox prevents us from doing
* getaddrinfo.
*
* We support only a limited range of getaddrinfo calls, where servname is null
* and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC.
*/
typedef struct cached_getaddrinfo_item_t {
HT_ENTRY(cached_getaddrinfo_item_t) node;
char *name;
int family;
/** set if no error; otherwise NULL */
struct addrinfo *res;
/** 0 for no error; otherwise an EAI_* value */
int err;
} cached_getaddrinfo_item_t;
static unsigned
cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item)
{
return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family;
}
static unsigned
cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a,
const cached_getaddrinfo_item_t *b)
{
return (a->family == b->family) && 0 == strcmp(a->name, b->name);
}
#define cached_getaddrinfo_item_free(item) \
FREE_AND_NULL(cached_getaddrinfo_item_t, \
cached_getaddrinfo_item_free_, (item))
static void
cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item)
{
if (item == NULL)
return;
tor_free(item->name);
if (item->res)
freeaddrinfo(item->res);
tor_free(item);
}
static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
getaddrinfo_cache = HT_INITIALIZER();
HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
cached_getaddrinfo_item_hash,
cached_getaddrinfo_items_eq)
HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
cached_getaddrinfo_item_hash,
cached_getaddrinfo_items_eq,
0.6, tor_reallocarray_, tor_free_)
/** If true, don't try to cache getaddrinfo results. */
static int sandbox_getaddrinfo_cache_disabled = 0;
/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in
* tor-resolve, when we have no intention of initializing crypto or of
* installing the sandbox.*/
void
sandbox_disable_getaddrinfo_cache(void)
{
sandbox_getaddrinfo_cache_disabled = 1;
}
void
sandbox_freeaddrinfo(struct addrinfo *ai)
{
if (sandbox_getaddrinfo_cache_disabled)
freeaddrinfo(ai);
}
int
sandbox_getaddrinfo(const char *name, const char *servname,
const struct addrinfo *hints,
struct addrinfo **res)
{
int err;
struct cached_getaddrinfo_item_t search, *item;
if (sandbox_getaddrinfo_cache_disabled) {
return getaddrinfo(name, NULL, hints, res);
}
if (servname != NULL) {
log_warn(LD_BUG, "called with non-NULL servname");
return EAI_NONAME;
}
if (name == NULL) {
log_warn(LD_BUG, "called with NULL name");
return EAI_NONAME;
}
*res = NULL;
memset(&search, 0, sizeof(search));
search.name = (char *) name;
search.family = hints ? hints->ai_family : AF_UNSPEC;
item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search);
if (! sandbox_is_active()) {
/* If the sandbox is not turned on yet, then getaddrinfo and store the
result. */
err = getaddrinfo(name, NULL, hints, res);
log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded");
if (! item) {
item = tor_malloc_zero(sizeof(*item));
item->name = tor_strdup(name);
item->family = hints ? hints->ai_family : AF_UNSPEC;
HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item);
}
if (item->res) {
freeaddrinfo(item->res);
item->res = NULL;
}
item->res = *res;
item->err = err;
return err;
}
/* Otherwise, the sandbox is on. If we have an item, yield its cached
result. */
if (item) {
*res = item->res;
return item->err;
}
/* getting here means something went wrong */
log_err(LD_BUG,"(Sandbox) failed to get address %s!", name);
return EAI_NONAME;
}
int
sandbox_add_addrinfo(const char *name)
{
struct addrinfo *res;
struct addrinfo hints;
int i;
static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC };
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
for (i = 0; i < 3; ++i) {
hints.ai_family = families[i];
res = NULL;
(void) sandbox_getaddrinfo(name, NULL, &hints, &res);
if (res)
sandbox_freeaddrinfo(res);
}
return 0;
}
void
sandbox_free_getaddrinfo_cache(void)
{
cached_getaddrinfo_item_t **next, **item, *this;
for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache);
item;
item = next) {
this = *item;
next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item);
cached_getaddrinfo_item_free(this);
}
HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache);
}
/**
* Function responsible for going through the parameter syscall filters and
* call each function pointer in the list.
@@ -1727,6 +1551,7 @@ install_syscall_filter(sandbox_cfg_t* cfg)
// marking the sandbox as active
sandbox_active = 1;
sandbox_make_getaddrinfo_cache_active();
end:
seccomp_release(ctx);
-24
View File
@@ -103,27 +103,6 @@ typedef struct {
#endif /* defined(USE_LIBSECCOMP) */
#ifdef USE_LIBSECCOMP
/** Pre-calls getaddrinfo in order to pre-record result. */
int sandbox_add_addrinfo(const char *addr);
struct addrinfo;
/** Replacement for getaddrinfo(), using pre-recorded results. */
int sandbox_getaddrinfo(const char *name, const char *servname,
const struct addrinfo *hints,
struct addrinfo **res);
void sandbox_freeaddrinfo(struct addrinfo *addrinfo);
void sandbox_free_getaddrinfo_cache(void);
#else /* !(defined(USE_LIBSECCOMP)) */
#define sandbox_getaddrinfo(name, servname, hints, res) \
getaddrinfo((name),(servname), (hints),(res))
#define sandbox_add_addrinfo(name) \
((void)(name))
#define sandbox_freeaddrinfo(addrinfo) \
freeaddrinfo((addrinfo))
#define sandbox_free_getaddrinfo_cache()
#endif /* defined(USE_LIBSECCOMP) */
#ifdef USE_LIBSECCOMP
/** Returns a registered protected string used with the sandbox, given that
* it matches the parameter.
@@ -168,7 +147,4 @@ int sandbox_init(sandbox_cfg_t* cfg);
/** Return true iff the sandbox is turned on. */
int sandbox_is_active(void);
void sandbox_disable_getaddrinfo_cache(void);
#endif /* !defined(SANDBOX_H_) */