summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/address.c20
-rw-r--r--src/common/buffers.h1
-rw-r--r--src/common/compat.c82
-rw-r--r--src/common/compat.h6
-rw-r--r--src/common/compat_libevent.c246
-rw-r--r--src/common/compat_libevent.h25
-rw-r--r--src/common/compat_time.c13
-rw-r--r--src/common/compat_time.h1
-rw-r--r--src/common/compat_winthreads.c1
-rw-r--r--src/common/compress.c10
-rw-r--r--src/common/compress.h1
-rw-r--r--src/common/compress_zstd.c112
-rw-r--r--src/common/compress_zstd.h7
-rw-r--r--src/common/container.c2
-rw-r--r--src/common/crypto.c779
-rw-r--r--src/common/crypto.h118
-rw-r--r--src/common/crypto_curve25519.c1
-rw-r--r--src/common/crypto_curve25519.h1
-rw-r--r--src/common/crypto_digest.c569
-rw-r--r--src/common/crypto_digest.h136
-rw-r--r--src/common/crypto_ed25519.c1
-rw-r--r--src/common/crypto_format.c1
-rw-r--r--src/common/crypto_pwbox.c1
-rw-r--r--src/common/crypto_rsa.c260
-rw-r--r--src/common/crypto_rsa.h17
-rw-r--r--src/common/crypto_s2k.c1
-rw-r--r--src/common/include.am4
-rw-r--r--src/common/log.c31
-rw-r--r--src/common/procmon.c27
-rw-r--r--src/common/timers.c23
-rw-r--r--src/common/token_bucket.c250
-rw-r--r--src/common/token_bucket.h118
-rw-r--r--src/common/torlog.h14
-rw-r--r--src/common/tortls.c2
-rw-r--r--src/common/tortls.h2
-rw-r--r--src/common/util.c395
-rw-r--r--src/common/util.h27
-rw-r--r--src/common/workqueue.c47
-rw-r--r--src/common/workqueue.h5
-rw-r--r--src/ext/ed25519/donna/ed25519-hash-custom.h2
-rw-r--r--src/ext/ed25519/ref10/crypto_hash_sha512.h2
-rw-r--r--src/ext/timeouts/timeout.c4
-rw-r--r--src/or/bridges.c10
-rw-r--r--src/or/bridges.h13
-rw-r--r--src/or/channel.c19
-rw-r--r--src/or/channel.h3
-rw-r--r--src/or/channelpadding.c1
-rw-r--r--src/or/channeltls.c5
-rw-r--r--src/or/circuitbuild.c87
-rw-r--r--src/or/circuitlist.c24
-rw-r--r--src/or/circuitmux.c678
-rw-r--r--src/or/circuitmux_ewma.c115
-rw-r--r--src/or/circuitmux_ewma.h7
-rw-r--r--src/or/circuituse.c5
-rw-r--r--src/or/command.c4
-rw-r--r--src/or/config.c64
-rw-r--r--src/or/connection.c382
-rw-r--r--src/or/connection.h11
-rw-r--r--src/or/connection_edge.c38
-rw-r--r--src/or/connection_or.c14
-rw-r--r--src/or/control.c67
-rw-r--r--src/or/control.h5
-rw-r--r--src/or/cpuworker.c27
-rw-r--r--src/or/directory.c2
-rw-r--r--src/or/dirserv.c9
-rw-r--r--src/or/dos.c15
-rw-r--r--src/or/entrynodes.c2
-rw-r--r--src/or/geoip.c6
-rw-r--r--src/or/hibernate.c2
-rw-r--r--src/or/hs_cell.c2
-rw-r--r--src/or/hs_client.c6
-rw-r--r--src/or/hs_common.c1
-rw-r--r--src/or/hs_intropoint.c1
-rw-r--r--src/or/hs_service.c1
-rw-r--r--src/or/include.am2
-rw-r--r--src/or/keypin.c13
-rw-r--r--src/or/main.c270
-rw-r--r--src/or/main.h9
-rw-r--r--src/or/networkstatus.c40
-rw-r--r--src/or/nodelist.c32
-rw-r--r--src/or/nodelist.h4
-rw-r--r--src/or/ntmain.c5
-rw-r--r--src/or/onion.c14
-rw-r--r--src/or/onion_ntor.c1
-rw-r--r--src/or/or.h89
-rw-r--r--src/or/periodic.c21
-rw-r--r--src/or/periodic.h5
-rw-r--r--src/or/relay.c210
-rw-r--r--src/or/relay.h5
-rw-r--r--src/or/relay_crypto.c326
-rw-r--r--src/or/relay_crypto.h31
-rw-r--r--src/or/rendclient.c4
-rw-r--r--src/or/rephist.c1
-rw-r--r--src/or/router.c233
-rw-r--r--src/or/router.h20
-rw-r--r--src/or/scheduler.c25
-rw-r--r--src/or/scheduler.h4
-rw-r--r--src/or/scheduler_kist.c4
-rw-r--r--src/or/scheduler_vanilla.c4
-rw-r--r--src/or/status.c1
-rw-r--r--src/or/transports.c188
-rw-r--r--src/or/transports.h5
-rw-r--r--src/rust/Cargo.lock10
-rw-r--r--src/rust/Cargo.toml3
-rw-r--r--src/rust/include.am3
-rw-r--r--src/rust/protover/Cargo.toml6
-rw-r--r--src/rust/protover/ffi.rs34
-rw-r--r--src/rust/protover/lib.rs1
-rw-r--r--src/rust/protover/protover.rs89
-rw-r--r--src/rust/tor_allocate/tor_allocate.rs19
-rw-r--r--src/rust/tor_log/Cargo.toml18
-rw-r--r--src/rust/tor_log/lib.rs16
-rw-r--r--src/rust/tor_log/tor_log.rs270
-rw-r--r--src/rust/tor_util/Cargo.toml3
-rw-r--r--src/rust/tor_util/ffi.rs13
-rw-r--r--src/rust/tor_util/lib.rs3
-rw-r--r--src/rust/tor_util/strings.rs154
-rw-r--r--src/test/bench.c18
-rw-r--r--src/test/include.am4
-rw-r--r--src/test/test-timers.c6
-rw-r--r--src/test/test.c378
-rw-r--r--src/test/test.h12
-rw-r--r--src/test/test_bridges.c618
-rw-r--r--src/test/test_bwmgt.c228
-rw-r--r--src/test/test_channel.c5
-rw-r--r--src/test/test_channelpadding.c16
-rw-r--r--src/test/test_circuitlist.c1
-rw-r--r--src/test/test_circuitmux.c2
-rw-r--r--src/test/test_compat_libevent.c61
-rw-r--r--src/test/test_config.c4
-rw-r--r--src/test/test_controller_events.c75
-rw-r--r--src/test/test_dir_handle_get.c1
-rw-r--r--src/test/test_geoip.c465
-rw-r--r--src/test/test_helpers.c3
-rw-r--r--src/test/test_hs_client.c16
-rw-r--r--src/test/test_hs_descriptor.c1
-rw-r--r--src/test/test_hs_intropoint.c1
-rw-r--r--src/test/test_hs_service.c10
-rw-r--r--src/test/test_options.c42
-rw-r--r--src/test/test_relaycrypt.c184
-rwxr-xr-xsrc/test/test_rust.sh1
-rw-r--r--src/test/test_scheduler.c75
-rw-r--r--src/test/test_status.c12
-rw-r--r--src/test/test_util.c50
-rw-r--r--src/test/test_workqueue.c35
-rw-r--r--src/test/testing_common.c2
-rw-r--r--src/tools/include.am2
-rw-r--r--src/tools/tor-fw-helper/README10
-rw-r--r--src/tools/tor-gencert.c2
-rw-r--r--src/win32/orconfig.h2
150 files changed, 5274 insertions, 4267 deletions
diff --git a/src/common/address.c b/src/common/address.c
index a2f4c93b91..a32df99107 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1225,7 +1225,7 @@ tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr)
/* LCOV_EXCL_START */
tor_fragile_assert();
return 0;
- /* LCOV_EXCL_END */
+ /* LCOV_EXCL_STOP */
}
}
@@ -1697,7 +1697,7 @@ get_interface_address6_via_udp_socket_hack,(int severity,
sa_family_t family,
tor_addr_t *addr))
{
- struct sockaddr_storage my_addr, target_addr;
+ struct sockaddr_storage target_addr;
int sock=-1, r=-1;
socklen_t addr_len;
@@ -1740,21 +1740,19 @@ get_interface_address6_via_udp_socket_hack,(int severity,
goto err;
}
- if (tor_getsockname(sock,(struct sockaddr*)&my_addr, &addr_len)) {
+ if (tor_addr_from_getsockname(addr, sock) < 0) {
int e = tor_socket_errno(sock);
log_fn(severity, LD_NET, "getsockname() to determine interface failed: %s",
tor_socket_strerror(e));
goto err;
}
- if (tor_addr_from_sockaddr(addr, (struct sockaddr*)&my_addr, NULL) == 0) {
- if (tor_addr_is_loopback(addr) || tor_addr_is_multicast(addr)) {
- log_fn(severity, LD_NET, "Address that we determined via UDP socket"
- " magic is unsuitable for public comms.");
- } else {
- r=0;
- }
- }
+ if (tor_addr_is_loopback(addr) || tor_addr_is_multicast(addr)) {
+ log_fn(severity, LD_NET, "Address that we determined via UDP socket"
+ " magic is unsuitable for public comms.");
+ } else {
+ r=0;
+ }
err:
if (sock >= 0)
diff --git a/src/common/buffers.h b/src/common/buffers.h
index 22a5f7bfa3..4275152de2 100644
--- a/src/common/buffers.h
+++ b/src/common/buffers.h
@@ -13,7 +13,6 @@
#define TOR_BUFFERS_H
#include "compat.h"
-#include "compat.h"
#include "torint.h"
#include "testsupport.h"
diff --git a/src/common/compat.c b/src/common/compat.c
index 7d9add50b2..6fdd6ecf00 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -100,7 +100,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
/* Only use the linux prctl; the IRIX prctl is totally different */
#include <sys/prctl.h>
#elif defined(__APPLE__)
-#include <sys/types.h>
#include <sys/ptrace.h>
#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) || ... */
@@ -116,7 +115,7 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
-#ifdef HAVE_SYS_MMAN_H
+#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#ifdef HAVE_SYS_SYSLIMITS_H
@@ -204,25 +203,17 @@ tor_rename(const char *path_old, const char *path_new)
sandbox_intern_string(path_new));
}
-/* Some MinGW builds have sys/mman.h, but not the corresponding symbols.
- * Other configs rename the symbols using macros (including getpagesize).
- * So check for sys/mman.h and unistd.h, and a getpagesize declaration. */
-#if (defined(HAVE_SYS_MMAN_H) && defined(HAVE_UNISTD_H) && \
- defined(HAVE_DECL_GETPAGESIZE))
-#define COMPAT_HAS_MMAN_AND_PAGESIZE
-#endif
-
-#if defined(COMPAT_HAS_MMAN_AND_PAGESIZE) || \
- defined(RUNNING_DOXYGEN)
+#if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN)
/** Try to create a memory mapping for <b>filename</b> and return it. On
- * failure, return NULL. Sets errno properly, using ERANGE to mean
- * "empty file". */
+ * failure, return NULL. Sets errno properly, using ERANGE to mean
+ * "empty file". Must only be called on trusted Tor-owned files, as changing
+ * the underlying file's size causes unspecified behavior. */
tor_mmap_t *
tor_mmap_file(const char *filename)
{
int fd; /* router file */
char *string;
- int page_size, result;
+ int result;
tor_mmap_t *res;
size_t size, filesize;
struct stat st;
@@ -251,13 +242,6 @@ tor_mmap_file(const char *filename)
return NULL;
}
size = filesize = (size_t)(st.st_size);
- /*
- * Should we check for weird crap like mmapping a named pipe here,
- * or just wait for if (!size) below to fail?
- */
- /* ensure page alignment */
- page_size = getpagesize();
- size += (size%page_size) ? page_size-(size%page_size) : 0;
if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) {
log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename);
@@ -418,40 +402,8 @@ tor_munmap_file(tor_mmap_t *handle)
return 0;
}
#else
-tor_mmap_t *
-tor_mmap_file(const char *filename)
-{
- struct stat st;
- char *res = read_file_to_str(filename, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
- tor_mmap_t *handle;
- if (! res)
- return NULL;
- handle = tor_malloc_zero(sizeof(tor_mmap_t));
- handle->data = res;
- handle->size = st.st_size;
- return handle;
-}
-
-/** Unmap the file mapped with tor_mmap_file(), and return 0 for success
- * or -1 for failure.
- */
-
-int
-tor_munmap_file(tor_mmap_t *handle)
-{
- char *d = NULL;
- if (handle == NULL)
- return 0;
-
- d = (char*)handle->data;
- tor_free(d);
- memwipe(handle, 0, sizeof(tor_mmap_t));
- tor_free(handle);
-
- /* Can't fail in this mmap()/munmap()-free case */
- return 0;
-}
-#endif /* defined(COMPAT_HAS_MMAN_AND_PAGESIZE) || ... || ... */
+#error "cannot implement tor_mmap_file"
+#endif /* defined(HAVE_MMAP) || ... || ... */
/** Replacement for snprintf. Differs from platform snprintf in two
* ways: First, always NUL-terminates its output. Second, always
@@ -1392,6 +1344,24 @@ tor_getsockname,(tor_socket_t sock, struct sockaddr *address,
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.
*/
diff --git a/src/common/compat.h b/src/common/compat.h
index 3088e68355..c7e7f8d9ef 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -318,12 +318,12 @@ typedef struct tor_mmap_t {
size_t size; /**< Size of the file. */
/* None of the fields below should be accessed from outside compat.c */
-#ifdef HAVE_SYS_MMAN_H
+#ifdef HAVE_MMAP
size_t mapping_size; /**< Size of the actual mapping. (This is this file
* size, rounded up to the nearest page.) */
#elif defined _WIN32
HANDLE mmap_handle;
-#endif /* defined(HAVE_SYS_MMAN_H) || ... */
+#endif /* defined(HAVE_MMAP) || ... */
} tor_mmap_t;
@@ -510,6 +510,8 @@ 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)
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 735385557c..9936c0aac4 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -79,6 +79,43 @@ tor_event_free_(struct event *ev)
/** Global event base for use by the main thread. */
static struct event_base *the_event_base = NULL;
+/**
+ * @defgroup postloop post-loop event helpers
+ *
+ * If we're not careful, Libevent can susceptible to infinite event chains:
+ * one event can activate another, whose callback activates another, whose
+ * callback activates another, ad infinitum. While this is happening,
+ * Libevent won't be checking timeouts, socket-based events, signals, and so
+ * on.
+ *
+ * We solve this problem by marking some events as "post-loop". A post-loop
+ * event behaves like any ordinary event, but any events that _it_ activates
+ * cannot run until Libevent has checked for other events at least once.
+ *
+ * @{ */
+
+/**
+ * An event that stops Libevent from running any more events on the current
+ * iteration of its loop, until it has re-checked for socket events, signal
+ * events, timeouts, etc.
+ */
+static struct event *rescan_mainloop_ev = NULL;
+
+/**
+ * Callback to implement rescan_mainloop_ev: it simply exits the mainloop,
+ * and relies on Tor to re-enter the mainloop since no error has occurred.
+ */
+static void
+rescan_mainloop_cb(evutil_socket_t fd, short events, void *arg)
+{
+ (void)fd;
+ (void)events;
+ struct event_base *the_base = arg;
+ event_base_loopbreak(the_base);
+}
+
+/** @} */
+
/* This is what passes for version detection on OSX. We set
* MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before
* 10.4.0 (aka 1040). */
@@ -130,6 +167,15 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
/* LCOV_EXCL_STOP */
}
+ rescan_mainloop_ev = event_new(the_event_base, -1, 0,
+ rescan_mainloop_cb, the_event_base);
+ if (!rescan_mainloop_ev) {
+ /* LCOV_EXCL_START */
+ log_err(LD_GENERAL, "Unable to create rescan event: cannot continue.");
+ exit(1); // exit ok: libevent is broken.
+ /* LCOV_EXCL_STOP */
+ }
+
log_info(LD_GENERAL,
"Initialized libevent version %s using method %s. Good.",
event_get_version(), tor_libevent_get_method());
@@ -221,6 +267,173 @@ periodic_timer_free_(periodic_timer_t *timer)
tor_free(timer);
}
+/**
+ * Type used to represent events that run directly from the main loop,
+ * either because they are activated from elsewhere in the code, or
+ * because they have a simple timeout.
+ *
+ * We use this type to avoid exposing Libevent's API throughout the rest
+ * of the codebase.
+ *
+ * This type can't be used for all events: it doesn't handle events that
+ * are triggered by signals or by sockets.
+ */
+struct mainloop_event_t {
+ struct event *ev;
+ void (*cb)(mainloop_event_t *, void *);
+ void *userdata;
+};
+
+/**
+ * Internal: Implements mainloop event using a libevent event.
+ */
+static void
+mainloop_event_cb(evutil_socket_t fd, short what, void *arg)
+{
+ (void)fd;
+ (void)what;
+ mainloop_event_t *mev = arg;
+ mev->cb(mev, mev->userdata);
+}
+
+/**
+ * As mainloop_event_cb, but implements a post-loop event.
+ */
+static void
+mainloop_event_postloop_cb(evutil_socket_t fd, short what, void *arg)
+{
+ (void)fd;
+ (void)what;
+
+ /* Note that if rescan_mainloop_ev is already activated,
+ * event_active() will do nothing: only the first post-loop event that
+ * happens each time through the event loop will cause it to be
+ * activated.
+ *
+ * Because event_active() puts events on a FIFO queue, every event
+ * that is made active _after_ rescan_mainloop_ev will get its
+ * callback run after rescan_mainloop_cb is called -- that is, on the
+ * next iteration of the loop.
+ */
+ event_active(rescan_mainloop_ev, EV_READ, 1);
+
+ mainloop_event_t *mev = arg;
+ mev->cb(mev, mev->userdata);
+}
+
+/**
+ * Helper for mainloop_event_new() and mainloop_event_postloop_new().
+ */
+static mainloop_event_t *
+mainloop_event_new_impl(int postloop,
+ void (*cb)(mainloop_event_t *, void *),
+ void *userdata)
+{
+ tor_assert(cb);
+
+ struct event_base *base = tor_libevent_get_base();
+ mainloop_event_t *mev = tor_malloc_zero(sizeof(mainloop_event_t));
+ mev->ev = tor_event_new(base, -1, 0,
+ postloop ? mainloop_event_postloop_cb : mainloop_event_cb,
+ mev);
+ tor_assert(mev->ev);
+ mev->cb = cb;
+ mev->userdata = userdata;
+ return mev;
+}
+
+/**
+ * Create and return a new mainloop_event_t to run the function <b>cb</b>.
+ *
+ * When run, the callback function will be passed the mainloop_event_t
+ * and <b>userdata</b> as its arguments. The <b>userdata</b> pointer
+ * must remain valid for as long as the mainloop_event_t event exists:
+ * it is your responsibility to free it.
+ *
+ * The event is not scheduled by default: Use mainloop_event_activate()
+ * or mainloop_event_schedule() to make it run.
+ */
+mainloop_event_t *
+mainloop_event_new(void (*cb)(mainloop_event_t *, void *),
+ void *userdata)
+{
+ return mainloop_event_new_impl(0, cb, userdata);
+}
+
+/**
+ * As mainloop_event_new(), but create a post-loop event.
+ *
+ * A post-loop event behaves like any ordinary event, but any events
+ * that _it_ activates cannot run until Libevent has checked for other
+ * events at least once.
+ */
+mainloop_event_t *
+mainloop_event_postloop_new(void (*cb)(mainloop_event_t *, void *),
+ void *userdata)
+{
+ return mainloop_event_new_impl(1, cb, userdata);
+}
+
+/**
+ * Schedule <b>event</b> to run in the main loop, immediately. If it is
+ * not scheduled, it will run anyway. If it is already scheduled to run
+ * later, it will run now instead. This function will have no effect if
+ * the event is already scheduled to run.
+ *
+ * This function may only be called from the main thread.
+ */
+void
+mainloop_event_activate(mainloop_event_t *event)
+{
+ tor_assert(event);
+ event_active(event->ev, EV_READ, 1);
+}
+
+/** Schedule <b>event</b> to run in the main loop, after a delay of <b>tv</b>.
+ *
+ * If the event is scheduled for a different time, cancel it and run
+ * after this delay instead. If the event is currently pending to run
+ * <em>now</b>, has no effect.
+ *
+ * Do not call this function with <b>tv</b> == NULL -- use
+ * mainloop_event_activate() instead.
+ *
+ * This function may only be called from the main thread.
+ */
+int
+mainloop_event_schedule(mainloop_event_t *event, const struct timeval *tv)
+{
+ tor_assert(event);
+ if (BUG(tv == NULL)) {
+ // LCOV_EXCL_START
+ mainloop_event_activate(event);
+ return 0;
+ // LCOV_EXCL_STOP
+ }
+ return event_add(event->ev, tv);
+}
+
+/** Cancel <b>event</b> if it is currently active or pending. (Do nothing if
+ * the event is not currently active or pending.) */
+void
+mainloop_event_cancel(mainloop_event_t *event)
+{
+ if (!event)
+ return;
+ (void) event_del(event->ev);
+}
+
+/** Cancel <b>event</b> and release all storage associated with it. */
+void
+mainloop_event_free_(mainloop_event_t *event)
+{
+ if (!event)
+ return;
+ tor_event_free(event->ev);
+ memset(event, 0xb8, sizeof(*event));
+ tor_free(event);
+}
+
int
tor_init_libevent_rng(void)
{
@@ -243,11 +456,44 @@ tor_init_libevent_rng(void)
void
tor_libevent_free_all(void)
{
+ tor_event_free(rescan_mainloop_ev);
if (the_event_base)
event_base_free(the_event_base);
the_event_base = NULL;
}
+/**
+ * Run the event loop for the provided event_base, handling events until
+ * something stops it. If <b>once</b> is set, then just poll-and-run
+ * once, then exit. Return 0 on success, -1 if an error occurred, or 1
+ * if we exited because no events were pending or active.
+ *
+ * This isn't reentrant or multithreaded.
+ */
+int
+tor_libevent_run_event_loop(struct event_base *base, int once)
+{
+ const int flags = once ? EVLOOP_ONCE : 0;
+ return event_base_loop(base, flags);
+}
+
+/** Tell the event loop to exit after <b>delay</b>. If <b>delay</b> is NULL,
+ * instead exit after we're done running the currently active events. */
+void
+tor_libevent_exit_loop_after_delay(struct event_base *base,
+ const struct timeval *delay)
+{
+ event_base_loopexit(base, delay);
+}
+
+/** Tell the event loop to exit after running whichever callback is currently
+ * active. */
+void
+tor_libevent_exit_loop_after_callback(struct event_base *base)
+{
+ event_base_loopbreak(base);
+}
+
#if defined(LIBEVENT_VERSION_NUMBER) && \
LIBEVENT_VERSION_NUMBER >= V(2,1,1) && \
!defined(TOR_UNIT_TESTS)
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 1853e50917..29c6ad375a 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -7,8 +7,6 @@
#include "orconfig.h"
#include "testsupport.h"
-#include <event2/event.h>
-
void configure_libevent_logging(void);
void suppress_libevent_log_msg(const char *msg);
@@ -19,6 +17,9 @@ void suppress_libevent_log_msg(const char *msg);
evdns_add_server_port_with_base(tor_libevent_get_base(), \
(sock),(tcp),(cb),(data));
+struct event;
+struct event_base;
+
void tor_event_free_(struct event *ev);
#define tor_event_free(ev) \
FREE_AND_NULL(struct event, tor_event_free_, (ev))
@@ -33,8 +34,19 @@ void periodic_timer_free_(periodic_timer_t *);
#define periodic_timer_free(t) \
FREE_AND_NULL(periodic_timer_t, periodic_timer_free_, (t))
-#define tor_event_base_loopexit event_base_loopexit
-#define tor_event_base_loopbreak event_base_loopbreak
+typedef struct mainloop_event_t mainloop_event_t;
+mainloop_event_t *mainloop_event_new(void (*cb)(mainloop_event_t *, void *),
+ void *userdata);
+mainloop_event_t * mainloop_event_postloop_new(
+ void (*cb)(mainloop_event_t *, void *),
+ void *userdata);
+void mainloop_event_activate(mainloop_event_t *event);
+int mainloop_event_schedule(mainloop_event_t *event,
+ const struct timeval *delay);
+void mainloop_event_cancel(mainloop_event_t *event);
+void mainloop_event_free_(mainloop_event_t *event);
+#define mainloop_event_free(event) \
+ FREE_AND_NULL(mainloop_event_t, mainloop_event_free_, (event))
/** Defines a configuration for using libevent with Tor: passed as an argument
* to tor_libevent_initialize() to describe how we want to set up. */
@@ -63,6 +75,11 @@ void tor_gettimeofday_cache_set(const struct timeval *tv);
void tor_libevent_postfork(void);
#endif
+int tor_libevent_run_event_loop(struct event_base *base, int once);
+void tor_libevent_exit_loop_after_delay(struct event_base *base,
+ const struct timeval *delay);
+void tor_libevent_exit_loop_after_callback(struct event_base *base);
+
#ifdef COMPAT_LIBEVENT_PRIVATE
/** Macro: returns the number of a Libevent version as a 4-byte number,
diff --git a/src/common/compat_time.c b/src/common/compat_time.c
index 183a60a480..b940447b67 100644
--- a/src/common/compat_time.c
+++ b/src/common/compat_time.c
@@ -830,11 +830,24 @@ monotime_coarse_stamp_units_to_approx_msec(uint64_t units)
return (abstime_diff * mach_time_info.numer) /
(mach_time_info.denom * ONE_MILLION);
}
+uint64_t
+monotime_msec_to_approx_coarse_stamp_units(uint64_t msec)
+{
+ uint64_t abstime_val =
+ (((uint64_t)msec) * ONE_MILLION * mach_time_info.denom) /
+ mach_time_info.numer;
+ return abstime_val >> monotime_shift;
+}
#else
uint64_t
monotime_coarse_stamp_units_to_approx_msec(uint64_t units)
{
return (units * 1000) / STAMP_TICKS_PER_SECOND;
}
+uint64_t
+monotime_msec_to_approx_coarse_stamp_units(uint64_t msec)
+{
+ return (msec * STAMP_TICKS_PER_SECOND) / 1000;
+}
#endif
diff --git a/src/common/compat_time.h b/src/common/compat_time.h
index 6ddd11883d..75b57f6f24 100644
--- a/src/common/compat_time.h
+++ b/src/common/compat_time.h
@@ -150,6 +150,7 @@ uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t);
* into an approximate number of milliseconds.
*/
uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units);
+uint64_t monotime_msec_to_approx_coarse_stamp_units(uint64_t msec);
uint32_t monotime_coarse_get_stamp(void);
#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)
diff --git a/src/common/compat_winthreads.c b/src/common/compat_winthreads.c
index 5f7ec94c23..7021344f6e 100644
--- a/src/common/compat_winthreads.c
+++ b/src/common/compat_winthreads.c
@@ -18,7 +18,6 @@
#include "util.h"
#include "container.h"
#include "torlog.h"
-#include <process.h>
/* This value is more or less total cargo-cult */
#define SPIN_COUNT 2000
diff --git a/src/common/compress.c b/src/common/compress.c
index 47c93cf6a9..cb1549f1aa 100644
--- a/src/common/compress.c
+++ b/src/common/compress.c
@@ -663,3 +663,13 @@ tor_compress_init(void)
tor_zstd_init();
}
+/** Warn if we had any problems while setting up our compression libraries.
+ *
+ * (This isn't part of tor_compress_init, since the logs aren't set up yet.)
+ */
+void
+tor_compress_log_init_warnings(void)
+{
+ tor_zstd_warn_if_version_mismatched();
+}
+
diff --git a/src/common/compress.h b/src/common/compress.h
index 952102bf97..65d63a4386 100644
--- a/src/common/compress.h
+++ b/src/common/compress.h
@@ -87,6 +87,7 @@ void tor_compress_free_(tor_compress_state_t *state);
size_t tor_compress_state_size(const tor_compress_state_t *state);
void tor_compress_init(void);
+void tor_compress_log_init_warnings(void);
#endif /* !defined(TOR_COMPRESS_H) */
diff --git a/src/common/compress_zstd.c b/src/common/compress_zstd.c
index 0db87d61b7..4024f5594d 100644
--- a/src/common/compress_zstd.c
+++ b/src/common/compress_zstd.c
@@ -18,6 +18,13 @@
#include "compress.h"
#include "compress_zstd.h"
+#ifdef ENABLE_ZSTD_ADVANCED_APIS
+/* This is a lie, but we make sure it doesn't get us in trouble by wrapping
+ * all invocations of zstd's static-only functions in a check to make sure
+ * that the compile-time version matches the run-time version. */
+#define ZSTD_STATIC_LINKING_ONLY
+#endif
+
#ifdef HAVE_ZSTD
#include <zstd.h>
#endif
@@ -51,21 +58,31 @@ tor_zstd_method_supported(void)
#endif
}
+#ifdef HAVE_ZSTD
+/** Format a zstd version number as a string in <b>buf</b>. */
+static void
+tor_zstd_format_version(char *buf, size_t buflen, unsigned version_number)
+{
+ tor_snprintf(buf, buflen,
+ "%u.%u.%u",
+ version_number / 10000 % 100,
+ version_number / 100 % 100,
+ version_number % 100);
+}
+#endif
+
+#define VERSION_STR_MAX_LEN 16 /* more than enough space for 99.99.99 */
+
/** Return a string representation of the version of the currently running
* version of libzstd. Returns NULL if Zstandard is unsupported. */
const char *
tor_zstd_get_version_str(void)
{
#ifdef HAVE_ZSTD
- static char version_str[16];
- size_t version_number;
+ static char version_str[VERSION_STR_MAX_LEN];
- version_number = ZSTD_versionNumber();
- tor_snprintf(version_str, sizeof(version_str),
- "%d.%d.%d",
- (int) version_number / 10000 % 100,
- (int) version_number / 100 % 100,
- (int) version_number % 100);
+ tor_zstd_format_version(version_str, sizeof(version_str),
+ ZSTD_versionNumber());
return version_str;
#else /* !(defined(HAVE_ZSTD)) */
@@ -85,6 +102,26 @@ tor_zstd_get_header_version_str(void)
#endif
}
+#ifdef TOR_UNIT_TESTS
+static int static_apis_disable_for_testing = 0;
+#endif
+
+/** Return true iff we can use the "static-only" APIs. */
+int
+tor_zstd_can_use_static_apis(void)
+{
+#if defined(ZSTD_STATIC_LINKING_ONLY) && defined(HAVE_ZSTD)
+#ifdef TOR_UNIT_TESTS
+ if (static_apis_disable_for_testing) {
+ return 0;
+ }
+#endif
+ return (ZSTD_VERSION_NUMBER == ZSTD_versionNumber());
+#else
+ return 0;
+#endif
+}
+
/** Internal Zstandard state for incremental compression/decompression.
* The body of this struct is not exposed. */
struct tor_zstd_compress_state_t {
@@ -112,9 +149,11 @@ struct tor_zstd_compress_state_t {
#ifdef HAVE_ZSTD
/** Return an approximate number of bytes stored in memory to hold the
- * Zstandard compression/decompression state. */
+ * Zstandard compression/decompression state. This is a fake estimate
+ * based on inspecting the zstd source: tor_zstd_state_size_precalc() is
+ * more accurate when it's allowed to use "static-only" functions */
static size_t
-tor_zstd_state_size_precalc(int compress, int preset)
+tor_zstd_state_size_precalc_fake(int compress, int preset)
{
tor_assert(preset > 0);
@@ -171,6 +210,28 @@ tor_zstd_state_size_precalc(int compress, int preset)
return memory_usage;
}
+
+/** Return an approximate number of bytes stored in memory to hold the
+ * Zstandard compression/decompression state. */
+static size_t
+tor_zstd_state_size_precalc(int compress, int preset)
+{
+#ifdef ZSTD_STATIC_LINKING_ONLY
+ if (tor_zstd_can_use_static_apis()) {
+ if (compress) {
+#ifdef HAVE_ZSTD_ESTIMATECSTREAMSIZE
+ return ZSTD_estimateCStreamSize(preset);
+#endif
+ } else {
+#ifdef HAVE_ZSTD_ESTIMATEDCTXSIZE
+ /* Could use DStream, but that takes a windowSize. */
+ return ZSTD_estimateDCtxSize();
+#endif
+ }
+ }
+#endif
+ return tor_zstd_state_size_precalc_fake(compress, preset);
+}
#endif /* defined(HAVE_ZSTD) */
/** Construct and return a tor_zstd_compress_state_t object using
@@ -440,3 +501,34 @@ tor_zstd_init(void)
atomic_counter_init(&total_zstd_allocation);
}
+/** Warn if the header and library versions don't match. */
+void
+tor_zstd_warn_if_version_mismatched(void)
+{
+#if defined(HAVE_ZSTD) && defined(ENABLE_ZSTD_ADVANCED_APIS)
+ if (! tor_zstd_can_use_static_apis()) {
+ char header_version[VERSION_STR_MAX_LEN];
+ char runtime_version[VERSION_STR_MAX_LEN];
+ tor_zstd_format_version(header_version, sizeof(header_version),
+ ZSTD_VERSION_NUMBER);
+ tor_zstd_format_version(runtime_version, sizeof(runtime_version),
+ ZSTD_versionNumber());
+
+ log_warn(LD_GENERAL,
+ "Tor was compiled with zstd %s, but is running with zstd %s. "
+ "For safety, we'll avoid using advanced zstd functionality.",
+ header_version, runtime_version);
+ }
+#endif
+}
+
+#ifdef TOR_UNIT_TESTS
+/** Testing only: disable usage of static-only APIs, so we can make sure that
+ * we still work without them. */
+void
+tor_zstd_set_static_apis_disabled_for_testing(int disabled)
+{
+ static_apis_disable_for_testing = disabled;
+}
+#endif
+
diff --git a/src/common/compress_zstd.h b/src/common/compress_zstd.h
index 9bca24ded7..bd42cf65ce 100644
--- a/src/common/compress_zstd.h
+++ b/src/common/compress_zstd.h
@@ -17,6 +17,8 @@ const char *tor_zstd_get_version_str(void);
const char *tor_zstd_get_header_version_str(void);
+int tor_zstd_can_use_static_apis(void);
+
/** Internal state for an incremental Zstandard compression/decompression. */
typedef struct tor_zstd_compress_state_t tor_zstd_compress_state_t;
@@ -41,6 +43,11 @@ size_t tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state);
size_t tor_zstd_get_total_allocation(void);
void tor_zstd_init(void);
+void tor_zstd_warn_if_version_mismatched(void);
+
+#ifdef TOR_UNIT_TESTS
+void tor_zstd_set_static_apis_disabled_for_testing(int disabled);
+#endif
#endif /* !defined(TOR_COMPRESS_ZSTD_H) */
diff --git a/src/common/container.c b/src/common/container.c
index 54b0b2028f..5386e6458b 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -15,7 +15,7 @@
#include "util.h"
#include "torlog.h"
#include "container.h"
-#include "crypto.h"
+#include "crypto_digest.h"
#include <stdlib.h>
#include <string.h>
diff --git a/src/common/crypto.c b/src/common/crypto.c
index d85aca4004..9fcd17742c 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -29,6 +29,7 @@
#include "crypto_ed25519.h"
#include "crypto_format.h"
#include "crypto_rsa.h"
+#include "crypto_digest.h"
DISABLE_GCC_WARNING(redundant-decls)
@@ -397,266 +398,6 @@ crypto_cipher_free_(crypto_cipher_t *env)
aes_cipher_free(env);
}
-/* public key crypto */
-
-/** Check a siglen-byte long signature at <b>sig</b> against
- * <b>datalen</b> bytes of data at <b>data</b>, using the public key
- * in <b>env</b>. Return 0 if <b>sig</b> is a correct signature for
- * SHA1(data). Else return -1.
- */
-MOCK_IMPL(int,
-crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data,
- size_t datalen, const char *sig,
- size_t siglen))
-{
- char digest[DIGEST_LEN];
- char *buf;
- size_t buflen;
- int r;
-
- tor_assert(env);
- tor_assert(data);
- tor_assert(sig);
- tor_assert(datalen < SIZE_T_CEILING);
- tor_assert(siglen < SIZE_T_CEILING);
-
- if (crypto_digest(digest,data,datalen)<0) {
- log_warn(LD_BUG, "couldn't compute digest");
- return -1;
- }
- buflen = crypto_pk_keysize(env);
- buf = tor_malloc(buflen);
- r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen);
- if (r != DIGEST_LEN) {
- log_warn(LD_CRYPTO, "Invalid signature");
- tor_free(buf);
- return -1;
- }
- if (tor_memneq(buf, digest, DIGEST_LEN)) {
- log_warn(LD_CRYPTO, "Signature mismatched with digest.");
- tor_free(buf);
- return -1;
- }
- tor_free(buf);
-
- return 0;
-}
-
-/** Compute a SHA1 digest of <b>fromlen</b> bytes of data stored at
- * <b>from</b>; sign the data with the private key in <b>env</b>, and
- * store it in <b>to</b>. Return the number of bytes written on
- * success, and -1 on failure.
- *
- * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
- * at least the length of the modulus of <b>env</b>.
- */
-int
-crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
- const char *from, size_t fromlen)
-{
- int r;
- char digest[DIGEST_LEN];
- if (crypto_digest(digest,from,fromlen)<0)
- return -1;
- r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN);
- memwipe(digest, 0, sizeof(digest));
- return r;
-}
-
-/** Perform a hybrid (public/secret) encryption on <b>fromlen</b>
- * bytes of data from <b>from</b>, with padding type 'padding',
- * storing the results on <b>to</b>.
- *
- * Returns the number of bytes written on success, -1 on failure.
- *
- * The encrypted data consists of:
- * - The source data, padded and encrypted with the public key, if the
- * padded source data is no longer than the public key, and <b>force</b>
- * is false, OR
- * - The beginning of the source data prefixed with a 16-byte symmetric key,
- * padded and encrypted with the public key; followed by the rest of
- * the source data encrypted in AES-CTR mode with the symmetric key.
- *
- * NOTE that this format does not authenticate the symmetrically encrypted
- * part of the data, and SHOULD NOT BE USED for new protocols.
- */
-int
-crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env,
- char *to, size_t tolen,
- const char *from,
- size_t fromlen,
- int padding, int force)
-{
- int overhead, outlen, r;
- size_t pkeylen, symlen;
- crypto_cipher_t *cipher = NULL;
- char *buf = NULL;
-
- tor_assert(env);
- tor_assert(from);
- tor_assert(to);
- tor_assert(fromlen < SIZE_T_CEILING);
-
- overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding));
- pkeylen = crypto_pk_keysize(env);
-
- if (!force && fromlen+overhead <= pkeylen) {
- /* It all fits in a single encrypt. */
- return crypto_pk_public_encrypt(env,to,
- tolen,
- from,fromlen,padding);
- }
- tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN);
- tor_assert(tolen >= pkeylen);
-
- char key[CIPHER_KEY_LEN];
- crypto_rand(key, sizeof(key)); /* generate a new key. */
- cipher = crypto_cipher_new(key);
-
- buf = tor_malloc(pkeylen+1);
- memcpy(buf, key, CIPHER_KEY_LEN);
- memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN);
-
- /* Length of symmetrically encrypted data. */
- symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN);
-
- outlen = crypto_pk_public_encrypt(env,to,tolen,buf,pkeylen-overhead,padding);
- if (outlen!=(int)pkeylen) {
- goto err;
- }
- r = crypto_cipher_encrypt(cipher, to+outlen,
- from+pkeylen-overhead-CIPHER_KEY_LEN, symlen);
-
- if (r<0) goto err;
- memwipe(buf, 0, pkeylen);
- memwipe(key, 0, sizeof(key));
- tor_free(buf);
- crypto_cipher_free(cipher);
- tor_assert(outlen+symlen < INT_MAX);
- return (int)(outlen + symlen);
- err:
-
- memwipe(buf, 0, pkeylen);
- memwipe(key, 0, sizeof(key));
- tor_free(buf);
- crypto_cipher_free(cipher);
- return -1;
-}
-
-/** Invert crypto_pk_obsolete_public_hybrid_encrypt. Returns the number of
- * bytes written on success, -1 on failure.
- *
- * NOTE that this format does not authenticate the symmetrically encrypted
- * part of the data, and SHOULD NOT BE USED for new protocols.
- */
-int
-crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env,
- char *to,
- size_t tolen,
- const char *from,
- size_t fromlen,
- int padding, int warnOnFailure)
-{
- int outlen, r;
- size_t pkeylen;
- crypto_cipher_t *cipher = NULL;
- char *buf = NULL;
-
- tor_assert(fromlen < SIZE_T_CEILING);
- pkeylen = crypto_pk_keysize(env);
-
- if (fromlen <= pkeylen) {
- return crypto_pk_private_decrypt(env,to,tolen,from,fromlen,padding,
- warnOnFailure);
- }
-
- buf = tor_malloc(pkeylen);
- outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding,
- warnOnFailure);
- if (outlen<0) {
- log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO,
- "Error decrypting public-key data");
- goto err;
- }
- if (outlen < CIPHER_KEY_LEN) {
- log_fn(warnOnFailure?LOG_WARN:LOG_INFO, LD_CRYPTO,
- "No room for a symmetric key");
- goto err;
- }
- cipher = crypto_cipher_new(buf);
- if (!cipher) {
- goto err;
- }
- memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN);
- outlen -= CIPHER_KEY_LEN;
- tor_assert(tolen - outlen >= fromlen - pkeylen);
- r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen);
- if (r<0)
- goto err;
- memwipe(buf,0,pkeylen);
- tor_free(buf);
- crypto_cipher_free(cipher);
- tor_assert(outlen + fromlen < INT_MAX);
- return (int)(outlen + (fromlen-pkeylen));
- err:
- memwipe(buf,0,pkeylen);
- tor_free(buf);
- crypto_cipher_free(cipher);
- return -1;
-}
-
-/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
- * public key into <b>digest_out</b> (must have DIGEST_LEN bytes of space).
- * Return 0 on success, -1 on failure.
- */
-int
-crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
-{
- char *buf;
- size_t buflen;
- int len;
- int rv = -1;
-
- buflen = crypto_pk_keysize(pk)*2;
- buf = tor_malloc(buflen);
- len = crypto_pk_asn1_encode(pk, buf, buflen);
- if (len < 0)
- goto done;
-
- if (crypto_digest(digest_out, buf, len) < 0)
- goto done;
-
- rv = 0;
- done:
- tor_free(buf);
- return rv;
-}
-
-/** Compute all digests of the DER encoding of <b>pk</b>, and store them
- * in <b>digests_out</b>. Return 0 on success, -1 on failure. */
-int
-crypto_pk_get_common_digests(crypto_pk_t *pk, common_digests_t *digests_out)
-{
- char *buf;
- size_t buflen;
- int len;
- int rv = -1;
-
- buflen = crypto_pk_keysize(pk)*2;
- buf = tor_malloc(buflen);
- len = crypto_pk_asn1_encode(pk, buf, buflen);
- if (len < 0)
- goto done;
-
- if (crypto_common_digests(digests_out, (char*)buf, len) < 0)
- goto done;
-
- rv = 0;
- done:
- tor_free(buf);
- return rv;
-}
-
/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces
* every four characters. */
void
@@ -788,524 +529,6 @@ crypto_cipher_decrypt_with_iv(const char *key,
return (int)(fromlen - CIPHER_IV_LEN);
}
-/* SHA-1 */
-
-/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in
- * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>.
- * Return 0 on success, -1 on failure.
- */
-int
-crypto_digest(char *digest, const char *m, size_t len)
-{
- tor_assert(m);
- tor_assert(digest);
- if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL)
- return -1;
- return 0;
-}
-
-/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
- * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result
- * into <b>digest</b>. Return 0 on success, -1 on failure. */
-int
-crypto_digest256(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm)
-{
- tor_assert(m);
- tor_assert(digest);
- tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
-
- int ret = 0;
- if (algorithm == DIGEST_SHA256)
- ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL);
- else
- ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
- > -1);
-
- if (!ret)
- return -1;
- return 0;
-}
-
-/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
- * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result
- * into <b>digest</b>. Return 0 on success, -1 on failure. */
-int
-crypto_digest512(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm)
-{
- tor_assert(m);
- tor_assert(digest);
- tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
-
- int ret = 0;
- if (algorithm == DIGEST_SHA512)
- ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
- != NULL);
- else
- ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
- > -1);
-
- if (!ret)
- return -1;
- return 0;
-}
-
-/** Set the common_digests_t in <b>ds_out</b> to contain every digest on the
- * <b>len</b> bytes in <b>m</b> that we know how to compute. Return 0 on
- * success, -1 on failure. */
-int
-crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len)
-{
- tor_assert(ds_out);
- memset(ds_out, 0, sizeof(*ds_out));
- if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
- return -1;
- if (crypto_digest256(ds_out->d[DIGEST_SHA256], m, len, DIGEST_SHA256) < 0)
- return -1;
-
- return 0;
-}
-
-/** Return the name of an algorithm, as used in directory documents. */
-const char *
-crypto_digest_algorithm_get_name(digest_algorithm_t alg)
-{
- switch (alg) {
- case DIGEST_SHA1:
- return "sha1";
- case DIGEST_SHA256:
- return "sha256";
- case DIGEST_SHA512:
- return "sha512";
- case DIGEST_SHA3_256:
- return "sha3-256";
- case DIGEST_SHA3_512:
- return "sha3-512";
- // LCOV_EXCL_START
- default:
- tor_fragile_assert();
- return "??unknown_digest??";
- // LCOV_EXCL_STOP
- }
-}
-
-/** Given the name of a digest algorithm, return its integer value, or -1 if
- * the name is not recognized. */
-int
-crypto_digest_algorithm_parse_name(const char *name)
-{
- if (!strcmp(name, "sha1"))
- return DIGEST_SHA1;
- else if (!strcmp(name, "sha256"))
- return DIGEST_SHA256;
- else if (!strcmp(name, "sha512"))
- return DIGEST_SHA512;
- else if (!strcmp(name, "sha3-256"))
- return DIGEST_SHA3_256;
- else if (!strcmp(name, "sha3-512"))
- return DIGEST_SHA3_512;
- else
- return -1;
-}
-
-/** Given an algorithm, return the digest length in bytes. */
-size_t
-crypto_digest_algorithm_get_length(digest_algorithm_t alg)
-{
- switch (alg) {
- case DIGEST_SHA1:
- return DIGEST_LEN;
- case DIGEST_SHA256:
- return DIGEST256_LEN;
- case DIGEST_SHA512:
- return DIGEST512_LEN;
- case DIGEST_SHA3_256:
- return DIGEST256_LEN;
- case DIGEST_SHA3_512:
- return DIGEST512_LEN;
- default:
- tor_assert(0); // LCOV_EXCL_LINE
- return 0; /* Unreachable */ // LCOV_EXCL_LINE
- }
-}
-
-/** Intermediate information about the digest of a stream of data. */
-struct crypto_digest_t {
- digest_algorithm_t algorithm; /**< Which algorithm is in use? */
- /** State for the digest we're using. Only one member of the
- * union is usable, depending on the value of <b>algorithm</b>. Note also
- * that space for other members might not even be allocated!
- */
- union {
- SHA_CTX sha1; /**< state for SHA1 */
- SHA256_CTX sha2; /**< state for SHA256 */
- SHA512_CTX sha512; /**< state for SHA512 */
- keccak_state sha3; /**< state for SHA3-[256,512] */
- } d;
-};
-
-#ifdef TOR_UNIT_TESTS
-
-digest_algorithm_t
-crypto_digest_get_algorithm(crypto_digest_t *digest)
-{
- tor_assert(digest);
-
- return digest->algorithm;
-}
-
-#endif /* defined(TOR_UNIT_TESTS) */
-
-/**
- * Return the number of bytes we need to malloc in order to get a
- * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
- * when we free one.
- */
-static size_t
-crypto_digest_alloc_bytes(digest_algorithm_t alg)
-{
- /* Helper: returns the number of bytes in the 'f' field of 'st' */
-#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
- /* Gives the length of crypto_digest_t through the end of the field 'd' */
-#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
- STRUCT_FIELD_SIZE(crypto_digest_t, f))
- switch (alg) {
- case DIGEST_SHA1:
- return END_OF_FIELD(d.sha1);
- case DIGEST_SHA256:
- return END_OF_FIELD(d.sha2);
- case DIGEST_SHA512:
- return END_OF_FIELD(d.sha512);
- case DIGEST_SHA3_256:
- case DIGEST_SHA3_512:
- return END_OF_FIELD(d.sha3);
- default:
- tor_assert(0); // LCOV_EXCL_LINE
- return 0; // LCOV_EXCL_LINE
- }
-#undef END_OF_FIELD
-#undef STRUCT_FIELD_SIZE
-}
-
-/**
- * Internal function: create and return a new digest object for 'algorithm'.
- * Does not typecheck the algorithm.
- */
-static crypto_digest_t *
-crypto_digest_new_internal(digest_algorithm_t algorithm)
-{
- crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
- r->algorithm = algorithm;
-
- switch (algorithm)
- {
- case DIGEST_SHA1:
- SHA1_Init(&r->d.sha1);
- break;
- case DIGEST_SHA256:
- SHA256_Init(&r->d.sha2);
- break;
- case DIGEST_SHA512:
- SHA512_Init(&r->d.sha512);
- break;
- case DIGEST_SHA3_256:
- keccak_digest_init(&r->d.sha3, 256);
- break;
- case DIGEST_SHA3_512:
- keccak_digest_init(&r->d.sha3, 512);
- break;
- default:
- tor_assert_unreached();
- }
-
- return r;
-}
-
-/** Allocate and return a new digest object to compute SHA1 digests.
- */
-crypto_digest_t *
-crypto_digest_new(void)
-{
- return crypto_digest_new_internal(DIGEST_SHA1);
-}
-
-/** Allocate and return a new digest object to compute 256-bit digests
- * using <b>algorithm</b>. */
-crypto_digest_t *
-crypto_digest256_new(digest_algorithm_t algorithm)
-{
- tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
- return crypto_digest_new_internal(algorithm);
-}
-
-/** Allocate and return a new digest object to compute 512-bit digests
- * using <b>algorithm</b>. */
-crypto_digest_t *
-crypto_digest512_new(digest_algorithm_t algorithm)
-{
- tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
- return crypto_digest_new_internal(algorithm);
-}
-
-/** Deallocate a digest object.
- */
-void
-crypto_digest_free_(crypto_digest_t *digest)
-{
- if (!digest)
- return;
- size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
- memwipe(digest, 0, bytes);
- tor_free(digest);
-}
-
-/** Add <b>len</b> bytes from <b>data</b> to the digest object.
- */
-void
-crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
- size_t len)
-{
- tor_assert(digest);
- tor_assert(data);
- /* Using the SHA*_*() calls directly means we don't support doing
- * SHA in hardware. But so far the delay of getting the question
- * to the hardware, and hearing the answer, is likely higher than
- * just doing it ourselves. Hashes are fast.
- */
- switch (digest->algorithm) {
- case DIGEST_SHA1:
- SHA1_Update(&digest->d.sha1, (void*)data, len);
- break;
- case DIGEST_SHA256:
- SHA256_Update(&digest->d.sha2, (void*)data, len);
- break;
- case DIGEST_SHA512:
- SHA512_Update(&digest->d.sha512, (void*)data, len);
- break;
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
- case DIGEST_SHA3_512:
- keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
- break;
- default:
- /* LCOV_EXCL_START */
- tor_fragile_assert();
- break;
- /* LCOV_EXCL_STOP */
- }
-}
-
-/** Compute the hash of the data that has been passed to the digest
- * object; write the first out_len bytes of the result to <b>out</b>.
- * <b>out_len</b> must be \<= DIGEST512_LEN.
- */
-void
-crypto_digest_get_digest(crypto_digest_t *digest,
- char *out, size_t out_len)
-{
- unsigned char r[DIGEST512_LEN];
- crypto_digest_t tmpenv;
- tor_assert(digest);
- tor_assert(out);
- tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm));
-
- /* The SHA-3 code handles copying into a temporary ctx, and also can handle
- * short output buffers by truncating appropriately. */
- if (digest->algorithm == DIGEST_SHA3_256 ||
- digest->algorithm == DIGEST_SHA3_512) {
- keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len);
- return;
- }
-
- const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
- /* memcpy into a temporary ctx, since SHA*_Final clears the context */
- memcpy(&tmpenv, digest, alloc_bytes);
- switch (digest->algorithm) {
- case DIGEST_SHA1:
- SHA1_Final(r, &tmpenv.d.sha1);
- break;
- case DIGEST_SHA256:
- SHA256_Final(r, &tmpenv.d.sha2);
- break;
- case DIGEST_SHA512:
- SHA512_Final(r, &tmpenv.d.sha512);
- break;
-//LCOV_EXCL_START
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
- case DIGEST_SHA3_512:
- default:
- log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
- /* This is fatal, because it should never happen. */
- tor_assert_unreached();
- break;
-//LCOV_EXCL_STOP
- }
- memcpy(out, r, out_len);
- memwipe(r, 0, sizeof(r));
-}
-
-/** Allocate and return a new digest object with the same state as
- * <b>digest</b>
- */
-crypto_digest_t *
-crypto_digest_dup(const crypto_digest_t *digest)
-{
- tor_assert(digest);
- const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
- return tor_memdup(digest, alloc_bytes);
-}
-
-/** Replace the state of the digest object <b>into</b> with the state
- * of the digest object <b>from</b>. Requires that 'into' and 'from'
- * have the same digest type.
- */
-void
-crypto_digest_assign(crypto_digest_t *into,
- const crypto_digest_t *from)
-{
- tor_assert(into);
- tor_assert(from);
- tor_assert(into->algorithm == from->algorithm);
- const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
- memcpy(into,from,alloc_bytes);
-}
-
-/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
- * at <b>digest_out</b> to the hash of the concatenation of those strings,
- * plus the optional string <b>append</b>, computed with the algorithm
- * <b>alg</b>.
- * <b>out_len</b> must be \<= DIGEST512_LEN. */
-void
-crypto_digest_smartlist(char *digest_out, size_t len_out,
- const smartlist_t *lst,
- const char *append,
- digest_algorithm_t alg)
-{
- crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
-}
-
-/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
- * at <b>digest_out</b> to the hash of the concatenation of: the
- * optional string <b>prepend</b>, those strings,
- * and the optional string <b>append</b>, computed with the algorithm
- * <b>alg</b>.
- * <b>len_out</b> must be \<= DIGEST512_LEN. */
-void
-crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
- const char *prepend,
- const smartlist_t *lst,
- const char *append,
- digest_algorithm_t alg)
-{
- crypto_digest_t *d = crypto_digest_new_internal(alg);
- if (prepend)
- crypto_digest_add_bytes(d, prepend, strlen(prepend));
- SMARTLIST_FOREACH(lst, const char *, cp,
- crypto_digest_add_bytes(d, cp, strlen(cp)));
- if (append)
- crypto_digest_add_bytes(d, append, strlen(append));
- crypto_digest_get_digest(d, digest_out, len_out);
- crypto_digest_free(d);
-}
-
-/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
- * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte
- * result in <b>hmac_out</b>. Asserts on failure.
- */
-void
-crypto_hmac_sha256(char *hmac_out,
- const char *key, size_t key_len,
- const char *msg, size_t msg_len)
-{
- unsigned char *rv = NULL;
- /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
- tor_assert(key_len < INT_MAX);
- tor_assert(msg_len < INT_MAX);
- tor_assert(hmac_out);
- rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
- (unsigned char*)hmac_out, NULL);
- tor_assert(rv);
-}
-
-/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a
- * <b>key</b> of length <b>key_len</b> and a <b>salt</b> of length
- * <b>salt_len</b>. Store the result of <b>len_out</b> bytes in in
- * <b>mac_out</b>. This function can't fail. */
-void
-crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
- const uint8_t *key, size_t key_len,
- const uint8_t *msg, size_t msg_len)
-{
- crypto_digest_t *digest;
-
- const uint64_t key_len_netorder = tor_htonll(key_len);
-
- tor_assert(mac_out);
- tor_assert(key);
- tor_assert(msg);
-
- digest = crypto_digest256_new(DIGEST_SHA3_256);
-
- /* Order matters here that is any subsystem using this function should
- * expect this very precise ordering in the MAC construction. */
- crypto_digest_add_bytes(digest, (const char *) &key_len_netorder,
- sizeof(key_len_netorder));
- crypto_digest_add_bytes(digest, (const char *) key, key_len);
- crypto_digest_add_bytes(digest, (const char *) msg, msg_len);
- crypto_digest_get_digest(digest, (char *) mac_out, len_out);
- crypto_digest_free(digest);
-}
-
-/** Internal state for a eXtendable-Output Function (XOF). */
-struct crypto_xof_t {
- keccak_state s;
-};
-
-/** Allocate a new XOF object backed by SHAKE-256. The security level
- * provided is a function of the length of the output used. Read and
- * understand FIPS-202 A.2 "Additional Consideration for Extendable-Output
- * Functions" before using this construct.
- */
-crypto_xof_t *
-crypto_xof_new(void)
-{
- crypto_xof_t *xof;
- xof = tor_malloc(sizeof(crypto_xof_t));
- keccak_xof_init(&xof->s, 256);
- return xof;
-}
-
-/** Absorb bytes into a XOF object. Must not be called after a call to
- * crypto_xof_squeeze_bytes() for the same instance, and will assert
- * if attempted.
- */
-void
-crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len)
-{
- int i = keccak_xof_absorb(&xof->s, data, len);
- tor_assert(i == 0);
-}
-
-/** Squeeze bytes out of a XOF object. Calling this routine will render
- * the XOF instance ineligible to absorb further data.
- */
-void
-crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len)
-{
- int i = keccak_xof_squeeze(&xof->s, out, len);
- tor_assert(i == 0);
-}
-
-/** Cleanse and deallocate a XOF object. */
-void
-crypto_xof_free_(crypto_xof_t *xof)
-{
- if (!xof)
- return;
- memwipe(xof, 0, sizeof(crypto_xof_t));
- tor_free(xof);
-}
-
/* DH */
/** Our DH 'g' parameter */
diff --git a/src/common/crypto.h b/src/common/crypto.h
index a9c8837b9e..b586790329 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -24,13 +24,6 @@
#include "keccak-tiny/keccak-tiny.h"
-/** Length of the output of our message digest. */
-#define DIGEST_LEN 20
-/** Length of the output of our second (improved) message digests. (For now
- * this is just sha256, but it could be any other 256-bit digest.) */
-#define DIGEST256_LEN 32
-/** Length of the output of our 64-bit optimized message digests (SHA512). */
-#define DIGEST512_LEN 64
/** Length of our symmetric cipher's keys of 128-bit. */
#define CIPHER_KEY_LEN 16
/** Length of our symmetric cipher's IV of 128-bit. */
@@ -40,54 +33,11 @@
/** Length of our DH keys. */
#define DH_BYTES (1024/8)
-/** Length of a sha1 message digest when encoded in base32 with trailing =
- * signs removed. */
-#define BASE32_DIGEST_LEN 32
-/** Length of a sha1 message digest when encoded in base64 with trailing =
- * signs removed. */
-#define BASE64_DIGEST_LEN 27
-/** Length of a sha256 message digest when encoded in base64 with trailing =
- * signs removed. */
-#define BASE64_DIGEST256_LEN 43
-/** Length of a sha512 message digest when encoded in base64 with trailing =
- * signs removed. */
-#define BASE64_DIGEST512_LEN 86
-
/** Length of encoded public key fingerprints, including space; but not
* including terminating NUL. */
#define FINGERPRINT_LEN 49
-/** Length of hex encoding of SHA1 digest, not including final NUL. */
-#define HEX_DIGEST_LEN 40
-/** Length of hex encoding of SHA256 digest, not including final NUL. */
-#define HEX_DIGEST256_LEN 64
-/** Length of hex encoding of SHA512 digest, not including final NUL. */
-#define HEX_DIGEST512_LEN 128
-
-typedef enum {
- DIGEST_SHA1 = 0,
- DIGEST_SHA256 = 1,
- DIGEST_SHA512 = 2,
- DIGEST_SHA3_256 = 3,
- DIGEST_SHA3_512 = 4,
-} digest_algorithm_t;
-#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1)
-#define N_COMMON_DIGEST_ALGORITHMS (DIGEST_SHA256+1)
-
-/** A set of all the digests we commonly compute, taken on a single
- * string. Any digests that are shorter than 512 bits are right-padded
- * with 0 bits.
- *
- * Note that this representation wastes 44 bytes for the SHA1 case, so
- * don't use it for anything where we need to allocate a whole bunch at
- * once.
- **/
-typedef struct {
- char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN];
-} common_digests_t;
typedef struct aes_cnt_cipher crypto_cipher_t;
-typedef struct crypto_digest_t crypto_digest_t;
-typedef struct crypto_xof_t crypto_xof_t;
typedef struct crypto_dh_t crypto_dh_t;
/* global state */
@@ -114,24 +64,6 @@ void crypto_cipher_free_(crypto_cipher_t *env);
#define crypto_cipher_free(c) \
FREE_AND_NULL(crypto_cipher_t, crypto_cipher_free_, (c))
-/* public key crypto */
-MOCK_DECL(int, crypto_pk_public_checksig_digest,(crypto_pk_t *env,
- const char *data, size_t datalen,
- const char *sig, size_t siglen));
-int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
- const char *from, size_t fromlen);
-int crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, char *to,
- size_t tolen,
- const char *from, size_t fromlen,
- int padding, int force);
-int crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, char *to,
- size_t tolen,
- const char *from, size_t fromlen,
- int padding, int warnOnFailure);
-int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out);
-int crypto_pk_get_common_digests(crypto_pk_t *pk,
- common_digests_t *digests_out);
-
/* symmetric crypto */
const char *crypto_cipher_get_key(crypto_cipher_t *env);
@@ -148,52 +80,6 @@ int crypto_cipher_decrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen);
-/* SHA-1 and other digests. */
-int crypto_digest(char *digest, const char *m, size_t len);
-int crypto_digest256(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm);
-int crypto_digest512(char *digest, const char *m, size_t len,
- digest_algorithm_t algorithm);
-int crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len);
-struct smartlist_t;
-void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
- const char *prepend,
- const struct smartlist_t *lst,
- const char *append,
- digest_algorithm_t alg);
-void crypto_digest_smartlist(char *digest_out, size_t len_out,
- const struct smartlist_t *lst, const char *append,
- digest_algorithm_t alg);
-const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
-size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg);
-int crypto_digest_algorithm_parse_name(const char *name);
-crypto_digest_t *crypto_digest_new(void);
-crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
-crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm);
-void crypto_digest_free_(crypto_digest_t *digest);
-#define crypto_digest_free(d) \
- FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d))
-void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
- size_t len);
-void crypto_digest_get_digest(crypto_digest_t *digest,
- char *out, size_t out_len);
-crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest);
-void crypto_digest_assign(crypto_digest_t *into,
- const crypto_digest_t *from);
-void crypto_hmac_sha256(char *hmac_out,
- const char *key, size_t key_len,
- const char *msg, size_t msg_len);
-void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
- const uint8_t *key, size_t key_len,
- const uint8_t *msg, size_t msg_len);
-
-crypto_xof_t *crypto_xof_new(void);
-void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len);
-void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len);
-void crypto_xof_free_(crypto_xof_t *xof);
-#define crypto_xof_free(xof) \
- FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof))
-
/* Key negotiation */
#define DH_TYPE_CIRCUIT 1
#define DH_TYPE_REND 2
@@ -262,9 +148,5 @@ extern int break_strongest_rng_fallback;
#endif
#endif /* defined(CRYPTO_PRIVATE) */
-#ifdef TOR_UNIT_TESTS
-digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest);
-#endif
-
#endif /* !defined(TOR_CRYPTO_H) */
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
index 8793fa6274..ccf12d00f9 100644
--- a/src/common/crypto_curve25519.c
+++ b/src/common/crypto_curve25519.c
@@ -24,6 +24,7 @@
#include "crypto.h"
#include "crypto_curve25519.h"
#include "crypto_format.h"
+#include "crypto_digest.h"
#include "util.h"
#include "torlog.h"
diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h
index 11f7423b07..4834fa0836 100644
--- a/src/common/crypto_curve25519.h
+++ b/src/common/crypto_curve25519.h
@@ -6,6 +6,7 @@
#include "testsupport.h"
#include "torint.h"
+#include "crypto_digest.h"
#include "crypto_openssl_mgt.h"
/** Length of a curve25519 public key when encoded. */
diff --git a/src/common/crypto_digest.c b/src/common/crypto_digest.c
new file mode 100644
index 0000000000..cdcc1828c8
--- /dev/null
+++ b/src/common/crypto_digest.c
@@ -0,0 +1,569 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_digest.c
+ * \brief Block of functions related with digest and xof utilities and
+ * operations.
+ **/
+
+#include "crypto_digest.h"
+
+#include "crypto.h" /* common functions */
+#include "crypto_openssl_mgt.h"
+
+DISABLE_GCC_WARNING(redundant-decls)
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+ENABLE_GCC_WARNING(redundant-decls)
+
+#include "container.h"
+
+/* Crypto digest functions */
+
+/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in
+ * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>.
+ * Return 0 on success, -1 on failure.
+ */
+int
+crypto_digest(char *digest, const char *m, size_t len)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL)
+ return -1;
+ return 0;
+}
+
+/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
+int
+crypto_digest256(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+
+ int ret = 0;
+ if (algorithm == DIGEST_SHA256)
+ ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL);
+ else
+ ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
+ > -1);
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
+int
+crypto_digest512(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm)
+{
+ tor_assert(m);
+ tor_assert(digest);
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+
+ int ret = 0;
+ if (algorithm == DIGEST_SHA512)
+ ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
+ != NULL);
+ else
+ ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
+ > -1);
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+/** Set the common_digests_t in <b>ds_out</b> to contain every digest on the
+ * <b>len</b> bytes in <b>m</b> that we know how to compute. Return 0 on
+ * success, -1 on failure. */
+int
+crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len)
+{
+ tor_assert(ds_out);
+ memset(ds_out, 0, sizeof(*ds_out));
+ if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
+ return -1;
+ if (crypto_digest256(ds_out->d[DIGEST_SHA256], m, len, DIGEST_SHA256) < 0)
+ return -1;
+
+ return 0;
+}
+
+/** Return the name of an algorithm, as used in directory documents. */
+const char *
+crypto_digest_algorithm_get_name(digest_algorithm_t alg)
+{
+ switch (alg) {
+ case DIGEST_SHA1:
+ return "sha1";
+ case DIGEST_SHA256:
+ return "sha256";
+ case DIGEST_SHA512:
+ return "sha512";
+ case DIGEST_SHA3_256:
+ return "sha3-256";
+ case DIGEST_SHA3_512:
+ return "sha3-512";
+ // LCOV_EXCL_START
+ default:
+ tor_fragile_assert();
+ return "??unknown_digest??";
+ // LCOV_EXCL_STOP
+ }
+}
+
+/** Given the name of a digest algorithm, return its integer value, or -1 if
+ * the name is not recognized. */
+int
+crypto_digest_algorithm_parse_name(const char *name)
+{
+ if (!strcmp(name, "sha1"))
+ return DIGEST_SHA1;
+ else if (!strcmp(name, "sha256"))
+ return DIGEST_SHA256;
+ else if (!strcmp(name, "sha512"))
+ return DIGEST_SHA512;
+ else if (!strcmp(name, "sha3-256"))
+ return DIGEST_SHA3_256;
+ else if (!strcmp(name, "sha3-512"))
+ return DIGEST_SHA3_512;
+ else
+ return -1;
+}
+
+/** Given an algorithm, return the digest length in bytes. */
+size_t
+crypto_digest_algorithm_get_length(digest_algorithm_t alg)
+{
+ switch (alg) {
+ case DIGEST_SHA1:
+ return DIGEST_LEN;
+ case DIGEST_SHA256:
+ return DIGEST256_LEN;
+ case DIGEST_SHA512:
+ return DIGEST512_LEN;
+ case DIGEST_SHA3_256:
+ return DIGEST256_LEN;
+ case DIGEST_SHA3_512:
+ return DIGEST512_LEN;
+ default:
+ tor_assert(0); // LCOV_EXCL_LINE
+ return 0; /* Unreachable */ // LCOV_EXCL_LINE
+ }
+}
+
+/** Intermediate information about the digest of a stream of data. */
+struct crypto_digest_t {
+ digest_algorithm_t algorithm; /**< Which algorithm is in use? */
+ /** State for the digest we're using. Only one member of the
+ * union is usable, depending on the value of <b>algorithm</b>. Note also
+ * that space for other members might not even be allocated!
+ */
+ union {
+ SHA_CTX sha1; /**< state for SHA1 */
+ SHA256_CTX sha2; /**< state for SHA256 */
+ SHA512_CTX sha512; /**< state for SHA512 */
+ keccak_state sha3; /**< state for SHA3-[256,512] */
+ } d;
+};
+
+#ifdef TOR_UNIT_TESTS
+
+digest_algorithm_t
+crypto_digest_get_algorithm(crypto_digest_t *digest)
+{
+ tor_assert(digest);
+
+ return digest->algorithm;
+}
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+/**
+ * Return the number of bytes we need to malloc in order to get a
+ * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
+ * when we free one.
+ */
+static size_t
+crypto_digest_alloc_bytes(digest_algorithm_t alg)
+{
+ /* Helper: returns the number of bytes in the 'f' field of 'st' */
+#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
+ /* Gives the length of crypto_digest_t through the end of the field 'd' */
+#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
+ STRUCT_FIELD_SIZE(crypto_digest_t, f))
+ switch (alg) {
+ case DIGEST_SHA1:
+ return END_OF_FIELD(d.sha1);
+ case DIGEST_SHA256:
+ return END_OF_FIELD(d.sha2);
+ case DIGEST_SHA512:
+ return END_OF_FIELD(d.sha512);
+ case DIGEST_SHA3_256:
+ case DIGEST_SHA3_512:
+ return END_OF_FIELD(d.sha3);
+ default:
+ tor_assert(0); // LCOV_EXCL_LINE
+ return 0; // LCOV_EXCL_LINE
+ }
+#undef END_OF_FIELD
+#undef STRUCT_FIELD_SIZE
+}
+
+/**
+ * Internal function: create and return a new digest object for 'algorithm'.
+ * Does not typecheck the algorithm.
+ */
+static crypto_digest_t *
+crypto_digest_new_internal(digest_algorithm_t algorithm)
+{
+ crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
+ r->algorithm = algorithm;
+
+ switch (algorithm)
+ {
+ case DIGEST_SHA1:
+ SHA1_Init(&r->d.sha1);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Init(&r->d.sha2);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Init(&r->d.sha512);
+ break;
+ case DIGEST_SHA3_256:
+ keccak_digest_init(&r->d.sha3, 256);
+ break;
+ case DIGEST_SHA3_512:
+ keccak_digest_init(&r->d.sha3, 512);
+ break;
+ default:
+ tor_assert_unreached();
+ }
+
+ return r;
+}
+
+/** Allocate and return a new digest object to compute SHA1 digests.
+ */
+crypto_digest_t *
+crypto_digest_new(void)
+{
+ return crypto_digest_new_internal(DIGEST_SHA1);
+}
+
+/** Allocate and return a new digest object to compute 256-bit digests
+ * using <b>algorithm</b>. */
+crypto_digest_t *
+crypto_digest256_new(digest_algorithm_t algorithm)
+{
+ tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+ return crypto_digest_new_internal(algorithm);
+}
+
+/** Allocate and return a new digest object to compute 512-bit digests
+ * using <b>algorithm</b>. */
+crypto_digest_t *
+crypto_digest512_new(digest_algorithm_t algorithm)
+{
+ tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+ return crypto_digest_new_internal(algorithm);
+}
+
+/** Deallocate a digest object.
+ */
+void
+crypto_digest_free_(crypto_digest_t *digest)
+{
+ if (!digest)
+ return;
+ size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ memwipe(digest, 0, bytes);
+ tor_free(digest);
+}
+
+/** Add <b>len</b> bytes from <b>data</b> to the digest object.
+ */
+void
+crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
+ size_t len)
+{
+ tor_assert(digest);
+ tor_assert(data);
+ /* Using the SHA*_*() calls directly means we don't support doing
+ * SHA in hardware. But so far the delay of getting the question
+ * to the hardware, and hearing the answer, is likely higher than
+ * just doing it ourselves. Hashes are fast.
+ */
+ switch (digest->algorithm) {
+ case DIGEST_SHA1:
+ SHA1_Update(&digest->d.sha1, (void*)data, len);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Update(&digest->d.sha2, (void*)data, len);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Update(&digest->d.sha512, (void*)data, len);
+ break;
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
+ break;
+ default:
+ /* LCOV_EXCL_START */
+ tor_fragile_assert();
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+}
+
+/** Compute the hash of the data that has been passed to the digest
+ * object; write the first out_len bytes of the result to <b>out</b>.
+ * <b>out_len</b> must be \<= DIGEST512_LEN.
+ */
+void
+crypto_digest_get_digest(crypto_digest_t *digest,
+ char *out, size_t out_len)
+{
+ unsigned char r[DIGEST512_LEN];
+ crypto_digest_t tmpenv;
+ tor_assert(digest);
+ tor_assert(out);
+ tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm));
+
+ /* The SHA-3 code handles copying into a temporary ctx, and also can handle
+ * short output buffers by truncating appropriately. */
+ if (digest->algorithm == DIGEST_SHA3_256 ||
+ digest->algorithm == DIGEST_SHA3_512) {
+ keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len);
+ return;
+ }
+
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ /* memcpy into a temporary ctx, since SHA*_Final clears the context */
+ memcpy(&tmpenv, digest, alloc_bytes);
+ switch (digest->algorithm) {
+ case DIGEST_SHA1:
+ SHA1_Final(r, &tmpenv.d.sha1);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Final(r, &tmpenv.d.sha2);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Final(r, &tmpenv.d.sha512);
+ break;
+//LCOV_EXCL_START
+ case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_512:
+ default:
+ log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
+ /* This is fatal, because it should never happen. */
+ tor_assert_unreached();
+ break;
+//LCOV_EXCL_STOP
+ }
+ memcpy(out, r, out_len);
+ memwipe(r, 0, sizeof(r));
+}
+
+/** Allocate and return a new digest object with the same state as
+ * <b>digest</b>
+ */
+crypto_digest_t *
+crypto_digest_dup(const crypto_digest_t *digest)
+{
+ tor_assert(digest);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ return tor_memdup(digest, alloc_bytes);
+}
+
+/** Temporarily save the state of <b>digest</b> in <b>checkpoint</b>.
+ * Asserts that <b>digest</b> is a SHA1 digest object.
+ */
+void
+crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint,
+ const crypto_digest_t *digest)
+{
+ const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ tor_assert(bytes <= sizeof(checkpoint->mem));
+ memcpy(checkpoint->mem, digest, bytes);
+}
+
+/** Restore the state of <b>digest</b> from <b>checkpoint</b>.
+ * Asserts that <b>digest</b> is a SHA1 digest object. Requires that the
+ * state was previously stored with crypto_digest_checkpoint() */
+void
+crypto_digest_restore(crypto_digest_t *digest,
+ const crypto_digest_checkpoint_t *checkpoint)
+{
+ const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
+ memcpy(digest, checkpoint->mem, bytes);
+}
+
+/** Replace the state of the digest object <b>into</b> with the state
+ * of the digest object <b>from</b>. Requires that 'into' and 'from'
+ * have the same digest type.
+ */
+void
+crypto_digest_assign(crypto_digest_t *into,
+ const crypto_digest_t *from)
+{
+ tor_assert(into);
+ tor_assert(from);
+ tor_assert(into->algorithm == from->algorithm);
+ const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
+ memcpy(into,from,alloc_bytes);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of those strings,
+ * plus the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>out_len</b> must be \<= DIGEST512_LEN. */
+void
+crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of: the
+ * optional string <b>prepend</b>, those strings,
+ * and the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>len_out</b> must be \<= DIGEST512_LEN. */
+void
+crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
+ const char *prepend,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_t *d = crypto_digest_new_internal(alg);
+ if (prepend)
+ crypto_digest_add_bytes(d, prepend, strlen(prepend));
+ SMARTLIST_FOREACH(lst, const char *, cp,
+ crypto_digest_add_bytes(d, cp, strlen(cp)));
+ if (append)
+ crypto_digest_add_bytes(d, append, strlen(append));
+ crypto_digest_get_digest(d, digest_out, len_out);
+ crypto_digest_free(d);
+}
+
+/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
+ * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte
+ * result in <b>hmac_out</b>. Asserts on failure.
+ */
+void
+crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len)
+{
+ unsigned char *rv = NULL;
+ /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
+ tor_assert(key_len < INT_MAX);
+ tor_assert(msg_len < INT_MAX);
+ tor_assert(hmac_out);
+ rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
+ (unsigned char*)hmac_out, NULL);
+ tor_assert(rv);
+}
+
+/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a
+ * <b>key</b> of length <b>key_len</b> and a <b>salt</b> of length
+ * <b>salt_len</b>. Store the result of <b>len_out</b> bytes in in
+ * <b>mac_out</b>. This function can't fail. */
+void
+crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
+ const uint8_t *key, size_t key_len,
+ const uint8_t *msg, size_t msg_len)
+{
+ crypto_digest_t *digest;
+
+ const uint64_t key_len_netorder = tor_htonll(key_len);
+
+ tor_assert(mac_out);
+ tor_assert(key);
+ tor_assert(msg);
+
+ digest = crypto_digest256_new(DIGEST_SHA3_256);
+
+ /* Order matters here that is any subsystem using this function should
+ * expect this very precise ordering in the MAC construction. */
+ crypto_digest_add_bytes(digest, (const char *) &key_len_netorder,
+ sizeof(key_len_netorder));
+ crypto_digest_add_bytes(digest, (const char *) key, key_len);
+ crypto_digest_add_bytes(digest, (const char *) msg, msg_len);
+ crypto_digest_get_digest(digest, (char *) mac_out, len_out);
+ crypto_digest_free(digest);
+}
+
+/* xof functions */
+
+/** Internal state for a eXtendable-Output Function (XOF). */
+struct crypto_xof_t {
+ keccak_state s;
+};
+
+/** Allocate a new XOF object backed by SHAKE-256. The security level
+ * provided is a function of the length of the output used. Read and
+ * understand FIPS-202 A.2 "Additional Consideration for Extendable-Output
+ * Functions" before using this construct.
+ */
+crypto_xof_t *
+crypto_xof_new(void)
+{
+ crypto_xof_t *xof;
+ xof = tor_malloc(sizeof(crypto_xof_t));
+ keccak_xof_init(&xof->s, 256);
+ return xof;
+}
+
+/** Absorb bytes into a XOF object. Must not be called after a call to
+ * crypto_xof_squeeze_bytes() for the same instance, and will assert
+ * if attempted.
+ */
+void
+crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len)
+{
+ int i = keccak_xof_absorb(&xof->s, data, len);
+ tor_assert(i == 0);
+}
+
+/** Squeeze bytes out of a XOF object. Calling this routine will render
+ * the XOF instance ineligible to absorb further data.
+ */
+void
+crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len)
+{
+ int i = keccak_xof_squeeze(&xof->s, out, len);
+ tor_assert(i == 0);
+}
+
+/** Cleanse and deallocate a XOF object. */
+void
+crypto_xof_free_(crypto_xof_t *xof)
+{
+ if (!xof)
+ return;
+ memwipe(xof, 0, sizeof(crypto_xof_t));
+ tor_free(xof);
+}
+
diff --git a/src/common/crypto_digest.h b/src/common/crypto_digest.h
new file mode 100644
index 0000000000..3bd74acdfa
--- /dev/null
+++ b/src/common/crypto_digest.h
@@ -0,0 +1,136 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file crypto_digest.h
+ *
+ * \brief Headers for crypto_digest.c
+ **/
+
+#ifndef TOR_CRYPTO_DIGEST_H
+#define TOR_CRYPTO_DIGEST_H
+
+#include <stdio.h>
+
+#include "container.h"
+#include "torint.h"
+
+/** Length of the output of our message digest. */
+#define DIGEST_LEN 20
+/** Length of the output of our second (improved) message digests. (For now
+ * this is just sha256, but it could be any other 256-bit digest.) */
+#define DIGEST256_LEN 32
+/** Length of the output of our 64-bit optimized message digests (SHA512). */
+#define DIGEST512_LEN 64
+
+/** Length of a sha1 message digest when encoded in base32 with trailing =
+ * signs removed. */
+#define BASE32_DIGEST_LEN 32
+/** Length of a sha1 message digest when encoded in base64 with trailing =
+ * signs removed. */
+#define BASE64_DIGEST_LEN 27
+/** Length of a sha256 message digest when encoded in base64 with trailing =
+ * signs removed. */
+#define BASE64_DIGEST256_LEN 43
+/** Length of a sha512 message digest when encoded in base64 with trailing =
+ * signs removed. */
+#define BASE64_DIGEST512_LEN 86
+
+/** Length of hex encoding of SHA1 digest, not including final NUL. */
+#define HEX_DIGEST_LEN 40
+/** Length of hex encoding of SHA256 digest, not including final NUL. */
+#define HEX_DIGEST256_LEN 64
+/** Length of hex encoding of SHA512 digest, not including final NUL. */
+#define HEX_DIGEST512_LEN 128
+
+typedef enum {
+ DIGEST_SHA1 = 0,
+ DIGEST_SHA256 = 1,
+ DIGEST_SHA512 = 2,
+ DIGEST_SHA3_256 = 3,
+ DIGEST_SHA3_512 = 4,
+} digest_algorithm_t;
+#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1)
+#define N_COMMON_DIGEST_ALGORITHMS (DIGEST_SHA256+1)
+
+#define DIGEST_CHECKPOINT_BYTES (SIZEOF_VOID_P + 512)
+/** Structure used to temporarily save the a digest object. Only implemented
+ * for SHA1 digest for now. */
+typedef struct crypto_digest_checkpoint_t {
+ uint8_t mem[DIGEST_CHECKPOINT_BYTES];
+} crypto_digest_checkpoint_t;
+
+/** A set of all the digests we commonly compute, taken on a single
+ * string. Any digests that are shorter than 512 bits are right-padded
+ * with 0 bits.
+ *
+ * Note that this representation wastes 44 bytes for the SHA1 case, so
+ * don't use it for anything where we need to allocate a whole bunch at
+ * once.
+ **/
+typedef struct {
+ char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN];
+} common_digests_t;
+
+typedef struct crypto_digest_t crypto_digest_t;
+typedef struct crypto_xof_t crypto_xof_t;
+
+/* SHA-1 and other digests */
+int crypto_digest(char *digest, const char *m, size_t len);
+int crypto_digest256(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm);
+int crypto_digest512(char *digest, const char *m, size_t len,
+ digest_algorithm_t algorithm);
+int crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len);
+void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
+ const char *prepend,
+ const struct smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg);
+void crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const struct smartlist_t *lst, const char *append,
+ digest_algorithm_t alg);
+const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
+size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg);
+int crypto_digest_algorithm_parse_name(const char *name);
+crypto_digest_t *crypto_digest_new(void);
+crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
+crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm);
+void crypto_digest_free_(crypto_digest_t *digest);
+#define crypto_digest_free(d) \
+ FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d))
+void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
+ size_t len);
+void crypto_digest_get_digest(crypto_digest_t *digest,
+ char *out, size_t out_len);
+crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest);
+void crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint,
+ const crypto_digest_t *digest);
+void crypto_digest_restore(crypto_digest_t *digest,
+ const crypto_digest_checkpoint_t *checkpoint);
+void crypto_digest_assign(crypto_digest_t *into,
+ const crypto_digest_t *from);
+void crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len);
+void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
+ const uint8_t *key, size_t key_len,
+ const uint8_t *msg, size_t msg_len);
+
+/* xof functions*/
+crypto_xof_t *crypto_xof_new(void);
+void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len);
+void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len);
+void crypto_xof_free_(crypto_xof_t *xof);
+#define crypto_xof_free(xof) \
+ FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof))
+
+#ifdef TOR_UNIT_TESTS
+digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest);
+#endif
+
+#endif /* !defined(TOR_CRYPTO_DIGEST_H) */
+
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
index b962a59de1..f1cc0cb188 100644
--- a/src/common/crypto_ed25519.c
+++ b/src/common/crypto_ed25519.c
@@ -23,6 +23,7 @@
#include "crypto.h"
+#include "crypto_digest.h"
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
#include "crypto_format.h"
diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c
index 1d090a8770..3f6fb9f54c 100644
--- a/src/common/crypto_format.c
+++ b/src/common/crypto_format.c
@@ -19,6 +19,7 @@
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
#include "crypto_format.h"
+#include "crypto_digest.h"
#include "util.h"
#include "util_format.h"
#include "torlog.h"
diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c
index 12acc9331c..604fc68e97 100644
--- a/src/common/crypto_pwbox.c
+++ b/src/common/crypto_pwbox.c
@@ -11,6 +11,7 @@
#include "crypto.h"
#include "crypto_s2k.h"
#include "crypto_pwbox.h"
+#include "crypto_digest.h"
#include "di_ops.h"
#include "util.h"
#include "pwbox.h"
diff --git a/src/common/crypto_rsa.c b/src/common/crypto_rsa.c
index fa572580a4..986ccb0ee2 100644
--- a/src/common/crypto_rsa.c
+++ b/src/common/crypto_rsa.c
@@ -13,8 +13,8 @@
#include "crypto.h"
#include "compat_openssl.h"
#include "crypto_curve25519.h"
-#include "crypto_ed25519.h"
#include "crypto_format.h"
+#include "crypto_digest.h"
DISABLE_GCC_WARNING(redundant-decls)
@@ -627,6 +627,148 @@ crypto_pk_copy_full(crypto_pk_t *env)
return crypto_new_pk_from_rsa_(new_key);
}
+/** Perform a hybrid (public/secret) encryption on <b>fromlen</b>
+ * bytes of data from <b>from</b>, with padding type 'padding',
+ * storing the results on <b>to</b>.
+ *
+ * Returns the number of bytes written on success, -1 on failure.
+ *
+ * The encrypted data consists of:
+ * - The source data, padded and encrypted with the public key, if the
+ * padded source data is no longer than the public key, and <b>force</b>
+ * is false, OR
+ * - The beginning of the source data prefixed with a 16-byte symmetric key,
+ * padded and encrypted with the public key; followed by the rest of
+ * the source data encrypted in AES-CTR mode with the symmetric key.
+ *
+ * NOTE that this format does not authenticate the symmetrically encrypted
+ * part of the data, and SHOULD NOT BE USED for new protocols.
+ */
+int
+crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env,
+ char *to, size_t tolen,
+ const char *from,
+ size_t fromlen,
+ int padding, int force)
+{
+ int overhead, outlen, r;
+ size_t pkeylen, symlen;
+ crypto_cipher_t *cipher = NULL;
+ char *buf = NULL;
+
+ tor_assert(env);
+ tor_assert(from);
+ tor_assert(to);
+ tor_assert(fromlen < SIZE_T_CEILING);
+
+ overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding));
+ pkeylen = crypto_pk_keysize(env);
+
+ if (!force && fromlen+overhead <= pkeylen) {
+ /* It all fits in a single encrypt. */
+ return crypto_pk_public_encrypt(env,to,
+ tolen,
+ from,fromlen,padding);
+ }
+ tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN);
+ tor_assert(tolen >= pkeylen);
+
+ char key[CIPHER_KEY_LEN];
+ crypto_rand(key, sizeof(key)); /* generate a new key. */
+ cipher = crypto_cipher_new(key);
+
+ buf = tor_malloc(pkeylen+1);
+ memcpy(buf, key, CIPHER_KEY_LEN);
+ memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN);
+
+ /* Length of symmetrically encrypted data. */
+ symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN);
+
+ outlen = crypto_pk_public_encrypt(env,to,tolen,buf,pkeylen-overhead,padding);
+ if (outlen!=(int)pkeylen) {
+ goto err;
+ }
+ r = crypto_cipher_encrypt(cipher, to+outlen,
+ from+pkeylen-overhead-CIPHER_KEY_LEN, symlen);
+
+ if (r<0) goto err;
+ memwipe(buf, 0, pkeylen);
+ memwipe(key, 0, sizeof(key));
+ tor_free(buf);
+ crypto_cipher_free(cipher);
+ tor_assert(outlen+symlen < INT_MAX);
+ return (int)(outlen + symlen);
+ err:
+
+ memwipe(buf, 0, pkeylen);
+ memwipe(key, 0, sizeof(key));
+ tor_free(buf);
+ crypto_cipher_free(cipher);
+ return -1;
+}
+
+/** Invert crypto_pk_obsolete_public_hybrid_encrypt. Returns the number of
+ * bytes written on success, -1 on failure.
+ *
+ * NOTE that this format does not authenticate the symmetrically encrypted
+ * part of the data, and SHOULD NOT BE USED for new protocols.
+ */
+int
+crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env,
+ char *to,
+ size_t tolen,
+ const char *from,
+ size_t fromlen,
+ int padding, int warnOnFailure)
+{
+ int outlen, r;
+ size_t pkeylen;
+ crypto_cipher_t *cipher = NULL;
+ char *buf = NULL;
+
+ tor_assert(fromlen < SIZE_T_CEILING);
+ pkeylen = crypto_pk_keysize(env);
+
+ if (fromlen <= pkeylen) {
+ return crypto_pk_private_decrypt(env,to,tolen,from,fromlen,padding,
+ warnOnFailure);
+ }
+
+ buf = tor_malloc(pkeylen);
+ outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding,
+ warnOnFailure);
+ if (outlen<0) {
+ log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO,
+ "Error decrypting public-key data");
+ goto err;
+ }
+ if (outlen < CIPHER_KEY_LEN) {
+ log_fn(warnOnFailure?LOG_WARN:LOG_INFO, LD_CRYPTO,
+ "No room for a symmetric key");
+ goto err;
+ }
+ cipher = crypto_cipher_new(buf);
+ if (!cipher) {
+ goto err;
+ }
+ memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN);
+ outlen -= CIPHER_KEY_LEN;
+ tor_assert(tolen - outlen >= fromlen - pkeylen);
+ r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen);
+ if (r<0)
+ goto err;
+ memwipe(buf,0,pkeylen);
+ tor_free(buf);
+ crypto_cipher_free(cipher);
+ tor_assert(outlen + fromlen < INT_MAX);
+ return (int)(outlen + (fromlen-pkeylen));
+ err:
+ memwipe(buf,0,pkeylen);
+ tor_free(buf);
+ crypto_cipher_free(cipher);
+ return -1;
+}
+
/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key
* in <b>env</b>, using the padding method <b>padding</b>. On success,
* write the result to <b>to</b>, and return the number of bytes
@@ -849,6 +991,122 @@ crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
return 0;
}
+/** Check a siglen-byte long signature at <b>sig</b> against
+ * <b>datalen</b> bytes of data at <b>data</b>, using the public key
+ * in <b>env</b>. Return 0 if <b>sig</b> is a correct signature for
+ * SHA1(data). Else return -1.
+ */
+MOCK_IMPL(int,
+crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data,
+ size_t datalen, const char *sig,
+ size_t siglen))
+{
+ char digest[DIGEST_LEN];
+ char *buf;
+ size_t buflen;
+ int r;
+
+ tor_assert(env);
+ tor_assert(data);
+ tor_assert(sig);
+ tor_assert(datalen < SIZE_T_CEILING);
+ tor_assert(siglen < SIZE_T_CEILING);
+
+ if (crypto_digest(digest,data,datalen)<0) {
+ log_warn(LD_BUG, "couldn't compute digest");
+ return -1;
+ }
+ buflen = crypto_pk_keysize(env);
+ buf = tor_malloc(buflen);
+ r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen);
+ if (r != DIGEST_LEN) {
+ log_warn(LD_CRYPTO, "Invalid signature");
+ tor_free(buf);
+ return -1;
+ }
+ if (tor_memneq(buf, digest, DIGEST_LEN)) {
+ log_warn(LD_CRYPTO, "Signature mismatched with digest.");
+ tor_free(buf);
+ return -1;
+ }
+ tor_free(buf);
+
+ return 0;
+}
+
+/** Compute a SHA1 digest of <b>fromlen</b> bytes of data stored at
+ * <b>from</b>; sign the data with the private key in <b>env</b>, and
+ * store it in <b>to</b>. Return the number of bytes written on
+ * success, and -1 on failure.
+ *
+ * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
+ * at least the length of the modulus of <b>env</b>.
+ */
+int
+crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
+ const char *from, size_t fromlen)
+{
+ int r;
+ char digest[DIGEST_LEN];
+ if (crypto_digest(digest,from,fromlen)<0)
+ return -1;
+ r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN);
+ memwipe(digest, 0, sizeof(digest));
+ return r;
+}
+
+/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
+ * public key into <b>digest_out</b> (must have DIGEST_LEN bytes of space).
+ * Return 0 on success, -1 on failure.
+ */
+int
+crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
+{
+ char *buf;
+ size_t buflen;
+ int len;
+ int rv = -1;
+
+ buflen = crypto_pk_keysize(pk)*2;
+ buf = tor_malloc(buflen);
+ len = crypto_pk_asn1_encode(pk, buf, buflen);
+ if (len < 0)
+ goto done;
+
+ if (crypto_digest(digest_out, buf, len) < 0)
+ goto done;
+
+ rv = 0;
+ done:
+ tor_free(buf);
+ return rv;
+}
+
+/** Compute all digests of the DER encoding of <b>pk</b>, and store them
+ * in <b>digests_out</b>. Return 0 on success, -1 on failure. */
+int
+crypto_pk_get_common_digests(crypto_pk_t *pk, common_digests_t *digests_out)
+{
+ char *buf;
+ size_t buflen;
+ int len;
+ int rv = -1;
+
+ buflen = crypto_pk_keysize(pk)*2;
+ buf = tor_malloc(buflen);
+ len = crypto_pk_asn1_encode(pk, buf, buflen);
+ if (len < 0)
+ goto done;
+
+ if (crypto_common_digests(digests_out, (char*)buf, len) < 0)
+ goto done;
+
+ rv = 0;
+ done:
+ tor_free(buf);
+ return rv;
+}
+
/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the
* Base64 encoding of the DER representation of the private key as a NUL
* terminated string, and return it via <b>priv_out</b>. Return 0 on
diff --git a/src/common/crypto_rsa.h b/src/common/crypto_rsa.h
index 5b9025c629..2f5442a5d2 100644
--- a/src/common/crypto_rsa.h
+++ b/src/common/crypto_rsa.h
@@ -15,13 +15,13 @@
#include "orconfig.h"
+#include "crypto_digest.h"
#include <stdio.h>
#include "torint.h"
#include "testsupport.h"
#include "compat.h"
#include "util.h"
#include "torlog.h"
-#include "crypto_curve25519.h"
/** Length of our public keys. */
#define PK_BYTES (1024/8)
@@ -69,6 +69,14 @@ crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig);
crypto_pk_t *crypto_pk_copy_full(crypto_pk_t *orig);
int crypto_pk_key_is_private(const crypto_pk_t *key);
int crypto_pk_public_exponent_ok(crypto_pk_t *env);
+int crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen,
+ int padding, int force);
+int crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen,
+ int padding, int warnOnFailure);
int crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen, int padding);
int crypto_pk_private_decrypt(crypto_pk_t *env, char *to, size_t tolen,
@@ -84,6 +92,13 @@ crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
int crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out);
+MOCK_DECL(int, crypto_pk_public_checksig_digest,(crypto_pk_t *env,
+ const char *data, size_t datalen, const char *sig, size_t siglen));
+int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
+ const char *from, size_t fromlen);
+int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out);
+int crypto_pk_get_common_digests(crypto_pk_t *pk,
+ common_digests_t *digests_out);
int crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out);
crypto_pk_t *crypto_pk_base64_decode(const char *str, size_t len);
diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c
index b2fcca54c4..316445e40f 100644
--- a/src/common/crypto_s2k.c
+++ b/src/common/crypto_s2k.c
@@ -16,6 +16,7 @@
#include "util.h"
#include "compat.h"
#include "crypto_s2k.h"
+#include "crypto_digest.h"
#include <openssl/evp.h>
diff --git a/src/common/include.am b/src/common/include.am
index 6945285108..87ab9d79e9 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -97,6 +97,7 @@ LIBOR_A_SRC = \
src/common/util_process.c \
src/common/sandbox.c \
src/common/storagedir.c \
+ src/common/token_bucket.c \
src/common/workqueue.c \
$(libor_extra_source) \
$(threads_impl_source) \
@@ -114,6 +115,7 @@ LIBOR_CRYPTO_A_SRC = \
src/common/compress_zlib.c \
src/common/compress_zstd.c \
src/common/crypto.c \
+ src/common/crypto_digest.c \
src/common/crypto_rsa.c \
src/common/crypto_openssl_mgt.c \
src/common/crypto_pwbox.c \
@@ -165,6 +167,7 @@ COMMONHEADERS = \
src/common/confline.h \
src/common/container.h \
src/common/crypto.h \
+ src/common/crypto_digest.h \
src/common/crypto_curve25519.h \
src/common/crypto_ed25519.h \
src/common/crypto_format.h \
@@ -182,6 +185,7 @@ COMMONHEADERS = \
src/common/storagedir.h \
src/common/testsupport.h \
src/common/timers.h \
+ src/common/token_bucket.h \
src/common/torint.h \
src/common/torlog.h \
src/common/tortls.h \
diff --git a/src/common/log.c b/src/common/log.c
index 9f4a8b2bc2..922e9dd38f 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -52,6 +52,13 @@
#define raw_assert(x) assert(x) // assert OK
+/** Defining compile-time constants for Tor log levels (used by the Rust
+ * log wrapper at src/rust/tor_log) */
+const int LOG_WARN_ = LOG_WARN;
+const int LOG_NOTICE_ = LOG_NOTICE;
+const log_domain_mask_t LD_GENERAL_ = LD_GENERAL;
+const log_domain_mask_t LD_NET_ = LD_NET;
+
/** Information for a single logfile; only used in log.c */
typedef struct logfile_t {
struct logfile_t *next; /**< Next logfile_t in the linked list. */
@@ -225,6 +232,30 @@ log_set_application_name(const char *name)
appname = name ? tor_strdup(name) : NULL;
}
+/** Return true if some of the running logs might be interested in a log
+ * message of the given severity in the given domains. If this function
+ * returns true, the log message might be ignored anyway, but if it returns
+ * false, it is definitely_ safe not to log the message. */
+int
+log_message_is_interesting(int severity, log_domain_mask_t domain)
+{
+ (void) domain;
+ return (severity <= log_global_min_severity_);
+}
+
+/**
+ * As tor_log, but takes an optional function name, and does not treat its
+ * <b>string</b> as a printf format.
+ *
+ * For use by Rust integration.
+ */
+void
+tor_log_string(int severity, log_domain_mask_t domain,
+ const char *function, const char *string)
+{
+ log_fn_(severity, domain, function, "%s", string);
+}
+
/** Log time granularity in milliseconds. */
static int log_time_granularity = 1;
diff --git a/src/common/procmon.c b/src/common/procmon.c
index abcbbeaa21..73c14cd584 100644
--- a/src/common/procmon.c
+++ b/src/common/procmon.c
@@ -10,8 +10,6 @@
#include "util.h"
-#include <event2/event.h>
-
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
@@ -44,7 +42,7 @@ typedef int pid_t;
/* Currently we need to poll in some way on all systems. */
#ifdef PROCMON_POLLS
-static void tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
+static void tor_process_monitor_poll_cb(periodic_timer_t *ev,
void *procmon_);
#endif
@@ -136,7 +134,7 @@ struct tor_process_monitor_t {
/** A Libevent event structure, to either poll for the process's
* existence or receive a notification when the process ends. */
- struct event *e;
+ periodic_timer_t *e;
/** A callback to be called when the process ends. */
tor_procmon_callback_t cb;
@@ -159,9 +157,6 @@ tor_validate_process_specifier(const char *process_spec,
return parse_process_specifier(process_spec, &ppspec, msg);
}
-/* XXXX we should use periodic_timer_new() for this stuff */
-#define PERIODIC_TIMER_FLAGS EV_PERSIST
-
/* DOCDOC poll_interval_tv */
static const struct timeval poll_interval_tv = {15, 0};
@@ -225,13 +220,9 @@ tor_process_monitor_new(struct event_base *base,
procmon->cb_arg = cb_arg;
#ifdef PROCMON_POLLS
- procmon->e = tor_event_new(base, -1 /* no FD */, PERIODIC_TIMER_FLAGS,
- tor_process_monitor_poll_cb, procmon);
- /* Note: If you port this file to plain Libevent 2, check that
- * procmon->e is non-NULL. We don't need to here because
- * tor_evtimer_new never returns NULL. */
-
- evtimer_add(procmon->e, &poll_interval_tv);
+ procmon->e = periodic_timer_new(base,
+ &poll_interval_tv,
+ tor_process_monitor_poll_cb, procmon);
#else /* !(defined(PROCMON_POLLS)) */
#error OOPS?
#endif /* defined(PROCMON_POLLS) */
@@ -246,14 +237,12 @@ tor_process_monitor_new(struct event_base *base,
/** Libevent callback to poll for the existence of the process
* monitored by <b>procmon_</b>. */
static void
-tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
- void *procmon_)
+tor_process_monitor_poll_cb(periodic_timer_t *event, void *procmon_)
{
+ (void)event;
tor_process_monitor_t *procmon = (tor_process_monitor_t *)(procmon_);
int its_dead_jim;
- (void)unused1; (void)unused2;
-
tor_assert(procmon != NULL);
#ifdef _WIN32
@@ -336,7 +325,7 @@ tor_process_monitor_free_(tor_process_monitor_t *procmon)
#endif
if (procmon->e != NULL)
- tor_event_free(procmon->e);
+ periodic_timer_free(procmon->e);
tor_free(procmon);
}
diff --git a/src/common/timers.c b/src/common/timers.c
index 552080b11e..6f6236ed3b 100644
--- a/src/common/timers.c
+++ b/src/common/timers.c
@@ -37,8 +37,6 @@
#include "torlog.h"
#include "util.h"
-#include <event2/event.h>
-
struct timeout_cb {
timer_cb_fn_t cb;
void *arg;
@@ -66,10 +64,15 @@ struct timeout_cb {
* above TIMEOUT_MAX can also be super-inefficient. Choosing 5 here sets
* timeout_max to 2^30 ticks, or 29 hours with our value for USEC_PER_TICK */
#define WHEEL_NUM 5
+#if SIZEOF_VOID_P == 4
+/* On 32-bit platforms, we want to override wheel_bit, so that timeout.c will
+ * use 32-bit math. */
+#define WHEEL_BIT 5
+#endif
#include "src/ext/timeouts/timeout.c"
static struct timeouts *global_timeouts = NULL;
-static struct event *global_timer_event = NULL;
+static struct mainloop_event_t *global_timer_event = NULL;
static monotime_t start_of_time;
@@ -147,7 +150,7 @@ libevent_timer_reschedule(void)
if (delay > MIN_CHECK_TICKS)
delay = MIN_CHECK_TICKS;
timeout_to_tv(delay, &d);
- event_add(global_timer_event, &d);
+ mainloop_event_schedule(global_timer_event, &d);
}
/** Run the callback of every timer that has expired, based on the current
@@ -170,10 +173,9 @@ timers_run_pending(void)
* have fired, activate their callbacks, and reschedule the libevent timer.
*/
static void
-libevent_timer_callback(evutil_socket_t fd, short what, void *arg)
+libevent_timer_callback(mainloop_event_t *ev, void *arg)
{
- (void)fd;
- (void)what;
+ (void)ev;
(void)arg;
timers_run_pending();
@@ -203,9 +205,8 @@ timers_initialize(void)
monotime_init();
monotime_get(&start_of_time);
- struct event *timer_event;
- timer_event = tor_event_new(tor_libevent_get_base(),
- -1, 0, libevent_timer_callback, NULL);
+ mainloop_event_t *timer_event;
+ timer_event = mainloop_event_new(libevent_timer_callback, NULL);
tor_assert(timer_event);
global_timer_event = timer_event;
@@ -219,7 +220,7 @@ void
timers_shutdown(void)
{
if (global_timer_event) {
- tor_event_free(global_timer_event);
+ mainloop_event_free(global_timer_event);
global_timer_event = NULL;
}
if (global_timeouts) {
diff --git a/src/common/token_bucket.c b/src/common/token_bucket.c
new file mode 100644
index 0000000000..747189e751
--- /dev/null
+++ b/src/common/token_bucket.c
@@ -0,0 +1,250 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file token_bucket.c
+ * \brief Functions to use and manipulate token buckets, used for
+ * rate-limiting on connections and globally.
+ *
+ * Tor uses these token buckets to keep track of bandwidth usage, and
+ * sometimes other things too.
+ *
+ * There are two layers of abstraction here: "raw" token buckets, in which all
+ * the pieces are decoupled, and "read-write" token buckets, which combine all
+ * the moving parts into one.
+ *
+ * Token buckets may become negative.
+ **/
+
+#define TOKEN_BUCKET_PRIVATE
+
+#include "token_bucket.h"
+#include "util_bug.h"
+
+/**
+ * Set the <b>rate</b> and <b>burst</b> value in a token_bucket_cfg.
+ *
+ * Note that the <b>rate</b> value is in arbitrary units, but those units will
+ * determine the units of token_bucket_raw_dec(), token_bucket_raw_refill, and
+ * so on.
+ */
+void
+token_bucket_cfg_init(token_bucket_cfg_t *cfg,
+ uint32_t rate,
+ uint32_t burst)
+{
+ tor_assert_nonfatal(rate > 0);
+ tor_assert_nonfatal(burst > 0);
+ if (burst > TOKEN_BUCKET_MAX_BURST)
+ burst = TOKEN_BUCKET_MAX_BURST;
+
+ cfg->rate = rate;
+ cfg->burst = burst;
+}
+
+/**
+ * Initialize a raw token bucket and its associated timestamp to the "full"
+ * state, according to <b>cfg</b>.
+ */
+void
+token_bucket_raw_reset(token_bucket_raw_t *bucket,
+ const token_bucket_cfg_t *cfg)
+{
+ bucket->bucket = cfg->burst;
+}
+
+/**
+ * Adust a preexisting token bucket to respect the new configuration
+ * <b>cfg</b>, by decreasing its current level if needed. */
+void
+token_bucket_raw_adjust(token_bucket_raw_t *bucket,
+ const token_bucket_cfg_t *cfg)
+{
+ bucket->bucket = MIN(bucket->bucket, cfg->burst);
+}
+
+/**
+ * Given an amount of <b>elapsed</b> time units, and a bucket configuration
+ * <b>cfg</b>, refill the level of <b>bucket</b> accordingly. Note that the
+ * units of time in <b>elapsed</b> must correspond to those used to set the
+ * rate in <b>cfg</b>, or the result will be illogical.
+ */
+int
+token_bucket_raw_refill_steps(token_bucket_raw_t *bucket,
+ const token_bucket_cfg_t *cfg,
+ const uint32_t elapsed)
+{
+ const int was_empty = (bucket->bucket <= 0);
+ /* The casts here prevent an underflow.
+ *
+ * Note that even if the bucket value is negative, subtracting it from
+ * "burst" will still produce a correct result. If this result is
+ * ridiculously high, then the "elapsed > gap / rate" check below
+ * should catch it. */
+ const size_t gap = ((size_t)cfg->burst) - ((size_t)bucket->bucket);
+
+ if (elapsed > gap / cfg->rate) {
+ bucket->bucket = cfg->burst;
+ } else {
+ bucket->bucket += cfg->rate * elapsed;
+ }
+
+ return was_empty && bucket->bucket > 0;
+}
+
+/**
+ * Decrement a provided bucket by <b>n</b> units. Note that <b>n</b>
+ * must be nonnegative.
+ */
+int
+token_bucket_raw_dec(token_bucket_raw_t *bucket,
+ ssize_t n)
+{
+ if (BUG(n < 0))
+ return 0;
+ const int becomes_empty = bucket->bucket > 0 && n >= bucket->bucket;
+ bucket->bucket -= n;
+ return becomes_empty;
+}
+
+/** Convert a rate in bytes per second to a rate in bytes per step */
+STATIC uint32_t
+rate_per_sec_to_rate_per_step(uint32_t rate)
+{
+ /*
+ The precise calculation we'd want to do is
+
+ (rate / 1000) * to_approximate_msec(TICKS_PER_STEP). But to minimize
+ rounding error, we do it this way instead, and divide last.
+ */
+ uint64_t units = (uint64_t) rate * TICKS_PER_STEP;
+ uint32_t val = (uint32_t)
+ (monotime_coarse_stamp_units_to_approx_msec(units) / 1000);
+ return val ? val : 1;
+}
+
+/**
+ * Initialize a token bucket in *<b>bucket</b>, set up to allow <b>rate</b>
+ * bytes per second, with a maximum burst of <b>burst</b> bytes. The bucket
+ * is created such that <b>now_ts</b> is the current timestamp. The bucket
+ * starts out full.
+ */
+void
+token_bucket_rw_init(token_bucket_rw_t *bucket,
+ uint32_t rate,
+ uint32_t burst,
+ uint32_t now_ts)
+{
+ memset(bucket, 0, sizeof(token_bucket_rw_t));
+ token_bucket_rw_adjust(bucket, rate, burst);
+ token_bucket_rw_reset(bucket, now_ts);
+}
+
+/**
+ * Change the configured rate (in bytes per second) and burst (in bytes)
+ * for the token bucket in *<b>bucket</b>.
+ */
+void
+token_bucket_rw_adjust(token_bucket_rw_t *bucket,
+ uint32_t rate,
+ uint32_t burst)
+{
+ token_bucket_cfg_init(&bucket->cfg,
+ rate_per_sec_to_rate_per_step(rate),
+ burst);
+ token_bucket_raw_adjust(&bucket->read_bucket, &bucket->cfg);
+ token_bucket_raw_adjust(&bucket->write_bucket, &bucket->cfg);
+}
+
+/**
+ * Reset <b>bucket</b> to be full, as of timestamp <b>now_ts</b>.
+ */
+void
+token_bucket_rw_reset(token_bucket_rw_t *bucket,
+ uint32_t now_ts)
+{
+ token_bucket_raw_reset(&bucket->read_bucket, &bucket->cfg);
+ token_bucket_raw_reset(&bucket->write_bucket, &bucket->cfg);
+ bucket->last_refilled_at_timestamp = now_ts;
+}
+
+/**
+ * Refill <b>bucket</b> as appropriate, given that the current timestamp
+ * is <b>now_ts</b>.
+ *
+ * Return a bitmask containing TB_READ iff read bucket was empty and became
+ * nonempty, and TB_WRITE iff the write bucket was empty and became nonempty.
+ */
+int
+token_bucket_rw_refill(token_bucket_rw_t *bucket,
+ uint32_t now_ts)
+{
+ const uint32_t elapsed_ticks =
+ (now_ts - bucket->last_refilled_at_timestamp);
+ if (elapsed_ticks > UINT32_MAX-(300*1000)) {
+ /* Either about 48 days have passed since the last refill, or the
+ * monotonic clock has somehow moved backwards. (We're looking at you,
+ * Windows.). We accept up to a 5 minute jump backwards as
+ * "unremarkable".
+ */
+ return 0;
+ }
+ const uint32_t elapsed_steps = elapsed_ticks / TICKS_PER_STEP;
+
+ if (!elapsed_steps) {
+ /* Note that if less than one whole step elapsed, we don't advance the
+ * time in last_refilled_at. That's intentional: we want to make sure
+ * that we add some bytes to it eventually. */
+ return 0;
+ }
+
+ int flags = 0;
+ if (token_bucket_raw_refill_steps(&bucket->read_bucket,
+ &bucket->cfg, elapsed_steps))
+ flags |= TB_READ;
+ if (token_bucket_raw_refill_steps(&bucket->write_bucket,
+ &bucket->cfg, elapsed_steps))
+ flags |= TB_WRITE;
+
+ bucket->last_refilled_at_timestamp = now_ts;
+ return flags;
+}
+
+/**
+ * Decrement the read token bucket in <b>bucket</b> by <b>n</b> bytes.
+ *
+ * Return true if the bucket was nonempty and became empty; return false
+ * otherwise.
+ */
+int
+token_bucket_rw_dec_read(token_bucket_rw_t *bucket,
+ ssize_t n)
+{
+ return token_bucket_raw_dec(&bucket->read_bucket, n);
+}
+
+/**
+ * Decrement the write token bucket in <b>bucket</b> by <b>n</b> bytes.
+ *
+ * Return true if the bucket was nonempty and became empty; return false
+ * otherwise.
+ */
+int
+token_bucket_rw_dec_write(token_bucket_rw_t *bucket,
+ ssize_t n)
+{
+ return token_bucket_raw_dec(&bucket->write_bucket, n);
+}
+
+/**
+ * As token_bucket_rw_dec_read and token_bucket_rw_dec_write, in a single
+ * operation.
+ */
+void
+token_bucket_rw_dec(token_bucket_rw_t *bucket,
+ ssize_t n_read, ssize_t n_written)
+{
+ token_bucket_rw_dec_read(bucket, n_read);
+ token_bucket_rw_dec_write(bucket, n_written);
+}
+
diff --git a/src/common/token_bucket.h b/src/common/token_bucket.h
new file mode 100644
index 0000000000..fb5d9fc60a
--- /dev/null
+++ b/src/common/token_bucket.h
@@ -0,0 +1,118 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file token_bucket_rw.h
+ * \brief Headers for token_bucket_rw.c
+ **/
+
+#ifndef TOR_TOKEN_BUCKET_H
+#define TOR_TOKEN_BUCKET_H
+
+#include "torint.h"
+#include "testsupport.h"
+
+/** Largest allowable burst value for a token buffer. */
+#define TOKEN_BUCKET_MAX_BURST INT32_MAX
+
+/** A generic token buffer configuration: determines the number of tokens
+ * added to the bucket in each time unit (the "rate"), and the maximum number
+ * of tokens in the bucket (the "burst") */
+typedef struct token_bucket_cfg_t {
+ uint32_t rate;
+ int32_t burst;
+} token_bucket_cfg_t;
+
+/** A raw token bucket, decoupled from its configuration and timestamp. */
+typedef struct token_bucket_raw_t {
+ int32_t bucket;
+} token_bucket_raw_t;
+
+void token_bucket_cfg_init(token_bucket_cfg_t *cfg,
+ uint32_t rate,
+ uint32_t burst);
+
+void token_bucket_raw_adjust(token_bucket_raw_t *bucket,
+ const token_bucket_cfg_t *cfg);
+
+void token_bucket_raw_reset(token_bucket_raw_t *bucket,
+ const token_bucket_cfg_t *cfg);
+
+int token_bucket_raw_dec(token_bucket_raw_t *bucket,
+ ssize_t n);
+
+int token_bucket_raw_refill_steps(token_bucket_raw_t *bucket,
+ const token_bucket_cfg_t *cfg,
+ const uint32_t elapsed_steps);
+
+static inline size_t token_bucket_raw_get(const token_bucket_raw_t *bucket);
+/** Return the current number of bytes set in a token bucket. */
+static inline size_t
+token_bucket_raw_get(const token_bucket_raw_t *bucket)
+{
+ return bucket->bucket >= 0 ? bucket->bucket : 0;
+}
+
+/** A convenience type containing all the pieces needed for a coupled
+ * read-bucket and write-bucket that have the same rate limit, and which use
+ * "timestamp units" (see compat_time.h) for their time. */
+typedef struct token_bucket_rw_t {
+ token_bucket_cfg_t cfg;
+ token_bucket_raw_t read_bucket;
+ token_bucket_raw_t write_bucket;
+ uint32_t last_refilled_at_timestamp;
+} token_bucket_rw_t;
+
+void token_bucket_rw_init(token_bucket_rw_t *bucket,
+ uint32_t rate,
+ uint32_t burst,
+ uint32_t now_ts);
+
+void token_bucket_rw_adjust(token_bucket_rw_t *bucket,
+ uint32_t rate, uint32_t burst);
+
+void token_bucket_rw_reset(token_bucket_rw_t *bucket,
+ uint32_t now_ts);
+
+#define TB_READ 1
+#define TB_WRITE 2
+
+int token_bucket_rw_refill(token_bucket_rw_t *bucket,
+ uint32_t now_ts);
+
+int token_bucket_rw_dec_read(token_bucket_rw_t *bucket,
+ ssize_t n);
+int token_bucket_rw_dec_write(token_bucket_rw_t *bucket,
+ ssize_t n);
+
+void token_bucket_rw_dec(token_bucket_rw_t *bucket,
+ ssize_t n_read, ssize_t n_written);
+
+static inline size_t token_bucket_rw_get_read(const token_bucket_rw_t *bucket);
+static inline size_t
+token_bucket_rw_get_read(const token_bucket_rw_t *bucket)
+{
+ return token_bucket_raw_get(&bucket->read_bucket);
+}
+
+static inline size_t token_bucket_rw_get_write(
+ const token_bucket_rw_t *bucket);
+static inline size_t
+token_bucket_rw_get_write(const token_bucket_rw_t *bucket)
+{
+ return token_bucket_raw_get(&bucket->write_bucket);
+}
+
+#ifdef TOKEN_BUCKET_PRIVATE
+
+/* To avoid making the rates too small, we consider units of "steps",
+ * where a "step" is defined as this many timestamp ticks. Keep this
+ * a power of two if you can. */
+#define TICKS_PER_STEP 16
+
+STATIC uint32_t rate_per_sec_to_rate_per_step(uint32_t rate);
+
+#endif
+
+#endif /* TOR_TOKEN_BUCKET_H */
+
diff --git a/src/common/torlog.h b/src/common/torlog.h
index cadfe3b879..ac632ff521 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -191,6 +191,10 @@ void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
const char *format, ...)
CHECK_PRINTF(5,6);
+int log_message_is_interesting(int severity, log_domain_mask_t domain);
+void tor_log_string(int severity, log_domain_mask_t domain,
+ const char *function, const char *string);
+
#if defined(__GNUC__) && __GNUC__ <= 3
/* These are the GCC varidaic macros, so that older versions of GCC don't
@@ -248,6 +252,16 @@ void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
args, ##__VA_ARGS__)
#endif /* defined(__GNUC__) && __GNUC__ <= 3 */
+/** This defines log levels that are linked in the Rust log module, rather
+ * than re-defining these in both Rust and C.
+ *
+ * C_RUST_COUPLED src/rust/tor_log LogSeverity, LogDomain
+ */
+extern const int LOG_WARN_;
+extern const int LOG_NOTICE_;
+extern const log_domain_mask_t LD_NET_;
+extern const log_domain_mask_t LD_GENERAL_;
+
#ifdef LOG_PRIVATE
MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain,
const char *funcname, const char *suffix, const char *format,
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 50609b8ac7..05e29e22ff 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -25,6 +25,7 @@
#include <ws2tcpip.h>
#endif
+#include "crypto.h"
#include "compat.h"
/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
@@ -32,7 +33,6 @@
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/opensslv.h>
-#include "crypto.h"
#ifdef OPENSSL_NO_EC
#error "We require OpenSSL with ECC support"
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 1dbf0b332f..7c867bfff2 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -11,7 +11,7 @@
* \brief Headers for tortls.c
**/
-#include "crypto.h"
+#include "crypto_rsa.h"
#include "compat_openssl.h"
#include "compat.h"
#include "testsupport.h"
diff --git a/src/common/util.c b/src/common/util.c
index a68fd30d09..041e7aee3d 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -16,7 +16,7 @@
#define UTIL_PRIVATE
#include "util.h"
#include "torlog.h"
-#include "crypto.h"
+#include "crypto_digest.h"
#include "torint.h"
#include "container.h"
#include "address.h"
@@ -5111,30 +5111,6 @@ stream_status_to_string(enum stream_status stream_status)
}
}
-/* DOCDOC */
-static void
-log_portfw_spawn_error_message(const char *buf,
- const char *executable, int *child_status)
-{
- /* Parse error message */
- int retval, child_state, saved_errno;
- retval = tor_sscanf(buf, SPAWN_ERROR_MESSAGE "%x/%x",
- &child_state, &saved_errno);
- if (retval == 2) {
- log_warn(LD_GENERAL,
- "Failed to start child process \"%s\" in state %d: %s",
- executable, child_state, strerror(saved_errno));
- if (child_status)
- *child_status = 1;
- } else {
- /* Failed to parse message from child process, log it as a
- warning */
- log_warn(LD_GENERAL,
- "Unexpected message from port forwarding helper \"%s\": %s",
- executable, buf);
- }
-}
-
#ifdef _WIN32
/** Return a smartlist containing lines outputted from
@@ -5180,51 +5156,6 @@ tor_get_lines_from_handle, (HANDLE *handle,
return lines;
}
-/** Read from stream, and send lines to log at the specified log level.
- * Returns -1 if there is a error reading, and 0 otherwise.
- * If the generated stream is flushed more often than on new lines, or
- * a read exceeds 256 bytes, lines will be truncated. This should be fixed,
- * along with the corresponding problem on *nix (see bug #2045).
- */
-static int
-log_from_handle(HANDLE *pipe, int severity)
-{
- char buf[256];
- int pos;
- smartlist_t *lines;
-
- pos = tor_read_all_handle(pipe, buf, sizeof(buf) - 1, NULL);
- if (pos < 0) {
- /* Error */
- log_warn(LD_GENERAL, "Failed to read data from subprocess");
- return -1;
- }
-
- if (0 == pos) {
- /* There's nothing to read (process is busy or has exited) */
- log_debug(LD_GENERAL, "Subprocess had nothing to say");
- return 0;
- }
-
- /* End with a null even if there isn't a \r\n at the end */
- /* TODO: What if this is a partial line? */
- buf[pos] = '\0';
- log_debug(LD_GENERAL, "Subprocess had %d bytes to say", pos);
-
- /* Split up the buffer */
- lines = smartlist_new();
- tor_split_lines(lines, buf, pos);
-
- /* Log each line */
- SMARTLIST_FOREACH(lines, char *, line,
- {
- log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", line);
- });
- smartlist_free(lines);
-
- return 0;
-}
-
#else /* !(defined(_WIN32)) */
/** Return a smartlist containing lines outputted from
@@ -5254,42 +5185,6 @@ tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out))
return lines;
}
-/** Read from fd, and send lines to log at the specified log level.
- * Returns 1 if stream is closed normally, -1 if there is a error reading, and
- * 0 otherwise. Handles lines from tor-fw-helper and
- * tor_spawn_background() specially.
- */
-static int
-log_from_pipe(int fd, int severity, const char *executable,
- int *child_status)
-{
- char buf[256];
- enum stream_status r;
-
- for (;;) {
- r = get_string_from_pipe(fd, buf, sizeof(buf) - 1);
-
- if (r == IO_STREAM_CLOSED) {
- return 1;
- } else if (r == IO_STREAM_EAGAIN) {
- return 0;
- } else if (r == IO_STREAM_TERM) {
- return -1;
- }
-
- tor_assert(r == IO_STREAM_OKAY);
-
- /* Check if buf starts with SPAWN_ERROR_MESSAGE */
- if (strcmpstart(buf, SPAWN_ERROR_MESSAGE) == 0) {
- log_portfw_spawn_error_message(buf, executable, child_status);
- } else {
- log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", buf);
- }
- }
-
- /* We should never get here */
- return -1;
-}
#endif /* defined(_WIN32) */
/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making
@@ -5332,294 +5227,6 @@ get_string_from_pipe(int fd, char *buf_out, size_t count)
return IO_STREAM_OKAY;
}
-/** Parse a <b>line</b> from tor-fw-helper and issue an appropriate
- * log message to our user. */
-static void
-handle_fw_helper_line(const char *executable, const char *line)
-{
- smartlist_t *tokens = smartlist_new();
- char *message = NULL;
- char *message_for_log = NULL;
- const char *external_port = NULL;
- const char *internal_port = NULL;
- const char *result = NULL;
- int port = 0;
- int success = 0;
-
- if (strcmpstart(line, SPAWN_ERROR_MESSAGE) == 0) {
- /* We need to check for SPAWN_ERROR_MESSAGE again here, since it's
- * possible that it got sent after we tried to read it in log_from_pipe.
- *
- * XXX Ideally, we should be using one of stdout/stderr for the real
- * output, and one for the output of the startup code. We used to do that
- * before cd05f35d2c.
- */
- int child_status;
- log_portfw_spawn_error_message(line, executable, &child_status);
- goto done;
- }
-
- smartlist_split_string(tokens, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
-
- if (smartlist_len(tokens) < 5)
- goto err;
-
- if (strcmp(smartlist_get(tokens, 0), "tor-fw-helper") ||
- strcmp(smartlist_get(tokens, 1), "tcp-forward"))
- goto err;
-
- external_port = smartlist_get(tokens, 2);
- internal_port = smartlist_get(tokens, 3);
- result = smartlist_get(tokens, 4);
-
- if (smartlist_len(tokens) > 5) {
- /* If there are more than 5 tokens, they are part of [<message>].
- Let's use a second smartlist to form the whole message;
- strncat loops suck. */
- int i;
- int message_words_n = smartlist_len(tokens) - 5;
- smartlist_t *message_sl = smartlist_new();
- for (i = 0; i < message_words_n; i++)
- smartlist_add(message_sl, smartlist_get(tokens, 5+i));
-
- tor_assert(smartlist_len(message_sl) > 0);
- message = smartlist_join_strings(message_sl, " ", 0, NULL);
-
- /* wrap the message in log-friendly wrapping */
- tor_asprintf(&message_for_log, " ('%s')", message);
-
- smartlist_free(message_sl);
- }
-
- port = atoi(external_port);
- if (port < 1 || port > 65535)
- goto err;
-
- port = atoi(internal_port);
- if (port < 1 || port > 65535)
- goto err;
-
- if (!strcmp(result, "SUCCESS"))
- success = 1;
- else if (!strcmp(result, "FAIL"))
- success = 0;
- else
- goto err;
-
- if (!success) {
- log_warn(LD_GENERAL, "Tor was unable to forward TCP port '%s' to '%s'%s. "
- "Please make sure that your router supports port "
- "forwarding protocols (like NAT-PMP). Note that if '%s' is "
- "your ORPort, your relay will be unable to receive inbound "
- "traffic.", external_port, internal_port,
- message_for_log ? message_for_log : "",
- internal_port);
- } else {
- log_info(LD_GENERAL,
- "Tor successfully forwarded TCP port '%s' to '%s'%s.",
- external_port, internal_port,
- message_for_log ? message_for_log : "");
- }
-
- goto done;
-
- err:
- log_warn(LD_GENERAL, "tor-fw-helper sent us a string we could not "
- "parse (%s).", line);
-
- done:
- SMARTLIST_FOREACH(tokens, char *, cp, tor_free(cp));
- smartlist_free(tokens);
- tor_free(message);
- tor_free(message_for_log);
-}
-
-/** Read what tor-fw-helper has to say in its stdout and handle it
- * appropriately */
-static int
-handle_fw_helper_output(const char *executable,
- process_handle_t *process_handle)
-{
- smartlist_t *fw_helper_output = NULL;
- enum stream_status stream_status = 0;
-
- fw_helper_output =
- tor_get_lines_from_handle(tor_process_get_stdout_pipe(process_handle),
- &stream_status);
- if (!fw_helper_output) { /* didn't get any output from tor-fw-helper */
- /* if EAGAIN we should retry in the future */
- return (stream_status == IO_STREAM_EAGAIN) ? 0 : -1;
- }
-
- /* Handle the lines we got: */
- SMARTLIST_FOREACH_BEGIN(fw_helper_output, char *, line) {
- handle_fw_helper_line(executable, line);
- tor_free(line);
- } SMARTLIST_FOREACH_END(line);
-
- smartlist_free(fw_helper_output);
-
- return 0;
-}
-
-/** Spawn tor-fw-helper and ask it to forward the ports in
- * <b>ports_to_forward</b>. <b>ports_to_forward</b> contains strings
- * of the form "<external port>:<internal port>", which is the format
- * that tor-fw-helper expects. */
-void
-tor_check_port_forwarding(const char *filename,
- smartlist_t *ports_to_forward,
- time_t now)
-{
-/* When fw-helper succeeds, how long do we wait until running it again */
-#define TIME_TO_EXEC_FWHELPER_SUCCESS 300
-/* When fw-helper failed to start, how long do we wait until running it again
- */
-#define TIME_TO_EXEC_FWHELPER_FAIL 60
-
- /* Static variables are initialized to zero, so child_handle.status=0
- * which corresponds to it not running on startup */
- static process_handle_t *child_handle=NULL;
-
- static time_t time_to_run_helper = 0;
- int stderr_status, retval;
- int stdout_status = 0;
-
- tor_assert(filename);
-
- /* Start the child, if it is not already running */
- if ((!child_handle || child_handle->status != PROCESS_STATUS_RUNNING) &&
- time_to_run_helper < now) {
- /*tor-fw-helper cli looks like this: tor_fw_helper -p :5555 -p 4555:1111 */
- const char **argv; /* cli arguments */
- int args_n, status;
- int argv_index = 0; /* index inside 'argv' */
-
- tor_assert(smartlist_len(ports_to_forward) > 0);
-
- /* check for overflow during 'argv' allocation:
- (len(ports_to_forward)*2 + 2)*sizeof(char*) > SIZE_MAX ==
- len(ports_to_forward) > (((SIZE_MAX/sizeof(char*)) - 2)/2) */
- if ((size_t) smartlist_len(ports_to_forward) >
- (((SIZE_MAX/sizeof(char*)) - 2)/2)) {
- log_warn(LD_GENERAL,
- "Overflow during argv allocation. This shouldn't happen.");
- return;
- }
- /* check for overflow during 'argv_index' increase:
- ((len(ports_to_forward)*2 + 2) > INT_MAX) ==
- len(ports_to_forward) > (INT_MAX - 2)/2 */
- if (smartlist_len(ports_to_forward) > (INT_MAX - 2)/2) {
- log_warn(LD_GENERAL,
- "Overflow during argv_index increase. This shouldn't happen.");
- return;
- }
-
- /* Calculate number of cli arguments: one for the filename, two
- for each smartlist element (one for "-p" and one for the
- ports), and one for the final NULL. */
- args_n = 1 + 2*smartlist_len(ports_to_forward) + 1;
- argv = tor_calloc(args_n, sizeof(char *));
-
- argv[argv_index++] = filename;
- SMARTLIST_FOREACH_BEGIN(ports_to_forward, const char *, port) {
- argv[argv_index++] = "-p";
- argv[argv_index++] = port;
- } SMARTLIST_FOREACH_END(port);
- argv[argv_index] = NULL;
-
- /* Assume tor-fw-helper will succeed, start it later*/
- time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_SUCCESS;
-
- if (child_handle) {
- tor_process_handle_destroy(child_handle, 1);
- child_handle = NULL;
- }
-
-#ifdef _WIN32
- /* Passing NULL as lpApplicationName makes Windows search for the .exe */
- status = tor_spawn_background(NULL, argv, NULL, &child_handle);
-#else
- status = tor_spawn_background(filename, argv, NULL, &child_handle);
-#endif /* defined(_WIN32) */
-
- tor_free_((void*)argv);
- argv=NULL;
-
- if (PROCESS_STATUS_ERROR == status) {
- log_warn(LD_GENERAL, "Failed to start port forwarding helper %s",
- filename);
- time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
- return;
- }
-
- log_info(LD_GENERAL,
- "Started port forwarding helper (%s) with pid '%d'",
- filename, tor_process_get_pid(child_handle));
- }
-
- /* If child is running, read from its stdout and stderr) */
- if (child_handle && PROCESS_STATUS_RUNNING == child_handle->status) {
- /* Read from stdout/stderr and log result */
- retval = 0;
-#ifdef _WIN32
- stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO);
-#else
- stderr_status = log_from_pipe(child_handle->stderr_pipe,
- LOG_INFO, filename, &retval);
-#endif /* defined(_WIN32) */
- if (handle_fw_helper_output(filename, child_handle) < 0) {
- log_warn(LD_GENERAL, "Failed to handle fw helper output.");
- stdout_status = -1;
- retval = -1;
- }
-
- if (retval) {
- /* There was a problem in the child process */
- time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
- }
-
- /* Combine the two statuses in order of severity */
- if (-1 == stdout_status || -1 == stderr_status)
- /* There was a failure */
- retval = -1;
-#ifdef _WIN32
- else if (!child_handle || tor_get_exit_code(child_handle, 0, NULL) !=
- PROCESS_EXIT_RUNNING) {
- /* process has exited or there was an error */
- /* TODO: Do something with the process return value */
- /* TODO: What if the process output something since
- * between log_from_handle and tor_get_exit_code? */
- retval = 1;
- }
-#else /* !(defined(_WIN32)) */
- else if (1 == stdout_status || 1 == stderr_status)
- /* stdout or stderr was closed, the process probably
- * exited. It will be reaped by waitpid() in main.c */
- /* TODO: Do something with the process return value */
- retval = 1;
-#endif /* defined(_WIN32) */
- else
- /* Both are fine */
- retval = 0;
-
- /* If either pipe indicates a failure, act on it */
- if (0 != retval) {
- if (1 == retval) {
- log_info(LD_GENERAL, "Port forwarding helper terminated");
- child_handle->status = PROCESS_STATUS_NOTRUNNING;
- } else {
- log_warn(LD_GENERAL, "Failed to read from port forwarding helper");
- child_handle->status = PROCESS_STATUS_ERROR;
- }
-
- /* TODO: The child might not actually be finished (maybe it failed or
- closed stdout/stderr), so maybe we shouldn't start another? */
- }
- }
-}
-
/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */
void
tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed)
diff --git a/src/common/util.h b/src/common/util.h
index 9380789128..ae27e5f016 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -73,9 +73,9 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
} \
STMT_END
#else /* !(defined(USE_DMALLOC)) */
-/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup, etc.
- * Unlike the free() function, tor_free() will still work on NULL pointers,
- * and it sets the pointer value to NULL after freeing it.
+/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup,
+ * etc. Unlike the free() function, the tor_free() macro sets the
+ * pointer value to NULL after freeing it.
*
* This is a macro. If you need a function pointer to release memory from
* tor_malloc(), use tor_free_().
@@ -88,17 +88,13 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
#ifdef __GNUC__
#define tor_free(p) STMT_BEGIN \
typeof(&(p)) tor_free__tmpvar = &(p); \
- if (PREDICT_LIKELY((*tor_free__tmpvar)!=NULL)) { \
- raw_free(*tor_free__tmpvar); \
- *tor_free__tmpvar=NULL; \
- } \
+ raw_free(*tor_free__tmpvar); \
+ *tor_free__tmpvar=NULL; \
STMT_END
#else
#define tor_free(p) STMT_BEGIN \
- if (PREDICT_LIKELY((p)!=NULL)) { \
- raw_free(p); \
- (p)=NULL; \
- } \
+ raw_free(p); \
+ (p)=NULL; \
STMT_END
#endif
#endif /* defined(USE_DMALLOC) */
@@ -418,11 +414,6 @@ void start_daemon(void);
void finish_daemon(const char *desired_cwd);
int write_pidfile(const char *filename);
-/* Port forwarding */
-void tor_check_port_forwarding(const char *filename,
- struct smartlist_t *ports_to_forward,
- time_t now);
-
void tor_disable_spawning_background_processes(void);
typedef struct process_handle_t process_handle_t;
@@ -461,9 +452,7 @@ void set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
void (*free_old)(void*),
int free_p);
-/* Values of process_handle_t.status. PROCESS_STATUS_NOTRUNNING must be
- * 0 because tor_check_port_forwarding depends on this being the initial
- * statue of the static instance of process_handle_t */
+/* Values of process_handle_t.status. */
#define PROCESS_STATUS_NOTRUNNING 0
#define PROCESS_STATUS_RUNNING 1
#define PROCESS_STATUS_ERROR -1
diff --git a/src/common/workqueue.c b/src/common/workqueue.c
index ec96959b7d..12e31414e7 100644
--- a/src/common/workqueue.c
+++ b/src/common/workqueue.c
@@ -1,3 +1,4 @@
+
/* copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
@@ -24,6 +25,7 @@
#include "orconfig.h"
#include "compat.h"
+#include "compat_libevent.h"
#include "compat_threads.h"
#include "crypto.h"
#include "util.h"
@@ -31,6 +33,8 @@
#include "tor_queue.h"
#include "torlog.h"
+#include <event2/event.h>
+
#define WORKQUEUE_PRIORITY_FIRST WQ_PRI_HIGH
#define WORKQUEUE_PRIORITY_LAST WQ_PRI_LOW
#define WORKQUEUE_N_PRIORITIES (((int) WORKQUEUE_PRIORITY_LAST)+1)
@@ -63,6 +67,9 @@ struct threadpool_s {
void (*free_update_arg_fn)(void *);
/** Array of n_threads update arguments. */
void **update_args;
+ /** Event to notice when another thread has sent a reply. */
+ struct event *reply_event;
+ void (*reply_cb)(threadpool_t *);
/** Number of elements in threads. */
int n_threads;
@@ -597,15 +604,41 @@ replyqueue_new(uint32_t alertsocks_flags)
return rq;
}
-/**
- * Return the "read socket" for a given reply queue. The main thread should
- * listen for read events on this socket, and call replyqueue_process() every
- * time it triggers.
+/** Internal: Run from the libevent mainloop when there is work to handle in
+ * the reply queue handler. */
+static void
+reply_event_cb(evutil_socket_t sock, short events, void *arg)
+{
+ threadpool_t *tp = arg;
+ (void) sock;
+ (void) events;
+ replyqueue_process(tp->reply_queue);
+ if (tp->reply_cb)
+ tp->reply_cb(tp);
+}
+
+/** Register the threadpool <b>tp</b>'s reply queue with the libevent
+ * mainloop of <b>base</b>. If <b>tp</b> is provided, it is run after
+ * each time there is work to process from the reply queue. Return 0 on
+ * success, -1 on failure.
*/
-tor_socket_t
-replyqueue_get_socket(replyqueue_t *rq)
+int
+threadpool_register_reply_event(threadpool_t *tp,
+ void (*cb)(threadpool_t *tp))
{
- return rq->alert.read_fd;
+ struct event_base *base = tor_libevent_get_base();
+
+ if (tp->reply_event) {
+ tor_event_free(tp->reply_event);
+ }
+ tp->reply_event = tor_event_new(base,
+ tp->reply_queue->alert.read_fd,
+ EV_READ|EV_PERSIST,
+ reply_event_cb,
+ tp);
+ tor_assert(tp->reply_event);
+ tp->reply_cb = cb;
+ return event_add(tp->reply_event, NULL);
}
/**
diff --git a/src/common/workqueue.h b/src/common/workqueue.h
index eb885e680d..e1fe612e2b 100644
--- a/src/common/workqueue.h
+++ b/src/common/workqueue.h
@@ -56,8 +56,11 @@ threadpool_t *threadpool_new(int n_threads,
replyqueue_t *threadpool_get_replyqueue(threadpool_t *tp);
replyqueue_t *replyqueue_new(uint32_t alertsocks_flags);
-tor_socket_t replyqueue_get_socket(replyqueue_t *rq);
void replyqueue_process(replyqueue_t *queue);
+struct event_base;
+int threadpool_register_reply_event(threadpool_t *tp,
+ void (*cb)(threadpool_t *tp));
+
#endif /* !defined(TOR_WORKQUEUE_H) */
diff --git a/src/ext/ed25519/donna/ed25519-hash-custom.h b/src/ext/ed25519/donna/ed25519-hash-custom.h
index 609451abd5..cdeab3e45b 100644
--- a/src/ext/ed25519/donna/ed25519-hash-custom.h
+++ b/src/ext/ed25519/donna/ed25519-hash-custom.h
@@ -9,7 +9,7 @@
void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
*/
-#include "crypto.h"
+#include "crypto_digest.h"
typedef struct ed25519_hash_context {
crypto_digest_t *ctx;
diff --git a/src/ext/ed25519/ref10/crypto_hash_sha512.h b/src/ext/ed25519/ref10/crypto_hash_sha512.h
index 5dad935c79..7faddb1597 100644
--- a/src/ext/ed25519/ref10/crypto_hash_sha512.h
+++ b/src/ext/ed25519/ref10/crypto_hash_sha512.h
@@ -1,5 +1,5 @@
/* Added for Tor. */
-#include "crypto.h"
+#include "crypto_digest.h"
/* Set 'out' to the 512-bit SHA512 hash of the 'len'-byte string in 'inp' */
#define crypto_hash_sha512(out, inp, len) \
diff --git a/src/ext/timeouts/timeout.c b/src/ext/timeouts/timeout.c
index 713ec219ce..d4b514d2c5 100644
--- a/src/ext/timeouts/timeout.c
+++ b/src/ext/timeouts/timeout.c
@@ -150,7 +150,7 @@
#else
#define ctz(n) ctz32(n)
#define clz(n) clz32(n)
-#define fls(n) ((int)(32 - clz32(n)))
+#define fls(n) ((int)(32 - clz32((uint32_t)n)))
#endif
#if WHEEL_BIT == 6
@@ -432,7 +432,7 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
* or can be replaced with a simpler operation.
*/
oslot = WHEEL_MASK & (T->curtime >> (wheel * WHEEL_BIT));
- pending = rotl(((UINT64_C(1) << _elapsed) - 1), oslot);
+ pending = rotl(((WHEEL_C(1) << _elapsed) - 1), oslot);
nslot = WHEEL_MASK & (curtime >> (wheel * WHEEL_BIT));
pending |= rotr(rotl(((WHEEL_C(1) << _elapsed) - 1), nslot), (int)_elapsed);
diff --git a/src/or/bridges.c b/src/or/bridges.c
index 29d00f37ba..699e030e6c 100644
--- a/src/or/bridges.c
+++ b/src/or/bridges.c
@@ -11,6 +11,8 @@
* Bridges are fixed entry nodes, used for censorship circumvention.
**/
+#define TOR_BRIDGES_PRIVATE
+
#include "or.h"
#include "bridges.h"
#include "circuitbuild.h"
@@ -93,7 +95,7 @@ sweep_bridge_list(void)
}
/** Initialize the bridge list to empty, creating it if needed. */
-static void
+STATIC void
clear_bridge_list(void)
{
if (!bridge_list)
@@ -156,7 +158,7 @@ bridge_get_addr_port(const bridge_info_t *bridge)
* bridge with no known digest whose address matches any of the
* tor_addr_port_t's in <b>orports</b>, return that bridge. Else return
* NULL. */
-static bridge_info_t *
+STATIC bridge_info_t *
get_configured_bridge_by_orports_digest(const char *digest,
const smartlist_t *orports)
{
@@ -350,7 +352,7 @@ bridge_has_digest(const bridge_info_t *bridge, const char *digest)
* existing bridge with the same address and port, and warn the user as
* appropriate.
*/
-static void
+STATIC void
bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
const char *digest, const char *transport_name)
{
@@ -471,7 +473,7 @@ bridge_add_from_config(bridge_line_t *bridge_line)
}
/** If <b>digest</b> is one of our known bridges, return it. */
-bridge_info_t *
+STATIC bridge_info_t *
find_bridge_by_digest(const char *digest)
{
if (! bridge_list)
diff --git a/src/or/bridges.h b/src/or/bridges.h
index 54a6250259..3108eb555d 100644
--- a/src/or/bridges.h
+++ b/src/or/bridges.h
@@ -20,7 +20,6 @@ typedef struct bridge_info_t bridge_info_t;
void mark_bridge_list(void);
void sweep_bridge_list(void);
const smartlist_t *bridge_list_get(void);
-bridge_info_t *find_bridge_by_digest(const char *digest);
const uint8_t *bridge_get_rsa_id_digest(const bridge_info_t *bridge);
const tor_addr_port_t * bridge_get_addr_port(const bridge_info_t *bridge);
bridge_info_t *get_configured_bridge_by_addr_port_digest(
@@ -65,5 +64,17 @@ MOCK_DECL(download_status_t *, get_bridge_dl_status_by_id,
void bridges_free_all(void);
+#ifdef TOR_BRIDGES_PRIVATE
+STATIC void clear_bridge_list(void);
+STATIC bridge_info_t *find_bridge_by_digest(const char *digest);
+STATIC bridge_info_t *get_configured_bridge_by_orports_digest(
+ const char *digest,
+ const smartlist_t *orports);
+STATIC void bridge_resolve_conflicts(const tor_addr_t *addr,
+ uint16_t port,
+ const char *digest,
+ const char *transport_name);
+#endif /* defined(TOR_BRIDGES_PRIVATE) */
+
#endif /* !defined(TOR_BRIDGES_H) */
diff --git a/src/or/channel.c b/src/or/channel.c
index a4740dd752..68245db497 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -2109,21 +2109,6 @@ channel_listener_dumpstats(int severity)
}
/**
- * Set the cmux policy on all active channels.
- */
-void
-channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol)
-{
- if (!active_channels) return;
-
- SMARTLIST_FOREACH_BEGIN(active_channels, channel_t *, curr) {
- if (curr->cmux) {
- circuitmux_set_policy(curr->cmux, pol);
- }
- } SMARTLIST_FOREACH_END(curr);
-}
-
-/**
* Clean up channels.
*
* This gets called periodically from run_scheduled_events() in main.c;
@@ -2402,7 +2387,7 @@ channel_get_for_extend(const char *rsa_id_digest,
{
channel_t *chan, *best = NULL;
int n_inprogress_goodaddr = 0, n_old = 0;
- int n_noncanonical = 0, n_possible = 0;
+ int n_noncanonical = 0;
tor_assert(msg_out);
tor_assert(launch_out);
@@ -2465,8 +2450,6 @@ channel_get_for_extend(const char *rsa_id_digest,
continue;
}
- ++n_possible;
-
if (!best) {
best = chan; /* If we have no 'best' so far, this one is good enough. */
continue;
diff --git a/src/or/channel.h b/src/or/channel.h
index 0af5aed414..6cf8cd7f72 100644
--- a/src/or/channel.h
+++ b/src/or/channel.h
@@ -422,9 +422,6 @@ void channel_free_all(void);
void channel_dumpstats(int severity);
void channel_listener_dumpstats(int severity);
-/* Set the cmux policy on all active channels */
-void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol);
-
#ifdef TOR_CHANNEL_INTERNAL_
#ifdef CHANNEL_PRIVATE_
diff --git a/src/or/channelpadding.c b/src/or/channelpadding.c
index 5da3009e67..33b1cba355 100644
--- a/src/or/channelpadding.c
+++ b/src/or/channelpadding.c
@@ -20,7 +20,6 @@
#include "rephist.h"
#include "router.h"
#include "compat_time.h"
-#include <event2/event.h>
#include "rendservice.h"
STATIC int32_t channelpadding_get_netflow_inactive_timeout_ms(
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index 9000703b01..54d94f6109 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -160,9 +160,8 @@ channel_tls_common_init(channel_tls_t *tlschan)
chan->write_var_cell = channel_tls_write_var_cell_method;
chan->cmux = circuitmux_alloc();
- if (cell_ewma_enabled()) {
- circuitmux_set_policy(chan->cmux, &ewma_policy);
- }
+ /* We only have one policy for now so always set it to EWMA. */
+ circuitmux_set_policy(chan->cmux, &ewma_policy);
}
/**
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 06aff06200..c33dbbeb2d 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -56,6 +56,7 @@
#include "onion_fast.h"
#include "policies.h"
#include "relay.h"
+#include "relay_crypto.h"
#include "rendcommon.h"
#include "rephist.h"
#include "router.h"
@@ -1055,7 +1056,7 @@ circuit_build_no_more_hops(origin_circuit_t *circ)
clear_broken_connection_map(1);
if (server_mode(options) && !check_whether_orport_reachable(options)) {
inform_testing_reachability();
- consider_testing_reachability(1, 1);
+ router_do_reachability_checks(1, 1);
}
}
@@ -1336,69 +1337,10 @@ circuit_init_cpath_crypto(crypt_path_t *cpath,
const char *key_data, size_t key_data_len,
int reverse, int is_hs_v3)
{
- crypto_digest_t *tmp_digest;
- crypto_cipher_t *tmp_crypto;
- size_t digest_len = 0;
- size_t cipher_key_len = 0;
tor_assert(cpath);
- tor_assert(key_data);
- tor_assert(!(cpath->f_crypto || cpath->b_crypto ||
- cpath->f_digest || cpath->b_digest));
-
- /* Basic key size validation */
- if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
- return -1;
- } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) {
- return -1;
- }
-
- /* If we are using this cpath for next gen onion services use SHA3-256,
- otherwise use good ol' SHA1 */
- if (is_hs_v3) {
- digest_len = DIGEST256_LEN;
- cipher_key_len = CIPHER256_KEY_LEN;
- cpath->f_digest = crypto_digest256_new(DIGEST_SHA3_256);
- cpath->b_digest = crypto_digest256_new(DIGEST_SHA3_256);
- } else {
- digest_len = DIGEST_LEN;
- cipher_key_len = CIPHER_KEY_LEN;
- cpath->f_digest = crypto_digest_new();
- cpath->b_digest = crypto_digest_new();
- }
-
- tor_assert(digest_len != 0);
- tor_assert(cipher_key_len != 0);
- const int cipher_key_bits = (int) cipher_key_len * 8;
-
- crypto_digest_add_bytes(cpath->f_digest, key_data, digest_len);
- crypto_digest_add_bytes(cpath->b_digest, key_data+digest_len, digest_len);
-
- cpath->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len),
- cipher_key_bits);
- if (!cpath->f_crypto) {
- log_warn(LD_BUG,"Forward cipher initialization failed.");
- return -1;
- }
-
- cpath->b_crypto = crypto_cipher_new_with_bits(
- key_data+(2*digest_len)+cipher_key_len,
- cipher_key_bits);
- if (!cpath->b_crypto) {
- log_warn(LD_BUG,"Backward cipher initialization failed.");
- return -1;
- }
-
- if (reverse) {
- tmp_digest = cpath->f_digest;
- cpath->f_digest = cpath->b_digest;
- cpath->b_digest = tmp_digest;
- tmp_crypto = cpath->f_crypto;
- cpath->f_crypto = cpath->b_crypto;
- cpath->b_crypto = tmp_crypto;
- }
-
- return 0;
+ return relay_crypto_init(&cpath->crypto, key_data, key_data_len, reverse,
+ is_hs_v3);
}
/** A "created" cell <b>reply</b> came back to us on circuit <b>circ</b>.
@@ -1521,7 +1463,6 @@ onionskin_answer(or_circuit_t *circ,
const uint8_t *rend_circ_nonce)
{
cell_t cell;
- crypt_path_t *tmp_cpath;
tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
@@ -1532,25 +1473,15 @@ onionskin_answer(or_circuit_t *circ,
}
cell.circ_id = circ->p_circ_id;
- tmp_cpath = tor_malloc_zero(sizeof(crypt_path_t));
- tmp_cpath->magic = CRYPT_PATH_MAGIC;
-
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
(unsigned int)get_uint32(keys),
(unsigned int)get_uint32(keys+20));
- if (circuit_init_cpath_crypto(tmp_cpath, keys, keys_len, 0, 0)<0) {
+ if (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) {
log_warn(LD_BUG,"Circuit initialization failed");
- tor_free(tmp_cpath);
return -1;
}
- circ->n_digest = tmp_cpath->f_digest;
- circ->n_crypto = tmp_cpath->f_crypto;
- circ->p_digest = tmp_cpath->b_digest;
- circ->p_crypto = tmp_cpath->b_crypto;
- tmp_cpath->magic = 0;
- tor_free(tmp_cpath);
memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
@@ -1611,7 +1542,7 @@ onionskin_answer(or_circuit_t *circ,
* rend_service_launch_establish_intro())
*
* - We are a router testing its own reachabiity
- * (CIRCUIT_PURPOSE_TESTING, via consider_testing_reachability())
+ * (CIRCUIT_PURPOSE_TESTING, via router_do_reachability_checks())
*
* onion_pick_cpath_exit() bypasses us (by not calling
* new_route_len()) in the one-hop tunnel case, so we don't need to
@@ -2877,8 +2808,10 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
valid_addr = fascist_firewall_choose_address_node(node,
FIREWALL_OR_CONNECTION,
0, &ap);
- else
- valid_addr = !node_get_prim_orport(node, &ap);
+ else {
+ node_get_prim_orport(node, &ap);
+ valid_addr = tor_addr_port_is_valid_ap(&ap, 0);
+ }
if (valid_addr)
log_debug(LD_CIRC, "using %s for %s",
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 7bdef0b878..9a82713cbe 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -76,6 +76,7 @@
#include "onion_fast.h"
#include "policies.h"
#include "relay.h"
+#include "relay_crypto.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rephist.h"
@@ -406,9 +407,6 @@ circuit_set_p_circid_chan(or_circuit_t *or_circ, circid_t id,
circuit_set_circid_chan_helper(circ, CELL_DIRECTION_IN, id, chan);
if (chan) {
- tor_assert(bool_eq(or_circ->p_chan_cells.n,
- or_circ->next_active_on_p_chan));
-
chan->timestamp_last_had_circuits = approx_time();
}
@@ -431,8 +429,6 @@ circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan);
if (chan) {
- tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan));
-
chan->timestamp_last_had_circuits = approx_time();
}
@@ -1087,10 +1083,7 @@ circuit_free_(circuit_t *circ)
should_free = (ocirc->workqueue_entry == NULL);
- crypto_cipher_free(ocirc->p_crypto);
- crypto_digest_free(ocirc->p_digest);
- crypto_cipher_free(ocirc->n_crypto);
- crypto_digest_free(ocirc->n_digest);
+ relay_crypto_clear(&ocirc->crypto);
if (ocirc->rend_splice) {
or_circuit_t *other = ocirc->rend_splice;
@@ -1230,10 +1223,7 @@ circuit_free_cpath_node(crypt_path_t *victim)
if (!victim)
return;
- crypto_cipher_free(victim->f_crypto);
- crypto_cipher_free(victim->b_crypto);
- crypto_digest_free(victim->f_digest);
- crypto_digest_free(victim->b_digest);
+ relay_crypto_clear(&victim->crypto);
onion_handshake_state_release(&victim->handshake_state);
crypto_dh_free(victim->rend_dh_handshake_state);
extend_info_free(victim->extend_info);
@@ -2596,8 +2586,7 @@ assert_cpath_layer_ok(const crypt_path_t *cp)
switch (cp->state)
{
case CPATH_STATE_OPEN:
- tor_assert(cp->f_crypto);
- tor_assert(cp->b_crypto);
+ relay_crypto_assert_ok(&cp->crypto);
/* fall through */
case CPATH_STATE_CLOSED:
/*XXXX Assert that there's no handshake_state either. */
@@ -2687,10 +2676,7 @@ assert_circuit_ok,(const circuit_t *c))
c->state == CIRCUIT_STATE_GUARD_WAIT) {
tor_assert(!c->n_chan_create_cell);
if (or_circ) {
- tor_assert(or_circ->n_crypto);
- tor_assert(or_circ->p_crypto);
- tor_assert(or_circ->n_digest);
- tor_assert(or_circ->p_digest);
+ relay_crypto_assert_ok(&or_circ->crypto);
}
}
if (c->state == CIRCUIT_STATE_CHAN_WAIT && !c->marked_for_close) {
diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c
index fe3d8f1332..f9f5faa057 100644
--- a/src/or/circuitmux.c
+++ b/src/or/circuitmux.c
@@ -114,13 +114,6 @@ struct circuitmux_s {
*/
chanid_circid_muxinfo_map_t *chanid_circid_map;
- /*
- * Double-linked ring of circuits with queued cells waiting for room to
- * free up on this connection's outbuf. Every time we pull cells from
- * a circuit, we advance this pointer to the next circuit in the ring.
- */
- struct circuit_t *active_circuits_head, *active_circuits_tail;
-
/** List of queued destroy cells */
destroy_cell_queue_t destroy_cell_queue;
/** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
@@ -177,17 +170,6 @@ struct chanid_circid_muxinfo_t {
};
/*
- * Internal-use #defines
- */
-
-#ifdef CMUX_PARANOIA
-#define circuitmux_assert_okay_paranoid(cmux) \
- circuitmux_assert_okay(cmux)
-#else
-#define circuitmux_assert_okay_paranoid(cmux)
-#endif /* defined(CMUX_PARANOIA) */
-
-/*
* Static function declarations
*/
@@ -199,21 +181,9 @@ chanid_circid_entry_hash(chanid_circid_muxinfo_t *a);
static chanid_circid_muxinfo_t *
circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
static void
-circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction);
+circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ);
static void
-circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction);
-static inline void
-circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction);
-static inline circuit_t **
-circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
-static inline circuit_t **
-circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
-static void circuitmux_assert_okay_pass_one(circuitmux_t *cmux);
-static void circuitmux_assert_okay_pass_two(circuitmux_t *cmux);
-static void circuitmux_assert_okay_pass_three(circuitmux_t *cmux);
+circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ);
/* Static global variables */
@@ -223,119 +193,6 @@ static int64_t global_destroy_ctr = 0;
/* Function definitions */
/**
- * Linked list helpers
- */
-
-/**
- * Move an active circuit to the tail of the cmux's active circuits list;
- * used by circuitmux_notify_xmit_cells().
- */
-
-static inline void
-circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction)
-{
- circuit_t **next_p = NULL, **prev_p = NULL;
- circuit_t **next_prev = NULL, **prev_next = NULL;
- circuit_t **tail_next = NULL;
- or_circuit_t *or_circ = NULL;
-
- tor_assert(cmux);
- tor_assert(circ);
-
- circuitmux_assert_okay_paranoid(cmux);
-
- /* Figure out our next_p and prev_p for this cmux/direction */
- if (direction) {
- if (direction == CELL_DIRECTION_OUT) {
- tor_assert(circ->n_mux == cmux);
- next_p = &(circ->next_active_on_n_chan);
- prev_p = &(circ->prev_active_on_n_chan);
- } else {
- or_circ = TO_OR_CIRCUIT(circ);
- tor_assert(or_circ->p_mux == cmux);
- next_p = &(or_circ->next_active_on_p_chan);
- prev_p = &(or_circ->prev_active_on_p_chan);
- }
- } else {
- if (circ->n_mux == cmux) {
- next_p = &(circ->next_active_on_n_chan);
- prev_p = &(circ->prev_active_on_n_chan);
- } else {
- or_circ = TO_OR_CIRCUIT(circ);
- tor_assert(or_circ->p_mux == cmux);
- next_p = &(or_circ->next_active_on_p_chan);
- prev_p = &(or_circ->prev_active_on_p_chan);
- }
- }
- tor_assert(next_p);
- tor_assert(prev_p);
-
- /* Check if this really is an active circuit */
- if ((*next_p == NULL && *prev_p == NULL) &&
- !(circ == cmux->active_circuits_head ||
- circ == cmux->active_circuits_tail)) {
- /* Not active, no-op */
- return;
- }
-
- /* Check if this is already the tail */
- if (circ == cmux->active_circuits_tail) return;
-
- /* Okay, we have to move it; figure out next_prev and prev_next */
- if (*next_p) next_prev = circuitmux_prev_active_circ_p(cmux, *next_p);
- if (*prev_p) prev_next = circuitmux_next_active_circ_p(cmux, *prev_p);
- /* Adjust the previous node's next pointer, if any */
- if (prev_next) *prev_next = *next_p;
- /* Otherwise, we were the head */
- else cmux->active_circuits_head = *next_p;
- /* Adjust the next node's previous pointer, if any */
- if (next_prev) *next_prev = *prev_p;
- /* We're out of the list; now re-attach at the tail */
- /* Adjust our next and prev pointers */
- *next_p = NULL;
- *prev_p = cmux->active_circuits_tail;
- /* Set the next pointer of the tail, or the head if none */
- if (cmux->active_circuits_tail) {
- tail_next = circuitmux_next_active_circ_p(cmux,
- cmux->active_circuits_tail);
- *tail_next = circ;
- } else {
- cmux->active_circuits_head = circ;
- }
- /* Set the tail to this circuit */
- cmux->active_circuits_tail = circ;
-
- circuitmux_assert_okay_paranoid(cmux);
-}
-
-static inline circuit_t **
-circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
-{
- tor_assert(cmux);
- tor_assert(circ);
-
- if (circ->n_mux == cmux) return &(circ->next_active_on_n_chan);
- else {
- tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
- return &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
- }
-}
-
-static inline circuit_t **
-circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
-{
- tor_assert(cmux);
- tor_assert(circ);
-
- if (circ->n_mux == cmux) return &(circ->prev_active_on_n_chan);
- else {
- tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
- return &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
- }
-}
-
-/**
* Helper for chanid_circid_cell_count_map_t hash table: compare the channel
* ID and circuit ID for a and b, and return less than, equal to, or greater
* than zero appropriately.
@@ -406,11 +263,6 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
circuit_t *circ = NULL;
tor_assert(cmux);
- /*
- * Don't circuitmux_assert_okay_paranoid() here; this gets called when
- * channels are being freed and have already been unregistered, so
- * the channel ID lookups it does will fail.
- */
i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
while (i) {
@@ -435,7 +287,7 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
*/
if (to_remove->muxinfo.cell_count > 0) {
- circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_OUT);
+ circuitmux_make_circuit_inactive(cmux, circ);
}
/* Clear n_mux */
@@ -450,7 +302,7 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
*/
if (to_remove->muxinfo.cell_count > 0) {
- circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_IN);
+ circuitmux_make_circuit_inactive(cmux, circ);
}
/*
@@ -606,9 +458,7 @@ circuitmux_clear_policy(circuitmux_t *cmux)
tor_assert(cmux);
/* Internally, this is just setting policy to NULL */
- if (cmux->policy) {
- circuitmux_set_policy(cmux, NULL);
- }
+ circuitmux_set_policy(cmux, NULL);
}
/**
@@ -944,7 +794,6 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
tor_assert(circ);
tor_assert(direction == CELL_DIRECTION_IN ||
direction == CELL_DIRECTION_OUT);
- circuitmux_assert_okay_paranoid(cmux);
/*
* Figure out which channel we're using, and get the circuit's current
@@ -1002,10 +851,10 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
*/
if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
--(cmux->n_active_circuits);
- circuitmux_make_circuit_inactive(cmux, circ, direction);
+ circuitmux_make_circuit_inactive(cmux, circ);
} else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
++(cmux->n_active_circuits);
- circuitmux_make_circuit_active(cmux, circ, direction);
+ circuitmux_make_circuit_active(cmux, circ);
}
cmux->n_cells -= hashent->muxinfo.cell_count;
cmux->n_cells += cell_count;
@@ -1033,7 +882,7 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
hashent->muxinfo.cell_count = cell_count;
hashent->muxinfo.direction = direction;
/* Allocate policy specific circuit data if we need it */
- if (cmux->policy && cmux->policy->alloc_circ_data) {
+ if (cmux->policy->alloc_circ_data) {
/* Assert that we have the means to free policy-specific data */
tor_assert(cmux->policy->free_circ_data);
/* Allocate it */
@@ -1053,25 +902,14 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux;
else TO_OR_CIRCUIT(circ)->p_mux = cmux;
- /* Make sure the next/prev pointers are NULL */
- if (direction == CELL_DIRECTION_OUT) {
- circ->next_active_on_n_chan = NULL;
- circ->prev_active_on_n_chan = NULL;
- } else {
- TO_OR_CIRCUIT(circ)->next_active_on_p_chan = NULL;
- TO_OR_CIRCUIT(circ)->prev_active_on_p_chan = NULL;
- }
-
/* Update counters */
++(cmux->n_circuits);
if (cell_count > 0) {
++(cmux->n_active_circuits);
- circuitmux_make_circuit_active(cmux, circ, direction);
+ circuitmux_make_circuit_active(cmux, circ);
}
cmux->n_cells += cell_count;
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1095,7 +933,6 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
tor_assert(cmux);
tor_assert(cmux->chanid_circid_map);
tor_assert(circ);
- circuitmux_assert_okay_paranoid(cmux);
/* See if we have it for n_chan/n_circ_id */
if (circ->n_chan) {
@@ -1133,7 +970,7 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
if (hashent->muxinfo.cell_count > 0) {
--(cmux->n_active_circuits);
/* This does policy notifies, so comes before freeing policy data */
- circuitmux_make_circuit_inactive(cmux, circ, last_searched_direction);
+ circuitmux_make_circuit_inactive(cmux, circ);
}
cmux->n_cells -= hashent->muxinfo.cell_count;
@@ -1162,8 +999,6 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
/* Free the hash entry */
tor_free(hashent);
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1172,94 +1007,22 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
*/
static void
-circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction)
+circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ)
{
- circuit_t **next_active = NULL, **prev_active = NULL, **next_prev = NULL;
- circuitmux_t *circuit_cmux = NULL;
- chanid_circid_muxinfo_t *hashent = NULL;
- channel_t *chan = NULL;
- circid_t circ_id;
- int already_active;
-
tor_assert(cmux);
+ tor_assert(cmux->policy);
tor_assert(circ);
- tor_assert(direction == CELL_DIRECTION_OUT ||
- direction == CELL_DIRECTION_IN);
- /*
- * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
- * already got changed and we have to update the list for it to be consistent
- * again.
- */
-
- /* Get the right set of active list links for this direction */
- if (direction == CELL_DIRECTION_OUT) {
- next_active = &(circ->next_active_on_n_chan);
- prev_active = &(circ->prev_active_on_n_chan);
- circuit_cmux = circ->n_mux;
- chan = circ->n_chan;
- circ_id = circ->n_circ_id;
- } else {
- next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
- prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
- circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
- chan = TO_OR_CIRCUIT(circ)->p_chan;
- circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
- }
-
- /* Assert that it is attached to this mux and a channel */
- tor_assert(cmux == circuit_cmux);
- tor_assert(chan != NULL);
-
- /*
- * Check if the circuit really was inactive; if it's active, at least one
- * of the next_active and prev_active pointers will not be NULL, or this
- * circuit will be either the head or tail of the list for this cmux.
- */
- already_active = (*prev_active != NULL || *next_active != NULL ||
- cmux->active_circuits_head == circ ||
- cmux->active_circuits_tail == circ);
-
- /* If we're already active, log a warning and finish */
- if (already_active) {
- log_warn(LD_CIRC,
- "Circuit %u on channel " U64_FORMAT " was already active",
- (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier));
- return;
- }
-
- /*
- * This is going at the head of the list; if the old head is not NULL,
- * then its prev pointer should point to this.
- */
- *next_active = cmux->active_circuits_head; /* Next is old head */
- *prev_active = NULL; /* Prev is NULL (this will be the head) */
- if (cmux->active_circuits_head) {
- /* The list had an old head; update its prev pointer */
- next_prev =
- circuitmux_prev_active_circ_p(cmux, cmux->active_circuits_head);
- tor_assert(next_prev);
- *next_prev = circ;
- } else {
- /* The list was empty; this becomes the tail as well */
- cmux->active_circuits_tail = circ;
- }
- /* This becomes the new head of the list */
- cmux->active_circuits_head = circ;
/* Policy-specific notification */
- if (cmux->policy &&
- cmux->policy->notify_circ_active) {
+ if (cmux->policy->notify_circ_active) {
/* Okay, we need to check the circuit for policy data now */
- hashent = circuitmux_find_map_entry(cmux, circ);
+ chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
/* We should have found something */
tor_assert(hashent);
/* Notify */
cmux->policy->notify_circ_active(cmux, cmux->policy_data,
circ, hashent->muxinfo.policy_data);
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1268,112 +1031,22 @@ circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
*/
static void
-circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction)
+circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ)
{
- circuit_t **next_active = NULL, **prev_active = NULL;
- circuit_t **next_prev = NULL, **prev_next = NULL;
- circuitmux_t *circuit_cmux = NULL;
- chanid_circid_muxinfo_t *hashent = NULL;
- channel_t *chan = NULL;
- circid_t circ_id;
- int already_inactive;
-
tor_assert(cmux);
+ tor_assert(cmux->policy);
tor_assert(circ);
- tor_assert(direction == CELL_DIRECTION_OUT ||
- direction == CELL_DIRECTION_IN);
- /*
- * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
- * already got changed and we have to update the list for it to be consistent
- * again.
- */
-
- /* Get the right set of active list links for this direction */
- if (direction == CELL_DIRECTION_OUT) {
- next_active = &(circ->next_active_on_n_chan);
- prev_active = &(circ->prev_active_on_n_chan);
- circuit_cmux = circ->n_mux;
- chan = circ->n_chan;
- circ_id = circ->n_circ_id;
- } else {
- next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
- prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
- circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
- chan = TO_OR_CIRCUIT(circ)->p_chan;
- circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
- }
-
- /* Assert that it is attached to this mux and a channel */
- tor_assert(cmux == circuit_cmux);
- tor_assert(chan != NULL);
-
- /*
- * Check if the circuit really was active; if it's inactive, the
- * next_active and prev_active pointers will be NULL and this circuit
- * will not be the head or tail of the list for this cmux.
- */
- already_inactive = (*prev_active == NULL && *next_active == NULL &&
- cmux->active_circuits_head != circ &&
- cmux->active_circuits_tail != circ);
-
- /* If we're already inactive, log a warning and finish */
- if (already_inactive) {
- log_warn(LD_CIRC,
- "Circuit %d on channel " U64_FORMAT " was already inactive",
- (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier));
- return;
- }
-
- /* Remove from the list; first get next_prev and prev_next */
- if (*next_active) {
- /*
- * If there's a next circuit, its previous circuit becomes this
- * circuit's previous circuit.
- */
- next_prev = circuitmux_prev_active_circ_p(cmux, *next_active);
- } else {
- /* Else, the tail becomes this circuit's previous circuit */
- next_prev = &(cmux->active_circuits_tail);
- }
-
- /* Got next_prev, now prev_next */
- if (*prev_active) {
- /*
- * If there's a previous circuit, its next circuit becomes this circuit's
- * next circuit.
- */
- prev_next = circuitmux_next_active_circ_p(cmux, *prev_active);
- } else {
- /* Else, the head becomes this circuit's next circuit */
- prev_next = &(cmux->active_circuits_head);
- }
-
- /* Assert that we got sensible values for the next/prev pointers */
- tor_assert(next_prev != NULL);
- tor_assert(prev_next != NULL);
-
- /* Update the next/prev pointers - this removes circ from the list */
- *next_prev = *prev_active;
- *prev_next = *next_active;
-
- /* Now null out prev_active/next_active */
- *prev_active = NULL;
- *next_active = NULL;
/* Policy-specific notification */
- if (cmux->policy &&
- cmux->policy->notify_circ_inactive) {
+ if (cmux->policy->notify_circ_inactive) {
/* Okay, we need to check the circuit for policy data now */
- hashent = circuitmux_find_map_entry(cmux, circ);
+ chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
/* We should have found something */
tor_assert(hashent);
/* Notify */
cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
circ, hashent->muxinfo.policy_data);
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1400,8 +1073,6 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
tor_assert(cmux);
tor_assert(circ);
- circuitmux_assert_okay_paranoid(cmux);
-
/* Search for this circuit's entry */
hashent = circuitmux_find_map_entry(cmux, circ);
/* Assert that we found one */
@@ -1412,7 +1083,7 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
cmux->n_cells += n_cells;
/* Do we need to notify a cmux policy? */
- if (cmux->policy && cmux->policy->notify_set_n_cells) {
+ if (cmux->policy->notify_set_n_cells) {
/* Call notify_set_n_cells */
cmux->policy->notify_set_n_cells(cmux,
cmux->policy_data,
@@ -1428,21 +1099,15 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
--(cmux->n_active_circuits);
hashent->muxinfo.cell_count = n_cells;
- circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
+ circuitmux_make_circuit_inactive(cmux, circ);
/* Is the old cell count == 0 and the new cell count > 0 ? */
} else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
++(cmux->n_active_circuits);
hashent->muxinfo.cell_count = n_cells;
- circuitmux_make_circuit_active(cmux, circ, hashent->muxinfo.direction);
+ circuitmux_make_circuit_active(cmux, circ);
} else {
- /*
- * Update the entry cell count like this so we can put a
- * circuitmux_assert_okay_paranoid inside make_circuit_(in)active() too.
- */
hashent->muxinfo.cell_count = n_cells;
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/*
@@ -1468,6 +1133,9 @@ circuitmux_get_first_active_circuit(circuitmux_t *cmux,
circuit_t *circ = NULL;
tor_assert(cmux);
+ tor_assert(cmux->policy);
+ /* This callback is mandatory. */
+ tor_assert(cmux->policy->pick_active_circuit);
tor_assert(destroy_queue_out);
*destroy_queue_out = NULL;
@@ -1486,14 +1154,7 @@ circuitmux_get_first_active_circuit(circuitmux_t *cmux,
/* We also must have a cell available for this to be the case */
tor_assert(cmux->n_cells > 0);
/* Do we have a policy-provided circuit selector? */
- if (cmux->policy && cmux->policy->pick_active_circuit) {
- circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
- }
- /* Fall back on the head of the active circuits list */
- if (!circ) {
- tor_assert(cmux->active_circuits_head);
- circ = cmux->active_circuits_head;
- }
+ circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
cmux->last_cell_was_destroy = 0;
} else {
tor_assert(cmux->n_cells == 0);
@@ -1517,7 +1178,6 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
tor_assert(cmux);
tor_assert(circ);
- circuitmux_assert_okay_paranoid(cmux);
if (n_cells == 0) return;
@@ -1544,17 +1204,11 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
/* Adjust the mux cell counter */
cmux->n_cells -= n_cells;
- /* If we aren't making it inactive later, move it to the tail of the list */
- if (!becomes_inactive) {
- circuitmux_move_active_circ_to_tail(cmux, circ,
- hashent->muxinfo.direction);
- }
-
/*
* We call notify_xmit_cells() before making the circuit inactive if needed,
* so the policy can always count on this coming in on an active circuit.
*/
- if (cmux->policy && cmux->policy->notify_xmit_cells) {
+ if (cmux->policy->notify_xmit_cells) {
cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
hashent->muxinfo.policy_data,
n_cells);
@@ -1566,10 +1220,8 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
*/
if (becomes_inactive) {
--(cmux->n_active_circuits);
- circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
+ circuitmux_make_circuit_inactive(cmux, circ);
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1592,282 +1244,6 @@ circuitmux_notify_xmit_destroy(circuitmux_t *cmux)
I64_PRINTF_ARG(global_destroy_ctr));
}
-/*
- * Circuitmux consistency checking assertions
- */
-
-/**
- * Check that circuitmux data structures are consistent and fail with an
- * assert if not.
- */
-
-void
-circuitmux_assert_okay(circuitmux_t *cmux)
-{
- tor_assert(cmux);
-
- /*
- * Pass 1: iterate the hash table; for each entry:
- * a) Check that the circuit has this cmux for n_mux or p_mux
- * b) If the cell_count is > 0, set the mark bit; otherwise clear it
- * c) Also check activeness (cell_count > 0 should be active)
- * d) Count the number of circuits, active circuits and queued cells
- * and at the end check that they match the counters in the cmux.
- *
- * Pass 2: iterate the active circuits list; for each entry,
- * make sure the circuit is attached to this mux and appears
- * in the hash table. Make sure the mark bit is 1, and clear
- * it in the hash table entry. Consistency-check the linked
- * list pointers.
- *
- * Pass 3: iterate the hash table again; assert if any active circuits
- * (mark bit set to 1) are discovered that weren't cleared in pass 2
- * (don't appear in the linked list).
- */
-
- circuitmux_assert_okay_pass_one(cmux);
- circuitmux_assert_okay_pass_two(cmux);
- circuitmux_assert_okay_pass_three(cmux);
-}
-
-/**
- * Do the first pass of circuitmux_assert_okay(); see the comment in that
- * function.
- */
-
-static void
-circuitmux_assert_okay_pass_one(circuitmux_t *cmux)
-{
- chanid_circid_muxinfo_t **i = NULL;
- uint64_t chan_id;
- channel_t *chan;
- circid_t circ_id;
- circuit_t *circ;
- or_circuit_t *or_circ;
- circuit_t **next_p, **prev_p;
- unsigned int n_circuits, n_active_circuits, n_cells;
-
- tor_assert(cmux);
- tor_assert(cmux->chanid_circid_map);
-
- /* Reset the counters */
- n_circuits = n_active_circuits = n_cells = 0;
- /* Start iterating the hash table */
- i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
- while (i) {
- /* Assert that the hash table entry isn't null */
- tor_assert(*i);
-
- /* Get the channel and circuit id */
- chan_id = (*i)->chan_id;
- circ_id = (*i)->circ_id;
-
- /* Find the channel and circuit, assert that they exist */
- chan = channel_find_by_global_id(chan_id);
- tor_assert(chan);
- circ = circuit_get_by_circid_channel_even_if_marked(circ_id, chan);
- tor_assert(circ);
-
- /* Assert that we know which direction this is going */
- tor_assert((*i)->muxinfo.direction == CELL_DIRECTION_OUT ||
- (*i)->muxinfo.direction == CELL_DIRECTION_IN);
-
- if ((*i)->muxinfo.direction == CELL_DIRECTION_OUT) {
- /* We should be n_mux on this circuit */
- tor_assert(cmux == circ->n_mux);
- tor_assert(chan == circ->n_chan);
- /* Get next and prev for next test */
- next_p = &(circ->next_active_on_n_chan);
- prev_p = &(circ->prev_active_on_n_chan);
- } else {
- /* This should be an or_circuit_t and we should be p_mux */
- or_circ = TO_OR_CIRCUIT(circ);
- tor_assert(cmux == or_circ->p_mux);
- tor_assert(chan == or_circ->p_chan);
- /* Get next and prev for next test */
- next_p = &(or_circ->next_active_on_p_chan);
- prev_p = &(or_circ->prev_active_on_p_chan);
- }
-
- /*
- * Should this circuit be active? I.e., does the mux know about > 0
- * cells on it?
- */
- const int circ_is_active = ((*i)->muxinfo.cell_count > 0);
-
- /* It should be in the linked list iff it's active */
- if (circ_is_active) {
- /* Either we have a next link or we are the tail */
- tor_assert(*next_p || (circ == cmux->active_circuits_tail));
- /* Either we have a prev link or we are the head */
- tor_assert(*prev_p || (circ == cmux->active_circuits_head));
- /* Increment the active circuits counter */
- ++n_active_circuits;
- } else {
- /* Shouldn't be in list, so no next or prev link */
- tor_assert(!(*next_p));
- tor_assert(!(*prev_p));
- /* And can't be head or tail */
- tor_assert(circ != cmux->active_circuits_head);
- tor_assert(circ != cmux->active_circuits_tail);
- }
-
- /* Increment the circuits counter */
- ++n_circuits;
- /* Adjust the cell counter */
- n_cells += (*i)->muxinfo.cell_count;
-
- /* Set the mark bit to circ_is_active */
- (*i)->muxinfo.mark = circ_is_active;
-
- /* Advance to the next entry */
- i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
- }
-
- /* Now check the counters */
- tor_assert(n_cells == cmux->n_cells);
- tor_assert(n_circuits == cmux->n_circuits);
- tor_assert(n_active_circuits == cmux->n_active_circuits);
-}
-
-/**
- * Do the second pass of circuitmux_assert_okay(); see the comment in that
- * function.
- */
-
-static void
-circuitmux_assert_okay_pass_two(circuitmux_t *cmux)
-{
- circuit_t *curr_circ, *prev_circ = NULL, *next_circ;
- or_circuit_t *curr_or_circ;
- uint64_t curr_chan_id;
- circid_t curr_circ_id;
- circuit_t **next_p, **prev_p;
- channel_t *chan;
- unsigned int n_active_circuits = 0;
- chanid_circid_muxinfo_t search, *hashent = NULL;
-
- tor_assert(cmux);
- tor_assert(cmux->chanid_circid_map);
-
- /*
- * Walk the linked list of active circuits in cmux; keep track of the
- * previous circuit seen for consistency checking purposes. Count them
- * to make sure the number in the linked list matches
- * cmux->n_active_circuits.
- */
- curr_circ = cmux->active_circuits_head;
- while (curr_circ) {
- /* Reset some things */
- chan = NULL;
- curr_or_circ = NULL;
- next_circ = NULL;
- next_p = prev_p = NULL;
- cell_direction_t direction;
-
- /* Figure out if this is n_mux or p_mux */
- if (cmux == curr_circ->n_mux) {
- /* Get next_p and prev_p */
- next_p = &(curr_circ->next_active_on_n_chan);
- prev_p = &(curr_circ->prev_active_on_n_chan);
- /* Get the channel */
- chan = curr_circ->n_chan;
- /* Get the circuit id */
- curr_circ_id = curr_circ->n_circ_id;
- /* Remember the direction */
- direction = CELL_DIRECTION_OUT;
- } else {
- /* We must be p_mux and this must be an or_circuit_t */
- curr_or_circ = TO_OR_CIRCUIT(curr_circ);
- tor_assert(cmux == curr_or_circ->p_mux);
- /* Get next_p and prev_p */
- next_p = &(curr_or_circ->next_active_on_p_chan);
- prev_p = &(curr_or_circ->prev_active_on_p_chan);
- /* Get the channel */
- chan = curr_or_circ->p_chan;
- /* Get the circuit id */
- curr_circ_id = curr_or_circ->p_circ_id;
- /* Remember the direction */
- direction = CELL_DIRECTION_IN;
- }
-
- /* Assert that we got a channel and get the channel ID */
- tor_assert(chan);
- curr_chan_id = chan->global_identifier;
-
- /* Assert that prev_p points to last circuit we saw */
- tor_assert(*prev_p == prev_circ);
- /* If that's NULL, assert that we are the head */
- if (!(*prev_p)) tor_assert(curr_circ == cmux->active_circuits_head);
-
- /* Get the next circuit */
- next_circ = *next_p;
- /* If it's NULL, assert that we are the tail */
- if (!(*next_p)) tor_assert(curr_circ == cmux->active_circuits_tail);
-
- /* Now find the hash table entry for this circuit */
- search.chan_id = curr_chan_id;
- search.circ_id = curr_circ_id;
- hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
- &search);
-
- /* Assert that we have one */
- tor_assert(hashent);
-
- /* Assert that the direction matches */
- tor_assert(direction == hashent->muxinfo.direction);
-
- /* Assert that the hash entry got marked in pass one */
- tor_assert(hashent->muxinfo.mark);
-
- /* Clear the mark */
- hashent->muxinfo.mark = 0;
-
- /* Increment the counter */
- ++n_active_circuits;
-
- /* Advance to the next active circuit and update prev_circ */
- prev_circ = curr_circ;
- curr_circ = next_circ;
- }
-
- /* Assert that the counter matches the cmux */
- tor_assert(n_active_circuits == cmux->n_active_circuits);
-}
-
-/**
- * Do the third pass of circuitmux_assert_okay(); see the comment in that
- * function.
- */
-
-static void
-circuitmux_assert_okay_pass_three(circuitmux_t *cmux)
-{
- chanid_circid_muxinfo_t **i = NULL;
-
- tor_assert(cmux);
- tor_assert(cmux->chanid_circid_map);
-
- /* Start iterating the hash table */
- i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
-
- /* Advance through each entry */
- while (i) {
- /* Assert that it isn't null */
- tor_assert(*i);
-
- /*
- * Assert that this entry is not marked - i.e., that either we didn't
- * think it should be active in pass one or we saw it in the active
- * circuits linked list.
- */
- tor_assert(!((*i)->muxinfo.mark));
-
- /* Advance to the next entry */
- i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
- }
-}
-
/*DOCDOC */
void
circuitmux_append_destroy_cell(channel_t *chan,
diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c
index fde2d22a89..b2ace8a9fa 100644
--- a/src/or/circuitmux_ewma.c
+++ b/src/or/circuitmux_ewma.c
@@ -223,8 +223,6 @@ ewma_cmp_cmux(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
* has value ewma_scale_factor ** N.)
*/
static double ewma_scale_factor = 0.1;
-/* DOCDOC ewma_enabled */
-static int ewma_enabled = 0;
/*** EWMA circuitmux_policy_t method table ***/
@@ -243,6 +241,13 @@ circuitmux_policy_t ewma_policy = {
/*** EWMA method implementations using the below EWMA helper functions ***/
+/** Compute and return the current cell_ewma tick. */
+static inline unsigned int
+cell_ewma_get_tick(void)
+{
+ return ((unsigned)approx_time() / EWMA_TICK_LEN);
+}
+
/**
* Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t;
* this is called when setting the policy on a circuitmux_t to ewma_policy.
@@ -612,59 +617,79 @@ cell_ewma_tick_from_timeval(const struct timeval *now,
return res;
}
-/** Tell the caller whether ewma_enabled is set */
-int
-cell_ewma_enabled(void)
+/* Default value for the CircuitPriorityHalflifeMsec consensus parameter in
+ * msec. */
+#define CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT 30000
+/* Minimum and maximum value for the CircuitPriorityHalflifeMsec consensus
+ * parameter. */
+#define CMUX_PRIORITY_HALFLIFE_MSEC_MIN 1
+#define CMUX_PRIORITY_HALFLIFE_MSEC_MAX INT32_MAX
+
+/* Return the value of the circuit priority halflife from the options if
+ * available or else from the consensus (in that order). If none can be found,
+ * a default value is returned.
+ *
+ * The source_msg points to a string describing from where the value was
+ * picked so it can be used for logging. */
+static double
+get_circuit_priority_halflife(const or_options_t *options,
+ const networkstatus_t *consensus,
+ const char **source_msg)
{
- return ewma_enabled;
-}
+ int32_t halflife_ms;
+ double halflife;
+ /* Compute the default value now. We might need it. */
+ double halflife_default =
+ ((double) CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT) / 1000.0;
-/** Compute and return the current cell_ewma tick. */
-unsigned int
-cell_ewma_get_tick(void)
-{
- return ((unsigned)approx_time() / EWMA_TICK_LEN);
+ /* Try to get it from configuration file first. */
+ if (options && options->CircuitPriorityHalflife < EPSILON) {
+ halflife = options->CircuitPriorityHalflife;
+ *source_msg = "CircuitPriorityHalflife in configuration";
+ goto end;
+ }
+
+ /* Try to get the msec value from the consensus. */
+ halflife_ms = networkstatus_get_param(consensus,
+ "CircuitPriorityHalflifeMsec",
+ CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT,
+ CMUX_PRIORITY_HALFLIFE_MSEC_MIN,
+ CMUX_PRIORITY_HALFLIFE_MSEC_MAX);
+ halflife = ((double) halflife_ms) / 1000.0;
+ *source_msg = "CircuitPriorityHalflifeMsec in consensus";
+
+ end:
+ /* We should never go below the EPSILON else we would consider it disabled
+ * and we can't have that. */
+ if (halflife < EPSILON) {
+ log_warn(LD_CONFIG, "CircuitPriorityHalflife is too small (%f). "
+ "Adjusting to the smallest value allowed: %f.",
+ halflife, halflife_default);
+ halflife = halflife_default;
+ }
+ return halflife;
}
/** Adjust the global cell scale factor based on <b>options</b> */
void
-cell_ewma_set_scale_factor(const or_options_t *options,
- const networkstatus_t *consensus)
+cmux_ewma_set_options(const or_options_t *options,
+ const networkstatus_t *consensus)
{
- int32_t halflife_ms;
double halflife;
const char *source;
- if (options && options->CircuitPriorityHalflife >= -EPSILON) {
- halflife = options->CircuitPriorityHalflife;
- source = "CircuitPriorityHalflife in configuration";
- } else if (consensus && (halflife_ms = networkstatus_get_param(
- consensus, "CircuitPriorityHalflifeMsec",
- -1, -1, INT32_MAX)) >= 0) {
- halflife = ((double)halflife_ms)/1000.0;
- source = "CircuitPriorityHalflifeMsec in consensus";
- } else {
- halflife = EWMA_DEFAULT_HALFLIFE;
- source = "Default value";
- }
- if (halflife <= EPSILON) {
- /* The cell EWMA algorithm is disabled. */
- ewma_scale_factor = 0.1;
- ewma_enabled = 0;
- log_info(LD_OR,
- "Disabled cell_ewma algorithm because of value in %s",
- source);
- } else {
- /* convert halflife into halflife-per-tick. */
- halflife /= EWMA_TICK_LEN;
- /* compute per-tick scale factor. */
- ewma_scale_factor = exp( LOG_ONEHALF / halflife );
- ewma_enabled = 1;
- log_info(LD_OR,
- "Enabled cell_ewma algorithm because of value in %s; "
- "scale factor is %f per %d seconds",
- source, ewma_scale_factor, EWMA_TICK_LEN);
- }
+ /* Both options and consensus can be NULL. This assures us to either get a
+ * valid configured value or the default one. */
+ halflife = get_circuit_priority_halflife(options, consensus, &source);
+
+ /* convert halflife into halflife-per-tick. */
+ halflife /= EWMA_TICK_LEN;
+ /* compute per-tick scale factor. */
+ ewma_scale_factor = exp( LOG_ONEHALF / halflife );
+ log_info(LD_OR,
+ "Enabled cell_ewma algorithm because of value in %s; "
+ "scale factor is %f per %d seconds",
+ source, ewma_scale_factor, EWMA_TICK_LEN);
}
/** Return the multiplier necessary to convert the value of a cell sent in
diff --git a/src/or/circuitmux_ewma.h b/src/or/circuitmux_ewma.h
index 8f4e57865e..2ef8c2586d 100644
--- a/src/or/circuitmux_ewma.h
+++ b/src/or/circuitmux_ewma.h
@@ -12,13 +12,12 @@
#include "or.h"
#include "circuitmux.h"
+/* The public EWMA policy callbacks object. */
extern circuitmux_policy_t ewma_policy;
/* Externally visible EWMA functions */
-int cell_ewma_enabled(void);
-unsigned int cell_ewma_get_tick(void);
-void cell_ewma_set_scale_factor(const or_options_t *options,
- const networkstatus_t *consensus);
+void cmux_ewma_set_options(const or_options_t *options,
+ const networkstatus_t *consensus);
#endif /* !defined(TOR_CIRCUITMUX_EWMA_H) */
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 5d8af4c6c8..47e29c28dd 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -55,7 +55,6 @@
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
-#include "config.h"
static void circuit_expire_old_circuits_clientside(void);
static void circuit_increment_failure_count(void);
@@ -1632,7 +1631,7 @@ circuit_testing_opened(origin_circuit_t *circ)
router_perform_bandwidth_test(NUM_PARALLEL_TESTING_CIRCS, time(NULL));
have_performed_bandwidth_test = 1;
} else
- consider_testing_reachability(1, 0);
+ router_do_reachability_checks(1, 0);
}
/** A testing circuit has failed to build. Take whatever stats we want. */
@@ -2584,7 +2583,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.",
(unsigned)circ->base_.n_circ_id);
/* reset it, so we can measure circ timeouts */
- ENTRY_TO_CONN(apconn)->timestamp_lastread = time(NULL);
+ ENTRY_TO_CONN(apconn)->timestamp_last_read_allowed = time(NULL);
ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams;
ENTRY_TO_EDGE_CONN(apconn)->on_circuit = TO_CIRCUIT(circ);
/* assert_connection_ok(conn, time(NULL)); */
diff --git a/src/or/command.c b/src/or/command.c
index 7280be1396..4f99462f38 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -339,7 +339,9 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
return;
}
- if (connection_or_digest_is_known_relay(chan->identity_digest)) {
+ if (!channel_is_client(chan)) {
+ /* remember create types we've seen, but don't remember them from
+ * clients, to be extra conservative about client statistics. */
rep_hist_note_circuit_handshake_requested(create_cell->handshake_type);
}
diff --git a/src/or/config.c b/src/or/config.c
index 986794cec5..9c0b321b56 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -267,7 +267,7 @@ static config_var_t option_vars_[] = {
OBSOLETE("CircuitIdleTimeout"),
V(CircuitsAvailableTimeout, INTERVAL, "0"),
V(CircuitStreamTimeout, INTERVAL, "0"),
- V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/
+ V(CircuitPriorityHalflife, DOUBLE, "-1.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
V(ClientOnly, BOOL, "0"),
V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"),
@@ -337,7 +337,7 @@ static config_var_t option_vars_[] = {
V(DownloadExtraInfo, BOOL, "0"),
V(TestingEnableConnBwEvent, BOOL, "0"),
V(TestingEnableCellStatsEvent, BOOL, "0"),
- V(TestingEnableTbEmptyEvent, BOOL, "0"),
+ OBSOLETE("TestingEnableTbEmptyEvent"),
V(EnforceDistinctSubnets, BOOL, "1"),
V(EntryNodes, ROUTERSET, NULL),
V(EntryStatistics, BOOL, "0"),
@@ -495,8 +495,8 @@ static config_var_t option_vars_[] = {
V(TestingSigningKeySlop, INTERVAL, "1 day"),
V(OptimisticData, AUTOBOOL, "auto"),
- V(PortForwarding, BOOL, "0"),
- V(PortForwardingHelper, FILENAME, "tor-fw-helper"),
+ OBSOLETE("PortForwarding"),
+ OBSOLETE("PortForwardingHelper"),
OBSOLETE("PreferTunneledDirConns"),
V(ProtocolWarnings, BOOL, "0"),
V(PublishServerDescriptor, CSV, "1"),
@@ -707,7 +707,6 @@ static const config_var_t testing_tor_network_defaults[] = {
V(TestingDirConnectionMaxStall, INTERVAL, "30 seconds"),
V(TestingEnableConnBwEvent, BOOL, "1"),
V(TestingEnableCellStatsEvent, BOOL, "1"),
- V(TestingEnableTbEmptyEvent, BOOL, "1"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
V(RendPostPeriod, INTERVAL, "2 minutes"),
@@ -1651,8 +1650,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int
options_need_geoip_info(const or_options_t *options, const char **reason_out)
{
- int bridge_usage =
- options->BridgeRelay && options->BridgeRecordUsageByCountry;
+ int bridge_usage = should_record_bridge_info(options);
int routerset_usage =
routerset_needs_geoip(options->EntryNodes) ||
routerset_needs_geoip(options->ExitNodes) ||
@@ -1760,7 +1758,6 @@ options_act(const or_options_t *old_options)
char *msg=NULL;
const int transition_affects_workers =
old_options && options_transition_affects_workers(old_options, options);
- int old_ewma_enabled;
const int transition_affects_guards =
old_options && options_transition_affects_guards(old_options, options);
@@ -2034,16 +2031,8 @@ options_act(const or_options_t *old_options)
if (accounting_is_enabled(options))
configure_accounting(time(NULL));
- old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */
- cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
- /* If we just enabled ewma, set the cmux policy on all active channels */
- if (cell_ewma_enabled() && !old_ewma_enabled) {
- channel_set_cmux_policy_everywhere(&ewma_policy);
- } else if (!cell_ewma_enabled() && old_ewma_enabled) {
- /* Turn it off everywhere */
- channel_set_cmux_policy_everywhere(NULL);
- }
+ cmux_ewma_set_options(options, networkstatus_get_latest_consensus());
/* Update the BridgePassword's hashed version as needed. We store this as a
* digest so that we can do side-channel-proof comparisons on it.
@@ -2199,6 +2188,12 @@ options_act(const or_options_t *old_options)
options->PerConnBWBurst != old_options->PerConnBWBurst)
connection_or_update_token_buckets(get_connection_array(), options);
+ if (options->BandwidthRate != old_options->BandwidthRate ||
+ options->BandwidthBurst != old_options->BandwidthBurst ||
+ options->RelayBandwidthRate != old_options->RelayBandwidthRate ||
+ options->RelayBandwidthBurst != old_options->RelayBandwidthBurst)
+ connection_bucket_adjust(options);
+
if (options->MainloopStats != old_options->MainloopStats) {
reset_main_loop_counters();
}
@@ -2248,6 +2243,11 @@ options_act(const or_options_t *old_options)
}
if ((!old_options || !old_options->EntryStatistics) &&
options->EntryStatistics && !should_record_bridge_info(options)) {
+ /* If we get here, we've started recording bridge info when we didn't
+ * do so before. Note that "should_record_bridge_info()" will
+ * always be false at this point, because of the earlier block
+ * that cleared EntryStatistics when public_server_mode() was false.
+ * We're leaving it in as defensive programming. */
if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) {
geoip_entry_stats_init(now);
print_notice = 1;
@@ -3885,15 +3885,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->KeepalivePeriod < 1)
REJECT("KeepalivePeriod option must be positive.");
- if (options->PortForwarding && options->Sandbox) {
- REJECT("PortForwarding is not compatible with Sandbox; at most one can "
- "be set");
- }
- if (options->PortForwarding && options->NoExec) {
- COMPLAIN("Both PortForwarding and NoExec are set; PortForwarding will "
- "be ignored.");
- }
-
if (ensure_bandwidth_cap(&options->BandwidthRate,
"BandwidthRate", msg) < 0)
return -1;
@@ -4473,12 +4464,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
"Tor networks!");
}
- if (options->TestingEnableTbEmptyEvent &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingEnableTbEmptyEvent may only be changed in testing "
- "Tor networks!");
- }
-
if (options->TestingTorNetwork) {
log_warn(LD_CONFIG, "TestingTorNetwork is set. This will make your node "
"almost unusable in the public Tor network, and is "
@@ -4622,15 +4607,14 @@ have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem,
if (options->DirCache) {
if (total_mem < DIRCACHE_MIN_MEM_BYTES) {
if (options->BridgeRelay) {
- *msg = tor_strdup("Running a Bridge with less than "
- STRINGIFY(DIRCACHE_MIN_MEM_MB) " MB of memory is not "
- "recommended.");
+ tor_asprintf(msg, "Running a Bridge with less than %d MB of memory "
+ "is not recommended.", DIRCACHE_MIN_MEM_MB);
} else {
- *msg = tor_strdup("Being a directory cache (default) with less than "
- STRINGIFY(DIRCACHE_MIN_MEM_MB) " MB of memory is not "
- "recommended and may consume most of the available "
- "resources, consider disabling this functionality by "
- "setting the DirCache option to 0.");
+ tor_asprintf(msg, "Being a directory cache (default) with less than "
+ "%d MB of memory is not recommended and may consume "
+ "most of the available resources. Consider disabling "
+ "this functionality by setting the DirCache option "
+ "to 0.", DIRCACHE_MIN_MEM_MB);
}
}
} else {
diff --git a/src/or/connection.c b/src/or/connection.c
index 2a6b10763e..9573989854 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -101,7 +101,6 @@
#include "transports.h"
#include "routerparse.h"
#include "sandbox.h"
-#include "transports.h"
#ifdef HAVE_PWD_H
#include <pwd.h>
@@ -120,8 +119,6 @@ static connection_t *connection_listener_new(
static void connection_init(time_t now, connection_t *conn, int type,
int socket_family);
static int connection_handle_listener_read(connection_t *conn, int new_type);
-static int connection_bucket_should_increase(int bucket,
- or_connection_t *conn);
static int connection_finished_flushing(connection_t *conn);
static int connection_flushed_some(connection_t *conn);
static int connection_finished_connecting(connection_t *conn);
@@ -460,8 +457,8 @@ connection_init(time_t now, connection_t *conn, int type, int socket_family)
}
conn->timestamp_created = now;
- conn->timestamp_lastread = now;
- conn->timestamp_lastwritten = now;
+ conn->timestamp_last_read_allowed = now;
+ conn->timestamp_last_write_allowed = now;
}
/** Create a link between <b>conn_a</b> and <b>conn_b</b>. */
@@ -859,7 +856,7 @@ connection_mark_for_close_internal_, (connection_t *conn,
/* in case we're going to be held-open-til-flushed, reset
* the number of seconds since last successful write, so
* we get our whole 15 seconds */
- conn->timestamp_lastwritten = time(NULL);
+ conn->timestamp_last_write_allowed = time(NULL);
}
/** Find each connection that has hold_open_until_flushed set to
@@ -881,7 +878,7 @@ connection_expire_held_open(void)
*/
if (conn->hold_open_until_flushed) {
tor_assert(conn->marked_for_close);
- if (now - conn->timestamp_lastwritten >= 15) {
+ if (now - conn->timestamp_last_write_allowed >= 15) {
int severity;
if (conn->type == CONN_TYPE_EXIT ||
(conn->type == CONN_TYPE_DIR &&
@@ -1259,15 +1256,12 @@ connection_listener_new(const struct sockaddr *listensockaddr,
gotPort = usePort;
} else {
tor_addr_t addr2;
- struct sockaddr_storage ss;
- socklen_t ss_len=sizeof(ss);
- if (getsockname(s, (struct sockaddr*)&ss, &ss_len)<0) {
+ if (tor_addr_from_getsockname(&addr2, s)<0) {
log_warn(LD_NET, "getsockname() couldn't learn address for %s: %s",
conn_type_to_string(type),
tor_socket_strerror(tor_socket_errno(s)));
gotPort = 0;
}
- tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort);
}
#ifdef HAVE_SYS_UN_H
/*
@@ -2852,7 +2846,7 @@ connection_counts_as_relayed_traffic(connection_t *conn, time_t now)
* non-negative) provides an upper limit for our answer. */
static ssize_t
connection_bucket_round_robin(int base, int priority,
- ssize_t global_bucket, ssize_t conn_bucket)
+ ssize_t global_bucket_val, ssize_t conn_bucket)
{
ssize_t at_most;
ssize_t num_bytes_high = (priority ? 32 : 16) * base;
@@ -2861,15 +2855,15 @@ connection_bucket_round_robin(int base, int priority,
/* Do a rudimentary round-robin so one circuit can't hog a connection.
* Pick at most 32 cells, at least 4 cells if possible, and if we're in
* the middle pick 1/8 of the available bandwidth. */
- at_most = global_bucket / 8;
+ at_most = global_bucket_val / 8;
at_most -= (at_most % base); /* round down */
if (at_most > num_bytes_high) /* 16 KB, or 8 KB for low-priority */
at_most = num_bytes_high;
else if (at_most < num_bytes_low) /* 2 KB, or 1 KB for low-priority */
at_most = num_bytes_low;
- if (at_most > global_bucket)
- at_most = global_bucket;
+ if (at_most > global_bucket_val)
+ at_most = global_bucket_val;
if (conn_bucket >= 0 && at_most > conn_bucket)
at_most = conn_bucket;
@@ -2885,13 +2879,13 @@ connection_bucket_read_limit(connection_t *conn, time_t now)
{
int base = RELAY_PAYLOAD_SIZE;
int priority = conn->type != CONN_TYPE_DIR;
- int conn_bucket = -1;
- int global_bucket = global_read_bucket;
+ ssize_t conn_bucket = -1;
+ size_t global_bucket_val = token_bucket_rw_get_read(&global_bucket);
if (connection_speaks_cells(conn)) {
or_connection_t *or_conn = TO_OR_CONN(conn);
if (conn->state == OR_CONN_STATE_OPEN)
- conn_bucket = or_conn->read_bucket;
+ conn_bucket = token_bucket_rw_get_read(&or_conn->bucket);
base = get_cell_network_size(or_conn->wide_circ_ids);
}
@@ -2900,12 +2894,13 @@ connection_bucket_read_limit(connection_t *conn, time_t now)
return conn_bucket>=0 ? conn_bucket : 1<<14;
}
- if (connection_counts_as_relayed_traffic(conn, now) &&
- global_relayed_read_bucket <= global_read_bucket)
- global_bucket = global_relayed_read_bucket;
+ if (connection_counts_as_relayed_traffic(conn, now)) {
+ size_t relayed = token_bucket_rw_get_read(&global_relayed_bucket);
+ global_bucket_val = MIN(global_bucket_val, relayed);
+ }
return connection_bucket_round_robin(base, priority,
- global_bucket, conn_bucket);
+ global_bucket_val, conn_bucket);
}
/** How many bytes at most can we write onto this connection? */
@@ -2914,8 +2909,8 @@ connection_bucket_write_limit(connection_t *conn, time_t now)
{
int base = RELAY_PAYLOAD_SIZE;
int priority = conn->type != CONN_TYPE_DIR;
- int conn_bucket = (int)conn->outbuf_flushlen;
- int global_bucket = global_write_bucket;
+ size_t conn_bucket = conn->outbuf_flushlen;
+ size_t global_bucket_val = token_bucket_rw_get_write(&global_bucket);
if (!connection_is_rate_limited(conn)) {
/* be willing to write to local conns even if our buckets are empty */
@@ -2923,22 +2918,21 @@ connection_bucket_write_limit(connection_t *conn, time_t now)
}
if (connection_speaks_cells(conn)) {
- /* use the per-conn write limit if it's lower, but if it's less
- * than zero just use zero */
+ /* use the per-conn write limit if it's lower */
or_connection_t *or_conn = TO_OR_CONN(conn);
if (conn->state == OR_CONN_STATE_OPEN)
- if (or_conn->write_bucket < conn_bucket)
- conn_bucket = or_conn->write_bucket >= 0 ?
- or_conn->write_bucket : 0;
+ conn_bucket = MIN(conn_bucket,
+ token_bucket_rw_get_write(&or_conn->bucket));
base = get_cell_network_size(or_conn->wide_circ_ids);
}
- if (connection_counts_as_relayed_traffic(conn, now) &&
- global_relayed_write_bucket <= global_write_bucket)
- global_bucket = global_relayed_write_bucket;
+ if (connection_counts_as_relayed_traffic(conn, now)) {
+ size_t relayed = token_bucket_rw_get_write(&global_relayed_bucket);
+ global_bucket_val = MIN(global_bucket_val, relayed);
+ }
return connection_bucket_round_robin(base, priority,
- global_bucket, conn_bucket);
+ global_bucket_val, conn_bucket);
}
/** Return 1 if the global write buckets are low enough that we
@@ -2963,15 +2957,16 @@ connection_bucket_write_limit(connection_t *conn, time_t now)
int
global_write_bucket_low(connection_t *conn, size_t attempt, int priority)
{
- int smaller_bucket = global_write_bucket < global_relayed_write_bucket ?
- global_write_bucket : global_relayed_write_bucket;
+ size_t smaller_bucket =
+ MIN(token_bucket_rw_get_write(&global_bucket),
+ token_bucket_rw_get_write(&global_relayed_bucket));
if (authdir_mode(get_options()) && priority>1)
return 0; /* there's always room to answer v2 if we're an auth dir */
if (!connection_is_rate_limited(conn))
return 0; /* local conns don't get limited */
- if (smaller_bucket < (int)attempt)
+ if (smaller_bucket < attempt)
return 1; /* not enough space no matter the priority */
if (write_buckets_empty_last_second)
@@ -2980,10 +2975,10 @@ global_write_bucket_low(connection_t *conn, size_t attempt, int priority)
if (priority == 1) { /* old-style v1 query */
/* Could we handle *two* of these requests within the next two seconds? */
const or_options_t *options = get_options();
- int64_t can_write = (int64_t)smaller_bucket
+ size_t can_write = (size_t) (smaller_bucket
+ 2*(options->RelayBandwidthRate ? options->RelayBandwidthRate :
- options->BandwidthRate);
- if (can_write < 2*(int64_t)attempt)
+ options->BandwidthRate));
+ if (can_write < 2*attempt)
return 1;
} else { /* v2 query */
/* no further constraints yet */
@@ -3023,57 +3018,6 @@ record_num_bytes_transferred_impl(connection_t *conn,
rep_hist_note_exit_bytes(conn->port, num_written, num_read);
}
-/** Helper: convert given <b>tvnow</b> time value to milliseconds since
- * midnight. */
-static uint32_t
-msec_since_midnight(const struct timeval *tvnow)
-{
- return (uint32_t)(((tvnow->tv_sec % 86400L) * 1000L) +
- ((uint32_t)tvnow->tv_usec / (uint32_t)1000L));
-}
-
-/** Helper: return the time in milliseconds since <b>last_empty_time</b>
- * when a bucket ran empty that previously had <b>tokens_before</b> tokens
- * now has <b>tokens_after</b> tokens after refilling at timestamp
- * <b>tvnow</b>, capped at <b>milliseconds_elapsed</b> milliseconds since
- * last refilling that bucket. Return 0 if the bucket has not been empty
- * since the last refill or has not been refilled. */
-uint32_t
-bucket_millis_empty(int tokens_before, uint32_t last_empty_time,
- int tokens_after, int milliseconds_elapsed,
- const struct timeval *tvnow)
-{
- uint32_t result = 0, refilled;
- if (tokens_before <= 0 && tokens_after > tokens_before) {
- refilled = msec_since_midnight(tvnow);
- result = (uint32_t)((refilled + 86400L * 1000L - last_empty_time) %
- (86400L * 1000L));
- if (result > (uint32_t)milliseconds_elapsed)
- result = (uint32_t)milliseconds_elapsed;
- }
- return result;
-}
-
-/** Check if a bucket which had <b>tokens_before</b> tokens and which got
- * <b>tokens_removed</b> tokens removed at timestamp <b>tvnow</b> has run
- * out of tokens, and if so, note the milliseconds since midnight in
- * <b>timestamp_var</b> for the next TB_EMPTY event. */
-void
-connection_buckets_note_empty_ts(uint32_t *timestamp_var,
- int tokens_before, size_t tokens_removed,
- const struct timeval *tvnow)
-{
- if (tokens_before > 0 && (uint32_t)tokens_before <= tokens_removed)
- *timestamp_var = msec_since_midnight(tvnow);
-}
-
-/** Last time at which the global or relay buckets were emptied in msec
- * since midnight. */
-static uint32_t global_relayed_read_emptied = 0,
- global_relayed_write_emptied = 0,
- global_read_emptied = 0,
- global_write_emptied = 0;
-
/** We just read <b>num_read</b> and wrote <b>num_written</b> bytes
* onto <b>conn</b>. Decrement buckets appropriately. */
static void
@@ -3098,39 +3042,13 @@ connection_buckets_decrement(connection_t *conn, time_t now,
if (!connection_is_rate_limited(conn))
return; /* local IPs are free */
- /* If one or more of our token buckets ran dry just now, note the
- * timestamp for TB_EMPTY events. */
- if (get_options()->TestingEnableTbEmptyEvent) {
- struct timeval tvnow;
- tor_gettimeofday_cached(&tvnow);
- if (connection_counts_as_relayed_traffic(conn, now)) {
- connection_buckets_note_empty_ts(&global_relayed_read_emptied,
- global_relayed_read_bucket, num_read, &tvnow);
- connection_buckets_note_empty_ts(&global_relayed_write_emptied,
- global_relayed_write_bucket, num_written, &tvnow);
- }
- connection_buckets_note_empty_ts(&global_read_emptied,
- global_read_bucket, num_read, &tvnow);
- connection_buckets_note_empty_ts(&global_write_emptied,
- global_write_bucket, num_written, &tvnow);
- if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
- or_connection_t *or_conn = TO_OR_CONN(conn);
- connection_buckets_note_empty_ts(&or_conn->read_emptied_time,
- or_conn->read_bucket, num_read, &tvnow);
- connection_buckets_note_empty_ts(&or_conn->write_emptied_time,
- or_conn->write_bucket, num_written, &tvnow);
- }
- }
-
if (connection_counts_as_relayed_traffic(conn, now)) {
- global_relayed_read_bucket -= (int)num_read;
- global_relayed_write_bucket -= (int)num_written;
+ token_bucket_rw_dec(&global_relayed_bucket, num_read, num_written);
}
- global_read_bucket -= (int)num_read;
- global_write_bucket -= (int)num_written;
+ token_bucket_rw_dec(&global_bucket, num_read, num_written);
if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
- TO_OR_CONN(conn)->read_bucket -= (int)num_read;
- TO_OR_CONN(conn)->write_bucket -= (int)num_written;
+ or_connection_t *or_conn = TO_OR_CONN(conn);
+ token_bucket_rw_dec(&or_conn->bucket, num_read, num_written);
}
}
@@ -3144,14 +3062,14 @@ connection_consider_empty_read_buckets(connection_t *conn)
if (!connection_is_rate_limited(conn))
return; /* Always okay. */
- if (global_read_bucket <= 0) {
+ if (token_bucket_rw_get_read(&global_bucket) <= 0) {
reason = "global read bucket exhausted. Pausing.";
} else if (connection_counts_as_relayed_traffic(conn, approx_time()) &&
- global_relayed_read_bucket <= 0) {
+ token_bucket_rw_get_read(&global_relayed_bucket) <= 0) {
reason = "global relayed read bucket exhausted. Pausing.";
} else if (connection_speaks_cells(conn) &&
conn->state == OR_CONN_STATE_OPEN &&
- TO_OR_CONN(conn)->read_bucket <= 0) {
+ token_bucket_rw_get_read(&TO_OR_CONN(conn)->bucket) <= 0) {
reason = "connection read bucket exhausted. Pausing.";
} else
return; /* all good, no need to stop it */
@@ -3171,14 +3089,14 @@ connection_consider_empty_write_buckets(connection_t *conn)
if (!connection_is_rate_limited(conn))
return; /* Always okay. */
- if (global_write_bucket <= 0) {
+ if (token_bucket_rw_get_write(&global_bucket) <= 0) {
reason = "global write bucket exhausted. Pausing.";
} else if (connection_counts_as_relayed_traffic(conn, approx_time()) &&
- global_relayed_write_bucket <= 0) {
+ token_bucket_rw_get_write(&global_relayed_bucket) <= 0) {
reason = "global relayed write bucket exhausted. Pausing.";
} else if (connection_speaks_cells(conn) &&
conn->state == OR_CONN_STATE_OPEN &&
- TO_OR_CONN(conn)->write_bucket <= 0) {
+ token_bucket_rw_get_write(&TO_OR_CONN(conn)->bucket) <= 0) {
reason = "connection write bucket exhausted. Pausing.";
} else
return; /* all good, no need to stop it */
@@ -3188,180 +3106,79 @@ connection_consider_empty_write_buckets(connection_t *conn)
connection_stop_writing(conn);
}
-/** Initialize the global read bucket to options-\>BandwidthBurst. */
+/** Initialize the global buckets to the values configured in the
+ * options */
void
connection_bucket_init(void)
{
const or_options_t *options = get_options();
- /* start it at max traffic */
- global_read_bucket = (int)options->BandwidthBurst;
- global_write_bucket = (int)options->BandwidthBurst;
+ const uint32_t now_ts = monotime_coarse_get_stamp();
+ token_bucket_rw_init(&global_bucket,
+ (int32_t)options->BandwidthRate,
+ (int32_t)options->BandwidthBurst,
+ now_ts);
if (options->RelayBandwidthRate) {
- global_relayed_read_bucket = (int)options->RelayBandwidthBurst;
- global_relayed_write_bucket = (int)options->RelayBandwidthBurst;
+ token_bucket_rw_init(&global_relayed_bucket,
+ (int32_t)options->RelayBandwidthRate,
+ (int32_t)options->RelayBandwidthBurst,
+ now_ts);
} else {
- global_relayed_read_bucket = (int)options->BandwidthBurst;
- global_relayed_write_bucket = (int)options->BandwidthBurst;
+ token_bucket_rw_init(&global_relayed_bucket,
+ (int32_t)options->BandwidthRate,
+ (int32_t)options->BandwidthBurst,
+ now_ts);
}
}
-/** Refill a single <b>bucket</b> called <b>name</b> with bandwidth rate per
- * second <b>rate</b> and bandwidth burst <b>burst</b>, assuming that
- * <b>milliseconds_elapsed</b> milliseconds have passed since the last
- * call. */
-static void
-connection_bucket_refill_helper(int *bucket, int rate, int burst,
- int milliseconds_elapsed,
- const char *name)
+/** Update the global connection bucket settings to a new value. */
+void
+connection_bucket_adjust(const or_options_t *options)
{
- int starting_bucket = *bucket;
- if (starting_bucket < burst && milliseconds_elapsed > 0) {
- int64_t incr = (((int64_t)rate) * milliseconds_elapsed) / 1000;
- if ((burst - starting_bucket) < incr) {
- *bucket = burst; /* We would overflow the bucket; just set it to
- * the maximum. */
- } else {
- *bucket += (int)incr;
- if (*bucket > burst || *bucket < starting_bucket) {
- /* If we overflow the burst, or underflow our starting bucket,
- * cap the bucket value to burst. */
- /* XXXX this might be redundant now, but it doesn't show up
- * in profiles. Remove it after analysis. */
- *bucket = burst;
- }
- }
- log_debug(LD_NET,"%s now %d.", name, *bucket);
+ token_bucket_rw_adjust(&global_bucket,
+ (int32_t)options->BandwidthRate,
+ (int32_t)options->BandwidthBurst);
+ if (options->RelayBandwidthRate) {
+ token_bucket_rw_adjust(&global_relayed_bucket,
+ (int32_t)options->RelayBandwidthRate,
+ (int32_t)options->RelayBandwidthBurst);
+ } else {
+ token_bucket_rw_adjust(&global_relayed_bucket,
+ (int32_t)options->BandwidthRate,
+ (int32_t)options->BandwidthBurst);
}
}
/** Time has passed; increment buckets appropriately. */
void
-connection_bucket_refill(int milliseconds_elapsed, time_t now)
+connection_bucket_refill(time_t now, uint32_t now_ts)
{
- const or_options_t *options = get_options();
smartlist_t *conns = get_connection_array();
- int bandwidthrate, bandwidthburst, relayrate, relayburst;
-
- int prev_global_read = global_read_bucket;
- int prev_global_write = global_write_bucket;
- int prev_relay_read = global_relayed_read_bucket;
- int prev_relay_write = global_relayed_write_bucket;
- struct timeval tvnow; /*< Only used if TB_EMPTY events are enabled. */
-
- bandwidthrate = (int)options->BandwidthRate;
- bandwidthburst = (int)options->BandwidthBurst;
-
- if (options->RelayBandwidthRate) {
- relayrate = (int)options->RelayBandwidthRate;
- relayburst = (int)options->RelayBandwidthBurst;
- } else {
- relayrate = bandwidthrate;
- relayburst = bandwidthburst;
- }
-
- tor_assert(milliseconds_elapsed >= 0);
write_buckets_empty_last_second =
- global_relayed_write_bucket <= 0 || global_write_bucket <= 0;
+ token_bucket_rw_get_write(&global_bucket) <= 0 ||
+ token_bucket_rw_get_write(&global_relayed_bucket) <= 0;
/* refill the global buckets */
- connection_bucket_refill_helper(&global_read_bucket,
- bandwidthrate, bandwidthburst,
- milliseconds_elapsed,
- "global_read_bucket");
- connection_bucket_refill_helper(&global_write_bucket,
- bandwidthrate, bandwidthburst,
- milliseconds_elapsed,
- "global_write_bucket");
- connection_bucket_refill_helper(&global_relayed_read_bucket,
- relayrate, relayburst,
- milliseconds_elapsed,
- "global_relayed_read_bucket");
- connection_bucket_refill_helper(&global_relayed_write_bucket,
- relayrate, relayburst,
- milliseconds_elapsed,
- "global_relayed_write_bucket");
-
- /* If buckets were empty before and have now been refilled, tell any
- * interested controllers. */
- if (get_options()->TestingEnableTbEmptyEvent) {
- uint32_t global_read_empty_time, global_write_empty_time,
- relay_read_empty_time, relay_write_empty_time;
- tor_gettimeofday_cached(&tvnow);
- global_read_empty_time = bucket_millis_empty(prev_global_read,
- global_read_emptied, global_read_bucket,
- milliseconds_elapsed, &tvnow);
- global_write_empty_time = bucket_millis_empty(prev_global_write,
- global_write_emptied, global_write_bucket,
- milliseconds_elapsed, &tvnow);
- control_event_tb_empty("GLOBAL", global_read_empty_time,
- global_write_empty_time, milliseconds_elapsed);
- relay_read_empty_time = bucket_millis_empty(prev_relay_read,
- global_relayed_read_emptied,
- global_relayed_read_bucket,
- milliseconds_elapsed, &tvnow);
- relay_write_empty_time = bucket_millis_empty(prev_relay_write,
- global_relayed_write_emptied,
- global_relayed_write_bucket,
- milliseconds_elapsed, &tvnow);
- control_event_tb_empty("RELAY", relay_read_empty_time,
- relay_write_empty_time, milliseconds_elapsed);
- }
+ token_bucket_rw_refill(&global_bucket, now_ts);
+ token_bucket_rw_refill(&global_relayed_bucket, now_ts);
/* refill the per-connection buckets */
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
if (connection_speaks_cells(conn)) {
or_connection_t *or_conn = TO_OR_CONN(conn);
- int orbandwidthrate = or_conn->bandwidthrate;
- int orbandwidthburst = or_conn->bandwidthburst;
-
- int prev_conn_read = or_conn->read_bucket;
- int prev_conn_write = or_conn->write_bucket;
-
- if (connection_bucket_should_increase(or_conn->read_bucket, or_conn)) {
- connection_bucket_refill_helper(&or_conn->read_bucket,
- orbandwidthrate,
- orbandwidthburst,
- milliseconds_elapsed,
- "or_conn->read_bucket");
- }
- if (connection_bucket_should_increase(or_conn->write_bucket, or_conn)) {
- connection_bucket_refill_helper(&or_conn->write_bucket,
- orbandwidthrate,
- orbandwidthburst,
- milliseconds_elapsed,
- "or_conn->write_bucket");
- }
- /* If buckets were empty before and have now been refilled, tell any
- * interested controllers. */
- if (get_options()->TestingEnableTbEmptyEvent) {
- char *bucket;
- uint32_t conn_read_empty_time, conn_write_empty_time;
- tor_asprintf(&bucket, "ORCONN ID="U64_FORMAT,
- U64_PRINTF_ARG(or_conn->base_.global_identifier));
- conn_read_empty_time = bucket_millis_empty(prev_conn_read,
- or_conn->read_emptied_time,
- or_conn->read_bucket,
- milliseconds_elapsed, &tvnow);
- conn_write_empty_time = bucket_millis_empty(prev_conn_write,
- or_conn->write_emptied_time,
- or_conn->write_bucket,
- milliseconds_elapsed, &tvnow);
- control_event_tb_empty(bucket, conn_read_empty_time,
- conn_write_empty_time,
- milliseconds_elapsed);
- tor_free(bucket);
+ if (conn->state == OR_CONN_STATE_OPEN) {
+ token_bucket_rw_refill(&or_conn->bucket, now_ts);
}
}
if (conn->read_blocked_on_bw == 1 /* marked to turn reading back on now */
- && global_read_bucket > 0 /* and we're allowed to read */
+ && token_bucket_rw_get_read(&global_bucket) > 0 /* and we can read */
&& (!connection_counts_as_relayed_traffic(conn, now) ||
- global_relayed_read_bucket > 0) /* even if we're relayed traffic */
+ token_bucket_rw_get_read(&global_relayed_bucket) > 0)
&& (!connection_speaks_cells(conn) ||
conn->state != OR_CONN_STATE_OPEN ||
- TO_OR_CONN(conn)->read_bucket > 0)) {
+ token_bucket_rw_get_read(&TO_OR_CONN(conn)->bucket) > 0)) {
/* and either a non-cell conn or a cell conn with non-empty bucket */
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
"waking up conn (fd %d) for read", (int)conn->s));
@@ -3370,12 +3187,12 @@ connection_bucket_refill(int milliseconds_elapsed, time_t now)
}
if (conn->write_blocked_on_bw == 1
- && global_write_bucket > 0 /* and we're allowed to write */
+ && token_bucket_rw_get_write(&global_bucket) > 0 /* and we can write */
&& (!connection_counts_as_relayed_traffic(conn, now) ||
- global_relayed_write_bucket > 0) /* even if it's relayed traffic */
+ token_bucket_rw_get_write(&global_relayed_bucket) > 0)
&& (!connection_speaks_cells(conn) ||
conn->state != OR_CONN_STATE_OPEN ||
- TO_OR_CONN(conn)->write_bucket > 0)) {
+ token_bucket_rw_get_write(&TO_OR_CONN(conn)->bucket) > 0)) {
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
"waking up conn (fd %d) for write", (int)conn->s));
conn->write_blocked_on_bw = 0;
@@ -3384,22 +3201,6 @@ connection_bucket_refill(int milliseconds_elapsed, time_t now)
} SMARTLIST_FOREACH_END(conn);
}
-/** Is the <b>bucket</b> for connection <b>conn</b> low enough that we
- * should add another pile of tokens to it?
- */
-static int
-connection_bucket_should_increase(int bucket, or_connection_t *conn)
-{
- tor_assert(conn);
-
- if (conn->base_.state != OR_CONN_STATE_OPEN)
- return 0; /* only open connections play the rate limiting game */
- if (bucket >= conn->bandwidthburst)
- return 0;
-
- return 1;
-}
-
/** Read bytes from conn-\>s and process them.
*
* It calls connection_buf_read_from_socket() to bring in any new bytes,
@@ -3418,7 +3219,7 @@ connection_handle_read_impl(connection_t *conn)
if (conn->marked_for_close)
return 0; /* do nothing */
- conn->timestamp_lastread = approx_time();
+ conn->timestamp_last_read_allowed = approx_time();
switch (conn->type) {
case CONN_TYPE_OR_LISTENER:
@@ -3819,7 +3620,7 @@ update_send_buffer_size(tor_socket_t sock)
* when libevent tells us that conn wants to write, or below
* from connection_buf_add() when an entire TLS record is ready.
*
- * Update <b>conn</b>-\>timestamp_lastwritten to now, and call flush_buf
+ * Update <b>conn</b>-\>timestamp_last_write_allowed to now, and call flush_buf
* or flush_buf_tls appropriately. If it succeeds and there are no more
* more bytes on <b>conn</b>-\>outbuf, then call connection_finished_flushing
* on it too.
@@ -3852,7 +3653,7 @@ connection_handle_write_impl(connection_t *conn, int force)
return 0;
}
- conn->timestamp_lastwritten = now;
+ conn->timestamp_last_write_allowed = now;
/* Sometimes, "writable" means "connected". */
if (connection_state_is_connecting(conn)) {
@@ -4528,8 +4329,6 @@ alloc_http_authenticator(const char *authenticator)
static void
client_check_address_changed(tor_socket_t sock)
{
- struct sockaddr_storage out_sockaddr;
- socklen_t out_addr_len = (socklen_t) sizeof(out_sockaddr);
tor_addr_t out_addr, iface_addr;
tor_addr_t **last_interface_ip_ptr;
sa_family_t family;
@@ -4537,13 +4336,12 @@ client_check_address_changed(tor_socket_t sock)
if (!outgoing_addrs)
outgoing_addrs = smartlist_new();
- if (getsockname(sock, (struct sockaddr*)&out_sockaddr, &out_addr_len)<0) {
+ if (tor_addr_from_getsockname(&out_addr, sock) < 0) {
int e = tor_socket_errno(sock);
log_warn(LD_NET, "getsockname() to check for address change failed: %s",
tor_socket_strerror(e));
return;
}
- tor_addr_from_sockaddr(&out_addr, (struct sockaddr*)&out_sockaddr, NULL);
family = tor_addr_family(&out_addr);
if (family == AF_INET)
diff --git a/src/or/connection.h b/src/or/connection.h
index 6bc5a7cfd0..cfe31c3727 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -122,7 +122,9 @@ void connection_mark_all_noncontrol_connections(void);
ssize_t connection_bucket_write_limit(connection_t *conn, time_t now);
int global_write_bucket_low(connection_t *conn, size_t attempt, int priority);
void connection_bucket_init(void);
-void connection_bucket_refill(int seconds_elapsed, time_t now);
+void connection_bucket_adjust(const or_options_t *options);
+void connection_bucket_refill(time_t now,
+ uint32_t now_ts);
int connection_handle_read(connection_t *conn);
@@ -272,13 +274,6 @@ void connection_check_oos(int n_socks, int failed);
STATIC void connection_free_minimal(connection_t *conn);
/* Used only by connection.c and test*.c */
-uint32_t bucket_millis_empty(int tokens_before, uint32_t last_empty_time,
- int tokens_after, int milliseconds_elapsed,
- const struct timeval *tvnow);
-void connection_buckets_note_empty_ts(uint32_t *timestamp_var,
- int tokens_before,
- size_t tokens_removed,
- const struct timeval *tvnow);
MOCK_DECL(STATIC int,connection_connect_sockaddr,
(connection_t *conn,
const struct sockaddr *sa,
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index a47f044e08..955f942c50 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -611,6 +611,12 @@ static smartlist_t *pending_entry_connections = NULL;
static int untried_pending_connections = 0;
+/**
+ * Mainloop event to tell us to scan for pending connections that can
+ * be attached.
+ */
+static mainloop_event_t *attach_pending_entry_connections_ev = NULL;
+
/** Common code to connection_(ap|exit)_about_to_close. */
static void
connection_edge_about_to_close(edge_connection_t *edge_conn)
@@ -739,7 +745,7 @@ connection_ap_expire_beginning(void)
/* if it's an internal linked connection, don't yell its status. */
severity = (tor_addr_is_null(&base_conn->addr) && !base_conn->port)
? LOG_INFO : LOG_NOTICE;
- seconds_idle = (int)( now - base_conn->timestamp_lastread );
+ seconds_idle = (int)( now - base_conn->timestamp_last_read_allowed );
seconds_since_born = (int)( now - base_conn->timestamp_created );
if (base_conn->state == AP_CONN_STATE_OPEN)
@@ -825,7 +831,7 @@ connection_ap_expire_beginning(void)
mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
/* give our stream another 'cutoff' seconds to try */
- conn->base_.timestamp_lastread += cutoff;
+ conn->base_.timestamp_last_read_allowed += cutoff;
if (entry_conn->num_socks_retries < 250) /* avoid overflow */
entry_conn->num_socks_retries++;
/* move it back into 'pending' state, and try to attach. */
@@ -956,6 +962,14 @@ connection_ap_attach_pending(int retry)
untried_pending_connections = 0;
}
+static void
+attach_pending_entry_connections_cb(mainloop_event_t *ev, void *arg)
+{
+ (void)ev;
+ (void)arg;
+ connection_ap_attach_pending(0);
+}
+
/** Mark <b>entry_conn</b> as needing to get attached to a circuit.
*
* And <b>entry_conn</b> must be in AP_CONN_STATE_CIRCUIT_WAIT,
@@ -973,9 +987,13 @@ connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn,
if (conn->marked_for_close)
return;
- if (PREDICT_UNLIKELY(NULL == pending_entry_connections))
+ if (PREDICT_UNLIKELY(NULL == pending_entry_connections)) {
pending_entry_connections = smartlist_new();
-
+ }
+ if (PREDICT_UNLIKELY(NULL == attach_pending_entry_connections_ev)) {
+ attach_pending_entry_connections_ev = mainloop_event_postloop_new(
+ attach_pending_entry_connections_cb, NULL);
+ }
if (PREDICT_UNLIKELY(smartlist_contains(pending_entry_connections,
entry_conn))) {
log_warn(LD_BUG, "What?? pending_entry_connections already contains %p! "
@@ -999,14 +1017,7 @@ connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn,
untried_pending_connections = 1;
smartlist_add(pending_entry_connections, entry_conn);
- /* Work-around for bug 19969: we handle pending_entry_connections at
- * the end of run_main_loop_once(), but in many cases that function will
- * take a very long time, if ever, to finish its call to event_base_loop().
- *
- * So the fix is to tell it right now that it ought to finish its loop at
- * its next available opportunity.
- */
- tell_event_loop_to_run_external_code();
+ mainloop_event_activate(attach_pending_entry_connections_ev);
}
/** Mark <b>entry_conn</b> as no longer waiting for a circuit. */
@@ -1135,7 +1146,7 @@ connection_ap_detach_retriable(entry_connection_t *conn,
int reason)
{
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason);
- ENTRY_TO_CONN(conn)->timestamp_lastread = time(NULL);
+ ENTRY_TO_CONN(conn)->timestamp_last_read_allowed = time(NULL);
/* Roll back path bias use state so that we probe the circuit
* if nothing else succeeds on it */
@@ -4165,5 +4176,6 @@ connection_edge_free_all(void)
untried_pending_connections = 0;
smartlist_free(pending_entry_connections);
pending_entry_connections = NULL;
+ mainloop_event_free(attach_pending_entry_connections_ev);
}
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 267463312c..7723d9d2bd 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -793,18 +793,10 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset,
(int)options->BandwidthBurst, 1, INT32_MAX);
}
- conn->bandwidthrate = rate;
- conn->bandwidthburst = burst;
- if (reset) { /* set up the token buckets to be full */
- conn->read_bucket = conn->write_bucket = burst;
- return;
+ token_bucket_rw_adjust(&conn->bucket, rate, burst);
+ if (reset) {
+ token_bucket_rw_reset(&conn->bucket, monotime_coarse_get_stamp());
}
- /* If the new token bucket is smaller, take out the extra tokens.
- * (If it's larger, don't -- the buckets can grow to reach the cap.) */
- if (conn->read_bucket > burst)
- conn->read_bucket = burst;
- if (conn->write_bucket > burst)
- conn->write_bucket = burst;
}
/** Either our set of relays or our per-conn rate limits have changed.
diff --git a/src/or/control.c b/src/or/control.c
index 028339f498..050509eccf 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -83,8 +83,6 @@
#include <sys/resource.h>
#endif
-#include <event2/event.h>
-
#include "crypto_s2k.h"
#include "procmon.h"
@@ -216,7 +214,7 @@ static void orconn_target_get_name(char *buf, size_t len,
static int get_cached_network_liveness(void);
static void set_cached_network_liveness(int liveness);
-static void flush_queued_events_cb(evutil_socket_t fd, short what, void *arg);
+static void flush_queued_events_cb(mainloop_event_t *event, void *arg);
static char * download_status_to_string(const download_status_t *dl);
@@ -691,7 +689,7 @@ static tor_mutex_t *queued_control_events_lock = NULL;
/** An event that should fire in order to flush the contents of
* queued_control_events. */
-static struct event *flush_queued_events_event = NULL;
+static mainloop_event_t *flush_queued_events_event = NULL;
void
control_initialize_event_queue(void)
@@ -703,9 +701,8 @@ control_initialize_event_queue(void)
if (flush_queued_events_event == NULL) {
struct event_base *b = tor_libevent_get_base();
if (b) {
- flush_queued_events_event = tor_event_new(b,
- -1, 0, flush_queued_events_cb,
- NULL);
+ flush_queued_events_event =
+ mainloop_event_new(flush_queued_events_cb, NULL);
tor_assert(flush_queued_events_event);
}
}
@@ -781,7 +778,7 @@ queue_control_event_string,(uint16_t event, char *msg))
*/
if (activate_event) {
tor_assert(flush_queued_events_event);
- event_active(flush_queued_events_event, EV_READ, 1);
+ mainloop_event_activate(flush_queued_events_event);
}
}
@@ -863,10 +860,9 @@ queued_events_flush_all(int force)
/** Libevent callback: Flushes pending events to controllers that are
* interested in them. */
static void
-flush_queued_events_cb(evutil_socket_t fd, short what, void *arg)
+flush_queued_events_cb(mainloop_event_t *event, void *arg)
{
- (void) fd;
- (void) what;
+ (void) event;
(void) arg;
queued_events_flush_all(0);
}
@@ -1218,7 +1214,6 @@ static const struct control_event_t control_event_table[] = {
{ EVENT_CONF_CHANGED, "CONF_CHANGED"},
{ EVENT_CONN_BW, "CONN_BW" },
{ EVENT_CELL_STATS, "CELL_STATS" },
- { EVENT_TB_EMPTY, "TB_EMPTY" },
{ EVENT_CIRC_BANDWIDTH_USED, "CIRC_BW" },
{ EVENT_TRANSPORT_LAUNCHED, "TRANSPORT_LAUNCHED" },
{ EVENT_HS_DESC, "HS_DESC" },
@@ -6084,28 +6079,6 @@ control_event_circuit_cell_stats(void)
return 0;
}
-/** Tokens in <b>bucket</b> have been refilled: the read bucket was empty
- * for <b>read_empty_time</b> millis, the write bucket was empty for
- * <b>write_empty_time</b> millis, and buckets were last refilled
- * <b>milliseconds_elapsed</b> millis ago. Only emit TB_EMPTY event if
- * either read or write bucket have been empty before. */
-int
-control_event_tb_empty(const char *bucket, uint32_t read_empty_time,
- uint32_t write_empty_time,
- int milliseconds_elapsed)
-{
- if (get_options()->TestingEnableTbEmptyEvent &&
- EVENT_IS_INTERESTING(EVENT_TB_EMPTY) &&
- (read_empty_time > 0 || write_empty_time > 0)) {
- send_control_event(EVENT_TB_EMPTY,
- "650 TB_EMPTY %s READ=%d WRITTEN=%d "
- "LAST=%d\r\n",
- bucket, read_empty_time, write_empty_time,
- milliseconds_elapsed);
- }
- return 0;
-}
-
/* about 5 minutes worth. */
#define N_BW_EVENTS_TO_CACHE 300
/* Index into cached_bw_events to next write. */
@@ -7589,22 +7562,38 @@ control_event_hs_descriptor_upload_failed(const char *id_digest,
void
control_free_all(void)
{
+ smartlist_t *queued_events = NULL;
+
if (authentication_cookie) /* Free the auth cookie */
tor_free(authentication_cookie);
if (detached_onion_services) { /* Free the detached onion services */
SMARTLIST_FOREACH(detached_onion_services, char *, cp, tor_free(cp));
smartlist_free(detached_onion_services);
}
- if (queued_control_events) {
- SMARTLIST_FOREACH(queued_control_events, queued_event_t *, ev,
- queued_event_free(ev));
- smartlist_free(queued_control_events);
+
+ if (queued_control_events_lock) {
+ tor_mutex_acquire(queued_control_events_lock);
+ flush_queued_event_pending = 0;
+ queued_events = queued_control_events;
queued_control_events = NULL;
+ tor_mutex_release(queued_control_events_lock);
+ }
+ if (queued_events) {
+ SMARTLIST_FOREACH(queued_events, queued_event_t *, ev,
+ queued_event_free(ev));
+ smartlist_free(queued_events);
}
if (flush_queued_events_event) {
- tor_event_free(flush_queued_events_event);
+ mainloop_event_free(flush_queued_events_event);
flush_queued_events_event = NULL;
}
+ bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
+ notice_bootstrap_percent = 0;
+ bootstrap_problems = 0;
+ authentication_cookie_is_set = 0;
+ global_event_mask = 0;
+ disable_log_messages = 0;
+ memset(last_sent_bootstrap_message, 0, sizeof(last_sent_bootstrap_message));
}
#ifdef TOR_UNIT_TESTS
diff --git a/src/or/control.h b/src/or/control.h
index 28ffeaed86..2fd3c553f3 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -59,9 +59,6 @@ int control_event_circ_bandwidth_used(void);
int control_event_conn_bandwidth(connection_t *conn);
int control_event_conn_bandwidth_used(void);
int control_event_circuit_cell_stats(void);
-int control_event_tb_empty(const char *bucket, uint32_t read_empty_time,
- uint32_t write_empty_time,
- int milliseconds_elapsed);
void control_event_logmsg(int severity, uint32_t domain, const char *msg);
int control_event_descriptors_changed(smartlist_t *routers);
int control_event_address_mapped(const char *from, const char *to,
@@ -194,7 +191,7 @@ void control_free_all(void);
#define EVENT_CONF_CHANGED 0x0019
#define EVENT_CONN_BW 0x001A
#define EVENT_CELL_STATS 0x001B
-#define EVENT_TB_EMPTY 0x001C
+/* UNUSED : 0x001C */
#define EVENT_CIRC_BANDWIDTH_USED 0x001D
#define EVENT_TRANSPORT_LAUNCHED 0x0020
#define EVENT_HS_DESC 0x0021
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 50761dd4d3..083691c4f6 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -30,8 +30,6 @@
#include "router.h"
#include "workqueue.h"
-#include <event2/event.h>
-
static void queue_pending_tasks(void);
typedef struct worker_state_s {
@@ -69,22 +67,12 @@ worker_state_free_void(void *arg)
static replyqueue_t *replyqueue = NULL;
static threadpool_t *threadpool = NULL;
-static struct event *reply_event = NULL;
static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT;
static int total_pending_tasks = 0;
static int max_pending_tasks = 128;
-static void
-replyqueue_process_cb(evutil_socket_t sock, short events, void *arg)
-{
- replyqueue_t *rq = arg;
- (void) sock;
- (void) events;
- replyqueue_process(rq);
-}
-
/** Initialize the cpuworker subsystem. It is OK to call this more than once
* during Tor's lifetime.
*/
@@ -94,14 +82,6 @@ cpu_init(void)
if (!replyqueue) {
replyqueue = replyqueue_new(0);
}
- if (!reply_event) {
- reply_event = tor_event_new(tor_libevent_get_base(),
- replyqueue_get_socket(replyqueue),
- EV_READ|EV_PERSIST,
- replyqueue_process_cb,
- replyqueue);
- event_add(reply_event, NULL);
- }
if (!threadpool) {
/*
In our threadpool implementation, half the threads are permissive and
@@ -115,7 +95,12 @@ cpu_init(void)
worker_state_new,
worker_state_free_void,
NULL);
+
+ int r = threadpool_register_reply_event(threadpool, NULL);
+
+ tor_assert(r == 0);
}
+
/* Total voodoo. Can we make this more sensible? */
max_pending_tasks = get_num_cpus(get_options()) * 64;
crypto_seed_weak_rng(&request_sample_rng);
@@ -547,7 +532,7 @@ assign_onionskin_to_cpuworker(or_circuit_t *circ,
return 0;
}
- if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest))
+ if (!channel_is_client(circ->p_chan))
rep_hist_note_circuit_handshake_assigned(onionskin->handshake_type);
should_time = should_time_request(onionskin->handshake_type);
diff --git a/src/or/directory.c b/src/or/directory.c
index 29d091af38..c419b61d02 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -2437,7 +2437,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
* and the date header. (We used to check now-date_header, but that's
* inaccurate if we spend a lot of time downloading.)
*/
- apparent_skew = conn->base_.timestamp_lastwritten - date_header;
+ apparent_skew = conn->base_.timestamp_last_write_allowed - date_header;
if (labs(apparent_skew)>ALLOW_DIRECTORY_TIME_SKEW) {
int trusted = router_digest_is_trusted_dir(conn->identity_digest);
clock_skew_warning(TO_CONN(conn), apparent_skew, trusted, LD_HTTP,
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index f0333e288f..68727f0718 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -858,13 +858,13 @@ directory_remove_invalid(void)
SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) {
const char *msg = NULL;
+ const char *description;
routerinfo_t *ent = node->ri;
- char description[NODE_DESC_BUF_LEN];
uint32_t r;
if (!ent)
continue;
r = dirserv_router_get_status(ent, &msg, LOG_INFO);
- router_get_description(description, ent);
+ description = router_describe(ent);
if (r & FP_REJECT) {
log_info(LD_DIRSERV, "Router %s is now rejected: %s",
description, msg?msg:"");
@@ -1423,7 +1423,7 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
* tests aren't instant. If we haven't been running long enough,
* trust the relay. */
- if (stats_n_seconds_working >
+ if (get_uptime() >
get_options()->MinUptimeHidServDirectoryV2 * 1.1)
uptime = MIN(rep_hist_get_uptime(router->cache_info.identity_digest, now),
real_uptime(router, now));
@@ -3393,7 +3393,8 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
tor_assert(node);
if (options->AuthDirTestEd25519LinkKeys &&
- node_supports_ed25519_link_authentication(node, 1)) {
+ node_supports_ed25519_link_authentication(node, 1) &&
+ router->cache_info.signing_key_cert) {
ed_id_key = &router->cache_info.signing_key_cert->signing_key;
} else {
ed_id_key = NULL;
diff --git a/src/or/dos.c b/src/or/dos.c
index 4d1797eece..2cb3470582 100644
--- a/src/or/dos.c
+++ b/src/or/dos.c
@@ -15,6 +15,7 @@
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
+#include "relay.h"
#include "router.h"
#include "dos.h"
@@ -622,10 +623,12 @@ dos_log_heartbeat(void)
char *conn_msg = NULL;
char *cc_msg = NULL;
char *single_hop_client_msg = NULL;
+ char *circ_stats_msg = NULL;
- if (!dos_is_enabled()) {
- goto end;
- }
+ /* Stats number coming from relay.c append_cell_to_circuit_queue(). */
+ tor_asprintf(&circ_stats_msg,
+ " %" PRIu64 " circuits killed with too many cells.",
+ stats_n_circ_max_cell_reached);
if (dos_cc_enabled) {
tor_asprintf(&cc_msg,
@@ -647,7 +650,8 @@ dos_log_heartbeat(void)
}
log_notice(LD_HEARTBEAT,
- "DoS mitigation since startup:%s%s%s",
+ "DoS mitigation since startup:%s%s%s%s",
+ circ_stats_msg,
(cc_msg != NULL) ? cc_msg : " [cc not enabled]",
(conn_msg != NULL) ? conn_msg : " [conn not enabled]",
(single_hop_client_msg != NULL) ? single_hop_client_msg : "");
@@ -655,8 +659,7 @@ dos_log_heartbeat(void)
tor_free(conn_msg);
tor_free(cc_msg);
tor_free(single_hop_client_msg);
-
- end:
+ tor_free(circ_stats_msg);
return;
}
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 54638810fa..96e6ccaace 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -2335,7 +2335,7 @@ entry_guard_cancel(circuit_guard_state_t **guard_state_p)
}
/**
- * Called by the circuit building module when a circuit has succeeded:
+ * Called by the circuit building module when a circuit has failed:
* informs the guards code that the guard in *<b>guard_state_p</b> is
* not working, and advances the state of the guard module.
*/
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 0ff1c6ce0d..2c917c564d 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -628,8 +628,7 @@ geoip_note_client_seen(geoip_client_action_t action,
/* Only remember statistics if the DoS mitigation subsystem is enabled. If
* not, only if as entry guard or as bridge. */
if (!dos_enabled()) {
- if (!options->EntryStatistics &&
- (!(options->BridgeRelay && options->BridgeRecordUsageByCountry))) {
+ if (!options->EntryStatistics && !should_record_bridge_info(options)) {
return;
}
}
@@ -1881,5 +1880,8 @@ geoip_free_all(void)
clear_geoip_db();
tor_free(bridge_stats_extrainfo);
+
+ memset(geoip_digest, 0, sizeof(geoip_digest));
+ memset(geoip6_digest, 0, sizeof(geoip6_digest));
}
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 4dc35f68d0..7261cf8002 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -866,7 +866,7 @@ hibernate_end(hibernate_state_t new_state)
hibernate_state = new_state;
hibernate_end_time = 0; /* no longer hibernating */
- stats_n_seconds_working = 0; /* reset published uptime */
+ reset_uptime(); /* reset published uptime */
}
/** A wrapper around hibernate_begin, for when we get SIGINT. */
diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c
index 5244cfa3dd..ad92521d34 100644
--- a/src/or/hs_cell.c
+++ b/src/or/hs_cell.c
@@ -369,7 +369,7 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell,
crypto_cipher_free(cipher);
offset += encoded_enc_cell_len;
/* Compute MAC from the above and put it in the buffer. This function will
- * make the adjustment to the encryptled_len to ommit the MAC length. */
+ * make the adjustment to the encrypted_len to omit the MAC length. */
compute_introduce_mac(encoded_cell, encoded_cell_len,
encrypted, encrypted_len,
keys.mac_key, sizeof(keys.mac_key),
diff --git a/src/or/hs_client.c b/src/or/hs_client.c
index d3978f22f0..20963cd453 100644
--- a/src/or/hs_client.c
+++ b/src/or/hs_client.c
@@ -17,7 +17,6 @@
#include "hs_descriptor.h"
#include "hs_cache.h"
#include "hs_cell.h"
-#include "hs_ident.h"
#include "config.h"
#include "directory.h"
#include "hs_client.h"
@@ -29,7 +28,6 @@
#include "connection.h"
#include "nodelist.h"
#include "circpathbias.h"
-#include "connection.h"
#include "hs_ntor.h"
#include "circuitbuild.h"
#include "networkstatus.h"
@@ -1439,8 +1437,8 @@ hs_client_desc_has_arrived(const hs_ident_dir_conn_t *ident)
* connection is considered "fresh" and can continue without being closed
* too early. */
base_conn->timestamp_created = now;
- base_conn->timestamp_lastread = now;
- base_conn->timestamp_lastwritten = now;
+ base_conn->timestamp_last_read_allowed = now;
+ base_conn->timestamp_last_write_allowed = now;
/* Change connection's state into waiting for a circuit. */
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
diff --git a/src/or/hs_common.c b/src/or/hs_common.c
index 10b56c0baa..24eb7a104a 100644
--- a/src/or/hs_common.c
+++ b/src/or/hs_common.c
@@ -28,7 +28,6 @@
#include "rendservice.h"
#include "routerset.h"
#include "router.h"
-#include "routerset.h"
#include "shared_random.h"
#include "shared_random_state.h"
diff --git a/src/or/hs_intropoint.c b/src/or/hs_intropoint.c
index 8c6453e6fd..3274e8e9c0 100644
--- a/src/or/hs_intropoint.c
+++ b/src/or/hs_intropoint.c
@@ -12,7 +12,6 @@
#include "config.h"
#include "circuitlist.h"
#include "circuituse.h"
-#include "config.h"
#include "relay.h"
#include "rendmid.h"
#include "rephist.h"
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 6fa9ec6b16..ba8abc4237 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -31,7 +31,6 @@
#include "hs_common.h"
#include "hs_config.h"
#include "hs_control.h"
-#include "hs_circuit.h"
#include "hs_descriptor.h"
#include "hs_ident.h"
#include "hs_intropoint.h"
diff --git a/src/or/include.am b/src/or/include.am
index c1e23dd3d9..9a68df5c3e 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -91,6 +91,7 @@ LIBTOR_A_SOURCES = \
src/or/policies.c \
src/or/reasons.c \
src/or/relay.c \
+ src/or/relay_crypto.c \
src/or/rendcache.c \
src/or/rendclient.c \
src/or/rendcommon.c \
@@ -238,6 +239,7 @@ ORHEADERS = \
src/or/proto_socks.h \
src/or/reasons.h \
src/or/relay.h \
+ src/or/relay_crypto.h \
src/or/rendcache.h \
src/or/rendclient.h \
src/or/rendcommon.h \
diff --git a/src/or/keypin.c b/src/or/keypin.c
index 1698dc184f..97e16c1f78 100644
--- a/src/or/keypin.c
+++ b/src/or/keypin.c
@@ -12,7 +12,7 @@
#include "orconfig.h"
#include "compat.h"
-#include "crypto.h"
+#include "crypto_digest.h"
#include "crypto_format.h"
#include "di_ops.h"
#include "ht.h"
@@ -289,8 +289,10 @@ static int keypin_journal_fd = -1;
int
keypin_open_journal(const char *fname)
{
- /* O_SYNC ??*/
- int fd = tor_open_cloexec(fname, O_WRONLY|O_CREAT|O_BINARY, 0600);
+#ifndef O_SYNC
+#define O_SYNC 0
+#endif
+ int fd = tor_open_cloexec(fname, O_WRONLY|O_CREAT|O_BINARY|O_SYNC, 0600);
if (fd < 0)
goto err;
@@ -417,10 +419,11 @@ keypin_load_journal_impl(const char *data, size_t size)
++n_entries;
}
- int severity = (n_corrupt_lines || n_duplicates) ? LOG_WARN : LOG_INFO;
+ int severity = (n_corrupt_lines || n_duplicates) ? LOG_NOTICE : LOG_INFO;
tor_log(severity, LD_DIRSERV,
"Loaded %d entries from keypin journal. "
- "Found %d corrupt lines, %d duplicates, and %d conflicts.",
+ "Found %d corrupt lines (ignored), %d duplicates (harmless), "
+ "and %d conflicts (resolved in favor or more recent entry).",
n_entries, n_corrupt_lines, n_duplicates, n_conflicts);
return 0;
diff --git a/src/or/main.c b/src/or/main.c
index d1f0044095..a852d3273d 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -133,7 +133,7 @@ void evdns_shutdown(int);
#ifdef HAVE_RUST
// helper function defined in Rust to output a log message indicating if tor is
// running with Rust enabled. See src/rust/tor_util
-char *rust_welcome_string(void);
+void rust_log_welcome_string(void);
#endif
/********* PROTOTYPES **********/
@@ -152,19 +152,19 @@ static void shutdown_did_not_work_callback(evutil_socket_t fd, short event,
void *arg) ATTR_NORETURN;
/********* START VARIABLES **********/
-int global_read_bucket; /**< Max number of bytes I can read this second. */
-int global_write_bucket; /**< Max number of bytes I can write this second. */
-
-/** Max number of relayed (bandwidth class 1) bytes I can read this second. */
-int global_relayed_read_bucket;
-/** Max number of relayed (bandwidth class 1) bytes I can write this second. */
-int global_relayed_write_bucket;
-/** What was the read bucket before the last second_elapsed_callback() call?
- * (used to determine how many bytes we've read). */
-static int stats_prev_global_read_bucket;
+
+/* Token bucket for all traffic. */
+token_bucket_rw_t global_bucket;
+
+/* Token bucket for relayed traffic. */
+token_bucket_rw_t global_relayed_bucket;
+
+/** What was the read/write bucket before the last second_elapsed_callback()
+ * call? (used to determine how many bytes we've read). */
+static size_t stats_prev_global_read_bucket;
/** What was the write bucket before the last second_elapsed_callback() call?
* (used to determine how many bytes we've written). */
-static int stats_prev_global_write_bucket;
+static size_t stats_prev_global_write_bucket;
/* DOCDOC stats_prev_n_read */
static uint64_t stats_prev_n_read = 0;
@@ -179,7 +179,7 @@ static uint64_t stats_n_bytes_written = 0;
/** What time did this process start up? */
time_t time_of_process_start = 0;
/** How many seconds have we been running? */
-long stats_n_seconds_working = 0;
+static long stats_n_seconds_working = 0;
/** How many times have we returned from the main loop successfully? */
static uint64_t stats_n_main_loop_successes = 0;
/** How many times have we received an error from the main loop? */
@@ -410,6 +410,27 @@ connection_unlink(connection_t *conn)
connection_free(conn);
}
+/**
+ * Callback: used to activate read events for all linked connections, so
+ * libevent knows to call their read callbacks. This callback run as a
+ * postloop event, so that the events _it_ activates don't happen until
+ * Libevent has a chance to check for other events.
+ */
+static void
+schedule_active_linked_connections_cb(mainloop_event_t *event, void *arg)
+{
+ (void)event;
+ (void)arg;
+
+ /* All active linked conns should get their read events activated,
+ * so that libevent knows to run their callbacks. */
+ SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn,
+ event_active(conn->read_event, EV_READ, 1));
+}
+
+/** Event that invokes schedule_active_linked_connections_cb. */
+static mainloop_event_t *schedule_active_linked_connections_event = NULL;
+
/** Initialize the global connection list, closeable connection list,
* and active connection list. */
STATIC void
@@ -710,20 +731,6 @@ connection_should_read_from_linked_conn(connection_t *conn)
return 0;
}
-/** If we called event_base_loop() and told it to never stop until it
- * runs out of events, now we've changed our mind: tell it we want it to
- * exit once the current round of callbacks is done, so that we can
- * run external code, and then return to the main loop. */
-void
-tell_event_loop_to_run_external_code(void)
-{
- if (!called_loop_once) {
- struct timeval tv = { 0, 0 };
- tor_event_base_loopexit(tor_libevent_get_base(), &tv);
- called_loop_once = 1; /* hack to avoid adding more exit events */
- }
-}
-
/** Event to run 'shutdown did not work callback'. */
static struct event *shutdown_did_not_work_event = NULL;
@@ -779,8 +786,9 @@ tor_shutdown_event_loop_and_exit(int exitcode)
shutdown_did_not_work_callback, NULL);
event_add(shutdown_did_not_work_event, &ten_seconds);
- /* Unlike loopexit, loopbreak prevents other callbacks from running. */
- tor_event_base_loopbreak(tor_libevent_get_base());
+ /* Unlike exit_loop_after_delay(), exit_loop_after_callback
+ * prevents other callbacks from running. */
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
}
/** Return true iff tor_shutdown_event_loop_and_exit() has been called. */
@@ -802,10 +810,7 @@ connection_start_reading_from_linked_conn(connection_t *conn)
if (!conn->active_on_link) {
conn->active_on_link = 1;
smartlist_add(active_linked_connection_lst, conn);
- /* make sure that the event_base_loop() function exits at
- * the end of its run through the current connections, so we can
- * activate read events for linked connections. */
- tell_event_loop_to_run_external_code();
+ mainloop_event_activate(schedule_active_linked_connections_event);
} else {
tor_assert(smartlist_contains(active_linked_connection_lst, conn));
}
@@ -1008,7 +1013,8 @@ conn_close_if_marked(int i)
LOG_FN_CONN(conn, (LOG_INFO,LD_NET,
"Holding conn (fd %d) open for more flushing.",
(int)conn->s));
- conn->timestamp_lastwritten = now; /* reset so we can flush more */
+ conn->timestamp_last_write_allowed = now; /* reset so we can flush
+ * more */
} else if (sz == 0) {
/* Also, retval==0. If we get here, we didn't want to write anything
* (because of rate-limiting) and we didn't. */
@@ -1059,9 +1065,8 @@ conn_close_if_marked(int i)
* reason.
*/
static void
-directory_all_unreachable_cb(evutil_socket_t fd, short event, void *arg)
+directory_all_unreachable_cb(mainloop_event_t *event, void *arg)
{
- (void)fd;
(void)event;
(void)arg;
@@ -1081,7 +1086,7 @@ directory_all_unreachable_cb(evutil_socket_t fd, short event, void *arg)
control_event_general_error("DIR_ALL_UNREACHABLE");
}
-static struct event *directory_all_unreachable_cb_event = NULL;
+static mainloop_event_t *directory_all_unreachable_cb_event = NULL;
/** We've just tried every dirserver we know about, and none of
* them were reachable. Assume the network is down. Change state
@@ -1094,16 +1099,15 @@ directory_all_unreachable(time_t now)
{
(void)now;
- stats_n_seconds_working=0; /* reset it */
+ reset_uptime(); /* reset it */
if (!directory_all_unreachable_cb_event) {
directory_all_unreachable_cb_event =
- tor_event_new(tor_libevent_get_base(),
- -1, EV_READ, directory_all_unreachable_cb, NULL);
+ mainloop_event_new(directory_all_unreachable_cb, NULL);
tor_assert(directory_all_unreachable_cb_event);
}
- event_active(directory_all_unreachable_cb_event, EV_READ, 1);
+ mainloop_event_activate(directory_all_unreachable_cb_event);
}
/** This function is called whenever we successfully pull down some new
@@ -1143,7 +1147,7 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs)
if (server_mode(options) && !net_is_disabled() && !from_cache &&
(have_completed_a_circuit() || !any_predicted_circuits(now)))
- consider_testing_reachability(1, 1);
+ router_do_reachability_checks(1, 1);
}
/** Perform regular maintenance tasks for a single connection. This
@@ -1159,7 +1163,7 @@ run_connection_housekeeping(int i, time_t now)
channel_t *chan = NULL;
int have_any_circuits;
int past_keepalive =
- now >= conn->timestamp_lastwritten + options->KeepalivePeriod;
+ now >= conn->timestamp_last_write_allowed + options->KeepalivePeriod;
if (conn->outbuf && !connection_get_outbuf_len(conn) &&
conn->type == CONN_TYPE_OR)
@@ -1174,10 +1178,10 @@ run_connection_housekeeping(int i, time_t now)
* if a server or received if a client) for 5 min */
if (conn->type == CONN_TYPE_DIR &&
((DIR_CONN_IS_SERVER(conn) &&
- conn->timestamp_lastwritten
+ conn->timestamp_last_write_allowed
+ options->TestingDirConnectionMaxStall < now) ||
(!DIR_CONN_IS_SERVER(conn) &&
- conn->timestamp_lastread
+ conn->timestamp_last_read_allowed
+ options->TestingDirConnectionMaxStall < now))) {
log_info(LD_DIR,"Expiring wedged directory conn (fd %d, purpose %d)",
(int)conn->s, conn->purpose);
@@ -1253,13 +1257,14 @@ run_connection_housekeeping(int i, time_t now)
connection_or_close_normally(TO_OR_CONN(conn), 0);
} else if (
now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 &&
- now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) {
+ now >=
+ conn->timestamp_last_write_allowed + options->KeepalivePeriod*10) {
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,
"Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to "
"flush; %d seconds since last write)",
(int)conn->s, conn->address, conn->port,
(int)connection_get_outbuf_len(conn),
- (int)(now-conn->timestamp_lastwritten));
+ (int)(now-conn->timestamp_last_write_allowed));
connection_or_close_normally(TO_OR_CONN(conn), 0);
} else if (past_keepalive && !connection_get_outbuf_len(conn)) {
/* send a padding cell */
@@ -1334,7 +1339,6 @@ CALLBACK(retry_listeners);
CALLBACK(expire_old_ciruits_serverside);
CALLBACK(check_dns_honesty);
CALLBACK(write_bridge_ns);
-CALLBACK(check_fw_helper_app);
CALLBACK(heartbeat);
CALLBACK(clean_consdiffmgr);
CALLBACK(reset_padding_counts);
@@ -1370,7 +1374,6 @@ static periodic_event_item_t periodic_events[] = {
CALLBACK(expire_old_ciruits_serverside),
CALLBACK(check_dns_honesty),
CALLBACK(write_bridge_ns),
- CALLBACK(check_fw_helper_app),
CALLBACK(heartbeat),
CALLBACK(clean_consdiffmgr),
CALLBACK(reset_padding_counts),
@@ -1473,6 +1476,7 @@ teardown_periodic_events(void)
for (i = 0; periodic_events[i].name; ++i) {
periodic_event_destroy(&periodic_events[i]);
}
+ periodic_events_initialized = 0;
}
/**
@@ -1940,14 +1944,14 @@ reset_padding_counts_callback(time_t now, const or_options_t *options)
return REPHIST_CELL_PADDING_COUNTS_INTERVAL;
}
+static int should_init_bridge_stats = 1;
+
/**
* Periodic callback: Write bridge statistics to disk if appropriate.
*/
static int
record_bridge_stats_callback(time_t now, const or_options_t *options)
{
- static int should_init_bridge_stats = 1;
-
/* 1h. Check whether we should write bridge statistics to disk.
*/
if (should_record_bridge_info(options)) {
@@ -2062,8 +2066,8 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options)
if (server_mode(options) &&
(have_completed_a_circuit() || !any_predicted_circuits(now)) &&
!net_is_disabled()) {
- if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
- consider_testing_reachability(1, dirport_reachability_count==0);
+ if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
+ router_do_reachability_checks(1, dirport_reachability_count==0);
if (++dirport_reachability_count > 5)
dirport_reachability_count = 0;
return 1;
@@ -2140,6 +2144,8 @@ expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options)
return 11;
}
+static int dns_honesty_first_time = 1;
+
/**
* Periodic event: if we're an exit, see if our DNS server is telling us
* obvious lies.
@@ -2155,10 +2161,9 @@ check_dns_honesty_callback(time_t now, const or_options_t *options)
router_my_exit_policy_is_reject_star())
return PERIODIC_EVENT_NO_UPDATE;
- static int first_time = 1;
- if (first_time) {
+ if (dns_honesty_first_time) {
/* Don't launch right when we start */
- first_time = 0;
+ dns_honesty_first_time = 0;
return crypto_rand_int_range(60, 180);
}
@@ -2182,32 +2187,7 @@ write_bridge_ns_callback(time_t now, const or_options_t *options)
return PERIODIC_EVENT_NO_UPDATE;
}
-/**
- * Periodic callback: poke the tor-fw-helper app if we're using one.
- */
-static int
-check_fw_helper_app_callback(time_t now, const or_options_t *options)
-{
- if (net_is_disabled() ||
- ! server_mode(options) ||
- ! options->PortForwarding ||
- options->NoExec) {
- return PERIODIC_EVENT_NO_UPDATE;
- }
- /* 11. check the port forwarding app */
-
-#define PORT_FORWARDING_CHECK_INTERVAL 5
- smartlist_t *ports_to_forward = get_list_of_ports_to_forward();
- if (ports_to_forward) {
- tor_check_port_forwarding(options->PortForwardingHelper,
- ports_to_forward,
- now);
-
- SMARTLIST_FOREACH(ports_to_forward, char *, cp, tor_free(cp));
- smartlist_free(ports_to_forward);
- }
- return PORT_FORWARDING_CHECK_INTERVAL;
-}
+static int heartbeat_callback_first_time = 1;
/**
* Periodic callback: write the heartbeat message in the logs.
@@ -2218,16 +2198,14 @@ check_fw_helper_app_callback(time_t now, const or_options_t *options)
static int
heartbeat_callback(time_t now, const or_options_t *options)
{
- static int first = 1;
-
/* Check if heartbeat is disabled */
if (!options->HeartbeatPeriod) {
return PERIODIC_EVENT_NO_UPDATE;
}
/* Skip the first one. */
- if (first) {
- first = 0;
+ if (heartbeat_callback_first_time) {
+ heartbeat_callback_first_time = 0;
return options->HeartbeatPeriod;
}
@@ -2279,6 +2257,8 @@ hs_service_callback(time_t now, const or_options_t *options)
static periodic_timer_t *second_timer = NULL;
/** Number of libevent errors in the last second: we die if we get too many. */
static int n_libevent_errors = 0;
+/** Last time that second_elapsed_callback was called. */
+static time_t current_second = 0;
/** Libevent callback: invoked once every second. */
static void
@@ -2287,7 +2267,6 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
/* XXXX This could be sensibly refactored into multiple callbacks, and we
* could use Libevent's timers for this rather than checking the current
* time against a bunch of timeouts every second. */
- static time_t current_second = 0;
time_t now;
size_t bytes_written;
size_t bytes_read;
@@ -2319,8 +2298,8 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
!net_is_disabled() &&
seconds_elapsed > 0 &&
have_completed_a_circuit() &&
- stats_n_seconds_working / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT !=
- (stats_n_seconds_working+seconds_elapsed) /
+ get_uptime() / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT !=
+ (get_uptime()+seconds_elapsed) /
TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
/* every 20 minutes, check and complain if necessary */
const routerinfo_t *me = router_get_my_routerinfo();
@@ -2382,12 +2361,14 @@ systemd_watchdog_callback(periodic_timer_t *timer, void *arg)
/** Timer: used to invoke refill_callback(). */
static periodic_timer_t *refill_timer = NULL;
+/** Millisecond when refall_callback was last invoked. */
+static struct timeval refill_timer_current_millisecond;
+
/** Libevent callback: invoked periodically to refill token buckets
* and count r/w bytes. */
static void
refill_callback(periodic_timer_t *timer, void *arg)
{
- static struct timeval current_millisecond;
struct timeval now;
size_t bytes_written;
@@ -2403,29 +2384,35 @@ refill_callback(periodic_timer_t *timer, void *arg)
tor_gettimeofday(&now);
/* If this is our first time, no time has passed. */
- if (current_millisecond.tv_sec) {
- long mdiff = tv_mdiff(&current_millisecond, &now);
+ if (refill_timer_current_millisecond.tv_sec) {
+ long mdiff = tv_mdiff(&refill_timer_current_millisecond, &now);
if (mdiff > INT_MAX)
mdiff = INT_MAX;
milliseconds_elapsed = (int)mdiff;
- seconds_rolled_over = (int)(now.tv_sec - current_millisecond.tv_sec);
+ seconds_rolled_over = (int)(now.tv_sec -
+ refill_timer_current_millisecond.tv_sec);
}
- bytes_written = stats_prev_global_write_bucket - global_write_bucket;
- bytes_read = stats_prev_global_read_bucket - global_read_bucket;
+ bytes_written = stats_prev_global_write_bucket -
+ token_bucket_rw_get_write(&global_bucket);
+ bytes_read = stats_prev_global_read_bucket -
+ token_bucket_rw_get_read(&global_bucket);
stats_n_bytes_read += bytes_read;
stats_n_bytes_written += bytes_written;
if (accounting_is_enabled(options) && milliseconds_elapsed >= 0)
accounting_add_bytes(bytes_read, bytes_written, seconds_rolled_over);
- if (milliseconds_elapsed > 0)
- connection_bucket_refill(milliseconds_elapsed, (time_t)now.tv_sec);
+ if (milliseconds_elapsed > 0) {
+ connection_bucket_refill((time_t)now.tv_sec,
+ monotime_coarse_get_stamp());
+ }
- stats_prev_global_read_bucket = global_read_bucket;
- stats_prev_global_write_bucket = global_write_bucket;
+ stats_prev_global_read_bucket = token_bucket_rw_get_read(&global_bucket);
+ stats_prev_global_write_bucket = token_bucket_rw_get_write(&global_bucket);
- current_millisecond = now; /* remember what time it is, for next time */
+ /* remember what time it is, for next time */
+ refill_timer_current_millisecond = now;
}
#ifndef _WIN32
@@ -2464,9 +2451,9 @@ ip_address_changed(int at_interface)
}
} else {
if (server) {
- if (stats_n_seconds_working > UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST)
+ if (get_uptime() > UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST)
reset_bandwidth_test();
- stats_n_seconds_working = 0;
+ reset_uptime();
router_reset_reachability();
}
}
@@ -2600,6 +2587,11 @@ do_main_loop(void)
initialize_periodic_events();
}
+ if (!schedule_active_linked_connections_event) {
+ schedule_active_linked_connections_event =
+ mainloop_event_postloop_new(schedule_active_linked_connections_cb, NULL);
+ }
+
/* initialize dns resolve map, spawn workers if needed */
if (dns_init() < 0) {
if (get_options()->ServerDNSAllowBrokenConfig)
@@ -2626,8 +2618,8 @@ do_main_loop(void)
/* Set up our buckets */
connection_bucket_init();
- stats_prev_global_read_bucket = global_read_bucket;
- stats_prev_global_write_bucket = global_write_bucket;
+ stats_prev_global_read_bucket = token_bucket_rw_get_read(&global_bucket);
+ stats_prev_global_write_bucket = token_bucket_rw_get_write(&global_bucket);
/* initialize the bootstrap status events to know we're starting up */
control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
@@ -2804,17 +2796,12 @@ run_main_loop_once(void)
errno = 0;
#endif
- /* All active linked conns should get their read events activated,
- * so that libevent knows to run their callbacks. */
- SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn,
- event_active(conn->read_event, EV_READ, 1));
-
if (get_options()->MainloopStats) {
/* We always enforce that EVLOOP_ONCE is passed to event_base_loop() if we
* are collecting main loop statistics. */
called_loop_once = 1;
} else {
- called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0;
+ called_loop_once = 0;
}
/* Make sure we know (about) what time it is. */
@@ -2824,8 +2811,8 @@ run_main_loop_once(void)
* an event, or the second ends, or until we have some active linked
* connections to trigger events for. Libevent will wait till one
* of these happens, then run all the appropriate callbacks. */
- loop_result = event_base_loop(tor_libevent_get_base(),
- called_loop_once ? EVLOOP_ONCE : 0);
+ loop_result = tor_libevent_run_event_loop(tor_libevent_get_base(),
+ called_loop_once);
if (get_options()->MainloopStats) {
/* Update our main loop counters. */
@@ -2870,19 +2857,6 @@ run_main_loop_once(void)
if (main_loop_should_exit)
return 0;
- /* And here is where we put callbacks that happen "every time the event loop
- * runs." They must be very fast, or else the whole Tor process will get
- * slowed down.
- *
- * Note that this gets called once per libevent loop, which will make it
- * happen once per group of events that fire, or once per second. */
-
- /* If there are any pending client connections, try attaching them to
- * circuits (if we can.) This will be pretty fast if nothing new is
- * pending.
- */
- connection_ap_attach_pending(0);
-
return 1;
}
@@ -3004,6 +2978,13 @@ get_uptime,(void))
return stats_n_seconds_working;
}
+/** Reset Tor's uptime. */
+MOCK_IMPL(void,
+reset_uptime,(void))
+{
+ stats_n_seconds_working = 0;
+}
+
/**
* Write current memory usage information to the log.
*/
@@ -3047,13 +3028,13 @@ dumpstats(int severity)
i,
(int)connection_get_inbuf_len(conn),
(int)buf_allocation(conn->inbuf),
- (int)(now - conn->timestamp_lastread));
+ (int)(now - conn->timestamp_last_read_allowed));
tor_log(severity,LD_GENERAL,
"Conn %d: %d bytes waiting on outbuf "
"(len %d, last written %d secs ago)",i,
(int)connection_get_outbuf_len(conn),
(int)buf_allocation(conn->outbuf),
- (int)(now - conn->timestamp_lastwritten));
+ (int)(now - conn->timestamp_last_write_allowed));
if (conn->type == CONN_TYPE_OR) {
or_connection_t *or_conn = TO_OR_CONN(conn);
if (or_conn->tls) {
@@ -3323,14 +3304,12 @@ tor_init(int argc, char *argv[])
if (strstr(version, "alpha") || strstr(version, "beta"))
log_notice(LD_GENERAL, "This version is not a stable Tor release. "
"Expect more bugs than usual.");
+
+ tor_compress_log_init_warnings();
}
#ifdef HAVE_RUST
- char *rust_str = rust_welcome_string();
- if (rust_str != NULL && strlen(rust_str) > 0) {
- log_notice(LD_GENERAL, "%s", rust_str);
- }
- tor_free(rust_str);
+ rust_log_welcome_string();
#endif /* defined(HAVE_RUST) */
if (network_init()<0) {
@@ -3511,6 +3490,33 @@ tor_free_all(int postfork)
periodic_timer_free(refill_timer);
tor_event_free(shutdown_did_not_work_event);
tor_event_free(initialize_periodic_events_event);
+ mainloop_event_free(directory_all_unreachable_cb_event);
+ mainloop_event_free(schedule_active_linked_connections_event);
+
+#ifdef HAVE_SYSTEMD_209
+ periodic_timer_free(systemd_watchdog_timer);
+#endif
+
+ memset(&global_bucket, 0, sizeof(global_bucket));
+ memset(&global_relayed_bucket, 0, sizeof(global_relayed_bucket));
+ stats_prev_global_read_bucket = stats_prev_global_write_bucket = 0;
+ stats_prev_n_read = stats_prev_n_written = 0;
+ stats_n_bytes_read = stats_n_bytes_written = 0;
+ time_of_process_start = 0;
+ time_of_last_signewnym = 0;
+ signewnym_is_pending = 0;
+ newnym_epoch = 0;
+ called_loop_once = 0;
+ main_loop_should_exit = 0;
+ main_loop_exit_value = 0;
+ can_complete_circuits = 0;
+ quiet_level = 0;
+ should_init_bridge_stats = 1;
+ dns_honesty_first_time = 1;
+ heartbeat_callback_first_time = 1;
+ n_libevent_errors = 0;
+ current_second = 0;
+ memset(&refill_timer_current_millisecond, 0, sizeof(struct timeval));
if (!postfork) {
release_lockfile();
diff --git a/src/or/main.h b/src/or/main.h
index c49d216f4e..e50d14d4d9 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -45,7 +45,6 @@ int connection_is_writing(connection_t *conn);
MOCK_DECL(void,connection_stop_writing,(connection_t *conn));
MOCK_DECL(void,connection_start_writing,(connection_t *conn));
-void tell_event_loop_to_run_external_code(void);
void tor_shutdown_event_loop_and_exit(int exitcode);
int tor_event_loop_shutdown_is_pending(void);
@@ -63,6 +62,7 @@ void reschedule_descriptor_update_check(void);
void reschedule_directory_downloads(void);
MOCK_DECL(long,get_uptime,(void));
+MOCK_DECL(void,reset_uptime,(void));
unsigned get_signewnym_epoch(void);
@@ -87,12 +87,9 @@ uint64_t get_main_loop_error_count(void);
uint64_t get_main_loop_idle_count(void);
extern time_t time_of_process_start;
-extern long stats_n_seconds_working;
extern int quiet_level;
-extern int global_read_bucket;
-extern int global_write_bucket;
-extern int global_relayed_read_bucket;
-extern int global_relayed_write_bucket;
+extern token_bucket_rw_t global_bucket;
+extern token_bucket_rw_t global_relayed_bucket;
#ifdef MAIN_PRIVATE
STATIC void init_connection_lists(void);
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 1f21e8adb8..e03d9e6fe5 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -237,7 +237,7 @@ router_reload_consensus_networkstatus(void)
s = networkstatus_read_cached_consensus_impl(flav, flavor, 1);
if (s) {
if (networkstatus_set_current_consensus(s, flavor,
- flags|NSSET_WAS_WAITING_FOR_CERTS,
+ flags | NSSET_WAS_WAITING_FOR_CERTS,
NULL)) {
log_info(LD_FS, "Couldn't load unverified consensus %s networkstatus "
"from cache", flavor);
@@ -951,9 +951,12 @@ update_consensus_networkstatus_downloads(time_t now)
continue;
}
- /* Check if we're waiting for certificates to download */
- if (check_consensus_waiting_for_certs(i, now, &consensus_dl_status[i]))
+ /** Check if we're waiting for certificates to download. If we are,
+ * launch download for missing directory authority certificates. */
+ if (check_consensus_waiting_for_certs(i, now, &consensus_dl_status[i])) {
+ update_certificate_downloads(now);
continue;
+ }
/* Try the requested attempt */
log_info(LD_DIR, "Launching %s standard networkstatus consensus "
@@ -1230,16 +1233,20 @@ should_delay_dir_fetches(const or_options_t *options, const char **msg_out)
return 0;
}
-/** Launch requests for networkstatus documents and authority certificates as
- * appropriate. */
+/** Launch requests for networkstatus documents as appropriate. This is called
+ * when we retry all the connections on a SIGHUP and periodically by a Periodic
+ * event which checks whether we want to download any networkstatus documents.
+ */
void
update_networkstatus_downloads(time_t now)
{
const or_options_t *options = get_options();
if (should_delay_dir_fetches(options, NULL))
return;
+ /** Launch a consensus download request, we will wait for the consensus to
+ * download and when it completes we will launch a certificate download
+ * request. */
update_consensus_networkstatus_downloads(now);
- update_certificate_downloads(now);
}
/** Launch requests as appropriate for missing directory authority
@@ -1769,7 +1776,6 @@ networkstatus_set_current_consensus(const char *consensus,
consensus_waiting_for_certs_t *waiting = NULL;
time_t current_valid_after = 0;
int free_consensus = 1; /* Free 'c' at the end of the function */
- int old_ewma_enabled;
int checked_protocols_already = 0;
if (flav < 0) {
@@ -1918,6 +1924,15 @@ networkstatus_set_current_consensus(const char *consensus,
}
}
+ /* Signatures from the consensus are verified */
+ if (from_cache && was_waiting_for_certs) {
+ /* We check if the consensus is loaded from disk cache and that it
+ * it is an unverified consensus. If it is unverified, rename it to
+ * cached-*-consensus since it has been verified. */
+ log_info(LD_DIR, "Unverified consensus signatures verified.");
+ tor_rename(unverified_fname, consensus_fname);
+ }
+
if (!from_cache && flav == usable_consensus_flavor())
control_event_client_status(LOG_NOTICE, "CONSENSUS_ARRIVED");
@@ -1993,17 +2008,8 @@ networkstatus_set_current_consensus(const char *consensus,
/* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/
update_consensus_networkstatus_fetch_time(now);
- /* Update ewma and adjust policy if needed; first cache the old value */
- old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */
- cell_ewma_set_scale_factor(options, c);
- /* If we just enabled ewma, set the cmux policy on all active channels */
- if (cell_ewma_enabled() && !old_ewma_enabled) {
- channel_set_cmux_policy_everywhere(&ewma_policy);
- } else if (!cell_ewma_enabled() && old_ewma_enabled) {
- /* Turn it off everywhere */
- channel_set_cmux_policy_everywhere(NULL);
- }
+ cmux_ewma_set_options(options, c);
/* XXXX this call might be unnecessary here: can changing the
* current consensus really alter our view of any OR's rate limits? */
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 212606d2f7..e7342f9799 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -1486,9 +1486,11 @@ node_ipv6_or_preferred(const node_t *node)
/* XX/teor - node->ipv6_preferred is set from
* fascist_firewall_prefer_ipv6_orport() each time the consensus is loaded.
*/
+ node_get_prim_orport(node, &ipv4_addr);
if (!fascist_firewall_use_ipv6(options)) {
return 0;
- } else if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) {
+ } else if (node->ipv6_preferred ||
+ !tor_addr_port_is_valid_ap(&ipv4_addr, 0)) {
return node_has_ipv6_orport(node);
}
return 0;
@@ -1499,14 +1501,12 @@ node_ipv6_or_preferred(const node_t *node)
if (r && tor_addr_port_is_valid_ipv4h((r)->addr, (r)->port_field, 0)) { \
tor_addr_from_ipv4h(&(ap_out)->addr, (r)->addr); \
(ap_out)->port = (r)->port_field; \
- return 0; \
} \
STMT_END
-/** Copy the primary (IPv4) OR port (IP address and TCP port) for
- * <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
- * port was copied, else return non-zero.*/
-int
+/** Copy the primary (IPv4) OR port (IP address and TCP port) for <b>node</b>
+ * into *<b>ap_out</b>. */
+void
node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
{
node_assert_ok(node);
@@ -1523,8 +1523,6 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
RETURN_IPV4_AP(node->ri, or_port, ap_out);
RETURN_IPV4_AP(node->rs, or_port, ap_out);
/* Microdescriptors only have an IPv6 address */
-
- return -1;
}
/** Copy the preferred OR port (IP address and TCP port) for
@@ -1549,6 +1547,7 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
{
node_assert_ok(node);
tor_assert(ap_out);
+ memset(ap_out, 0, sizeof(*ap_out));
/* Check ri first, because rewrite_node_address_for_bridge() updates
* node->ri with the configured bridge address.
@@ -1596,32 +1595,35 @@ node_ipv6_dir_preferred(const node_t *node)
* so we can't use it to determine DirPort IPv6 preference.
* This means that bridge clients will use IPv4 DirPorts by default.
*/
+ node_get_prim_dirport(node, &ipv4_addr);
if (!fascist_firewall_use_ipv6(options)) {
return 0;
- } else if (node_get_prim_dirport(node, &ipv4_addr)
+ } else if (!tor_addr_port_is_valid_ap(&ipv4_addr, 0)
|| fascist_firewall_prefer_ipv6_dirport(get_options())) {
return node_has_ipv6_dirport(node);
}
return 0;
}
-/** Copy the primary (IPv4) Dir port (IP address and TCP port) for
- * <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
- * port was copied, else return non-zero.*/
-int
+/** Copy the primary (IPv4) Dir port (IP address and TCP port) for <b>node</b>
+ * into *<b>ap_out</b>. */
+void
node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out)
{
node_assert_ok(node);
tor_assert(ap_out);
+ /* Clear the address, as a safety precaution if calling functions ignore the
+ * return value */
+ tor_addr_make_null(&ap_out->addr, AF_INET);
+ ap_out->port = 0;
+
/* Check ri first, because rewrite_node_address_for_bridge() updates
* node->ri with the configured bridge address. */
RETURN_IPV4_AP(node->ri, dir_port, ap_out);
RETURN_IPV4_AP(node->rs, dir_port, ap_out);
/* Microdescriptors only have an IPv6 address */
-
- return -1;
}
#undef RETURN_IPV4_AP
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 00f12ca1e4..1ffba2e8df 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -79,11 +79,11 @@ int node_has_ipv6_dirport(const node_t *node);
/* Deprecated - use node_ipv6_or_preferred or node_ipv6_dir_preferred */
#define node_ipv6_preferred(node) node_ipv6_or_preferred(node)
int node_ipv6_or_preferred(const node_t *node);
-int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out);
+void node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
int node_ipv6_dir_preferred(const node_t *node);
-int node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out);
+void node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out);
int node_has_curve25519_onion_key(const node_t *node);
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index ebbe0018bd..e9a299807a 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -24,8 +24,6 @@
#include "main.h"
#include "ntmain.h"
-#include <event2/event.h>
-
#include <windows.h>
#define GENSRV_SERVICENAME "tor"
#define GENSRV_DISPLAYNAME "Tor Win32 Service"
@@ -245,7 +243,8 @@ nt_service_control(DWORD request)
log_notice(LD_GENERAL,
"Got stop/shutdown request; shutting down cleanly.");
service_status.dwCurrentState = SERVICE_STOP_PENDING;
- event_base_loopexit(tor_libevent_get_base(), &exit_now);
+ tor_libevent_exit_loop_after_delay(tor_libevent_get_base(),
+ &exit_now);
return;
}
service_fns.SetServiceStatus_fn(hStatus, &service_status);
diff --git a/src/or/onion.c b/src/or/onion.c
index bd80c2f503..0c88c4d7ee 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -521,6 +521,11 @@ onion_skin_create(int type,
return r;
}
+/* This is the maximum value for keys_out_len passed to
+ * onion_skin_server_handshake, plus 16. We can make it bigger if needed:
+ * It just defines how many bytes to stack-allocate. */
+#define MAX_KEYS_TMP_LEN 128
+
/** Perform the second (server-side) step of a circuit-creation handshake of
* type <b>type</b>, responding to the client request in <b>onion_skin</b>
* using the keys in <b>keys</b>. On success, write our response into
@@ -563,20 +568,21 @@ onion_skin_server_handshake(int type,
return -1;
{
size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
- uint8_t *keys_tmp = tor_malloc(keys_out_len + DIGEST_LEN);
+ tor_assert(keys_tmp_len <= MAX_KEYS_TMP_LEN);
+ uint8_t keys_tmp[MAX_KEYS_TMP_LEN];
if (onion_skin_ntor_server_handshake(
onion_skin, keys->curve25519_key_map,
keys->junk_keypair,
keys->my_identity,
reply_out, keys_tmp, keys_tmp_len)<0) {
- tor_free(keys_tmp);
+ /* no need to memwipe here, since the output will never be used */
return -1;
}
+
memcpy(keys_out, keys_tmp, keys_out_len);
memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN);
- memwipe(keys_tmp, 0, keys_tmp_len);
- tor_free(keys_tmp);
+ memwipe(keys_tmp, 0, sizeof(keys_tmp));
r = NTOR_REPLY_LEN;
}
break;
diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c
index b167cb61fb..8ad876a587 100644
--- a/src/or/onion_ntor.c
+++ b/src/or/onion_ntor.c
@@ -22,6 +22,7 @@
#define ONION_NTOR_PRIVATE
#include "crypto.h"
+#include "crypto_digest.h"
#include "onion_ntor.h"
#include "torlog.h"
#include "util.h"
diff --git a/src/or/or.h b/src/or/or.h
index 3c0c2ad613..c5a039e939 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -80,6 +80,7 @@
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
#include "tor_queue.h"
+#include "token_bucket.h"
#include "util_format.h"
#include "hs_circuitmap.h"
@@ -1369,10 +1370,10 @@ typedef struct connection_t {
* connection. */
size_t outbuf_flushlen; /**< How much data should we try to flush from the
* outbuf? */
- time_t timestamp_lastread; /**< When was the last time libevent said we could
- * read? */
- time_t timestamp_lastwritten; /**< When was the last time libevent said we
- * could write? */
+ time_t timestamp_last_read_allowed; /**< When was the last time libevent said
+ * we could read? */
+ time_t timestamp_last_write_allowed; /**< When was the last time libevent
+ * said we could write? */
time_t timestamp_created; /**< When was this connection_t created? */
@@ -1660,20 +1661,8 @@ typedef struct or_connection_t {
time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/
- /* bandwidth* and *_bucket only used by ORs in OPEN state: */
- int bandwidthrate; /**< Bytes/s added to the bucket. (OPEN ORs only.) */
- int bandwidthburst; /**< Max bucket size for this conn. (OPEN ORs only.) */
- int read_bucket; /**< When this hits 0, stop receiving. Every second we
- * add 'bandwidthrate' to this, capping it at
- * bandwidthburst. (OPEN ORs only) */
- int write_bucket; /**< When this hits 0, stop writing. Like read_bucket. */
-
- /** Last emptied read token bucket in msec since midnight; only used if
- * TB_EMPTY events are enabled. */
- uint32_t read_emptied_time;
- /** Last emptied write token bucket in msec since midnight; only used if
- * TB_EMPTY events are enabled. */
- uint32_t write_emptied_time;
+ token_bucket_rw_t bucket; /**< Used for rate limiting when the connection is
+ * in state CONN_OPEN. */
/*
* Count the number of bytes flushed out on this orconn, and the number of
@@ -2351,10 +2340,10 @@ typedef struct routerstatus_t {
* If it's a descriptor, we only use the first DIGEST_LEN bytes. */
char descriptor_digest[DIGEST256_LEN];
uint32_t addr; /**< IPv4 address for this router, in host order. */
- uint16_t or_port; /**< OR port for this router. */
+ uint16_t or_port; /**< IPv4 OR port for this router. */
uint16_t dir_port; /**< Directory port for this router. */
tor_addr_t ipv6_addr; /**< IPv6 address for this router. */
- uint16_t ipv6_orport; /**<IPV6 OR port for this router. */
+ uint16_t ipv6_orport; /**< IPv6 OR port for this router. */
unsigned int is_authority:1; /**< True iff this router is an authority. */
unsigned int is_exit:1; /**< True iff this router is a good exit. */
unsigned int is_stable:1; /**< True iff this router stays up a long time. */
@@ -2907,11 +2896,7 @@ typedef struct {
} u;
} onion_handshake_state_t;
-/** Holds accounting information for a single step in the layered encryption
- * performed by a circuit. Used only at the client edge of a circuit. */
-typedef struct crypt_path_t {
- uint32_t magic;
-
+typedef struct relay_crypto_t {
/* crypto environments */
/** Encryption key and counter for cells heading towards the OR at this
* step. */
@@ -2925,6 +2910,17 @@ typedef struct crypt_path_t {
/** Digest state for cells heading away from the OR at this step. */
crypto_digest_t *b_digest;
+} relay_crypto_t;
+
+/** Holds accounting information for a single step in the layered encryption
+ * performed by a circuit. Used only at the client edge of a circuit. */
+typedef struct crypt_path_t {
+ uint32_t magic;
+
+ /** Cryptographic state used for encrypting and authenticating relay
+ * cells to and from this hop. */
+ relay_crypto_t crypto;
+
/** Current state of the handshake as performed with the OR at this
* step. */
onion_handshake_state_t handshake_state;
@@ -3170,15 +3166,6 @@ typedef struct circuit_t {
/** Index in smartlist of all circuits (global_circuitlist). */
int global_circuitlist_idx;
- /** Next circuit in the doubly-linked ring of circuits waiting to add
- * cells to n_conn. NULL if we have no cells pending, or if we're not
- * linked to an OR connection. */
- struct circuit_t *next_active_on_n_chan;
- /** Previous circuit in the doubly-linked ring of circuits waiting to add
- * cells to n_conn. NULL if we have no cells pending, or if we're not
- * linked to an OR connection. */
- struct circuit_t *prev_active_on_n_chan;
-
/** Various statistics about cells being added to or removed from this
* circuit's queues; used only if CELL_STATS events are enabled and
* cleared after being sent to control port. */
@@ -3458,14 +3445,6 @@ struct onion_queue_t;
typedef struct or_circuit_t {
circuit_t base_;
- /** Next circuit in the doubly-linked ring of circuits waiting to add
- * cells to p_chan. NULL if we have no cells pending, or if we're not
- * linked to an OR connection. */
- struct circuit_t *next_active_on_p_chan;
- /** Previous circuit in the doubly-linked ring of circuits waiting to add
- * cells to p_chan. NULL if we have no cells pending, or if we're not
- * linked to an OR connection. */
- struct circuit_t *prev_active_on_p_chan;
/** Pointer to an entry on the onion queue, if this circuit is waiting for a
* chance to give an onionskin to a cpuworker. Used only in onion.c */
struct onion_queue_t *onionqueue_entry;
@@ -3490,21 +3469,10 @@ typedef struct or_circuit_t {
/** Linked list of Exit streams associated with this circuit that are
* still being resolved. */
edge_connection_t *resolving_streams;
- /** The cipher used by intermediate hops for cells heading toward the
- * OP. */
- crypto_cipher_t *p_crypto;
- /** The cipher used by intermediate hops for cells heading away from
- * the OP. */
- crypto_cipher_t *n_crypto;
-
- /** The integrity-checking digest used by intermediate hops, for
- * cells packaged here and heading towards the OP.
- */
- crypto_digest_t *p_digest;
- /** The integrity-checking digest used by intermediate hops, for
- * cells packaged at the OP and arriving here.
- */
- crypto_digest_t *n_digest;
+
+ /** Cryptographic state used for encrypting and authenticating relay
+ * cells to and from this hop. */
+ relay_crypto_t crypto;
/** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
* is not marked for close. */
@@ -4223,10 +4191,6 @@ typedef struct {
* testing our DNS server. */
int EnforceDistinctSubnets; /**< If true, don't allow multiple routers in the
* same network zone in the same circuit. */
- int PortForwarding; /**< If true, use NAT-PMP or UPnP to automatically
- * forward the DirPort and ORPort on the NAT device */
- char *PortForwardingHelper; /** < Filename or full path of the port
- forwarding helper executable */
int AllowNonRFC953Hostnames; /**< If true, we allow connections to hostnames
* with weird characters. */
/** If true, we try resolving hostnames with weird characters. */
@@ -4450,9 +4414,6 @@ typedef struct {
/** Enable CELL_STATS events. Only altered on testing networks. */
int TestingEnableCellStatsEvent;
- /** Enable TB_EMPTY events. Only altered on testing networks. */
- int TestingEnableTbEmptyEvent;
-
/** If true, and we have GeoIP data, and we're a bridge, keep a per-country
* count of how many client addresses have contacted us so that we can help
* the bridge authority guess which countries have blocked access to us. */
diff --git a/src/or/periodic.c b/src/or/periodic.c
index 6896b41c86..fa40965de1 100644
--- a/src/or/periodic.c
+++ b/src/or/periodic.c
@@ -16,8 +16,6 @@
#include "config.h"
#include "periodic.h"
-#include <event2/event.h>
-
/** We disable any interval greater than this number of seconds, on the
* grounds that it is probably an absolute time mistakenly passed in as a
* relative time.
@@ -34,17 +32,16 @@ periodic_event_set_interval(periodic_event_item_t *event,
struct timeval tv;
tv.tv_sec = next_interval;
tv.tv_usec = 0;
- event_add(event->ev, &tv);
+ mainloop_event_schedule(event->ev, &tv);
}
/** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
* event that needs to be called */
static void
-periodic_event_dispatch(evutil_socket_t fd, short what, void *data)
+periodic_event_dispatch(mainloop_event_t *ev, void *data)
{
- (void)fd;
- (void)what;
periodic_event_item_t *event = data;
+ tor_assert(ev == event->ev);
time_t now = time(NULL);
const or_options_t *options = get_options();
@@ -74,7 +71,7 @@ periodic_event_dispatch(evutil_socket_t fd, short what, void *data)
// log_debug(LD_GENERAL, "Scheduling %s for %d seconds", event->name,
// next_interval);
struct timeval tv = { next_interval , 0 };
- event_add(event->ev, &tv);
+ mainloop_event_schedule(ev, &tv);
}
/** Schedules <b>event</b> to run as soon as possible from now. */
@@ -93,10 +90,8 @@ periodic_event_setup(periodic_event_item_t *event)
tor_assert(0);
}
- event->ev = tor_event_new(tor_libevent_get_base(),
- -1, 0,
- periodic_event_dispatch,
- event);
+ event->ev = mainloop_event_new(periodic_event_dispatch,
+ event);
tor_assert(event->ev);
}
@@ -111,7 +106,7 @@ periodic_event_launch(periodic_event_item_t *event)
}
// Initial dispatch
- periodic_event_dispatch(-1, EV_TIMEOUT, event);
+ periodic_event_dispatch(event->ev, event);
}
/** Release all storage associated with <b>event</b> */
@@ -120,7 +115,7 @@ periodic_event_destroy(periodic_event_item_t *event)
{
if (!event)
return;
- tor_event_free(event->ev);
+ mainloop_event_free(event->ev);
event->last_action_time = 0;
}
diff --git a/src/or/periodic.h b/src/or/periodic.h
index 8baf3994eb..285400b8bb 100644
--- a/src/or/periodic.h
+++ b/src/or/periodic.h
@@ -14,13 +14,14 @@
typedef int (*periodic_event_helper_t)(time_t now,
const or_options_t *options);
-struct event;
+struct mainloop_event_t;
/** A single item for the periodic-events-function table. */
typedef struct periodic_event_item_t {
periodic_event_helper_t fn; /**< The function to run the event */
time_t last_action_time; /**< The last time the function did something */
- struct event *ev; /**< Libevent callback we're using to implement this */
+ struct mainloop_event_t *ev; /**< Libevent callback we're using to implement
+ * this */
const char *name; /**< Name of the function -- for debug */
} periodic_event_item_t;
diff --git a/src/or/relay.c b/src/or/relay.c
index 5a3c43e058..a33e0d1f36 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -70,6 +70,7 @@
#include "policies.h"
#include "reasons.h"
#include "relay.h"
+#include "relay_crypto.h"
#include "rendcache.h"
#include "rendcommon.h"
#include "router.h"
@@ -115,81 +116,13 @@ uint64_t stats_n_relay_cells_relayed = 0;
* hop?
*/
uint64_t stats_n_relay_cells_delivered = 0;
+/** Stats: how many circuits have we closed due to the cell queue limit being
+ * reached (see append_cell_to_circuit_queue()) */
+uint64_t stats_n_circ_max_cell_reached = 0;
/** Used to tell which stream to read from first on a circuit. */
static tor_weak_rng_t stream_choice_rng = TOR_WEAK_RNG_INIT;
-/** Update digest from the payload of cell. Assign integrity part to
- * cell.
- */
-static void
-relay_set_digest(crypto_digest_t *digest, cell_t *cell)
-{
- char integrity[4];
- relay_header_t rh;
-
- crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE);
- crypto_digest_get_digest(digest, integrity, 4);
-// log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.",
-// integrity[0], integrity[1], integrity[2], integrity[3]);
- relay_header_unpack(&rh, cell->payload);
- memcpy(rh.integrity, integrity, 4);
- relay_header_pack(cell->payload, &rh);
-}
-
-/** Does the digest for this circuit indicate that this cell is for us?
- *
- * Update digest from the payload of cell (with the integrity part set
- * to 0). If the integrity part is valid, return 1, else restore digest
- * and cell to their original state and return 0.
- */
-static int
-relay_digest_matches(crypto_digest_t *digest, cell_t *cell)
-{
- uint32_t received_integrity, calculated_integrity;
- relay_header_t rh;
- crypto_digest_t *backup_digest=NULL;
-
- backup_digest = crypto_digest_dup(digest);
-
- relay_header_unpack(&rh, cell->payload);
- memcpy(&received_integrity, rh.integrity, 4);
- memset(rh.integrity, 0, 4);
- relay_header_pack(cell->payload, &rh);
-
-// log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.",
-// received_integrity[0], received_integrity[1],
-// received_integrity[2], received_integrity[3]);
-
- crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE);
- crypto_digest_get_digest(digest, (char*) &calculated_integrity, 4);
-
- if (calculated_integrity != received_integrity) {
-// log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing.");
-// (%d vs %d).", received_integrity, calculated_integrity);
- /* restore digest to its old form */
- crypto_digest_assign(digest, backup_digest);
- /* restore the relay header */
- memcpy(rh.integrity, &received_integrity, 4);
- relay_header_pack(cell->payload, &rh);
- crypto_digest_free(backup_digest);
- return 0;
- }
- crypto_digest_free(backup_digest);
- return 1;
-}
-
-/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b>
- * (in place).
- *
- * Note that we use the same operation for encrypting and for decrypting.
- */
-static void
-relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
-{
- crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE);
-}
-
/**
* Update channel usage state based on the type of relay cell and
* circuit properties.
@@ -294,7 +227,8 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
if (circ->marked_for_close)
return 0;
- if (relay_crypt(circ, cell, cell_direction, &layer_hint, &recognized) < 0) {
+ if (relay_decrypt_cell(circ, cell, cell_direction, &layer_hint, &recognized)
+ < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"relay crypt failed. Dropping connection.");
return -END_CIRC_REASON_INTERNAL;
@@ -399,87 +333,6 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
return 0;
}
-/** Do the appropriate en/decryptions for <b>cell</b> arriving on
- * <b>circ</b> in direction <b>cell_direction</b>.
- *
- * If cell_direction == CELL_DIRECTION_IN:
- * - If we're at the origin (we're the OP), for hops 1..N,
- * decrypt cell. If recognized, stop.
- * - Else (we're not the OP), encrypt one hop. Cell is not recognized.
- *
- * If cell_direction == CELL_DIRECTION_OUT:
- * - decrypt one hop. Check if recognized.
- *
- * If cell is recognized, set *recognized to 1, and set
- * *layer_hint to the hop that recognized it.
- *
- * Return -1 to indicate that we should mark the circuit for close,
- * else return 0.
- */
-int
-relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
- crypt_path_t **layer_hint, char *recognized)
-{
- relay_header_t rh;
-
- tor_assert(circ);
- tor_assert(cell);
- tor_assert(recognized);
- tor_assert(cell_direction == CELL_DIRECTION_IN ||
- cell_direction == CELL_DIRECTION_OUT);
-
- if (cell_direction == CELL_DIRECTION_IN) {
- if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit.
- * We'll want to do layered decrypts. */
- crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath;
- thishop = cpath;
- if (thishop->state != CPATH_STATE_OPEN) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Relay cell before first created cell? Closing.");
- return -1;
- }
- do { /* Remember: cpath is in forward order, that is, first hop first. */
- tor_assert(thishop);
-
- /* decrypt one layer */
- relay_crypt_one_payload(thishop->b_crypto, cell->payload);
-
- relay_header_unpack(&rh, cell->payload);
- if (rh.recognized == 0) {
- /* it's possibly recognized. have to check digest to be sure. */
- if (relay_digest_matches(thishop->b_digest, cell)) {
- *recognized = 1;
- *layer_hint = thishop;
- return 0;
- }
- }
-
- thishop = thishop->next;
- } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN);
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Incoming cell at client not recognized. Closing.");
- return -1;
- } else {
- /* We're in the middle. Encrypt one layer. */
- relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto, cell->payload);
- }
- } else /* cell_direction == CELL_DIRECTION_OUT */ {
- /* We're in the middle. Decrypt one layer. */
-
- relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->n_crypto, cell->payload);
-
- relay_header_unpack(&rh, cell->payload);
- if (rh.recognized == 0) {
- /* it's possibly recognized. have to check digest to be sure. */
- if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) {
- *recognized = 1;
- return 0;
- }
- }
- }
- return 0;
-}
-
/** Package a relay cell from an edge:
* - Encrypt it to the right layer
* - Append it to the appropriate cell_queue on <b>circ</b>.
@@ -498,7 +351,6 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
}
if (cell_direction == CELL_DIRECTION_OUT) {
- crypt_path_t *thishop; /* counter for repeated crypts */
chan = circ->n_chan;
if (!chan) {
log_warn(LD_BUG,"outgoing relay cell sent from %s:%d has n_chan==NULL."
@@ -521,20 +373,8 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
return 0; /* just drop it */
}
- relay_set_digest(layer_hint->f_digest, cell);
-
- thishop = layer_hint;
- /* moving from farthest to nearest hop */
- do {
- tor_assert(thishop);
- log_debug(LD_OR,"encrypting a layer of the relay cell.");
- relay_crypt_one_payload(thishop->f_crypto, cell->payload);
-
- thishop = thishop->prev;
- } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev);
-
+ relay_encrypt_cell_outbound(cell, TO_ORIGIN_CIRCUIT(circ), layer_hint);
} else { /* incoming cell */
- or_circuit_t *or_circ;
if (CIRCUIT_IS_ORIGIN(circ)) {
/* We should never package an _incoming_ cell from the circuit
* origin; that means we messed up somewhere. */
@@ -542,11 +382,9 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
assert_circuit_ok(circ);
return 0; /* just drop it */
}
- or_circ = TO_OR_CIRCUIT(circ);
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ relay_encrypt_cell_inbound(cell, or_circ);
chan = or_circ->p_chan;
- relay_set_digest(or_circ->p_digest, cell);
- /* encrypt one layer */
- relay_crypt_one_payload(or_circ->p_crypto, cell->payload);
}
++stats_n_relay_cells_relayed;
@@ -1446,7 +1284,7 @@ connection_edge_process_relay_cell_not_open(
"after %d seconds.",
(unsigned)circ->n_circ_id,
rh->stream_id,
- (int)(time(NULL) - conn->base_.timestamp_lastread));
+ (int)(time(NULL) - conn->base_.timestamp_last_read_allowed));
if (connected_cell_parse(rh, cell, &addr, &ttl) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
"Got a badly formatted connected cell. Closing.");
@@ -2394,13 +2232,6 @@ circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint)
}
}
-#ifdef ACTIVE_CIRCUITS_PARANOIA
-#define assert_cmux_ok_paranoid(chan) \
- assert_circuit_mux_okay(chan)
-#else
-#define assert_cmux_ok_paranoid(chan)
-#endif /* defined(ACTIVE_CIRCUITS_PARANOIA) */
-
/** The total number of cells we have allocated. */
static size_t total_cells_allocated = 0;
@@ -2688,16 +2519,12 @@ update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
}
tor_assert(circuitmux_attached_circuit_direction(cmux, circ) == direction);
- assert_cmux_ok_paranoid(chan);
-
/* Update the number of cells we have for the circuit mux */
if (direction == CELL_DIRECTION_OUT) {
circuitmux_set_num_cells(cmux, circ, circ->n_chan_cells.n);
} else {
circuitmux_set_num_cells(cmux, circ, or_circ->p_chan_cells.n);
}
-
- assert_cmux_ok_paranoid(chan);
}
/** Remove all circuits from the cmux on <b>chan</b>.
@@ -2842,7 +2669,6 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
}
/* If it returns NULL, no cells left to send */
if (!circ) break;
- assert_cmux_ok_paranoid(chan);
if (circ->n_chan == chan) {
queue = &circ->n_chan_cells;
@@ -2946,8 +2772,6 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
}
/* Okay, we're done sending now */
- assert_cmux_ok_paranoid(chan);
-
return n_flushed;
}
@@ -3008,7 +2832,7 @@ relay_consensus_has_changed(const networkstatus_t *ns)
/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b>
* transmitting in <b>direction</b>.
*
- * The given <b>cell</b> is copied over the circuit queue so the caller must
+ * The given <b>cell</b> is copied onto the circuit queue so the caller must
* cleanup the memory.
*
* This function is part of the fast path. */
@@ -3041,6 +2865,7 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
(exitward) ? "Outbound" : "Inbound", queue->n,
max_circuit_cell_queue_size);
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+ stats_n_circ_max_cell_reached++;
return;
}
@@ -3162,17 +2987,6 @@ circuit_clear_cell_queue(circuit_t *circ, channel_t *chan)
update_circuit_on_cmux(circ, direction);
}
-/** Fail with an assert if the circuit mux on chan is corrupt
- */
-void
-assert_circuit_mux_okay(channel_t *chan)
-{
- tor_assert(chan);
- tor_assert(chan->cmux);
-
- circuitmux_assert_okay(chan->cmux);
-}
-
/** Return 1 if we shouldn't restart reading on this circuit, even if
* we get a SENDME. Else return 0.
*/
diff --git a/src/or/relay.h b/src/or/relay.h
index c9281c5eae..f304af684a 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -14,6 +14,7 @@
extern uint64_t stats_n_relay_cells_relayed;
extern uint64_t stats_n_relay_cells_delivered;
+extern uint64_t stats_n_circ_max_cell_reached;
void relay_consensus_has_changed(const networkstatus_t *ns);
int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
@@ -77,7 +78,6 @@ void destroy_cell_queue_append(destroy_cell_queue_t *queue,
void channel_unlink_all_circuits(channel_t *chan, smartlist_t *detached_out);
MOCK_DECL(int, channel_flush_from_first_active_circuit,
(channel_t *chan, int max));
-void assert_circuit_mux_okay(channel_t *chan);
void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
const char *file, int lineno);
#define update_circuit_on_cmux(circ, direction) \
@@ -91,9 +91,6 @@ void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
void stream_choice_seed_weak_rng(void);
-int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
- crypt_path_t **layer_hint, char *recognized);
-
circid_t packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids);
#ifdef RELAY_PRIVATE
diff --git a/src/or/relay_crypto.c b/src/or/relay_crypto.c
new file mode 100644
index 0000000000..c42a4f9cca
--- /dev/null
+++ b/src/or/relay_crypto.c
@@ -0,0 +1,326 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "config.h"
+#include "hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN
+#include "relay_crypto.h"
+#include "relay.h"
+
+/** Update digest from the payload of cell. Assign integrity part to
+ * cell.
+ */
+static void
+relay_set_digest(crypto_digest_t *digest, cell_t *cell)
+{
+ char integrity[4];
+ relay_header_t rh;
+
+ crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE);
+ crypto_digest_get_digest(digest, integrity, 4);
+// log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.",
+// integrity[0], integrity[1], integrity[2], integrity[3]);
+ relay_header_unpack(&rh, cell->payload);
+ memcpy(rh.integrity, integrity, 4);
+ relay_header_pack(cell->payload, &rh);
+}
+
+/** Does the digest for this circuit indicate that this cell is for us?
+ *
+ * Update digest from the payload of cell (with the integrity part set
+ * to 0). If the integrity part is valid, return 1, else restore digest
+ * and cell to their original state and return 0.
+ */
+static int
+relay_digest_matches(crypto_digest_t *digest, cell_t *cell)
+{
+ uint32_t received_integrity, calculated_integrity;
+ relay_header_t rh;
+ crypto_digest_checkpoint_t backup_digest;
+
+ crypto_digest_checkpoint(&backup_digest, digest);
+
+ relay_header_unpack(&rh, cell->payload);
+ memcpy(&received_integrity, rh.integrity, 4);
+ memset(rh.integrity, 0, 4);
+ relay_header_pack(cell->payload, &rh);
+
+// log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.",
+// received_integrity[0], received_integrity[1],
+// received_integrity[2], received_integrity[3]);
+
+ crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE);
+ crypto_digest_get_digest(digest, (char*) &calculated_integrity, 4);
+
+ int rv = 1;
+
+ if (calculated_integrity != received_integrity) {
+// log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing.");
+// (%d vs %d).", received_integrity, calculated_integrity);
+ /* restore digest to its old form */
+ crypto_digest_restore(digest, &backup_digest);
+ /* restore the relay header */
+ memcpy(rh.integrity, &received_integrity, 4);
+ relay_header_pack(cell->payload, &rh);
+ rv = 0;
+ }
+
+ memwipe(&backup_digest, 0, sizeof(backup_digest));
+ return rv;
+}
+
+/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b>
+ * (in place).
+ *
+ * Note that we use the same operation for encrypting and for decrypting.
+ */
+static void
+relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
+{
+ crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE);
+}
+
+/** Do the appropriate en/decryptions for <b>cell</b> arriving on
+ * <b>circ</b> in direction <b>cell_direction</b>.
+ *
+ * If cell_direction == CELL_DIRECTION_IN:
+ * - If we're at the origin (we're the OP), for hops 1..N,
+ * decrypt cell. If recognized, stop.
+ * - Else (we're not the OP), encrypt one hop. Cell is not recognized.
+ *
+ * If cell_direction == CELL_DIRECTION_OUT:
+ * - decrypt one hop. Check if recognized.
+ *
+ * If cell is recognized, set *recognized to 1, and set
+ * *layer_hint to the hop that recognized it.
+ *
+ * Return -1 to indicate that we should mark the circuit for close,
+ * else return 0.
+ */
+int
+relay_decrypt_cell(circuit_t *circ, cell_t *cell,
+ cell_direction_t cell_direction,
+ crypt_path_t **layer_hint, char *recognized)
+{
+ relay_header_t rh;
+
+ tor_assert(circ);
+ tor_assert(cell);
+ tor_assert(recognized);
+ tor_assert(cell_direction == CELL_DIRECTION_IN ||
+ cell_direction == CELL_DIRECTION_OUT);
+
+ if (cell_direction == CELL_DIRECTION_IN) {
+ if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit.
+ * We'll want to do layered decrypts. */
+ crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath;
+ thishop = cpath;
+ if (thishop->state != CPATH_STATE_OPEN) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Relay cell before first created cell? Closing.");
+ return -1;
+ }
+ do { /* Remember: cpath is in forward order, that is, first hop first. */
+ tor_assert(thishop);
+
+ /* decrypt one layer */
+ relay_crypt_one_payload(thishop->crypto.b_crypto, cell->payload);
+
+ relay_header_unpack(&rh, cell->payload);
+ if (rh.recognized == 0) {
+ /* it's possibly recognized. have to check digest to be sure. */
+ if (relay_digest_matches(thishop->crypto.b_digest, cell)) {
+ *recognized = 1;
+ *layer_hint = thishop;
+ return 0;
+ }
+ }
+
+ thishop = thishop->next;
+ } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN);
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Incoming cell at client not recognized. Closing.");
+ return -1;
+ } else {
+ relay_crypto_t *crypto = &TO_OR_CIRCUIT(circ)->crypto;
+ /* We're in the middle. Encrypt one layer. */
+ relay_crypt_one_payload(crypto->b_crypto, cell->payload);
+ }
+ } else /* cell_direction == CELL_DIRECTION_OUT */ {
+ /* We're in the middle. Decrypt one layer. */
+ relay_crypto_t *crypto = &TO_OR_CIRCUIT(circ)->crypto;
+
+ relay_crypt_one_payload(crypto->f_crypto, cell->payload);
+
+ relay_header_unpack(&rh, cell->payload);
+ if (rh.recognized == 0) {
+ /* it's possibly recognized. have to check digest to be sure. */
+ if (relay_digest_matches(crypto->f_digest, cell)) {
+ *recognized = 1;
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Encrypt a cell <b>cell</b> that we are creating, and sending outbound on
+ * <b>circ</b> until the hop corresponding to <b>layer_hint</b>.
+ *
+ * The integrity field and recognized field of <b>cell</b>'s relay headers
+ * must be set to zero.
+ */
+void
+relay_encrypt_cell_outbound(cell_t *cell,
+ origin_circuit_t *circ,
+ crypt_path_t *layer_hint)
+{
+ crypt_path_t *thishop; /* counter for repeated crypts */
+ relay_set_digest(layer_hint->crypto.f_digest, cell);
+
+ thishop = layer_hint;
+ /* moving from farthest to nearest hop */
+ do {
+ tor_assert(thishop);
+ log_debug(LD_OR,"encrypting a layer of the relay cell.");
+ relay_crypt_one_payload(thishop->crypto.f_crypto, cell->payload);
+
+ thishop = thishop->prev;
+ } while (thishop != circ->cpath->prev);
+}
+
+/**
+ * Encrypt a cell <b>cell</b> that we are creating, and sending on
+ * <b>circuit</b> to the origin.
+ *
+ * The integrity field and recognized field of <b>cell</b>'s relay headers
+ * must be set to zero.
+ */
+void
+relay_encrypt_cell_inbound(cell_t *cell,
+ or_circuit_t *or_circ)
+{
+ relay_set_digest(or_circ->crypto.b_digest, cell);
+ /* encrypt one layer */
+ relay_crypt_one_payload(or_circ->crypto.b_crypto, cell->payload);
+}
+
+/**
+ * Release all storage held inside <b>crypto</b>, but do not free
+ * <b>crypto</b> itself: it lives inside another object.
+ */
+void
+relay_crypto_clear(relay_crypto_t *crypto)
+{
+ if (BUG(!crypto))
+ return;
+ crypto_cipher_free(crypto->f_crypto);
+ crypto_cipher_free(crypto->b_crypto);
+ crypto_digest_free(crypto->f_digest);
+ crypto_digest_free(crypto->b_digest);
+}
+
+/** Initialize <b>crypto</b> from the key material in key_data.
+ *
+ * If <b>is_hs_v3</b> is set, this cpath will be used for next gen hidden
+ * service circuits and <b>key_data</b> must be at least
+ * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length.
+ *
+ * If <b>is_hs_v3</b> is not set, key_data must contain CPATH_KEY_MATERIAL_LEN
+ * bytes, which are used as follows:
+ * - 20 to initialize f_digest
+ * - 20 to initialize b_digest
+ * - 16 to key f_crypto
+ * - 16 to key b_crypto
+ *
+ * (If 'reverse' is true, then f_XX and b_XX are swapped.)
+ *
+ * Return 0 if init was successful, else -1 if it failed.
+ */
+int
+relay_crypto_init(relay_crypto_t *crypto,
+ const char *key_data, size_t key_data_len,
+ int reverse, int is_hs_v3)
+{
+ crypto_digest_t *tmp_digest;
+ crypto_cipher_t *tmp_crypto;
+ size_t digest_len = 0;
+ size_t cipher_key_len = 0;
+
+ tor_assert(crypto);
+ tor_assert(key_data);
+ tor_assert(!(crypto->f_crypto || crypto->b_crypto ||
+ crypto->f_digest || crypto->b_digest));
+
+ /* Basic key size validation */
+ if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
+ goto err;
+ } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) {
+ goto err;
+ }
+
+ /* If we are using this crypto for next gen onion services use SHA3-256,
+ otherwise use good ol' SHA1 */
+ if (is_hs_v3) {
+ digest_len = DIGEST256_LEN;
+ cipher_key_len = CIPHER256_KEY_LEN;
+ crypto->f_digest = crypto_digest256_new(DIGEST_SHA3_256);
+ crypto->b_digest = crypto_digest256_new(DIGEST_SHA3_256);
+ } else {
+ digest_len = DIGEST_LEN;
+ cipher_key_len = CIPHER_KEY_LEN;
+ crypto->f_digest = crypto_digest_new();
+ crypto->b_digest = crypto_digest_new();
+ }
+
+ tor_assert(digest_len != 0);
+ tor_assert(cipher_key_len != 0);
+ const int cipher_key_bits = (int) cipher_key_len * 8;
+
+ crypto_digest_add_bytes(crypto->f_digest, key_data, digest_len);
+ crypto_digest_add_bytes(crypto->b_digest, key_data+digest_len, digest_len);
+
+ crypto->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len),
+ cipher_key_bits);
+ if (!crypto->f_crypto) {
+ log_warn(LD_BUG,"Forward cipher initialization failed.");
+ goto err;
+ }
+
+ crypto->b_crypto = crypto_cipher_new_with_bits(
+ key_data+(2*digest_len)+cipher_key_len,
+ cipher_key_bits);
+ if (!crypto->b_crypto) {
+ log_warn(LD_BUG,"Backward cipher initialization failed.");
+ goto err;
+ }
+
+ if (reverse) {
+ tmp_digest = crypto->f_digest;
+ crypto->f_digest = crypto->b_digest;
+ crypto->b_digest = tmp_digest;
+ tmp_crypto = crypto->f_crypto;
+ crypto->f_crypto = crypto->b_crypto;
+ crypto->b_crypto = tmp_crypto;
+ }
+
+ return 0;
+ err:
+ relay_crypto_clear(crypto);
+ return -1;
+}
+
+/** Assert that <b>crypto</b> is valid and set. */
+void
+relay_crypto_assert_ok(const relay_crypto_t *crypto)
+{
+ tor_assert(crypto->f_crypto);
+ tor_assert(crypto->b_crypto);
+ tor_assert(crypto->f_digest);
+ tor_assert(crypto->b_digest);
+}
+
diff --git a/src/or/relay_crypto.h b/src/or/relay_crypto.h
new file mode 100644
index 0000000000..66ae02cee9
--- /dev/null
+++ b/src/or/relay_crypto.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay.h
+ * \brief Header file for relay.c.
+ **/
+
+#ifndef TOR_RELAY_CRYPTO_H
+#define TOR_RELAY_CRYPTO_H
+
+int relay_crypto_init(relay_crypto_t *crypto,
+ const char *key_data, size_t key_data_len,
+ int reverse, int is_hs_v3);
+
+int relay_decrypt_cell(circuit_t *circ, cell_t *cell,
+ cell_direction_t cell_direction,
+ crypt_path_t **layer_hint, char *recognized);
+void relay_encrypt_cell_outbound(cell_t *cell, origin_circuit_t *or_circ,
+ crypt_path_t *layer_hint);
+void relay_encrypt_cell_inbound(cell_t *cell, or_circuit_t *or_circ);
+
+void relay_crypto_clear(relay_crypto_t *crypto);
+
+void relay_crypto_assert_ok(const relay_crypto_t *crypto);
+
+#endif /* !defined(TOR_RELAY_CRYPTO_H) */
+
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 57815815b9..9a1b97c6d6 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -915,8 +915,8 @@ rend_client_desc_trynow(const char *query)
/* restart their timeout values, so they get a fair shake at
* connecting to the hidden service. */
base_conn->timestamp_created = now;
- base_conn->timestamp_lastread = now;
- base_conn->timestamp_lastwritten = now;
+ base_conn->timestamp_last_read_allowed = now;
+ base_conn->timestamp_last_write_allowed = now;
connection_ap_mark_as_pending_circuit(conn);
} else { /* 404, or fetch didn't get that far */
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 43494692cb..ac3e9f502e 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -86,7 +86,6 @@
#include "ht.h"
#include "channelpadding.h"
-#include "channelpadding.h"
#include "connection_or.h"
static void bw_arrays_init(void);
diff --git a/src/or/router.c b/src/or/router.c
index 9c053cad46..e5996f665e 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -103,6 +103,13 @@ static authority_cert_t *legacy_key_certificate = NULL;
* used by tor-gencert to sign new signing keys and make new key
* certificates. */
+const char *format_node_description(char *buf,
+ const char *id_digest,
+ int is_named,
+ const char *nickname,
+ const tor_addr_t *addr,
+ uint32_t addr32h);
+
/** Replace the current onion key with <b>k</b>. Does not affect
* lastonionkey; to update lastonionkey correctly, call rotate_onion_key().
*/
@@ -1227,7 +1234,8 @@ check_whether_dirport_reachable(const or_options_t *options)
/* XXX Should this be increased? */
#define MIN_BW_TO_ADVERTISE_DIRSERVER 51200
-/** Return true iff we have enough configured bandwidth to cache directory
+/** Return true iff we have enough configured bandwidth to advertise or
+ * automatically provide directory services from cache directory
* information. */
static int
router_has_bandwidth_to_be_dirserver(const or_options_t *options)
@@ -1250,7 +1258,7 @@ router_has_bandwidth_to_be_dirserver(const or_options_t *options)
* MIN_BW_TO_ADVERTISE_DIRSERVER, don't bother trying to serve requests.
*/
static int
-router_should_be_directory_server(const or_options_t *options, int dir_port)
+router_should_be_dirserver(const or_options_t *options, int dir_port)
{
static int advertising=1; /* start out assuming we will advertise */
int new_choice=1;
@@ -1355,7 +1363,7 @@ decide_to_advertise_dir_impl(const or_options_t *options,
/* Part two: consider config options that could make us choose to
* publish or not publish that the user might find surprising. */
- return router_should_be_directory_server(options, dir_port);
+ return router_should_be_dirserver(options, dir_port);
}
/** Front-end to decide_to_advertise_dir_impl(): return 0 if we don't want to
@@ -1363,7 +1371,7 @@ decide_to_advertise_dir_impl(const or_options_t *options,
* DirPort we want to advertise.
*/
static int
-decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
+router_should_advertise_dirport(const or_options_t *options, uint16_t dir_port)
{
/* supports_tunnelled_dir_requests is not relevant, pass 0 */
return decide_to_advertise_dir_impl(options, dir_port, 0) ? dir_port : 0;
@@ -1373,7 +1381,7 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
* advertise the fact that we support begindir requests, else return 1.
*/
static int
-decide_to_advertise_begindir(const or_options_t *options,
+router_should_advertise_begindir(const or_options_t *options,
int supports_tunnelled_dir_requests)
{
/* dir_port is not relevant, pass 0 */
@@ -1406,26 +1414,17 @@ extend_info_from_router(const routerinfo_t *r)
&ap.addr, ap.port);
}
-/** Some time has passed, or we just got new directory information.
- * See if we currently believe our ORPort or DirPort to be
- * unreachable. If so, launch a new test for it.
- *
- * For ORPort, we simply try making a circuit that ends at ourselves.
- * Success is noticed in onionskin_answer().
- *
- * For DirPort, we make a connection via Tor to our DirPort and ask
- * for our own server descriptor.
- * Success is noticed in connection_dir_client_reached_eof().
+/**See if we currently believe our ORPort or DirPort to be
+ * unreachable. If so, return 1 else return 0.
*/
-void
-consider_testing_reachability(int test_or, int test_dir)
+static int
+router_should_check_reachability(int test_or, int test_dir)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
- int orport_reachable = check_whether_orport_reachable(options);
- tor_addr_t addr;
+
if (!me)
- return;
+ return 0;
if (routerset_contains_router(options->ExcludeNodes, me, -1) &&
options->StrictNodes) {
@@ -1440,43 +1439,66 @@ consider_testing_reachability(int test_or, int test_dir)
"We cannot learn whether we are usable, and will not "
"be able to advertise ourself.");
}
- return;
+ return 0;
}
+ return 1;
+}
+
+/** Some time has passed, or we just got new directory information.
+ * See if we currently believe our ORPort or DirPort to be
+ * unreachable. If so, launch a new test for it.
+ *
+ * For ORPort, we simply try making a circuit that ends at ourselves.
+ * Success is noticed in onionskin_answer().
+ *
+ * For DirPort, we make a connection via Tor to our DirPort and ask
+ * for our own server descriptor.
+ * Success is noticed in connection_dir_client_reached_eof().
+ */
+void
+router_do_reachability_checks(int test_or, int test_dir)
+{
+ const routerinfo_t *me = router_get_my_routerinfo();
+ const or_options_t *options = get_options();
+ int orport_reachable = check_whether_orport_reachable(options);
+ tor_addr_t addr;
+
+ if (router_should_check_reachability(test_or, test_dir)) {
+ if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
+ extend_info_t *ei = extend_info_from_router(me);
+ /* XXX IPv6 self testing */
+ log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
+ !orport_reachable ? "reachability" : "bandwidth",
+ fmt_addr32(me->addr), me->or_port);
+ circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
+ CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
+ extend_info_free(ei);
+ }
- if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
- extend_info_t *ei = extend_info_from_router(me);
/* XXX IPv6 self testing */
- log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
- !orport_reachable ? "reachability" : "bandwidth",
- fmt_addr32(me->addr), me->or_port);
- circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
- CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
- extend_info_free(ei);
- }
-
- /* XXX IPv6 self testing */
- tor_addr_from_ipv4h(&addr, me->addr);
- if (test_dir && !check_whether_dirport_reachable(options) &&
- !connection_get_by_type_addr_port_purpose(
- CONN_TYPE_DIR, &addr, me->dir_port,
- DIR_PURPOSE_FETCH_SERVERDESC)) {
- tor_addr_port_t my_orport, my_dirport;
- memcpy(&my_orport.addr, &addr, sizeof(addr));
- memcpy(&my_dirport.addr, &addr, sizeof(addr));
- my_orport.port = me->or_port;
- my_dirport.port = me->dir_port;
- /* ask myself, via tor, for my server descriptor. */
- directory_request_t *req =
- directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC);
- directory_request_set_or_addr_port(req, &my_orport);
- directory_request_set_dir_addr_port(req, &my_dirport);
- directory_request_set_directory_id_digest(req,
+ tor_addr_from_ipv4h(&addr, me->addr);
+ if (test_dir && !check_whether_dirport_reachable(options) &&
+ !connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR, &addr, me->dir_port,
+ DIR_PURPOSE_FETCH_SERVERDESC)) {
+ tor_addr_port_t my_orport, my_dirport;
+ memcpy(&my_orport.addr, &addr, sizeof(addr));
+ memcpy(&my_dirport.addr, &addr, sizeof(addr));
+ my_orport.port = me->or_port;
+ my_dirport.port = me->dir_port;
+ /* ask myself, via tor, for my server descriptor. */
+ directory_request_t *req =
+ directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC);
+ directory_request_set_or_addr_port(req, &my_orport);
+ directory_request_set_dir_addr_port(req, &my_dirport);
+ directory_request_set_directory_id_digest(req,
me->cache_info.identity_digest);
- // ask via an anon circuit, connecting to our dirport.
- directory_request_set_indirection(req, DIRIND_ANON_DIRPORT);
- directory_request_set_resource(req, "authority.z");
- directory_initiate_request(req);
- directory_request_free(req);
+ // ask via an anon circuit, connecting to our dirport.
+ directory_request_set_indirection(req, DIRIND_ANON_DIRPORT);
+ directory_request_set_resource(req, "authority.z");
+ directory_initiate_request(req);
+ directory_request_free(req);
+ }
}
}
@@ -1521,7 +1543,7 @@ router_dirport_found_reachable(void)
&& check_whether_orport_reachable(options) ?
" Publishing server descriptor." : "");
can_reach_dir_port = 1;
- if (decide_to_advertise_dirport(options, me->dir_port)) {
+ if (router_should_advertise_dirport(options, me->dir_port)) {
mark_my_descriptor_dirty("DirPort found reachable");
/* This is a significant enough change to upload immediately,
* at least in a test network */
@@ -2915,14 +2937,14 @@ router_dump_router_to_string(routerinfo_t *router,
router->nickname,
address,
router->or_port,
- decide_to_advertise_dirport(options, router->dir_port),
+ router_should_advertise_dirport(options, router->dir_port),
ed_cert_line ? ed_cert_line : "",
extra_or_address ? extra_or_address : "",
router->platform,
proto_line,
published,
fingerprint,
- stats_n_seconds_working,
+ get_uptime(),
(int) router->bandwidthrate,
(int) router->bandwidthburst,
(int) router->bandwidthcapacity,
@@ -2989,7 +3011,7 @@ router_dump_router_to_string(routerinfo_t *router,
tor_free(p6);
}
- if (decide_to_advertise_begindir(options,
+ if (router_should_advertise_begindir(options,
router->supports_tunnelled_dir_requests)) {
smartlist_add_strdup(chunks, "tunnelled-dir-server\n");
}
@@ -3438,6 +3460,15 @@ is_legal_hexdigest(const char *s)
strspn(s,HEX_CHARACTERS)==HEX_DIGEST_LEN);
}
+/**
+ * Longest allowed output of format_node_description, plus 1 character for
+ * NUL. This allows space for:
+ * "$FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF~xxxxxxxxxxxxxxxxxxx at"
+ * " [ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]"
+ * plus a terminating NUL.
+ */
+#define NODE_DESC_BUF_LEN (MAX_VERBOSE_NICKNAME_LEN+4+TOR_ADDR_BUF_LEN)
+
/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
* hold a human-readable description of a node with identity digest
* <b>id_digest</b>, named-status <b>is_named</b>, nickname <b>nickname</b>,
@@ -3483,15 +3514,16 @@ format_node_description(char *buf,
return buf;
}
-/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
- * hold a human-readable description of <b>ri</b>.
- *
+/** Return a human-readable description of the routerinfo_t <b>ri</b>.
*
- * Return a pointer to the front of <b>buf</b>.
+ * This function is not thread-safe. Each call to this function invalidates
+ * previous values returned by this function.
*/
const char *
-router_get_description(char *buf, const routerinfo_t *ri)
+router_describe(const routerinfo_t *ri)
{
+ static char buf[NODE_DESC_BUF_LEN];
+
if (!ri)
return "<null>";
return format_node_description(buf,
@@ -3502,14 +3534,15 @@ router_get_description(char *buf, const routerinfo_t *ri)
ri->addr);
}
-/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
- * hold a human-readable description of <b>node</b>.
+/** Return a human-readable description of the node_t <b>node</b>.
*
- * Return a pointer to the front of <b>buf</b>.
+ * This function is not thread-safe. Each call to this function invalidates
+ * previous values returned by this function.
*/
const char *
-node_get_description(char *buf, const node_t *node)
+node_describe(const node_t *node)
{
+ static char buf[NODE_DESC_BUF_LEN];
const char *nickname = NULL;
uint32_t addr32h = 0;
int is_named = 0;
@@ -3534,14 +3567,16 @@ node_get_description(char *buf, const node_t *node)
addr32h);
}
-/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
- * hold a human-readable description of <b>rs</b>.
+/** Return a human-readable description of the routerstatus_t <b>rs</b>.
*
- * Return a pointer to the front of <b>buf</b>.
+ * This function is not thread-safe. Each call to this function invalidates
+ * previous values returned by this function.
*/
const char *
-routerstatus_get_description(char *buf, const routerstatus_t *rs)
+routerstatus_describe(const routerstatus_t *rs)
{
+ static char buf[NODE_DESC_BUF_LEN];
+
if (!rs)
return "<null>";
return format_node_description(buf,
@@ -3552,14 +3587,16 @@ routerstatus_get_description(char *buf, const routerstatus_t *rs)
rs->addr);
}
-/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
- * hold a human-readable description of <b>ei</b>.
+/** Return a human-readable description of the extend_info_t <b>ei</b>.
*
- * Return a pointer to the front of <b>buf</b>.
+ * This function is not thread-safe. Each call to this function invalidates
+ * previous values returned by this function.
*/
const char *
-extend_info_get_description(char *buf, const extend_info_t *ei)
+extend_info_describe(const extend_info_t *ei)
{
+ static char buf[NODE_DESC_BUF_LEN];
+
if (!ei)
return "<null>";
return format_node_description(buf,
@@ -3570,54 +3607,6 @@ extend_info_get_description(char *buf, const extend_info_t *ei)
0);
}
-/** Return a human-readable description of the routerinfo_t <b>ri</b>.
- *
- * This function is not thread-safe. Each call to this function invalidates
- * previous values returned by this function.
- */
-const char *
-router_describe(const routerinfo_t *ri)
-{
- static char buf[NODE_DESC_BUF_LEN];
- return router_get_description(buf, ri);
-}
-
-/** Return a human-readable description of the node_t <b>node</b>.
- *
- * This function is not thread-safe. Each call to this function invalidates
- * previous values returned by this function.
- */
-const char *
-node_describe(const node_t *node)
-{
- static char buf[NODE_DESC_BUF_LEN];
- return node_get_description(buf, node);
-}
-
-/** Return a human-readable description of the routerstatus_t <b>rs</b>.
- *
- * This function is not thread-safe. Each call to this function invalidates
- * previous values returned by this function.
- */
-const char *
-routerstatus_describe(const routerstatus_t *rs)
-{
- static char buf[NODE_DESC_BUF_LEN];
- return routerstatus_get_description(buf, rs);
-}
-
-/** Return a human-readable description of the extend_info_t <b>ei</b>.
- *
- * This function is not thread-safe. Each call to this function invalidates
- * previous values returned by this function.
- */
-const char *
-extend_info_describe(const extend_info_t *ei)
-{
- static char buf[NODE_DESC_BUF_LEN];
- return extend_info_get_description(buf, ei);
-}
-
/** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the
* verbose representation of the identity of <b>router</b>. The format is:
* A dollar sign.
diff --git a/src/or/router.h b/src/or/router.h
index 696e983662..e5efe577e3 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -47,7 +47,7 @@ int init_keys_client(void);
int check_whether_orport_reachable(const or_options_t *options);
int check_whether_dirport_reachable(const or_options_t *options);
int dir_server_mode(const or_options_t *options);
-void consider_testing_reachability(int test_or, int test_dir);
+void router_do_reachability_checks(int test_or, int test_dir);
void router_orport_found_reachable(void);
void router_dirport_found_reachable(void);
void router_perform_bandwidth_test(int num_circs, time_t now);
@@ -123,24 +123,6 @@ int is_legal_nickname(const char *s);
int is_legal_nickname_or_hexdigest(const char *s);
int is_legal_hexdigest(const char *s);
-/**
- * Longest allowed output of format_node_description, plus 1 character for
- * NUL. This allows space for:
- * "$FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF~xxxxxxxxxxxxxxxxxxx at"
- * " [ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]"
- * plus a terminating NUL.
- */
-#define NODE_DESC_BUF_LEN (MAX_VERBOSE_NICKNAME_LEN+4+TOR_ADDR_BUF_LEN)
-const char *format_node_description(char *buf,
- const char *id_digest,
- int is_named,
- const char *nickname,
- const tor_addr_t *addr,
- uint32_t addr32h);
-const char *router_get_description(char *buf, const routerinfo_t *ri);
-const char *node_get_description(char *buf, const node_t *node);
-const char *routerstatus_get_description(char *buf, const routerstatus_t *rs);
-const char *extend_info_get_description(char *buf, const extend_info_t *ei);
const char *router_describe(const routerinfo_t *ri);
const char *node_describe(const node_t *node);
const char *routerstatus_describe(const routerstatus_t *ri);
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
index 382b3e3ca9..da894294bf 100644
--- a/src/or/scheduler.c
+++ b/src/or/scheduler.c
@@ -13,8 +13,6 @@
#define TOR_CHANNEL_INTERNAL_
#include "channeltls.h"
-#include <event2/event.h>
-
/**
* \file scheduler.c
* \brief Channel scheduling system: decides which channels should send and
@@ -169,7 +167,7 @@ STATIC smartlist_t *channels_pending = NULL;
* This event runs the scheduler from its callback, and is manually
* activated whenever a channel enters open for writes/cells to send.
*/
-STATIC struct event *run_sched_ev = NULL;
+STATIC struct mainloop_event_t *run_sched_ev = NULL;
static int have_logged_kist_suddenly_disabled = 0;
@@ -203,10 +201,9 @@ get_scheduler_type_string(scheduler_types_t type)
* if any scheduling work was created during the event loop.
*/
static void
-scheduler_evt_callback(evutil_socket_t fd, short events, void *arg)
+scheduler_evt_callback(mainloop_event_t *event, void *arg)
{
- (void) fd;
- (void) events;
+ (void) event;
(void) arg;
log_debug(LD_SCHED, "Scheduler event callback called");
@@ -487,10 +484,7 @@ scheduler_free_all(void)
log_debug(LD_SCHED, "Shutting down scheduler");
if (run_sched_ev) {
- if (event_del(run_sched_ev) < 0) {
- log_warn(LD_BUG, "Problem deleting run_sched_ev");
- }
- tor_event_free(run_sched_ev);
+ mainloop_event_free(run_sched_ev);
run_sched_ev = NULL;
}
@@ -589,7 +583,7 @@ scheduler_ev_add(const struct timeval *next_run)
{
tor_assert(run_sched_ev);
tor_assert(next_run);
- if (BUG(event_add(run_sched_ev, next_run) < 0)) {
+ if (BUG(mainloop_event_schedule(run_sched_ev, next_run) < 0)) {
log_warn(LD_SCHED, "Adding to libevent failed. Next run time was set to: "
"%ld.%06ld", next_run->tv_sec, (long)next_run->tv_usec);
return;
@@ -598,10 +592,10 @@ scheduler_ev_add(const struct timeval *next_run)
/** Make the scheduler event active with the given flags. */
void
-scheduler_ev_active(int flags)
+scheduler_ev_active(void)
{
tor_assert(run_sched_ev);
- event_active(run_sched_ev, flags, 1);
+ mainloop_event_activate(run_sched_ev);
}
/*
@@ -618,11 +612,10 @@ scheduler_init(void)
IF_BUG_ONCE(!!run_sched_ev) {
log_warn(LD_SCHED, "We should not already have a libevent scheduler event."
"I'll clean the old one up, but this is odd.");
- tor_event_free(run_sched_ev);
+ mainloop_event_free(run_sched_ev);
run_sched_ev = NULL;
}
- run_sched_ev = tor_event_new(tor_libevent_get_base(), -1,
- 0, scheduler_evt_callback, NULL);
+ run_sched_ev = mainloop_event_new(scheduler_evt_callback, NULL);
channels_pending = smartlist_new();
set_scheduler();
diff --git a/src/or/scheduler.h b/src/or/scheduler.h
index aeba9e2b75..08b02e286f 100644
--- a/src/or/scheduler.h
+++ b/src/or/scheduler.h
@@ -155,12 +155,12 @@ void scheduler_bug_occurred(const channel_t *chan);
smartlist_t *get_channels_pending(void);
MOCK_DECL(int, scheduler_compare_channels,
(const void *c1_v, const void *c2_v));
-void scheduler_ev_active(int flags);
+void scheduler_ev_active(void);
void scheduler_ev_add(const struct timeval *next_run);
#ifdef TOR_UNIT_TESTS
extern smartlist_t *channels_pending;
-extern struct event *run_sched_ev;
+extern struct mainloop_event_t *run_sched_ev;
extern const scheduler_t *the_scheduler;
void scheduler_touch_channel(channel_t *chan);
#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/or/scheduler_kist.c b/src/or/scheduler_kist.c
index 6d6490077d..c6e9b72c48 100644
--- a/src/or/scheduler_kist.c
+++ b/src/or/scheduler_kist.c
@@ -3,8 +3,6 @@
#define SCHEDULER_KIST_PRIVATE
-#include <event2/event.h>
-
#include "or.h"
#include "buffers.h"
#include "config.h"
@@ -553,7 +551,7 @@ kist_scheduler_schedule(void)
/* Re-adding an event reschedules it. It does not duplicate it. */
scheduler_ev_add(&next_run);
} else {
- scheduler_ev_active(EV_TIMEOUT);
+ scheduler_ev_active();
}
}
diff --git a/src/or/scheduler_vanilla.c b/src/or/scheduler_vanilla.c
index 7a83b9da18..b674d8256c 100644
--- a/src/or/scheduler_vanilla.c
+++ b/src/or/scheduler_vanilla.c
@@ -1,8 +1,6 @@
/* Copyright (c) 2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#include <event2/event.h>
-
#include "or.h"
#include "config.h"
#define TOR_CHANNEL_INTERNAL_
@@ -42,7 +40,7 @@ vanilla_scheduler_schedule(void)
}
/* Activate our event so it can process channels. */
- scheduler_ev_active(EV_TIMEOUT);
+ scheduler_ev_active();
}
static void
diff --git a/src/or/status.c b/src/or/status.c
index 4f7be164b1..4c497739e8 100644
--- a/src/or/status.c
+++ b/src/or/status.c
@@ -25,7 +25,6 @@
#include "main.h"
#include "rephist.h"
#include "hibernate.h"
-#include "rephist.h"
#include "statefile.h"
#include "hs_stats.h"
#include "hs_service.h"
diff --git a/src/or/transports.c b/src/or/transports.c
index b08dcd1613..614fc81da8 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -135,7 +135,7 @@ static smartlist_t *transport_list = NULL;
/** Returns a transport_t struct for a transport proxy supporting the
protocol <b>name</b> listening at <b>addr</b>:<b>port</b> using
SOCKS version <b>socks_ver</b>. */
-static transport_t *
+STATIC transport_t *
transport_new(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver,
const char *extra_info_args)
@@ -222,8 +222,8 @@ transport_copy(const transport_t *transport)
/** Returns the transport in our transport list that has the name <b>name</b>.
* Else returns NULL. */
-transport_t *
-transport_get_by_name(const char *name)
+MOCK_IMPL(transport_t *,
+transport_get_by_name,(const char *name))
{
tor_assert(name);
@@ -1025,48 +1025,71 @@ parse_method_error(const char *line, int is_server)
line+strlen(error)+1);
}
-/** Parses an SMETHOD <b>line</b> and if well-formed it registers the
- * new transport in <b>mp</b>. */
-STATIC int
-parse_smethod_line(const char *line, managed_proxy_t *mp)
+/** A helper for parse_{c,s}method_line(), bootstraps its
+ * functionalities. If <b>is_smethod</b> is true then the
+ * the line to parse is a SMETHOD line otherwise it is a
+ * CMETHOD line*/
+static int
+parse_method_line_helper(const char *line,
+ managed_proxy_t *mp,
+ int is_smethod)
{
+ int item_index = 0;
int r;
- smartlist_t *items = NULL;
- char *method_name=NULL;
+ char *transport_name=NULL;
char *args_string=NULL;
char *addrport=NULL;
- tor_addr_t tor_addr;
+ int socks_ver=PROXY_NONE;
char *address=NULL;
uint16_t port = 0;
+ const char *method_str = is_smethod ? PROTO_SMETHOD : PROTO_CMETHOD;
+ const int min_args_count = is_smethod ? 3 : 4;
+
+ tor_addr_t tor_addr;
transport_t *transport=NULL;
+ smartlist_t *items= smartlist_new();
- items = smartlist_new();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
- if (smartlist_len(items) < 3) {
- log_warn(LD_CONFIG, "Server managed proxy sent us a SMETHOD line "
- "with too few arguments.");
+ if (smartlist_len(items) < min_args_count) {
+ log_warn(LD_CONFIG, "Managed proxy sent us a %s line "
+ "with too few arguments.", method_str);
goto err;
}
- /* Example of legit SMETHOD line:
- SMETHOD obfs2 0.0.0.0:25612 ARGS:secret=supersekrit,key=superkey */
-
- tor_assert(!strcmp(smartlist_get(items,0),PROTO_SMETHOD));
+ tor_assert(!strcmp(smartlist_get(items, item_index),method_str));
+ ++item_index;
- method_name = smartlist_get(items,1);
- if (!string_is_C_identifier(method_name)) {
+ transport_name = smartlist_get(items,item_index);
+ ++item_index;
+ if (!string_is_C_identifier(transport_name)) {
log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
- method_name);
+ transport_name);
goto err;
}
- addrport = smartlist_get(items, 2);
+ /** Check for the proxy method sent to us in CMETHOD line. */
+ if (!is_smethod) {
+ const char *socks_ver_str = smartlist_get(items,item_index);
+ ++item_index;
+
+ if (!strcmp(socks_ver_str,"socks4")) {
+ socks_ver = PROXY_SOCKS4;
+ } else if (!strcmp(socks_ver_str,"socks5")) {
+ socks_ver = PROXY_SOCKS5;
+ } else {
+ log_warn(LD_CONFIG, "Client managed proxy sent us a proxy protocol "
+ "we don't recognize. (%s)", socks_ver_str);
+ goto err;
+ }
+ }
+
+ addrport = smartlist_get(items, item_index);
+ ++item_index;
if (tor_addr_port_split(LOG_WARN, addrport, &address, &port)<0) {
- log_warn(LD_CONFIG, "Error parsing transport "
- "address '%s'", addrport);
+ log_warn(LD_CONFIG, "Error parsing transport address '%s'", addrport);
goto err;
}
@@ -1081,10 +1104,11 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
goto err;
}
- if (smartlist_len(items) > 3) {
+ /** Check for options in the SMETHOD line. */
+ if (is_smethod && smartlist_len(items) > min_args_count) {
/* Seems like there are also some [options] in the SMETHOD line.
Let's see if we can parse them. */
- char *options_string = smartlist_get(items, 3);
+ char *options_string = smartlist_get(items, item_index);
log_debug(LD_CONFIG, "Got options_string: %s", options_string);
if (!strcmpstart(options_string, "ARGS:")) {
args_string = options_string+strlen("ARGS:");
@@ -1092,15 +1116,20 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
}
}
- transport = transport_new(&tor_addr, port, method_name,
- PROXY_NONE, args_string);
+ transport = transport_new(&tor_addr, port, transport_name,
+ socks_ver, args_string);
smartlist_add(mp->transports, transport);
- /* For now, notify the user so that they know where the server
- transport is listening. */
- log_info(LD_CONFIG, "Server transport %s at %s:%d.",
- method_name, address, (int)port);
+ /** Logs info about line parsing success for client or server */
+ if (is_smethod) {
+ log_info(LD_CONFIG, "Server transport %s at %s:%d.",
+ transport_name, address, (int)port);
+ } else {
+ log_info(LD_CONFIG, "Transport %s at %s:%d with SOCKS %d. "
+ "Attached to managed proxy.",
+ transport_name, address, (int)port, socks_ver);
+ }
r=0;
goto done;
@@ -1115,93 +1144,24 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
return r;
}
+/** Parses an SMETHOD <b>line</b> and if well-formed it registers the
+ * new transport in <b>mp</b>. */
+STATIC int
+parse_smethod_line(const char *line, managed_proxy_t *mp)
+{
+ /* Example of legit SMETHOD line:
+ SMETHOD obfs2 0.0.0.0:25612 ARGS:secret=supersekrit,key=superkey */
+ return parse_method_line_helper(line, mp, 1);
+}
+
/** Parses a CMETHOD <b>line</b>, and if well-formed it registers
* the new transport in <b>mp</b>. */
STATIC int
parse_cmethod_line(const char *line, managed_proxy_t *mp)
{
- int r;
- smartlist_t *items = NULL;
-
- char *method_name=NULL;
-
- char *socks_ver_str=NULL;
- int socks_ver=PROXY_NONE;
-
- char *addrport=NULL;
- tor_addr_t tor_addr;
- char *address=NULL;
- uint16_t port = 0;
-
- transport_t *transport=NULL;
-
- items = smartlist_new();
- smartlist_split_string(items, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
- if (smartlist_len(items) < 4) {
- log_warn(LD_CONFIG, "Client managed proxy sent us a CMETHOD line "
- "with too few arguments.");
- goto err;
- }
-
- tor_assert(!strcmp(smartlist_get(items,0),PROTO_CMETHOD));
-
- method_name = smartlist_get(items,1);
- if (!string_is_C_identifier(method_name)) {
- log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
- method_name);
- goto err;
- }
-
- socks_ver_str = smartlist_get(items,2);
-
- if (!strcmp(socks_ver_str,"socks4")) {
- socks_ver = PROXY_SOCKS4;
- } else if (!strcmp(socks_ver_str,"socks5")) {
- socks_ver = PROXY_SOCKS5;
- } else {
- log_warn(LD_CONFIG, "Client managed proxy sent us a proxy protocol "
- "we don't recognize. (%s)", socks_ver_str);
- goto err;
- }
-
- addrport = smartlist_get(items, 3);
- if (tor_addr_port_split(LOG_WARN, addrport, &address, &port)<0) {
- log_warn(LD_CONFIG, "Error parsing transport "
- "address '%s'", addrport);
- goto err;
- }
-
- if (!port) {
- log_warn(LD_CONFIG,
- "Transport address '%s' has no port.", addrport);
- goto err;
- }
-
- if (tor_addr_parse(&tor_addr, address) < 0) {
- log_warn(LD_CONFIG, "Error parsing transport address '%s'", address);
- goto err;
- }
-
- transport = transport_new(&tor_addr, port, method_name, socks_ver, NULL);
-
- smartlist_add(mp->transports, transport);
-
- log_info(LD_CONFIG, "Transport %s at %s:%d with SOCKS %d. "
- "Attached to managed proxy.",
- method_name, address, (int)port, socks_ver);
-
- r=0;
- goto done;
-
- err:
- r = -1;
-
- done:
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- tor_free(address);
- return r;
+ /* Example of legit CMETHOD line:
+ CMETHOD obfs2 socks5 127.0.0.1:35713 */
+ return parse_method_line_helper(line, mp, 0);
}
/** Parses an PROXY-ERROR <b>line</b> and warns the user accordingly. */
diff --git a/src/or/transports.h b/src/or/transports.h
index 1b2786472c..022b926a03 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -38,7 +38,7 @@ MOCK_DECL(int, transport_add_from_config,
void transport_free_(transport_t *transport);
#define transport_free(tr) FREE_AND_NULL(transport_t, transport_free_, (tr))
-transport_t *transport_get_by_name(const char *name);
+MOCK_DECL(transport_t*, transport_get_by_name, (const char *name));
MOCK_DECL(void, pt_kickstart_proxy,
(const smartlist_t *transport_list, char **proxy_argv,
@@ -113,6 +113,9 @@ typedef struct {
smartlist_t *transports;
} managed_proxy_t;
+STATIC transport_t *transport_new(const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver,
+ const char *extra_info_args);
STATIC int parse_cmethod_line(const char *line, managed_proxy_t *mp);
STATIC int parse_smethod_line(const char *line, managed_proxy_t *mp);
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 4f918c0221..91c0502c60 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -18,6 +18,7 @@ dependencies = [
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
"smartlist 0.0.1",
"tor_allocate 0.0.1",
+ "tor_log 0.1.0",
"tor_util 0.0.1",
]
@@ -36,6 +37,14 @@ dependencies = [
]
[[package]]
+name = "tor_log"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tor_allocate 0.0.1",
+]
+
+[[package]]
name = "tor_rust"
version = "0.1.0"
dependencies = [
@@ -49,6 +58,7 @@ version = "0.0.1"
dependencies = [
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
"tor_allocate 0.0.1",
+ "tor_log 0.1.0",
]
[metadata]
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index 953c9b96b7..4ae8033eb3 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -1,5 +1,6 @@
[workspace]
-members = ["tor_util", "protover", "smartlist", "external", "tor_allocate", "tor_rust"]
+members = ["tor_util", "protover", "smartlist", "external", "tor_allocate",
+"tor_rust", "tor_log"]
[profile.release]
debug = true
diff --git a/src/rust/include.am b/src/rust/include.am
index 7a0181e373..f1aa0bd5ac 100644
--- a/src/rust/include.am
+++ b/src/rust/include.am
@@ -20,6 +20,9 @@ EXTRA_DIST +=\
src/rust/tor_allocate/Cargo.toml \
src/rust/tor_allocate/lib.rs \
src/rust/tor_allocate/tor_allocate.rs \
+ src/rust/tor_log/Cargo.toml \
+ src/rust/tor_log/lib.rs \
+ src/rust/tor_log/tor_log.rs \
src/rust/tor_rust/Cargo.toml \
src/rust/tor_rust/include.am \
src/rust/tor_rust/lib.rs \
diff --git a/src/rust/protover/Cargo.toml b/src/rust/protover/Cargo.toml
index 86301b8787..af1089c914 100644
--- a/src/rust/protover/Cargo.toml
+++ b/src/rust/protover/Cargo.toml
@@ -3,6 +3,9 @@ authors = ["The Tor Project"]
version = "0.0.1"
name = "protover"
+[features]
+testing = ["tor_log/testing"]
+
[dependencies]
libc = "=0.2.39"
@@ -18,6 +21,9 @@ path = "../tor_util"
[dependencies.tor_allocate]
path = "../tor_allocate"
+[dependencies.tor_log]
+path = "../tor_log"
+
[lib]
name = "protover"
path = "lib.rs"
diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs
index a40353eb13..2dfeda87b2 100644
--- a/src/rust/protover/ffi.rs
+++ b/src/rust/protover/ffi.rs
@@ -11,9 +11,6 @@ use std::ffi::CString;
use smartlist::*;
use tor_allocate::allocate_and_copy_string;
-use tor_util::strings::byte_slice_is_c_like;
-use tor_util::strings::empty_static_cstr;
-
use errors::ProtoverError;
use protover::*;
@@ -158,18 +155,7 @@ pub extern "C" fn protocol_list_supports_protocol_or_later(
pub extern "C" fn protover_get_supported_protocols() -> *const c_char {
let supported: &'static CStr;
- // If we're going to pass it to C, there cannot be any intermediate NUL
- // bytes. An assert is okay here, since changing the const byte slice
- // in protover.rs to contain a NUL byte somewhere in the middle would be a
- // programming error.
- assert!(byte_slice_is_c_like(SUPPORTED_PROTOCOLS));
-
- // It's okay to unwrap the result of this function because
- // we can see that the bytes we're passing into it 1) are valid UTF-8,
- // 2) have no intermediate NUL bytes, and 3) are terminated with a NUL
- // byte.
- supported = CStr::from_bytes_with_nul(SUPPORTED_PROTOCOLS).unwrap();
-
+ supported = get_supported_protocols_cstr();
supported.as_ptr()
}
@@ -228,10 +214,9 @@ pub extern "C" fn protover_is_supported_here(
#[no_mangle]
pub extern "C" fn protover_compute_for_old_tor(version: *const c_char) -> *const c_char {
let supported: &'static CStr;
- let elder_protocols: &'static [u8];
let empty: &'static CStr;
- empty = empty_static_cstr();
+ empty = cstr!("");
if version.is_null() {
return empty.as_ptr();
@@ -246,19 +231,6 @@ pub extern "C" fn protover_compute_for_old_tor(version: *const c_char) -> *const
Err(_) => return empty.as_ptr(),
};
- elder_protocols = compute_for_old_tor_cstr(&version);
-
- // If we're going to pass it to C, there cannot be any intermediate NUL
- // bytes. An assert is okay here, since changing the const byte slice
- // in protover.rs to contain a NUL byte somewhere in the middle would be a
- // programming error.
- assert!(byte_slice_is_c_like(elder_protocols));
-
- // It's okay to unwrap the result of this function because
- // we can see that the bytes we're passing into it 1) are valid UTF-8,
- // 2) have no intermediate NUL bytes, and 3) are terminated with a NUL
- // byte.
- supported = CStr::from_bytes_with_nul(elder_protocols).unwrap_or(empty);
-
+ supported = compute_for_old_tor_cstr(&version);
supported.as_ptr()
}
diff --git a/src/rust/protover/lib.rs b/src/rust/protover/lib.rs
index 483260bca8..ce964196fd 100644
--- a/src/rust/protover/lib.rs
+++ b/src/rust/protover/lib.rs
@@ -28,6 +28,7 @@ extern crate libc;
extern crate smartlist;
extern crate external;
extern crate tor_allocate;
+#[macro_use]
extern crate tor_util;
pub mod errors;
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
index 5e5a31cd33..514aeffc58 100644
--- a/src/rust/protover/protover.rs
+++ b/src/rust/protover/protover.rs
@@ -3,12 +3,12 @@
use std::collections::HashMap;
use std::collections::hash_map;
+use std::ffi::CStr;
use std::fmt;
use std::str;
use std::str::FromStr;
use std::string::String;
-use tor_util::strings::NUL_BYTE;
use external::c_tor_version_as_new_as;
use errors::ProtoverError;
@@ -28,30 +28,6 @@ const FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS: &'static str = "0.2.9.3-alpha";
/// C_RUST_COUPLED: src/or/protover.c `MAX_PROTOCOLS_TO_EXPAND`
const MAX_PROTOCOLS_TO_EXPAND: usize = (1<<16);
-/// Currently supported protocols and their versions, as a byte-slice.
-///
-/// # Warning
-///
-/// This byte-slice ends in a NUL byte. This is so that we can directly convert
-/// it to an `&'static CStr` in the FFI code, in order to hand the static string
-/// to C in a way that is compatible with C static strings.
-///
-/// Rust code which wishes to accesses this string should use
-/// `protover::get_supported_protocols()` instead.
-///
-/// C_RUST_COUPLED: src/or/protover.c `protover_get_supported_protocols`
-pub(crate) const SUPPORTED_PROTOCOLS: &'static [u8] =
- b"Cons=1-2 \
- Desc=1-2 \
- DirCache=1-2 \
- HSDir=1-2 \
- HSIntro=3-4 \
- HSRend=1-2 \
- Link=1-5 \
- LinkAuth=1,3 \
- Microdesc=1-2 \
- Relay=1-2\0";
-
/// Known subprotocols in Tor. Indicates which subprotocol a relay supports.
///
/// C_RUST_COUPLED: src/or/protover.h `protocol_type_t`
@@ -124,21 +100,33 @@ impl From<Protocol> for UnknownProtocol {
}
}
-/// Get the string representation of current supported protocols
+/// Get a CStr representation of current supported protocols, for
+/// passing to C, or for converting to a `&str` for Rust.
///
/// # Returns
///
-/// A `String` whose value is the existing protocols supported by tor.
+/// An `&'static CStr` whose value is the existing protocols supported by tor.
/// Returned data is in the format as follows:
///
/// "HSDir=1-1 LinkAuth=1"
///
-pub fn get_supported_protocols() -> &'static str {
- // The `len() - 1` is to remove the NUL byte.
- // The `unwrap` is safe becauase we SUPPORTED_PROTOCOLS is under
- // our control.
- str::from_utf8(&SUPPORTED_PROTOCOLS[..SUPPORTED_PROTOCOLS.len() - 1])
- .unwrap_or("")
+/// # Note
+///
+/// Rust code can use the `&'static CStr` as a normal `&'a str` by
+/// calling `protover::get_supported_protocols`.
+///
+// C_RUST_COUPLED: src/or/protover.c `protover_get_supported_protocols`
+pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
+ cstr!("Cons=1-2 \
+ Desc=1-2 \
+ DirCache=1-2 \
+ HSDir=1-2 \
+ HSIntro=3-4 \
+ HSRend=1-2 \
+ Link=1-5 \
+ LinkAuth=1,3 \
+ Microdesc=1-2 \
+ Relay=1-2")
}
/// A map of protocol names to the versions of them which are supported.
@@ -161,7 +149,8 @@ impl ProtoEntry {
/// ProtoEntry, which is useful when looking up a specific
/// subprotocol.
pub fn supported() -> Result<Self, ProtoverError> {
- let supported: &'static str = get_supported_protocols();
+ let supported_cstr: &'static CStr = get_supported_protocols_cstr();
+ let supported: &str = supported_cstr.to_str().unwrap_or("");
supported.parse()
}
@@ -627,7 +616,7 @@ pub fn is_supported_here(proto: &Protocol, vers: &Version) -> bool {
///
/// # Returns
///
-/// A `&'static [u8]` encoding a list of protocol names and supported
+/// A `&'static CStr` encoding a list of protocol names and supported
/// versions. The string takes the following format:
///
/// "HSDir=1-1 LinkAuth=1"
@@ -643,24 +632,25 @@ pub fn is_supported_here(proto: &Protocol, vers: &Version) -> bool {
/// like to use this code in Rust, please see `compute_for_old_tor()`.
//
// C_RUST_COUPLED: src/rust/protover.c `compute_for_old_tor`
-pub(crate) fn compute_for_old_tor_cstr(version: &str) -> &'static [u8] {
+pub(crate) fn compute_for_old_tor_cstr(version: &str) -> &'static CStr {
+ let empty: &'static CStr = cstr!("");
+
if c_tor_version_as_new_as(version, FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS) {
- return NUL_BYTE;
+ return empty;
}
if c_tor_version_as_new_as(version, "0.2.9.1-alpha") {
- return b"Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 \
- Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2\0";
+ return cstr!("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 \
+ Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2");
}
if c_tor_version_as_new_as(version, "0.2.7.5") {
- return b"Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
- Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2\0";
+ return cstr!("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
+ Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2");
}
if c_tor_version_as_new_as(version, "0.2.4.19") {
- return b"Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
- Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2\0";
+ return cstr!("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
+ Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2");
}
-
- NUL_BYTE
+ empty
}
/// Since older versions of Tor cannot infer their own subprotocols,
@@ -691,14 +681,9 @@ pub(crate) fn compute_for_old_tor_cstr(version: &str) -> &'static [u8] {
//
// C_RUST_COUPLED: src/rust/protover.c `compute_for_old_tor`
pub fn compute_for_old_tor(version: &str) -> Result<&'static str, ProtoverError> {
- let mut computed: &'static [u8] = compute_for_old_tor_cstr(version);
-
- // Remove the NULL byte at the end.
- computed = &computed[..computed.len() - 1];
-
- // .from_utf8() fails with a Utf8Error if it couldn't validate the
+ // .to_str() fails with a Utf8Error if it couldn't validate the
// utf-8, so convert that here into an Unparseable ProtoverError.
- str::from_utf8(computed).or(Err(ProtoverError::Unparseable))
+ compute_for_old_tor_cstr(version).to_str().or(Err(ProtoverError::Unparseable))
}
#[cfg(test)]
diff --git a/src/rust/tor_allocate/tor_allocate.rs b/src/rust/tor_allocate/tor_allocate.rs
index 359df1cd7a..3c0037f139 100644
--- a/src/rust/tor_allocate/tor_allocate.rs
+++ b/src/rust/tor_allocate/tor_allocate.rs
@@ -1,12 +1,17 @@
// Copyright (c) 2016-2017, The Tor Project, Inc. */
// See LICENSE for licensing information */
+// No-op defined purely for testing at the module level
+use libc::c_char;
-use libc::{c_char, c_void};
+#[cfg(not(feature = "testing"))]
use std::{ptr, slice, mem};
+use libc::c_void;
-#[cfg(not(test))]
-extern "C" {
- fn tor_malloc_(size: usize) -> *mut c_void;
+// Define a no-op implementation for testing Rust modules without linking to C
+#[cfg(feature = "testing")]
+pub fn allocate_and_copy_string(s: &String) -> *mut c_char {
+ use std::ffi::CString;
+ CString::new(s.as_str()).unwrap().into_raw()
}
// Defined only for tests, used for testing purposes, so that we don't need
@@ -17,6 +22,11 @@ unsafe extern "C" fn tor_malloc_(size: usize) -> *mut c_void {
malloc(size)
}
+#[cfg(all(not(test), not(feature = "testing")))]
+extern "C" {
+ fn tor_malloc_(size: usize) -> *mut c_void;
+}
+
/// Allocate memory using tor_malloc_ and copy an existing string into the
/// allocated buffer, returning a pointer that can later be called in C.
///
@@ -28,6 +38,7 @@ unsafe extern "C" fn tor_malloc_(size: usize) -> *mut c_void {
///
/// A `*mut c_char` that should be freed by tor_free in C
///
+#[cfg(not(feature = "testing"))]
pub fn allocate_and_copy_string(src: &String) -> *mut c_char {
let bytes: &[u8] = src.as_bytes();
diff --git a/src/rust/tor_log/Cargo.toml b/src/rust/tor_log/Cargo.toml
new file mode 100644
index 0000000000..971cd658b1
--- /dev/null
+++ b/src/rust/tor_log/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "tor_log"
+version = "0.1.0"
+authors = ["The Tor Project"]
+
+[lib]
+name = "tor_log"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
+
+[features]
+testing = []
+
+[dependencies]
+libc = "0.2.39"
+
+[dependencies.tor_allocate]
+path = "../tor_allocate"
diff --git a/src/rust/tor_log/lib.rs b/src/rust/tor_log/lib.rs
new file mode 100644
index 0000000000..72f9e38339
--- /dev/null
+++ b/src/rust/tor_log/lib.rs
@@ -0,0 +1,16 @@
+//! Copyright (c) 2016-2017, The Tor Project, Inc. */
+//! See LICENSE for licensing information */
+
+//! Logging wrapper for Rust to utilize Tor's logger, found at
+//! src/common/log.c and src/common/torlog.h
+//!
+//! Exposes different interfaces depending on whether we are running in test
+//! or non-test mode. When testing, we use a no-op implementation,
+//! otherwise we link directly to C.
+
+extern crate libc;
+extern crate tor_allocate;
+
+mod tor_log;
+
+pub use tor_log::*;
diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs
new file mode 100644
index 0000000000..1fdc0026bf
--- /dev/null
+++ b/src/rust/tor_log/tor_log.rs
@@ -0,0 +1,270 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+// Note that these functions are untested due to the fact that there are no
+// return variables to test and they are calling into a C API.
+
+/// The related domain which the logging message is relevant. For example,
+/// log messages relevant to networking would use LogDomain::LdNet, whereas
+/// general messages can use LdGeneral.
+#[derive(Eq, PartialEq)]
+pub enum LogDomain {
+ Net,
+ General,
+}
+
+/// The severity level at which to log messages.
+#[derive(Eq, PartialEq)]
+pub enum LogSeverity {
+ Notice,
+ Warn,
+}
+
+/// Main entry point for Rust modules to log messages.
+///
+/// # Inputs
+///
+/// * A `severity` of type LogSeverity, which defines the level of severity the
+/// message will be logged.
+/// * A `domain` of type LogDomain, which defines the domain the log message
+/// will be associated with.
+/// * A `function` of type &str, which defines the name of the function where
+/// the message is being logged. There is a current RFC for a macro that
+/// defines function names. When it is, we should use it. See
+/// https://github.com/rust-lang/rfcs/pull/1719
+/// * A `message` of type &str, which is the log message itself.
+#[macro_export]
+macro_rules! tor_log_msg {
+ ($severity: path,
+ $domain: path,
+ $function: expr,
+ $($message:tt)*) =>
+ {
+ {
+ let msg = format!($($message)*);
+ $crate::tor_log_msg_impl($severity, $domain, $function, msg)
+ }
+ };
+}
+
+#[inline]
+pub fn tor_log_msg_impl(
+ severity: LogSeverity,
+ domain: LogDomain,
+ function: &str,
+ message: String,
+) {
+ use std::ffi::CString;
+
+ /// Default function name to log in case of errors when converting
+ /// a function name to a CString
+ const ERR_LOG_FUNCTION: &str = "tor_log_msg";
+
+ /// Default message to log in case of errors when converting a log
+ /// message to a CString
+ const ERR_LOG_MSG: &str = "Unable to log message from Rust \
+ module due to error when converting to CString";
+
+ let func = match CString::new(function) {
+ Ok(n) => n,
+ Err(_) => CString::new(ERR_LOG_FUNCTION).unwrap(),
+ };
+
+ let msg = match CString::new(message) {
+ Ok(n) => n,
+ Err(_) => CString::new(ERR_LOG_MSG).unwrap(),
+ };
+
+ // Bind to a local variable to preserve ownership. This is essential so
+ // that ownership is guaranteed until these local variables go out of scope
+ let func_ptr = func.as_ptr();
+ let msg_ptr = msg.as_ptr();
+
+ let c_severity = unsafe { log::translate_severity(severity) };
+ let c_domain = unsafe { log::translate_domain(domain) };
+
+ unsafe { log::tor_log_string(c_severity, c_domain, func_ptr, msg_ptr) }
+}
+
+/// This implementation is used when compiling for actual use, as opposed to
+/// testing.
+#[cfg(all(not(test), not(feature = "testing")))]
+pub mod log {
+ use libc::{c_char, c_int};
+ use super::LogDomain;
+ use super::LogSeverity;
+
+ /// Severity log types. These mirror definitions in /src/common/torlog.h
+ /// C_RUST_COUPLED: src/common/log.c, log domain types
+ extern "C" {
+ static LOG_WARN_: c_int;
+ static LOG_NOTICE_: c_int;
+ }
+
+ /// Domain log types. These mirror definitions in /src/common/torlog.h
+ /// C_RUST_COUPLED: src/common/log.c, log severity types
+ extern "C" {
+ static LD_NET_: u32;
+ static LD_GENERAL_: u32;
+ }
+
+ /// Translate Rust defintions of log domain levels to C. This exposes a 1:1
+ /// mapping between types.
+ #[inline]
+ pub unsafe fn translate_domain(domain: LogDomain) -> u32 {
+ match domain {
+ LogDomain::Net => LD_NET_,
+ LogDomain::General => LD_GENERAL_,
+ }
+ }
+
+ /// Translate Rust defintions of log severity levels to C. This exposes a
+ /// 1:1 mapping between types.
+ #[inline]
+ pub unsafe fn translate_severity(severity: LogSeverity) -> c_int {
+ match severity {
+ LogSeverity::Warn => LOG_WARN_,
+ LogSeverity::Notice => LOG_NOTICE_,
+ }
+ }
+
+ /// The main entry point into Tor's logger. When in non-test mode, this
+ /// will link directly with `tor_log_string` in /src/or/log.c
+ extern "C" {
+ pub fn tor_log_string(
+ severity: c_int,
+ domain: u32,
+ function: *const c_char,
+ string: *const c_char,
+ );
+ }
+}
+
+/// This module exposes no-op functionality for testing other Rust modules
+/// without linking to C.
+#[cfg(any(test, feature = "testing"))]
+pub mod log {
+ use libc::{c_char, c_int};
+ use super::LogDomain;
+ use super::LogSeverity;
+
+ pub static mut LAST_LOGGED_FUNCTION: *mut String = 0 as *mut String;
+ pub static mut LAST_LOGGED_MESSAGE: *mut String = 0 as *mut String;
+
+ pub unsafe fn tor_log_string(
+ _severity: c_int,
+ _domain: u32,
+ function: *const c_char,
+ message: *const c_char,
+ ) {
+ use std::ffi::CStr;
+
+ let f = CStr::from_ptr(function);
+ let fct = match f.to_str() {
+ Ok(n) => n,
+ Err(_) => "",
+ };
+ LAST_LOGGED_FUNCTION = Box::into_raw(Box::new(String::from(fct)));
+
+ let m = CStr::from_ptr(message);
+ let msg = match m.to_str() {
+ Ok(n) => n,
+ Err(_) => "",
+ };
+ LAST_LOGGED_MESSAGE = Box::into_raw(Box::new(String::from(msg)));
+ }
+
+ pub unsafe fn translate_domain(_domain: LogDomain) -> u32 {
+ 1
+ }
+
+ pub unsafe fn translate_severity(_severity: LogSeverity) -> c_int {
+ 1
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use tor_log::*;
+ use tor_log::log::{LAST_LOGGED_FUNCTION, LAST_LOGGED_MESSAGE};
+
+ #[test]
+ fn test_get_log_message() {
+ {
+ fn test_macro() {
+ tor_log_msg!(
+ LogSeverity::Warn,
+ LogDomain::Net,
+ "test_macro",
+ "test log message {}",
+ "a",
+ );
+ }
+
+ test_macro();
+
+ let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
+ assert_eq!("test_macro", *function);
+
+ let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
+ assert_eq!("test log message a", *message);
+ }
+
+ // test multiple inputs into the log message
+ {
+ fn test_macro() {
+ tor_log_msg!(
+ LogSeverity::Warn,
+ LogDomain::Net,
+ "next_test_macro",
+ "test log message {} {} {} {} {}",
+ 1,
+ 2,
+ 3,
+ 4,
+ 5
+ );
+ }
+
+ test_macro();
+
+ let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
+ assert_eq!("next_test_macro", *function);
+
+ let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
+ assert_eq!("test log message 1 2 3 4 5", *message);
+ }
+
+ // test how a long log message will be formatted
+ {
+ fn test_macro() {
+ tor_log_msg!(
+ LogSeverity::Warn,
+ LogDomain::Net,
+ "test_macro",
+ "{}",
+ "All the world's a stage, and all the men and women \
+ merely players: they have their exits and their \
+ entrances; and one man in his time plays many parts, his \
+ acts being seven ages."
+ );
+ }
+
+ test_macro();
+
+ let expected_string = "All the world's a \
+ stage, and all the men \
+ and women merely players: \
+ they have their exits and \
+ their entrances; and one man \
+ in his time plays many parts, \
+ his acts being seven ages.";
+
+ let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
+ assert_eq!("test_macro", *function);
+
+ let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
+ assert_eq!(expected_string, *message);
+ }
+ }
+}
diff --git a/src/rust/tor_util/Cargo.toml b/src/rust/tor_util/Cargo.toml
index b540d8c847..a606a280b2 100644
--- a/src/rust/tor_util/Cargo.toml
+++ b/src/rust/tor_util/Cargo.toml
@@ -11,6 +11,9 @@ crate_type = ["rlib", "staticlib"]
[dependencies.tor_allocate]
path = "../tor_allocate"
+[dependencies.tor_log]
+path = "../tor_log"
+
[dependencies]
libc = "=0.2.39"
diff --git a/src/rust/tor_util/ffi.rs b/src/rust/tor_util/ffi.rs
index 5c3cdba4be..32779ed476 100644
--- a/src/rust/tor_util/ffi.rs
+++ b/src/rust/tor_util/ffi.rs
@@ -5,8 +5,7 @@
//! called from C.
//!
-use libc::c_char;
-use tor_allocate::allocate_and_copy_string;
+use tor_log::{LogSeverity, LogDomain};
/// Returns a short string to announce Rust support during startup.
///
@@ -17,10 +16,12 @@ use tor_allocate::allocate_and_copy_string;
/// tor_free(rust_str);
/// ```
#[no_mangle]
-pub extern "C" fn rust_welcome_string() -> *mut c_char {
- let rust_welcome = String::from(
+pub extern "C" fn rust_log_welcome_string() {
+ tor_log_msg!(
+ LogSeverity::Notice,
+ LogDomain::General,
+ "rust_log_welcome_string",
"Tor is running with Rust integration. Please report \
- any bugs you encounter.",
+ any bugs you encounter."
);
- allocate_and_copy_string(&rust_welcome)
}
diff --git a/src/rust/tor_util/lib.rs b/src/rust/tor_util/lib.rs
index 12cb3896b6..94697b6069 100644
--- a/src/rust/tor_util/lib.rs
+++ b/src/rust/tor_util/lib.rs
@@ -7,5 +7,8 @@
extern crate libc;
extern crate tor_allocate;
+#[macro_use]
+extern crate tor_log;
+
pub mod ffi;
pub mod strings;
diff --git a/src/rust/tor_util/strings.rs b/src/rust/tor_util/strings.rs
index 9321ce4f85..505191d913 100644
--- a/src/rust/tor_util/strings.rs
+++ b/src/rust/tor_util/strings.rs
@@ -3,80 +3,138 @@
//! Utilities for working with static strings.
-use std::ffi::CStr;
-
-/// A byte-array containing a single NUL byte (`b"\0"`).
-pub const NUL_BYTE: &'static [u8] = b"\0";
-
-/// Determine if a byte slice is a C-like string.
-///
-/// These checks guarantee that:
-///
-/// 1. there are no intermediate NUL bytes
-/// 2. the last byte *is* a NUL byte
+/// Create a `CStr` from a literal byte slice, appending a NUL byte to it first.
///
/// # Warning
///
-/// This function does _not_ guarantee that the bytes represent any valid
-/// encoding such as ASCII or UTF-8.
+/// The literal byte slice which is taken as an argument *MUST NOT* have any NUL
+/// bytes (`b"\0"`) in it, anywhere, or else an empty string will be returned
+/// (`CStr::from_bytes_with_nul_unchecked(b"\0")`) so as to avoid `panic!()`ing.
///
/// # Examples
///
/// ```
-/// # use tor_util::strings::byte_slice_is_c_like;
-/// #
-/// let bytes: &[u8] = b"foo bar baz";
+/// #[macro_use]
+/// extern crate tor_util;
///
-/// assert!(byte_slice_is_c_like(&bytes) == false);
+/// use std::ffi::CStr;
///
-/// let bytes: &[u8] = b"foo\0bar baz";
+/// # fn do_test() -> Result<&'static CStr, &'static str> {
+/// let message: &'static str = "This is a test of the tsunami warning system.";
+/// let tuesday: &'static CStr;
+/// let original: &str;
///
-/// assert!(byte_slice_is_c_like(&bytes) == false);
+/// tuesday = cstr!("This is a test of the tsunami warning system.");
+/// original = tuesday.to_str().or(Err("Couldn't unwrap CStr!"))?;
///
-/// let bytes: &[u8] = b"foo bar baz\0";
+/// assert!(original == message);
+/// #
+/// # Ok(tuesday)
+/// # }
+/// # fn main() {
+/// # do_test(); // so that we can use the ? operator in the test
+/// # }
+/// ```
+/// It is also possible to pass several string literals to this macro. They
+/// will be concatenated together in the order of the arguments, unmodified,
+/// before finally being suffixed with a NUL byte:
///
-/// assert!(byte_slice_is_c_like(&bytes) == true);
/// ```
-pub fn byte_slice_is_c_like(bytes: &[u8]) -> bool {
- if !bytes[..bytes.len() - 1].contains(&0x00) && bytes[bytes.len() - 1] == 0x00 {
- return true;
- }
- false
-}
-
-/// Get a static `CStr` containing a single `NUL_BYTE`.
+/// #[macro_use]
+/// extern crate tor_util;
+/// #
+/// # use std::ffi::CStr;
+/// #
+/// # fn do_test() -> Result<&'static CStr, &'static str> {
///
-/// # Examples
+/// let quux: &'static CStr = cstr!("foo", "bar", "baz");
+/// let orig: &'static str = quux.to_str().or(Err("Couldn't unwrap CStr!"))?;
///
-/// When used as follows in a Rust FFI function, which could be called
-/// from C:
+/// assert!(orig == "foobarbaz");
+/// # Ok(quux)
+/// # }
+/// # fn main() {
+/// # do_test(); // so that we can use the ? operator in the test
+/// # }
+/// ```
+/// This is useful for passing static strings to C from Rust FFI code. To do so
+/// so, use the `.as_ptr()` method on the resulting `&'static CStr` to convert
+/// it to the Rust equivalent of a C `const char*`:
///
/// ```
-/// # extern crate libc;
-/// # extern crate tor_util;
-/// #
-/// # use tor_util::strings::empty_static_cstr;
-/// use libc::c_char;
+/// #[macro_use]
+/// extern crate tor_util;
+///
/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
///
-/// pub extern "C" fn give_c_code_an_empty_static_string() -> *const c_char {
-/// let empty: &'static CStr = empty_static_cstr();
+/// pub extern "C" fn give_static_borrowed_string_to_c() -> *const c_char {
+/// let hello: &'static CStr = cstr!("Hello, language my parents wrote.");
///
-/// empty.as_ptr()
+/// hello.as_ptr()
/// }
-///
/// # fn main() {
-/// # give_c_code_an_empty_static_string();
+/// # let greetings = give_static_borrowed_string_to_c();
/// # }
/// ```
+/// Note that the C code this static borrowed string is passed to *MUST NOT*
+/// attempt to free the memory for the string.
+///
+/// # Note
+///
+/// An unfortunate limitation of the rustc compiler (as of 1.25.0-nightly), is
+/// that the first example above compiles, but if we were to change the
+/// assignment of `tuesday` as follows, it will fail to compile, because Rust
+/// macros are expanded at parse time, and at parse time there is no symbol
+/// table available.
///
-/// This equates to an "empty" `const char*` static string in C.
-pub fn empty_static_cstr() -> &'static CStr {
- let empty: &'static CStr;
+/// ```ignore
+/// tuesday = cstr!(message);
+/// ```
+/// with the error message `error: expected a literal`.
+///
+/// # Returns
+///
+/// If the string literals passed as arguments contain no NUL bytes anywhere,
+/// then an `&'static CStr` containing the (concatenated) bytes of the string
+/// literal(s) passed as arguments, with a NUL byte appended, is returned.
+/// Otherwise, an `&'static CStr` containing a single NUL byte is returned (an
+/// "empty" string in C).
+#[macro_export]
+macro_rules! cstr {
+ ($($bytes:expr),*) => (
+ ::std::ffi::CStr::from_bytes_with_nul(
+ concat!($($bytes),*, "\0").as_bytes()
+ ).unwrap_or(
+ unsafe{
+ ::std::ffi::CStr::from_bytes_with_nul_unchecked(b"\0")
+ }
+ )
+ )
+}
+
+#[cfg(test)]
+mod test {
+ use std::ffi::CStr;
+
+ #[test]
+ fn cstr_macro() {
+ let _: &'static CStr = cstr!("boo");
+ }
+
+ #[test]
+ fn cstr_macro_multi_input() {
+ let quux: &'static CStr = cstr!("foo", "bar", "baz");
- unsafe {
- empty = CStr::from_bytes_with_nul_unchecked(NUL_BYTE);
+ assert!(quux.to_str().unwrap() == "foobarbaz");
}
- empty
+ #[test]
+ fn cstr_macro_bad_input() {
+ let waving: &'static CStr = cstr!("waving not drowning o/");
+ let drowning: &'static CStr = cstr!("\0 drowning not waving");
+
+ assert!(waving.to_str().unwrap() == "waving not drowning o/");
+ assert!(drowning.to_str().unwrap() == "")
+ }
}
diff --git a/src/test/bench.c b/src/test/bench.c
index 92d7a244f7..be04c5209a 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -12,7 +12,7 @@
#include "or.h"
#include "onion_tap.h"
-#include "relay.h"
+#include "relay_crypto.h"
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
@@ -505,10 +505,10 @@ bench_cell_ops(void)
char key1[CIPHER_KEY_LEN], key2[CIPHER_KEY_LEN];
crypto_rand(key1, sizeof(key1));
crypto_rand(key2, sizeof(key2));
- or_circ->p_crypto = crypto_cipher_new(key1);
- or_circ->n_crypto = crypto_cipher_new(key2);
- or_circ->p_digest = crypto_digest_new();
- or_circ->n_digest = crypto_digest_new();
+ or_circ->crypto.f_crypto = crypto_cipher_new(key1);
+ or_circ->crypto.b_crypto = crypto_cipher_new(key2);
+ or_circ->crypto.f_digest = crypto_digest_new();
+ or_circ->crypto.b_digest = crypto_digest_new();
reset_perftime();
@@ -518,7 +518,8 @@ bench_cell_ops(void)
for (i = 0; i < iters; ++i) {
char recognized = 0;
crypt_path_t *layer_hint = NULL;
- relay_crypt(TO_CIRCUIT(or_circ), cell, d, &layer_hint, &recognized);
+ relay_decrypt_cell(TO_CIRCUIT(or_circ), cell, d,
+ &layer_hint, &recognized);
}
end = perftime();
printf("%sbound cells: %.2f ns per cell. (%.2f ns per byte of payload)\n",
@@ -527,10 +528,7 @@ bench_cell_ops(void)
NANOCOUNT(start,end,iters*CELL_PAYLOAD_SIZE));
}
- crypto_digest_free(or_circ->p_digest);
- crypto_digest_free(or_circ->n_digest);
- crypto_cipher_free(or_circ->p_crypto);
- crypto_cipher_free(or_circ->n_crypto);
+ relay_crypto_clear(&or_circ->crypto);
tor_free(or_circ);
tor_free(cell);
}
diff --git a/src/test/include.am b/src/test/include.am
index b768f74475..474da3f880 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -88,7 +88,9 @@ src_test_test_SOURCES = \
src/test/test_addr.c \
src/test/test_address.c \
src/test/test_address_set.c \
+ src/test/test_bridges.c \
src/test/test_buffers.c \
+ src/test/test_bwmgt.c \
src/test/test_cell_formats.c \
src/test/test_cell_queue.c \
src/test/test_channel.c \
@@ -118,6 +120,7 @@ src_test_test_SOURCES = \
src/test/test_dos.c \
src/test/test_entryconn.c \
src/test/test_entrynodes.c \
+ src/test/test_geoip.c \
src/test/test_guardfraction.c \
src/test/test_extorport.c \
src/test/test_hs.c \
@@ -150,6 +153,7 @@ src_test_test_SOURCES = \
src/test/test_pubsub.c \
src/test/test_relay.c \
src/test/test_relaycell.c \
+ src/test/test_relaycrypt.c \
src/test/test_rendcache.c \
src/test/test_replay.c \
src/test/test_router.c \
diff --git a/src/test/test-timers.c b/src/test/test-timers.c
index a0b5b535c2..5efd99cacf 100644
--- a/src/test/test-timers.c
+++ b/src/test/test-timers.c
@@ -7,8 +7,6 @@
#include <stdio.h>
#include <string.h>
-#include <event2/event.h>
-
#include "compat.h"
#include "compat_libevent.h"
#include "crypto.h"
@@ -50,7 +48,7 @@ timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono)
// printf("%d / %d\n",n_fired, N_TIMERS);
if (n_fired == n_active_timers) {
- event_base_loopbreak(tor_libevent_get_base());
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
}
}
@@ -90,7 +88,7 @@ main(int argc, char **argv)
--n_active_timers;
}
- event_base_loop(tor_libevent_get_base(), 0);
+ tor_libevent_run_event_loop(tor_libevent_get_base(), 0);
int64_t total_difference = 0;
uint64_t total_square_difference = 0;
diff --git a/src/test/test.c b/src/test/test.c
index 2712de4ed1..422e181b94 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -24,7 +24,6 @@
/* These macros pull in declarations for some functions and structures that
* are typically file-private. */
-#define GEOIP_PRIVATE
#define ROUTER_PRIVATE
#define CIRCUITSTATS_PRIVATE
#define CIRCUITLIST_PRIVATE
@@ -47,7 +46,6 @@ double fabs(double x);
#include "compress.h"
#include "config.h"
#include "connection_edge.h"
-#include "geoip.h"
#include "rendcommon.h"
#include "rendcache.h"
#include "test.h"
@@ -629,376 +627,6 @@ test_rend_fns(void *arg)
tor_free(intro_points_encrypted);
}
- /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs
- * using ipv4. Since our fake geoip database is the same between
- * ipv4 and ipv6, we should get the same result no matter which
- * address family we pick for each IP. */
-#define SET_TEST_ADDRESS(i) do { \
- if ((i) & 1) { \
- SET_TEST_IPV6(i); \
- tor_addr_from_in6(&addr, &in6); \
- } else { \
- tor_addr_from_ipv4h(&addr, (uint32_t) i); \
- } \
- } while (0)
-
- /* Make sure that country ID actually works. */
-#define SET_TEST_IPV6(i) \
- do { \
- set_uint32(in6.s6_addr + 12, htonl((uint32_t) (i))); \
- } while (0)
-#define CHECK_COUNTRY(country, val) do { \
- /* test ipv4 country lookup */ \
- tt_str_op(country, OP_EQ, \
- geoip_get_country_name(geoip_get_country_by_ipv4(val))); \
- /* test ipv6 country lookup */ \
- SET_TEST_IPV6(val); \
- tt_str_op(country, OP_EQ, \
- geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \
- } while (0)
-
-/** Run unit tests for GeoIP code. */
-static void
-test_geoip(void *arg)
-{
- int i, j;
- time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- char *s = NULL, *v = NULL;
- const char *bridge_stats_1 =
- "bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "bridge-ips zz=24,xy=8\n"
- "bridge-ip-versions v4=16,v6=16\n"
- "bridge-ip-transports <OR>=24\n",
- *dirreq_stats_1 =
- "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "dirreq-v3-ips ab=8\n"
- "dirreq-v3-reqs ab=8\n"
- "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
- "not-modified=0,busy=0\n"
- "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
- *dirreq_stats_2 =
- "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "dirreq-v3-ips \n"
- "dirreq-v3-reqs \n"
- "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
- "not-modified=0,busy=0\n"
- "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
- *dirreq_stats_3 =
- "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "dirreq-v3-ips \n"
- "dirreq-v3-reqs \n"
- "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
- "not-modified=0,busy=0\n"
- "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
- *dirreq_stats_4 =
- "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "dirreq-v3-ips \n"
- "dirreq-v3-reqs \n"
- "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
- "not-modified=0,busy=0\n"
- "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n",
- *entry_stats_1 =
- "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "entry-ips ab=8\n",
- *entry_stats_2 =
- "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "entry-ips \n";
- tor_addr_t addr;
- struct in6_addr in6;
-
- /* Populate the DB a bit. Add these in order, since we can't do the final
- * 'sort' step. These aren't very good IP addresses, but they're perfectly
- * fine uint32_t values. */
- (void)arg;
- tt_int_op(0,OP_EQ, geoip_parse_entry("10,50,AB", AF_INET));
- tt_int_op(0,OP_EQ, geoip_parse_entry("52,90,XY", AF_INET));
- tt_int_op(0,OP_EQ, geoip_parse_entry("95,100,AB", AF_INET));
- tt_int_op(0,OP_EQ, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET));
- tt_int_op(0,OP_EQ, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET));
- tt_int_op(0,OP_EQ, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET));
-
- /* Populate the IPv6 DB equivalently with fake IPs in the same range */
- tt_int_op(0,OP_EQ, geoip_parse_entry("::a,::32,AB", AF_INET6));
- tt_int_op(0,OP_EQ, geoip_parse_entry("::34,::5a,XY", AF_INET6));
- tt_int_op(0,OP_EQ, geoip_parse_entry("::5f,::64,AB", AF_INET6));
- tt_int_op(0,OP_EQ, geoip_parse_entry("::69,::8c,ZZ", AF_INET6));
- tt_int_op(0,OP_EQ, geoip_parse_entry("::96,::be,XY", AF_INET6));
- tt_int_op(0,OP_EQ, geoip_parse_entry("::c8,::fa,AB", AF_INET6));
-
- /* We should have 4 countries: ??, ab, xy, zz. */
- tt_int_op(4,OP_EQ, geoip_get_n_countries());
- memset(&in6, 0, sizeof(in6));
-
- CHECK_COUNTRY("??", 3);
- CHECK_COUNTRY("ab", 32);
- CHECK_COUNTRY("??", 5);
- CHECK_COUNTRY("??", 51);
- CHECK_COUNTRY("xy", 150);
- CHECK_COUNTRY("xy", 190);
- CHECK_COUNTRY("??", 2000);
-
- tt_int_op(0,OP_EQ, geoip_get_country_by_ipv4(3));
- SET_TEST_IPV6(3);
- tt_int_op(0,OP_EQ, geoip_get_country_by_ipv6(&in6));
-
- get_options_mutable()->BridgeRelay = 1;
- get_options_mutable()->BridgeRecordUsageByCountry = 1;
- /* Put 9 observations in AB... */
- for (i=32; i < 40; ++i) {
- SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
- }
- SET_TEST_ADDRESS(225);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
- /* and 3 observations in XY, several times. */
- for (j=0; j < 10; ++j)
- for (i=52; i < 55; ++i) {
- SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-3600);
- }
- /* and 17 observations in ZZ... */
- for (i=110; i < 127; ++i) {
- SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
- }
- geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
- tt_assert(s);
- tt_assert(v);
- tt_str_op("zz=24,ab=16,xy=8",OP_EQ, s);
- tt_str_op("v4=16,v6=16",OP_EQ, v);
- tor_free(s);
- tor_free(v);
-
- /* Now clear out all the AB observations. */
- geoip_remove_old_clients(now-6000);
- geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
- tt_assert(s);
- tt_assert(v);
- tt_str_op("zz=24,xy=8",OP_EQ, s);
- tt_str_op("v4=16,v6=16",OP_EQ, v);
- tor_free(s);
- tor_free(v);
-
- /* Start testing bridge statistics by making sure that we don't output
- * bridge stats without initializing them. */
- s = geoip_format_bridge_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats and generate the bridge-stats history string out of
- * the connecting clients added above. */
- geoip_bridge_stats_init(now);
- s = geoip_format_bridge_stats(now + 86400);
- tt_assert(s);
- tt_str_op(bridge_stats_1,OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting bridge stats and make sure we don't write a history
- * string anymore. */
- geoip_bridge_stats_term();
- s = geoip_format_bridge_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Stop being a bridge and start being a directory mirror that gathers
- * directory request statistics. */
- geoip_bridge_stats_term();
- get_options_mutable()->BridgeRelay = 0;
- get_options_mutable()->BridgeRecordUsageByCountry = 0;
- get_options_mutable()->DirReqStatistics = 1;
-
- /* Start testing dirreq statistics by making sure that we don't collect
- * dirreq stats without initializing them. */
- SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
- s = geoip_format_dirreq_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats, note one connecting client, and generate the
- * dirreq-stats history string. */
- geoip_dirreq_stats_init(now);
- SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
- s = geoip_format_dirreq_stats(now + 86400);
- tt_str_op(dirreq_stats_1,OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting stats, add another connecting client, and ensure we
- * don't generate a history string. */
- geoip_dirreq_stats_term();
- SET_TEST_ADDRESS(101);
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
- s = geoip_format_dirreq_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Re-start stats, add a connecting client, reset stats, and make sure
- * that we get an all empty history string. */
- geoip_dirreq_stats_init(now);
- SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
- geoip_reset_dirreq_stats(now);
- s = geoip_format_dirreq_stats(now + 86400);
- tt_str_op(dirreq_stats_2,OP_EQ, s);
- tor_free(s);
-
- /* Note a successful network status response and make sure that it
- * appears in the history string. */
- geoip_note_ns_response(GEOIP_SUCCESS);
- s = geoip_format_dirreq_stats(now + 86400);
- tt_str_op(dirreq_stats_3,OP_EQ, s);
- tor_free(s);
-
- /* Start a tunneled directory request. */
- geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED);
- s = geoip_format_dirreq_stats(now + 86400);
- tt_str_op(dirreq_stats_4,OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting directory request statistics and start gathering
- * entry stats. */
- geoip_dirreq_stats_term();
- get_options_mutable()->DirReqStatistics = 0;
- get_options_mutable()->EntryStatistics = 1;
-
- /* Start testing entry statistics by making sure that we don't collect
- * anything without initializing entry stats. */
- SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
- s = geoip_format_entry_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats, note one connecting client, and generate the
- * entry-stats history string. */
- geoip_entry_stats_init(now);
- SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
- s = geoip_format_entry_stats(now + 86400);
- tt_str_op(entry_stats_1,OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting stats, add another connecting client, and ensure we
- * don't generate a history string. */
- geoip_entry_stats_term();
- SET_TEST_ADDRESS(101);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
- s = geoip_format_entry_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Re-start stats, add a connecting client, reset stats, and make sure
- * that we get an all empty history string. */
- geoip_entry_stats_init(now);
- SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
- geoip_reset_entry_stats(now);
- s = geoip_format_entry_stats(now + 86400);
- tt_str_op(entry_stats_2,OP_EQ, s);
- tor_free(s);
-
- /* Test the OOM handler. Add a client, run the OOM. */
- geoip_entry_stats_init(now);
- SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL,
- now - (12 * 60 * 60));
- /* We've seen this 12 hours ago. Run the OOM, it should clean the entry
- * because it is above the minimum cutoff of 4 hours. */
- size_t bytes_removed = geoip_client_cache_handle_oom(now, 1000);
- tt_size_op(bytes_removed, OP_GT, 0);
-
- /* Do it again but this time with an entry with a lower cutoff. */
- geoip_entry_stats_init(now);
- SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL,
- now - (3 * 60 * 60));
- bytes_removed = geoip_client_cache_handle_oom(now, 1000);
- tt_size_op(bytes_removed, OP_EQ, 0);
-
- /* Stop collecting entry statistics. */
- geoip_entry_stats_term();
- get_options_mutable()->EntryStatistics = 0;
-
- done:
- tor_free(s);
- tor_free(v);
-}
-
-static void
-test_geoip_with_pt(void *arg)
-{
- time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- char *s = NULL;
- int i;
- tor_addr_t addr;
- struct in6_addr in6;
-
- (void)arg;
- get_options_mutable()->BridgeRelay = 1;
- get_options_mutable()->BridgeRecordUsageByCountry = 1;
-
- memset(&in6, 0, sizeof(in6));
-
- /* No clients seen yet. */
- s = geoip_get_transport_history();
- tor_assert(!s);
-
- /* 4 connections without a pluggable transport */
- for (i=0; i < 4; ++i) {
- SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
- }
-
- /* 9 connections with "alpha" */
- for (i=4; i < 13; ++i) {
- SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "alpha", now-7200);
- }
-
- /* one connection with "beta" */
- SET_TEST_ADDRESS(13);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "beta", now-7200);
-
- /* 14 connections with "charlie" */
- for (i=14; i < 28; ++i) {
- SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "charlie", now-7200);
- }
-
- /* 131 connections with "ddr" */
- for (i=28; i < 159; ++i) {
- SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "ddr", now-7200);
- }
-
- /* 8 connections with "entropy" */
- for (i=159; i < 167; ++i) {
- SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "entropy", now-7200);
- }
-
- /* 2 connections from the same IP with two different transports. */
- SET_TEST_ADDRESS(++i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "fire", now-7200);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "google", now-7200);
-
- /* Test the transport history string. */
- s = geoip_get_transport_history();
- tor_assert(s);
- tt_str_op(s,OP_EQ, "<OR>=8,alpha=16,beta=8,charlie=16,ddr=136,"
- "entropy=8,fire=8,google=8");
-
- /* Stop collecting entry statistics. */
- geoip_entry_stats_term();
- get_options_mutable()->EntryStatistics = 0;
-
- done:
- tor_free(s);
-}
-
-#undef SET_TEST_ADDRESS
-#undef SET_TEST_IPV6
-#undef CHECK_COUNTRY
-
/** Run unit tests for stats code. */
static void
test_stats(void *arg)
@@ -1172,8 +800,6 @@ static struct testcase_t test_array[] = {
{ "fast_handshake", test_fast_handshake, 0, NULL, NULL },
FORK(circuit_timeout),
FORK(rend_fns),
- ENT(geoip),
- FORK(geoip_with_pt),
FORK(stats),
END_OF_TESTCASES
@@ -1185,7 +811,9 @@ struct testgroup_t testgroups[] = {
{ "addr/", addr_tests },
{ "address/", address_tests },
{ "address_set/", address_set_tests },
+ { "bridges/", bridges_tests },
{ "buffer/", buffer_tests },
+ { "bwmgt/", bwmgt_tests },
{ "cellfmt/", cell_format_tests },
{ "cellqueue/", cell_queue_tests },
{ "channel/", channel_tests },
@@ -1216,6 +844,7 @@ struct testgroup_t testgroups[] = {
{ "entrynodes/", entrynodes_tests },
{ "guardfraction/", guardfraction_tests },
{ "extorport/", extorport_tests },
+ { "geoip/", geoip_tests },
{ "legacy_hs/", hs_tests },
{ "hs_cache/", hs_cache },
{ "hs_cell/", hs_cell_tests },
@@ -1242,6 +871,7 @@ struct testgroup_t testgroups[] = {
{ "pt/", pt_tests },
{ "relay/" , relay_tests },
{ "relaycell/", relaycell_tests },
+ { "relaycrypt/", relaycrypt_tests },
{ "rend_cache/", rend_cache_tests },
{ "replaycache/", replaycache_tests },
{ "router/", router_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 26139fc5fe..1728831ed0 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -72,6 +72,14 @@
I64_PRINTF_TYPE, I64_FORMAT, \
{print_ = (I64_PRINTF_TYPE) value_;}, {}, TT_EXIT_TEST_FUNCTION)
+/**
+ * Declare that the test is done, even though no tt___op() calls were made.
+ *
+ * For use when you only want to test calling something, but not check
+ * any values/pointers/etc afterwards.
+ */
+#define tt_finished() TT_EXIT_TEST_FUNCTION
+
const char *get_fname(const char *name);
const char *get_fname_rnd(const char *name);
struct crypto_pk_t *pk_generate(int idx);
@@ -178,6 +186,8 @@ extern struct testcase_t accounting_tests[];
extern struct testcase_t addr_tests[];
extern struct testcase_t address_tests[];
extern struct testcase_t address_set_tests[];
+extern struct testcase_t bridges_tests[];
+extern struct testcase_t bwmgt_tests[];
extern struct testcase_t buffer_tests[];
extern struct testcase_t cell_format_tests[];
extern struct testcase_t cell_queue_tests[];
@@ -208,6 +218,7 @@ extern struct testcase_t entryconn_tests[];
extern struct testcase_t entrynodes_tests[];
extern struct testcase_t guardfraction_tests[];
extern struct testcase_t extorport_tests[];
+extern struct testcase_t geoip_tests[];
extern struct testcase_t hs_tests[];
extern struct testcase_t hs_cache[];
extern struct testcase_t hs_cell_tests[];
@@ -237,6 +248,7 @@ extern struct testcase_t pubsub_tests[];
extern struct testcase_t pt_tests[];
extern struct testcase_t relay_tests[];
extern struct testcase_t relaycell_tests[];
+extern struct testcase_t relaycrypt_tests[];
extern struct testcase_t rend_cache_tests[];
extern struct testcase_t replaycache_tests[];
extern struct testcase_t router_tests[];
diff --git a/src/test/test_bridges.c b/src/test/test_bridges.c
new file mode 100644
index 0000000000..c4a4cacd98
--- /dev/null
+++ b/src/test/test_bridges.c
@@ -0,0 +1,618 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_bridges.c
+ * \brief Unittests for code in src/or/bridges.c
+ **/
+
+#define TOR_BRIDGES_PRIVATE
+#define PT_PRIVATE /* Only needed for the mock_* items below */
+
+#include <stdbool.h>
+
+#include "or.h"
+#include "address.h"
+#include "bridges.h"
+#include "config.h"
+#include "container.h"
+#include "transports.h"
+#include "util.h"
+
+/* Test suite stuff */
+#include "test.h"
+
+/**
+ * A mocked transport_t, constructed via mock_transport_get_by_name().
+ */
+static transport_t *mock_transport = NULL;
+
+/**
+ * Mock transport_get_by_name() to simply return a transport_t for the
+ * transport name that was input to it.
+ */
+static transport_t *
+mock_transport_get_by_name(const char *name)
+{
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ uint16_t port = 9999;
+ int socksv = 9;
+ char *args = tor_strdup("foo=bar");
+
+ if (!mock_transport) {
+ tor_addr_parse(addr, "99.99.99.99");
+ mock_transport = transport_new(addr, port, name, socksv, args);
+ }
+
+ tor_free(addr);
+ tor_free(args);
+
+ return mock_transport;
+}
+
+#undef PT_PRIVATE /* defined(PT_PRIVATE) */
+
+/**
+ * Test helper: Add a variety of bridges to our global bridgelist.
+ */
+static void
+helper_add_bridges_to_bridgelist(void *arg)
+{
+ /* Note: the two bridges which do not have specified fingerprints will be
+ * internally stored as both having the same fingerprint of all-zero bytes.
+ */
+
+ (void)arg;
+ char *bridge0 = tor_strdup("6.6.6.6:6666");
+ char *bridge1 = tor_strdup("6.6.6.7:6667 "
+ "A10C4F666D27364036B562823E5830BC448E046A");
+ char *bridge2 = tor_strdup("obfs4 198.245.60.51:443 "
+ "752CF7825B3B9EA6A98C83AC41F7099D67007EA5 "
+ "cert=xpmQtKUqQ/6v5X7ijgYE/f03+l2/EuQ1dexjyUhh16wQlu/"
+ "cpXUGalmhDIlhuiQPNEKmKw iat-mode=0");
+ char *bridge3 = tor_strdup("banana 5.5.5.5:5555 "
+ "9D6AE1BD4FDF39721CE908966E79E16F9BFCCF2F");
+ char *bridge4 = tor_strdup("obfs4 1.2.3.4:1234 "
+ "foo=abcdefghijklmnopqrstuvwxyz");
+ char *bridge5 = tor_strdup("apple 4.4.4.4:4444 "
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
+ "foo=abcdefghijklmnopqrstuvwxyz");
+
+ mark_bridge_list();
+
+#define ADD_BRIDGE(bridge) \
+ bridge_line_t *bridge_line_ ##bridge = parse_bridge_line(bridge); \
+ if (!bridge_line_ ##bridge) { \
+ printf("Unparseable bridge line: '%s'", #bridge); \
+ } else { \
+ bridge_add_from_config(bridge_line_ ##bridge); \
+ } \
+ tor_free(bridge);
+
+ ADD_BRIDGE(bridge0);
+ ADD_BRIDGE(bridge1);
+ ADD_BRIDGE(bridge2);
+ ADD_BRIDGE(bridge3);
+ ADD_BRIDGE(bridge4);
+ ADD_BRIDGE(bridge5);
+#undef ADD_BRIDGES
+
+ sweep_bridge_list();
+}
+
+/**
+ * Make sure our test helper works too.
+ */
+static void
+test_bridges_helper_func_add_bridges_to_bridgelist(void *arg)
+{
+ helper_add_bridges_to_bridgelist(arg);
+ tt_finished();
+
+ done:
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling bridge_list_get() should create a new bridgelist if we
+ * didn't have one before.
+ */
+static void
+test_bridges_bridge_list_get_creates_new_bridgelist(void *arg)
+{
+ const smartlist_t *bridgelist = bridge_list_get();
+
+ (void)arg;
+
+ tt_ptr_op(bridgelist, OP_NE, NULL);
+
+ done:
+ return;
+}
+
+/**
+ * Calling clear_bridge_list() should remove all bridges from the bridgelist.
+ */
+static void
+test_bridges_clear_bridge_list(void *arg)
+{
+ const smartlist_t *bridgelist;
+ const smartlist_t *bridgelist_after;
+ const bridge_info_t *bridge;
+ const bridge_info_t *bridge_after;
+
+ helper_add_bridges_to_bridgelist(arg);
+ bridgelist = bridge_list_get();
+ tt_ptr_op(bridgelist, OP_NE, NULL);
+
+ bridge = smartlist_get(bridgelist, 0);
+ tt_ptr_op(bridge, OP_NE, NULL);
+
+ clear_bridge_list();
+ bridgelist_after = bridge_list_get();
+ tt_ptr_op(bridgelist_after, OP_NE, NULL);
+
+ bridge_after = smartlist_get(bridgelist, 0);
+ // There now shouldn't be a first bridge
+ tt_ptr_op(bridge_after, OP_EQ, NULL);
+
+ done:
+ return;
+}
+
+/**
+ * Calling bridge_get_addrport() should give me the address and port
+ * of the bridge. In this case, we sort the smartlist of bridges on
+ * fingerprints and choose the first one.
+ */
+static void
+test_bridges_bridge_get_addrport(void *arg)
+{
+ smartlist_t *bridgelist;
+ const bridge_info_t *bridge;
+ const tor_addr_port_t *addrport;
+
+ helper_add_bridges_to_bridgelist(arg);
+ bridgelist = (smartlist_t*)bridge_list_get();
+ tt_ptr_op(bridgelist, OP_NE, NULL);
+
+ // This should be the bridge at 6.6.6.6:6666 with fingerprint
+ // 0000000000000000000000000000000000000000
+ bridge = smartlist_get(bridgelist, 0);
+ tt_ptr_op(bridge, OP_NE, NULL);
+
+ addrport = bridge_get_addr_port(bridge);
+ tt_int_op(addrport->port, OP_EQ, 6666);
+
+ done:
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling get_configured_bridge_by_orports_digest() with two
+ * configured bridge orports and an invalid digest should return the
+ * bridge of the first addrport in the list.
+ */
+static void
+test_bridges_get_configured_bridge_by_orports_digest(void *arg)
+{
+ smartlist_t *orports = NULL;
+ const smartlist_t *bridgelist;
+ const bridge_info_t *bridge1;
+ const bridge_info_t *bridge2;
+ const bridge_info_t *ret;
+ tor_addr_port_t *addrport1;
+ tor_addr_port_t *addrport2;
+ const char *digest;
+
+ helper_add_bridges_to_bridgelist(arg);
+ bridgelist = bridge_list_get();
+ tt_ptr_op(bridgelist, OP_NE, NULL);
+
+ // This should be the bridge at 6.6.6.6:6666 with fingerprint
+ // 0000000000000000000000000000000000000000
+ bridge1 = smartlist_get(bridgelist, 0);
+ tt_ptr_op(bridge1, OP_NE, NULL);
+ // This should be the bridge at 6.6.6.7:6667 with fingerprint
+ // A10C4F666D27364036B562823E5830BC448E046A
+ bridge2 = smartlist_get(bridgelist, 1);
+ tt_ptr_op(bridge2, OP_NE, NULL);
+
+ addrport1 = (tor_addr_port_t*)bridge_get_addr_port(bridge1);
+ tt_int_op(addrport1->port, OP_EQ, 6666);
+ addrport2 = (tor_addr_port_t*)bridge_get_addr_port(bridge2);
+ tt_int_op(addrport2->port, OP_EQ, 6667);
+
+ orports = smartlist_new();
+ smartlist_add(orports, addrport1);
+ smartlist_add(orports, addrport2);
+
+ digest = "zzzzzzzzzzzzzzzz";
+
+ ret = get_configured_bridge_by_orports_digest(digest, orports);
+ tt_ptr_op(ret, OP_NE, NULL);
+
+ tt_assert(tor_addr_port_eq(addrport1, bridge_get_addr_port(ret)));
+
+ done:
+ smartlist_free(orports);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling get_configured_bridge_by_addr_port_digest() with a digest that we do
+ * have and an addr:port pair we don't should return the bridge for that
+ * digest.
+ */
+static void
+test_bridges_get_configured_bridge_by_addr_port_digest_digest_only(void *arg)
+{
+ char digest[DIGEST_LEN];
+ bridge_info_t *bridge;
+ const char fingerprint[HEX_DIGEST_LEN] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ char ret_addr[16];
+ uint16_t port = 11111;
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ // We don't actually have a bridge with this addr:port pair
+ base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN);
+ ret = tor_addr_parse(addr, "111.111.111.111");
+ tt_int_op(ret, OP_EQ, 2); // it returns the address family on success
+
+ bridge = get_configured_bridge_by_addr_port_digest(addr, port, digest);
+ tt_ptr_op(bridge, OP_NE, NULL);
+
+ tor_addr_to_str(ret_addr, &bridge_get_addr_port(bridge)->addr, 16, 0);
+ tt_str_op("4.4.4.4", OP_EQ, ret_addr);
+
+ done:
+ tor_free(addr);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling get_configured_bridge_by_addr_port_digest() with only an
+ * addr:port (i.e. digest set to NULL) should return the bridge for
+ * that digest when there is such a bridge.
+ */
+static void
+test_bridges_get_configured_bridge_by_addr_port_digest_address_only(void *arg)
+{
+ bridge_info_t *bridge;
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ char ret_addr[16];
+ uint16_t port = 6666;
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ ret = tor_addr_parse(addr, "6.6.6.6");
+ tt_int_op(ret, OP_EQ, 2); // it returns the address family on success
+
+ bridge = get_configured_bridge_by_addr_port_digest(addr, port, NULL);
+ tt_ptr_op(bridge, OP_NE, NULL);
+
+ tor_addr_to_str(ret_addr, &bridge_get_addr_port(bridge)->addr, 16, 0);
+ tt_str_op("6.6.6.6", OP_EQ, ret_addr);
+
+ done:
+ tor_free(addr);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling get_configured_bridge_by_exact_addr_port_digest() with a digest that
+ * we do have, and an addr:port pair we don't have, should return NULL.
+ */
+static void
+test_bridges_get_configured_bridge_by_exact_addr_port_digest_donly(void *arg)
+{
+ char digest[DIGEST_LEN];
+ bridge_info_t *bridge;
+ const char fingerprint[HEX_DIGEST_LEN] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ uint16_t port = 11111;
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ // We don't actually have a bridge with this addr:port pair
+ base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN);
+ ret = tor_addr_parse(addr, "111.111.111.111");
+ tt_int_op(ret, OP_EQ, 2); // it returns the address family on success
+
+ bridge = get_configured_bridge_by_exact_addr_port_digest(addr, port, digest);
+ tt_ptr_op(bridge, OP_EQ, NULL);
+
+ done:
+ tor_free(addr);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling get_configured_bridge_by_exact_addr_port_digest() with a digest that
+ * we do have, and an addr:port pair we do have, should return the bridge.
+ */
+static void
+test_bridges_get_configured_bridge_by_exact_addr_port_digest_both(void *arg)
+{
+ char digest[DIGEST_LEN];
+ bridge_info_t *bridge;
+ const char fingerprint[HEX_DIGEST_LEN] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ uint16_t port = 4444;
+ char ret_addr[16];
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN);
+ ret = tor_addr_parse(addr, "4.4.4.4");
+ tt_int_op(ret, OP_EQ, 2); // it returns the address family on success
+
+ bridge = get_configured_bridge_by_exact_addr_port_digest(addr, port, digest);
+ tt_ptr_op(bridge, OP_NE, NULL);
+
+ tor_addr_to_str(ret_addr, &bridge_get_addr_port(bridge)->addr, 16, 0);
+ tt_str_op("4.4.4.4", OP_EQ, ret_addr);
+
+ done:
+ tor_free(addr);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling get_configured_bridge_by_exact_addr_port_digest() with no digest,
+ * and an addr:port pair we do have, should return the bridge.
+ */
+static void
+test_bridges_get_configured_bridge_by_exact_addr_port_digest_aonly(void *arg)
+{
+ bridge_info_t *bridge;
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ uint16_t port = 4444;
+ char ret_addr[16];
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ ret = tor_addr_parse(addr, "4.4.4.4");
+ tt_int_op(ret, OP_EQ, 2); // it returns the address family on success
+
+ bridge = get_configured_bridge_by_exact_addr_port_digest(addr, port, NULL);
+ tt_ptr_op(bridge, OP_NE, NULL);
+
+ tor_addr_to_str(ret_addr, &bridge_get_addr_port(bridge)->addr, 16, 0);
+ tt_str_op("4.4.4.4", OP_EQ, ret_addr);
+
+ done:
+ tor_free(addr);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling find_bridge_by_digest() when we have a bridge with a known
+ * identity digest should return the bridge's information.
+ */
+static void
+test_bridges_find_bridge_by_digest_known(void *arg)
+{
+ char digest1[DIGEST_LEN];
+ bridge_info_t *bridge;
+ const char fingerprint[HEX_DIGEST_LEN] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ base16_decode(digest1, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN);
+ bridge = find_bridge_by_digest(digest1);
+
+ tt_ptr_op(bridge, OP_NE, NULL);
+
+ /* We have to call bridge_get_rsa_id_digest() here because the bridge_info_t
+ * struct is opaquely defined in bridges.h. */
+ const uint8_t *digest2 = bridge_get_rsa_id_digest(bridge);
+
+ tt_mem_op((char*)digest2, OP_EQ, digest1, DIGEST_LEN);
+
+ done:
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling find_bridge_by_digest() when we do NOT have a bridge with that
+ * identity digest should return NULL.
+ */
+static void
+test_bridges_find_bridge_by_digest_unknown(void *arg)
+{
+ const char *fingerprint = "cccccccccccccccccccccccccccccccccccccccc";
+ bridge_info_t *bridge;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ bridge = find_bridge_by_digest(fingerprint);
+
+ tt_ptr_op(bridge, OP_EQ, NULL);
+
+ done:
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling bridge_resolve_conflicts() with an identical bridge to one we've
+ * already configure should mark the pre-configured bridge for removal.
+ */
+static void
+test_bridges_bridge_resolve_conflicts(void *arg)
+{
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ uint16_t port = 4444;
+ const char *digest = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+ const char *transport = "apple";
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ ret = tor_addr_parse(addr, "4.4.4.4");
+ tt_int_op(ret, OP_EQ, 2); // it returns the address family on success
+
+ bridge_resolve_conflicts((const tor_addr_t*)addr, port, digest, transport);
+
+ /* The bridge should now be marked for removal, and removed when we sweep the
+ * bridge_list */
+ sweep_bridge_list();
+ ret = addr_is_a_configured_bridge((const tor_addr_t*)addr, port, digest);
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ tor_free(addr);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling transport_is_needed() with a transport we do need ("obfs4") and a
+ * bogus transport that we don't need should return 1 and 0, respectively.
+ */
+static void
+test_bridges_transport_is_needed(void *arg)
+{
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ ret = transport_is_needed("obfs4");
+ tt_int_op(ret, OP_EQ, 1);
+
+ ret = transport_is_needed("apowefjaoewpaief");
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+/**
+ * Calling get_transport_by_bridge_addrport() with the address and port of a
+ * configured bridge which uses a pluggable transport when there is no global
+ * transport_list should return -1 and the transport_t should be NULL.
+ */
+static void
+test_bridges_get_transport_by_bridge_addrport_no_ptlist(void *arg)
+{
+ transport_t *transport = NULL;
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ uint16_t port = 1234;
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+
+ ret = tor_addr_parse(addr, "1.2.3.4");
+ tt_int_op(ret, OP_EQ, 2); // it returns the address family on success?
+
+ /* This will fail because the global transport_list has nothing in it, and so
+ * transport_get_by_name() has nothing to return, even the the bridge *did*
+ * say it had an obfs4 transport.
+ */
+ ret = get_transport_by_bridge_addrport((const tor_addr_t*)addr, port,
+ (const transport_t**)&transport);
+ tt_int_op(ret, OP_EQ, -1); // returns -1 on failure
+ tt_ptr_op(transport, OP_EQ, NULL);
+
+ done:
+ tor_free(addr);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+#define PT_PRIVATE
+
+/**
+ * Calling get_transport_by_bridge_addrport() with the address and port of a
+ * configured bridge which uses a pluggable transport should return 0 and set
+ * appropriate transport_t.
+ */
+static void
+test_bridges_get_transport_by_bridge_addrport(void *arg)
+{
+ transport_t *transport = NULL;
+ tor_addr_t *addr = tor_malloc(sizeof(tor_addr_t));
+ uint16_t port = 1234;
+ int ret;
+
+ helper_add_bridges_to_bridgelist(arg);
+ mark_transport_list(); // Also initialise our transport_list
+
+ ret = tor_addr_parse(addr, "1.2.3.4");
+ tt_int_op(ret, OP_EQ, 2); // it returns the address family on success?
+
+ /* After we mock transport_get_by_name() to return a bogus transport_t with
+ * the name it was asked for, the call should succeed.
+ */
+ MOCK(transport_get_by_name, mock_transport_get_by_name);
+ ret = get_transport_by_bridge_addrport((const tor_addr_t*)addr, port,
+ (const transport_t**)&transport);
+ tt_int_op(ret, OP_EQ, 0); // returns 0 on success
+ tt_ptr_op(transport, OP_NE, NULL);
+ tt_str_op(transport->name, OP_EQ, "obfs4");
+
+ done:
+ UNMOCK(transport_get_by_name);
+
+ tor_free(addr);
+ transport_free(transport);
+
+ mark_bridge_list();
+ sweep_bridge_list();
+}
+
+#undef PT_PRIVATE /* defined(PT_PRIVATE) */
+
+#define B_TEST(name, flags) \
+ { #name, test_bridges_ ##name, (flags), NULL, NULL }
+
+struct testcase_t bridges_tests[] = {
+ B_TEST(helper_func_add_bridges_to_bridgelist, 0),
+ B_TEST(bridge_list_get_creates_new_bridgelist, 0),
+ B_TEST(clear_bridge_list, 0),
+ B_TEST(bridge_get_addrport, 0),
+ B_TEST(get_configured_bridge_by_orports_digest, 0),
+ B_TEST(get_configured_bridge_by_addr_port_digest_digest_only, 0),
+ B_TEST(get_configured_bridge_by_addr_port_digest_address_only, 0),
+ B_TEST(get_configured_bridge_by_exact_addr_port_digest_donly, 0),
+ B_TEST(get_configured_bridge_by_exact_addr_port_digest_both, 0),
+ B_TEST(get_configured_bridge_by_exact_addr_port_digest_aonly, 0),
+ B_TEST(find_bridge_by_digest_known, 0),
+ B_TEST(find_bridge_by_digest_unknown, 0),
+ B_TEST(bridge_resolve_conflicts, 0),
+ B_TEST(get_transport_by_bridge_addrport_no_ptlist, 0),
+ B_TEST(get_transport_by_bridge_addrport, 0),
+ B_TEST(transport_is_needed, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_bwmgt.c b/src/test/test_bwmgt.c
new file mode 100644
index 0000000000..268917005e
--- /dev/null
+++ b/src/test/test_bwmgt.c
@@ -0,0 +1,228 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_bwmgt.c
+ * \brief tests for bandwidth management / token bucket functions
+ */
+
+#define TOKEN_BUCKET_PRIVATE
+
+#include "or.h"
+#include "test.h"
+
+#include "token_bucket.h"
+
+// an imaginary time, in timestamp units. Chosen so it will roll over.
+static const uint32_t START_TS = UINT32_MAX-10;
+static const int32_t KB = 1024;
+static const uint32_t GB = (U64_LITERAL(1) << 30);
+
+static void
+test_bwmgt_token_buf_init(void *arg)
+{
+ (void)arg;
+ token_bucket_rw_t b;
+
+ token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
+ // Burst is correct
+ tt_uint_op(b.cfg.burst, OP_EQ, 64*KB);
+ // Rate is correct, within 1 percent.
+ {
+ uint32_t ticks_per_sec =
+ (uint32_t) monotime_msec_to_approx_coarse_stamp_units(1000);
+ uint32_t rate_per_sec = (b.cfg.rate * ticks_per_sec / TICKS_PER_STEP);
+
+ tt_uint_op(rate_per_sec, OP_GT, 16*KB-160);
+ tt_uint_op(rate_per_sec, OP_LT, 16*KB+160);
+ }
+ // Bucket starts out full:
+ tt_uint_op(b.last_refilled_at_timestamp, OP_EQ, START_TS);
+ tt_int_op(b.read_bucket.bucket, OP_EQ, 64*KB);
+
+ done:
+ ;
+}
+
+static void
+test_bwmgt_token_buf_adjust(void *arg)
+{
+ (void)arg;
+ token_bucket_rw_t b;
+
+ token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
+
+ uint32_t rate_orig = b.cfg.rate;
+ // Increasing burst
+ token_bucket_rw_adjust(&b, 16*KB, 128*KB);
+ tt_uint_op(b.cfg.rate, OP_EQ, rate_orig);
+ tt_uint_op(b.read_bucket.bucket, OP_EQ, 64*KB);
+ tt_uint_op(b.cfg.burst, OP_EQ, 128*KB);
+
+ // Decreasing burst but staying above bucket
+ token_bucket_rw_adjust(&b, 16*KB, 96*KB);
+ tt_uint_op(b.cfg.rate, OP_EQ, rate_orig);
+ tt_uint_op(b.read_bucket.bucket, OP_EQ, 64*KB);
+ tt_uint_op(b.cfg.burst, OP_EQ, 96*KB);
+
+ // Decreasing burst below bucket,
+ token_bucket_rw_adjust(&b, 16*KB, 48*KB);
+ tt_uint_op(b.cfg.rate, OP_EQ, rate_orig);
+ tt_uint_op(b.read_bucket.bucket, OP_EQ, 48*KB);
+ tt_uint_op(b.cfg.burst, OP_EQ, 48*KB);
+
+ // Changing rate.
+ token_bucket_rw_adjust(&b, 32*KB, 48*KB);
+ tt_uint_op(b.cfg.rate, OP_GE, rate_orig*2 - 10);
+ tt_uint_op(b.cfg.rate, OP_LE, rate_orig*2 + 10);
+ tt_uint_op(b.read_bucket.bucket, OP_EQ, 48*KB);
+ tt_uint_op(b.cfg.burst, OP_EQ, 48*KB);
+
+ done:
+ ;
+}
+
+static void
+test_bwmgt_token_buf_dec(void *arg)
+{
+ (void)arg;
+ token_bucket_rw_t b;
+ token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
+
+ // full-to-not-full.
+ tt_int_op(0, OP_EQ, token_bucket_rw_dec_read(&b, KB));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, 63*KB);
+
+ // Full to almost-not-full
+ tt_int_op(0, OP_EQ, token_bucket_rw_dec_read(&b, 63*KB - 1));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, 1);
+
+ // almost-not-full to empty.
+ tt_int_op(1, OP_EQ, token_bucket_rw_dec_read(&b, 1));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, 0);
+
+ // reset bucket, try full-to-empty
+ token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
+ tt_int_op(1, OP_EQ, token_bucket_rw_dec_read(&b, 64*KB));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, 0);
+
+ // reset bucket, try underflow.
+ token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
+ tt_int_op(1, OP_EQ, token_bucket_rw_dec_read(&b, 64*KB + 1));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, -1);
+
+ // A second underflow does not make the bucket empty.
+ tt_int_op(0, OP_EQ, token_bucket_rw_dec_read(&b, 1000));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, -1001);
+
+ done:
+ ;
+}
+
+static void
+test_bwmgt_token_buf_refill(void *arg)
+{
+ (void)arg;
+ token_bucket_rw_t b;
+ const uint32_t SEC =
+ (uint32_t)monotime_msec_to_approx_coarse_stamp_units(1000);
+ token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
+
+ /* Make the buffer much emptier, then let one second elapse. */
+ token_bucket_rw_dec_read(&b, 48*KB);
+ tt_int_op(b.read_bucket.bucket, OP_EQ, 16*KB);
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC));
+ tt_int_op(b.read_bucket.bucket, OP_GT, 32*KB - 300);
+ tt_int_op(b.read_bucket.bucket, OP_LT, 32*KB + 300);
+
+ /* Another half second. */
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*3/2));
+ tt_int_op(b.read_bucket.bucket, OP_GT, 40*KB - 400);
+ tt_int_op(b.read_bucket.bucket, OP_LT, 40*KB + 400);
+ tt_uint_op(b.last_refilled_at_timestamp, OP_EQ, START_TS + SEC*3/2);
+
+ /* No time: nothing happens. */
+ {
+ const uint32_t bucket_orig = b.read_bucket.bucket;
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*3/2));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, bucket_orig);
+ }
+
+ /* Another 30 seconds: fill the bucket. */
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*3/2 + SEC*30));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, b.cfg.burst);
+ tt_uint_op(b.last_refilled_at_timestamp, OP_EQ, START_TS + SEC*3/2 + SEC*30);
+
+ /* Another 30 seconds: nothing happens. */
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*3/2 + SEC*60));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, b.cfg.burst);
+ tt_uint_op(b.last_refilled_at_timestamp, OP_EQ, START_TS + SEC*3/2 + SEC*60);
+
+ /* Empty the bucket, let two seconds pass, and make sure that a refill is
+ * noticed. */
+ tt_int_op(1, OP_EQ, token_bucket_rw_dec_read(&b, b.cfg.burst));
+ tt_int_op(0, OP_EQ, b.read_bucket.bucket);
+ tt_int_op(1, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*3/2 + SEC*61));
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*3/2 + SEC*62));
+ tt_int_op(b.read_bucket.bucket, OP_GT, 32*KB-400);
+ tt_int_op(b.read_bucket.bucket, OP_LT, 32*KB+400);
+
+ /* Underflow the bucket, make sure we detect when it has tokens again. */
+ tt_int_op(1, OP_EQ,
+ token_bucket_rw_dec_read(&b, b.read_bucket.bucket+16*KB));
+ tt_int_op(-16*KB, OP_EQ, b.read_bucket.bucket);
+ // half a second passes...
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*64));
+ tt_int_op(b.read_bucket.bucket, OP_GT, -8*KB-300);
+ tt_int_op(b.read_bucket.bucket, OP_LT, -8*KB+300);
+ // a second passes
+ tt_int_op(1, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*65));
+ tt_int_op(b.read_bucket.bucket, OP_GT, 8*KB-400);
+ tt_int_op(b.read_bucket.bucket, OP_LT, 8*KB+400);
+
+ // We step a second backwards, and nothing happens.
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + SEC*64));
+ tt_int_op(b.read_bucket.bucket, OP_GT, 8*KB-400);
+ tt_int_op(b.read_bucket.bucket, OP_LT, 8*KB+400);
+
+ // A ridiculous amount of time passes.
+ tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, INT32_MAX));
+ tt_int_op(b.read_bucket.bucket, OP_EQ, b.cfg.burst);
+
+ done:
+ ;
+}
+
+/* Test some helper functions we use within the token bucket interface. */
+static void
+test_bwmgt_token_buf_helpers(void *arg)
+{
+ uint32_t ret;
+
+ (void) arg;
+
+ /* The returned value will be OS specific but in any case, it should be
+ * greater than 1 since we are passing 1GB/sec rate. */
+ ret = rate_per_sec_to_rate_per_step(1 * GB);
+ tt_u64_op(ret, OP_GT, 1);
+
+ /* We default to 1 in case rate is 0. */
+ ret = rate_per_sec_to_rate_per_step(0);
+ tt_u64_op(ret, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+#define BWMGT(name) \
+ { #name, test_bwmgt_ ## name , 0, NULL, NULL }
+
+struct testcase_t bwmgt_tests[] = {
+ BWMGT(token_buf_init),
+ BWMGT(token_buf_adjust),
+ BWMGT(token_buf_dec),
+ BWMGT(token_buf_refill),
+ BWMGT(token_buf_helpers),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index bdc9d32f78..812ec6c1ac 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -281,6 +281,7 @@ new_fake_channel(void)
chan->state = CHANNEL_STATE_OPEN;
chan->cmux = circuitmux_alloc();
+ circuitmux_set_policy(chan->cmux, &ewma_policy);
return chan;
}
@@ -575,15 +576,13 @@ test_channel_outbound_cell(void *arg)
channel_register(chan);
tt_int_op(chan->registered, OP_EQ, 1);
/* Set EWMA policy so we can pick it when flushing. */
- channel_set_cmux_policy_everywhere(&ewma_policy);
+ circuitmux_set_policy(chan->cmux, &ewma_policy);
tt_ptr_op(circuitmux_get_policy(chan->cmux), OP_EQ, &ewma_policy);
/* Register circuit to the channel circid map which will attach the circuit
* to the channel's cmux as well. */
circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan);
tt_int_op(channel_num_circuits(chan), OP_EQ, 1);
- tt_assert(!TO_CIRCUIT(circ)->next_active_on_n_chan);
- tt_assert(!TO_CIRCUIT(circ)->prev_active_on_n_chan);
/* Test the cmux state. */
tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux);
tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),
diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c
index 9e570b81a7..2c803c3443 100644
--- a/src/test/test_channelpadding.c
+++ b/src/test/test_channelpadding.c
@@ -15,7 +15,6 @@
#include "channelpadding.h"
#include "compat_libevent.h"
#include "config.h"
-#include <event2/event.h>
#include "compat_time.h"
#include "main.h"
#include "networkstatus.h"
@@ -65,7 +64,7 @@ mock_channel_write_cell_relay2(channel_t *chan, cell_t *cell)
(void)chan;
tried_to_write_cell++;
channel_tls_handle_cell(cell, ((channel_tls_t*)relay1_relay2)->conn);
- event_base_loopbreak(tor_libevent_get_base());
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
return 0;
}
@@ -75,7 +74,7 @@ mock_channel_write_cell_relay1(channel_t *chan, cell_t *cell)
(void)chan;
tried_to_write_cell++;
channel_tls_handle_cell(cell, ((channel_tls_t*)relay2_relay1)->conn);
- event_base_loopbreak(tor_libevent_get_base());
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
return 0;
}
@@ -85,7 +84,7 @@ mock_channel_write_cell_relay3(channel_t *chan, cell_t *cell)
(void)chan;
tried_to_write_cell++;
channel_tls_handle_cell(cell, ((channel_tls_t*)client_relay3)->conn);
- event_base_loopbreak(tor_libevent_get_base());
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
return 0;
}
@@ -95,7 +94,7 @@ mock_channel_write_cell_client(channel_t *chan, cell_t *cell)
(void)chan;
tried_to_write_cell++;
channel_tls_handle_cell(cell, ((channel_tls_t*)relay3_client)->conn);
- event_base_loopbreak(tor_libevent_get_base());
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
return 0;
}
@@ -105,7 +104,7 @@ mock_channel_write_cell(channel_t *chan, cell_t *cell)
tried_to_write_cell++;
channel_tls_handle_cell(cell, ((channel_tls_t*)chan)->conn);
if (!dont_stop_libevent)
- event_base_loopbreak(tor_libevent_get_base());
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
return 0;
}
@@ -246,7 +245,7 @@ static void
dummy_timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono)
{
(void)t; (void)arg; (void)now_mono;
- event_base_loopbreak(tor_libevent_get_base());
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
return;
}
@@ -264,7 +263,8 @@ dummy_nop_timer(void)
timer_schedule(dummy_timer, &timeout);
- event_base_loop(tor_libevent_get_base(), 0);
+ tor_libevent_run_event_loop(tor_libevent_get_base(), 0);
+
timer_free(dummy_timer);
}
diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c
index d170009a9c..3794ffc2c6 100644
--- a/src/test/test_circuitlist.c
+++ b/src/test/test_circuitlist.c
@@ -9,6 +9,7 @@
#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitmux_ewma.h"
#include "hs_circuitmap.h"
#include "test.h"
#include "log_test_helpers.h"
diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c
index 854f725054..75b7a0ea47 100644
--- a/src/test/test_circuitmux.c
+++ b/src/test/test_circuitmux.c
@@ -7,6 +7,7 @@
#include "or.h"
#include "channel.h"
#include "circuitmux.h"
+#include "circuitmux_ewma.h"
#include "relay.h"
#include "scheduler.h"
#include "test.h"
@@ -45,6 +46,7 @@ test_cmux_destroy_cell_queue(void *arg)
cmux = circuitmux_alloc();
tt_assert(cmux);
ch = new_fake_channel();
+ circuitmux_set_policy(cmux, &ewma_policy);
ch->has_queued_writes = has_queued_writes;
ch->wide_circ_ids = 1;
diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c
index 7dd8e65194..85f69bd626 100644
--- a/src/test/test_compat_libevent.c
+++ b/src/test/test_compat_libevent.c
@@ -10,7 +10,6 @@
#include "compat_libevent.h"
#include <event2/event.h>
-#include <event2/thread.h>
#include "log_test_helpers.h"
@@ -122,10 +121,70 @@ test_compat_libevent_header_version(void *ignored)
(void)0;
}
+/* Test for postloop events */
+
+/* Event callback to increment a counter. */
+static void
+increment_int_counter_cb(periodic_timer_t *timer, void *arg)
+{
+ (void)timer;
+ int *ctr = arg;
+ ++*ctr;
+}
+
+static int activated_counter = 0;
+
+/* Mainloop event callback to activate another mainloop event */
+static void
+activate_event_cb(mainloop_event_t *ev, void *arg)
+{
+ (void)ev;
+ mainloop_event_t **other_event = arg;
+ mainloop_event_activate(*other_event);
+ ++activated_counter;
+}
+
+static void
+test_compat_libevent_postloop_events(void *arg)
+{
+ (void)arg;
+ mainloop_event_t *a = NULL, *b = NULL;
+ periodic_timer_t *timed = NULL;
+
+ tor_libevent_postfork();
+
+ /* If postloop events don't work, then these events will activate one
+ * another ad infinitum and, and the periodic event will never occur. */
+ b = mainloop_event_postloop_new(activate_event_cb, &a);
+ a = mainloop_event_postloop_new(activate_event_cb, &b);
+
+ int counter = 0;
+ struct timeval fifty_ms = { 0, 10 * 1000 };
+ timed = periodic_timer_new(tor_libevent_get_base(), &fifty_ms,
+ increment_int_counter_cb, &counter);
+
+ mainloop_event_activate(a);
+ int r;
+ do {
+ r = tor_libevent_run_event_loop(tor_libevent_get_base(), 0);
+ if (r == -1)
+ break;
+ } while (counter < 5);
+
+ tt_int_op(activated_counter, OP_GE, 2);
+
+ done:
+ mainloop_event_free(a);
+ mainloop_event_free(b);
+ periodic_timer_free(timed);
+}
+
struct testcase_t compat_libevent_tests[] = {
{ "logging_callback", test_compat_libevent_logging_callback,
TT_FORK, NULL, NULL },
{ "header_version", test_compat_libevent_header_version, 0, NULL, NULL },
+ { "postloop_events", test_compat_libevent_postloop_events,
+ TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_config.c b/src/test/test_config.c
index e214a82771..7983106a2f 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -20,7 +20,6 @@
#include "connection_edge.h"
#include "test.h"
#include "util.h"
-#include "address.h"
#include "connection_or.h"
#include "control.h"
#include "cpuworker.h"
@@ -42,9 +41,6 @@
#include "routerlist.h"
#include "routerset.h"
#include "statefile.h"
-#include "test.h"
-#include "transports.h"
-#include "util.h"
#include "test_helpers.h"
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
index 901ad7ab3d..e81aea8d66 100644
--- a/src/test/test_controller_events.c
+++ b/src/test/test_controller_events.c
@@ -12,79 +12,6 @@
#include "test.h"
static void
-help_test_bucket_note_empty(uint32_t expected_msec_since_midnight,
- int tokens_before, size_t tokens_removed,
- uint32_t msec_since_epoch)
-{
- uint32_t timestamp_var = 0;
- struct timeval tvnow;
- tvnow.tv_sec = msec_since_epoch / 1000;
- tvnow.tv_usec = (msec_since_epoch % 1000) * 1000;
- connection_buckets_note_empty_ts(&timestamp_var, tokens_before,
- tokens_removed, &tvnow);
- tt_int_op(expected_msec_since_midnight, OP_EQ, timestamp_var);
-
- done:
- ;
-}
-
-static void
-test_cntev_bucket_note_empty(void *arg)
-{
- (void)arg;
-
- /* Two cases with nothing to note, because bucket was empty before;
- * 86442200 == 1970-01-02 00:00:42.200000 */
- help_test_bucket_note_empty(0, 0, 0, 86442200);
- help_test_bucket_note_empty(0, -100, 100, 86442200);
-
- /* Nothing to note, because bucket has not been emptied. */
- help_test_bucket_note_empty(0, 101, 100, 86442200);
-
- /* Bucket was emptied, note 42200 msec since midnight. */
- help_test_bucket_note_empty(42200, 101, 101, 86442200);
- help_test_bucket_note_empty(42200, 101, 102, 86442200);
-}
-
-static void
-test_cntev_bucket_millis_empty(void *arg)
-{
- struct timeval tvnow;
- (void)arg;
-
- /* 1970-01-02 00:00:42.200000 */
- tvnow.tv_sec = 86400 + 42;
- tvnow.tv_usec = 200000;
-
- /* Bucket has not been refilled. */
- tt_int_op(0, OP_EQ, bucket_millis_empty(0, 42120, 0, 100, &tvnow));
- tt_int_op(0, OP_EQ, bucket_millis_empty(-10, 42120, -10, 100, &tvnow));
-
- /* Bucket was not empty. */
- tt_int_op(0, OP_EQ, bucket_millis_empty(10, 42120, 20, 100, &tvnow));
-
- /* Bucket has been emptied 80 msec ago and has just been refilled. */
- tt_int_op(80, OP_EQ, bucket_millis_empty(-20, 42120, -10, 100, &tvnow));
- tt_int_op(80, OP_EQ, bucket_millis_empty(-10, 42120, 0, 100, &tvnow));
- tt_int_op(80, OP_EQ, bucket_millis_empty(0, 42120, 10, 100, &tvnow));
-
- /* Bucket has been emptied 180 msec ago, last refill was 100 msec ago
- * which was insufficient to make it positive, so cap msec at 100. */
- tt_int_op(100, OP_EQ, bucket_millis_empty(0, 42020, 1, 100, &tvnow));
-
- /* 1970-01-02 00:00:00:050000 */
- tvnow.tv_sec = 86400;
- tvnow.tv_usec = 50000;
-
- /* Last emptied 30 msec before midnight, tvnow is 50 msec after
- * midnight, that's 80 msec in total. */
- tt_int_op(80, OP_EQ, bucket_millis_empty(0, 86400000 - 30, 1, 100, &tvnow));
-
- done:
- ;
-}
-
-static void
add_testing_cell_stats_entry(circuit_t *circ, uint8_t command,
unsigned int waiting_time,
unsigned int removed, unsigned int exitward)
@@ -395,8 +322,6 @@ test_cntev_event_mask(void *arg)
{ #name, test_cntev_ ## name, flags, 0, NULL }
struct testcase_t controller_event_tests[] = {
- TEST(bucket_note_empty, TT_FORK),
- TEST(bucket_millis_empty, TT_FORK),
TEST(sum_up_cell_stats, TT_FORK),
TEST(append_cell_stats, TT_FORK),
TEST(format_cell_stats, TT_FORK),
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index ca64dce5fe..71faf70af2 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -16,7 +16,6 @@
#include "directory.h"
#include "test.h"
#include "compress.h"
-#include "connection.h"
#include "rendcommon.h"
#include "rendcache.h"
#include "router.h"
diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c
new file mode 100644
index 0000000000..20f6114dc0
--- /dev/null
+++ b/src/test/test_geoip.c
@@ -0,0 +1,465 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+/* These macros pull in declarations for some functions and structures that
+ * are typically file-private. */
+#define GEOIP_PRIVATE
+#include "or.h"
+#include "config.h"
+#include "geoip.h"
+#include "test.h"
+
+ /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs
+ * using ipv4. Since our fake geoip database is the same between
+ * ipv4 and ipv6, we should get the same result no matter which
+ * address family we pick for each IP. */
+#define SET_TEST_ADDRESS(i) do { \
+ if ((i) & 1) { \
+ SET_TEST_IPV6(i); \
+ tor_addr_from_in6(&addr, &in6); \
+ } else { \
+ tor_addr_from_ipv4h(&addr, (uint32_t) i); \
+ } \
+ } while (0)
+
+ /* Make sure that country ID actually works. */
+#define SET_TEST_IPV6(i) \
+ do { \
+ set_uint32(in6.s6_addr + 12, htonl((uint32_t) (i))); \
+ } while (0)
+#define CHECK_COUNTRY(country, val) do { \
+ /* test ipv4 country lookup */ \
+ tt_str_op(country, OP_EQ, \
+ geoip_get_country_name(geoip_get_country_by_ipv4(val))); \
+ /* test ipv6 country lookup */ \
+ SET_TEST_IPV6(val); \
+ tt_str_op(country, OP_EQ, \
+ geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \
+ } while (0)
+
+/** Run unit tests for GeoIP code. */
+static void
+test_geoip(void *arg)
+{
+ int i, j;
+ time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
+ char *s = NULL, *v = NULL;
+ const char *bridge_stats_1 =
+ "bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "bridge-ips zz=24,xy=8\n"
+ "bridge-ip-versions v4=16,v6=16\n"
+ "bridge-ip-transports <OR>=24\n",
+ *dirreq_stats_1 =
+ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "dirreq-v3-ips ab=8\n"
+ "dirreq-v3-reqs ab=8\n"
+ "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=0,busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
+ *dirreq_stats_2 =
+ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "dirreq-v3-ips \n"
+ "dirreq-v3-reqs \n"
+ "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=0,busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
+ *dirreq_stats_3 =
+ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "dirreq-v3-ips \n"
+ "dirreq-v3-reqs \n"
+ "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=0,busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
+ *dirreq_stats_4 =
+ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "dirreq-v3-ips \n"
+ "dirreq-v3-reqs \n"
+ "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=0,busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n",
+ *entry_stats_1 =
+ "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "entry-ips ab=8\n",
+ *entry_stats_2 =
+ "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "entry-ips \n";
+ tor_addr_t addr;
+ struct in6_addr in6;
+
+ /* Populate the DB a bit. Add these in order, since we can't do the final
+ * 'sort' step. These aren't very good IP addresses, but they're perfectly
+ * fine uint32_t values. */
+ (void)arg;
+ tt_int_op(0,OP_EQ, geoip_parse_entry("10,50,AB", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("52,90,XY", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("95,100,AB", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET));
+
+ /* Populate the IPv6 DB equivalently with fake IPs in the same range */
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::a,::32,AB", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::34,::5a,XY", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::5f,::64,AB", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::69,::8c,ZZ", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::96,::be,XY", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::c8,::fa,AB", AF_INET6));
+
+ /* We should have 4 countries: ??, ab, xy, zz. */
+ tt_int_op(4,OP_EQ, geoip_get_n_countries());
+ memset(&in6, 0, sizeof(in6));
+
+ CHECK_COUNTRY("??", 3);
+ CHECK_COUNTRY("ab", 32);
+ CHECK_COUNTRY("??", 5);
+ CHECK_COUNTRY("??", 51);
+ CHECK_COUNTRY("xy", 150);
+ CHECK_COUNTRY("xy", 190);
+ CHECK_COUNTRY("??", 2000);
+
+ tt_int_op(0,OP_EQ, geoip_get_country_by_ipv4(3));
+ SET_TEST_IPV6(3);
+ tt_int_op(0,OP_EQ, geoip_get_country_by_ipv6(&in6));
+
+ get_options_mutable()->BridgeRelay = 1;
+ get_options_mutable()->BridgeRecordUsageByCountry = 1;
+ /* Put 9 observations in AB... */
+ for (i=32; i < 40; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
+ }
+ SET_TEST_ADDRESS(225);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
+ /* and 3 observations in XY, several times. */
+ for (j=0; j < 10; ++j)
+ for (i=52; i < 55; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-3600);
+ }
+ /* and 17 observations in ZZ... */
+ for (i=110; i < 127; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
+ }
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
+ tt_assert(s);
+ tt_assert(v);
+ tt_str_op("zz=24,ab=16,xy=8",OP_EQ, s);
+ tt_str_op("v4=16,v6=16",OP_EQ, v);
+ tor_free(s);
+ tor_free(v);
+
+ /* Now clear out all the AB observations. */
+ geoip_remove_old_clients(now-6000);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
+ tt_assert(s);
+ tt_assert(v);
+ tt_str_op("zz=24,xy=8",OP_EQ, s);
+ tt_str_op("v4=16,v6=16",OP_EQ, v);
+ tor_free(s);
+ tor_free(v);
+
+ /* Start testing bridge statistics by making sure that we don't output
+ * bridge stats without initializing them. */
+ s = geoip_format_bridge_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats and generate the bridge-stats history string out of
+ * the connecting clients added above. */
+ geoip_bridge_stats_init(now);
+ s = geoip_format_bridge_stats(now + 86400);
+ tt_assert(s);
+ tt_str_op(bridge_stats_1,OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting bridge stats and make sure we don't write a history
+ * string anymore. */
+ geoip_bridge_stats_term();
+ s = geoip_format_bridge_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Stop being a bridge and start being a directory mirror that gathers
+ * directory request statistics. */
+ geoip_bridge_stats_term();
+ get_options_mutable()->BridgeRelay = 0;
+ get_options_mutable()->BridgeRecordUsageByCountry = 0;
+ get_options_mutable()->DirReqStatistics = 1;
+
+ /* Start testing dirreq statistics by making sure that we don't collect
+ * dirreq stats without initializing them. */
+ SET_TEST_ADDRESS(100);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
+ s = geoip_format_dirreq_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats, note one connecting client, and generate the
+ * dirreq-stats history string. */
+ geoip_dirreq_stats_init(now);
+ SET_TEST_ADDRESS(100);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
+ s = geoip_format_dirreq_stats(now + 86400);
+ tt_str_op(dirreq_stats_1,OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add another connecting client, and ensure we
+ * don't generate a history string. */
+ geoip_dirreq_stats_term();
+ SET_TEST_ADDRESS(101);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
+ s = geoip_format_dirreq_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Re-start stats, add a connecting client, reset stats, and make sure
+ * that we get an all empty history string. */
+ geoip_dirreq_stats_init(now);
+ SET_TEST_ADDRESS(100);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
+ geoip_reset_dirreq_stats(now);
+ s = geoip_format_dirreq_stats(now + 86400);
+ tt_str_op(dirreq_stats_2,OP_EQ, s);
+ tor_free(s);
+
+ /* Note a successful network status response and make sure that it
+ * appears in the history string. */
+ geoip_note_ns_response(GEOIP_SUCCESS);
+ s = geoip_format_dirreq_stats(now + 86400);
+ tt_str_op(dirreq_stats_3,OP_EQ, s);
+ tor_free(s);
+
+ /* Start a tunneled directory request. */
+ geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED);
+ s = geoip_format_dirreq_stats(now + 86400);
+ tt_str_op(dirreq_stats_4,OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting directory request statistics and start gathering
+ * entry stats. */
+ geoip_dirreq_stats_term();
+ get_options_mutable()->DirReqStatistics = 0;
+ get_options_mutable()->EntryStatistics = 1;
+
+ /* Start testing entry statistics by making sure that we don't collect
+ * anything without initializing entry stats. */
+ SET_TEST_ADDRESS(100);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
+ s = geoip_format_entry_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats, note one connecting client, and generate the
+ * entry-stats history string. */
+ geoip_entry_stats_init(now);
+ SET_TEST_ADDRESS(100);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
+ s = geoip_format_entry_stats(now + 86400);
+ tt_str_op(entry_stats_1,OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add another connecting client, and ensure we
+ * don't generate a history string. */
+ geoip_entry_stats_term();
+ SET_TEST_ADDRESS(101);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
+ s = geoip_format_entry_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Re-start stats, add a connecting client, reset stats, and make sure
+ * that we get an all empty history string. */
+ geoip_entry_stats_init(now);
+ SET_TEST_ADDRESS(100);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
+ geoip_reset_entry_stats(now);
+ s = geoip_format_entry_stats(now + 86400);
+ tt_str_op(entry_stats_2,OP_EQ, s);
+ tor_free(s);
+
+ /* Test the OOM handler. Add a client, run the OOM. */
+ geoip_entry_stats_init(now);
+ SET_TEST_ADDRESS(100);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL,
+ now - (12 * 60 * 60));
+ /* We've seen this 12 hours ago. Run the OOM, it should clean the entry
+ * because it is above the minimum cutoff of 4 hours. */
+ size_t bytes_removed = geoip_client_cache_handle_oom(now, 1000);
+ tt_size_op(bytes_removed, OP_GT, 0);
+
+ /* Do it again but this time with an entry with a lower cutoff. */
+ geoip_entry_stats_init(now);
+ SET_TEST_ADDRESS(100);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL,
+ now - (3 * 60 * 60));
+ bytes_removed = geoip_client_cache_handle_oom(now, 1000);
+ tt_size_op(bytes_removed, OP_EQ, 0);
+
+ /* Stop collecting entry statistics. */
+ geoip_entry_stats_term();
+ get_options_mutable()->EntryStatistics = 0;
+
+ done:
+ tor_free(s);
+ tor_free(v);
+}
+
+static void
+test_geoip_with_pt(void *arg)
+{
+ time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
+ char *s = NULL;
+ int i;
+ tor_addr_t addr;
+ struct in6_addr in6;
+
+ (void)arg;
+ get_options_mutable()->BridgeRelay = 1;
+ get_options_mutable()->BridgeRecordUsageByCountry = 1;
+
+ memset(&in6, 0, sizeof(in6));
+
+ /* No clients seen yet. */
+ s = geoip_get_transport_history();
+ tor_assert(!s);
+
+ /* 4 connections without a pluggable transport */
+ for (i=0; i < 4; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
+ }
+
+ /* 9 connections with "alpha" */
+ for (i=4; i < 13; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "alpha", now-7200);
+ }
+
+ /* one connection with "beta" */
+ SET_TEST_ADDRESS(13);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "beta", now-7200);
+
+ /* 14 connections with "charlie" */
+ for (i=14; i < 28; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "charlie", now-7200);
+ }
+
+ /* 131 connections with "ddr" */
+ for (i=28; i < 159; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "ddr", now-7200);
+ }
+
+ /* 8 connections with "entropy" */
+ for (i=159; i < 167; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "entropy", now-7200);
+ }
+
+ /* 2 connections from the same IP with two different transports. */
+ SET_TEST_ADDRESS(++i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "fire", now-7200);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "google", now-7200);
+
+ /* Test the transport history string. */
+ s = geoip_get_transport_history();
+ tor_assert(s);
+ tt_str_op(s,OP_EQ, "<OR>=8,alpha=16,beta=8,charlie=16,ddr=136,"
+ "entropy=8,fire=8,google=8");
+
+ /* Stop collecting entry statistics. */
+ geoip_entry_stats_term();
+ get_options_mutable()->EntryStatistics = 0;
+
+ done:
+ tor_free(s);
+}
+
+#undef SET_TEST_ADDRESS
+#undef SET_TEST_IPV6
+#undef CHECK_COUNTRY
+
+static void
+test_geoip_load_file(void *arg)
+{
+ (void)arg;
+ char *contents = NULL;
+ char *dhex = NULL;
+
+ /* A nonexistant filename should fail. */
+ tt_int_op(-1, OP_EQ,
+ geoip_load_file(AF_INET, "/you/did/not/put/a/file/here/I/hope"));
+
+ /* We start out with only "Ningunpartia" in the database. */
+ tt_int_op(1, OP_EQ, geoip_get_n_countries());
+ tt_str_op("??", OP_EQ, geoip_get_country_name(0));
+ /* Any lookup attempt should say "-1" because we have no info */
+ tt_int_op(-1, OP_EQ, geoip_get_country_by_ipv4(0x01020304));
+ /* There should be no 'digest' for a nonexistant file */
+ tt_str_op("0000000000000000000000000000000000000000", OP_EQ,
+ geoip_db_digest(AF_INET));
+
+ const char FNAME[] = SRCDIR "/src/config/geoip";
+ int rv = geoip_load_file(AF_INET, FNAME);
+ if (rv != 0) {
+ TT_GRIPE(("Unable to load geoip from %s", escaped(FNAME)));
+ }
+ tt_int_op(0, OP_EQ, rv);
+
+ /* Check that we loaded some countries; this will fail if there are ever
+ * fewer than 50 countries in the world. */
+ tt_int_op(geoip_get_n_countries(), OP_GE, 50);
+
+ /* Let's see where 8.8.8.8 is. */
+ int country = geoip_get_country_by_ipv4(0x08080808);
+ tt_int_op(country, OP_GE, 1); /* It shouldn't be 'unknown' or 'nowhere' */
+ const char *cc = geoip_get_country_name(country);
+ tt_int_op(strlen(cc), OP_EQ, 2);
+
+ /* The digest should be set.... */
+ tt_str_op("0000000000000000000000000000000000000000", OP_NE,
+ geoip_db_digest(AF_INET));
+
+ /* And it should be set correctly */
+ contents = read_file_to_str(FNAME, RFTS_BIN, NULL);
+ uint8_t d[DIGEST_LEN];
+ crypto_digest((char*)d, contents, strlen(contents));
+ dhex = tor_strdup(hex_str((char*)d, DIGEST_LEN));
+ tt_str_op(dhex, OP_EQ, geoip_db_digest(AF_INET));
+
+ /* Make sure geoip_free_all() works. */
+ geoip_free_all();
+ tt_int_op(1, OP_EQ, geoip_get_n_countries());
+ tt_str_op("??", OP_EQ, geoip_get_country_name(0));
+ tt_int_op(-1, OP_EQ, geoip_get_country_by_ipv4(0x01020304));
+ tt_str_op("0000000000000000000000000000000000000000", OP_EQ,
+ geoip_db_digest(AF_INET)); // <--- nick bets this will fail.
+
+ done:
+ tor_free(contents);
+ tor_free(dhex);
+}
+
+#define ENT(name) \
+ { #name, test_ ## name , 0, NULL, NULL }
+#define FORK(name) \
+ { #name, test_ ## name , TT_FORK, NULL, NULL }
+
+#ifdef _WIN32
+#define SKIP_ON_WINDOWS TT_SKIP
+#else
+#define SKIP_ON_WINDOWS 0
+#endif
+
+struct testcase_t geoip_tests[] = {
+ { "geoip", test_geoip, TT_FORK, NULL, NULL },
+ { "geoip_with_pt", test_geoip_with_pt, TT_FORK, NULL, NULL },
+ { "load_file", test_geoip_load_file, TT_FORK|SKIP_ON_WINDOWS, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index 0da9cf64d0..6ada64dcff 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -33,7 +33,6 @@ DISABLE_GCC_WARNING(overlength-strings)
* at large. */
#endif
#include "test_descriptors.inc"
-#include "or.h"
#include "circuitlist.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
ENABLE_GCC_WARNING(overlength-strings)
@@ -156,7 +155,7 @@ mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
/* Helper for test_conn_get_connection() */
static int
-fake_close_socket(evutil_socket_t sock)
+fake_close_socket(tor_socket_t sock)
{
(void)sock;
return 0;
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index 7ee7210bc9..58e12abca0 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -213,12 +213,12 @@ test_e2e_rend_circuit_setup_legacy(void *arg)
tt_int_op(retval, OP_EQ, 1);
/* Check the digest algo */
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->f_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest),
OP_EQ, DIGEST_SHA1);
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->b_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest),
OP_EQ, DIGEST_SHA1);
- tt_assert(or_circ->cpath->f_crypto);
- tt_assert(or_circ->cpath->b_crypto);
+ tt_assert(or_circ->cpath->crypto.f_crypto);
+ tt_assert(or_circ->cpath->crypto.b_crypto);
/* Ensure that circ purpose was changed */
tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
@@ -283,12 +283,12 @@ test_e2e_rend_circuit_setup(void *arg)
tt_int_op(retval, OP_EQ, 1);
/* Check that the crypt path has prop224 algorithm parameters */
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->f_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->b_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_assert(or_circ->cpath->f_crypto);
- tt_assert(or_circ->cpath->b_crypto);
+ tt_assert(or_circ->cpath->crypto.f_crypto);
+ tt_assert(or_circ->cpath->crypto.b_crypto);
/* Ensure that circ purpose was changed */
tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 8e9d461c40..388b85f975 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -9,6 +9,7 @@
#define HS_DESCRIPTOR_PRIVATE
#include "crypto_ed25519.h"
+#include "crypto_digest.h"
#include "ed25519_cert.h"
#include "or.h"
#include "hs_descriptor.h"
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index 55dfafbeac..fe3236c331 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -14,7 +14,6 @@
#include "test.h"
#include "log_test_helpers.h"
#include "crypto.h"
-#include "log_test_helpers.h"
#include "or.h"
#include "circuitlist.h"
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index 2e5280610f..481521520c 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -173,12 +173,12 @@ test_e2e_rend_circuit_setup(void *arg)
tt_int_op(retval, OP_EQ, 1);
/* Check the digest algo */
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->f_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->b_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_assert(or_circ->cpath->f_crypto);
- tt_assert(or_circ->cpath->b_crypto);
+ tt_assert(or_circ->cpath->crypto.f_crypto);
+ tt_assert(or_circ->cpath->crypto.b_crypto);
/* Ensure that circ purpose was changed */
tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_S_REND_JOINED);
@@ -1237,7 +1237,7 @@ test_build_update_descriptors(void *arg)
node->is_running = node->is_valid = node->is_fast = node->is_stable = 1;
}
- /* We have to set thise, or the lack of microdescriptors for these
+ /* We have to set this, or the lack of microdescriptors for these
* nodes will make them unusable. */
get_options_mutable()->UseMicrodescriptors = 0;
diff --git a/src/test/test_options.c b/src/test/test_options.c
index eaf5034397..9974ed2575 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -2422,37 +2422,6 @@ test_options_validate__circuits(void *ignored)
}
static void
-test_options_validate__port_forwarding(void *ignored)
-{
- (void)ignored;
- int ret;
- char *msg;
- options_test_data_t *tdata = NULL;
-
- free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PortForwarding 1\nSandbox 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "PortForwarding is not compatible with Sandbox;"
- " at most one can be set");
- tor_free(msg);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PortForwarding 1\nSandbox 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, 0);
- tt_assert(!msg);
- tor_free(msg);
-
- done:
- free_options_test_data(tdata);
- policies_free_all();
- tor_free(msg);
-}
-
-static void
test_options_validate__tor2web(void *ignored)
{
(void)ignored;
@@ -4135,16 +4104,6 @@ test_options_validate__testing_options(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
"TestingEnableTbEmptyEvent 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "TestingEnableTbEmptyEvent may only be changed "
- "in testing Tor networks!");
- tor_free(msg);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableTbEmptyEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"___UsingTestNetworkDefaults 0\n"
@@ -4261,7 +4220,6 @@ struct testcase_t options_tests[] = {
LOCAL_VALIDATE_TEST(path_bias),
LOCAL_VALIDATE_TEST(bandwidth),
LOCAL_VALIDATE_TEST(circuits),
- LOCAL_VALIDATE_TEST(port_forwarding),
LOCAL_VALIDATE_TEST(tor2web),
LOCAL_VALIDATE_TEST(rend),
LOCAL_VALIDATE_TEST(single_onion),
diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c
new file mode 100644
index 0000000000..eba9897184
--- /dev/null
+++ b/src/test/test_relaycrypt.c
@@ -0,0 +1,184 @@
+/* Copyright 2001-2004 Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "circuitbuild.h"
+#define CIRCUITLIST_PRIVATE
+#include "circuitlist.h"
+#include "relay.h"
+#include "relay_crypto.h"
+#include "test.h"
+
+static const char KEY_MATERIAL[3][CPATH_KEY_MATERIAL_LEN] = {
+ " 'My public key is in this signed x509 object', said Tom assertively.",
+ "'Let's chart the pedal phlanges in the tomb', said Tom cryptographically",
+ " 'Segmentation fault bugs don't _just happen_', said Tom seethingly.",
+};
+
+typedef struct testing_circuitset_t {
+ or_circuit_t *or_circ[3];
+ origin_circuit_t *origin_circ;
+} testing_circuitset_t;
+
+static int testing_circuitset_teardown(const struct testcase_t *testcase,
+ void *ptr);
+
+static void *
+testing_circuitset_setup(const struct testcase_t *testcase)
+{
+ testing_circuitset_t *cs = tor_malloc_zero(sizeof(testing_circuitset_t));
+ int i;
+
+ for (i=0; i<3; ++i) {
+ cs->or_circ[i] = or_circuit_new(0, NULL);
+ tt_int_op(0, OP_EQ,
+ relay_crypto_init(&cs->or_circ[i]->crypto,
+ KEY_MATERIAL[i], sizeof(KEY_MATERIAL[i]),
+ 0, 0));
+ }
+
+ cs->origin_circ = origin_circuit_new();
+ cs->origin_circ->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ for (i=0; i<3; ++i) {
+ crypt_path_t *hop = tor_malloc_zero(sizeof(*hop));
+ relay_crypto_init(&hop->crypto, KEY_MATERIAL[i], sizeof(KEY_MATERIAL[i]),
+ 0, 0);
+ hop->state = CPATH_STATE_OPEN;
+ onion_append_to_cpath(&cs->origin_circ->cpath, hop);
+ tt_ptr_op(hop, OP_EQ, cs->origin_circ->cpath->prev);
+ }
+
+ return cs;
+ done:
+ testing_circuitset_teardown(testcase, cs);
+ return NULL;
+}
+
+static int
+testing_circuitset_teardown(const struct testcase_t *testcase, void *ptr)
+{
+ (void)testcase;
+ testing_circuitset_t *cs = ptr;
+ int i;
+ for (i=0; i<3; ++i) {
+ circuit_free_(TO_CIRCUIT(cs->or_circ[i]));
+ }
+ circuit_free_(TO_CIRCUIT(cs->origin_circ));
+ tor_free(cs);
+ return 1;
+}
+
+static const struct testcase_setup_t relaycrypt_setup = {
+ testing_circuitset_setup, testing_circuitset_teardown
+};
+
+/* Test encrypting a cell to the final hop on a circuit, decrypting it
+ * at each hop, and recognizing it at the other end. Then do it again
+ * and again as the state evolves. */
+static void
+test_relaycrypt_outbound(void *arg)
+{
+ testing_circuitset_t *cs = arg;
+ tt_assert(cs);
+
+ relay_header_t rh;
+ cell_t orig;
+ cell_t encrypted;
+ int i, j;
+
+ for (i = 0; i < 50; ++i) {
+ crypto_rand((char *)&orig, sizeof(orig));
+
+ relay_header_unpack(&rh, orig.payload);
+ rh.recognized = 0;
+ memset(rh.integrity, 0, sizeof(rh.integrity));
+ relay_header_pack(orig.payload, &rh);
+
+ memcpy(&encrypted, &orig, sizeof(orig));
+
+ /* Encrypt the cell to the last hop */
+ relay_encrypt_cell_outbound(&encrypted, cs->origin_circ,
+ cs->origin_circ->cpath->prev);
+
+ for (j = 0; j < 3; ++j) {
+ crypt_path_t *layer_hint = NULL;
+ char recognized = 0;
+ int r = relay_decrypt_cell(TO_CIRCUIT(cs->or_circ[j]),
+ &encrypted,
+ CELL_DIRECTION_OUT,
+ &layer_hint, &recognized);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(layer_hint, OP_EQ, NULL);
+ tt_int_op(recognized != 0, OP_EQ, j == 2);
+ }
+
+ tt_mem_op(orig.payload, OP_EQ, encrypted.payload, CELL_PAYLOAD_SIZE);
+ }
+
+ done:
+ ;
+}
+
+/* As above, but simulate inbound cells from the last hop. */
+static void
+test_relaycrypt_inbound(void *arg)
+{
+ testing_circuitset_t *cs = arg;
+ tt_assert(cs);
+
+ relay_header_t rh;
+ cell_t orig;
+ cell_t encrypted;
+ int i, j;
+
+ for (i = 0; i < 50; ++i) {
+ crypto_rand((char *)&orig, sizeof(orig));
+
+ relay_header_unpack(&rh, orig.payload);
+ rh.recognized = 0;
+ memset(rh.integrity, 0, sizeof(rh.integrity));
+ relay_header_pack(orig.payload, &rh);
+
+ memcpy(&encrypted, &orig, sizeof(orig));
+
+ /* Encrypt the cell to the last hop */
+ relay_encrypt_cell_inbound(&encrypted, cs->or_circ[2]);
+
+ crypt_path_t *layer_hint = NULL;
+ char recognized = 0;
+ int r;
+ for (j = 1; j >= 0; --j) {
+ r = relay_decrypt_cell(TO_CIRCUIT(cs->or_circ[j]),
+ &encrypted,
+ CELL_DIRECTION_IN,
+ &layer_hint, &recognized);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(layer_hint, OP_EQ, NULL);
+ tt_int_op(recognized, OP_EQ, 0);
+ }
+
+ relay_decrypt_cell(TO_CIRCUIT(cs->origin_circ),
+ &encrypted,
+ CELL_DIRECTION_IN,
+ &layer_hint, &recognized);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(recognized, OP_EQ, 1);
+ tt_ptr_op(layer_hint, OP_EQ, cs->origin_circ->cpath->prev);
+
+ tt_mem_op(orig.payload, OP_EQ, encrypted.payload, CELL_PAYLOAD_SIZE);
+ }
+ done:
+ ;
+}
+
+#define TEST(name) \
+ { # name, test_relaycrypt_ ## name, 0, &relaycrypt_setup, NULL }
+
+struct testcase_t relaycrypt_tests[] = {
+ TEST(outbound),
+ TEST(inbound),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh
index d87336e700..c35c57456f 100755
--- a/src/test/test_rust.sh
+++ b/src/test/test_rust.sh
@@ -12,4 +12,3 @@ CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \
--manifest-path '{}' \;
exit $?
-
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index ebba71266c..841fc69456 100644
--- a/src/test/test_scheduler.c
+++ b/src/test/test_scheduler.c
@@ -4,7 +4,6 @@
#include "orconfig.h"
#include <math.h>
-#include <event2/event.h>
#define SCHEDULER_KIST_PRIVATE
#define TOR_CHANNEL_INTERNAL_
@@ -101,62 +100,6 @@ mock_kist_networkstatus_get_param(
return 12;
}
-/* Event base for scheduelr tests */
-static struct event_base *mock_event_base = NULL;
-/* Setup for mock event stuff */
-static void mock_event_free_all(void);
-static void mock_event_init(void);
-static void
-mock_event_free_all(void)
-{
- tt_ptr_op(mock_event_base, OP_NE, NULL);
-
- if (mock_event_base) {
- event_base_free(mock_event_base);
- mock_event_base = NULL;
- }
-
- tt_ptr_op(mock_event_base, OP_EQ, NULL);
-
- done:
- return;
-}
-
-static void
-mock_event_init(void)
-{
- struct event_config *cfg = NULL;
-
- tt_ptr_op(mock_event_base, OP_EQ, NULL);
-
- /*
- * Really cut down from tor_libevent_initialize of
- * src/common/compat_libevent.c to kill config dependencies
- */
-
- if (!mock_event_base) {
- cfg = event_config_new();
-#if LIBEVENT_VERSION_NUMBER >= V(2,0,9)
- /* We can enable changelist support with epoll, since we don't give
- * Libevent any dup'd fds. This lets us avoid some syscalls. */
- event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
-#endif
- mock_event_base = event_base_new_with_config(cfg);
- event_config_free(cfg);
- }
-
- tt_ptr_op(mock_event_base, OP_NE, NULL);
-
- done:
- return;
-}
-
-static struct event_base *
-tor_libevent_get_base_mock(void)
-{
- return mock_event_base;
-}
-
static int
scheduler_compare_channels_mock(const void *c1_v,
const void *c2_v)
@@ -417,9 +360,7 @@ perform_channel_state_tests(int KISTSchedRunInterval, int sched_type)
mocked_options.KISTSchedRunInterval = KISTSchedRunInterval;
set_scheduler_options(sched_type);
- /* Set up libevent and scheduler */
- mock_event_init();
- MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
+ /* Set up scheduler */
scheduler_init();
/*
* Install the compare channels mock so we can test
@@ -523,14 +464,12 @@ perform_channel_state_tests(int KISTSchedRunInterval, int sched_type)
channel_free_all();
scheduler_free_all();
- mock_event_free_all();
done:
tor_free(ch1);
tor_free(ch2);
UNMOCK(scheduler_compare_channels);
- UNMOCK(tor_libevent_get_base);
UNMOCK(get_options);
cleanup_scheduler_options();
@@ -635,10 +574,7 @@ test_scheduler_loop_vanilla(void *arg)
set_scheduler_options(SCHEDULER_VANILLA);
mocked_options.KISTSchedRunInterval = 0;
- /* Set up libevent and scheduler */
-
- mock_event_init();
- MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
+ /* Set up scheduler */
scheduler_init();
/*
* Install the compare channels mock so we can test
@@ -786,7 +722,6 @@ test_scheduler_loop_vanilla(void *arg)
channel_flush_some_cells_mock_free_all();
channel_free_all();
scheduler_free_all();
- mock_event_free_all();
done:
tor_free(ch1);
@@ -795,7 +730,6 @@ test_scheduler_loop_vanilla(void *arg)
UNMOCK(channel_flush_some_cells);
UNMOCK(scheduler_compare_channels);
- UNMOCK(tor_libevent_get_base);
UNMOCK(get_options);
}
@@ -917,8 +851,6 @@ test_scheduler_initfree(void *arg)
tt_ptr_op(channels_pending, ==, NULL);
tt_ptr_op(run_sched_ev, ==, NULL);
- mock_event_init();
- MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
MOCK(get_options, mock_get_options);
set_scheduler_options(SCHEDULER_KIST);
set_scheduler_options(SCHEDULER_KIST_LITE);
@@ -935,9 +867,6 @@ test_scheduler_initfree(void *arg)
scheduler_free_all();
- UNMOCK(tor_libevent_get_base);
- mock_event_free_all();
-
tt_ptr_op(channels_pending, ==, NULL);
tt_ptr_op(run_sched_ev, ==, NULL);
diff --git a/src/test/test_status.c b/src/test/test_status.c
index 50ea203e4d..b4ca17891b 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -340,7 +340,7 @@ NS(test_main)(void *arg)
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 5);
+ tt_int_op(CALLED(logv), OP_EQ, 6);
done:
NS_UNMOCK(tls_get_write_overhead_ratio);
@@ -439,6 +439,16 @@ NS(logv)(int severity, log_domain_mask_t domain,
tt_ptr_op(strstr(funcname, "rep_hist_log_link_protocol_counts"),
OP_NE, NULL);
break;
+ case 5:
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s");
+ tt_str_op(va_arg(ap, char *), OP_EQ,
+ " 0 circuits killed with too many cells.");
+ tt_str_op(va_arg(ap, char *), OP_EQ, " [cc not enabled]");
+ tt_str_op(va_arg(ap, char *), OP_EQ, " [conn not enabled]");
+ tt_str_op(va_arg(ap, char *), OP_EQ, "");
+ break;
default:
tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
break;
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 036f739b89..24b43c899b 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -16,6 +16,7 @@
#include "memarea.h"
#include "util_process.h"
#include "log_test_helpers.h"
+#include "compress_zstd.h"
#ifdef HAVE_PWD_H
#include <pwd.h>
@@ -2396,6 +2397,37 @@ test_util_compress_stream_impl(compress_method_t method,
tor_free(buf3);
}
+/** Setup function for compression tests: handles x-zstd:nostatic
+ */
+static void *
+compression_test_setup(const struct testcase_t *testcase)
+{
+ tor_assert(testcase->setup_data);
+ tor_assert(testcase->setup_data != (void*)TT_SKIP);
+ const char *methodname = testcase->setup_data;
+
+ if (!strcmp(methodname, "x-zstd:nostatic")) {
+ methodname = "x-zstd";
+ tor_zstd_set_static_apis_disabled_for_testing(1);
+ }
+
+ return (void *)methodname;
+}
+
+/** Cleanup for compression tests: disables nostatic */
+static int
+compression_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ (void)testcase;
+ (void)ptr;
+ tor_zstd_set_static_apis_disabled_for_testing(0);
+ return 1;
+}
+
+static const struct testcase_setup_t compress_setup = {
+ compression_test_setup, compression_test_cleanup
+};
+
/** Run unit tests for compression functions */
static void
test_util_compress(void *arg)
@@ -5875,6 +5907,13 @@ test_util_monotonic_time(void *arg)
tt_u64_op(coarse_stamp_diff, OP_GE, 120);
tt_u64_op(coarse_stamp_diff, OP_LE, 1200);
+ {
+ uint64_t units = monotime_msec_to_approx_coarse_stamp_units(5000);
+ uint64_t ms = monotime_coarse_stamp_units_to_approx_msec(units);
+ tt_u64_op(ms, OP_GE, 4950);
+ tt_u64_op(ms, OP_LT, 5050);
+ }
+
done:
;
}
@@ -6122,22 +6161,22 @@ test_util_get_unquoted_path(void *arg)
{ #name, test_util_ ## name, flags, NULL, NULL }
#define COMPRESS(name, identifier) \
- { "compress/" #name, test_util_compress, 0, &passthrough_setup, \
+ { "compress/" #name, test_util_compress, 0, &compress_setup, \
(char*)(identifier) }
#define COMPRESS_CONCAT(name, identifier) \
{ "compress_concat/" #name, test_util_decompress_concatenated, 0, \
- &passthrough_setup, \
+ &compress_setup, \
(char*)(identifier) }
#define COMPRESS_JUNK(name, identifier) \
{ "compress_junk/" #name, test_util_decompress_junk, 0, \
- &passthrough_setup, \
+ &compress_setup, \
(char*)(identifier) }
#define COMPRESS_DOS(name, identifier) \
{ "compress_dos/" #name, test_util_decompress_dos, 0, \
- &passthrough_setup, \
+ &compress_setup, \
(char*)(identifier) }
#ifdef _WIN32
@@ -6168,11 +6207,13 @@ struct testcase_t util_tests[] = {
COMPRESS(gzip, "gzip"),
COMPRESS(lzma, "x-tor-lzma"),
COMPRESS(zstd, "x-zstd"),
+ COMPRESS(zstd_nostatic, "x-zstd:nostatic"),
COMPRESS(none, "identity"),
COMPRESS_CONCAT(zlib, "deflate"),
COMPRESS_CONCAT(gzip, "gzip"),
COMPRESS_CONCAT(lzma, "x-tor-lzma"),
COMPRESS_CONCAT(zstd, "x-zstd"),
+ COMPRESS_CONCAT(zstd_nostatic, "x-zstd:nostatic"),
COMPRESS_CONCAT(none, "identity"),
COMPRESS_JUNK(zlib, "deflate"),
COMPRESS_JUNK(gzip, "gzip"),
@@ -6181,6 +6222,7 @@ struct testcase_t util_tests[] = {
COMPRESS_DOS(gzip, "gzip"),
COMPRESS_DOS(lzma, "x-tor-lzma"),
COMPRESS_DOS(zstd, "x-zstd"),
+ COMPRESS_DOS(zstd_nostatic, "x-zstd:nostatic"),
UTIL_TEST(gzip_compression_bomb, TT_FORK),
UTIL_LEGACY(datadir),
UTIL_LEGACY(memarea),
diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c
index 2b03173717..940973cda5 100644
--- a/src/test/test_workqueue.c
+++ b/src/test/test_workqueue.c
@@ -12,7 +12,6 @@
#include "compat_libevent.h"
#include <stdio.h>
-#include <event2/event.h>
#define MAX_INFLIGHT (1<<16)
@@ -159,6 +158,7 @@ static tor_weak_rng_t weak_rng;
static int n_sent = 0;
static int rsa_sent = 0;
static int ecdh_sent = 0;
+static int n_received_previously = 0;
static int n_received = 0;
static int no_shutdown = 0;
@@ -230,7 +230,7 @@ add_n_work_items(threadpool_t *tp, int n)
ent = add_work(tp);
if (! ent) {
puts("Z");
- tor_event_base_loopexit(tor_libevent_get_base(), NULL);
+ tor_libevent_exit_loop_after_delay(tor_libevent_get_base(), NULL);
return -1;
}
if (n_try_cancel < opt_n_cancel &&
@@ -256,19 +256,13 @@ add_n_work_items(threadpool_t *tp, int n)
static int shutting_down = 0;
static void
-replysock_readable_cb(tor_socket_t sock, short what, void *arg)
+replysock_readable_cb(threadpool_t *tp)
{
- threadpool_t *tp = arg;
- replyqueue_t *rq = threadpool_get_replyqueue(tp);
-
- int old_r = n_received;
- (void) sock;
- (void) what;
-
- replyqueue_process(rq);
- if (old_r == n_received)
+ if (n_received_previously == n_received)
return;
+ n_received_previously = n_received;
+
if (opt_verbose) {
printf("%d / %d", n_received, n_sent);
if (opt_n_cancel)
@@ -308,7 +302,7 @@ replysock_readable_cb(tor_socket_t sock, short what, void *arg)
handle_reply_shutdown, NULL);
{
struct timeval limit = { 2, 0 };
- tor_event_base_loopexit(tor_libevent_get_base(), &limit);
+ tor_libevent_exit_loop_after_delay(tor_libevent_get_base(), &limit);
}
}
}
@@ -337,7 +331,6 @@ main(int argc, char **argv)
threadpool_t *tp;
int i;
tor_libevent_cfg evcfg;
- struct event *ev;
uint32_t as_flags = 0;
for (i = 1; i < argc; ++i) {
@@ -411,11 +404,11 @@ main(int argc, char **argv)
memset(&evcfg, 0, sizeof(evcfg));
tor_libevent_initialize(&evcfg);
- ev = tor_event_new(tor_libevent_get_base(),
- replyqueue_get_socket(rq), EV_READ|EV_PERSIST,
- replysock_readable_cb, tp);
-
- event_add(ev, NULL);
+ {
+ int r = threadpool_register_reply_event(tp,
+ replysock_readable_cb);
+ tor_assert(r == 0);
+ }
#ifdef TRACK_RESPONSES
handled = bitarray_init_zero(opt_n_items);
@@ -433,10 +426,10 @@ main(int argc, char **argv)
{
struct timeval limit = { 180, 0 };
- tor_event_base_loopexit(tor_libevent_get_base(), &limit);
+ tor_libevent_exit_loop_after_delay(tor_libevent_get_base(), &limit);
}
- event_base_loop(tor_libevent_get_base(), 0);
+ tor_libevent_run_event_loop(tor_libevent_get_base(), 0);
if (n_sent != opt_n_items || n_received+n_successful_cancel != n_sent) {
printf("%d vs %d\n", n_sent, opt_n_items);
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 52729147b2..b9b36d96d0 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -29,8 +29,6 @@
#include <dirent.h>
#endif /* defined(_WIN32) */
-#include "or.h"
-
#ifdef USE_DMALLOC
#include <dmalloc.h>
#include "main.h"
diff --git a/src/tools/include.am b/src/tools/include.am
index 92cc3f10a2..016cf3b124 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -44,8 +44,6 @@ src_tools_tor_cov_gencert_LDADD = src/common/libor-testing.a \
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
endif
-EXTRA_DIST += src/tools/tor-fw-helper/README
-
if BUILD_LIBTORRUNNER
noinst_LIBRARIES += src/tools/libtorrunner.a
src_tools_libtorrunner_a_SOURCES = src/tools/tor_runner.c src/or/tor_api.c
diff --git a/src/tools/tor-fw-helper/README b/src/tools/tor-fw-helper/README
deleted file mode 100644
index 6a1ecaa1e4..0000000000
--- a/src/tools/tor-fw-helper/README
+++ /dev/null
@@ -1,10 +0,0 @@
-
-We no longer recommend the use of this tool. Instead, please use the
-pure-Go version of tor-fw-helper available at
- https://gitweb.torproject.org/tor-fw-helper.git
-
-Why?
-
-The C code here was fine, but frankly: we don't trust the underlying
-libraries. They don't seem to have been written with network security
-in mind, and we have very little faith in their safety.
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index fb7465c0eb..639a6fbc23 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -36,10 +36,10 @@ ENABLE_GCC_WARNING(redundant-decls)
#include <assert.h>
#endif
-#include "compat.h"
#include "util.h"
#include "torlog.h"
#include "crypto.h"
+#include "crypto_digest.h"
#include "address.h"
#include "util_format.h"
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index de1bc8c858..238e0f6962 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -218,7 +218,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.3.3.5-rc-dev"
+#define VERSION "0.3.4.0-alpha-dev"