mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
Merge branch 'net_refactor'
This commit is contained in:
@@ -183,6 +183,8 @@ uptime-*.json
|
||||
/src/lib/libtor-log-testing.a
|
||||
/src/lib/libtor-malloc.a
|
||||
/src/lib/libtor-malloc-testing.a
|
||||
/src/lib/libtor-net.a
|
||||
/src/lib/libtor-net-testing.a
|
||||
/src/lib/libtor-string.a
|
||||
/src/lib/libtor-string-testing.a
|
||||
/src/lib/libtor-smartlist-core.a
|
||||
|
||||
@@ -41,6 +41,7 @@ endif
|
||||
TOR_UTIL_LIBS = \
|
||||
src/common/libor.a \
|
||||
src/lib/libtor-container.a \
|
||||
src/lib/libtor-net.a \
|
||||
src/lib/libtor-log.a \
|
||||
src/lib/libtor-lock.a \
|
||||
src/lib/libtor-fdio.a \
|
||||
@@ -57,6 +58,7 @@ TOR_UTIL_LIBS = \
|
||||
TOR_UTIL_TESTING_LIBS = \
|
||||
src/common/libor-testing.a \
|
||||
src/lib/libtor-container-testing.a \
|
||||
src/lib/libtor-net-testing.a \
|
||||
src/lib/libtor-log-testing.a \
|
||||
src/lib/libtor-lock-testing.a \
|
||||
src/lib/libtor-fdio-testing.a \
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
o Removed features:
|
||||
- Tor no longer attempts to run on Windows environments without the
|
||||
GetAdaptersAddresses() function. This function has existed since
|
||||
Windows XP, which is itself already older than we support.
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "common/address_set.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "common/compat.h"
|
||||
#include "lib/container/bloomfilt.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
|
||||
+6
-865
@@ -128,14 +128,9 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
|
||||
#include "common/util.h"
|
||||
#include "lib/container/smartlist.h"
|
||||
#include "lib/wallclock/tm_cvt.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/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
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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_) */
|
||||
|
||||
|
||||
+1
-239
@@ -20,7 +20,7 @@
|
||||
#include "lib/cc/torint.h"
|
||||
#include "lib/container/smartlist.h"
|
||||
#include "lib/fdio/fdio.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "common/sandbox.h"
|
||||
#include "lib/err/backtrace.h"
|
||||
#include "common/util_process.h"
|
||||
@@ -443,244 +443,6 @@ tor_digest256_is_zero(const char *digest)
|
||||
return tor_mem_is_zero(digest, DIGEST256_LEN);
|
||||
}
|
||||
|
||||
/* Helper: common code to check whether the result of a strtol or strtoul or
|
||||
* strtoll is correct. */
|
||||
#define CHECK_STRTOX_RESULT() \
|
||||
/* Did an overflow occur? */ \
|
||||
if (errno == ERANGE) \
|
||||
goto err; \
|
||||
/* Was at least one character converted? */ \
|
||||
if (endptr == s) \
|
||||
goto err; \
|
||||
/* Were there unexpected unconverted characters? */ \
|
||||
if (!next && *endptr) \
|
||||
goto err; \
|
||||
/* Illogical (max, min) inputs? */ \
|
||||
if (BUG(max < min)) \
|
||||
goto err; \
|
||||
/* Is r within limits? */ \
|
||||
if (r < min || r > max) \
|
||||
goto err; \
|
||||
if (ok) *ok = 1; \
|
||||
if (next) *next = endptr; \
|
||||
return r; \
|
||||
err: \
|
||||
if (ok) *ok = 0; \
|
||||
if (next) *next = endptr; \
|
||||
return 0
|
||||
|
||||
/** Extract a long from the start of <b>s</b>, in the given numeric
|
||||
* <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal,
|
||||
* octal, or hex number in the syntax of a C integer literal. If
|
||||
* there is unconverted data and <b>next</b> is provided, set
|
||||
* *<b>next</b> to the first unconverted character. An error has
|
||||
* occurred if no characters are converted; or if there are
|
||||
* unconverted characters and <b>next</b> is NULL; or if the parsed
|
||||
* value is not between <b>min</b> and <b>max</b>. When no error
|
||||
* occurs, return the parsed value and set *<b>ok</b> (if provided) to
|
||||
* 1. When an error occurs, return 0 and set *<b>ok</b> (if provided)
|
||||
* to 0.
|
||||
*/
|
||||
long
|
||||
tor_parse_long(const char *s, int base, long min, long max,
|
||||
int *ok, char **next)
|
||||
{
|
||||
char *endptr;
|
||||
long r;
|
||||
|
||||
if (BUG(base < 0)) {
|
||||
if (ok)
|
||||
*ok = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
r = strtol(s, &endptr, base);
|
||||
CHECK_STRTOX_RESULT();
|
||||
}
|
||||
|
||||
/** As tor_parse_long(), but return an unsigned long. */
|
||||
unsigned long
|
||||
tor_parse_ulong(const char *s, int base, unsigned long min,
|
||||
unsigned long max, int *ok, char **next)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long r;
|
||||
|
||||
if (BUG(base < 0)) {
|
||||
if (ok)
|
||||
*ok = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
r = strtoul(s, &endptr, base);
|
||||
CHECK_STRTOX_RESULT();
|
||||
}
|
||||
|
||||
/** As tor_parse_long(), but return a double. */
|
||||
double
|
||||
tor_parse_double(const char *s, double min, double max, int *ok, char **next)
|
||||
{
|
||||
char *endptr;
|
||||
double r;
|
||||
|
||||
errno = 0;
|
||||
r = strtod(s, &endptr);
|
||||
CHECK_STRTOX_RESULT();
|
||||
}
|
||||
|
||||
/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to
|
||||
* work for now. */
|
||||
uint64_t
|
||||
tor_parse_uint64(const char *s, int base, uint64_t min,
|
||||
uint64_t max, int *ok, char **next)
|
||||
{
|
||||
char *endptr;
|
||||
uint64_t r;
|
||||
|
||||
if (BUG(base < 0)) {
|
||||
if (ok)
|
||||
*ok = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
#ifdef HAVE_STRTOULL
|
||||
r = (uint64_t)strtoull(s, &endptr, base);
|
||||
#elif defined(_WIN32)
|
||||
r = (uint64_t)_strtoui64(s, &endptr, base);
|
||||
#elif SIZEOF_LONG == 8
|
||||
r = (uint64_t)strtoul(s, &endptr, base);
|
||||
#else
|
||||
#error "I don't know how to parse 64-bit numbers."
|
||||
#endif /* defined(HAVE_STRTOULL) || ... */
|
||||
|
||||
CHECK_STRTOX_RESULT();
|
||||
}
|
||||
|
||||
/** Allocate and return a new string representing the contents of <b>s</b>,
|
||||
* surrounded by quotes and using standard C escapes.
|
||||
*
|
||||
* Generally, we use this for logging values that come in over the network to
|
||||
* keep them from tricking users, and for sending certain values to the
|
||||
* controller.
|
||||
*
|
||||
* We trust values from the resolver, OS, configuration file, and command line
|
||||
* to not be maliciously ill-formed. We validate incoming routerdescs and
|
||||
* SOCKS requests and addresses from BEGIN cells as they're parsed;
|
||||
* afterwards, we trust them as non-malicious.
|
||||
*/
|
||||
char *
|
||||
esc_for_log(const char *s)
|
||||
{
|
||||
const char *cp;
|
||||
char *result, *outp;
|
||||
size_t len = 3;
|
||||
if (!s) {
|
||||
return tor_strdup("(null)");
|
||||
}
|
||||
|
||||
for (cp = s; *cp; ++cp) {
|
||||
switch (*cp) {
|
||||
case '\\':
|
||||
case '\"':
|
||||
case '\'':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\t':
|
||||
len += 2;
|
||||
break;
|
||||
default:
|
||||
if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127)
|
||||
++len;
|
||||
else
|
||||
len += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tor_assert(len <= SSIZE_MAX);
|
||||
|
||||
result = outp = tor_malloc(len);
|
||||
*outp++ = '\"';
|
||||
for (cp = s; *cp; ++cp) {
|
||||
/* This assertion should always succeed, since we will write at least
|
||||
* one char here, and two chars for closing quote and nul later */
|
||||
tor_assert((outp-result) < (ssize_t)len-2);
|
||||
switch (*cp) {
|
||||
case '\\':
|
||||
case '\"':
|
||||
case '\'':
|
||||
*outp++ = '\\';
|
||||
*outp++ = *cp;
|
||||
break;
|
||||
case '\n':
|
||||
*outp++ = '\\';
|
||||
*outp++ = 'n';
|
||||
break;
|
||||
case '\t':
|
||||
*outp++ = '\\';
|
||||
*outp++ = 't';
|
||||
break;
|
||||
case '\r':
|
||||
*outp++ = '\\';
|
||||
*outp++ = 'r';
|
||||
break;
|
||||
default:
|
||||
if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) {
|
||||
*outp++ = *cp;
|
||||
} else {
|
||||
tor_assert((outp-result) < (ssize_t)len-4);
|
||||
tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp);
|
||||
outp += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tor_assert((outp-result) <= (ssize_t)len-2);
|
||||
*outp++ = '\"';
|
||||
*outp++ = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Similar to esc_for_log. Allocate and return a new string representing
|
||||
* the first n characters in <b>chars</b>, surround by quotes and using
|
||||
* standard C escapes. If a NUL character is encountered in <b>chars</b>,
|
||||
* the resulting string will be terminated there.
|
||||
*/
|
||||
char *
|
||||
esc_for_log_len(const char *chars, size_t n)
|
||||
{
|
||||
char *string = tor_strndup(chars, n);
|
||||
char *string_escaped = esc_for_log(string);
|
||||
tor_free(string);
|
||||
return string_escaped;
|
||||
}
|
||||
|
||||
/** Allocate and return a new string representing the contents of <b>s</b>,
|
||||
* surrounded by quotes and using standard C escapes.
|
||||
*
|
||||
* THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main
|
||||
* thread. Also, each call invalidates the last-returned value, so don't
|
||||
* try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b));
|
||||
*/
|
||||
const char *
|
||||
escaped(const char *s)
|
||||
{
|
||||
static char *escaped_val_ = NULL;
|
||||
tor_free(escaped_val_);
|
||||
|
||||
if (s)
|
||||
escaped_val_ = esc_for_log(s);
|
||||
else
|
||||
escaped_val_ = NULL;
|
||||
|
||||
return escaped_val_;
|
||||
}
|
||||
|
||||
/** Return a newly allocated string equal to <b>string</b>, except that every
|
||||
* character in <b>chars_to_escape</b> is preceded by a backslash. */
|
||||
char *
|
||||
|
||||
+2
-13
@@ -26,6 +26,7 @@
|
||||
#include "lib/malloc/util_malloc.h"
|
||||
#include "lib/wallclock/approx_time.h"
|
||||
#include "lib/string/util_string.h"
|
||||
#include "lib/string/parse_int.h"
|
||||
#include "lib/string/scanf.h"
|
||||
#include "lib/intmath/bits.h"
|
||||
#include "lib/intmath/addsub.h"
|
||||
@@ -33,6 +34,7 @@
|
||||
#include "lib/intmath/cmp.h"
|
||||
#include "lib/log/ratelim.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
#include "lib/log/escape.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
@@ -78,15 +80,6 @@ int64_t clamp_double_to_int64(double number);
|
||||
|
||||
/* String manipulation */
|
||||
|
||||
long tor_parse_long(const char *s, int base, long min,
|
||||
long max, int *ok, char **next);
|
||||
unsigned long tor_parse_ulong(const char *s, int base, unsigned long min,
|
||||
unsigned long max, int *ok, char **next);
|
||||
double tor_parse_double(const char *s, double min, double max, int *ok,
|
||||
char **next);
|
||||
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min,
|
||||
uint64_t max, int *ok, char **next);
|
||||
|
||||
const char *hex_str(const char *from, size_t fromlen) ATTR_NONNULL((1));
|
||||
|
||||
int string_is_key_value(int severity, const char *string);
|
||||
@@ -99,10 +92,6 @@ int tor_mem_is_zero(const char *mem, size_t len);
|
||||
int tor_digest_is_zero(const char *digest);
|
||||
int tor_digest256_is_zero(const char *digest);
|
||||
|
||||
char *esc_for_log(const char *string) ATTR_MALLOC;
|
||||
char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC;
|
||||
const char *escaped(const char *string);
|
||||
|
||||
char *tor_escape_str_for_pt_args(const char *string,
|
||||
const char *chars_to_escape);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ include src/lib/intmath/include.am
|
||||
include src/lib/lock/include.am
|
||||
include src/lib/log/include.am
|
||||
include src/lib/malloc/include.am
|
||||
include src/lib/net/include.am
|
||||
include src/lib/string/include.am
|
||||
include src/lib/smartlist_core/include.am
|
||||
include src/lib/testsupport/include.am
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/* Copyright (c) 2003, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "lib/log/escape.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
#include "lib/string/compat_ctype.h"
|
||||
#include "lib/string/printf.h"
|
||||
#include "lib/malloc/util_malloc.h"
|
||||
|
||||
/** Allocate and return a new string representing the contents of <b>s</b>,
|
||||
* surrounded by quotes and using standard C escapes.
|
||||
*
|
||||
* Generally, we use this for logging values that come in over the network to
|
||||
* keep them from tricking users, and for sending certain values to the
|
||||
* controller.
|
||||
*
|
||||
* We trust values from the resolver, OS, configuration file, and command line
|
||||
* to not be maliciously ill-formed. We validate incoming routerdescs and
|
||||
* SOCKS requests and addresses from BEGIN cells as they're parsed;
|
||||
* afterwards, we trust them as non-malicious.
|
||||
*/
|
||||
char *
|
||||
esc_for_log(const char *s)
|
||||
{
|
||||
const char *cp;
|
||||
char *result, *outp;
|
||||
size_t len = 3;
|
||||
if (!s) {
|
||||
return tor_strdup("(null)");
|
||||
}
|
||||
|
||||
for (cp = s; *cp; ++cp) {
|
||||
switch (*cp) {
|
||||
case '\\':
|
||||
case '\"':
|
||||
case '\'':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\t':
|
||||
len += 2;
|
||||
break;
|
||||
default:
|
||||
if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127)
|
||||
++len;
|
||||
else
|
||||
len += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tor_assert(len <= SSIZE_MAX);
|
||||
|
||||
result = outp = tor_malloc(len);
|
||||
*outp++ = '\"';
|
||||
for (cp = s; *cp; ++cp) {
|
||||
/* This assertion should always succeed, since we will write at least
|
||||
* one char here, and two chars for closing quote and nul later */
|
||||
tor_assert((outp-result) < (ssize_t)len-2);
|
||||
switch (*cp) {
|
||||
case '\\':
|
||||
case '\"':
|
||||
case '\'':
|
||||
*outp++ = '\\';
|
||||
*outp++ = *cp;
|
||||
break;
|
||||
case '\n':
|
||||
*outp++ = '\\';
|
||||
*outp++ = 'n';
|
||||
break;
|
||||
case '\t':
|
||||
*outp++ = '\\';
|
||||
*outp++ = 't';
|
||||
break;
|
||||
case '\r':
|
||||
*outp++ = '\\';
|
||||
*outp++ = 'r';
|
||||
break;
|
||||
default:
|
||||
if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) {
|
||||
*outp++ = *cp;
|
||||
} else {
|
||||
tor_assert((outp-result) < (ssize_t)len-4);
|
||||
tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp);
|
||||
outp += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tor_assert((outp-result) <= (ssize_t)len-2);
|
||||
*outp++ = '\"';
|
||||
*outp++ = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Similar to esc_for_log. Allocate and return a new string representing
|
||||
* the first n characters in <b>chars</b>, surround by quotes and using
|
||||
* standard C escapes. If a NUL character is encountered in <b>chars</b>,
|
||||
* the resulting string will be terminated there.
|
||||
*/
|
||||
char *
|
||||
esc_for_log_len(const char *chars, size_t n)
|
||||
{
|
||||
char *string = tor_strndup(chars, n);
|
||||
char *string_escaped = esc_for_log(string);
|
||||
tor_free(string);
|
||||
return string_escaped;
|
||||
}
|
||||
|
||||
/** Allocate and return a new string representing the contents of <b>s</b>,
|
||||
* surrounded by quotes and using standard C escapes.
|
||||
*
|
||||
* THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main
|
||||
* thread. Also, each call invalidates the last-returned value, so don't
|
||||
* try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b));
|
||||
*/
|
||||
const char *
|
||||
escaped(const char *s)
|
||||
{
|
||||
static char *escaped_val_ = NULL;
|
||||
tor_free(escaped_val_);
|
||||
|
||||
if (s)
|
||||
escaped_val_ = esc_for_log(s);
|
||||
else
|
||||
escaped_val_ = NULL;
|
||||
|
||||
return escaped_val_;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/* Copyright (c) 2001, Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_ESCAPE_H
|
||||
#define TOR_ESCAPE_H
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "lib/cc/compat_compiler.h"
|
||||
#include <stddef.h>
|
||||
|
||||
char *esc_for_log(const char *string) ATTR_MALLOC;
|
||||
char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC;
|
||||
const char *escaped(const char *string);
|
||||
|
||||
#endif /* !defined(TOR_TORLOG_H) */
|
||||
@@ -6,6 +6,7 @@ noinst_LIBRARIES += src/lib/libtor-log-testing.a
|
||||
endif
|
||||
|
||||
src_lib_libtor_log_a_SOURCES = \
|
||||
src/lib/log/escape.c \
|
||||
src/lib/log/ratelim.c \
|
||||
src/lib/log/torlog.c \
|
||||
src/lib/log/util_bug.c
|
||||
@@ -19,6 +20,7 @@ src/lib/log/torlog.$(OBJEXT) \
|
||||
src/lib/log/src_lib_libtor_log_testing_a-torlog.$(OBJEXT): micro-revision.i
|
||||
|
||||
noinst_HEADERS += \
|
||||
src/lib/log/escape.h \
|
||||
src/lib/log/ratelim.h \
|
||||
src/lib/log/torlog.h \
|
||||
src/lib/log/util_bug.h
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
orconfig.h
|
||||
siphash.h
|
||||
ht.h
|
||||
|
||||
lib/cc/*.h
|
||||
lib/container/*.h
|
||||
lib/ctime/*.h
|
||||
lib/lock/*.h
|
||||
lib/log/*.h
|
||||
lib/net/*.h
|
||||
lib/string/*.h
|
||||
lib/testsupport/*.h
|
||||
lib/malloc/*.h
|
||||
@@ -35,13 +35,21 @@
|
||||
#include <iphlpapi.h>
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#include "common/compat.h"
|
||||
#include "common/util.h"
|
||||
#include "common/util_format.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/log/torlog.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "lib/net/socket.h"
|
||||
#include "lib/net/resolve.h"
|
||||
#include "lib/container/smartlist.h"
|
||||
#include "common/sandbox.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/string/compat_ctype.h"
|
||||
#include "lib/string/compat_string.h"
|
||||
#include "lib/string/parse_int.h"
|
||||
#include "lib/string/printf.h"
|
||||
#include "lib/string/util_string.h"
|
||||
|
||||
#include "siphash.h"
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
@@ -53,9 +61,6 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
@@ -1474,14 +1479,7 @@ ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses)
|
||||
STATIC smartlist_t *
|
||||
get_interface_addresses_win32(int severity, sa_family_t family)
|
||||
{
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll"));
|
||||
smartlist_t *result = NULL;
|
||||
GetAdaptersAddresses_fn_t fn;
|
||||
ULONG size, res;
|
||||
IP_ADAPTER_ADDRESSES *addresses = NULL;
|
||||
|
||||
@@ -1491,27 +1489,16 @@ get_interface_addresses_win32(int severity, sa_family_t family)
|
||||
GAA_FLAG_SKIP_MULTICAST | \
|
||||
GAA_FLAG_SKIP_DNS_SERVER)
|
||||
|
||||
if (!lib) {
|
||||
log_fn(severity, LD_NET, "Unable to load iphlpapi.dll");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(fn = (GetAdaptersAddresses_fn_t)
|
||||
GetProcAddress(lib, "GetAdaptersAddresses"))) {
|
||||
log_fn(severity, LD_NET, "Unable to obtain pointer to "
|
||||
"GetAdaptersAddresses");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Guess how much space we need. */
|
||||
size = 15*1024;
|
||||
addresses = tor_malloc(size);
|
||||
res = fn(family, FLAGS, NULL, addresses, &size);
|
||||
/* Exists in windows XP and later. */
|
||||
res = GetAdaptersAddresses(family, FLAGS, NULL, addresses, &size);
|
||||
if (res == ERROR_BUFFER_OVERFLOW) {
|
||||
/* we didn't guess that we needed enough space; try again */
|
||||
tor_free(addresses);
|
||||
addresses = tor_malloc(size);
|
||||
res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
|
||||
res = GetAdaptersAddresses(AF_UNSPEC, FLAGS, NULL, addresses, &size);
|
||||
}
|
||||
if (res != NO_ERROR) {
|
||||
log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res);
|
||||
@@ -1521,8 +1508,6 @@ get_interface_addresses_win32(int severity, sa_family_t family)
|
||||
result = ip_adapter_addresses_to_smartlist(addresses);
|
||||
|
||||
done:
|
||||
if (lib)
|
||||
FreeLibrary(lib);
|
||||
tor_free(addresses);
|
||||
return result;
|
||||
}
|
||||
@@ -2087,22 +2072,6 @@ parse_port_range(const char *port, uint16_t *port_min_out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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 a host-order <b>addr</b>, call tor_inet_ntop() on it
|
||||
* and return a strdup of the resulting address.
|
||||
*/
|
||||
@@ -11,11 +11,22 @@
|
||||
#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"
|
||||
#include "lib/net/ipv6.h"
|
||||
#include "lib/net/nettypes.h"
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef ADDRESS_PRIVATE
|
||||
|
||||
@@ -73,6 +84,9 @@ typedef struct tor_addr_port_t
|
||||
|
||||
#define TOR_ADDR_NULL {AF_UNSPEC, {0}}
|
||||
|
||||
/* XXXX To do: extract all of the functions here that can possibly invoke
|
||||
* XXXX resolver, and make sure they have distinctive names. */
|
||||
|
||||
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);
|
||||
@@ -321,9 +335,6 @@ int addr_port_lookup(int severity, const char *addrport, char **address,
|
||||
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)\
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
noinst_LIBRARIES += src/lib/libtor-net.a
|
||||
|
||||
if UNITTESTS_ENABLED
|
||||
noinst_LIBRARIES += src/lib/libtor-net-testing.a
|
||||
endif
|
||||
|
||||
src_lib_libtor_net_a_SOURCES = \
|
||||
src/lib/net/address.c \
|
||||
src/lib/net/ipv4.c \
|
||||
src/lib/net/ipv6.c \
|
||||
src/lib/net/resolve.c \
|
||||
src/lib/net/socket.c
|
||||
|
||||
src_lib_libtor_net_testing_a_SOURCES = \
|
||||
$(src_lib_libtor_net_a_SOURCES)
|
||||
src_lib_libtor_net_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
|
||||
src_lib_libtor_net_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
|
||||
noinst_HEADERS += \
|
||||
src/lib/net/address.h \
|
||||
src/lib/net/ipv4.h \
|
||||
src/lib/net/ipv6.h \
|
||||
src/lib/net/nettypes.h \
|
||||
src/lib/net/resolve.h \
|
||||
src/lib/net/socket.h
|
||||
@@ -0,0 +1,52 @@
|
||||
/* 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 */
|
||||
|
||||
#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);
|
||||
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));
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef TOR_IPV4_H
|
||||
#define TOR_IPV4_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);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,221 @@
|
||||
/* 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 */
|
||||
|
||||
#include "lib/net/ipv6.h"
|
||||
#include "lib/net/ipv4.h"
|
||||
#include "lib/string/util_string.h"
|
||||
#include "lib/string/compat_string.h"
|
||||
#include "lib/string/compat_ctype.h"
|
||||
#include "lib/string/printf.h"
|
||||
#include "lib/string/scanf.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/** 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef TOR_IPV6_H
|
||||
#define TOR_IPV6_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"
|
||||
|
||||
/** 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) */
|
||||
|
||||
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
|
||||
@@ -0,0 +1,39 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef TOR_NET_TYPES_H
|
||||
#define TOR_NET_TYPES_H
|
||||
|
||||
#include "orconfig.h"
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#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) */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,236 @@
|
||||
/* 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 */
|
||||
|
||||
#include "lib/net/resolve.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "lib/malloc/util_malloc.h"
|
||||
|
||||
#include "siphash.h"
|
||||
#include "ht.h"
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
#ifdef USE_SANDBOX_GETADDRINFO
|
||||
/** True if we should only return cached values */
|
||||
static int sandbox_getaddrinfo_is_active = 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_getaddrinfo_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);
|
||||
}
|
||||
|
||||
void
|
||||
sandbox_make_getaddrinfo_cache_active(void)
|
||||
{
|
||||
sandbox_getaddrinfo_is_active = 1;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef TOR_RESOLVE_H
|
||||
#define TOR_RESOLVE_H
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "lib/cc/torint.h"
|
||||
#include "lib/testsupport/testsupport.h"
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SECCOMP_H) && defined(__linux__)
|
||||
#define USE_SANDBOX_GETADDRINFO
|
||||
#endif
|
||||
|
||||
MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr));
|
||||
|
||||
struct addrinfo;
|
||||
#ifdef USE_SANDBOX_GETADDRINFO
|
||||
/** Pre-calls getaddrinfo in order to pre-record result. */
|
||||
int sandbox_add_addrinfo(const char *addr);
|
||||
|
||||
// XXXX rename these. They are named as though they were sandbox-only,
|
||||
// XXXX but in fact they're the only allowed entry point to getaddrinfo.
|
||||
// XXXX They don't invoke the sandbox code; they only have an internal cache.
|
||||
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);
|
||||
void sandbox_make_getaddrinfo_cache_active(void);
|
||||
#else /* !(defined(USE_SANDBOX_GETADDRINFO)) */
|
||||
#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_SANDBOX_GETADDRINFO) */
|
||||
|
||||
void sandbox_disable_getaddrinfo_cache(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,649 @@
|
||||
/* 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 */
|
||||
|
||||
#define SOCKET_PRIVATE
|
||||
#include "lib/net/socket.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "lib/cc/compat_compiler.h"
|
||||
#include "lib/lock/compat_mutex.h"
|
||||
#include "lib/log/torlog.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* When set_max_file_sockets() 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;
|
||||
|
||||
/** Return the maximum number of allowed sockets. */
|
||||
int
|
||||
get_max_sockets(void)
|
||||
{
|
||||
return max_sockets;
|
||||
}
|
||||
|
||||
/** Set the maximum number of allowed sockets to <b>n</b> */
|
||||
void
|
||||
set_max_sockets(int n)
|
||||
{
|
||||
max_sockets = n;
|
||||
}
|
||||
|
||||
#undef DEBUG_SOCKET_COUNTING
|
||||
#ifdef DEBUG_SOCKET_COUNTING
|
||||
#include "lib/container/bitarray.h"
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */
|
||||
|
||||
/** 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(struct 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;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/* 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 */
|
||||
|
||||
#ifndef TOR_SOCKET_H
|
||||
#define TOR_SOCKET_H
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "lib/cc/torint.h"
|
||||
#include "lib/net/nettypes.h"
|
||||
#include "lib/testsupport/testsupport.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
struct sockaddr;
|
||||
|
||||
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)
|
||||
|
||||
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);
|
||||
|
||||
int get_max_sockets(void);
|
||||
void set_max_sockets(int);
|
||||
|
||||
/* 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) */
|
||||
|
||||
#ifdef SOCKET_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) */
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,7 @@ src_lib_libtor_string_a_SOURCES = \
|
||||
src/lib/string/compat_ctype.c \
|
||||
src/lib/string/compat_string.c \
|
||||
src/lib/string/util_string.c \
|
||||
src/lib/string/parse_int.c \
|
||||
src/lib/string/printf.c \
|
||||
src/lib/string/scanf.c
|
||||
|
||||
@@ -21,5 +22,6 @@ noinst_HEADERS += \
|
||||
src/lib/string/compat_ctype.h \
|
||||
src/lib/string/compat_string.h \
|
||||
src/lib/string/util_string.h \
|
||||
src/lib/string/parse_int.h \
|
||||
src/lib/string/printf.h \
|
||||
src/lib/string/scanf.h
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/* Copyright (c) 2003, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "lib/string/parse_int.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Helper: common code to check whether the result of a strtol or strtoul or
|
||||
* strtoll is correct. */
|
||||
#define CHECK_STRTOX_RESULT() \
|
||||
/* Did an overflow occur? */ \
|
||||
if (errno == ERANGE) \
|
||||
goto err; \
|
||||
/* Was at least one character converted? */ \
|
||||
if (endptr == s) \
|
||||
goto err; \
|
||||
/* Were there unexpected unconverted characters? */ \
|
||||
if (!next && *endptr) \
|
||||
goto err; \
|
||||
/* Illogical (max, min) inputs? */ \
|
||||
if (max < min) \
|
||||
goto err; \
|
||||
/* Is r within limits? */ \
|
||||
if (r < min || r > max) \
|
||||
goto err; \
|
||||
if (ok) *ok = 1; \
|
||||
if (next) *next = endptr; \
|
||||
return r; \
|
||||
err: \
|
||||
if (ok) *ok = 0; \
|
||||
if (next) *next = endptr; \
|
||||
return 0
|
||||
|
||||
/** Extract a long from the start of <b>s</b>, in the given numeric
|
||||
* <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal,
|
||||
* octal, or hex number in the syntax of a C integer literal. If
|
||||
* there is unconverted data and <b>next</b> is provided, set
|
||||
* *<b>next</b> to the first unconverted character. An error has
|
||||
* occurred if no characters are converted; or if there are
|
||||
* unconverted characters and <b>next</b> is NULL; or if the parsed
|
||||
* value is not between <b>min</b> and <b>max</b>. When no error
|
||||
* occurs, return the parsed value and set *<b>ok</b> (if provided) to
|
||||
* 1. When an error occurs, return 0 and set *<b>ok</b> (if provided)
|
||||
* to 0.
|
||||
*/
|
||||
long
|
||||
tor_parse_long(const char *s, int base, long min, long max,
|
||||
int *ok, char **next)
|
||||
{
|
||||
char *endptr;
|
||||
long r;
|
||||
|
||||
if (base < 0) {
|
||||
if (ok)
|
||||
*ok = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
r = strtol(s, &endptr, base);
|
||||
CHECK_STRTOX_RESULT();
|
||||
}
|
||||
|
||||
/** As tor_parse_long(), but return an unsigned long. */
|
||||
unsigned long
|
||||
tor_parse_ulong(const char *s, int base, unsigned long min,
|
||||
unsigned long max, int *ok, char **next)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long r;
|
||||
|
||||
if (base < 0) {
|
||||
if (ok)
|
||||
*ok = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
r = strtoul(s, &endptr, base);
|
||||
CHECK_STRTOX_RESULT();
|
||||
}
|
||||
|
||||
/** As tor_parse_long(), but return a double. */
|
||||
double
|
||||
tor_parse_double(const char *s, double min, double max, int *ok, char **next)
|
||||
{
|
||||
char *endptr;
|
||||
double r;
|
||||
|
||||
errno = 0;
|
||||
r = strtod(s, &endptr);
|
||||
CHECK_STRTOX_RESULT();
|
||||
}
|
||||
|
||||
/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to
|
||||
* work for now. */
|
||||
uint64_t
|
||||
tor_parse_uint64(const char *s, int base, uint64_t min,
|
||||
uint64_t max, int *ok, char **next)
|
||||
{
|
||||
char *endptr;
|
||||
uint64_t r;
|
||||
|
||||
if (base < 0) {
|
||||
if (ok)
|
||||
*ok = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
#ifdef HAVE_STRTOULL
|
||||
r = (uint64_t)strtoull(s, &endptr, base);
|
||||
#elif defined(_WIN32)
|
||||
r = (uint64_t)_strtoui64(s, &endptr, base);
|
||||
#elif SIZEOF_LONG == 8
|
||||
r = (uint64_t)strtoul(s, &endptr, base);
|
||||
#else
|
||||
#error "I don't know how to parse 64-bit numbers."
|
||||
#endif /* defined(HAVE_STRTOULL) || ... */
|
||||
|
||||
CHECK_STRTOX_RESULT();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Copyright (c) 2003, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_PARSE_INT_H
|
||||
#define TOR_PARSE_INT_H
|
||||
|
||||
#include "lib/cc/torint.h"
|
||||
|
||||
long tor_parse_long(const char *s, int base, long min,
|
||||
long max, int *ok, char **next);
|
||||
unsigned long tor_parse_ulong(const char *s, int base, unsigned long min,
|
||||
unsigned long max, int *ok, char **next);
|
||||
double tor_parse_double(const char *s, double min, double max, int *ok,
|
||||
char **next);
|
||||
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min,
|
||||
uint64_t max, int *ok, char **next);
|
||||
|
||||
#endif
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "or/or.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "lib/crypt_ops/crypto.h"
|
||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||
#include "trunnel/ed25519_cert.h" /* needed for trunnel */
|
||||
|
||||
+3
-2
@@ -162,7 +162,7 @@ src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libev
|
||||
src_or_tor_LDADD = $(TOR_INTERNAL_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
|
||||
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
|
||||
|
||||
@@ -173,7 +173,8 @@ src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
|
||||
src_or_tor_cov_LDADD = $(TOR_INTERNAL_TESTING_LIBS) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ \
|
||||
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
|
||||
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
|
||||
endif
|
||||
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
#define NODELIST_PRIVATE
|
||||
|
||||
#include "or/or.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "common/address_set.h"
|
||||
#include "or/bridges.h"
|
||||
#include "or/config.h"
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@
|
||||
#include "lib/container/smartlist.h"
|
||||
#include "lib/container/map.h"
|
||||
#include "lib/compress/compress.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "common/compat_libevent.h"
|
||||
#include "ht.h"
|
||||
#include "common/confline.h"
|
||||
|
||||
@@ -151,6 +151,7 @@ pub fn main() {
|
||||
// moving forward!
|
||||
cfg.component("tor-crypt-ops-testing");
|
||||
cfg.component("or-testing");
|
||||
cfg.component("tor-net");
|
||||
cfg.component("tor-log");
|
||||
cfg.component("tor-lock");
|
||||
cfg.component("tor-fdio");
|
||||
|
||||
@@ -11,7 +11,7 @@ FUZZING_LIBS = \
|
||||
$(rust_ldadd) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
|
||||
@TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
|
||||
@TOR_SYSTEMD_LIBS@ \
|
||||
@TOR_LZMA_LIBS@ \
|
||||
@TOR_ZSTD_LIBS@
|
||||
|
||||
+8
-8
@@ -222,7 +222,7 @@ src_test_test_switch_id_LDADD = \
|
||||
$(TOR_UTIL_TESTING_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_USERENV@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \
|
||||
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
|
||||
|
||||
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
|
||||
@@ -231,7 +231,7 @@ src_test_test_LDADD = \
|
||||
$(TOR_INTERNAL_TESTING_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@CURVE25519_LIBS@ \
|
||||
@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
|
||||
|
||||
@@ -254,7 +254,7 @@ src_test_bench_LDADD = \
|
||||
$(TOR_INTERNAL_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@CURVE25519_LIBS@ \
|
||||
@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
|
||||
|
||||
@@ -264,7 +264,7 @@ src_test_test_workqueue_LDADD = \
|
||||
$(TOR_INTERNAL_TESTING_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@CURVE25519_LIBS@ \
|
||||
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
|
||||
|
||||
@@ -276,7 +276,7 @@ src_test_test_timers_LDADD = \
|
||||
$(TOR_UTIL_TESTING_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@CURVE25519_LIBS@ \
|
||||
@TOR_LZMA_LIBS@
|
||||
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
|
||||
@@ -306,7 +306,7 @@ src_test_test_ntor_cl_LDADD = \
|
||||
$(TOR_INTERNAL_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
|
||||
@CURVE25519_LIBS@ @TOR_LZMA_LIBS@
|
||||
src_test_test_ntor_cl_AM_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS)
|
||||
@@ -316,7 +316,7 @@ src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
|
||||
src_test_test_hs_ntor_cl_LDADD = \
|
||||
$(TOR_INTERNAL_LIBS) \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
|
||||
src_test_test_hs_ntor_cl_AM_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS)
|
||||
|
||||
@@ -327,7 +327,7 @@ src_test_test_bt_cl_LDADD = \
|
||||
$(TOR_UTIL_TESTING_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_LIB_MATH@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@
|
||||
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@
|
||||
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
|
||||
|
||||
#include "or/or.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "test/test.h"
|
||||
#include "test/log_test_helpers.h"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "or/or.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "or/bridges.h"
|
||||
#include "or/config.h"
|
||||
#include "or/transports.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#define TOR_CHANNEL_INTERNAL_
|
||||
#include "or/or.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "common/buffers.h"
|
||||
#include "or/channel.h"
|
||||
#include "or/channeltls.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define PT_PRIVATE
|
||||
#define ROUTERSET_PRIVATE
|
||||
#include "or/or.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "or/addressmap.h"
|
||||
#include "or/bridges.h"
|
||||
#include "or/circuitmux_ewma.h"
|
||||
|
||||
+2
-20
@@ -9,6 +9,7 @@
|
||||
#define CONTROL_PRIVATE
|
||||
#define UTIL_PRIVATE
|
||||
#define UTIL_MALLOC_PRIVATE
|
||||
#define SOCKET_PRIVATE
|
||||
#include "or/or.h"
|
||||
#include "common/buffers.h"
|
||||
#include "or/config.h"
|
||||
@@ -2117,20 +2118,10 @@ test_util_parse_integer(void *arg)
|
||||
tt_int_op(1,OP_EQ, i);
|
||||
tt_str_op(cp,OP_EQ, " plus garbage");
|
||||
/* Illogical min max */
|
||||
tor_capture_bugs_(1);
|
||||
tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,4,&i,NULL));
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
|
||||
tt_str_op("!(max < min)", OP_EQ,
|
||||
smartlist_get(tor_get_captured_bug_log_(), 0));
|
||||
tor_end_capture_bugs_();
|
||||
tor_capture_bugs_(1);
|
||||
tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,100,-100,&i,NULL));
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
|
||||
tt_str_op("!(max < min)", OP_EQ,
|
||||
smartlist_get(tor_get_captured_bug_log_(), 0));
|
||||
tor_end_capture_bugs_();
|
||||
/* Out of bounds */
|
||||
tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL));
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
@@ -2141,11 +2132,8 @@ test_util_parse_integer(void *arg)
|
||||
tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL));
|
||||
tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL));
|
||||
tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL));
|
||||
tor_capture_bugs_(2);
|
||||
tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL));
|
||||
tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL));
|
||||
tt_int_op(2, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
|
||||
tor_end_capture_bugs_();
|
||||
tt_int_op(i,OP_EQ, 0);
|
||||
|
||||
/* Test parse_ulong */
|
||||
@@ -2158,10 +2146,7 @@ test_util_parse_integer(void *arg)
|
||||
tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL));
|
||||
tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL));
|
||||
tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,NULL,NULL));
|
||||
tor_capture_bugs_(1);
|
||||
tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL));
|
||||
tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
|
||||
tor_end_capture_bugs_();
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,&i,NULL));
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
@@ -2177,11 +2162,8 @@ test_util_parse_integer(void *arg)
|
||||
tt_assert(U64_LITERAL(0) ==
|
||||
tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp));
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
tor_capture_bugs_(1);
|
||||
tt_assert(U64_LITERAL(0) ==
|
||||
tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp));
|
||||
tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
|
||||
tor_end_capture_bugs_();
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
|
||||
{
|
||||
@@ -2226,7 +2208,7 @@ test_util_parse_integer(void *arg)
|
||||
tt_int_op(i,OP_EQ, 0);
|
||||
}
|
||||
done:
|
||||
tor_end_capture_bugs_();
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -9,7 +9,7 @@ src_tools_tor_resolve_LDFLAGS =
|
||||
src_tools_tor_resolve_LDADD = \
|
||||
$(TOR_UTIL_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_USERENV@
|
||||
@TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@
|
||||
|
||||
if COVERAGE_ENABLED
|
||||
src_tools_tor_cov_resolve_SOURCES = src/tools/tor-resolve.c
|
||||
@@ -27,7 +27,7 @@ src_tools_tor_gencert_LDADD = \
|
||||
$(TOR_UTIL_LIBS) \
|
||||
$(rust_ldadd) \
|
||||
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@
|
||||
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@
|
||||
|
||||
if COVERAGE_ENABLED
|
||||
src_tools_tor_cov_gencert_SOURCES = src/tools/tor-gencert.c
|
||||
@@ -38,7 +38,7 @@ src_tools_tor_cov_gencert_LDADD = \
|
||||
$(TOR_CRYPTO_TESTING_LIBS) \
|
||||
$(TOR_UTIL_TESTING_LIBS) \
|
||||
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
|
||||
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
|
||||
endif
|
||||
|
||||
if BUILD_LIBTORRUNNER
|
||||
|
||||
@@ -41,7 +41,7 @@ ENABLE_GCC_WARNING(redundant-decls)
|
||||
#include "lib/crypt_ops/crypto_digest.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "common/util_format.h"
|
||||
|
||||
#define IDENTITY_KEY_BITS 3072
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "orconfig.h"
|
||||
#include "common/compat.h"
|
||||
#include "common/util.h"
|
||||
#include "common/address.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "lib/log/torlog.h"
|
||||
#include "common/sandbox.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user