Browse Source

Move network code to libtor-net.

There are some additional changes to come: those points are marked
by XXXX.
Nick Mathewson 5 years ago
parent
commit
42b3caa6ad

+ 2 - 0
.gitignore

@@ -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-tls.a

+ 2 - 0
Makefile.am

@@ -40,6 +40,7 @@ endif
 # "Common" libraries used to link tor's utility code.
 TOR_UTIL_LIBS = \
 	src/common/libor.a \
+	src/lib/libtor-net.a \
         src/lib/libtor-log.a \
         src/lib/libtor-lock.a \
         src/lib/libtor-fdio.a \
@@ -55,6 +56,7 @@ TOR_UTIL_LIBS = \
 # and tests)
 TOR_UTIL_TESTING_LIBS = \
 	src/common/libor-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 \

+ 5 - 864
src/common/compat.c

@@ -131,11 +131,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
 #include "common/address.h"
 #include "common/sandbox.h"
 
-/* When set_max_file_descriptors() is called, update this with the max file
- * descriptor value so we can use it to check the limit when opening a new
- * socket. Default value is what Debian sets as the default hard limit. */
-static int max_sockets = 1024;
-
 /** As open(path, flags, mode), but return an fd with the close-on-exec mode
  * set. */
 int
@@ -707,618 +702,6 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
   tor_free(lockfile);
 }
 
