|
@@ -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"
|
|
|
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
|
|
|
* set. */
|
|
|
int
|
|
@@ -707,618 +702,6 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
|
|
|
tor_free(lockfile);
|
|
|
}
|
|
|
|
|
|
-#undef DEBUG_SOCKET_COUNTING
|
|
|
-#ifdef DEBUG_SOCKET_COUNTING
|
|
|
-
|
|
|
- * used if DEBUG_SOCKET_COUNTING is defined. */
|
|
|
-static bitarray_t *open_sockets = NULL;
|
|
|
-
|
|
|
-static int max_socket = -1;
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
- * eventdns and libevent.) */
|
|
|
-static int n_sockets_open = 0;
|
|
|
-
|
|
|
-
|
|
|
-static tor_mutex_t *socket_accounting_mutex = NULL;
|
|
|
-
|
|
|
-
|
|
|
-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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static inline void
|
|
|
-socket_accounting_unlock(void)
|
|
|
-{
|
|
|
- tor_mutex_release(socket_accounting_mutex);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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
|
|
|
- if (r == 0) {
|
|
|
- --n_sockets_open;
|
|
|
- } else {
|
|
|
-#ifdef _WIN32
|
|
|
- if (r != WSAENOTSOCK)
|
|
|
- --n_sockets_open;
|
|
|
-#else
|
|
|
- if (r != EBADF)
|
|
|
- --n_sockets_open;
|
|
|
-#endif
|
|
|
- r = -1;
|
|
|
- }
|
|
|
-
|
|
|
- tor_assert_nonfatal(n_sockets_open >= 0);
|
|
|
- socket_accounting_unlock();
|
|
|
- return r;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#ifdef DEBUG_SOCKET_COUNTING
|
|
|
-
|
|
|
- * now an open socket. */
|
|
|
-static inline void
|
|
|
-mark_socket_open(tor_socket_t s)
|
|
|
-{
|
|
|
-
|
|
|
- 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
|
|
|
-#define mark_socket_open(s) ((void) (s))
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
- * 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
|
|
|
-
|
|
|
- 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
|
|
|
- (void)cloexec;
|
|
|
-#endif
|
|
|
-
|
|
|
- if (nonblock) {
|
|
|
- if (set_socket_nonblocking(s) == -1) {
|
|
|
- tor_close_socket_simple(s);
|
|
|
- return TOR_INVALID_SOCKET;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- goto socket_ok;
|
|
|
-
|
|
|
- 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();
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
- * 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
|
|
|
-
|
|
|
- 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
|
|
|
- (void)cloexec;
|
|
|
-#endif
|
|
|
-
|
|
|
- if (nonblock) {
|
|
|
- if (set_socket_nonblocking(s) == -1) {
|
|
|
- tor_close_socket_simple(s);
|
|
|
- return TOR_INVALID_SOCKET;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- goto socket_ok;
|
|
|
-
|
|
|
- socket_ok:
|
|
|
- tor_take_socket_ownership(s);
|
|
|
- return s;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-int
|
|
|
-get_n_open_sockets(void)
|
|
|
-{
|
|
|
- int n;
|
|
|
- socket_accounting_lock();
|
|
|
- n = n_sockets_open;
|
|
|
- socket_accounting_unlock();
|
|
|
- return n;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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
|
|
|
-
|
|
|
- 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().
|
|
|
- **/
|
|
|
-
|
|
|
-int
|
|
|
-tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
|
|
|
-{
|
|
|
-
|
|
|
-#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;
|
|
|
-
|
|
|
- * even though we were built on a system with SOCK_CLOEXEC support, we
|
|
|
- * are running on one without. */
|
|
|
- if (errno != EINVAL)
|
|
|
- return -errno;
|
|
|
-#endif
|
|
|
-
|
|
|
- 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
|
|
|
- goto sockets_ok;
|
|
|
-
|
|
|
- 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
|
|
|
- return tor_ersatz_socketpair(family, type, protocol, fd);
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-#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])
|
|
|
-{
|
|
|
-
|
|
|
- * 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) {
|
|
|
-
|
|
|
- ersatz_domain = AF_INET6;
|
|
|
- listener = tor_open_socket(ersatz_domain, type, 0);
|
|
|
- if (!SOCKET_OK(listener)) {
|
|
|
-
|
|
|
- * (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;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- * 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 ,
|
|
|
- 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;
|
|
|
-
|
|
|
- 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;
|
|
|
-
|
|
|
- two sockets. */
|
|
|
- if (getsockname(connector, connect_addr, &size) == -1)
|
|
|
- goto tidy_up_and_fail;
|
|
|
-
|
|
|
- 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;
|
|
|
-#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
|
|
|
-
|
|
|
-
|
|
|
-int
|
|
|
-get_max_sockets(void)
|
|
|
-{
|
|
|
- return max_sockets;
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
* tell Tor it's allowed to use. */
|
|
|
#define ULIMIT_BUFFER 32
|
|
@@ -1396,7 +779,8 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
|
|
|
}
|
|
|
|
|
|
* 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);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- * 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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * <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))) {
|
|
|
-
|
|
|
- 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)
|
|
|
- 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;
|
|
|
- } 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)
|
|
|
- return NULL;
|
|
|
- strlcpy(dst, buf, len);
|
|
|
- return dst;
|
|
|
- } else {
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
- 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;
|
|
|
-
|
|
|
-
|
|
|
- * 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) {
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
- 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;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * *<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;
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
static char uname_result[256];
|
|
|
|