-#undef DEBUG_SOCKET_COUNTING
-#ifdef DEBUG_SOCKET_COUNTING
-/** A bitarray of all fds that should be passed to tor_socket_close(). Only
- * used if DEBUG_SOCKET_COUNTING is defined. */
-static bitarray_t *open_sockets = NULL;
-/** The size of <b>open_sockets</b>, in bits. */
-static int max_socket = -1;
-#endif /* defined(DEBUG_SOCKET_COUNTING) */
-
-/** Count of number of sockets currently open.  (Undercounts sockets opened by
- * eventdns and libevent.) */
-static int n_sockets_open = 0;
-
-/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */
-static tor_mutex_t *socket_accounting_mutex = NULL;
-
-/** Helper: acquire the socket accounting lock. */
-static inline void
-socket_accounting_lock(void)
-{
-  if (PREDICT_UNLIKELY(!socket_accounting_mutex))
-    socket_accounting_mutex = tor_mutex_new();
-  tor_mutex_acquire(socket_accounting_mutex);
-}
-
-/** Helper: release the socket accounting lock. */
-static inline void
-socket_accounting_unlock(void)
-{
-  tor_mutex_release(socket_accounting_mutex);
-}
-
-/** As close(), but guaranteed to work for sockets across platforms (including
- * Windows, where close()ing a socket doesn't work.  Returns 0 on success and
- * the socket error code on failure. */
-int
-tor_close_socket_simple(tor_socket_t s)
-{
-  int r = 0;
-
-  /* On Windows, you have to call close() on fds returned by open(),
-  * and closesocket() on fds returned by socket().  On Unix, everything
-  * gets close()'d.  We abstract this difference by always using
-  * tor_close_socket to close sockets, and always using close() on
-  * files.
-  */
-  #if defined(_WIN32)
-    r = closesocket(s);
-  #else
-    r = close(s);
-  #endif
-
-  if (r != 0) {
-    int err = tor_socket_errno(-1);
-    log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err));
-    return err;
-  }
-
-  return r;
-}
-
-/** As tor_close_socket_simple(), but keeps track of the number
- * of open sockets. Returns 0 on success, -1 on failure. */
-MOCK_IMPL(int,
-tor_close_socket,(tor_socket_t s))
-{
-  int r = tor_close_socket_simple(s);
-
-  socket_accounting_lock();
-#ifdef DEBUG_SOCKET_COUNTING
-  if (s > max_socket || ! bitarray_is_set(open_sockets, s)) {
-    log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_"
-             "socket(), or that was already closed or something.", s);
-  } else {
-    tor_assert(open_sockets && s <= max_socket);
-    bitarray_clear(open_sockets, s);
-  }
-#endif /* defined(DEBUG_SOCKET_COUNTING) */
-  if (r == 0) {
-    --n_sockets_open;
-  } else {
-#ifdef _WIN32
-    if (r != WSAENOTSOCK)
-      --n_sockets_open;
-#else
-    if (r != EBADF)
-      --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force.
-#endif /* defined(_WIN32) */
-    r = -1;
-  }
-
-  tor_assert_nonfatal(n_sockets_open >= 0);
-  socket_accounting_unlock();
-  return r;
-}
-
-/** @{ */
-#ifdef DEBUG_SOCKET_COUNTING
-/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is
- * now an open socket. */
-static inline void
-mark_socket_open(tor_socket_t s)
-{
-  /* XXXX This bitarray business will NOT work on windows: sockets aren't
-     small ints there. */
-  if (s > max_socket) {
-    if (max_socket == -1) {
-      open_sockets = bitarray_init_zero(s+128);
-      max_socket = s+128;
-    } else {
-      open_sockets = bitarray_expand(open_sockets, max_socket, s+128);
-      max_socket = s+128;
-    }
-  }
-  if (bitarray_is_set(open_sockets, s)) {
-    log_warn(LD_BUG, "I thought that %d was already open, but socket() just "
-             "gave it to me!", s);
-  }
-  bitarray_set(open_sockets, s);
-}
-#else /* !(defined(DEBUG_SOCKET_COUNTING)) */
-#define mark_socket_open(s) ((void) (s))
-#endif /* defined(DEBUG_SOCKET_COUNTING) */
-/** @} */
-
-/** As socket(), but counts the number of open sockets. */
-MOCK_IMPL(tor_socket_t,
-tor_open_socket,(int domain, int type, int protocol))
-{
-  return tor_open_socket_with_extensions(domain, type, protocol, 1, 0);
-}
-
-/** Mockable wrapper for connect(). */
-MOCK_IMPL(tor_socket_t,
-tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address,
-                     socklen_t address_len))
-{
-  return connect(sock,address,address_len);
-}
-
-/** As socket(), but creates a nonblocking socket and
- * counts the number of open sockets. */
-tor_socket_t
-tor_open_socket_nonblocking(int domain, int type, int protocol)
-{
-  return tor_open_socket_with_extensions(domain, type, protocol, 1, 1);
-}
-
-/** As socket(), but counts the number of open sockets and handles
- * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
- * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
- * if the corresponding extension should be used.*/
-tor_socket_t
-tor_open_socket_with_extensions(int domain, int type, int protocol,
-                                int cloexec, int nonblock)
-{
-  tor_socket_t s;
-
-  /* We are about to create a new file descriptor so make sure we have
-   * enough of them. */
-  if (get_n_open_sockets() >= max_sockets - 1) {
-#ifdef _WIN32
-    WSASetLastError(WSAEMFILE);
-#else
-    errno = EMFILE;
-#endif
-    return TOR_INVALID_SOCKET;
-  }
-
-#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
-  int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
-                  (nonblock ? SOCK_NONBLOCK : 0);
-  s = socket(domain, type|ext_flags, protocol);
-  if (SOCKET_OK(s))
-    goto socket_ok;
-  /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
-   * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK
-   * support, we are running on one without. */
-  if (errno != EINVAL)
-    return s;
-#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */
-
-  s = socket(domain, type, protocol);
-  if (! SOCKET_OK(s))
-    return s;
-
-#if defined(FD_CLOEXEC)
-  if (cloexec) {
-    if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
-      log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
-      tor_close_socket_simple(s);
-      return TOR_INVALID_SOCKET;
-    }
-  }
-#else /* !(defined(FD_CLOEXEC)) */
-  (void)cloexec;
-#endif /* defined(FD_CLOEXEC) */
-
-  if (nonblock) {
-    if (set_socket_nonblocking(s) == -1) {
-      tor_close_socket_simple(s);
-      return TOR_INVALID_SOCKET;
-    }
-  }
-
-  goto socket_ok; /* So that socket_ok will not be unused. */
-
- socket_ok:
-  tor_take_socket_ownership(s);
-  return s;
-}
-
-/**
- * For socket accounting: remember that we are the owner of the socket
- * <b>s</b>. This will prevent us from overallocating sockets, and prevent us
- * from asserting later when we close the socket <b>s</b>.
- */
-void
-tor_take_socket_ownership(tor_socket_t s)
-{
-  socket_accounting_lock();
-  ++n_sockets_open;
-  mark_socket_open(s);
-  socket_accounting_unlock();
-}
-
-/** As accept(), but counts the number of open sockets. */
-tor_socket_t
-tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
-{
-  return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0);
-}
-
-/** As accept(), but returns a nonblocking socket and
- * counts the number of open sockets. */
-tor_socket_t
-tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr,
-                              socklen_t *len)
-{
-  return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1);
-}
-
-/** As accept(), but counts the number of open sockets and handles
- * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified.
- * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate
- * if the corresponding extension should be used.*/
-tor_socket_t
-tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr,
-                                 socklen_t *len, int cloexec, int nonblock)
-{
-  tor_socket_t s;
-
-  /* We are about to create a new file descriptor so make sure we have
-   * enough of them. */
-  if (get_n_open_sockets() >= max_sockets - 1) {
-#ifdef _WIN32
-    WSASetLastError(WSAEMFILE);
-#else
-    errno = EMFILE;
-#endif
-    return TOR_INVALID_SOCKET;
-  }
-
-#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \
-  && defined(SOCK_NONBLOCK)
-  int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) |
-                  (nonblock ? SOCK_NONBLOCK : 0);
-  s = accept4(sockfd, addr, len, ext_flags);
-  if (SOCKET_OK(s))
-    goto socket_ok;
-  /* If we got an error, see if it is ENOSYS. ENOSYS indicates that,
-   * even though we were built on a system with accept4 support, we
-   * are running on one without. Also, check for EINVAL, which indicates that
-   * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */
-  if (errno != EINVAL && errno != ENOSYS)
-    return s;
-#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */
-
-  s = accept(sockfd, addr, len);
-  if (!SOCKET_OK(s))
-    return s;
-
-#if defined(FD_CLOEXEC)
-  if (cloexec) {
-    if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
-      log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
-      tor_close_socket_simple(s);
-      return TOR_INVALID_SOCKET;
-    }
-  }
-#else /* !(defined(FD_CLOEXEC)) */
-  (void)cloexec;
-#endif /* defined(FD_CLOEXEC) */
-
-  if (nonblock) {
-    if (set_socket_nonblocking(s) == -1) {
-      tor_close_socket_simple(s);
-      return TOR_INVALID_SOCKET;
-    }
-  }
-
-  goto socket_ok; /* So that socket_ok will not be unused. */
-
- socket_ok:
-  tor_take_socket_ownership(s);
-  return s;
-}
-
-/** Return the number of sockets we currently have opened. */
-int
-get_n_open_sockets(void)
-{
-  int n;
-  socket_accounting_lock();
-  n = n_sockets_open;
-  socket_accounting_unlock();
-  return n;
-}
-
-/** Mockable wrapper for getsockname(). */
-MOCK_IMPL(int,
-tor_getsockname,(tor_socket_t sock, struct sockaddr *address,
-                 socklen_t *address_len))
-{
-   return getsockname(sock, address, address_len);
-}
-
-/**
- * Find the local address associated with the socket <b>sock</b>, and
- * place it in *<b>addr_out</b>.  Return 0 on success, -1 on failure.
- *
- * (As tor_getsockname, but instead places the result in a tor_addr_t.) */
-int
-tor_addr_from_getsockname(tor_addr_t *addr_out, tor_socket_t sock)
-{
-  struct sockaddr_storage ss;
-  socklen_t ss_len = sizeof(ss);
-  memset(&ss, 0, sizeof(ss));
-
-  if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0)
-    return -1;
-
-  return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL);
-}
-
-/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
- * on failure.
- */
-int
-set_socket_nonblocking(tor_socket_t sock)
-{
-#if defined(_WIN32)
-  unsigned long nonblocking = 1;
-  ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking);
-#else
-  int flags;
-
-  flags = fcntl(sock, F_GETFL, 0);
-  if (flags == -1) {
-    log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno));
-    return -1;
-  }
-  flags |= O_NONBLOCK;
-  if (fcntl(sock, F_SETFL, flags) == -1) {
-    log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno));
-    return -1;
-  }
-#endif /* defined(_WIN32) */
-
-  return 0;
-}
-
-/**
- * Allocate a pair of connected sockets.  (Like socketpair(family,
- * type,protocol,fd), but works on systems that don't have
- * socketpair.)
- *
- * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported.
- *
- * Note that on systems without socketpair, this call will fail if
- * localhost is inaccessible (for example, if the networking
- * stack is down). And even if it succeeds, the socket pair will not
- * be able to read while localhost is down later (the socket pair may
- * even close, depending on OS-specific timeouts).
- *
- * Returns 0 on success and -errno on failure; do not rely on the value
- * of errno or WSAGetLastError().
- **/
-/* It would be nicer just to set errno, but that won't work for windows. */
-int
-tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
-{
-//don't use win32 socketpairs (they are always bad)
-#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32)
-  int r;
-
-#ifdef SOCK_CLOEXEC
-  r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd);
-  if (r == 0)
-    goto sockets_ok;
-  /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
-   * even though we were built on a system with SOCK_CLOEXEC support, we
-   * are running on one without. */
-  if (errno != EINVAL)
-    return -errno;
-#endif /* defined(SOCK_CLOEXEC) */
-
-  r = socketpair(family, type, protocol, fd);
-  if (r < 0)
-    return -errno;
-
-#if defined(FD_CLOEXEC)
-  if (SOCKET_OK(fd[0])) {
-    r = fcntl(fd[0], F_SETFD, FD_CLOEXEC);
-    if (r == -1) {
-      close(fd[0]);
-      close(fd[1]);
-      return -errno;
-    }
-  }
-  if (SOCKET_OK(fd[1])) {
-    r = fcntl(fd[1], F_SETFD, FD_CLOEXEC);
-    if (r == -1) {
-      close(fd[0]);
-      close(fd[1]);
-      return -errno;
-    }
-  }
-#endif /* defined(FD_CLOEXEC) */
-  goto sockets_ok; /* So that sockets_ok will not be unused. */
-
- sockets_ok:
-  socket_accounting_lock();
-  if (SOCKET_OK(fd[0])) {
-    ++n_sockets_open;
-    mark_socket_open(fd[0]);
-  }
-  if (SOCKET_OK(fd[1])) {
-    ++n_sockets_open;
-    mark_socket_open(fd[1]);
-  }
-  socket_accounting_unlock();
-
-  return 0;
-#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */
-  return tor_ersatz_socketpair(family, type, protocol, fd);
-#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */
-}
-
-#ifdef NEED_ERSATZ_SOCKETPAIR
-
-static inline socklen_t
-SIZEOF_SOCKADDR(int domain)
-{
-  switch (domain) {
-    case AF_INET:
-      return sizeof(struct sockaddr_in);
-    case AF_INET6:
-      return sizeof(struct sockaddr_in6);
-    default:
-      return 0;
-  }
-}
-
-/**
- * Helper used to implement socketpair on systems that lack it, by
- * making a direct connection to localhost.
- */
-STATIC int
-tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
-{
-    /* This socketpair does not work when localhost is down. So
-     * it's really not the same thing at all. But it's close enough
-     * for now, and really, when localhost is down sometimes, we
-     * have other problems too.
-     */
-    tor_socket_t listener = TOR_INVALID_SOCKET;
-    tor_socket_t connector = TOR_INVALID_SOCKET;
-    tor_socket_t acceptor = TOR_INVALID_SOCKET;
-    tor_addr_t listen_tor_addr;
-    struct sockaddr_storage connect_addr_ss, listen_addr_ss;
-    struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss;
-    uint16_t listen_port = 0;
-    tor_addr_t connect_tor_addr;
-    uint16_t connect_port = 0;
-    struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss;
-    socklen_t size;
-    int saved_errno = -1;
-    int ersatz_domain = AF_INET;
-
-    memset(&connect_tor_addr, 0, sizeof(connect_tor_addr));
-    memset(&connect_addr_ss, 0, sizeof(connect_addr_ss));
-    memset(&listen_tor_addr, 0, sizeof(listen_tor_addr));
-    memset(&listen_addr_ss, 0, sizeof(listen_addr_ss));
-
-    if (protocol
-#ifdef AF_UNIX
-        || family != AF_UNIX
-#endif
-        ) {
-#ifdef _WIN32
-      return -WSAEAFNOSUPPORT;
-#else
-      return -EAFNOSUPPORT;
-#endif
-    }
-    if (!fd) {
-      return -EINVAL;
-    }
-
-    listener = tor_open_socket(ersatz_domain, type, 0);
-    if (!SOCKET_OK(listener)) {
-      int first_errno = tor_socket_errno(-1);
-      if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT)
-          && ersatz_domain == AF_INET) {
-        /* Assume we're on an IPv6-only system */
-        ersatz_domain = AF_INET6;
-        listener = tor_open_socket(ersatz_domain, type, 0);
-        if (!SOCKET_OK(listener)) {
-          /* Keep the previous behaviour, which was to return the IPv4 error.
-           * (This may be less informative on IPv6-only systems.)
-           * XX/teor - is there a better way to decide which errno to return?
-           * (I doubt we care much either way, once there is an error.)
-           */
-          return -first_errno;
-        }
-      }
-    }
-    /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we
-     * risk exposing a socketpair on a routable IP address. (Some BSD jails
-     * use a routable address for localhost. Fortunately, they have the real
-     * AF_UNIX socketpair.) */
-    if (ersatz_domain == AF_INET) {
-      tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK);
-    } else {
-      tor_addr_parse(&listen_tor_addr, "[::1]");
-    }
-    tor_assert(tor_addr_is_loopback(&listen_tor_addr));
-    size = tor_addr_to_sockaddr(&listen_tor_addr,
-                         0 /* kernel chooses port.  */,
-                         listen_addr,
-                         sizeof(listen_addr_ss));
-    if (bind(listener, listen_addr, size) == -1)
-      goto tidy_up_and_fail;
-    if (listen(listener, 1) == -1)
-      goto tidy_up_and_fail;
-
-    connector = tor_open_socket(ersatz_domain, type, 0);
-    if (!SOCKET_OK(connector))
-      goto tidy_up_and_fail;
-    /* We want to find out the port number to connect to.  */
-    size = sizeof(connect_addr_ss);
-    if (getsockname(listener, connect_addr, &size) == -1)
-      goto tidy_up_and_fail;
-    if (size != SIZEOF_SOCKADDR (connect_addr->sa_family))
-      goto abort_tidy_up_and_fail;
-    if (connect(connector, connect_addr, size) == -1)
-      goto tidy_up_and_fail;
-
-    size = sizeof(listen_addr_ss);
-    acceptor = tor_accept_socket(listener, listen_addr, &size);
-    if (!SOCKET_OK(acceptor))
-      goto tidy_up_and_fail;
-    if (size != SIZEOF_SOCKADDR(listen_addr->sa_family))
-      goto abort_tidy_up_and_fail;
-    /* Now check we are talking to ourself by matching port and host on the
-       two sockets.  */
-    if (getsockname(connector, connect_addr, &size) == -1)
-      goto tidy_up_and_fail;
-    /* Set *_tor_addr and *_port to the address and port that was used */
-    tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port);
-    tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port);
-    if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)
-        || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC)
-        || listen_port != connect_port) {
-      goto abort_tidy_up_and_fail;
-    }
-    tor_close_socket(listener);
-    fd[0] = connector;
-    fd[1] = acceptor;
-
-    return 0;
-
-  abort_tidy_up_and_fail:
-#ifdef _WIN32
-    saved_errno = WSAECONNABORTED;
-#else
-    saved_errno = ECONNABORTED; /* I hope this is portable and appropriate.  */
-#endif
-  tidy_up_and_fail:
-    if (saved_errno < 0)
-      saved_errno = errno;
-    if (SOCKET_OK(listener))
-      tor_close_socket(listener);
-    if (SOCKET_OK(connector))
-      tor_close_socket(connector);
-    if (SOCKET_OK(acceptor))
-      tor_close_socket(acceptor);
-    return -saved_errno;
-}
-
-#undef SIZEOF_SOCKADDR
-
-#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */
-
-/* Return the maximum number of allowed sockets. */
-int
-get_max_sockets(void)
-{
-  return max_sockets;
-}
-
 /** Number of extra file descriptors to keep in reserve beyond those that we
  * tell Tor it's allowed to use. */
 #define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */
@@ -1396,7 +779,8 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
   }
   /* Set the current limit value so if the attempt to set the limit to the
    * max fails at least we'll have a valid value of maximum sockets. */
-  *max_out = max_sockets = (int)rlim.rlim_cur - ULIMIT_BUFFER;
+  *max_out = (int)rlim.rlim_cur - ULIMIT_BUFFER;
+  set_max_sockets(*max_out);
   rlim.rlim_cur = rlim.rlim_max;
 
   if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
@@ -1438,7 +822,9 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
   if (limit > INT_MAX)
     limit = INT_MAX;
   tor_assert(max_out);
-  *max_out = max_sockets = (int)limit - ULIMIT_BUFFER;
+  *max_out = (int)limit - ULIMIT_BUFFER;
+  set_max_sockets(*max_out);
+
   return 0;
 }
 
@@ -2124,251 +1510,6 @@ tor_gethostname,(char *name, size_t namelen))
    return gethostname(name,namelen);
 }
 
-/** Set *addr to the IP address (in dotted-quad notation) stored in *str.
- * Return 1 on success, 0 if *str is badly formatted.
- * (Like inet_aton(str,addr), but works on Windows and Solaris.)
- */
-int
-tor_inet_aton(const char *str, struct in_addr* addr)
-{
-  unsigned a,b,c,d;
-  char more;
-  if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4)
-    return 0;
-  if (a > 255) return 0;
-  if (b > 255) return 0;
-  if (c > 255) return 0;
-  if (d > 255) return 0;
-  addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
-  return 1;
-}
-
-/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or
- * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the
- * address and store it in the <b>len</b>-byte buffer <b>dst</b>.  Returns
- * <b>dst</b> on success, NULL on failure.
- *
- * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it:
- * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6
- * support.) */
-const char *
-tor_inet_ntop(int af, const void *src, char *dst, size_t len)
-{
-  if (af == AF_INET) {
-    if (tor_inet_ntoa(src, dst, len) < 0)
-      return NULL;
-    else
-      return dst;
-  } else if (af == AF_INET6) {
-    const struct in6_addr *addr = src;
-    char buf[64], *cp;
-    int longestGapLen = 0, longestGapPos = -1, i,
-      curGapPos = -1, curGapLen = 0;
-    uint16_t words[8];
-    for (i = 0; i < 8; ++i) {
-      words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
-    }
-    if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
-        words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
-                          (words[5] == 0xffff))) {
-      /* This is an IPv4 address. */
-      if (words[5] == 0) {
-        tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
-                     addr->s6_addr[12], addr->s6_addr[13],
-                     addr->s6_addr[14], addr->s6_addr[15]);
-      } else {
-        tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
-                     addr->s6_addr[12], addr->s6_addr[13],
-                     addr->s6_addr[14], addr->s6_addr[15]);
-      }
-      if ((strlen(buf) + 1) > len) /* +1 for \0 */
-        return NULL;
-      strlcpy(dst, buf, len);
-      return dst;
-    }
-    i = 0;
-    while (i < 8) {
-      if (words[i] == 0) {
-        curGapPos = i++;
-        curGapLen = 1;
-        while (i<8 && words[i] == 0) {
-          ++i; ++curGapLen;
-        }
-        if (curGapLen > longestGapLen) {
-          longestGapPos = curGapPos;
-          longestGapLen = curGapLen;
-        }
-      } else {
-        ++i;
-      }
-    }
-    if (longestGapLen<=1)
-      longestGapPos = -1;
-
-    cp = buf;
-    for (i = 0; i < 8; ++i) {
-      if (words[i] == 0 && longestGapPos == i) {
-        if (i == 0)
-          *cp++ = ':';
-        *cp++ = ':';
-        while (i < 8 && words[i] == 0)
-          ++i;
-        --i; /* to compensate for loop increment. */
-      } else {
-        tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
-        cp += strlen(cp);
-        if (i != 7)
-          *cp++ = ':';
-      }
-    }
-    *cp = '\0';
-    if ((strlen(buf) + 1) > len) /* +1 for \0 */
-      return NULL;
-    strlcpy(dst, buf, len);
-    return dst;
-  } else {
-    return NULL;
-  }
-}
-
-/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b>
- * encoding an IPv4 address or IPv6 address correspondingly, try to parse the
- * address and store the result in <b>dst</b> (which must have space for a
- * struct in_addr or a struct in6_addr, as appropriate).  Return 1 on success,
- * 0 on a bad parse, and -1 on a bad <b>af</b>.
- *
- * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor
- * sometimes needs to format ipv6 addresses even on platforms without ipv6
- * support.) */
-int
-tor_inet_pton(int af, const char *src, void *dst)
-{
-  if (af == AF_INET) {
-    return tor_inet_aton(src, dst);
-  } else if (af == AF_INET6) {
-    struct in6_addr *out = dst;
-    uint16_t words[8];
-    int gapPos = -1, i, setWords=0;
-    const char *dot = strchr(src, '.');
-    const char *eow; /* end of words. */
-    memset(words, 0xf8, sizeof(words));
-    if (dot == src)
-      return 0;
-    else if (!dot)
-      eow = src+strlen(src);
-    else {
-      unsigned byte1,byte2,byte3,byte4;
-      char more;
-      for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow)
-        ;
-      if (*eow != ':')
-        return 0;
-      ++eow;
-
-      /* We use "scanf" because some platform inet_aton()s are too lax
-       * about IPv4 addresses of the form "1.2.3" */
-      if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c",
-                     &byte1,&byte2,&byte3,&byte4,&more) != 4)
-        return 0;
-
-      if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255)
-        return 0;
-
-      words[6] = (byte1<<8) | byte2;
-      words[7] = (byte3<<8) | byte4;
-      setWords += 2;
-    }
-
-    i = 0;
-    while (src < eow) {
-      if (i > 7)
-        return 0;
-      if (TOR_ISXDIGIT(*src)) {
-        char *next;
-        ssize_t len;
-        long r = strtol(src, &next, 16);
-        if (next == NULL || next == src) {
-          /* The 'next == src' error case can happen on versions of openbsd
-           * which treat "0xfoo" as an error, rather than as "0" followed by
-           * "xfoo". */
-          return 0;
-        }
-
-        len = *next == '\0' ? eow - src : next - src;
-        if (len > 4)
-          return 0;
-        if (len > 1 && !TOR_ISXDIGIT(src[1]))
-          return 0; /* 0x is not valid */
-
-        tor_assert(r >= 0);
-        tor_assert(r < 65536);
-        words[i++] = (uint16_t)r;
-        setWords++;
-        src = next;
-        if (*src != ':' && src != eow)
-          return 0;
-        ++src;
-      } else if (*src == ':' && i > 0 && gapPos == -1) {
-        gapPos = i;
-        ++src;
-      } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' &&
-                 gapPos == -1) {
-        gapPos = i;
-        src += 2;
-      } else {
-        return 0;
-      }
-    }
-
-    if (setWords > 8 ||
-        (setWords == 8 && gapPos != -1) ||
-        (setWords < 8 && gapPos == -1))
-      return 0;
-
-    if (gapPos >= 0) {
-      int nToMove = setWords - (dot ? 2 : 0) - gapPos;
-      int gapLen = 8 - setWords;
-      tor_assert(nToMove >= 0);
-      memmove(&words[gapPos+gapLen], &words[gapPos],
-              sizeof(uint16_t)*nToMove);
-      memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
-    }
-    for (i = 0; i < 8; ++i) {
-      out->s6_addr[2*i  ] = words[i] >> 8;
-      out->s6_addr[2*i+1] = words[i] & 0xff;
-    }
-
-    return 1;
-  } else {
-    return -1;
-  }
-}
-
-/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
- * *<b>addr</b> to the proper IP address, in host byte order.  Returns 0
- * on success, -1 on failure; 1 on transient failure.
- *
- * (This function exists because standard windows gethostbyname
- * doesn't treat raw IP addresses properly.)
- */
-
-MOCK_IMPL(int,
-tor_lookup_hostname,(const char *name, uint32_t *addr))
-{
-  tor_addr_t myaddr;
-  int ret;
-
-  if ((ret = tor_addr_lookup(name, AF_INET, &myaddr)))
-    return ret;
-
-  if (tor_addr_family(&myaddr) == AF_INET) {
-    *addr = tor_addr_to_ipv4h(&myaddr);
-    return ret;
-  }
-
-  return -1;
-}
-
 /** Hold the result of our call to <b>uname</b>. */
 static char uname_result[256];
 /** True iff uname_result is set. */

+ 4 - 182
src/common/compat.h

@@ -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. */

+ 0 - 2
src/common/include.am

@@ -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
src/common/sandbox.c

@@ -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);

+ 0 - 24
src/common/sandbox.h

@@ -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 - 0
src/include.am

@@ -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/testsupport/include.am
 include src/lib/tls/include.am

+ 13 - 0
src/lib/net/.may_include

@@ -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

+ 18 - 26
src/common/address.c → src/lib/net/address.c

@@ -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,7 +1479,10 @@ ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses)
 STATIC smartlist_t *
 get_interface_addresses_win32(int severity, sa_family_t family)
 {
-
+  /*
+    XXXX We can assume that this function exists now; we can't
+    XXXX provide backward compatibility to pre-windows-XP.
+  */
   /* 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.
@@ -2087,22 +2095,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.
  */

+ 16 - 5
src/common/address.h → src/lib/net/address.h

@@ -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)\

+ 26 - 0
src/lib/net/include.am

@@ -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

+ 52 - 0
src/lib/net/ipv4.c

@@ -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));
+}

+ 17 - 0
src/lib/net/ipv4.h

@@ -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

+ 221 - 0
src/lib/net/ipv6.c

@@ -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;
+  }
+}

+ 86 - 0
src/lib/net/ipv6.h

@@ -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

+ 39 - 0
src/lib/net/nettypes.h

@@ -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

+ 236 - 0
src/lib/net/resolve.c

@@ -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

+ 50 - 0
src/lib/net/resolve.h

@@ -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

+ 649 - 0
src/lib/net/socket.c

@@ -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;
+}

+ 113 - 0
src/lib/net/socket.h

@@ -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

+ 1 - 0
src/rust/build.rs

@@ -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");

+ 1 - 0
src/test/test_util.c

@@ -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"